Squeryl: Run query explicitly - scala

When I create a query in squeryl, it returns a Query[T] object. The query was not yet executed and will be, when I iterate over the Query object (Query[T] extends Iterable[T]).
Around the execution of a query there has to be either a transaction{} or a inTransaction{} block.
I'm just speaking of SELECT queries and transactions wouldn't be necessary, but the squeryl framework needs them.
I'd like to create a query in the model of my application and pass it directly to the view where a view helper in the template iterates over it and presents the data.
This is only possible when putting the transaction{} block in the controller (the controller includes the call of the template, so the template which does the iteration is also inside). It's not possible to put the transaction{} block in the model, because the model doesn't really execute the query.
But in my understanding the transaction has nothing to do with the controller. It's a decision of the model which database framework to use, how to use it and where to use transactions. So I want the transaction{} block to be in the model.
I know that I can - instead of returning the Query[T] instance - call Iterable[T].toList on this Query[T] object and then return the created list. Then the whole query is executed in the model and everything is fine. But I don't like this approach, because all the data requested from the database has to be cached in this list. I'd prefer a way where this data is directly passed to the view. I like the MySql feature of streaming the result set when it's large.
Is there any possibility? Maybe something like a function Query[T].executeNow() which sends the request to the database, is able to close the transaction, but still uses the MySQL streaming feature and receives the rest of the (selected and therefore fixed) result set when it's accessed? Because the result set is fixed in the moment of the query, closing the transaction shouldn't be a problem.

The general problem that I see here is that you try to combine the following two ideas:
lazy computation of data; here: database results
hiding the need for a post-processing action that must be triggered when the computation is done; here: hiding from your controller or view that the database session must be closed
Since your computation is lazy and since you are not obliged to perform it to the very end (here: to iterate over the whole result set), there is no obvious hook that could trigger the post-processing step.
Your suggestion of invoking Query[T].toList does not exhibit this problem, since the computation is performed to the very end, and requesting the last element of the result set can be used as a trigger for closing the session.
That said, the best I could come up with is the following, which is an adaptation of the code inside org.squeryl.dsl.QueryDsl._using:
class IterableQuery[T](val q: Query[T]) extends Iterable[T] {
private var lifeCycleState: Int = 0
private var session: Session = null
private var prevSession: Option[Session] = None
def start() {
assert(lifeCycleState == 0, "Queries may not be restarted.")
lifeCycleState = 1
/* Create a new session for this query. */
session = SessionFactory.newSession
/* Store and unbind a possibly existing session. */
val prevSession = Session.currentSessionOption
if(prevSession != None) prevSession.get.unbindFromCurrentThread
/* Bind newly created session. */
session.bindToCurrentThread
}
def iterator = {
assert(lifeCycleState == 1, "Query is not active.")
q.toStream.iterator
}
def stop() {
assert(lifeCycleState == 1, "Query is not active.")
lifeCycleState = 2
/* Unbind session and close it. */
session.unbindFromCurrentThread
session.close
/* Re-bind previous session, if it existed. */
if(prevSession != None) prevSession.get.bindToCurrentThread
}
}
Clients can use the query wrapper as follows:
var manualIt = new IterableQuery(booksQuery)
manualIt.start()
manualIt.foreach(println)
manualIt.stop()
// manualIt.foreach(println) /* Fails, as expected */
manualIt = new IterableQuery(booksQuery) /* Queries can be reused */
manualIt.start()
manualIt.foreach(b => println("Book: " + b))
manualIt.stop()
The invocation of manualIt.start() could already be done when the object is created, i.e., inside the constructor of IterableQuery, or before the object is passed to the controller.
However, working with resources (files, database connections, etc.) in such a way is very fragile, because the post-processing is not triggered in case of exceptions. If you look at the implementation of org.squeryl.dsl.QueryDsl._using you will see a couple of try ... finally blocks that are missing from IterableQuery.

Related

What would be the best way to define a gatling a user flow using ChainBuilder?

I am new to Scala and Gatling and I am trying to figure out what would be the best way to define a user story and pass it a ChainBuilder to Gatling Scenario.
When I say user Story In my case I mean a flow that will consist of Login, many different calls and then a loop over another list of calls for the whole duration of the test.
I have created the following function to create a scenario:
def createScenario(name: String, feed: FeederBuilder, chains: ChainBuilder*): ScenarioBuilder = {
scenario(name).feed(feed).forever() {
exec(chains).pause(Config.pauseBetweenRequests)
}
}
And here is how I execute this function:
val scenario = createScenario(Config.testName, feeder.random,
setSessionParams(PARAM1, Config.param1),
setSessionParams(PARAM2, Config.param2),
login,
executeSomeCall1,
executeSomeCall2,
executeSomeCall3,
executeSomeCall4,
executeSomeCall5,
executeSomeCall6,
executeSomeCall7,
executeSomeCall8,
executeSomeCall9,
)
Here is an example of what executeSomeCall function looks like:
def executeSomeCall = {
exec(http("ET Call Home")
.post("/et/call/home")
.body(ElFileBody("/redFingerBody.json")).asJson
.check(status is 200))
}
My first question:
Is that the correct way to define a chain of rest calls and feed it to the scenario? I am asking that because what I see when I define a flow like that is that for some reason not all the my REST calls are actually executed. Weirdly enough, if I change the order of the calls it does work and all functions are called. (So I am definitely doing something wrong)
My second question:
How can I define an infinite loop within this flow? (Infinite for as long as the test is running)
So for example, I'd like the above flow to start and when it reaches executeSomeCall8, it will then loop executeSomeCall8 and executeSomeCall9 for the whole duration of the test.
I don't see why your calls would not be executed, however the way you're constructing your scenario is not that flexible. You can make use of chaining without requiring a createScenario() method.
That leads to your second question, when you have the scenario chained like:
val scn = scenario("something")
...
.exec(someCall7)
.forever(){
exec(sommeCall8)
.exec(someCall9)
}
...
where someCallN in my case look like:
val someCall = http("request name")
.get("/some/uri")
...
Note: foerever() is just an example, you can use other loop statements that suits your needs.
I hope it helps.

TYPO3 DataHandler: Copying record and relate it to itself --> running into loop

I'm developing an event extension with recurring dates. Therefor, I have a recurring date pattern and copy the record for each date. So the record has a relation to itself:
- Main Event
-- N Child Events
Currently, I use the DataHandler method copyRecord, which works perfect. But this just copies the record, without mapping the relation.
- Main Event --> should have the count of children in the database
-- N Child Events --> should habe the relation to its parent main event
The DB should look like:
Event 1 (Main Event) | uid: 1 | event: 0 | recurring_children: 3 (count)
Event copy 1 | uid: 2 |  event: 1 | recurring_children: 0
Event copy 2 | uid: 3 |  event: 1 | recurring_children: 0
Event copy 3 | uid: 4 |  event: 1 | recurring_children: 0
I tried several ways, but none without problems.
The following try sets the relation in the database, but creates more events (I guess, this loops and I have to build a condition to avoid filling the datamap with duplications):
public function processDatamap_afterDatabaseOperations(
$status,
$table,
$recordUid,
array $fields,
\TYPO3\CMS\Core\DataHandling\DataHandler $parentObject){
$event = BackendUtility::getRecord($table, $recordUid);
if ($status === 'update') {
/** #var \TYPO3\CMS\Core\DataHandling\DataHandler $tce */
$tce = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\DataHandling\DataHandler::class);
$tce->start(array(), array());
$overrides = [
'is_recurring_parent' => 0,
'is_recurring_child' => 1,
'recurring_weekdays' => '',
'recurring_period_end' => '0000-00-00',
'event' => $recordUid,
'title' => 'FOOBAR'
];
if ($event['is_recurring_parent']) {
$foobar = $tce->copyRecord('tx_technoseumevents_domain_model_event', $event['uid'], $event['pid'], false, $overrides);
}
T3 version 8.7
Sorry, my first time I'm using the datahandler for complex tasks. Maybe someone has a hint for me...
The recursiveness happening in the first place, indicates a problem with your architecture that might be worth addressing before this problem as it would solve it at the root cause instead of treating symptoms. Normally, a record should not relate to itself - but that said, recursiveness can happen in other ways and it might not be possible to avoid in your use case.
Advise for addressing the problem:
Consider adding a condition that prevents your code from being called on tables other than the one table you need to operate on. This alone could actually be why your copies recurse so that's number one to handle.
If possible, and if you are not concerned with short-circuiting things like changing the title TCA field for a record to prepend "Copy of", or causing the copy to be hidden, you can switch to copyRecord_raw. It takes slightly different arguments (you may have to refactor to pass some arguments as part of the overrides array, compared to calling copyRecord). Doing that will prevent hooks from being called on the children you copy.
You are using a nested DataHandler instance - it might be preferable to call that method on the $dataHandler instance in your example. The DataHandler maintains a copy stack, but (parts of) it will only work if you do things in the same instance and only for some particular hooks (i.e. the pre-type and not-global hooks).
Lastly, there exists a runtime cache entry which contains an array of records which have been copied. Although the utility methods that access and store entries in this cache entry are not publicly accessible - so you cannot call them from your hook class - you can read the array of entries, manipulate it and put it back to prevent recursive processing of the same record. See the method isNestedElementCallRegistered in DataHandler (https://github.com/TYPO3/TYPO3.CMS/blob/v8.7.17/typo3/sysext/core/Classes/DataHandling/DataHandler.php#L9034).
Final note: the after-database-operations hook may be called at times when you do not expect it. For example, if you copy a record and also move it (as in: the copy comes from the UI, not programmatically) the array you receive in $fieldArray may not be the final one (for example, pid may be an unexpected value). Not being aware of this and the peculiarities above might also increase the danger of unintentionally causing recursive operations.
EDIT: If you are using bi-directional relations in TCA then removing one side may also improve the situation. For example, each "date" doesn't necessarily have to be aware of which event it is associated with. Something to consider.

Returning value from a Scala Future

In the below code, I'm trying to do two operations. One, to create a customer in a db, and the other, to create an event in the db. The creation of the event, is dependent on the creation of the user.
I'm new to Scala, and confused on the role of Futures here. I'm trying to query a db and see if the user is there, and if not, create the user. The below code is supposed to check if the user exists with the customerByPhone() function, and if it doesn't, then go into the createUserAndEvent() function.
What it's actually doing, is skipping the response from customerByPhone and going straight into createUserAndEvent(). I thought that by using a flatmap, the program would automatically wait for the response and that I wouldn't have to use Await.result is that not the case? Is there a way to avoid using Await.result to not block the thread on production code?
override def findOrCreate(phoneNumber: String, creationReason: String): Future[AvroCustomer] = {
//query for customer in db
//TODO this goes into createUserAndEvent before checking that response comes back empty from querying for user
customerByPhone(phoneNumber)
.flatMap(_ => createUserAndEvent(phoneNumber, creationReason, 1.0))
}
You don't need to use Await.result or any other blocking. You do in fact have the result from customerByPhone, you're just ignoring it with the _ . I think what you want is something like this:
customerByPhone(phoneNumber)
.flatMap(customer => {
if(customer == null)
createUserAndEvent(phoneNumber, creationReason, 1.0)
else
Future(customer)
})
You need to code the logic to do something only if the customer isn't there.

Does model.getProperty() return a live object for objects that are members of an array?

I get an object from within an array in my model (a JSONmodel type) which is
{
"task": [
{
"dbid": 465,
"bk_cnt": 11,
}, {
"dbid": 472,
"bk_cnt": 16,
}
]
}
I bind this model to a table and connect the bk_cnt up to an objectNumber in a cell. No problem so far.
In code I want to change the value of the first bk_cnt value from 11 to 20 on press of a button. Inside the event I have:
var model = this.getView().getModel() // get the model
var tasks = model.getProperty("/task"); // get as a JS object
tasks[0].bk_cnt = 20 // update the model...will it update the view?
// model.refresh() // it will if this is uncommented.
Problem: Though it is bound to the view, the displayed value of bk_cnt does not change. if I add model.refresh() it does. This code is extracted from a larger section and one of the larger features is sorting by column click. When I click a column to re-sort (no change to the model), the value 20 appears.
What gives?
Musings: I have read that the model.getProprty() function returns a javascript object with a live reference back to the model, and that a change to the value of the object will automatically be reflected in the view for any bound controls. Does this statement fall down on array attributes ?
EDIT: Still feeling around the issue I find that
model.setProperty("/task/0/bk_cnt", 20)
Does not require a model.refresh() to update the view. Not a total surprise as this command is directly acting through the model. This leaves me thinking that the 'live' object returned by getProperty() is only live when it is a primitive datatype like a string or integer, but not for a JS object. Or am I missing something ?
EDIT 2: #Ash points out in his answer that there is a further approach which is to access the JS object from the model property, set whatever attributes need to be updated in the JS object, then replace that into the model, e.g.
var tasks = model.getProperty("/task");
tasks[0].bk_cnt = 20
model.setProperty('/task', tasks)
Second edit done to complete the trio of approaches for future readers.
The Model object is an abstraction layer ON TOP of a javascript object. There is no way that a change within an object is notified anywhere. You need to explicitly trigger the notifications through model.refresh() or model.setProperty().
So both of your solutions are valid, another one (which I favor) would be
var tasks = model.getProperty("/task");
tasks[0].bk_cnt = 20
model.setProperty('/task', tasks)
But this actually depends on how you bind your model to your UI objects :)

Entity Framework Views and Linq .Where

I have a very small entity framework setup containing only a few related classes/tables and a view. I need to be able to pull a specific record from this view, namely, I need to be able to grab the record that meets two criteria, it has a specific ProfileID and a specific QuoteID.
This line is what's causing the problem:
TWProfileUpchargeTotal upchargeTotals = _context.TWProfileUpchargeTotals.Where(p => p.Profileid == profile.id && p.quoteid == _quote.quoteid).First();
I'm looping through the profiles I know about and getting their information from the view, so profile.id changes each time.
The first time this code executes it gets the correct record from the view.
The second and third (and presumably beyond that) time it executes, it retrieves the exact same record.
Any idea why or what I'm doing wrong here?
Thanks, in advance.
You've been bitten by the LINQ "gotcha" called closure. The following post (and many others) on SO detail this:
closure
What you need to do is declare a variable WITHIN the foreach you've ommited from the above code and assign the profile.id to this and use this in the Where clause.
foreach(Profile profile in ListOfProfiles)
{
var localProfile = profile;
TWProfileUpchargeTotal upchargeTotals = _context.TWProfileUpchargeTotals.Where(p => p.Profileid == localProfile.id && p.quoteid == _quote.quoteid).First();
}