-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve query composability and support for utility functions #881
Conversation
@jevakallio, great idea. I have some things to say:
From this two points your example can look like this: function withImageAssetOf(tableName) {
return function(query) {
return query
.leftJoin('image_assets', tableName + '.image_asset_id', 'image_assets.id')
.select(
'image_assets.asset_url',
'image_assets.asset_height',
'image_assets.asset_width');
}
} Other, not parametrized transformers can be done without hi-order function (they just refer to query builder).
Here's example which reveals the power of this three points: /* simple transformer */
function isPublic (query)
{
return query
.where('is_public', true)
.where('rank', '>', 0)
}
/* parametrized transformer */
function byUser (author_or_reviewer_id)
{
return function (query)
{
return query
.where('author', author_or_reviewer_id)
.orWhere('reviewer', author_or_reviewer_id)
}
}
/* now some query */
db.table('publications')
.select()
.transform(isPublic)
.transform(byUser(1))
/* thanks to (1) & (2) transformer functions can be composed*/
var compose = require('lodash').compose
var userRelatedPublic = compose(byUser(1), isPublic)
/* ... */
query.transform(userRelatedPublic) |
@StreetStrider thanks for the feedback! My thoughts in order
Whether we like it or now, higher order functions and returning closures is still something that many javascript developers are not very familiar or comfortable with, and because the rest of knex does not require that style of programming, I don't think we should force it on to the user either. You can, however, choose not to use the optional provided parameters and use higher order functions if you want:
In this case concerns about traditional functional composability isn't really that relevant, IMO. The "composition" is achieved with chaining multiple Which brings us to...
You're probably right. I don't like the proposed In any case I would like to hear from a core contributor whether there is interest in the feature in the first place, and we can fine tune based on their feedback. |
That is correct. But knex also supports an argument-style. I've not found the issue when I've replied to you for the first time, but I've found it now: #863. I'm not sure which is the preferred way. I think we should wait for maintainers' judgement here.
OK. To be clear, in your exmaple function compose (composer[, arg1, arg2, … argN]) Where I think the name must represent that we're using some complex attachment to query builder. It is like a «plugin», maybe |
Supporting query as arg would make it more cumbersome to receive parameters to the function (not hard, mind you, just syntactically error prone, as you might forget to receive the query arg first in the callback signature). In any case, I'll wait to hear interest from maintainer. I think this would be a very useful feature with a very low code footprint, but no point bikeshedding on it if it's not going to ship. I'll be AFK until Monday, will catch up then if there is progress on this.
|
Any way, I'm 👍 on it. This would be a great tool for composability. |
@jevakallio The unit tests seem to be failing, but it doesn't seem to be related to your changes... You could try rebasing this off master, and see if that fixes them. Also, in order to get this merged, you'll need to add some unit tests for the |
3d7c4d1
to
c9bfbf3
Compare
@whitelynx rebased, updated pull request with tests and documentation. |
@jevakallio, nice concept. Just a comment on the Perhaps |
@rhys-vdw interesting, I had not considered that indeed technically speaking this feature is equivalent to That's my only argument against That said, I am fine with any naming the core contributors prefer, my interest is primarily to get the functionality in, since IMO it would be very useful, and simplify the codebases where I use knex myself. Other names off the top of my head, for your consideration: |
Hey @jevakallio. Sorry, I got sick and forgot about this. I think this is a great feature and I will definitely merge it. Hope I'm not bikeshedding now, but I do find the Your point on Perhaps something explicit like If you prefer |
@rhys-vdw, as they say, two hard things in programming: naming, cache invalidation and off-by-one errors... I can very well see the point about the Let me know if further modifications are necessary. Cheers! |
70d7355
to
299bbfa
Compare
😆
Thanks. It looks solid to me. Clean code, docs and tests. |
Improve query composability and support for utility functions
Actually, I just looked again and realized there were a couple of things I missed. Could you make the QueryBuilder the first argument to the callback? The Sorry! |
I already fixed the documentation naming omission with The query builder parameter added in #901 |
Recently moved from Bookshelf to writing raw
knex
queries and loving the experience. One thing that's bugging me is that there doesn't seem to be a great way to extract commonly used domain-specific query patterns and reuse them as functions.This spike adds
.compose(fn)
method to the query builder to achieve this. The method takes in a callback function, whosethis
context is bound to the current query builder. From syntax point of view it works similarly with.whereWrapped(fn)
, but additionally allows the function to add arbitrary operations to the query. See example below for details.Just testing waters here, are you interested in this type of new functionality? If yes, I can contribute tests and documentation. Naming and semantics of the method can be changed if you see fit.
Example
In my domain many tables have a foreign key
image_asset_id
referencingimage_assets
table, and I would like to include certain fields from this table into my query results.Currently I have this pattern in multiple queries:
With compose I could do the following
Where the
withImageAssetOf
function can be defined reusably e.g. as follows:Thanks for your great work on knex!