Relation filters does their job, but i would be great if we can have fluent syntax for them.
Person
.query()
.eager('[pets(orderByName, onlyDogs), children(orderByAge).[pets, children]]', {
orderByName: function (builder) {
builder.orderBy('name');
},
orderByAge: function (builder) {
builder.orderBy('age');
},
onlyDogs: function (builder) {
builder.where('species', 'dog');
}
})
.then(function (people) {
})
Person
.query()
.eager(['pets', 'children.[pets, children]'])
.scope('pets', function (builder) {
builder.where('species', 'dog').orderBy('name')
})
.scope('children.[peta, children]', function (builder) {
builder.orderBy('age');
})
.then(function (people) {
console.log(people[0].children[0].pets[0].name);
console.log(people[0].children[0].movies[0].id);
});
Using this way i can also build my query incrementally.
var query = Person.query().eager(['pets'])
if (needsOrderBy) {
query.scope('pets', function () {
builder.orderBy('name');
})
}
I like the idea that you could define filters incrementally. For which queries would the orderBy called in this case:
.scope('children.[pets, children]', function (builder) {
builder.orderBy('age');
})
All three children, children.pets and children.children? Or only the "leaves" children.pets and children.children? The second option could actually work, since you could specify any single relation in the relation tree. So to order only the children relation:
.scope('children', function (builder) {
builder.orderBy('age');
})
children.pets:
.scope('children.pets', function (builder) {
builder.orderBy('age');
})
Both children.pets and children.children:
.scope('children.[pets, children]', function (builder) {
builder.orderBy('age');
})
Yes, even individual relations will be fine, like children.pets and children.children.
scope is not a good name for this method IMO. I think the name should mention eager as this is a feature that can be used only with eager expressions. Also the word filter has been used elsewhere to refer to functions that modify the query builders. How about something like eagerFilteror filterEager?
I believe filterEager will be better, also i took scope from the term called queryScopes, which is quite similar to filters.
You are right, filterEager is better. eagerFilter sounds like you are defining a named filter to be used somewhere. scope would be a good name also if it was used elsewhere in objection. I don't want to introduce new terminology if I don't have to.
I think this is worth implementing. I'll start working on this in the near future. This also solves another problem: filtering eager expressions that come as user input. For example:
expressApp.get('/people', (req, res) => {
Person
.query()
.allowEager('[pets, children.[pets, children]]')
.eager(req.query.eager)
.filterEager('children', builder => builder.orderBy('firstName'))
.filterEager('children.pets', builder => builder.orderBy('age').limit(10))
.then(people => res.send(people))
.catch(err => res.status(500).send(err));
});
Assuming filterEager just silently fails if the eager expression doesn't have the given path.
:+1:
@koskimas Thanks for your hard work and brilliant library :smile:
@koskimas Also want to say thanks - best ORM I've seen in a while. This feature is great when building a json:api !
Thank you! Keep the issues coming :smile:
@koskimas we are using objection to develop a small cms with dom+http api and the decoupling of database w.r.t. schema is so good. We can create postgres views and get an api for them in minutes. We can populate a very complex page with just one http query. Thank you and long live to objection :)
Thanks, It's great to hear that objection is working for you!