Skip to content
This repository has been archived by the owner on Mar 6, 2020. It is now read-only.

Revisit & improve the knexify concept. #5

Closed
ErisDS opened this issue Jul 27, 2015 · 3 comments
Closed

Revisit & improve the knexify concept. #5

ErisDS opened this issue Jul 27, 2015 · 3 comments

Comments

@ErisDS
Copy link
Member

ErisDS commented Jul 27, 2015

This is a brain dump of thoughts on the currently very temporary knexify module that exists in #2.

Currently, the 'knexifier' is just a mish-mash of functions which provide glue between the JSON format output from the GQL parser, and a knex query builder instance. The key part is the buildWhere function which organises the filter JSON into a set of query builder calls. I envisage we need a similar buildJoin function to do the same for joins, but I'm not sure if that truly should live in GQL.

(currently it's a dirty hack in Ghost's core/server/models/base/utils.js similar to the existing 'query' behaviour that handles joins for the existing implementation of tag/author filtering)

For now, knexify contains a bunch of contextual information that it uses to do its thing, and it needs a whole load more - like which attributes are permitted on a model, what their valid values are, and so on.

All of this is information that is already encoded inside of Ghost's model layer, so having it splatted in here is just a duplication for convenience sake whilst we're building all this fancy stuff out and trying to connect the dots between GQL and Ghost.

Long term, we should be grabbing all of the contextual information we need from Ghost's models, in a uniform and predictable way. This suggests that what we want to hook into with GQL is bookshelf, rather than knex.

I believe that the best approach for doing this might be to provide a bookshelf plugin as part of GQL, one that can hook into any bookshelf models and produce the same effect, providing those models expose the same functions or properties.

Short term, this might be too time-consuming, and it may be best to continue duplicating the information inside GQL in the most useful format, whilst the API in Ghost is also extended out, and revisit doing this in a better way in the future.

A question for right now is: is there some sort of middle ground? E.g. restructuring knexify as a bookshelf plugin, but still using hard-coded contextual information for now, or perhaps providing both the utils like buildWhere and buildJoin in a 'knexify' module, and having a second bookshelf plugin module to hook in?

I'm loosely aiming to make GQL useful to other people, although it's not a priority, for now the main priority is getting it both working AND highly testable.

Some interesting things, mostly for later, that I'm not sure how to do as a bookshelf plugin are:

  • provide the allowed attributes - Ghost models have their own permittedAttributes function - can we include that in the plugin in some way?
  • provide information about relations - I haven't yet found a way to get a list of what relations a model has from bookshelf itself. It may be that this is possible, or that it needs to become possible as part of bookshelf, or that we need to expose a permittedJoins type function as well
  • specify which relations should have counts and how they should behave
  • specify special rules for particular queries (see the 'Special Rules' section here)
@Mickael-van-der-Beek
Copy link

I'm not working at Ghost so this is just a random person who worked on a similar problem's opinion.

I wrote a boolean-logic (plus some basic math operators) querying language that would then translate to ElasticSearch aggregations.

Rather than using a parser-generator I preferred for debugging and error messaging purposes to create my own tokenizer and lexer.

The way it worked was that the query was tokenized into tokens, then the lexer would create lexemes and build the AST. Once that was done, a ElasticSearch specific module would traverse the AST and just build the individual subqueries by switching on the name of the operators in the AST recursively.

For the Ghost use-case I think that a similar structure could be interesting. Something like:

  • one Query -> AST (Tokenizer / Lexer) module
  • one ORM specific plugin that converts an AST into a query object
  • one Ghost specific module that enriches the already built query with additional WHEN conditions or other clauses

I might work on this if there is any interest in it.
Just my two cents.

@ErisDS
Copy link
Member Author

ErisDS commented Mar 28, 2016

Hey @Mickael-van-der-Beek sorry for the slow reply. There are some similar conversations around the future direction for GQL happening on TryGhost/Ghost#5604 and #17

@kirrg001
Copy link
Contributor

GQL was replaced by NQL.

I will close this issue because GQL is deprecated now. We won't refactor GQL anymore.

If you have a question how NQL works, please raise an issue here.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants