Is there a cleaner way to iterate through Mongo query results in Fantom? - mongodb

I'm writing a web app in Fantom language and using afMongo to access a Mongo DB instance. Following the example in afMongo documentation I get the results of a query that I need to iterate through. In a simplified example, the iteration looks like this
class MapListIterator {
Void main(){
[Str:Obj?][] listOfMaps := [,]
listOfMaps.add(
["12345":[
"id":12345,
"code":"AU",
"name":"Australia"
]])
listOfMaps.each |Str:Obj? map| {
echo(map.keys)
keys := map.keys
keys.each {
echo(it)
echo(((Str:Obj?)map[it])["code"])
echo(((Str:Obj?)map[it])["name"])
}
}
}
}
I ran this code in Fantom online playground and it works Ok, but I wonder if it is a cleaner way to iterate through the results. I don't like the casting in my code above. Also, is there a better way to write the nested it-block, please?
EDIT:
Turns out that I was overcomplicating things. This is how the code looks after applying Steve's suggestions:
Str:Country mapOfCountries := [:]
mapOfCountries.ordered = true
listOfMaps := ([Str:Str?][]) collection.findAll
listOfMaps.each {
c := it["code"]
n := it["name"]
mapOfCountries.add(c, Country { code = c ; name = n })
}

I would re-cast the result and assign the map early on... which gives:
listOfMappedMaps := ([Str:[Str:Obj?]][]) listOfMaps
listOfMappedMaps.each {
map := it
map.keys.each {
echo(map[it]["code"])
echo(map[it]["name"])
}
}
The next step would be use Morphia which lets you use objects in place of maps.

Related

Call a PostgreSQL function and get result back with no loop

I have a simple rust program that interacts with a PostgreSQL database.
The actual code is:
for row in &db_client.query("select magic_value from priv.magic_value();", &[]).unwrap()
{
magic_value = row.get("magic_value");
println!("Magic value is = {}", magic_value);
}
And.. it works. But I don't like it: I know this function will return one and only one value.
From the example I found, for example here: https://docs.rs/postgres/latest/postgres/index.html
and here: https://tms-dev-blog.com/postgresql-database-with-rust-how-to/
You always have a recordset to loop on.
Which is the clean way to call a function without looping?
query returns a Result<Vec<Row>, _>. You are already unwrapping the Vec, so you can just use it directly instead of looping. By turning the Vec into an owning iterator yourself, you can even easily obtain a Row instead of a &Row.
magic_value = db_client.query("select magic_value from priv.magic_value();", &[])
.unwrap() // -> Vec<Row>
.into_iter() // -> impl Iterator<Item=Row>
.next() // -> Option<Row>
.unwrap() // -> Row
.get("magic_value");

How to combine the elements of an arbitrary number of dependent Fluxes?

In the non reactive world the following code snippet is nothing special:
interface Enhancer {
Result enhance(Result result);
}
Result result = Result.empty();
result = fooEnhancer.enhance(result);
result = barEnhancer.enhance(result);
result = bazEnhancer.enhance(result);
There are three different Enhancer implementations taking a Result instance, enhancing it and returning the enhanced result. Let's assume the order of the enhancer calls matters.
Now what if these methods are replaced by reactive variants returning a Flux<Result>? Because the methods depend on the result(s) of the preceding method, we cannot use combineLatest here.
A possible solution could be:
Flux.just(Result.empty())
.switchMap(result -> first(result)
.switchMap(result -> second(result)
.switchMap(result -> third(result))))
.subscribe(result -> doSomethingWith(result));
Note that the switchMap calls are nested. As we are only interested in the final result, we let switchMap switch to the next flux as soon as new events are emitted in preceding fluxes.
Now let's try to do it with a dynamic number of fluxes. Non reactive (without fluxes), this would again be nothing special:
List<Enhancer> enhancers = <ordered list of different Enhancer impls>;
Result result = Result.empty();
for (Enhancer enhancer : enhancers) {
result = enhancer.enhance(result);
}
But how can I generalize the above reactive example with three fluxes to deal with an arbitrary number of fluxes?
I found a solution using recursion:
#FunctionalInterface
interface FluxProvider {
Flux<Result> get(Result result);
}
// recursive method creating the final Flux
private Flux<Result> cascadingSwitchMap(Result input, List<FluxProvider> fluxProviders, int idx) {
if (idx < fluxProviders.size()) {
return fluxProviders.get(idx).get(input).switchMap(result -> cascadingSwitchMap(result, fluxProviders, idx + 1));
}
return Flux.just(input);
}
// code using the recursive method
List<FluxProvider> fluxProviders = new ArrayList<>();
fluxProviders.add(fooEnhancer::enhance);
fluxProviders.add(barEnhancer::enhance);
fluxProviders.add(bazEnhancer::enhance);
cascadingSwitchMap(Result.empty(), fluxProviders, 0)
.subscribe(result -> doSomethingWith(result));
But maybe there is a more elegant solution using an operator/feature of project-reactor. Does anybody know such a feature? In fact, the requirement doesn't seem to be such an unusual one, is it?
switchMap feels inappropriate here. If you have a List<Enhancer> by the time the Flux pipeline is declared, why not apply a logic close to what you had in imperative style:
List<Enhancer> enhancers = <ordered list of different Enhancer impls>;
Mono<Result> resultMono = Mono.just(Result.empty)
for (Enhancer enhancer : enhancers) {
resultMono = resultMono.map(enhancer::enhance); //previousValue -> enhancer.enhance(previousValue)
}
return resultMono;
That can even be performed later at subscription time for even more dynamic resolution of the enhancers by wrapping the whole code above in a Mono.defer(() -> {...}) block.

Receiving "not found: value" even the variable is define

I'm receiving not found: value counter even though the variable is defined.
Any help with this? I'm new with scala and everything is new to my eyes. Thanks
#{def counter = 0}
#for(atg <- Activity.groupContiguous(activityGroup)) {
#if(!atg.isEmpty) {
#views.html.activity.activityTypeGroup(atg, counter))
}
counter = counter + 1
}
You code doesn't work because #{def counter = 0} doesn't define anything in the template scope and returns Unit. I don't know any convenient way to define mutable variable in the scala template, and this is actually discouraged.
The code could be easily rewritten using functional approach:
#for((atg, counter) <- Activity.groupContiguous(activityGroup).filterNot(_.isEmpty).zipWithIndex) {
#views.html.activity.activityTypeGroup(atg, counter))
}
Take a look to other similar issue, you can solve it with zipWithIndex https://stackoverflow.com/a/14613877/1066240
Yo'll find there also other useful examples.

Play! + Scala: Split string by commnas then Foreach loop

I have a long string similar to this:
"tag1, tag2, tag3, tag4"
Now in my play template I would like to create a foreach loop like this:
#posts.foreach { post =>
#for(tag <- #post.tags.split(",")) {
<span>#tag</span>
}
}
With this, I'm getting this error: ')' expected but '}' found.
I switched ) for a } & it just throws back more errors.
How would I do this in Play! using Scala?
Thx in advance
With the help of #Xyzk, here's the answer: stackoverflow.com/questions/13860227/split-string-assignment
Posting this because the answer marked correct isn't necessarily true, as pointed out in my comment. There are only two things wrong with the original code. One, the foreach returns Unit, so it has no output. The code should actually run, but nothing would get printed to the page. Two, you don't need the magic # symbol within #for(...).
This will work:
#for(post <- posts)
#for(tag <- post.tags.split(",")) {
<span>#tag</span>
}
}
There is in fact nothing wrong with using other functions in play templates.
This should be the problem
#for(tag <- post.tags.split(",")) {
<span>#tag</span>
}

What would be the opposite to hasFields?

I'm using logical deletes by adding a field deletedAt. If I want to get only the deleted documents it would be something like r.table('clients').hasFields('deletedAt'). My method has a withDeletes parameter which determines if deleted documents are excluded or not.
Finally, people at the #rethinkdb IRC channel suggested me to use the filter method and that did the trick:
query = adapter.table(table).filter(filters)
if withDeleted
query = adapter.filter (doc) ->
return doc.hasFields 'deletedAt'
else
query = adapter.filter (doc) ->
return doc.hasFields('deletedAt').not()
query.run connection, (err, results) ->
...
My question is why do I have to use filter and not something like:
query = adapter.table(table).filter(filters)
query = if withDeleted then query.hasFields 'deletedAt' else query.hasFields('deletedAt').not()
...
or something like that.
Thanks in advance.
The hasFields function can be called on both objects and sequences, but not cannot.
This query:
query.hasFields('deletedAt')
Behaves the same as this one (on sequences of objects):
query.filter((doc) -> return doc.hasFields('deletedAt'))
However, this query:
query.hasFields('deletedAt').not()
Behaves like this:
query.filter((doc) -> return doc.hasFields('deletedAt')).not()
But that doesn't make sense. you want the not to be inside the filter, not after it. Like this:
query.filter((doc) -> return doc.hasFields('deletedAt').not())
One nice that about RethinkDB is that because of the way queries are built up in host language it's very easy to define new fluent syntax by just defining functions in your language. For example if you wanted to have a lacksFields function you could define it in Python (sorry I don't really know coffeescript) like so:
def lacks_fields(stream, *args):
res = stream
for arg in args:
res = res.filter(lambda x: ~x.has_fields(arg))
return res
Then you can use a nice fluent syntax like:
lacks_fields(stream, "foo", "bar", "buzz")