-
-
Notifications
You must be signed in to change notification settings - Fork 174
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
Query: parse as AST #6788
base: v5/develop
Are you sure you want to change the base?
Query: parse as AST #6788
Conversation
Updates
DiscussionIn regards to intercept, all evaluated objects and variables are now passed through intercept. Even stuff like literal strings or numbers. It could be worth discussing if this is actually useful or just slow. One idea could be to only intercept objects on which a member field or method is accessed. Like:
|
|
Sure, intercept(
intercept(page).files
).first
intercept(
intercept(
intercept(page).files
).first
).delete also intercept(
intercept(foo).callMeBack(() => page('bar'))
).delete |
Having implemented the " $query = new Query('Shipping Address');
$this->assertSame('742 Evergreen Terrace', $query->resolve(['Shipping Address' => '742 Evergreen Terrace'])); I see 4 options:
The index operator obviously gives the most bang for the buck as it allows any kind of expression as index (not just strings), but it either requires an unconventional syntax (the |
d82b385
to
738674e
Compare
I've implememted the intercept logic like described above (see test here) Other notable change would be moving the "resolver cache" (the cache that maps query strings to closures) to the |
@rasteiner we are currently trying to wrap some things up for the v5 beta, that's why I'm not active here much these days, but will get back to it probably next week! :) |
b3998f5
to
4c4521c
Compare
41b2678
to
d961f46
Compare
bc90c22
to
c717f87
Compare
- cast data objects to arrays before passing to query runner - allow integers as identifiers of array keys when used after a dot - don't emit warnings when an array key is missing
- Implements the intercept mechanism for both runners - Renames the AST Node classes with a "Node" suffix to avoid confusion with some PHP internal classes (like `Closure` -> `ClosureNode`)
…ompatible with parent
6ca0140
to
3785933
Compare
a41c90f
to
0e9dbef
Compare
0e9dbef
to
d55ac78
Compare
src/Query/Query.php
Outdated
* @deprecated 6.0.0 | ||
* @codeCoverageIgnore | ||
*/ | ||
private function resolve_legacy(array|object $data = []): mixed |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
private function resolve_legacy(array|object $data = []): mixed | |
private function resolveLegacy(array|object $data = []): mixed |
Description
This PR Introduces a new query parser and "runners" which allow Kirby to "compile" queries as ASTs so that they can subsequently execute faster. Based on initial tests, the runners seem to be about 30% faster (28% for
Interpreted
, 35% forTranspiled
, the other "more experimental" one).Summary of changes
Many new classes in
Kirby\Query
:Kirby\Query\Parser
: take care of splitting a string query first into tokens of specific types and then parsing these into an AST nodes treeKirby\Query\AST
: all kind of nodes a query can consist of and the logic how they can be resolvedKirby\Query\Visitor
: classes that help resolving (visit) an AST and turn nodes either directly into processed results (Interpreter
) or PHP code representations (Transpiler
)Kirby\Query\Runner
: classes that take a query and with the help of the above either directly process the result (Interpreted
, with in-memory cache) or turn it into PHP code and run it (Transpiled
, cached in memory but also the pure PHP code as files for running the same code again in future reque)The general process is:
Kirby\Query\Parser\Tokenizer
).Kirby\Query\Parser\Parser
).Interpreter
that directly evaluates the query, or aTranspiler
that transpiles it into PHP code.Interpreted
/Transpiled
The original
Kirby\Query\Query
class remains in place and chooses which runner to use based on thequery.runner
option.All previous Query classes have been deprecated and will be removed in v7. Until then setting
query.runner
tolegacy
can still make use of them.Reasoning
Separating the parsing and execution steps allows for more flexibility and better performance, since it allows us to cache the AST, either as PHP code or in memory during a request (or in some other out of process memory cache).
By adding the new runners as optional and leaving the old parser as default legacy in place, this minimizes the risk of issues and hopefully allows us to add this still to v5, only changing the default in v6.
Additional context
The parser is a predictive recursive descent parser, making the parsing step
O(n)
. As such it can't support ambigous code, which leads to the following breaking change.Changelog
Enhancements
query.runner
option to switch tointerpreted
ortranspiled
mode, the latter caches queries as PHP filespage[site.pageMethodName]
Breaking changes
The new query runners are stricter in parsing queries. Ambiguous terms aren't supported anymore. In some edge cases, this will require you to access an array/object via subscript notation - in rare cases on the top level via the new
this
keyword, e.g.this["indentifier.with dots and spaces"]
.Docs
Config option
query.runner
:Receive arguments in closures:
Queries will still be tried to resolve first directly from the data context, e.g. when your query is
null
and your data['null' => 'foo']
the result will directly be'foo'
. Same foruser.username
and['user.username' => 'foo']
.Ready?
No! This is a work in progress. The proposed API could change.
Also, for some reason VS Code decided to merge the
main
branch into this one... As this PR isn't really ment to be merged "as is" I'll just ignore this mistake: this is mainly a place for dicussion.For review team