expand parser with live views, row expiry, posting indexes#28
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Summary
Brings the parser up to grammar parity with QuestDB OSS ≥ 9.4.0 and Enterprise ≥ 3.3.0, plus the two still-open feature PRs (LIVE VIEWS, mat-view row expiry). Every construct parses to a typed AST, round-trips through
toSql(), and autocompletes. Also fills prior-minor gaps (9.3.0→9.4.0, 3.2.0→3.3.0) surfaced by a full audit, and improves autocomplete/highlighting for keywords the grammar reaches via the non-reservedidentifierpath.Guiding rule: never reject syntax QuestDB accepts (extra leniency is fine).
What's been added
LIVE VIEWS — create/drop/alter,
SHOW CREATE, and theANCHORwindow clause;live_views()function.CREATE LIVE VIEW lv FLUSH EVERY 5s IN MEMORY 1h START FROM BEGINNING AS (SELECT * FROM t)CREATE LIVE VIEW lv FLUSH EVERY 1s START FROM NOW AS SELECT ... FROM baseALTER LIVE VIEW lv RESUME WAL FROM TXN 1,DROP LIVE VIEW IF EXISTS lv,SHOW CREATE LIVE VIEW lvSELECT avg(x) OVER (ORDER BY ts ANCHOR EXPRESSION timestamp_floor('1d', ts)) FROM t... WINDOW w AS (ORDER BY ts ANCHOR DAILY '09:30')Materialized-view
EXPIRE ROWSrow retention (WHEN/KEEP LATEST/KEEP [n] HIGHEST|LOWEST[CLEANUP EVERY]), plusALTER … SET/DROP EXPIRE.CREATE MATERIALIZED VIEW mv AS (SELECT * FROM base) EXPIRE ROWS WHEN v < 2.0 CLEANUP EVERY 30m... EXPIRE ROWS KEEP LATEST PARTITION BY symALTER MATERIALIZED VIEW price_1h SET EXPIRE ROWS KEEP HIGHEST px PARTITION BY sym CLEANUP EVERY 1hALTER MATERIALIZED VIEW price_1h DROP EXPIRE ROWSSAMPLE BYbare single-letter units ({n,U,T,s,m,h,d,w,M,y}, no leading digit).SELECT ts, avg(x) FROM t SAMPLE BY wREFRESH MATERIALIZED VIEW … STATS.REFRESH MATERIALIZED VIEW mv STATSREBASE WAL [INTO '<dir>']onALTER TABLEandALTER MATERIALIZED VIEW.ALTER TABLE t REBASE WAL INTO 'd1'ALTER MATERIALIZED VIEW mv REBASE WALSHOW CREATE DATABASE [ (INCLUDE|EXCLUDE) (ALL | (cat, …)) ].SHOW CREATE DATABASE INCLUDE (tables, views, users)SHOW CREATE DATABASE EXCLUDE (materialized_views, service_accounts, acl)Table
FORMAT { PARQUET | NATIVE }onCREATE TABLE(3 positions) andALTER TABLE … SET FORMAT.CREATE TABLE t (a INT) TIMESTAMP(a) PARTITION BY DAY FORMAT PARQUET WALALTER TABLE t SET FORMAT NATIVEEnterprise
SWITCH ROLE TO { PRIMARY | REPLICA } [TIMEOUT <ms>]/SWITCH STATUS.SWITCH ROLE TO REPLICA TIMEOUT 5000SWITCH STATUSColumn-level
GRANT/REVOKEwildcards, 3-word permissions, andCONVERT PARTITIONpermission.GRANT SELECT ON tab(* EXCLUDE(a, b)) TO aliceGRANT SET TABLE FORMAT ON t TO alice(also SET STORAGE POLICY / SET TABLE TYPE / REMOVE STORAGE POLICY)GRANT CONVERT PARTITION TO PARQUET ON tab TO alicePosting/bitmap indexes —
INDEX TYPE POSTING [DELTA|EF] [CAPACITY n] [INCLUDE(cols)]/TYPE BITMAP|NONE, column- and table-level, plusALTER COLUMN … ADD INDEX.CREATE TABLE t (s SYMBOL INDEX TYPE POSTING DELTA INCLUDE (a, b), a INT, ts TIMESTAMP) TIMESTAMP(ts)CREATE TABLE x (t TIMESTAMP, s SYMBOL), INDEX(s TYPE POSTING) TIMESTAMP(t)ALTER TABLE t ALTER COLUMN sym ADD INDEX TYPE POSTING INCLUDE (p)Dynamic
WINDOW JOINbound — a column/cast/function expression as theRANGE BETWEEN … PRECEDING/FOLLOWINGbound.SELECT * FROM t WINDOW JOIN p ON t.sym = p.sym RANGE BETWEEN wndBound SECONDS PRECEDING AND wndBound SECONDS FOLLOWING... WINDOW JOIN prices p RANGE BETWEEN t.price::long minutes PRECEDING AND 1 minute FOLLOWING INCLUDE PREVAILINGMulti-RHS
HORIZON JOINchaining before a trailingRANGE/LIST … AS x.SELECT ... FROM trades t HORIZON JOIN bids AS b ON (t.sym = b.sym) HORIZON JOIN asks AS a ON (t.sym = a.sym) LIST (-1s, 0s, 1s) AS hEnterprise
COPY PERMISSIONS FROM <src> TO <dst>andCONVERT PARTITIONgrant/revoke names.COPY PERMISSIONS FROM src TO dstNew function names (autocomplete):
sleep,regr_r2,is_end_of_month,kurtosis*,skewness*,array_agg,live_views,cume_dist,ntile,nth_value,backups.Autocomplete & highlighting
contextKeywordSuggestionsre-surfaces keywords the grammar accepts only through the non-reservedidentifiersub-rule (so Chevrotain reports them as the abstractIdentifierKeywordand they never appeared as hints):GRANT/REVOKE CONVERT PARTITION,SET TABLE FORMAT/TYPE,SET/REMOVE STORAGE POLICY,CONVERT PARTITION TO PARQUET|NATIVE, andSHOW CREATE DATABASEcategory names. Parsing already accepted these — this only affects the hints.nowas a constant and theSHOW CREATE DATABASEcategory names (schema,views,acl,materialized_views,service_accounts) as non-reserved constants, so they classify/highlight consistently while staying usable as identifiers (START FROM NOWnow highlights as a constant;now()stays a function).Testing
tests/parser.test.ts, autocomplete regression tests intests/autocomplete.test.ts, and representative fixtures intests/fixtures/docs-queries.json.typecheck,lint, andbuildare clean.