Reputation: 18005
I am using rethinkDB with node.js. The following request works fine :
function myFn () {
return co(function *() {
let query;
query = yield r.db("my-db")
.table("app")
.filter(r.row("id").eq(id))
.run(conn);
return query.toArray();
});
}
I would like to return the result of multiple yield
asynchronously, however the following fails :
function myFn () {
return co(function *() {
let query, query2;
query = r.db("my-db")
.table("app")
.filter(r.row("id").eq(id))
.run(conn);
query2 = r.db("my-db")
.table("app")
.filter(...)
.run(conn);
return yield {q1 : query, q2 : query2};
});
}
Then I have to call toArray()
on each element, so on the calling function I do :
// using ramda.js
var res = R.map((el) => {
return el.toArray();
}, yield myFn);
However I get :
{
"q1": {
"isFulfilled": false,
"isRejected": false
},
"q2": {
"isFulfilled": false,
"isRejected": false
}
}
Something odd too :
// this works perfectly
return q.toArray();
// this returns the following :
return {q: q.toArray()};
"q": {
"isFulfilled": true,
"isRejected": false,
"fulfillmentValue": [ ... ]
}
I suspect I am missing something about the way yield
works, so how can I return the fulfilled result of multiple yield
results ?
Upvotes: 2
Views: 2065
Reputation: 18005
So I asked the same question on the reThinkDB google groups
:
To quote Ryan Paul :
Your original attempt was actually really close, there were just two things that you need to add:
- You need to yield the queries individually
- And you need to convert to array in the query if you don’t want to get cursors
Here’s a working example with the coroutine and yield:
function myFn() { return co(function*() { var conn = yield r.connect(); var query1 = yield r.db("test").table("fellowship") .filter({species: "hobbit"}) .coerceTo("array").run(conn); var query2 = yield r.db("test").table("fellowship") .filter({species: "human"}) .coerceTo("array").run(conn); conn.close(); return {q1: query1, q2: query2}; }); }
It’s also pretty simple to do without the coroutines and yield, and as long as you use a promise library like bluebird. Here’s how I would do it:
function myFn1() { return r.connect().then(conn => { return bluebird.all([ r.db("test").table("fellowship") .filter({species: "hobbit"}) .coerceTo("array").run(conn), r.db("test").table("fellowship") .filter({species: "human"}) .coerceTo("array").run(conn) ]).then(items => ({q1: items[0], q2: items[1]})); }); }
Upvotes: 1
Reputation: 664620
yield
doesn't work with objects that contain promises - it only works with promises itself. Instead of return yield {q1: query, q2: query2};
you'd have to do
return {q1: yield query, q2: yield query2};
However, that is kinda problematic as errors in query2
will not be thrown until query
is done. So if you don't just want to sequentially execute them, you will have to use Promise.all
to await a collection of promises "in parallel":
var [q1, q2] = yield Promise.all([query, query2]);
return {q1, q2};
(Depending on the promise lib you're using, there might also be a helper function to treat objects as collections, not only arrays)
Upvotes: 1