(POC, WIP) Allow querying APIv4 with SQL expressions #17054
Closed
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Preface
As I was reading some of the PRs for dev/report#31 like #16947 and #17047, I was struck by the sense that they were, essentially, expanding APIv4's PHP API to incorporate a small DSL within the
select
(e.g.$params['select'][]='avg(fee_amount) as average_fee';
)This struck me for a couple reasons. On one hand, it's bit confusing because my impression is that APIv4's PHP API is supposed to be a straight-up 'query-builder' pattern using methods and arrays which are amenable to data-integration and complex UIs, so the DSL feels out-of-character. On the other hand, I can relate because I found it easier to use APIv4 through a DSL (ahem
cv api4
and dev/core#1489).To be sure, I think that it's useful to have both a DSL-pattern (for simple improvisations) and a query-builder-pattern (for data-integrations and complex UI building). Ideally, you would be able to summon either pattern when convenient, and you'd be able to interchange them.
But there's a problem with the current design -- the
select
DSL and forcv api4
DSL don't currently work together.If only there were some standard DSL for writing queries, that could be interpreted consistently in different layers. Maybe something which already had existing parsers. Something that would take the name of the data-set and a list of return-values and a list of filters...
Overview
This is a proof-of-concept for
\Civi\Api4::sql($expr)
which allows you to construct an APIv4 call using a SQL expression.Consider a query written in APIv4's query-building notation:
Of course, in a DSL like SQL, you don't need as many funny symbols. It's just one line:
Before
You have to use query-builder notation all the time.
After
You can construct the APIv4 query like so:
For good and ill, this will execute APIv4 -- applying the same permission model, custom-data mechanics, option-value-mappings, BAO fiddly-bits, etc.
You can also mingle the styles -- seeding a base-query with the SQL and then mixing-in extra bits with the query-building interface:
Comments
It may be confusing for some people that MySQL-SQL and APIv4-SQL are different dialects. One could take a cue from Doctrine, Hibernate, Salesforce, etal and rebrand it. (API4QL? 4QL? A4? Fourql? CiviQL? ad nauseum)
You can see this in action by checking out the PR and running one of these commands:
Benchmarking data for some PHP-SQL parsers: https://gist.github.com/totten/409f9f1f6d96a17d83e1d100e2eca3a6
This PR is a "proof-of-concept" for a few reasons. Trivially, it doesn't have a unit-test, and there's a lot of 'FIXME' bits for mapping different parts of the query. Additionally, some of the functionality will be more doable as
dev/report#31
progresses in supporting SQL-features in APv4 queries. More broadly, I think there should be a bit more thought to the inter-change of structured/query-building representations and DSL/pithy representations. Maybe things like this would allow you freely move among notations: