From 396b912d92960007a9f5635849ffd3b55a51af9f Mon Sep 17 00:00:00 2001 From: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Date: Sat, 18 Feb 2023 18:37:50 -0800 Subject: [PATCH 001/106] chore: Add changelog template for 0.5.3 (#1892) --- CHANGELOG.md | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bec0b920bb4d..9f7a48567a3e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,25 @@ # PRQL Changelog +## 0.5.3 — [unreleased] + +**Features**: + +**Fixes**: + +**Documentation**: + +**Web**: + +**Integrations**: + +**Internal changes**: + +**New Contributors**: + ## 0.5.2 — 2022-02-18 -0.5.2 is a tiny release to fixes an issue with `prql-js`'s build in yesterday's -0.5.1 release. +0.5.2 is a tiny release to fix an build issue in yesterday's `prql-js` 0.5.1 +release. This release has 7 commits from 2 contributors. From c79c5f1e2b54c021538da2954352e9c3207fca4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alja=C5=BE=20Mur=20Er=C5=BEen?= Date: Sun, 19 Feb 2023 11:17:49 +0100 Subject: [PATCH 002/106] feat!: loop (#1642) --- CHANGELOG.md | 2 + book/README.md | 2 +- book/book.toml | 2 +- book/src/SUMMARY.md | 4 +- book/src/integrations/jupyter.md | 2 +- book/src/integrations/rill.md | 2 +- book/src/internals/name-resolving.md | 2 +- .../README.md} | 2 +- .../standard-library/from-text.md | 63 ++ .../standard-library/loop.md | 50 ++ book/src/syntax.md | 2 +- book/src/transforms/from_text.md | 61 -- .../README-0.prql} | 0 .../standard-library/from-text-0.prql} | 0 .../standard-library/from-text-1.prql} | 0 .../standard-library/from-text-2.prql} | 0 .../standard-library/loop-0.prql | 7 + .../snapshot__@examples__cte-0.prql.snap | 22 +- ...snapshot__@examples__employees-0.prql.snap | 21 +- ...snapshot__@examples__employees-1.prql.snap | 27 +- ...snapshot__@examples__employees-2.prql.snap | 23 +- ...snapshot__@examples__employees-3.prql.snap | 11 +- .../snapshot__@examples__misc-0.prql.snap | 15 +- ...snapshot__@examples__variables-0.prql.snap | 3 +- ...snapshot__@examples__variables-1.prql.snap | 9 +- .../snapshot__@introduction-0.prql.snap | 5 +- ...__@language-features__distinct-2.prql.snap | 3 +- ..._@language-features__s-strings-3.prql.snap | 13 +- ...res__standard-library__README-0.prql.snap} | 3 +- ...__standard-library__from-text-0.prql.snap} | 6 +- ...__standard-library__from-text-1.prql.snap} | 2 +- ...__standard-library__from-text-2.prql.snap} | 2 +- ...atures__standard-library__loop-0.prql.snap | 34 + .../snapshot__@queries__pipelines-2.prql.snap | 9 +- .../snapshot__@queries__variables-0.prql.snap | 4 +- .../snapshots/snapshot__@syntax-5.prql.snap | 3 +- .../snapshot__@transforms__group-2.prql.snap | 3 +- .../snapshot__@transforms__sort-3.prql.snap | 17 +- .../snapshot__@transforms__sort-5.prql.snap | 7 +- .../snapshot__@transforms__window-4.prql.snap | 3 +- ...res__standard-library__README-0.prql.snap} | 2 +- ...__standard-library__from-text-0.prql.snap} | 2 +- ...__standard-library__from-text-1.prql.snap} | 2 +- ...__standard-library__from-text-2.prql.snap} | 2 +- ...atures__standard-library__loop-0.prql.snap | 13 + prql-compiler/src/ast/pl/expr.rs | 1 + prql-compiler/src/ast/pl/fold.rs | 1 + prql-compiler/src/ast/pl/types.rs | 8 +- prql-compiler/src/ast/rq/fold.rs | 1 + prql-compiler/src/ast/rq/transform.rs | 1 + prql-compiler/src/semantic/lowering.rs | 33 +- prql-compiler/src/semantic/std.prql | 1 + prql-compiler/src/semantic/transforms.rs | 8 + .../prql_compiler__test__prql_to_sql_2.snap | 3 +- prql-compiler/src/sql/anchor.rs | 87 ++- prql-compiler/src/sql/context.rs | 61 +- prql-compiler/src/sql/gen_expr.rs | 75 +- prql-compiler/src/sql/gen_query.rs | 687 ++++++++++-------- prql-compiler/src/sql/mod.rs | 35 + prql-compiler/src/sql/preprocess.rs | 68 +- ...query__test__variable_after_aggregate.snap | 3 +- prql-compiler/src/test.rs | 291 +++++--- .../tests/integration/queries/loop.prql | 7 + .../integration__tests__test@loop.prql.snap | 12 + 64 files changed, 1107 insertions(+), 743 deletions(-) rename book/src/language-features/{standard-library.md => standard-library/README.md} (98%) create mode 100644 book/src/language-features/standard-library/from-text.md create mode 100644 book/src/language-features/standard-library/loop.md rename book/tests/prql/language-features/{standard-library-0.prql => standard-library/README-0.prql} (100%) rename book/tests/prql/{transforms/from_text-0.prql => language-features/standard-library/from-text-0.prql} (100%) rename book/tests/prql/{transforms/from_text-1.prql => language-features/standard-library/from-text-1.prql} (100%) rename book/tests/prql/{transforms/from_text-2.prql => language-features/standard-library/from-text-2.prql} (100%) create mode 100644 book/tests/prql/language-features/standard-library/loop-0.prql rename book/tests/snapshots/{snapshot__@language-features__standard-library-0.prql.snap => snapshot__@language-features__standard-library__README-0.prql.snap} (84%) rename book/tests/snapshots/{snapshot__@transforms__from_text-0.prql.snap => snapshot__@language-features__standard-library__from-text-0.prql.snap} (73%) rename book/tests/snapshots/{snapshot__@transforms__from_text-1.prql.snap => snapshot__@language-features__standard-library__from-text-1.prql.snap} (90%) rename book/tests/snapshots/{snapshot__@transforms__from_text-2.prql.snap => snapshot__@language-features__standard-library__from-text-2.prql.snap} (91%) create mode 100644 book/tests/snapshots/snapshot__@language-features__standard-library__loop-0.prql.snap rename book/tests/snapshots/{snapshot__run_display_reference_prql@language-features__standard-library-0.prql.snap => snapshot__run_display_reference_prql@language-features__standard-library__README-0.prql.snap} (76%) rename book/tests/snapshots/{snapshot__run_display_reference_prql@transforms__from_text-0.prql.snap => snapshot__run_display_reference_prql@language-features__standard-library__from-text-0.prql.snap} (69%) rename book/tests/snapshots/{snapshot__run_display_reference_prql@transforms__from_text-1.prql.snap => snapshot__run_display_reference_prql@language-features__standard-library__from-text-1.prql.snap} (76%) rename book/tests/snapshots/{snapshot__run_display_reference_prql@transforms__from_text-2.prql.snap => snapshot__run_display_reference_prql@language-features__standard-library__from-text-2.prql.snap} (82%) create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__standard-library__loop-0.prql.snap create mode 100644 prql-compiler/tests/integration/queries/loop.prql create mode 100644 prql-compiler/tests/integration/snapshots/integration__tests__test@loop.prql.snap diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f7a48567a3e..4a3c85b96daf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ **Features**: +- `loop`, which translates to `WITH RECURSIVE` (#1642, @aljazerzen) + **Fixes**: **Documentation**: diff --git a/book/README.md b/book/README.md index ec088b512dcb..57b803d93865 100644 --- a/book/README.md +++ b/book/README.md @@ -1,4 +1,4 @@ -# PRQL Language Book +# PRQL language book These docs serve as a language book, for users of the language. They should be friendly & accessible, at a minimum to those who understand basic SQL. diff --git a/book/book.toml b/book/book.toml index f503dc2bb7a9..8c10a1e4b368 100644 --- a/book/book.toml +++ b/book/book.toml @@ -2,7 +2,7 @@ description = "Modern language for transforming data — a simple, powerful, pipelined SQL replacement" language = "en" multilingual = false -title = "PRQL Language Book" +title = "PRQL language book" [output.html] additional-css = ["comparison-table.css", "mdbook-admonish.css"] diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md index 153e70bdb090..cc27566b74a2 100644 --- a/book/src/SUMMARY.md +++ b/book/src/SUMMARY.md @@ -36,7 +36,9 @@ - [Ranges](./language-features/ranges.md) - [Regex](./language-features/regex.md) - - [Stdlib](./language-features/standard-library.md) + - [Standard library](./language-features/standard-library/README.md) + - [From text](./language-features/standard-library/from-text.md) + - [Loop](./language-features/standard-library/loop.md) - [Strings](./language-features/strings.md) - [S-strings](./language-features/s-strings.md) - [F-strings](./language-features/f-strings.md) diff --git a/book/src/integrations/jupyter.md b/book/src/integrations/jupyter.md index 176a47ac11ad..7b0bdd3c063d 100644 --- a/book/src/integrations/jupyter.md +++ b/book/src/integrations/jupyter.md @@ -24,7 +24,7 @@ could to go! We bundle in `IPython` and `pandas`, though you'll need to install pip install pyprql ``` -### Set Up +### Set up Open up either an `IPython` terminal or `Jupyter` notebook. First, we need to load the extension and connect to a database. diff --git a/book/src/integrations/rill.md b/book/src/integrations/rill.md index 950e0b5fb50d..0e2f4729e32e 100644 --- a/book/src/integrations/rill.md +++ b/book/src/integrations/rill.md @@ -1,5 +1,5 @@ # Rill PRQL has had some work to integrate with Rill. See the -[Rill Issues](https://github.com/PRQL/prql/issues?q=is%3Aissue+rill) for more +[Rill ssues](https://github.com/PRQL/prql/issues?q=is%3Aissue+rill) for more details. diff --git a/book/src/internals/name-resolving.md b/book/src/internals/name-resolving.md index 74b590e93a14..78a153358959 100644 --- a/book/src/internals/name-resolving.md +++ b/book/src/internals/name-resolving.md @@ -50,7 +50,7 @@ three things can happen: ## Translating to SQL -When translating into a SQL statement which references only one table, there is +When translating into an SQL statement which references only one table, there is no need to reference column names with table prefix. ```prql diff --git a/book/src/language-features/standard-library.md b/book/src/language-features/standard-library/README.md similarity index 98% rename from book/src/language-features/standard-library.md rename to book/src/language-features/standard-library/README.md index 220565d5cf3d..1ccbbc5d92f8 100644 --- a/book/src/language-features/standard-library.md +++ b/book/src/language-features/standard-library/README.md @@ -1,4 +1,4 @@ -# Standard Library +# Standard library The standard library currently contains commonly used functions that are used in SQL. It's not yet as broad as we'd like, and we're very open to expanding it. diff --git a/book/src/language-features/standard-library/from-text.md b/book/src/language-features/standard-library/from-text.md new file mode 100644 index 000000000000..29229f6db0ef --- /dev/null +++ b/book/src/language-features/standard-library/from-text.md @@ -0,0 +1,63 @@ +# From text + +It's often useful to make a small table inline, for example when exploring how a +database will evaluate an expression, or to have a small lookup table inline. +This can be quite verbose in SQL. + +PRQL uses `from_text` for this. + +It accepts a few formats: + +- `format:csv` parses CSV (default), +- `format:json` parses either: + - an array of objects each of which represents a row, or + - an object with fields `columns` & `data`, where `columns` take an array of + column names and `data` takes an array of arrays. + +```prql +from_text """ +a,b,c +1,2,3 +4,5,6 +""" +derive [ + d = b + c, + answer = 20 * 2 + 2, +] +``` + +An example of adding a small lookup table: + +```prql +let temp_format_lookup = from_text format:csv """ +country_code,format +uk,C +us,F +lr,F +de,C +""" + +from temperatures +join temp_format_lookup [==country_code] +``` + +And JSON: + +```prql +let x = from_text format:json """{ + "columns": ["a", "b", "c"], + "data": [ + [1, "x", false], + [4, "y", null] + ] +}""" + +let y = from_text format:json """ + [ + {"a": 1, "m": "5"}, + {"a": 4, "n": "6"} + ] +""" + +from x | join y [==a] +``` diff --git a/book/src/language-features/standard-library/loop.md b/book/src/language-features/standard-library/loop.md new file mode 100644 index 000000000000..97f462a8b5cc --- /dev/null +++ b/book/src/language-features/standard-library/loop.md @@ -0,0 +1,50 @@ +# Loop + +> _experimental_ + +```prql_no_test +loop {step_function} {initial_relation} +``` + +Iteratively applies `step` function to `initial` relation until the `step` +returns an empty table. Returns a relation that contains rows of initial +relation and all intermediate relations. + +This behavior could be expressed with following pseudo-code: + +``` +def loop(step, initial): + result = [] + current = initial + while current is not empty: + result = append(result, current) + current = step(current) + + return result +``` + +## Examples + +```prql +from_text format:json '[{"n": 1 }]' +loop ( + filter n<4 + select n = n+1 +) + +# returns [1, 2, 3, 4] +``` + +```admonish +Behavior of WITH RECURSIVE may depend on database configuration (MySQL). +prql-compiler assumes behavior described by +[Postgres documentation](https://www.postgresql.org/docs/15/queries-with.html#QUERIES-WITH-RECURSIVE) +and will not produce correct results for +[alternative configurations of MySQL](https://dev.mysql.com/doc/refman/8.0/en/with.html#common-table-expressions-recursive). +``` + +```admonish +Currently, `loop` may produce references to the recursive CTE in sub-queries, +which is not supported by some database engines (SQLite). For now, we suggest you keep step +functions simple enough to fit into a single SELECT statement. +``` diff --git a/book/src/syntax.md b/book/src/syntax.md index 3c0afc5dd5b7..b23537228f4c 100644 --- a/book/src/syntax.md +++ b/book/src/syntax.md @@ -166,7 +166,7 @@ sort (-distance) sort [-distance] ``` -## Inner Transforms +## Inner transforms Parentheses are also used for transforms (such as `group` and `window`) that pass their result to an "inner transform". The example below applies the diff --git a/book/src/transforms/from_text.md b/book/src/transforms/from_text.md index 0a9b51160ca7..a05d2a4b011d 100644 --- a/book/src/transforms/from_text.md +++ b/book/src/transforms/from_text.md @@ -1,62 +1 @@ # From Text - -It's often useful to make a small table inline, for example when exploring how a -database will evaluate an expression, or to have a small lookup table inline. -This can be quite verbose in SQL. - -PRQL uses `from_text` for this. - -It accepts a few formats: - -- `format:csv`; also the default, for CSV. -- `format:json` for either: - - A list of dicts, - - or a schema of `columns` & `data>`. - -```prql -from_text """ -a,b,c -1,2,3 -4,5,6 -""" -derive [ - d = b + c, - answer = 20 * 2 + 2, -] -``` - -An example of adding a small lookup table: - -```prql -let temp_format_lookup = from_text format:csv """ -country_code,format -uk,C -us,F -lr,F -de,C -""" - -from temperatures -join temp_format_lookup [==country_code] -``` - -And JSON: - -```prql -let x = from_text format:json """{ - "columns": ["a", "b", "c"], - "data": [ - [1, "x", false], - [4, "y", null] - ] -}""" - -let y = from_text format:json """ - [ - {"a": 1, "m": "5"}, - {"a": 4, "n": "6"} - ] -""" - -from x | join y [==a] -``` diff --git a/book/tests/prql/language-features/standard-library-0.prql b/book/tests/prql/language-features/standard-library/README-0.prql similarity index 100% rename from book/tests/prql/language-features/standard-library-0.prql rename to book/tests/prql/language-features/standard-library/README-0.prql diff --git a/book/tests/prql/transforms/from_text-0.prql b/book/tests/prql/language-features/standard-library/from-text-0.prql similarity index 100% rename from book/tests/prql/transforms/from_text-0.prql rename to book/tests/prql/language-features/standard-library/from-text-0.prql diff --git a/book/tests/prql/transforms/from_text-1.prql b/book/tests/prql/language-features/standard-library/from-text-1.prql similarity index 100% rename from book/tests/prql/transforms/from_text-1.prql rename to book/tests/prql/language-features/standard-library/from-text-1.prql diff --git a/book/tests/prql/transforms/from_text-2.prql b/book/tests/prql/language-features/standard-library/from-text-2.prql similarity index 100% rename from book/tests/prql/transforms/from_text-2.prql rename to book/tests/prql/language-features/standard-library/from-text-2.prql diff --git a/book/tests/prql/language-features/standard-library/loop-0.prql b/book/tests/prql/language-features/standard-library/loop-0.prql new file mode 100644 index 000000000000..5dccfdba14ae --- /dev/null +++ b/book/tests/prql/language-features/standard-library/loop-0.prql @@ -0,0 +1,7 @@ +from_text format:json '[{"n": 1 }]' +loop ( + filter n<4 + select n = n+1 +) + +# returns [1, 2, 3, 4] diff --git a/book/tests/snapshots/snapshot__@examples__cte-0.prql.snap b/book/tests/snapshots/snapshot__@examples__cte-0.prql.snap index 5e55e6c27d2b..36a99fd31e3f 100644 --- a/book/tests/snapshots/snapshot__@examples__cte-0.prql.snap +++ b/book/tests/snapshots/snapshot__@examples__cte-0.prql.snap @@ -1,18 +1,9 @@ --- source: book/tests/snapshot.rs -expression: "table newest_employees = (\n from employees\n sort tenure\n take 50\n)\n\ntable average_salaries = (\n from salaries\n group country (\n aggregate average_country_salary = (average salary)\n )\n)\n\nfrom newest_employees\njoin average_salaries [==country]\nselect [name, salary, average_country_salary]\n" +expression: "let newest_employees = (\n from employees\n sort tenure\n take 50\n)\n\nlet average_salaries = (\n from salaries\n group country (\n aggregate average_country_salary = (average salary)\n )\n)\n\nfrom newest_employees\njoin average_salaries [==country]\nselect [name, salary, average_country_salary]\n" input_file: book/tests/prql/examples/cte-0.prql --- -WITH average_salaries AS ( - SELECT - country, - AVG(salary) AS average_country_salary - FROM - salaries - GROUP BY - country -), -newest_employees AS ( +WITH newest_employees AS ( SELECT * FROM @@ -21,6 +12,14 @@ newest_employees AS ( tenure LIMIT 50 +), average_salaries AS ( + SELECT + country, + AVG(salary) AS average_country_salary + FROM + salaries + GROUP BY + country ) SELECT newest_employees.name, @@ -29,3 +28,4 @@ SELECT FROM newest_employees JOIN average_salaries ON newest_employees.country = average_salaries.country + diff --git a/book/tests/snapshots/snapshot__@examples__employees-0.prql.snap b/book/tests/snapshots/snapshot__@examples__employees-0.prql.snap index 2ed2d4eba75e..47650f37675d 100644 --- a/book/tests/snapshots/snapshot__@examples__employees-0.prql.snap +++ b/book/tests/snapshots/snapshot__@examples__employees-0.prql.snap @@ -3,7 +3,7 @@ source: book/tests/snapshot.rs expression: "from salaries\ngroup [emp_no] (\n aggregate [emp_salary = average salary]\n)\njoin t=titles [==emp_no]\njoin dept_emp side:left [==emp_no]\ngroup [dept_emp.dept_no, t.title] (\n aggregate [avg_salary = average emp_salary]\n)\njoin departments [==dept_no]\nselect [dept_name, title, avg_salary]\n" input_file: book/tests/prql/examples/employees-0.prql --- -WITH table_1 AS ( +WITH table_3 AS ( SELECT AVG(salary) AS _expr_0, emp_no @@ -12,23 +12,24 @@ WITH table_1 AS ( GROUP BY emp_no ), -table_2 AS ( +table_1 AS ( SELECT t.title, - AVG(table_1._expr_0) AS avg_salary, + AVG(table_2._expr_0) AS avg_salary, dept_emp.dept_no FROM - table_1 - JOIN titles AS t ON table_1.emp_no = t.emp_no - LEFT JOIN dept_emp ON table_1.emp_no = dept_emp.emp_no + table_3 AS table_2 + JOIN titles AS t ON table_2.emp_no = t.emp_no + LEFT JOIN dept_emp ON table_2.emp_no = dept_emp.emp_no GROUP BY dept_emp.dept_no, t.title ) SELECT departments.dept_name, - table_2.title, - table_2.avg_salary + table_0.title, + table_0.avg_salary FROM - table_2 - JOIN departments ON table_2.dept_no = departments.dept_no + table_1 AS table_0 + JOIN departments ON table_0.dept_no = departments.dept_no + diff --git a/book/tests/snapshots/snapshot__@examples__employees-1.prql.snap b/book/tests/snapshots/snapshot__@examples__employees-1.prql.snap index 434d377e6067..88f00f10486c 100644 --- a/book/tests/snapshots/snapshot__@examples__employees-1.prql.snap +++ b/book/tests/snapshots/snapshot__@examples__employees-1.prql.snap @@ -3,7 +3,7 @@ source: book/tests/snapshot.rs expression: "from e=employees\njoin salaries [==emp_no]\ngroup [e.emp_no, e.gender] (\n aggregate [\n emp_salary = average salaries.salary\n ]\n)\njoin de=dept_emp [==emp_no] side:left\ngroup [de.dept_no, gender] (\n aggregate [\n salary_avg = average emp_salary,\n salary_sd = stddev emp_salary,\n ]\n)\njoin departments [==dept_no]\nselect [dept_name, gender, salary_avg, salary_sd]\n" input_file: book/tests/prql/examples/employees-1.prql --- -WITH table_1 AS ( +WITH table_3 AS ( SELECT e.gender, AVG(salaries.salary) AS _expr_0, @@ -15,24 +15,25 @@ WITH table_1 AS ( e.emp_no, e.gender ), -table_2 AS ( +table_1 AS ( SELECT - table_1.gender, - AVG(table_1._expr_0) AS salary_avg, - STDDEV(table_1._expr_0) AS salary_sd, + table_2.gender, + AVG(table_2._expr_0) AS salary_avg, + STDDEV(table_2._expr_0) AS salary_sd, de.dept_no FROM - table_1 - LEFT JOIN dept_emp AS de ON table_1.emp_no = de.emp_no + table_3 AS table_2 + LEFT JOIN dept_emp AS de ON table_2.emp_no = de.emp_no GROUP BY de.dept_no, - table_1.gender + table_2.gender ) SELECT departments.dept_name, - table_2.gender, - table_2.salary_avg, - table_2.salary_sd + table_0.gender, + table_0.salary_avg, + table_0.salary_sd FROM - table_2 - JOIN departments ON table_2.dept_no = departments.dept_no + table_1 AS table_0 + JOIN departments ON table_0.dept_no = departments.dept_no + diff --git a/book/tests/snapshots/snapshot__@examples__employees-2.prql.snap b/book/tests/snapshots/snapshot__@examples__employees-2.prql.snap index 6918730104c0..612ece4db0c6 100644 --- a/book/tests/snapshots/snapshot__@examples__employees-2.prql.snap +++ b/book/tests/snapshots/snapshot__@examples__employees-2.prql.snap @@ -3,7 +3,7 @@ source: book/tests/snapshot.rs expression: "from e=employees\njoin salaries [==emp_no]\ngroup [e.emp_no, e.gender] (\n aggregate [\n emp_salary = average salaries.salary\n ]\n)\njoin de=dept_emp [==emp_no]\njoin dm=dept_manager [\n (dm.dept_no == de.dept_no) and s\"(de.from_date, de.to_date) OVERLAPS (dm.from_date, dm.to_date)\"\n]\ngroup [dm.emp_no, gender] (\n aggregate [\n salary_avg = average emp_salary,\n salary_sd = stddev emp_salary\n ]\n)\nderive mng_no = emp_no\njoin managers=employees [==emp_no]\nderive mng_name = s\"managers.first_name || ' ' || managers.last_name\"\nselect [mng_name, managers.gender, salary_avg, salary_sd]\n" input_file: book/tests/prql/examples/employees-2.prql --- -WITH table_1 AS ( +WITH table_3 AS ( SELECT e.gender, AVG(salaries.salary) AS _expr_0, @@ -15,25 +15,26 @@ WITH table_1 AS ( e.emp_no, e.gender ), -table_2 AS ( +table_1 AS ( SELECT - AVG(table_1._expr_0) AS salary_avg, - STDDEV(table_1._expr_0) AS salary_sd, + AVG(table_2._expr_0) AS salary_avg, + STDDEV(table_2._expr_0) AS salary_sd, dm.emp_no FROM - table_1 - JOIN dept_emp AS de ON table_1.emp_no = de.emp_no + table_3 AS table_2 + JOIN dept_emp AS de ON table_2.emp_no = de.emp_no JOIN dept_manager AS dm ON dm.dept_no = de.dept_no AND (de.from_date, de.to_date) OVERLAPS (dm.from_date, dm.to_date) GROUP BY dm.emp_no, - table_1.gender + table_2.gender ) SELECT managers.first_name || ' ' || managers.last_name AS mng_name, managers.gender, - table_2.salary_avg, - table_2.salary_sd + table_0.salary_avg, + table_0.salary_sd FROM - table_2 - JOIN employees AS managers ON table_2.emp_no = managers.emp_no + table_1 AS table_0 + JOIN employees AS managers ON table_0.emp_no = managers.emp_no + diff --git a/book/tests/snapshots/snapshot__@examples__employees-3.prql.snap b/book/tests/snapshots/snapshot__@examples__employees-3.prql.snap index fa439fbf23c0..68c457076ef7 100644 --- a/book/tests/snapshots/snapshot__@examples__employees-3.prql.snap +++ b/book/tests/snapshots/snapshot__@examples__employees-3.prql.snap @@ -17,11 +17,12 @@ WITH table_1 AS ( de.dept_no ) SELECT - table_1.dept_no, - table_1.salary, + table_0.dept_no, + table_0.salary, employees.gender, titles.title FROM - table_1 - JOIN employees ON table_1.emp_no = employees.emp_no - JOIN titles ON table_1.emp_no = titles.emp_no + table_1 AS table_0 + JOIN employees ON table_0.emp_no = employees.emp_no + JOIN titles ON table_0.emp_no = titles.emp_no + diff --git a/book/tests/snapshots/snapshot__@examples__misc-0.prql.snap b/book/tests/snapshots/snapshot__@examples__misc-0.prql.snap index b12126c24dd3..676b3103af9c 100644 --- a/book/tests/snapshots/snapshot__@examples__misc-0.prql.snap +++ b/book/tests/snapshots/snapshot__@examples__misc-0.prql.snap @@ -1,15 +1,9 @@ --- source: book/tests/snapshot.rs -expression: "# TODO: this table should have a column `part` with values 1..5,\n# but such data declaration is not yet supported, see #286\ntable parts = (\n from seq_1_to_5\n)\n\nfrom pl=prospect_lists_prospects\nfilter prospect_list_id == 'cc675eee-8bd1-237f-be5e-622ba511d65e'\njoin a=accounts [a.id == pl.related_id]\njoin er=email_addr_bean_rel [er.bean_id == a.id and er.primary_address == '1']\njoin ea=email_addresses [ea.id == er.email_address_id]\nselect ea.email_address\nderive prefix = s\"regexp_replace(SUBSTRING_INDEX({email_address}, '@', 1), '[.0-9-_:]+', '.')\"\nderive stub = s\"SUBSTRING_INDEX(SUBSTRING_INDEX({prefix}, '.', part), '.', -1)\"\nselect [email_address, stub]\n" +expression: "# TODO: this table should have a column `part` with values 1..5,\n# but such data declaration is not yet supported, see #286\nlet parts = (\n from seq_1_to_5\n)\n\nfrom pl=prospect_lists_prospects\nfilter prospect_list_id == 'cc675eee-8bd1-237f-be5e-622ba511d65e'\njoin a=accounts [a.id == pl.related_id]\njoin er=email_addr_bean_rel [er.bean_id == a.id and er.primary_address == '1']\njoin ea=email_addresses [ea.id == er.email_address_id]\nselect ea.email_address\nderive prefix = s\"regexp_replace(SUBSTRING_INDEX({email_address}, '@', 1), '[.0-9-_:]+', '.')\"\nderive stub = s\"SUBSTRING_INDEX(SUBSTRING_INDEX({prefix}, '.', part), '.', -1)\"\nselect [email_address, stub]\n" input_file: book/tests/prql/examples/misc-0.prql --- -WITH parts AS ( - SELECT - * - FROM - seq_1_to_5 -), -table_1 AS ( +WITH table_1 AS ( SELECT related_id FROM @@ -33,8 +27,9 @@ SELECT -1 ) AS stub FROM - table_1 - JOIN accounts AS a ON a.id = table_1.related_id + table_1 AS table_0 + JOIN accounts AS a ON a.id = table_0.related_id JOIN email_addr_bean_rel AS er ON er.bean_id = a.id AND er.primary_address = '1' JOIN email_addresses AS ea ON ea.id = er.email_address_id + diff --git a/book/tests/snapshots/snapshot__@examples__variables-0.prql.snap b/book/tests/snapshots/snapshot__@examples__variables-0.prql.snap index 9f7411a758ba..69e10cb2c16d 100644 --- a/book/tests/snapshots/snapshot__@examples__variables-0.prql.snap +++ b/book/tests/snapshots/snapshot__@examples__variables-0.prql.snap @@ -26,7 +26,7 @@ SELECT SUM(_expr_0) AS sum_gross_cost, COUNT(*) AS ct FROM - table_1 + table_1 AS table_0 WHERE _expr_0 > 0 GROUP BY @@ -38,3 +38,4 @@ ORDER BY sum_gross_cost LIMIT 20 + diff --git a/book/tests/snapshots/snapshot__@examples__variables-1.prql.snap b/book/tests/snapshots/snapshot__@examples__variables-1.prql.snap index ea3da8460bb5..77b68ee0c7d1 100644 --- a/book/tests/snapshots/snapshot__@examples__variables-1.prql.snap +++ b/book/tests/snapshots/snapshot__@examples__variables-1.prql.snap @@ -13,12 +13,13 @@ WITH table_1 AS ( emp_no ) SELECT - AVG(table_1._expr_0) / 1000 AS salary_k, - AVG(table_1._expr_0) / 1000 * 1000 AS salary + AVG(table_0._expr_0) / 1000 AS salary_k, + AVG(table_0._expr_0) / 1000 * 1000 AS salary FROM - table_1 - JOIN titles ON table_1.emp_no = titles.emp_no + table_1 AS table_0 + JOIN titles ON table_0.emp_no = titles.emp_no GROUP BY titles.title LIMIT 10 + diff --git a/book/tests/snapshots/snapshot__@introduction-0.prql.snap b/book/tests/snapshots/snapshot__@introduction-0.prql.snap index 741163b2be4d..2cfecfb1a71d 100644 --- a/book/tests/snapshots/snapshot__@introduction-0.prql.snap +++ b/book/tests/snapshots/snapshot__@introduction-0.prql.snap @@ -1,6 +1,6 @@ --- source: book/tests/snapshot.rs -expression: "from employees\nfilter start_date > @2021-01-01 # Clear date syntax\nderive [ # `derive` adds columns / variables\n gross_salary = salary + (tax ?? 0), # Terse coalesce\n gross_cost = gross_salary + benefits_cost, # Variables can use other variables\n]\nfilter gross_cost > 0\ngroup [title, country] ( # `group` runs a pipeline over each group\n aggregate [ # `aggregate` reduces each group to a value\n average gross_salary,\n sum_gross_cost = sum gross_cost, # `=` sets a column name\n ]\n)\nfilter sum_gross_cost > 100_000 # `filter` replaces both of SQL's `WHERE` & `HAVING`\nderive id = f\"{title}_{country}\" # F-strings like python\nderive country_code = s\"LEFT(country, 2)\" # S-strings allow using SQL as an escape hatch\nsort [sum_gross_cost, -country] # `-country` means descending order\ntake 1..20 # Range expressions (also valid here as `take 20`)\n" +expression: "from employees\nfilter start_date > @2021-01-01 # Clear date syntax\nderive [ # `derive` adds columns / variables\n gross_salary = salary + (tax ?? 0), # Terse coalesce\n gross_cost = gross_salary + benefits_cost, # Variables can use other variables\n]\nfilter gross_cost > 0\ngroup [title, country] ( # `group` runs a pipeline over each group\n aggregate [ # `aggregate` reduces each group to a value\n average gross_salary,\n sum_gross_cost = sum gross_cost, # `=` sets a column name\n ]\n)\nfilter sum_gross_cost > 100_000 # `filter` replaces both of SQL's `WHERE` & `HAVING`\nderive id = f\"{title}_{country}\" # F-strings like Python\nderive country_code = s\"LEFT(country, 2)\" # S-strings allow using SQL as an escape hatch\nsort [sum_gross_cost, -country] # `-country` means descending order\ntake 1..20 # Range expressions (also valid here as `take 20`)\n" input_file: book/tests/prql/introduction-0.prql --- WITH table_1 AS ( @@ -22,7 +22,7 @@ SELECT CONCAT(title, '_', country) AS id, LEFT(country, 2) AS country_code FROM - table_1 + table_1 AS table_0 WHERE _expr_0 > 0 GROUP BY @@ -35,3 +35,4 @@ ORDER BY country DESC LIMIT 20 + diff --git a/book/tests/snapshots/snapshot__@language-features__distinct-2.prql.snap b/book/tests/snapshots/snapshot__@language-features__distinct-2.prql.snap index 2d9d6d5178f5..693c04dcf449 100644 --- a/book/tests/snapshots/snapshot__@language-features__distinct-2.prql.snap +++ b/book/tests/snapshots/snapshot__@language-features__distinct-2.prql.snap @@ -17,6 +17,7 @@ WITH table_1 AS ( SELECT * FROM - table_1 + table_1 AS table_0 WHERE _expr_0 <= 1 + diff --git a/book/tests/snapshots/snapshot__@language-features__s-strings-3.prql.snap b/book/tests/snapshots/snapshot__@language-features__s-strings-3.prql.snap index 3f5c880fd181..3d97e867fc17 100644 --- a/book/tests/snapshots/snapshot__@language-features__s-strings-3.prql.snap +++ b/book/tests/snapshots/snapshot__@language-features__s-strings-3.prql.snap @@ -3,7 +3,7 @@ source: book/tests/snapshot.rs expression: "from s\"SELECT DISTINCT ON first_name, id, age FROM employees ORDER BY age ASC\"\njoin s = s\"SELECT * FROM salaries\" [==id]\n" input_file: book/tests/prql/language-features/s-strings-3.prql --- -WITH table_2 AS ( +WITH table_0 AS ( SELECT DISTINCT ON first_name, id, @@ -13,15 +13,16 @@ WITH table_2 AS ( ORDER BY age ASC ), -table_3 AS ( +table_1 AS ( SELECT * FROM salaries ) SELECT - table_0.*, - table_1.* + table_2.*, + table_3.* FROM - table_2 AS table_0 - JOIN table_3 AS table_1 ON table_0.id = table_1.id + table_0 AS table_2 + JOIN table_1 AS table_3 ON table_2.id = table_3.id + diff --git a/book/tests/snapshots/snapshot__@language-features__standard-library-0.prql.snap b/book/tests/snapshots/snapshot__@language-features__standard-library__README-0.prql.snap similarity index 84% rename from book/tests/snapshots/snapshot__@language-features__standard-library-0.prql.snap rename to book/tests/snapshots/snapshot__@language-features__standard-library__README-0.prql.snap index 31e030d55e0b..b3a371283e07 100644 --- a/book/tests/snapshots/snapshot__@language-features__standard-library-0.prql.snap +++ b/book/tests/snapshots/snapshot__@language-features__standard-library__README-0.prql.snap @@ -1,7 +1,7 @@ --- source: book/tests/snapshot.rs expression: "from employees\nderive [\n gross_salary = (salary + payroll_tax | as int),\n gross_salary_rounded = (gross_salary | round 0),\n time = s\"NOW()\", # an s-string, given no `now` function exists in PRQL\n]\n" -input_file: book/tests/prql/language-features/standard-library-0.prql +input_file: book/tests/prql/language-features/standard-library/README-0.prql --- SELECT *, @@ -10,3 +10,4 @@ SELECT NOW() AS time FROM employees + diff --git a/book/tests/snapshots/snapshot__@transforms__from_text-0.prql.snap b/book/tests/snapshots/snapshot__@language-features__standard-library__from-text-0.prql.snap similarity index 73% rename from book/tests/snapshots/snapshot__@transforms__from_text-0.prql.snap rename to book/tests/snapshots/snapshot__@language-features__standard-library__from-text-0.prql.snap index 59de499b2072..904a45d549da 100644 --- a/book/tests/snapshots/snapshot__@transforms__from_text-0.prql.snap +++ b/book/tests/snapshots/snapshot__@language-features__standard-library__from-text-0.prql.snap @@ -1,9 +1,9 @@ --- source: book/tests/snapshot.rs expression: "from_text \"\"\"\na,b,c\n1,2,3\n4,5,6\n\"\"\"\nderive [\n d = b + c,\n answer = 20 * 2 + 2,\n]\n" -input_file: book/tests/prql/transforms/from_text-0.prql +input_file: book/tests/prql/language-features/standard-library/from-text-0.prql --- -WITH table_1 AS ( +WITH table_0 AS ( SELECT '1' AS a, '2' AS b, @@ -22,5 +22,5 @@ SELECT b + c AS d, 42 AS answer FROM - table_1 AS table_0 + table_0 AS table_1 diff --git a/book/tests/snapshots/snapshot__@transforms__from_text-1.prql.snap b/book/tests/snapshots/snapshot__@language-features__standard-library__from-text-1.prql.snap similarity index 90% rename from book/tests/snapshots/snapshot__@transforms__from_text-1.prql.snap rename to book/tests/snapshots/snapshot__@language-features__standard-library__from-text-1.prql.snap index 9ae070f052eb..670e58dfc204 100644 --- a/book/tests/snapshots/snapshot__@transforms__from_text-1.prql.snap +++ b/book/tests/snapshots/snapshot__@language-features__standard-library__from-text-1.prql.snap @@ -1,7 +1,7 @@ --- source: book/tests/snapshot.rs expression: "let temp_format_lookup = from_text format:csv \"\"\"\ncountry_code,format\nuk,C\nus,F\nlr,F\nde,C\n\"\"\"\n\nfrom temperatures\njoin temp_format_lookup [==country_code]\n" -input_file: book/tests/prql/transforms/from_text-1.prql +input_file: book/tests/prql/language-features/standard-library/from-text-1.prql --- WITH table_0 AS ( SELECT diff --git a/book/tests/snapshots/snapshot__@transforms__from_text-2.prql.snap b/book/tests/snapshots/snapshot__@language-features__standard-library__from-text-2.prql.snap similarity index 91% rename from book/tests/snapshots/snapshot__@transforms__from_text-2.prql.snap rename to book/tests/snapshots/snapshot__@language-features__standard-library__from-text-2.prql.snap index 085bbccf68f8..becf706977bb 100644 --- a/book/tests/snapshots/snapshot__@transforms__from_text-2.prql.snap +++ b/book/tests/snapshots/snapshot__@language-features__standard-library__from-text-2.prql.snap @@ -1,7 +1,7 @@ --- source: book/tests/snapshot.rs expression: "let x = from_text format:json \"\"\"{\n \"columns\": [\"a\", \"b\", \"c\"],\n \"data\": [\n [1, \"x\", false],\n [4, \"y\", null]\n ]\n}\"\"\"\n\nlet y = from_text format:json \"\"\"\n [\n {\"a\": 1, \"m\": \"5\"},\n {\"a\": 4, \"n\": \"6\"}\n ]\n\"\"\"\n\nfrom x | join y [==a]\n" -input_file: book/tests/prql/transforms/from_text-2.prql +input_file: book/tests/prql/language-features/standard-library/from-text-2.prql --- WITH table_0 AS ( SELECT diff --git a/book/tests/snapshots/snapshot__@language-features__standard-library__loop-0.prql.snap b/book/tests/snapshots/snapshot__@language-features__standard-library__loop-0.prql.snap new file mode 100644 index 000000000000..5515357a6c0c --- /dev/null +++ b/book/tests/snapshots/snapshot__@language-features__standard-library__loop-0.prql.snap @@ -0,0 +1,34 @@ +--- +source: book/tests/snapshot.rs +expression: "from_text format:json '[{\"n\": 1 }]'\nloop (\n filter n<4\n select n = n+1\n)\n\n# returns [1, 2, 3, 4]\n" +input_file: book/tests/prql/language-features/standard-library/loop-0.prql +--- +WITH table_0 AS ( + SELECT + 1 AS n +), +table_4 AS ( + WITH RECURSIVE loop AS ( + SELECT + n + FROM + table_0 AS table_1 + UNION + ALL + SELECT + n + 1 + FROM + loop AS table_2 + WHERE + n < 4 + ) + SELECT + * + FROM + loop +) +SELECT + n +FROM + table_4 AS table_3 + diff --git a/book/tests/snapshots/snapshot__@queries__pipelines-2.prql.snap b/book/tests/snapshots/snapshot__@queries__pipelines-2.prql.snap index 48c578cb780a..8a7e0fd99bc5 100644 --- a/book/tests/snapshots/snapshot__@queries__pipelines-2.prql.snap +++ b/book/tests/snapshots/snapshot__@queries__pipelines-2.prql.snap @@ -16,9 +16,10 @@ WITH table_1 AS ( 10 ) SELECT - table_1.name, - table_1.gross_salary, + table_0.name, + table_0.gross_salary, d.name FROM - table_1 - JOIN department AS d ON table_1.dept_no = d.dept_no + table_1 AS table_0 + JOIN department AS d ON table_0.dept_no = d.dept_no + diff --git a/book/tests/snapshots/snapshot__@queries__variables-0.prql.snap b/book/tests/snapshots/snapshot__@queries__variables-0.prql.snap index e37a88722453..ca97469b4749 100644 --- a/book/tests/snapshots/snapshot__@queries__variables-0.prql.snap +++ b/book/tests/snapshots/snapshot__@queries__variables-0.prql.snap @@ -3,7 +3,7 @@ source: book/tests/snapshot.rs expression: "let top_50 = (\n from employees\n sort salary\n take 50\n aggregate [total_salary = sum salary]\n)\n\nfrom top_50 # Starts a new pipeline\n" input_file: book/tests/prql/queries/variables-0.prql --- -WITH table_0 AS ( +WITH table_1 AS ( SELECT salary FROM @@ -16,7 +16,7 @@ WITH table_0 AS ( SELECT SUM(salary) AS total_salary FROM - table_0 + table_1 AS table_0 ) SELECT total_salary diff --git a/book/tests/snapshots/snapshot__@syntax-5.prql.snap b/book/tests/snapshots/snapshot__@syntax-5.prql.snap index 374cbd663cf3..9095768d6603 100644 --- a/book/tests/snapshots/snapshot__@syntax-5.prql.snap +++ b/book/tests/snapshots/snapshot__@syntax-5.prql.snap @@ -14,7 +14,8 @@ SELECT circumference, color FROM - table_1 + table_1 AS table_0 WHERE circumference > 10 AND color <> 'red' + diff --git a/book/tests/snapshots/snapshot__@transforms__group-2.prql.snap b/book/tests/snapshots/snapshot__@transforms__group-2.prql.snap index a11503ab56c8..03289443cc04 100644 --- a/book/tests/snapshots/snapshot__@transforms__group-2.prql.snap +++ b/book/tests/snapshots/snapshot__@transforms__group-2.prql.snap @@ -17,6 +17,7 @@ WITH table_1 AS ( SELECT * FROM - table_1 + table_1 AS table_0 WHERE _expr_0 <= 1 + diff --git a/book/tests/snapshots/snapshot__@transforms__sort-3.prql.snap b/book/tests/snapshots/snapshot__@transforms__sort-3.prql.snap index 7b6e784e1da0..fb7acd653ec6 100644 --- a/book/tests/snapshots/snapshot__@transforms__sort-3.prql.snap +++ b/book/tests/snapshots/snapshot__@transforms__sort-3.prql.snap @@ -3,16 +3,11 @@ source: book/tests/snapshot.rs expression: "from employees\nsort [s\"substr({first_name}, 2, 5)\"]\n" input_file: book/tests/prql/transforms/sort-3.prql --- -WITH table_1 AS ( - SELECT - *, - substr(first_name, 2, 5) AS _expr_0 - FROM - employees - ORDER BY - _expr_0 -) SELECT - * + *, + substr(first_name, 2, 5) AS _expr_0 FROM - table_1 + employees +ORDER BY + _expr_0 + diff --git a/book/tests/snapshots/snapshot__@transforms__sort-5.prql.snap b/book/tests/snapshots/snapshot__@transforms__sort-5.prql.snap index de8d52ca5f42..b969c19b2a4d 100644 --- a/book/tests/snapshots/snapshot__@transforms__sort-5.prql.snap +++ b/book/tests/snapshots/snapshot__@transforms__sort-5.prql.snap @@ -12,8 +12,9 @@ WITH table_1 AS ( tenure ) SELECT - table_1.*, + table_0.*, locations.* FROM - table_1 - JOIN locations ON table_1.employee_id = locations.employee_id + table_1 AS table_0 + JOIN locations ON table_0.employee_id = locations.employee_id + diff --git a/book/tests/snapshots/snapshot__@transforms__window-4.prql.snap b/book/tests/snapshots/snapshot__@transforms__window-4.prql.snap index 13bb14a01bc7..0dcf1866c987 100644 --- a/book/tests/snapshots/snapshot__@transforms__window-4.prql.snap +++ b/book/tests/snapshots/snapshot__@transforms__window-4.prql.snap @@ -13,6 +13,7 @@ WITH table_1 AS ( SELECT * FROM - table_1 + table_1 AS table_0 WHERE salary < _expr_0 + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__standard-library-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__standard-library__README-0.prql.snap similarity index 76% rename from book/tests/snapshots/snapshot__run_display_reference_prql@language-features__standard-library-0.prql.snap rename to book/tests/snapshots/snapshot__run_display_reference_prql@language-features__standard-library__README-0.prql.snap index 691cabab4a62..7103d173bb5b 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__standard-library-0.prql.snap +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__standard-library__README-0.prql.snap @@ -1,7 +1,7 @@ --- source: book/tests/snapshot.rs expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/standard-library-0.prql +input_file: book/tests/prql/language-features/standard-library/README-0.prql --- from employees derive [ diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from_text-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__standard-library__from-text-0.prql.snap similarity index 69% rename from book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from_text-0.prql.snap rename to book/tests/snapshots/snapshot__run_display_reference_prql@language-features__standard-library__from-text-0.prql.snap index d86f2e1e86bb..f5eae06d50c6 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from_text-0.prql.snap +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__standard-library__from-text-0.prql.snap @@ -1,7 +1,7 @@ --- source: book/tests/snapshot.rs expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/from_text-0.prql +input_file: book/tests/prql/language-features/standard-library/from-text-0.prql --- from_text " a,b,c diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from_text-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__standard-library__from-text-1.prql.snap similarity index 76% rename from book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from_text-1.prql.snap rename to book/tests/snapshots/snapshot__run_display_reference_prql@language-features__standard-library__from-text-1.prql.snap index 740349748e00..8dcf2f21faac 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from_text-1.prql.snap +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__standard-library__from-text-1.prql.snap @@ -1,7 +1,7 @@ --- source: book/tests/snapshot.rs expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/from_text-1.prql +input_file: book/tests/prql/language-features/standard-library/from-text-1.prql --- let temp_format_lookup = ( from_text format:csv " diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from_text-2.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__standard-library__from-text-2.prql.snap similarity index 82% rename from book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from_text-2.prql.snap rename to book/tests/snapshots/snapshot__run_display_reference_prql@language-features__standard-library__from-text-2.prql.snap index a0aaabe15cb7..13b437d66562 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from_text-2.prql.snap +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__standard-library__from-text-2.prql.snap @@ -1,7 +1,7 @@ --- source: book/tests/snapshot.rs expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/from_text-2.prql +input_file: book/tests/prql/language-features/standard-library/from-text-2.prql --- let x = ( from_text format:json '{ diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__standard-library__loop-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__standard-library__loop-0.prql.snap new file mode 100644 index 000000000000..b039f259620b --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__standard-library__loop-0.prql.snap @@ -0,0 +1,13 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/language-features/standard-library/loop-0.prql +--- +from_text format:json '[{"n": 1 }]' +loop ( + filter n < 4 + select n = n + 1 +) + + + diff --git a/prql-compiler/src/ast/pl/expr.rs b/prql-compiler/src/ast/pl/expr.rs index ea3dc6f0a7b7..a3b0b7b9132c 100644 --- a/prql-compiler/src/ast/pl/expr.rs +++ b/prql-compiler/src/ast/pl/expr.rs @@ -310,6 +310,7 @@ pub enum TransformKind { pipeline: Box, }, Append(Box), + Loop(Box), } #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] diff --git a/prql-compiler/src/ast/pl/fold.rs b/prql-compiler/src/ast/pl/fold.rs index 3af403b8525d..b82f9178a296 100644 --- a/prql-compiler/src/ast/pl/fold.rs +++ b/prql-compiler/src/ast/pl/fold.rs @@ -273,6 +273,7 @@ pub fn fold_transform_kind( range: fold_range(fold, range)?, pipeline: Box::new(fold.fold_expr(*pipeline)?), }, + Loop(pipeline) => Loop(Box::new(fold.fold_expr(*pipeline)?)), }) } diff --git a/prql-compiler/src/ast/pl/types.rs b/prql-compiler/src/ast/pl/types.rs index 3d4c428d5d75..cb1463940c7b 100644 --- a/prql-compiler/src/ast/pl/types.rs +++ b/prql-compiler/src/ast/pl/types.rs @@ -6,7 +6,7 @@ use serde::{Deserialize, Serialize}; use super::Frame; -#[derive(Clone, PartialEq, Serialize, Deserialize, EnumAsInner)] +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, EnumAsInner)] pub enum Ty { Empty, Literal(TyLit), @@ -162,9 +162,3 @@ impl Display for Ty { } } } - -impl Debug for Ty { - fn fmt(&self, f: &mut Formatter<'_>) -> Result { - Display::fmt(self, f) - } -} diff --git a/prql-compiler/src/ast/rq/fold.rs b/prql-compiler/src/ast/rq/fold.rs index d84d6385ba37..1c799e35dfe0 100644 --- a/prql-compiler/src/ast/rq/fold.rs +++ b/prql-compiler/src/ast/rq/fold.rs @@ -187,6 +187,7 @@ pub fn fold_transform( filter: fold.fold_expr(filter)?, }, Append(bottom) => Append(fold.fold_table_ref(bottom)?), + Loop(transforms) => Loop(fold_transforms(fold, transforms)?), }; Ok(transform) } diff --git a/prql-compiler/src/ast/rq/transform.rs b/prql-compiler/src/ast/rq/transform.rs index 7a946e1d2c13..875bc3d922b6 100644 --- a/prql-compiler/src/ast/rq/transform.rs +++ b/prql-compiler/src/ast/rq/transform.rs @@ -25,6 +25,7 @@ pub enum Transform { filter: Expr, }, Append(TableRef), + Loop(Vec), } #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] diff --git a/prql-compiler/src/semantic/lowering.rs b/prql-compiler/src/semantic/lowering.rs index bb595dd20da0..25383b9dd744 100644 --- a/prql-compiler/src/semantic/lowering.rs +++ b/prql-compiler/src/semantic/lowering.rs @@ -269,7 +269,7 @@ impl Lowerer { let ty = expr.ty.clone(); let prev_pipeline = self.pipeline.drain(..).collect_vec(); - self.lower_pipeline(expr)?; + self.lower_pipeline(expr, None)?; let mut transforms = self.pipeline.drain(..).collect_vec(); let columns = self.push_select(ty, &mut transforms)?; @@ -284,10 +284,22 @@ impl Lowerer { } // Result is stored in self.pipeline - fn lower_pipeline(&mut self, ast: pl::Expr) -> Result<()> { + fn lower_pipeline(&mut self, ast: pl::Expr, closure_param: Option) -> Result<()> { let transform_call = match ast.kind { pl::ExprKind::TransformCall(transform) => transform, + pl::ExprKind::Closure(closure) => { + let param = closure.params.first(); + let param = param.and_then(|p| p.name.parse::().ok()); + return self.lower_pipeline(*closure.body, param); + } _ => { + if let Some(target) = ast.target_id { + if Some(target) == closure_param { + // ast is a closure param, so we can skip pushing From + return Ok(()); + } + } + let table_ref = self.lower_table_ref(ast)?; self.pipeline.push(Transform::From(table_ref)); return Ok(()); @@ -295,7 +307,7 @@ impl Lowerer { }; // lower input table - self.lower_pipeline(*transform_call.input)?; + self.lower_pipeline(*transform_call.input, closure_param)?; // ... and continues with transforms created in this function @@ -362,8 +374,16 @@ impl Lowerer { pl::TransformKind::Append(bottom) => { let bottom = self.lower_table_ref(*bottom)?; - let transform = Transform::Append(bottom); - self.pipeline.push(transform); + self.pipeline.push(Transform::Append(bottom)); + } + pl::TransformKind::Loop(pipeline) => { + let relation = self.lower_relation(*pipeline)?; + let mut pipeline = relation.kind.into_pipeline().unwrap(); + + // last select is not needed here + pipeline.pop(); + + self.pipeline.push(Transform::Loop(pipeline)); } pl::TransformKind::Group { .. } | pl::TransformKind::Window { .. } => unreachable!( "transform `{}` cannot be lowered.", @@ -680,9 +700,10 @@ impl Lowerer { let name = match name { Some(v) => RelationColumn::Single(Some(v.clone())), None => return Err(Error::new_simple( - "This table contains unnamed columns, that need to be referenced by name", + "This table contains unnamed columns that need to be referenced by name", ) .with_span(self.context.span_map.get(&id).cloned()) + .with_help("The name may have been overridden later in the pipeline.") .into()), }; log::trace!("lookup cid of name={name:?} in input {input_columns:?}"); diff --git a/prql-compiler/src/semantic/std.prql b/prql-compiler/src/semantic/std.prql index f906e2dc7b23..586a9dcaf94f 100644 --- a/prql-compiler/src/semantic/std.prql +++ b/prql-compiler/src/semantic/std.prql @@ -48,6 +48,7 @@ func remove `default_db.bottom`
top
-> ( filter (all (map _is_null b.*)) select t.* ) +func loop
pipeline top
-> null # List functions func all list -> null diff --git a/prql-compiler/src/semantic/transforms.rs b/prql-compiler/src/semantic/transforms.rs index b517b2a81c33..15c73cbbe44f 100644 --- a/prql-compiler/src/semantic/transforms.rs +++ b/prql-compiler/src/semantic/transforms.rs @@ -192,6 +192,13 @@ pub fn cast_transform(resolver: &mut Resolver, closure: Closure) -> Result { + let [pipeline, tbl] = unpack::<2>(closure); + + let pipeline = fold_by_simulating_eval(resolver, pipeline, tbl.ty.clone().unwrap())?; + + (TransformKind::Loop(Box::new(pipeline)), tbl) + } "std.in" => { // yes, this is not a transform, but this is the most appropriate place for it @@ -582,6 +589,7 @@ impl TransformCall { let bottom = ty_frame_or_default(bottom)?; append(top, bottom)? } + Loop(_) => ty_frame_or_default(&self.input)?, Sort { .. } | Filter { .. } | Take { .. } => ty_frame_or_default(&self.input)?, }) } diff --git a/prql-compiler/src/snapshots/prql_compiler__test__prql_to_sql_2.snap b/prql-compiler/src/snapshots/prql_compiler__test__prql_to_sql_2.snap index bbc44298cbb5..23a1cc2ad749 100644 --- a/prql-compiler/src/snapshots/prql_compiler__test__prql_to_sql_2.snap +++ b/prql-compiler/src/snapshots/prql_compiler__test__prql_to_sql_2.snap @@ -25,7 +25,7 @@ SELECT SUM(_expr_0) AS sum_gross_cost, COUNT(*) AS ct FROM - table_1 + table_1 AS table_0 WHERE _expr_0 > 0 GROUP BY @@ -37,3 +37,4 @@ ORDER BY sum_gross_cost LIMIT 20 + diff --git a/prql-compiler/src/sql/anchor.rs b/prql-compiler/src/sql/anchor.rs index 6740cd2cc391..4c0e0ece9b76 100644 --- a/prql-compiler/src/sql/anchor.rs +++ b/prql-compiler/src/sql/anchor.rs @@ -3,28 +3,28 @@ use itertools::Itertools; use std::collections::{HashMap, HashSet}; use crate::ast::rq::{ - self, fold_transform, CId, Compute, Expr, Relation, RelationColumn, RelationKind, RqFold, - TableDecl, TableRef, Transform, + self, fold_transform, CId, Compute, Expr, RelationColumn, RqFold, TableRef, Transform, }; +use crate::sql::context::SqlTableDecl; +use crate::sql::preprocess::{SqlRelation, SqlRelationKind}; use super::{ context::{AnchorContext, ColumnDecl}, preprocess::{SqlFold, SqlTransform}, }; -type RemainingPipeline = (Vec, Vec); - /// Splits pipeline into two parts, such that the second part contains /// maximum number of transforms while "fitting" into a SELECT query. pub(super) fn split_off_back( - ctx: &mut AnchorContext, - output: Vec, mut pipeline: Vec, -) -> (Option, Vec) { + ctx: &mut AnchorContext, +) -> (Option>, Vec) { if pipeline.is_empty() { return (None, Vec::new()); } + let output = AnchorContext::determine_select_columns(&pipeline); + log::debug!("traversing pipeline to obtain columns: {output:?}"); let mut following_transforms: HashSet = HashSet::new(); @@ -137,8 +137,9 @@ pub(super) fn split_off_back( None } else { // drop inputs that were satisfied in current pipeline + pipeline.push(SqlTransform::Super(Transform::Select(missing))); - Some((pipeline, missing)) + Some(pipeline) }; curr_pipeline_rev.reverse(); @@ -166,20 +167,23 @@ fn can_materialize(compute: &Compute, inputs_required: &[Requirement]) -> bool { } /// Applies adjustments to second part of a pipeline when it's split: -/// - prepend pipeline with From -/// - redefine columns materialized in preceding pipeline +/// - append Select to proceeding pipeline +/// - prepend From to atomic pipeline +/// - redefine columns materialized in atomic pipeline /// - redirect all references to original columns to the new ones pub(super) fn anchor_split( ctx: &mut AnchorContext, - first_table_name: &str, - cols_at_split: &[CId], - second_pipeline: Vec, + preceding: Vec, + atomic: Vec, ) -> Vec { let new_tid = ctx.tid.gen(); + let preceding_select = &preceding.last().unwrap().as_super().unwrap(); + let cols_at_split = preceding_select.as_select().unwrap(); + log::debug!("split pipeline, first pipeline output: {cols_at_split:?}"); - // define columns of the new CTE + // redefine columns of the atomic pipeline let mut cid_redirects = HashMap::::new(); let mut new_columns = Vec::new(); for old_cid in cols_at_split { @@ -204,32 +208,31 @@ pub(super) fn anchor_split( // define a new table ctx.table_decls.insert( new_tid, - TableDecl { + SqlTableDecl { id: new_tid, - name: Some(first_table_name.to_string()), - // here we should put the pipeline, but because how this function is called, - // we need to return the pipeline directly, so we just insert dummy expr instead - relation: Relation { - kind: RelationKind::SString(vec![]), - columns: vec![], - }, + name: None, + relation: Some(SqlRelation { + columns: cols_at_split + .iter() + .map(|_| RelationColumn::Single(None)) + .collect_vec(), + kind: SqlRelationKind::PreprocessedPipeline(preceding), + }), }, ); // define instance of that table - let table_ref = TableRef { + let table_ref = ctx.create_table_instance(TableRef { source: new_tid, - name: Some(first_table_name.to_string()), + name: None, columns: new_columns, - }; - ctx.create_table_instance(table_ref.clone()); + }); // adjust second part: prepend from and rewrite expressions to use new columns - let mut second = second_pipeline; + let mut second = atomic; second.insert(0, SqlTransform::Super(Transform::From(table_ref))); - let mut redirector = CidRedirector { ctx, cid_redirects }; - redirector.fold_sql_transforms(second).unwrap() + CidRedirector::redirect(second, cid_redirects, ctx) } /// Determines whether a pipeline must be split at a transform to @@ -248,6 +251,7 @@ fn is_split_required(transform: &SqlTransform, following: &mut HashSet) // - take (no limit) // - distinct // - append/except/intersect (no limit) + // - loop (max 1x) // // Select is not affected by the order. use SqlTransform::*; @@ -306,6 +310,7 @@ fn is_split_required(transform: &SqlTransform, following: &mut HashSet) "Distinct", ], ), + SqlTransform::Loop(_) => !following.is_empty(), _ => false, }; @@ -387,12 +392,13 @@ pub(super) fn get_requirements( cids } - Super(Append(_)) => unreachable!(), - Super(Select(_) | From(_) | Aggregate { .. }) + Super(Aggregate { .. } | Append(_) | Transform::Loop(_)) => unreachable!(), + Super(Select(_) | From(_)) | Distinct | Union { .. } | Except { .. } - | Intersect { .. } => return Vec::new(), + | Intersect { .. } + | SqlTransform::Loop(_) => return Vec::new(), }; // general case: determine complexity @@ -502,9 +508,20 @@ impl RqFold for CidCollector { } } -struct CidRedirector<'a> { - ctx: &'a mut AnchorContext, - cid_redirects: HashMap, +pub(super) struct CidRedirector<'a> { + pub ctx: &'a mut AnchorContext, + pub cid_redirects: HashMap, +} + +impl<'a> CidRedirector<'a> { + pub fn redirect( + pipeline: Vec, + cid_redirects: HashMap, + ctx: &mut AnchorContext, + ) -> Vec { + let mut redirector = CidRedirector { ctx, cid_redirects }; + redirector.fold_sql_transforms(pipeline).unwrap() + } } impl<'a> RqFold for CidRedirector<'a> { diff --git a/prql-compiler/src/sql/context.rs b/prql-compiler/src/sql/context.rs index 4fa41ea51e71..b9b38e1ae2bf 100644 --- a/prql-compiler/src/sql/context.rs +++ b/prql-compiler/src/sql/context.rs @@ -10,19 +10,19 @@ use itertools::Itertools; use crate::ast::pl::TableExternRef; use crate::ast::rq::{ - fold_table, CId, Compute, Query, RelationColumn, RelationKind, RqFold, TId, TableDecl, - TableRef, Transform, + fold_table, CId, Compute, Query, Relation, RelationColumn, RelationKind, RqFold, TId, + TableDecl, TableRef, Transform, }; use crate::utils::{IdGenerator, NameGenerator}; -use super::preprocess::SqlTransform; +use super::preprocess::{SqlRelation, SqlTransform}; #[derive(Default)] pub struct AnchorContext { pub(super) column_decls: HashMap, pub(super) column_names: HashMap, - pub(super) table_decls: HashMap, + pub(super) table_decls: HashMap, pub(super) table_instances: HashMap, @@ -33,6 +33,20 @@ pub struct AnchorContext { pub(super) tid: IdGenerator, pub(super) tiid: IdGenerator, } + +#[derive(Debug, Clone)] +pub(super) struct SqlTableDecl { + #[allow(dead_code)] + pub id: TId, + + pub name: Option, + + /// Relation that still needs to be defined (usually as CTE) so it can be referenced by name. + /// None means that it has already been defined, or was not needed to be defined in the + /// first place. + pub relation: Option, +} + /// Table instance id #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct TIId(usize); @@ -51,7 +65,7 @@ pub enum ColumnDecl { } impl AnchorContext { - pub fn of(query: Query) -> (Self, Query) { + pub fn of(query: Query) -> (Self, Relation) { let (cid, tid, query) = IdGenerator::load(query); let context = AnchorContext { @@ -78,7 +92,7 @@ impl AnchorContext { self.column_decls.insert(id, decl); } - pub fn create_table_instance(&mut self, mut table_ref: TableRef) { + pub fn create_table_instance(&mut self, mut table_ref: TableRef) -> TableRef { let tiid = self.tiid.gen(); for (col, cid) in &table_ref.columns { @@ -90,7 +104,8 @@ impl AnchorContext { table_ref.name = Some(self.table_name.gen()) } - self.table_instances.insert(tiid, table_ref); + self.table_instances.insert(tiid, table_ref.clone()); + table_ref } pub(crate) fn ensure_column_name(&mut self, cid: CId) -> Option<&String> { @@ -193,29 +208,45 @@ struct QueryLoader { } impl QueryLoader { - fn load(context: AnchorContext, query: Query) -> (AnchorContext, Query) { + fn load(context: AnchorContext, query: Query) -> (AnchorContext, Relation) { let mut loader = QueryLoader { context }; - let query = loader.fold_query(query).unwrap(); - (loader.context, query) + + for t in query.tables { + loader.load_table(t).unwrap(); + } + let relation = loader.fold_relation(query.relation).unwrap(); + (loader.context, relation) } -} -impl RqFold for QueryLoader { - fn fold_table(&mut self, table: TableDecl) -> Result { + fn load_table(&mut self, table: TableDecl) -> Result<()> { let mut decl = fold_table(self, table)?; + // assume name of the LocalTable that the relation is referencing if let RelationKind::ExternRef(TableExternRef::LocalTable(table)) = &decl.relation.kind { decl.name = Some(table.clone()); } + // generate name (if not present) if decl.name.is_none() && decl.relation.kind.as_extern_ref().is_none() { decl.name = Some(self.context.table_name.gen()); } - self.context.table_decls.insert(decl.id, decl.clone()); - Ok(decl) + let sql_decl = SqlTableDecl { + id: decl.id, + name: decl.name, + relation: if matches!(decl.relation.kind, RelationKind::ExternRef(_)) { + None + } else { + Some(decl.relation.into()) + }, + }; + + self.context.table_decls.insert(decl.id, sql_decl); + Ok(()) } +} +impl RqFold for QueryLoader { fn fold_compute(&mut self, compute: Compute) -> Result { self.context.register_compute(compute.clone()); Ok(compute) diff --git a/prql-compiler/src/sql/gen_expr.rs b/prql-compiler/src/sql/gen_expr.rs index 44fd67901dbe..7806cf9b70a4 100644 --- a/prql-compiler/src/sql/gen_expr.rs +++ b/prql-compiler/src/sql/gen_expr.rs @@ -6,8 +6,7 @@ use lazy_static::lazy_static; use regex::Regex; use sqlparser::ast::{ self as sql_ast, BinaryOperator, DateTimeField, Function, FunctionArg, FunctionArgExpr, Ident, - Join, JoinConstraint, JoinOperator, ObjectName, OrderByExpr, SelectItem, TableAlias, - TableFactor, Top, UnaryOperator, Value, WindowFrameBound, WindowSpec, + ObjectName, OrderByExpr, SelectItem, Top, UnaryOperator, Value, WindowFrameBound, WindowSpec, }; use sqlparser::keywords::{ Keyword, ALL_KEYWORDS, ALL_KEYWORDS_INDEX, RESERVED_FOR_COLUMN_ALIAS, RESERVED_FOR_TABLE_ALIAS, @@ -15,8 +14,7 @@ use sqlparser::keywords::{ use std::collections::HashSet; use crate::ast::pl::{ - BinOp, ColumnSort, InterpolateItem, JoinSide, Literal, Range, SortDirection, TableExternRef, - WindowFrame, WindowKind, + BinOp, ColumnSort, InterpolateItem, Literal, Range, SortDirection, WindowFrame, WindowKind, }; use crate::ast::rq::*; use crate::error::{Error, Span}; @@ -187,7 +185,7 @@ pub(super) fn translate_literal(l: Literal, ctx: &Context) -> Result Result { - if ctx.pre_projection { + if ctx.query.pre_projection { log::debug!("translating {cid:?} pre projection"); let decl = ctx.anchor.column_decls.get(&cid).expect("bad RQ ids"); @@ -231,7 +229,7 @@ pub(super) fn translate_cid(cid: CId, ctx: &mut Context) -> Result { let name = ctx.anchor.column_names.get(&cid).cloned(); - name.expect("a name of this column to be set before generating SQL") + name.expect("name of this column has not been to be set before generating SQL") } }; @@ -244,38 +242,6 @@ pub(super) fn translate_cid(cid: CId, ctx: &mut Context) -> Result TableFactor { - let decl = ctx.anchor.table_decls.get(&table_ref.source).unwrap(); - - let name = match &decl.relation.kind { - // special case for anchor - RelationKind::ExternRef(TableExternRef::Anchor(anchor_id)) => { - sql_ast::ObjectName(vec![Ident::new(anchor_id.clone())]) - } - - // base case - _ => { - let decl_name = decl.name.clone().unwrap(); - - sql_ast::ObjectName(translate_ident(Some(decl_name), None, ctx)) - } - }; - - TableFactor::Table { - name, - alias: if decl.name == table_ref.name { - None - } else { - table_ref.name.map(|ident| TableAlias { - name: translate_ident_part(ident, ctx), - columns: vec![], - }) - }, - args: None, - with_hints: vec![], - } -} - pub(super) fn translate_sstring( items: Vec>, ctx: &mut Context, @@ -623,23 +589,6 @@ pub(super) fn translate_column_sort( }) } -pub(super) fn translate_join( - (side, with, filter): (JoinSide, TableRef, Expr), - ctx: &mut Context, -) -> Result { - let constraint = JoinConstraint::On(translate_expr_kind(filter.kind, ctx)?); - - Ok(Join { - relation: table_factor_of_tid(with, ctx), - join_operator: match side { - JoinSide::Inner => JoinOperator::Inner(constraint), - JoinSide::Left => JoinOperator::LeftOuter(constraint), - JoinSide::Right => JoinOperator::RightOuter(constraint), - JoinSide::Full => JoinOperator::FullOuter(constraint), - }, - }) -} - /// Translate a PRQL Ident to a Vec of SQL Idents. // We return a vec of SQL Idents because sqlparser sometimes uses // [ObjectName](sql_ast::ObjectName) and sometimes uses @@ -651,7 +600,7 @@ pub(super) fn translate_ident( ctx: &Context, ) -> Vec { let mut parts = Vec::with_capacity(4); - if !ctx.omit_ident_prefix || column.is_none() { + if !ctx.query.omit_ident_prefix || column.is_none() { if let Some(table) = table_name { #[allow(clippy::if_same_then_else)] if ctx.dialect.big_query_quoting() { @@ -957,22 +906,12 @@ mod test { { let query = resolve(parse("from foo")?)?; let (anchor, _) = AnchorContext::of(query); - context_with_concat_function = Context { - dialect: Box::new(GenericDialect {}), - anchor, - omit_ident_prefix: false, - pre_projection: false, - }; + context_with_concat_function = Context::new(Box::new(GenericDialect {}), anchor); } { let query = resolve(parse("from foo")?)?; let (anchor, _) = AnchorContext::of(query); - context_without_concat_function = Context { - dialect: Box::new(SQLiteDialect {}), - anchor, - omit_ident_prefix: false, - pre_projection: false, - }; + context_without_concat_function = Context::new(Box::new(SQLiteDialect {}), anchor); } fn str_lit(s: &str) -> InterpolateItem { diff --git a/prql-compiler/src/sql/gen_query.rs b/prql-compiler/src/sql/gen_query.rs index a109eb8b0aa1..fba04d0be692 100644 --- a/prql-compiler/src/sql/gen_query.rs +++ b/prql-compiler/src/sql/gen_query.rs @@ -6,21 +6,23 @@ use std::collections::HashSet; use std::str::FromStr; use anyhow::{anyhow, Result}; -use enum_as_inner::EnumAsInner; use itertools::Itertools; use sqlparser::ast::{ - self as sql_ast, Ident, Select, SelectItem, SetExpr, TableAlias, TableFactor, TableWithJoins, + self as sql_ast, Ident, Join, JoinConstraint, JoinOperator, Select, SelectItem, SetExpr, + TableAlias, TableFactor, TableWithJoins, }; -use crate::ast::pl::{BinOp, Literal, RelationLiteral}; -use crate::ast::rq::{CId, Expr, ExprKind, Query, Relation, RelationKind, TableDecl, Transform}; +use crate::ast::pl::{BinOp, JoinSide, Literal, RelationLiteral}; +use crate::ast::rq::{CId, Expr, ExprKind, Query, RelationKind, TableRef, Transform}; +use crate::sql::anchor::anchor_split; +use crate::sql::preprocess::SqlRelationKind; use crate::utils::{BreakUp, IntoOnly, Pluck}; use crate::Target; use super::context::AnchorContext; use super::gen_expr::*; use super::gen_projection::*; -use super::preprocess::{self, SqlTransform}; +use super::preprocess::{self, SqlRelation, SqlTransform}; use super::{anchor, Context, Dialect}; pub fn translate_query(query: Query, dialect: Option) -> Result { @@ -36,77 +38,17 @@ pub fn translate_query(query: Query, dialect: Option) -> Result { - // preprocess - let pipeline = Ok(pipeline) - .map(preprocess::normalize) - .map(preprocess::push_down_selects) - .map(preprocess::prune_inputs) - .map(preprocess::wrap) - .and_then(|p| preprocess::distinct(p, &mut context)) - .map(preprocess::union) - .and_then(|p| preprocess::except(p, &context)) - .and_then(|p| preprocess::intersect(p, &context)) - .map(preprocess::reorder)?; - - // load names of output columns - context.anchor.load_names(&pipeline, table.relation.columns); - - // split to atomics - let ats = split_into_atomics(name, pipeline, &mut context.anchor); - - // ensure names for all columns that need it - ensure_names(&ats, &mut context.anchor); - - atomics.extend(ats); - } - RelationKind::Literal(_) | RelationKind::SString(_) => atomics.push(AtomicQuery { - name, - relation: SqlRelation::Super(table.relation.kind), - }), - RelationKind::ExternRef(_) => { - // ref does not need it's own CTE - } - } - } - - // take last table - let main_query = atomics.remove(atomics.len() - 1); - let ctes = atomics; - - // convert each of the CTEs - let ctes: Vec<_> = ctes - .into_iter() - .map(|t| table_to_sql_cte(t, &mut context)) - .try_collect()?; + let mut ctx = Context::new(dialect, anchor); - // convert main query - let mut main_query = sql_query_of_relation(main_query.relation, &mut context)?; + // compile main relation that will recursively compile CTEs + let mut main_query = sql_query_of_sql_relation(main_relation.into(), &mut ctx)?; // attach CTEs - if !ctes.is_empty() { + if !ctx.ctes.is_empty() { main_query.with = Some(sql_ast::With { - cte_tables: ctes, + cte_tables: ctx.ctes.drain(..).collect_vec(), recursive: false, }); } @@ -114,99 +56,188 @@ pub fn translate_query(query: Query, dialect: Option) -> Result Result { + use RelationKind::*; -#[derive(Debug, EnumAsInner)] -enum SqlRelation { - Super(RelationKind), - Pipeline(Vec), -} + // preprocess & split into atomics + match sql_relation.kind { + // base case + SqlRelationKind::Super(Pipeline(pipeline)) => { + // preprocess + let pipeline = Ok(pipeline) + .map(preprocess::normalize) + .map(preprocess::prune_inputs) + .map(preprocess::wrap) + .and_then(|p| preprocess::distinct(p, ctx)) + .map(preprocess::union) + .and_then(|p| preprocess::except(p, ctx)) + .and_then(|p| preprocess::intersect(p, ctx)) + .map(preprocess::reorder)?; + + // load names of output columns + ctx.anchor.load_names(&pipeline, sql_relation.columns); + + sql_query_of_pipeline(pipeline, ctx) + } -fn into_tables( - main_pipeline: Relation, - tables: Vec, - context: &mut Context, -) -> Result> { - let main = TableDecl { - id: context.anchor.tid.gen(), - name: None, - relation: main_pipeline, - }; - Ok([tables, vec![main]].concat()) + // no need to preprocess, has been done already + SqlRelationKind::PreprocessedPipeline(pipeline) => sql_query_of_pipeline(pipeline, ctx), + + // special case: literals + SqlRelationKind::Super(Literal(lit)) => sql_of_sample_data(lit, ctx), + + // special case: s-strings + SqlRelationKind::Super(SString(items)) => translate_query_sstring(items, ctx), + + // ref cannot be converted directly into query and does not need it's own CTE + SqlRelationKind::Super(ExternRef(_)) => unreachable!(), + } } -fn table_to_sql_cte(table: AtomicQuery, context: &mut Context) -> Result { - let alias = sql_ast::TableAlias { - name: translate_ident_part(table.name, context), - columns: vec![], +fn table_factor_of_table_ref(table_ref: TableRef, ctx: &mut Context) -> Result { + let table_ref_alias = (table_ref.name.clone()) + .map(|ident| translate_ident_part(ident, ctx)) + .map(simple_table_alias); + + let decl = ctx.anchor.table_decls.get_mut(&table_ref.source).unwrap(); + + // prepare names + let table_name = match &decl.name { + None => { + decl.name = Some(ctx.anchor.table_name.gen()); + decl.name.clone().unwrap() + } + Some(n) => n.clone(), }; - Ok(sql_ast::Cte { - alias, - query: Box::new(sql_query_of_relation(table.relation, context)?), - from: None, - }) -} -fn sql_query_of_relation(relation: SqlRelation, context: &mut Context) -> Result { - use RelationKind::*; + // ensure that the table is declared + if let Some(sql_relation) = decl.relation.take() { + // if we cannot use CTEs + if ctx.query.forbid_ctes { + // restore relation for other references + decl.relation = Some(sql_relation.clone()); + + // return a sub-query + let query = sql_query_of_sql_relation(sql_relation, ctx)?; + return Ok(TableFactor::Derived { + lateral: false, + subquery: Box::new(query), + alias: table_ref_alias, + }); + } + + let query = sql_query_of_sql_relation(sql_relation, ctx)?; + let alias = sql_ast::TableAlias { + name: translate_ident_part(table_name.clone(), ctx), + columns: vec![], + }; - match relation { - SqlRelation::Super(ExternRef(_)) | SqlRelation::Super(Pipeline(_)) => unreachable!(), - SqlRelation::Pipeline(pipeline) => sql_query_of_pipeline(pipeline, context), - SqlRelation::Super(Literal(lit)) => Ok(sql_of_sample_data(lit, context)?), - SqlRelation::Super(SString(items)) => translate_query_sstring(items, context), + ctx.ctes.push(sql_ast::Cte { + alias, + query: Box::new(query), + from: None, + }) } + + // let name = match &decl.relation { + // // special case for anchor + // // TODO + // // Some(SqlRelationKind::Super(RelationKind::ExternRef(TableExternRef::Anchor( + // // anchor_id, + // // )))) => sql_ast::ObjectName(vec![Ident::new(anchor_id.clone())]), + + // // base case + // _ => { + + // } + // }; + + let name = sql_ast::ObjectName(translate_ident(Some(table_name.clone()), None, ctx)); + + Ok(TableFactor::Table { + name, + alias: if Some(table_name) == table_ref.name { + None + } else { + table_ref_alias + }, + args: None, + with_hints: vec![], + }) +} + +fn translate_join( + (side, with, filter): (JoinSide, TableRef, Expr), + ctx: &mut Context, +) -> Result { + let relation = table_factor_of_table_ref(with, ctx)?; + + let constraint = JoinConstraint::On(translate_expr_kind(filter.kind, ctx)?); + + Ok(Join { + relation, + join_operator: match side { + JoinSide::Inner => JoinOperator::Inner(constraint), + JoinSide::Left => JoinOperator::LeftOuter(constraint), + JoinSide::Right => JoinOperator::RightOuter(constraint), + JoinSide::Full => JoinOperator::FullOuter(constraint), + }, + }) } fn sql_query_of_pipeline( - pipeline: Vec, - context: &mut Context, + mut pipeline: Vec, + ctx: &mut Context, ) -> Result { use SqlTransform::*; + // special case: loop + if pipeline.iter().any(|t| matches!(t, Loop(_))) { + pipeline = sql_of_loop(pipeline, ctx)?; + } + + // extract an atomic pipeline from back of the pipeline and stash preceding part into context + let pipeline = extract_atomic(pipeline, &mut ctx.anchor); + + // ensure names for all columns that need it + ensure_names(&pipeline, &mut ctx.anchor); + let (select, set_ops) = pipeline.break_up(|t| matches!(t, Union { .. } | Except { .. } | Intersect { .. })); - let select = sql_select_query_of_pipeline(select, context)?; + let select = sql_select_query_of_pipeline(select, ctx)?; - sql_set_ops_of_pipeline(select, set_ops, context) + sql_set_ops_of_pipeline(select, set_ops, ctx) } fn sql_select_query_of_pipeline( mut pipeline: Vec, - context: &mut Context, + ctx: &mut Context, ) -> Result { let table_count = count_tables(&pipeline); log::debug!("atomic query contains {table_count} tables"); - context.omit_ident_prefix = table_count == 1; - - context.pre_projection = true; - - let projection = pipeline - .pluck(|t| t.into_super_and(|t| t.into_select())) - .into_only() - .unwrap(); - let projection = translate_wildcards(&context.anchor, projection); - let projection = translate_select_items(projection.0, projection.1, context)?; + ctx.push_query(); + ctx.query.omit_ident_prefix = table_count == 1; + ctx.query.pre_projection = true; - let mut from = pipeline + let mut from: Vec<_> = pipeline .pluck(|t| t.into_super_and(|t| t.into_from())) .into_iter() - .map(|source| TableWithJoins { - relation: table_factor_of_tid(source, context), - joins: vec![], + .map(|source| -> Result { + Ok(TableWithJoins { + relation: table_factor_of_table_ref(source, ctx)?, + joins: vec![], + }) }) - .collect::>(); + .try_collect()?; let joins = pipeline .pluck(|t| t.into_super_and(|t| t.into_join())) .into_iter() - .map(|j| translate_join(j, context)) + .map(|j| translate_join(j, ctx)) .collect::>>()?; if !joins.is_empty() { if let Some(from) = from.last_mut() { @@ -216,6 +247,13 @@ fn sql_select_query_of_pipeline( } } + let projection = pipeline + .pluck(|t| t.into_super_and(|t| t.into_select())) + .into_only() + .unwrap(); + let projection = translate_wildcards(&ctx.anchor, projection); + let projection = translate_select_items(projection.0, projection.1, ctx)?; + let sorts = pipeline.pluck(|t| t.into_super_and(|t| t.into_sort())); let takes = pipeline.pluck(|t| t.into_super_and(|t| t.into_take())); let distinct = pipeline.iter().any(|t| matches!(t, SqlTransform::Distinct)); @@ -231,11 +269,11 @@ fn sql_select_query_of_pipeline( // WHERE and HAVING let where_ = filter_of_conditions( before_agg.pluck(|t| t.into_super_and(|t| t.into_filter())), - context, + ctx, )?; let having = filter_of_conditions( after_agg.pluck(|t| t.into_super_and(|t| t.into_filter())), - context, + ctx, )?; // GROUP BY @@ -244,9 +282,9 @@ fn sql_select_query_of_pipeline( .into_iter() .next(); let group_by: Vec = aggregate.map(|(part, _)| part).unwrap_or_default(); - let group_by = try_into_exprs(group_by, context, None)?; + let group_by = try_into_exprs(group_by, ctx, None)?; - context.pre_projection = false; + ctx.query.pre_projection = false; let ranges = takes.into_iter().map(|x| x.range).collect(); let take = range_of_ranges(ranges)?; @@ -257,7 +295,7 @@ fn sql_select_query_of_pipeline( None } else { Some(sqlparser::ast::Offset { - value: translate_expr_kind(ExprKind::Literal(Literal::Integer(offset)), context)?, + value: translate_expr_kind(ExprKind::Literal(Literal::Integer(offset)), ctx)?, rows: sqlparser::ast::OffsetRows::None, }) }; @@ -268,17 +306,20 @@ fn sql_select_query_of_pipeline( .map(|sorts| { sorts .iter() - .map(|s| translate_column_sort(s, context)) + .map(|s| translate_column_sort(s, ctx)) .try_collect() }) .transpose()? .unwrap_or_default(); - let (top, limit) = if context.dialect.use_top() { - (limit.map(|l| top_of_i64(l, context)), None) + let (top, limit) = if ctx.dialect.use_top() { + (limit.map(|l| top_of_i64(l, ctx)), None) } else { (None, limit.map(expr_of_i64)) }; + + ctx.pop_query(); + Ok(sql_ast::Query { order_by, limit, @@ -322,36 +363,7 @@ fn sql_set_ops_of_pipeline( }; // prepare top - let top_is_simple = top.with.is_none() - && top.order_by.is_empty() - && top.limit.is_none() - && top.offset.is_none() - && top.fetch.is_none() - && top.locks.is_empty(); - - let left = if top_is_simple { - top.body - } else { - // top is not simple, so we need to wrap it into - // `SELECT * FROM top` - Box::new(SetExpr::Select(Box::new(Select { - projection: vec![SelectItem::Wildcard( - sql_ast::WildcardAdditionalOptions::default(), - )], - from: vec![TableWithJoins { - relation: TableFactor::Derived { - lateral: false, - subquery: Box::new(top), - alias: Some(TableAlias { - name: Ident::new(context.anchor.table_name.gen()), - columns: Vec::new(), - }), - }, - joins: vec![], - }], - ..default_select() - }))) - }; + let left = query_to_set_expr(top, context); top = default_query(SetExpr::SetOperation { left, @@ -360,7 +372,7 @@ fn sql_set_ops_of_pipeline( sql_ast::WildcardAdditionalOptions::default(), )], from: vec![TableWithJoins { - relation: table_factor_of_tid(bottom, context), + relation: table_factor_of_table_ref(bottom, context)?, joins: vec![], }], ..default_select() @@ -381,6 +393,99 @@ fn sql_set_ops_of_pipeline( Ok(top) } +fn sql_of_loop(pipeline: Vec, ctx: &mut Context) -> Result> { + // split the pipeline + let (mut initial, mut following) = pipeline.break_up(|t| matches!(t, SqlTransform::Loop(_))); + let loop_ = following.remove(0); + let step = loop_.into_loop().unwrap(); + + // RECURSIVE can only follow WITH directly, which means that if we want to use it for + // an arbitrary query, we have to defined a *nested* WITH RECURSIVE and not use + // the top-level list of CTEs. + + // determine columns of the initial table + let recursive_columns = AnchorContext::determine_select_columns(&initial); + + // do the same thing we do when splitting a pipeline + // (defining new columns, redirecting cids) + let recursive_columns = SqlTransform::Super(Transform::Select(recursive_columns)); + initial.push(recursive_columns.clone()); + let step = anchor_split(&mut ctx.anchor, initial, step); + let from = step.first().unwrap().as_super().unwrap().as_from().unwrap(); + + let initial = ctx.anchor.table_decls.get_mut(&from.source).unwrap(); + initial.name = Some("loop".to_string()); + let initial_relation = initial.relation.take().unwrap(); + + let initial = initial_relation.kind.into_preprocessed_pipeline().unwrap(); + + // compile initial + let initial = query_to_set_expr(sql_query_of_pipeline(initial, ctx)?, ctx); + + // compile step (without producing CTEs) + ctx.push_query(); + ctx.query.forbid_ctes = true; + + let step = query_to_set_expr(sql_query_of_pipeline(step, ctx)?, ctx); + + ctx.pop_query(); + + // build CTE and it's SELECT + let cte = sql_ast::Cte { + alias: simple_table_alias(Ident::new("loop")), + query: Box::new(default_query(SetExpr::SetOperation { + op: sql_ast::SetOperator::Union, + set_quantifier: sql_ast::SetQuantifier::All, + left: initial, + right: step, + })), + from: None, + }; + let query = Box::new(sql_ast::Query { + with: Some(sql_ast::With { + recursive: true, + cte_tables: vec![cte], + }), + ..default_query(sql_ast::SetExpr::Select(Box::new(sql_ast::Select { + projection: vec![SelectItem::Wildcard( + sql_ast::WildcardAdditionalOptions::default(), + )], + from: vec![TableWithJoins { + relation: TableFactor::Table { + name: sql_ast::ObjectName(vec![Ident::new("loop")]), + alias: None, + args: None, + with_hints: Vec::new(), + }, + joins: vec![], + }], + ..default_select() + }))) + }); + + // create a split between the loop SELECT statement and the following pipeline + let mut following = anchor_split(&mut ctx.anchor, vec![recursive_columns], following); + + let from = following.first_mut().unwrap(); + let from = from.as_super().unwrap().as_from().unwrap(); + + // this will be table decl that references the whole loop expression + let loop_decl = ctx.anchor.table_decls.get_mut(&from.source).unwrap(); + + let loop_name = ctx.anchor.table_name.gen(); + loop_decl.name = Some(loop_name.clone()); + loop_decl.relation = None; + + // push the whole thing into WITH of the main query + ctx.ctes.push(sql_ast::Cte { + alias: simple_table_alias(Ident::new(loop_name)), + query, + from: None, + }); + + Ok(following) +} + fn sql_of_sample_data(data: RelationLiteral, ctx: &Context) -> Result { // TODO: this could be made to use VALUES instead of SELECT UNION ALL SELECT // I'm not sure about compatibility though. @@ -416,121 +521,65 @@ fn sql_of_sample_data(data: RelationLiteral, ctx: &Context) -> Result, - ctx: &mut AnchorContext, -) -> Vec { - let outputs_cid = AnchorContext::determine_select_columns(&pipeline); - - let mut required_cols = outputs_cid.clone(); - - // split pipeline, back to front - let mut parts_rev = Vec::new(); - loop { - let (preceding, split) = anchor::split_off_back(ctx, required_cols, pipeline); - - if let Some((preceding, cols_at_split)) = preceding { - log::debug!( - "pipeline split after {}", - preceding.last().unwrap().as_str() - ); - parts_rev.push((split, cols_at_split.clone())); - - pipeline = preceding; - required_cols = cols_at_split; - } else { - parts_rev.push((split, Vec::new())); - break; - } - } - parts_rev.reverse(); - let mut parts = parts_rev; +/// Extract last part of pipeline that is able to "fit" into a single SELECT statement. +/// Remaining proceeding pipeline is declared as a table and stored in AnchorContext. +fn extract_atomic(pipeline: Vec, ctx: &mut AnchorContext) -> Vec { + let (preceding, atomic) = anchor::split_off_back(pipeline, ctx); - // sometimes, additional columns will be added into select, which have to - // be filtered out here, using additional CTE - if let Some((pipeline, _)) = parts.last() { - let select_cols = pipeline - .first() - .unwrap() - .as_super() - .unwrap() - .as_select() - .unwrap(); - - if select_cols.iter().any(|c| !outputs_cid.contains(c)) { - parts.push(( - vec![SqlTransform::Super(Transform::Select(outputs_cid))], - select_cols.clone(), - )); - } - } + if let Some(preceding) = preceding { + log::debug!( + "pipeline split after {}", + preceding.last().unwrap().as_str() + ); - // add names to pipelines, anchor, front to back - let mut atomics = Vec::with_capacity(parts.len()); - let last = parts.pop().unwrap(); - - let last_pipeline = if parts.is_empty() { - last.0 + anchor::anchor_split(ctx, preceding, atomic) } else { - // this code chunk is bloated but I cannot find a more concise alternative - let first = parts.remove(0); - - let first_name = ctx.table_name.gen(); - atomics.push(AtomicQuery { - name: first_name.clone(), - relation: SqlRelation::Pipeline(first.0), - }); - - let mut prev_name = first_name; - for (pipeline, cols_before) in parts.into_iter() { - let name = ctx.table_name.gen(); - let pipeline = anchor::anchor_split(ctx, &prev_name, &cols_before, pipeline); - - atomics.push(AtomicQuery { - name: name.clone(), - relation: SqlRelation::Pipeline(pipeline), - }); - - prev_name = name; - } - - anchor::anchor_split(ctx, &prev_name, &last.1, last.0) - }; - atomics.push(AtomicQuery { - name, - relation: SqlRelation::Pipeline(last_pipeline), - }); + atomic + } - atomics + // TODO + // sometimes, additional columns will be added into select, which have to + // be filtered out here, using additional CTE + // if let Some((pipeline, _)) = parts.last() { + // let select_cols = pipeline + // .first() + // .unwrap() + // .as_super() + // .unwrap() + // .as_select() + // .unwrap(); + + // if select_cols.iter().any(|c| !outputs_cid.contains(c)) { + // parts.push(( + // vec![SqlTransform::Super(Transform::Select(outputs_cid))], + // select_cols.clone(), + // )); + // } + // } } -fn ensure_names(atomics: &[AtomicQuery], ctx: &mut AnchorContext) { - // ensure column names for columns that need it - for a in atomics { - let empty = HashSet::new(); - for t in a.relation.as_pipeline().unwrap() { - match t { - SqlTransform::Super(Transform::Sort(_)) => { - for r in anchor::get_requirements(t, &empty) { - ctx.ensure_column_name(r.col); - } +fn ensure_names(transforms: &[SqlTransform], ctx: &mut AnchorContext) { + let empty = HashSet::new(); + for t in transforms { + match t { + SqlTransform::Super(Transform::Sort(_)) => { + for r in anchor::get_requirements(t, &empty) { + ctx.ensure_column_name(r.col); } - SqlTransform::Super(Transform::Select(cids)) => { - for cid in cids { - let _decl = &ctx.column_decls[cid]; - //let name = match decl { - // ColumnDecl::RelationColumn(_, _, _) => todo!(), - // ColumnDecl::Compute(_) => ctx.column_names[..], - //}; - } + } + SqlTransform::Super(Transform::Select(cids)) => { + for cid in cids { + let _decl = &ctx.column_decls[cid]; + //let name = match decl { + // ColumnDecl::RelationColumn(_, _, _) => todo!(), + // ColumnDecl::Compute(_) => ctx.column_names[..], + //}; } - _ => (), } + _ => (), } } } - fn filter_of_conditions(exprs: Vec, context: &mut Context) -> Result> { Ok(if let Some(cond) = all(exprs) { Some(translate_expr_kind(cond.kind, context)?) @@ -584,6 +633,45 @@ fn default_select() -> Select { } } +fn simple_table_alias(name: Ident) -> TableAlias { + TableAlias { + name, + columns: Vec::new(), + } +} + +fn query_to_set_expr(query: sql_ast::Query, context: &mut Context) -> Box { + let is_simple = query.with.is_none() + && query.order_by.is_empty() + && query.limit.is_none() + && query.offset.is_none() + && query.fetch.is_none() + && query.locks.is_empty(); + + if is_simple { + return query.body; + } + + // query is not simple, so we need to wrap it into + // `SELECT * FROM (query)` + Box::new(SetExpr::Select(Box::new(Select { + projection: vec![SelectItem::Wildcard( + sql_ast::WildcardAdditionalOptions::default(), + )], + from: vec![TableWithJoins { + relation: TableFactor::Derived { + lateral: false, + subquery: Box::new(query), + alias: Some(simple_table_alias(Ident::new( + context.anchor.table_name.gen(), + ))), + }, + joins: vec![], + }], + ..default_select() + }))) +} + fn count_tables(transforms: &[SqlTransform]) -> usize { let mut count = 0; for transform in transforms { @@ -603,19 +691,36 @@ mod test { fn parse_and_resolve(prql: &str) -> Result<(Vec, Context)> { let query = resolve(parse(prql)?)?; - let (anchor, query) = AnchorContext::of(query); - let context = Context { - dialect: Box::new(GenericDialect {}), - anchor, - omit_ident_prefix: false, - pre_projection: false, - }; + let (anchor, main_relation) = AnchorContext::of(query); + let context = Context::new(Box::new(GenericDialect {}), anchor); - let pipeline = query.relation.kind.into_pipeline().unwrap(); + let pipeline = main_relation.kind.into_pipeline().unwrap(); Ok((preprocess::reorder(preprocess::wrap(pipeline)), context)) } + fn count_atomics(prql: &str) -> usize { + let (mut pipeline, mut context) = parse_and_resolve(prql).unwrap(); + context.anchor.table_decls.clear(); + + let mut atomics = 0; + loop { + let _ = extract_atomic(pipeline, &mut context.anchor); + atomics += 1; + + if let Some((_, decl)) = context.anchor.table_decls.drain().next() { + if let Some(relation) = decl.relation { + if let SqlRelationKind::PreprocessedPipeline(p) = relation.kind { + pipeline = p; + continue; + } + } + } + break; + } + atomics + } + #[test] fn test_ctes_of_pipeline() { // One aggregate, take at the end @@ -627,9 +732,7 @@ mod test { take 20 "###; - let (pipeline, mut context) = parse_and_resolve(prql).unwrap(); - let queries = split_into_atomics("".to_string(), pipeline, &mut context.anchor); - assert_eq!(queries.len(), 1); + assert_eq!(count_atomics(prql), 1); // One aggregate, but take at the top let prql: &str = r###" @@ -640,9 +743,7 @@ mod test { sort sal "###; - let (pipeline, mut context) = parse_and_resolve(prql).unwrap(); - let queries = split_into_atomics("".to_string(), pipeline, &mut context.anchor); - assert_eq!(queries.len(), 2); + assert_eq!(count_atomics(prql), 2); // A take, then two aggregates let prql: &str = r###" @@ -654,9 +755,7 @@ mod test { sort sal2 "###; - let (pipeline, mut context) = parse_and_resolve(prql).unwrap(); - let queries = split_into_atomics("".to_string(), pipeline, &mut context.anchor); - assert_eq!(queries.len(), 3); + assert_eq!(count_atomics(prql), 3); // A take, then a select let prql: &str = r###" @@ -665,9 +764,7 @@ mod test { select first_name "###; - let (pipeline, mut context) = parse_and_resolve(prql).unwrap(); - let queries = split_into_atomics("".to_string(), pipeline, &mut context.anchor); - assert_eq!(queries.len(), 1); + assert_eq!(count_atomics(prql), 1); } #[test] @@ -719,7 +816,7 @@ mod test { *, RANK() OVER () AS rank FROM - table_1 + table_1 AS table_0 WHERE country = 'USA' "###); @@ -744,7 +841,7 @@ mod test { SELECT * FROM - table_1 + table_1 AS table_0 WHERE _expr_0 > 3 "###); diff --git a/prql-compiler/src/sql/mod.rs b/prql-compiler/src/sql/mod.rs index 0be592ecf4b3..31f422c9ab6b 100644 --- a/prql-compiler/src/sql/mod.rs +++ b/prql-compiler/src/sql/mod.rs @@ -63,6 +63,18 @@ struct Context { pub dialect: Box, pub anchor: AnchorContext, + // stuff regarding current query + query: QueryOpts, + + // stuff regarding parent queries + query_stack: Vec, + + pub ctes: Vec, +} + +#[derive(Default, Clone)] +struct QueryOpts { + /// When true, column references will not include table names prefixes. pub omit_ident_prefix: bool, /// True iff codegen should generate expressions before SELECT's projection is applied. @@ -70,6 +82,29 @@ struct Context { /// - WHERE needs `pre_projection=true`, but /// - ORDER BY needs `pre_projection=false`. pub pre_projection: bool, + + /// When true, queries will contain nested sub-queries instead of WITH CTEs. + pub forbid_ctes: bool, +} + +impl Context { + fn new(dialect: Box, anchor: AnchorContext) -> Self { + Context { + dialect, + anchor, + query: QueryOpts::default(), + query_stack: Vec::new(), + ctes: Vec::new(), + } + } + + fn push_query(&mut self) { + self.query_stack.push(self.query.clone()); + } + + fn pop_query(&mut self) { + self.query = self.query_stack.pop().unwrap(); + } } #[cfg(test)] diff --git a/prql-compiler/src/sql/preprocess.rs b/prql-compiler/src/sql/preprocess.rs index 7c04c4cbf7cb..035f6858dd30 100644 --- a/prql-compiler/src/sql/preprocess.rs +++ b/prql-compiler/src/sql/preprocess.rs @@ -10,7 +10,8 @@ use crate::ast::pl::{ BinOp, ColumnSort, InterpolateItem, JoinSide, Literal, Range, WindowFrame, WindowKind, }; use crate::ast::rq::{ - self, new_binop, CId, Compute, Expr, ExprKind, RqFold, TableRef, Transform, Window, + self, new_binop, CId, Compute, Expr, ExprKind, Relation, RelationColumn, RelationKind, RqFold, + TableRef, Transform, Window, }; use crate::error::Error; use crate::sql::context::AnchorContext; @@ -18,31 +19,45 @@ use crate::sql::context::AnchorContext; use super::anchor::{infer_complexity, CidCollector, Complexity}; use super::Context; -#[derive(Debug, EnumAsInner, strum::AsRefStr)] +#[derive(Debug, Clone, EnumAsInner)] +pub(super) enum SqlRelationKind { + Super(RelationKind), + PreprocessedPipeline(Vec), +} + +#[derive(Debug, Clone)] +pub(super) struct SqlRelation { + pub kind: SqlRelationKind, + pub columns: Vec, +} + +#[derive(Debug, Clone, EnumAsInner, strum::AsRefStr)] pub(super) enum SqlTransform { Super(Transform), Distinct, Except { bottom: TableRef, distinct: bool }, Intersect { bottom: TableRef, distinct: bool }, Union { bottom: TableRef, distinct: bool }, + Loop(Vec), } -/// Pushes all [Transform::Select]s to the back of the pipeline. -pub(super) fn push_down_selects(pipeline: Vec) -> Vec { - let mut select = None; - let mut res = Vec::with_capacity(pipeline.len()); - for t in pipeline { - if let Transform::Select(_) = t { - select = Some(t); - } else { - res.push(t); - } - } - if let Some(select) = select { - res.push(select); - } - res -} +// This function was disabled because it changes semantics of the pipeline in some cases. +// /// Pushes all [Transform::Select]s to the back of the pipeline. +// pub(super) fn push_down_selects(pipeline: Vec) -> Vec { +// let mut select = None; +// let mut res = Vec::with_capacity(pipeline.len()); +// for t in pipeline { +// if let Transform::Select(_) = t { +// select = Some(t); +// } else { +// res.push(t); +// } +// } +// if let Some(select) = select { +// res.push(select); +// } +// res +// } /// Removes unused relation inputs pub(super) fn prune_inputs(mut pipeline: Vec) -> Vec { @@ -76,7 +91,12 @@ pub(super) fn prune_inputs(mut pipeline: Vec) -> Vec { } pub(super) fn wrap(pipe: Vec) -> Vec { - pipe.into_iter().map(SqlTransform::Super).collect() + pipe.into_iter() + .map(|t| match t { + Transform::Loop(pipeline) => SqlTransform::Loop(wrap(pipeline)), + _ => SqlTransform::Super(t), + }) + .collect() } /// Creates [SqlTransform::Distinct] from [Transform::Take] @@ -557,6 +577,15 @@ impl SqlTransform { } } +impl From for SqlRelation { + fn from(rel: Relation) -> Self { + SqlRelation { + kind: SqlRelationKind::Super(rel.kind), + columns: rel.columns, + } + } +} + pub(super) trait SqlFold: RqFold { fn fold_sql_transforms(&mut self, transforms: Vec) -> Result> { transforms @@ -581,6 +610,7 @@ pub(super) trait SqlFold: RqFold { bottom: self.fold_table_ref(bottom)?, distinct, }, + SqlTransform::Loop(pipeline) => SqlTransform::Loop(self.fold_sql_transforms(pipeline)?), }) } } diff --git a/prql-compiler/src/sql/snapshots/prql_compiler__sql__gen_query__test__variable_after_aggregate.snap b/prql-compiler/src/sql/snapshots/prql_compiler__sql__gen_query__test__variable_after_aggregate.snap index 5b7e140a157a..1164db5605aa 100644 --- a/prql-compiler/src/sql/snapshots/prql_compiler__sql__gen_query__test__variable_after_aggregate.snap +++ b/prql-compiler/src/sql/snapshots/prql_compiler__sql__gen_query__test__variable_after_aggregate.snap @@ -16,6 +16,7 @@ SELECT title, AVG(_expr_0) AS avg_salary FROM - table_1 + table_1 AS table_0 GROUP BY title + diff --git a/prql-compiler/src/test.rs b/prql-compiler/src/test.rs index d1a4f1f2dd5b..d5991e8a9eb5 100644 --- a/prql-compiler/src/test.rs +++ b/prql-compiler/src/test.rs @@ -205,7 +205,7 @@ fn test_append() { take 10 ) "###).unwrap(), @r###" - WITH table_1 AS ( + WITH table_0 AS ( SELECT *, name, @@ -227,13 +227,13 @@ fn test_append() { employees LIMIT 3 - ) AS table_3 + ) AS table_2 UNION ALL SELECT * FROM - table_1 AS table_0 + table_0 AS table_1 "###); assert_display_snapshot!(compile(r###" @@ -310,7 +310,7 @@ fn test_remove() { ) "#).unwrap(), @r###" - WITH table_1 AS ( + WITH table_0 AS ( SELECT artist_id FROM @@ -325,7 +325,7 @@ fn test_remove() { SELECT * FROM - table_1 AS table_0 + table_0 AS table_1 "### ); @@ -337,7 +337,7 @@ fn test_remove() { ) "#).unwrap(), @r###" - WITH table_1 AS ( + WITH table_0 AS ( SELECT artist_id FROM @@ -348,9 +348,9 @@ fn test_remove() { album.title FROM album - LEFT JOIN table_1 AS table_0 ON album.artist_id = table_0.artist_id + LEFT JOIN table_0 AS table_1 ON album.artist_id = table_1.artist_id WHERE - table_0.artist_id IS NULL + table_1.artist_id IS NULL "### ); @@ -382,11 +382,11 @@ fn test_remove() { album ) SELECT - table_1.artist_id, - table_1.title + table_0.artist_id, + table_0.title FROM - table_1 - LEFT JOIN bottom AS b ON table_1.artist_id = b.* + table_1 AS table_0 + LEFT JOIN bottom AS b ON table_0.artist_id = b.* WHERE b.* IS NULL "### @@ -443,7 +443,7 @@ fn test_intersect() { ) "#).unwrap(), @r###" - WITH table_1 AS ( + WITH table_0 AS ( SELECT artist_id FROM @@ -458,7 +458,7 @@ fn test_intersect() { SELECT * FROM - table_1 AS table_0 + table_0 AS table_1 "### ); @@ -474,22 +474,28 @@ fn test_intersect() { distinct "#).unwrap(), @r###" - WITH table_1 AS ( + WITH table_0 AS ( SELECT artist_id FROM artist + ), + table_3 AS ( + SELECT + artist_id + FROM + album + INTERSECT + DISTINCT + SELECT + * + FROM + table_0 AS table_1 ) SELECT - artist_id + DISTINCT artist_id FROM - album - INTERSECT - DISTINCT - SELECT - * - FROM - table_1 AS table_0 + table_3 AS table_2 "### ); @@ -504,22 +510,28 @@ fn test_intersect() { distinct "#).unwrap(), @r###" - WITH table_1 AS ( + WITH table_0 AS ( SELECT artist_id FROM artist + ), + table_3 AS ( + SELECT + artist_id + FROM + album + INTERSECT + ALL + SELECT + * + FROM + table_0 AS table_1 ) SELECT - artist_id - FROM - album - INTERSECT - DISTINCT - SELECT - * + DISTINCT artist_id FROM - table_1 AS table_0 + table_3 AS table_2 "### ); @@ -534,7 +546,7 @@ fn test_intersect() { ) "#).unwrap(), @r###" - WITH table_1 AS ( + WITH table_0 AS ( SELECT artist_id FROM @@ -549,7 +561,7 @@ fn test_intersect() { SELECT * FROM - table_1 AS table_0 + table_0 AS table_1 "### ); @@ -574,28 +586,28 @@ fn test_rn_ids_are_unique() { take 3 ) "###).unwrap()), @r###" - WITH table_1 AS ( + WITH table_3 AS ( SELECT *, - ROW_NUMBER() OVER (PARTITION BY y_id) AS _expr_0 + ROW_NUMBER() OVER (PARTITION BY y_id) AS _expr_1 FROM y_orig ), - table_2 AS ( + table_1 AS ( SELECT *, - ROW_NUMBER() OVER (PARTITION BY x_id) AS _expr_1 + ROW_NUMBER() OVER (PARTITION BY x_id) AS _expr_0 FROM - table_1 + table_3 AS table_2 WHERE - _expr_0 <= 2 + _expr_1 <= 2 ) SELECT * FROM - table_2 + table_1 AS table_0 WHERE - _expr_1 <= 3 + _expr_0 <= 3 "###); } @@ -690,19 +702,13 @@ fn test_sorts() { select [renamed = somefield] "### ).unwrap()), @r###" - WITH table_1 AS ( - SELECT - 'something' AS renamed, - 'something' AS _expr_0 - FROM - x - ORDER BY - _expr_0 - ) SELECT - renamed + 'something' AS renamed, + 'something' AS _expr_0 FROM - table_1 + x + ORDER BY + _expr_0 "###); } @@ -877,7 +883,7 @@ fn test_window_functions_02() { order_day ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ) AS num_books_last_week FROM - table_1 + table_1 AS table_0 ORDER BY order_day "###); @@ -1261,7 +1267,7 @@ fn test_take() { SELECT * FROM - table_1 + table_1 AS table_0 ORDER BY name LIMIT @@ -1340,7 +1346,7 @@ fn test_distinct() { SELECT * FROM - table_1 + table_1 AS table_0 WHERE rn > 2 "###); @@ -1397,7 +1403,7 @@ fn test_distinct() { SELECT * FROM - table_1 + table_1 AS table_0 WHERE _expr_0 <= 3 "###); @@ -1420,7 +1426,7 @@ fn test_distinct() { SELECT * FROM - table_1 + table_1 AS table_0 WHERE _expr_0 BETWEEN 2 AND 3 "###); @@ -1443,7 +1449,7 @@ fn test_distinct() { SELECT * FROM - table_1 + table_1 AS table_0 WHERE _expr_0 = 4 "###); @@ -1832,16 +1838,7 @@ fn test_prql_to_sql_table() { let sql = compile(query).unwrap(); assert_display_snapshot!(sql, @r###" - WITH average_salaries AS ( - SELECT - country, - AVG(salary) AS average_country_salary - FROM - salaries - GROUP BY - country - ), - newest_employees AS ( + WITH newest_employees AS ( SELECT * FROM @@ -1850,6 +1847,14 @@ fn test_prql_to_sql_table() { tenure LIMIT 50 + ), average_salaries AS ( + SELECT + country, + AVG(salary) AS average_country_salary + FROM + salaries + GROUP BY + country ) SELECT newest_employees.name, @@ -1883,7 +1888,7 @@ fn test_nonatomic() { "###; assert_display_snapshot!((compile(query).unwrap()), @r###" - WITH table_1 AS ( + WITH table_3 AS ( SELECT title, country, @@ -1892,13 +1897,13 @@ fn test_nonatomic() { employees LIMIT 20 - ), table_2 AS ( + ), table_1 AS ( SELECT title, country, AVG(salary) AS _expr_0 FROM - table_1 + table_3 AS table_2 WHERE country = 'USA' GROUP BY @@ -1910,7 +1915,7 @@ fn test_nonatomic() { country, AVG(_expr_0) AS sum_gross_cost FROM - table_2 + table_1 AS table_0 GROUP BY title, country @@ -1963,7 +1968,7 @@ fn test_nonatomic_table() { "###; assert_display_snapshot!((compile(query).unwrap()), @r###" - WITH table_0 AS ( + WITH table_1 AS ( SELECT country FROM @@ -1975,7 +1980,7 @@ fn test_nonatomic_table() { country, count(*) FROM - table_0 + table_1 AS table_0 GROUP BY country ) @@ -2012,12 +2017,12 @@ fn test_table_names_between_splits() { 10 ) SELECT - table_1.emp_no, - table_1.name, + table_0.emp_no, + table_0.name, s.salary FROM - table_1 - JOIN salaries AS s ON table_1.emp_no = s.emp_no + table_1 AS table_0 + JOIN salaries AS s ON table_0.emp_no = s.emp_no "###); let prql = r###" @@ -2037,11 +2042,11 @@ fn test_table_names_between_splits() { 10 ) SELECT - table_1.*, + table_0.*, salaries.salary FROM - table_1 - JOIN salaries ON table_1.emp_no = salaries.emp_no + table_1 AS table_0 + JOIN salaries ON table_0.emp_no = salaries.emp_no "###); } @@ -2321,12 +2326,6 @@ fn test_toposort() { * FROM somesource - ), - a AS ( - SELECT - * - FROM - b ) SELECT * @@ -2346,7 +2345,7 @@ fn test_inline_tables() { join s = (from salaries | select [emp_id, salary]) [==emp_id] "###).unwrap(), @r###" - WITH table_1 AS ( + WITH table_0 AS ( SELECT emp_id, salary @@ -2359,11 +2358,11 @@ fn test_inline_tables() { employees.surname, employees.type, employees.amount, - table_0.emp_id, - table_0.salary + table_1.emp_id, + table_1.salary FROM employees - JOIN table_1 AS table_0 ON employees.emp_id = table_0.emp_id + JOIN table_0 AS table_1 ON employees.emp_id = table_1.emp_id "### ); } @@ -2448,7 +2447,7 @@ fn test_table_s_string() { s"SELECT DISTINCT ON first_name, age FROM employees ORDER BY age ASC" "###).unwrap(), @r###" - WITH table_1 AS ( + WITH table_0 AS ( SELECT DISTINCT ON first_name, age @@ -2459,7 +2458,7 @@ fn test_table_s_string() { ) SELECT FROM - table_1 AS table_0 + table_0 AS table_1 "### ); @@ -2470,7 +2469,7 @@ fn test_table_s_string() { join s = s"SELECT * FROM salaries" [==id] "###).unwrap(), @r###" - WITH table_2 AS ( + WITH table_0 AS ( SELECT DISTINCT ON first_name, id, @@ -2480,18 +2479,18 @@ fn test_table_s_string() { ORDER BY age ASC ), - table_3 AS ( + table_1 AS ( SELECT * FROM salaries ) SELECT - table_0.*, - table_1.* + table_2.*, + table_3.* FROM - table_2 AS table_0 - JOIN table_3 AS table_1 ON table_0.id = table_1.id + table_0 AS table_2 + JOIN table_1 AS table_3 ON table_2.id = table_3.id "### ); @@ -2500,7 +2499,7 @@ fn test_table_s_string() { filter country == "USA" "###).unwrap(), @r###" - WITH table_1 AS ( + WITH table_0 AS ( SELECT * FROM @@ -2509,7 +2508,7 @@ fn test_table_s_string() { SELECT * FROM - table_1 AS table_0 + table_0 AS table_1 WHERE country = 'USA' "### @@ -2520,7 +2519,7 @@ fn test_table_s_string() { filter e.country == "USA" "###).unwrap(), @r###" - WITH table_1 AS ( + WITH table_0 AS ( SELECT * FROM @@ -2529,7 +2528,7 @@ fn test_table_s_string() { SELECT * FROM - table_1 AS table_0 + table_0 AS table_1 WHERE country = 'USA' "### @@ -2542,7 +2541,7 @@ fn test_table_s_string() { weeks_between @2022-06-03 (current_week + 4) "###).unwrap(), @r###" - WITH table_1 AS ( + WITH table_0 AS ( SELECT generate_series( DATE '2022-06-03', @@ -2552,7 +2551,7 @@ fn test_table_s_string() { ) SELECT FROM - table_1 AS table_0 + table_0 AS table_1 "### ); @@ -2560,7 +2559,7 @@ fn test_table_s_string() { s"SELECT * FROM {default_db.x}" "###).unwrap(), @r###" - WITH table_1 AS ( + WITH table_0 AS ( SELECT * FROM @@ -2568,7 +2567,7 @@ fn test_table_s_string() { ) SELECT FROM - table_1 AS table_0 + table_0 AS table_1 "### ); } @@ -2668,13 +2667,13 @@ fn test_group_all() { 10 ) SELECT - table_1.*, + table_0.*, SUM(salaries.salary) AS sal FROM - table_1 - JOIN salaries ON table_1.emp_no = salaries.emp_no + table_1 AS table_0 + JOIN salaries ON table_0.emp_no = salaries.emp_no GROUP BY - table_1.* + table_0.* "### ); @@ -2705,7 +2704,7 @@ fn test_output_column_deduplication() { SELECT * FROM - table_1 + table_1 AS table_0 WHERE r = 1 "### @@ -2779,7 +2778,7 @@ fn test_switch() { category, COUNT(*) FROM - table_1 + table_1 AS table_0 GROUP BY category "### @@ -3135,7 +3134,7 @@ a,b,c select [b, c] "#).unwrap(), @r###" - WITH table_1 AS ( + WITH table_0 AS ( SELECT '1' AS a, '2' AS b, @@ -3151,7 +3150,7 @@ a,b,c b, c FROM - table_1 AS table_0 + table_0 AS table_1 "### ); @@ -3162,7 +3161,7 @@ a,b,c select [b, c] "#).unwrap(), @r###" - WITH table_1 AS ( + WITH table_0 AS ( SELECT 1 AS a, 'x' AS b, @@ -3178,7 +3177,7 @@ a,b,c b, c FROM - table_1 AS table_0 + table_0 AS table_1 "### ); @@ -3193,7 +3192,7 @@ a,b,c select [b, c] "#).unwrap(), @r###" - WITH table_1 AS ( + WITH table_0 AS ( SELECT 1 AS a, 'x' AS b, @@ -3209,7 +3208,7 @@ a,b,c b, c FROM - table_1 AS table_0 + table_0 AS table_1 "### ); } @@ -3226,3 +3225,55 @@ fn test_header_target_error() { from a "#).unwrap_err(),@r###"target `"sql.foo"` not found"###) } + +#[test] +fn test_loop() { + assert_display_snapshot!(compile(r#" + from_text format:json '[{"n": 1 }]' + select n = n - 2 + loop ( + select n = n+1 + filter n<5 + ) + select n = n * 2 + take 4 + "#).unwrap(), + @r###" + WITH table_0 AS ( + SELECT + 1 AS n + ), + table_6 AS ( + WITH RECURSIVE loop AS ( + SELECT + n - 2 AS _expr_0 + FROM + table_0 AS table_1 + UNION + ALL + SELECT + _expr_1 + FROM + ( + SELECT + _expr_0 + 1 AS _expr_1 + FROM + loop AS table_2 + ) AS table_3 + WHERE + _expr_1 < 5 + ) + SELECT + * + FROM + loop + ) + SELECT + _expr_0 * 2 AS n + FROM + table_6 AS table_5 + LIMIT + 4 + "### + ); +} diff --git a/prql-compiler/tests/integration/queries/loop.prql b/prql-compiler/tests/integration/queries/loop.prql new file mode 100644 index 000000000000..e83d02e37057 --- /dev/null +++ b/prql-compiler/tests/integration/queries/loop.prql @@ -0,0 +1,7 @@ +from_text format:json '[{"n": 1 }]' +select n = n - 2 +loop ( + filter n<4 + select n = n+1 +) +select n = n * 2 diff --git a/prql-compiler/tests/integration/snapshots/integration__tests__test@loop.prql.snap b/prql-compiler/tests/integration/snapshots/integration__tests__test@loop.prql.snap new file mode 100644 index 000000000000..482dc9933c4d --- /dev/null +++ b/prql-compiler/tests/integration/snapshots/integration__tests__test@loop.prql.snap @@ -0,0 +1,12 @@ +--- +source: prql-compiler/tests/integration/main.rs +expression: sqlite_out +input_file: prql-compiler/tests/integration/queries/loop.prql +--- +n +-2 +0 +2 +4 +6 +8 From b68a944aa09233636be832afb73cee9b933d0bde Mon Sep 17 00:00:00 2001 From: Jonathan Date: Sun, 19 Feb 2023 13:01:32 +0100 Subject: [PATCH 003/106] feat: Generate C header file for prql-lib (#1879) --- prql-lib/README.md | 8 ++++++++ prql-lib/cbindgen.toml | 1 + prql-lib/libprql_lib.h | 18 ++++++++++++++++++ 3 files changed, 27 insertions(+) create mode 100644 prql-lib/cbindgen.toml create mode 100644 prql-lib/libprql_lib.h diff --git a/prql-lib/README.md b/prql-lib/README.md index 9c17b3da2b21..ba49ff9fffa5 100644 --- a/prql-lib/README.md +++ b/prql-lib/README.md @@ -82,3 +82,11 @@ func ToJSON(prql string) (string, error) { return "", errors.New(C.GoString(cstr)) } ``` + +## C header file + +The C header file `libprql_lib.h` was generated using +[cbindgen](https://github.com/eqrion/cbindgen). To generate a new one run: + + cargo install --force cbindgen + cbindgen --crate prql-lib --output libprql_lib.h diff --git a/prql-lib/cbindgen.toml b/prql-lib/cbindgen.toml new file mode 100644 index 000000000000..08094f28fc2c --- /dev/null +++ b/prql-lib/cbindgen.toml @@ -0,0 +1 @@ +language = "C" diff --git a/prql-lib/libprql_lib.h b/prql-lib/libprql_lib.h new file mode 100644 index 000000000000..8a1ed325e4f0 --- /dev/null +++ b/prql-lib/libprql_lib.h @@ -0,0 +1,18 @@ +#include +#include +#include +#include + +/** + * # Safety + * + * This function is inherently unsafe because it is using C ABI. + */ +int to_sql(const char *query, char *out); + +/** + * # Safety + * + * This function is inherently unsafe because it using C ABI. + */ +int to_json(const char *query, char *out); From d8b7e63f2edeab7dc4598d6736354030b841ecc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alja=C5=BE=20Mur=20Er=C5=BEen?= Date: Sun, 19 Feb 2023 13:15:42 +0100 Subject: [PATCH 004/106] fix: website tests (#1894) --- website/content/_index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/content/_index.md b/website/content/_index.md index 035f4eaedfe2..c40e3396934f 100644 --- a/website/content/_index.md +++ b/website/content/_index.md @@ -246,7 +246,7 @@ showcase_section: SELECT * FROM - table_1 + table_1 as table_0 WHERE _expr_0 <= 1 From 9bd27f19d91ba326918a7ec157eec2aec083994c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alja=C5=BE=20Mur=20Er=C5=BEen?= Date: Sun, 19 Feb 2023 21:27:49 +0100 Subject: [PATCH 005/106] feat(prqlc)!: preprocess Jinja templates (#1722) --- Cargo.lock | 15 ++- prql-compiler/prqlc/Cargo.toml | 5 +- prql-compiler/prqlc/src/jinja.rs | 177 +++++++++++++++++++++++++++++ prql-compiler/prqlc/src/main.rs | 2 + prql-compiler/prqlc/src/watch.rs | 10 +- prql-compiler/src/parser/mod.rs | 41 +------ prql-compiler/src/parser/prql.pest | 5 +- prql-compiler/src/sql/gen_expr.rs | 5 +- prql-compiler/src/sql/mod.rs | 5 +- prql-compiler/src/test.rs | 13 --- website/content/_index.md | 2 +- 11 files changed, 215 insertions(+), 65 deletions(-) create mode 100644 prql-compiler/prqlc/src/jinja.rs diff --git a/Cargo.lock b/Cargo.lock index fbf59f6863f1..f94ad387bfbf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1669,6 +1669,14 @@ dependencies = [ "autocfg", ] +[[package]] +name = "minijinja" +version = "0.30.2" +source = "git+https://github.com/aljazerzen/minijinja#af5a4fd89e5ee5455d673a23098dcbc3d8444229" +dependencies = [ + "serde", +] + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -2217,8 +2225,11 @@ dependencies = [ "env_logger 0.9.3", "insta", "itertools", + "minijinja", "notify", "prql-compiler", + "regex", + "serde", "serde_json", "serde_yaml", "walkdir", @@ -2397,9 +2408,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.7.0" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a" +checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" dependencies = [ "aho-corasick", "memchr", diff --git a/prql-compiler/prqlc/Cargo.toml b/prql-compiler/prqlc/Cargo.toml index 322148aae867..621fdc071a43 100644 --- a/prql-compiler/prqlc/Cargo.toml +++ b/prql-compiler/prqlc/Cargo.toml @@ -18,9 +18,12 @@ color-eyre = "0.6.1" env_logger = {version = "0.9.1", features = ["termcolor"]} itertools = "0.10.3" notify = "^5.1.0" -prql-compiler = {path = '..', version = "0.5.2" } +minijinja = {git = "https://github.com/aljazerzen/minijinja"} +prql-compiler = {path = '..', version = "0.5.2"} +regex = {version = "1.7.1", features = ["std", "unicode"]} serde_json = "1.0.81" serde_yaml = "0.9.1" +serde = "^1" walkdir = "^2.3.2" [target.'cfg(not(target_family="wasm"))'.dev-dependencies] diff --git a/prql-compiler/prqlc/src/jinja.rs b/prql-compiler/prqlc/src/jinja.rs new file mode 100644 index 000000000000..ac8835747a37 --- /dev/null +++ b/prql-compiler/prqlc/src/jinja.rs @@ -0,0 +1,177 @@ +//! Handling of Jinja templates +//! +//! dbt is using the following pipeline: `Jinja+SQL -> SQL -> execution`. +//! +//! To prevent messing up the templates, we have create the following pipeline: +//! ``` +//! Jinja+PRQL -> Jinja+SQL -> SQL -> execution +//! ``` +//! +//! But because prql-compiler does not (and should not) know how to handle Jinja, +//! we have to extract the interpolations, replace them something that is valid PRQL, +//! compile the query and inject interpolations back in. +//! +//! Unfortunately, this requires parsing Jinja. +//! +//! use crate::compiler::tokens::{Span, Token}; + +use std::collections::HashMap; + +use anyhow::Result; +use minijinja::compiler::tokens::{Span, Token}; +use regex::Regex; + +const ANCHOR_PREFIX: &str = "_jinja_"; + +#[derive(Debug)] +pub enum JinjaBlock<'a> { + Data(&'a str), + Interpolation(Vec<(Token<'a>, Span)>), +} + +#[derive(Default)] +pub struct JinjaContext<'a> { + anchor_map: HashMap, + header: Vec<&'a str>, +} + +/// Parse source as Jinja template, extract all interpolations +/// and replace them with anchors. +pub fn pre_process(source: &str) -> Result<(String, JinjaContext)> { + let mut blocks = Vec::new(); + let mut current_block = Vec::new(); + + for res in minijinja::compiler::lexer::tokenize(source, false) { + let (token, span) = res?; + + if let Token::TemplateData(data) = token { + if !current_block.is_empty() { + blocks.push(JinjaBlock::Interpolation(current_block)); + current_block = Vec::new(); + } + blocks.push(JinjaBlock::Data(data)) + } else { + current_block.push((token, span)); + } + } + if !current_block.is_empty() { + blocks.push(JinjaBlock::Interpolation(current_block)); + } + + let mut anchored_source = String::new(); + let mut next_anchor_id = 0; + let mut context = JinjaContext::default(); + for block in blocks { + match block { + JinjaBlock::Data(data) => anchored_source += data, + JinjaBlock::Interpolation(block) => { + let (tokens, spans): (Vec<_>, _) = block.into_iter().unzip(); + + let source_span = find_span(source, spans); + + if let Some(Token::Ident("config" | "set")) = tokens.get(1) { + context.header.push(source_span); + } else { + let id = format!("{ANCHOR_PREFIX}{next_anchor_id}"); + next_anchor_id += 1; + + anchored_source += &id; + + context.anchor_map.insert(id, source_span); + } + } + } + } + + Ok((anchored_source, context)) +} + +fn find_span(source: &str, spans: Vec) -> &str { + let start = spans.first().unwrap(); + let end = spans.last().unwrap(); + + let mut start_index = 0; + let mut end_index = source.len(); + + let mut line = 1; + let mut col = 0; + for (index, char) in source.chars().enumerate() { + if char == '\n' { + line += 1; + col = 0; + continue; + } else { + col += 1; + } + + if line == start.start_line && col == start.start_col { + start_index = index; + } + if line == end.end_line && col == end.end_col { + end_index = index + 1; + } + } + &source[start_index..end_index] +} + +/// Replace anchors with their values. +pub fn post_process(source: &str, context: JinjaContext) -> String { + let mut res = String::new(); + + for stmt in context.header { + res += stmt; + res += "\n"; + } + + let re = Regex::new(&format!(r"{ANCHOR_PREFIX}\d+")).unwrap(); + + let mut last_index = 0; + for cap in re.captures_iter(source) { + let cap = cap.get(0).unwrap(); + let index = cap.start(); + let anchor_id = cap.as_str(); + + res += &source[last_index..index]; + res += context.anchor_map.get(anchor_id).unwrap_or(&anchor_id); + + last_index = index + anchor_id.len(); + } + res += &source[last_index..]; + + res +} + +#[cfg(test)] +mod test { + use super::Span; + + #[test] + fn test_find_span() { + let text = r#"line 1 col 13 + line 2 col 21 + some text line 3 col 31 more text + "#; + + assert_eq!( + super::find_span( + text, + vec![ + Span { + start_line: 2, + start_col: 9, + end_line: 12123123, + end_col: 2930293, + }, + Span { + start_line: 7893648, + start_col: 79678, + end_line: 3, + end_col: 31, + } + ] + ), + r#"line 2 col 21 + some text line 3 col 31"# + ); + } +} diff --git a/prql-compiler/prqlc/src/main.rs b/prql-compiler/prqlc/src/main.rs index 98ed661a72d6..0a3e3d6edc14 100644 --- a/prql-compiler/prqlc/src/main.rs +++ b/prql-compiler/prqlc/src/main.rs @@ -7,6 +7,8 @@ #[cfg(not(target_family = "wasm"))] mod cli; #[cfg(not(target_family = "wasm"))] +mod jinja; +#[cfg(not(target_family = "wasm"))] mod watch; #[cfg(not(target_family = "wasm"))] diff --git a/prql-compiler/prqlc/src/watch.rs b/prql-compiler/prqlc/src/watch.rs index a6bd2c4d0a2b..6c0f70121372 100644 --- a/prql-compiler/prqlc/src/watch.rs +++ b/prql-compiler/prqlc/src/watch.rs @@ -8,6 +8,8 @@ use notify::{Config, RecommendedWatcher, RecursiveMode, Watcher}; use prql_compiler::downcast; use walkdir::WalkDir; +use crate::jinja; + #[derive(Parser)] pub struct WatchCommand { /// Directory or file to watch for changes @@ -33,7 +35,7 @@ pub fn run(command: &mut WatchCommand) -> Result<()> { // watch and compile println!("Watching path \"{}\"", path.display()); - watch_and_compile(path, &opt).unwrap(); + watch_and_compile(path, &opt)?; Ok(()) } @@ -108,6 +110,9 @@ fn compile_path(path: &Path, opt: &prql_compiler::Options) -> Result<()> { return Ok(()); } + // pre-process Jinja + let (prql_string, jinja_context) = jinja::pre_process(&prql_string)?; + // compile println!("Compiling {}", prql_path.display()); let sql_string = match prql_compiler::compile(&prql_string, opt.clone()) { @@ -119,6 +124,9 @@ fn compile_path(path: &Path, opt: &prql_compiler::Options) -> Result<()> { } }; + // post-process Jinja + let sql_string = jinja::post_process(&sql_string, jinja_context); + // write fs::write(sql_path, sql_string)?; diff --git a/prql-compiler/src/parser/mod.rs b/prql-compiler/src/parser/mod.rs index 12aad8385407..4483911c5604 100644 --- a/prql-compiler/src/parser/mod.rs +++ b/prql-compiler/src/parser/mod.rs @@ -233,10 +233,6 @@ fn expr_of_parse_pair(pair: Pair) -> Result { named_args: named, }) } - Rule::jinja => { - let inner = pair.as_str(); - ExprKind::Ident(Ident::from_name(inner)) - } Rule::ident => { // Pest has already parsed, so Chumsky should never fail let ident = ::chumsky::Parser::parse(&chumsky::ident(), pair.as_str()).unwrap(); @@ -850,39 +846,14 @@ Canada } #[test] - fn test_parse_jinja() -> Result<()> { - assert_yaml_snapshot!(stmts_of_string(r#" + fn test_parse_jinja() { + stmts_of_string( + r#" from {{ ref('stg_orders') }} aggregate (sum order_id) - "#)?, @r###" - --- - - Main: - Pipeline: - exprs: - - FuncCall: - name: - Ident: - - from - args: - - Ident: - - "{{ ref('stg_orders') }}" - named_args: {} - - FuncCall: - name: - Ident: - - aggregate - args: - - FuncCall: - name: - Ident: - - sum - args: - - Ident: - - order_id - named_args: {} - named_args: {} - "###); - Ok(()) + "#, + ) + .unwrap_err(); } #[test] diff --git a/prql-compiler/src/parser/prql.pest b/prql-compiler/src/parser/prql.pest index 50cf6707ce68..b30651838c25 100644 --- a/prql-compiler/src/parser/prql.pest +++ b/prql-compiler/src/parser/prql.pest @@ -57,7 +57,7 @@ expr_compare = { expr_add ~ (operator_compare ~ expr_add)? } expr_add = { expr_mul ~ (operator_add ~ expr_add)? } expr_mul = { term ~ (operator_mul ~ expr_mul)? } -term = _{ ( switch | s_string | f_string | range | literal | ident | nested_pipeline | expr_unary | list | jinja ) } +term = _{ ( switch | s_string | f_string | range | literal | ident | nested_pipeline | expr_unary | list ) } expr_unary = { ( operator_unary ~ ( nested_pipeline | ident | list )) } literal = _{ value_and_unit | number | boolean | null | string | timestamp | date | time | "(" ~ literal ~ ")" } // `assign | pipeline` based on discussion in #648 @@ -146,8 +146,5 @@ timestamp_inner = ${ date_inner ~ "T" ~ time_inner } // not supported) end_expr = _{ WHITESPACE | "," | ")" | "]" | EOI | NEWLINE | ".." } -// We pass text between `{{` and `}}` through, so dbt can use Jinja. -jinja = { ("{{" ~ (!"}}" ~ ANY)* ~ "}}") } - switch = { "switch" ~ "[" ~ (NEWLINE* ~ switch_case ~ ("," ~ NEWLINE* ~ switch_case )* ~ ","?)? ~ NEWLINE* ~ "]" } switch_case = { expr_call ~ "->" ~ expr_call } diff --git a/prql-compiler/src/sql/gen_expr.rs b/prql-compiler/src/sql/gen_expr.rs index 7806cf9b70a4..271b4a6a1833 100644 --- a/prql-compiler/src/sql/gen_expr.rs +++ b/prql-compiler/src/sql/gen_expr.rs @@ -664,9 +664,6 @@ fn is_keyword(ident: &str) -> bool { } pub(super) fn translate_ident_part(ident: String, ctx: &Context) -> sql_ast::Ident { - // We'll remove this when we get the new dbt plugin working (so no need to - // integrate into the regex) - let is_jinja = ident.starts_with("{{") && ident.ends_with("}}"); lazy_static! { // One of: // - `*` @@ -679,7 +676,7 @@ pub(super) fn translate_ident_part(ident: String, ctx: &Context) -> sql_ast::Ide let is_bare = VALID_BARE_IDENT.is_match(&ident); - if is_jinja || is_bare && !is_keyword(&ident) { + if is_bare && !is_keyword(&ident) { sql_ast::Ident::new(ident) } else { sql_ast::Ident::with_quote(ctx.dialect.ident_quote(), ident) diff --git a/prql-compiler/src/sql/mod.rs b/prql-compiler/src/sql/mod.rs index 31f422c9ab6b..c49140711390 100644 --- a/prql-compiler/src/sql/mod.rs +++ b/prql-compiler/src/sql/mod.rs @@ -32,10 +32,7 @@ pub fn compile(query: Query, options: Options) -> Result { sqlformat::FormatOptions::default(), ); - // The sql formatter turns `{{` into `{ {`, and while that's reasonable SQL, - // we want to allow jinja expressions through. So we (somewhat hackily) replace - // any `{ {` with `{{`. - formatted.replace("{ {", "{{").replace("} }", "}}") + "\n" + formatted + "\n" } else { sql }; diff --git a/prql-compiler/src/test.rs b/prql-compiler/src/test.rs index d5991e8a9eb5..16c1d560cf5a 100644 --- a/prql-compiler/src/test.rs +++ b/prql-compiler/src/test.rs @@ -1455,19 +1455,6 @@ fn test_distinct() { "###); } -#[test] -fn test_dbt_query() { - assert_display_snapshot!((compile(r###" - from {{ ref('stg_orders') }} - aggregate (min order_id) - "###).unwrap()), @r###" - SELECT - MIN(order_id) - FROM - {{ ref('stg_orders') }} - "###); -} - #[test] fn test_join() { assert_display_snapshot!((compile(r###" diff --git a/website/content/_index.md b/website/content/_index.md index c40e3396934f..349317aaf594 100644 --- a/website/content/_index.md +++ b/website/content/_index.md @@ -246,7 +246,7 @@ showcase_section: SELECT * FROM - table_1 as table_0 + table_1 AS table_0 WHERE _expr_0 <= 1 From b430f03e05171c898ece420674d63511d17f2d69 Mon Sep 17 00:00:00 2001 From: Rich Brown Date: Sun, 19 Feb 2023 16:04:57 -0500 Subject: [PATCH 006/106] docs: Fix "LSP server" (#1896) Fix "LSP server" --- website/content/roadmap.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/content/roadmap.md b/website/content/roadmap.md index 7a9cb1b107c6..46c5deb259e4 100644 --- a/website/content/roadmap.md +++ b/website/content/roadmap.md @@ -78,7 +78,7 @@ This requires development across multiple dimensions — writing an [LSP server](https://langserver.org/), better support for typing in the compiler, and possibly database cohesion. -While PRQL compiler will never depend on a database to compile queries, LPS +While PRQL compiler will never depend on a database to compile queries, an LSP server could greatly help with generating type definitions from the information schema of a database. From 2560ca59c90faa64eae0b4188e43cd6a2fb64d91 Mon Sep 17 00:00:00 2001 From: Jonathan Date: Sun, 19 Feb 2023 23:31:10 +0100 Subject: [PATCH 007/106] docs: Added C header file (#1898) Added C header file --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a3c85b96daf..d42f9d8eee82 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,8 @@ **Integrations**: +- [prql-lib] Added C header file (@vanillajonathan, #1879) + **Internal changes**: **New Contributors**: From d2ee50239c121875c8e55754a932f9ffef895831 Mon Sep 17 00:00:00 2001 From: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Date: Sun, 19 Feb 2023 16:26:53 -0800 Subject: [PATCH 008/106] revert: "feat!: loop" (#1899) Revert "feat!: loop (#1642)" This reverts commit c79c5f1e2b54c021538da2954352e9c3207fca4c. --- CHANGELOG.md | 2 - book/README.md | 2 +- book/book.toml | 2 +- book/src/SUMMARY.md | 4 +- book/src/integrations/jupyter.md | 2 +- book/src/integrations/rill.md | 2 +- book/src/internals/name-resolving.md | 2 +- .../README.md => standard-library.md} | 2 +- .../standard-library/from-text.md | 63 -- .../standard-library/loop.md | 50 -- book/src/syntax.md | 2 +- book/src/transforms/from_text.md | 61 ++ .../README-0.prql => standard-library-0.prql} | 0 .../standard-library/loop-0.prql | 7 - .../from_text-0.prql} | 0 .../from_text-1.prql} | 0 .../from_text-2.prql} | 0 .../snapshot__@examples__cte-0.prql.snap | 22 +- ...snapshot__@examples__employees-0.prql.snap | 21 +- ...snapshot__@examples__employees-1.prql.snap | 27 +- ...snapshot__@examples__employees-2.prql.snap | 23 +- ...snapshot__@examples__employees-3.prql.snap | 11 +- .../snapshot__@examples__misc-0.prql.snap | 15 +- ...snapshot__@examples__variables-0.prql.snap | 3 +- ...snapshot__@examples__variables-1.prql.snap | 9 +- .../snapshot__@introduction-0.prql.snap | 5 +- ...__@language-features__distinct-2.prql.snap | 3 +- ..._@language-features__s-strings-3.prql.snap | 13 +- ...ge-features__standard-library-0.prql.snap} | 3 +- ...atures__standard-library__loop-0.prql.snap | 34 - .../snapshot__@queries__pipelines-2.prql.snap | 9 +- .../snapshot__@queries__variables-0.prql.snap | 4 +- .../snapshots/snapshot__@syntax-5.prql.snap | 3 +- ...pshot__@transforms__from_text-0.prql.snap} | 6 +- ...pshot__@transforms__from_text-1.prql.snap} | 2 +- ...pshot__@transforms__from_text-2.prql.snap} | 2 +- .../snapshot__@transforms__group-2.prql.snap | 3 +- .../snapshot__@transforms__sort-3.prql.snap | 17 +- .../snapshot__@transforms__sort-5.prql.snap | 7 +- .../snapshot__@transforms__window-4.prql.snap | 3 +- ...ge-features__standard-library-0.prql.snap} | 2 +- ...atures__standard-library__loop-0.prql.snap | 13 - ...ce_prql@transforms__from_text-0.prql.snap} | 2 +- ...ce_prql@transforms__from_text-1.prql.snap} | 2 +- ...ce_prql@transforms__from_text-2.prql.snap} | 2 +- prql-compiler/src/ast/pl/expr.rs | 1 - prql-compiler/src/ast/pl/fold.rs | 1 - prql-compiler/src/ast/pl/types.rs | 8 +- prql-compiler/src/ast/rq/fold.rs | 1 - prql-compiler/src/ast/rq/transform.rs | 1 - prql-compiler/src/semantic/lowering.rs | 33 +- prql-compiler/src/semantic/std.prql | 1 - prql-compiler/src/semantic/transforms.rs | 8 - .../prql_compiler__test__prql_to_sql_2.snap | 3 +- prql-compiler/src/sql/anchor.rs | 87 +-- prql-compiler/src/sql/context.rs | 61 +- prql-compiler/src/sql/gen_expr.rs | 75 +- prql-compiler/src/sql/gen_query.rs | 687 ++++++++---------- prql-compiler/src/sql/mod.rs | 35 - prql-compiler/src/sql/preprocess.rs | 68 +- ...query__test__variable_after_aggregate.snap | 3 +- prql-compiler/src/test.rs | 291 +++----- .../tests/integration/queries/loop.prql | 7 - .../integration__tests__test@loop.prql.snap | 12 - 64 files changed, 743 insertions(+), 1107 deletions(-) rename book/src/language-features/{standard-library/README.md => standard-library.md} (98%) delete mode 100644 book/src/language-features/standard-library/from-text.md delete mode 100644 book/src/language-features/standard-library/loop.md rename book/tests/prql/language-features/{standard-library/README-0.prql => standard-library-0.prql} (100%) delete mode 100644 book/tests/prql/language-features/standard-library/loop-0.prql rename book/tests/prql/{language-features/standard-library/from-text-0.prql => transforms/from_text-0.prql} (100%) rename book/tests/prql/{language-features/standard-library/from-text-1.prql => transforms/from_text-1.prql} (100%) rename book/tests/prql/{language-features/standard-library/from-text-2.prql => transforms/from_text-2.prql} (100%) rename book/tests/snapshots/{snapshot__@language-features__standard-library__README-0.prql.snap => snapshot__@language-features__standard-library-0.prql.snap} (84%) delete mode 100644 book/tests/snapshots/snapshot__@language-features__standard-library__loop-0.prql.snap rename book/tests/snapshots/{snapshot__@language-features__standard-library__from-text-0.prql.snap => snapshot__@transforms__from_text-0.prql.snap} (73%) rename book/tests/snapshots/{snapshot__@language-features__standard-library__from-text-1.prql.snap => snapshot__@transforms__from_text-1.prql.snap} (90%) rename book/tests/snapshots/{snapshot__@language-features__standard-library__from-text-2.prql.snap => snapshot__@transforms__from_text-2.prql.snap} (91%) rename book/tests/snapshots/{snapshot__run_display_reference_prql@language-features__standard-library__README-0.prql.snap => snapshot__run_display_reference_prql@language-features__standard-library-0.prql.snap} (76%) delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__standard-library__loop-0.prql.snap rename book/tests/snapshots/{snapshot__run_display_reference_prql@language-features__standard-library__from-text-0.prql.snap => snapshot__run_display_reference_prql@transforms__from_text-0.prql.snap} (69%) rename book/tests/snapshots/{snapshot__run_display_reference_prql@language-features__standard-library__from-text-1.prql.snap => snapshot__run_display_reference_prql@transforms__from_text-1.prql.snap} (76%) rename book/tests/snapshots/{snapshot__run_display_reference_prql@language-features__standard-library__from-text-2.prql.snap => snapshot__run_display_reference_prql@transforms__from_text-2.prql.snap} (82%) delete mode 100644 prql-compiler/tests/integration/queries/loop.prql delete mode 100644 prql-compiler/tests/integration/snapshots/integration__tests__test@loop.prql.snap diff --git a/CHANGELOG.md b/CHANGELOG.md index d42f9d8eee82..fa1d666d8796 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,8 +4,6 @@ **Features**: -- `loop`, which translates to `WITH RECURSIVE` (#1642, @aljazerzen) - **Fixes**: **Documentation**: diff --git a/book/README.md b/book/README.md index 57b803d93865..ec088b512dcb 100644 --- a/book/README.md +++ b/book/README.md @@ -1,4 +1,4 @@ -# PRQL language book +# PRQL Language Book These docs serve as a language book, for users of the language. They should be friendly & accessible, at a minimum to those who understand basic SQL. diff --git a/book/book.toml b/book/book.toml index 8c10a1e4b368..f503dc2bb7a9 100644 --- a/book/book.toml +++ b/book/book.toml @@ -2,7 +2,7 @@ description = "Modern language for transforming data — a simple, powerful, pipelined SQL replacement" language = "en" multilingual = false -title = "PRQL language book" +title = "PRQL Language Book" [output.html] additional-css = ["comparison-table.css", "mdbook-admonish.css"] diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md index cc27566b74a2..153e70bdb090 100644 --- a/book/src/SUMMARY.md +++ b/book/src/SUMMARY.md @@ -36,9 +36,7 @@ - [Ranges](./language-features/ranges.md) - [Regex](./language-features/regex.md) - - [Standard library](./language-features/standard-library/README.md) - - [From text](./language-features/standard-library/from-text.md) - - [Loop](./language-features/standard-library/loop.md) + - [Stdlib](./language-features/standard-library.md) - [Strings](./language-features/strings.md) - [S-strings](./language-features/s-strings.md) - [F-strings](./language-features/f-strings.md) diff --git a/book/src/integrations/jupyter.md b/book/src/integrations/jupyter.md index 7b0bdd3c063d..176a47ac11ad 100644 --- a/book/src/integrations/jupyter.md +++ b/book/src/integrations/jupyter.md @@ -24,7 +24,7 @@ could to go! We bundle in `IPython` and `pandas`, though you'll need to install pip install pyprql ``` -### Set up +### Set Up Open up either an `IPython` terminal or `Jupyter` notebook. First, we need to load the extension and connect to a database. diff --git a/book/src/integrations/rill.md b/book/src/integrations/rill.md index 0e2f4729e32e..950e0b5fb50d 100644 --- a/book/src/integrations/rill.md +++ b/book/src/integrations/rill.md @@ -1,5 +1,5 @@ # Rill PRQL has had some work to integrate with Rill. See the -[Rill ssues](https://github.com/PRQL/prql/issues?q=is%3Aissue+rill) for more +[Rill Issues](https://github.com/PRQL/prql/issues?q=is%3Aissue+rill) for more details. diff --git a/book/src/internals/name-resolving.md b/book/src/internals/name-resolving.md index 78a153358959..74b590e93a14 100644 --- a/book/src/internals/name-resolving.md +++ b/book/src/internals/name-resolving.md @@ -50,7 +50,7 @@ three things can happen: ## Translating to SQL -When translating into an SQL statement which references only one table, there is +When translating into a SQL statement which references only one table, there is no need to reference column names with table prefix. ```prql diff --git a/book/src/language-features/standard-library/README.md b/book/src/language-features/standard-library.md similarity index 98% rename from book/src/language-features/standard-library/README.md rename to book/src/language-features/standard-library.md index 1ccbbc5d92f8..220565d5cf3d 100644 --- a/book/src/language-features/standard-library/README.md +++ b/book/src/language-features/standard-library.md @@ -1,4 +1,4 @@ -# Standard library +# Standard Library The standard library currently contains commonly used functions that are used in SQL. It's not yet as broad as we'd like, and we're very open to expanding it. diff --git a/book/src/language-features/standard-library/from-text.md b/book/src/language-features/standard-library/from-text.md deleted file mode 100644 index 29229f6db0ef..000000000000 --- a/book/src/language-features/standard-library/from-text.md +++ /dev/null @@ -1,63 +0,0 @@ -# From text - -It's often useful to make a small table inline, for example when exploring how a -database will evaluate an expression, or to have a small lookup table inline. -This can be quite verbose in SQL. - -PRQL uses `from_text` for this. - -It accepts a few formats: - -- `format:csv` parses CSV (default), -- `format:json` parses either: - - an array of objects each of which represents a row, or - - an object with fields `columns` & `data`, where `columns` take an array of - column names and `data` takes an array of arrays. - -```prql -from_text """ -a,b,c -1,2,3 -4,5,6 -""" -derive [ - d = b + c, - answer = 20 * 2 + 2, -] -``` - -An example of adding a small lookup table: - -```prql -let temp_format_lookup = from_text format:csv """ -country_code,format -uk,C -us,F -lr,F -de,C -""" - -from temperatures -join temp_format_lookup [==country_code] -``` - -And JSON: - -```prql -let x = from_text format:json """{ - "columns": ["a", "b", "c"], - "data": [ - [1, "x", false], - [4, "y", null] - ] -}""" - -let y = from_text format:json """ - [ - {"a": 1, "m": "5"}, - {"a": 4, "n": "6"} - ] -""" - -from x | join y [==a] -``` diff --git a/book/src/language-features/standard-library/loop.md b/book/src/language-features/standard-library/loop.md deleted file mode 100644 index 97f462a8b5cc..000000000000 --- a/book/src/language-features/standard-library/loop.md +++ /dev/null @@ -1,50 +0,0 @@ -# Loop - -> _experimental_ - -```prql_no_test -loop {step_function} {initial_relation} -``` - -Iteratively applies `step` function to `initial` relation until the `step` -returns an empty table. Returns a relation that contains rows of initial -relation and all intermediate relations. - -This behavior could be expressed with following pseudo-code: - -``` -def loop(step, initial): - result = [] - current = initial - while current is not empty: - result = append(result, current) - current = step(current) - - return result -``` - -## Examples - -```prql -from_text format:json '[{"n": 1 }]' -loop ( - filter n<4 - select n = n+1 -) - -# returns [1, 2, 3, 4] -``` - -```admonish -Behavior of WITH RECURSIVE may depend on database configuration (MySQL). -prql-compiler assumes behavior described by -[Postgres documentation](https://www.postgresql.org/docs/15/queries-with.html#QUERIES-WITH-RECURSIVE) -and will not produce correct results for -[alternative configurations of MySQL](https://dev.mysql.com/doc/refman/8.0/en/with.html#common-table-expressions-recursive). -``` - -```admonish -Currently, `loop` may produce references to the recursive CTE in sub-queries, -which is not supported by some database engines (SQLite). For now, we suggest you keep step -functions simple enough to fit into a single SELECT statement. -``` diff --git a/book/src/syntax.md b/book/src/syntax.md index b23537228f4c..3c0afc5dd5b7 100644 --- a/book/src/syntax.md +++ b/book/src/syntax.md @@ -166,7 +166,7 @@ sort (-distance) sort [-distance] ``` -## Inner transforms +## Inner Transforms Parentheses are also used for transforms (such as `group` and `window`) that pass their result to an "inner transform". The example below applies the diff --git a/book/src/transforms/from_text.md b/book/src/transforms/from_text.md index a05d2a4b011d..0a9b51160ca7 100644 --- a/book/src/transforms/from_text.md +++ b/book/src/transforms/from_text.md @@ -1 +1,62 @@ # From Text + +It's often useful to make a small table inline, for example when exploring how a +database will evaluate an expression, or to have a small lookup table inline. +This can be quite verbose in SQL. + +PRQL uses `from_text` for this. + +It accepts a few formats: + +- `format:csv`; also the default, for CSV. +- `format:json` for either: + - A list of dicts, + - or a schema of `columns` & `data>`. + +```prql +from_text """ +a,b,c +1,2,3 +4,5,6 +""" +derive [ + d = b + c, + answer = 20 * 2 + 2, +] +``` + +An example of adding a small lookup table: + +```prql +let temp_format_lookup = from_text format:csv """ +country_code,format +uk,C +us,F +lr,F +de,C +""" + +from temperatures +join temp_format_lookup [==country_code] +``` + +And JSON: + +```prql +let x = from_text format:json """{ + "columns": ["a", "b", "c"], + "data": [ + [1, "x", false], + [4, "y", null] + ] +}""" + +let y = from_text format:json """ + [ + {"a": 1, "m": "5"}, + {"a": 4, "n": "6"} + ] +""" + +from x | join y [==a] +``` diff --git a/book/tests/prql/language-features/standard-library/README-0.prql b/book/tests/prql/language-features/standard-library-0.prql similarity index 100% rename from book/tests/prql/language-features/standard-library/README-0.prql rename to book/tests/prql/language-features/standard-library-0.prql diff --git a/book/tests/prql/language-features/standard-library/loop-0.prql b/book/tests/prql/language-features/standard-library/loop-0.prql deleted file mode 100644 index 5dccfdba14ae..000000000000 --- a/book/tests/prql/language-features/standard-library/loop-0.prql +++ /dev/null @@ -1,7 +0,0 @@ -from_text format:json '[{"n": 1 }]' -loop ( - filter n<4 - select n = n+1 -) - -# returns [1, 2, 3, 4] diff --git a/book/tests/prql/language-features/standard-library/from-text-0.prql b/book/tests/prql/transforms/from_text-0.prql similarity index 100% rename from book/tests/prql/language-features/standard-library/from-text-0.prql rename to book/tests/prql/transforms/from_text-0.prql diff --git a/book/tests/prql/language-features/standard-library/from-text-1.prql b/book/tests/prql/transforms/from_text-1.prql similarity index 100% rename from book/tests/prql/language-features/standard-library/from-text-1.prql rename to book/tests/prql/transforms/from_text-1.prql diff --git a/book/tests/prql/language-features/standard-library/from-text-2.prql b/book/tests/prql/transforms/from_text-2.prql similarity index 100% rename from book/tests/prql/language-features/standard-library/from-text-2.prql rename to book/tests/prql/transforms/from_text-2.prql diff --git a/book/tests/snapshots/snapshot__@examples__cte-0.prql.snap b/book/tests/snapshots/snapshot__@examples__cte-0.prql.snap index 36a99fd31e3f..5e55e6c27d2b 100644 --- a/book/tests/snapshots/snapshot__@examples__cte-0.prql.snap +++ b/book/tests/snapshots/snapshot__@examples__cte-0.prql.snap @@ -1,9 +1,18 @@ --- source: book/tests/snapshot.rs -expression: "let newest_employees = (\n from employees\n sort tenure\n take 50\n)\n\nlet average_salaries = (\n from salaries\n group country (\n aggregate average_country_salary = (average salary)\n )\n)\n\nfrom newest_employees\njoin average_salaries [==country]\nselect [name, salary, average_country_salary]\n" +expression: "table newest_employees = (\n from employees\n sort tenure\n take 50\n)\n\ntable average_salaries = (\n from salaries\n group country (\n aggregate average_country_salary = (average salary)\n )\n)\n\nfrom newest_employees\njoin average_salaries [==country]\nselect [name, salary, average_country_salary]\n" input_file: book/tests/prql/examples/cte-0.prql --- -WITH newest_employees AS ( +WITH average_salaries AS ( + SELECT + country, + AVG(salary) AS average_country_salary + FROM + salaries + GROUP BY + country +), +newest_employees AS ( SELECT * FROM @@ -12,14 +21,6 @@ WITH newest_employees AS ( tenure LIMIT 50 -), average_salaries AS ( - SELECT - country, - AVG(salary) AS average_country_salary - FROM - salaries - GROUP BY - country ) SELECT newest_employees.name, @@ -28,4 +29,3 @@ SELECT FROM newest_employees JOIN average_salaries ON newest_employees.country = average_salaries.country - diff --git a/book/tests/snapshots/snapshot__@examples__employees-0.prql.snap b/book/tests/snapshots/snapshot__@examples__employees-0.prql.snap index 47650f37675d..2ed2d4eba75e 100644 --- a/book/tests/snapshots/snapshot__@examples__employees-0.prql.snap +++ b/book/tests/snapshots/snapshot__@examples__employees-0.prql.snap @@ -3,7 +3,7 @@ source: book/tests/snapshot.rs expression: "from salaries\ngroup [emp_no] (\n aggregate [emp_salary = average salary]\n)\njoin t=titles [==emp_no]\njoin dept_emp side:left [==emp_no]\ngroup [dept_emp.dept_no, t.title] (\n aggregate [avg_salary = average emp_salary]\n)\njoin departments [==dept_no]\nselect [dept_name, title, avg_salary]\n" input_file: book/tests/prql/examples/employees-0.prql --- -WITH table_3 AS ( +WITH table_1 AS ( SELECT AVG(salary) AS _expr_0, emp_no @@ -12,24 +12,23 @@ WITH table_3 AS ( GROUP BY emp_no ), -table_1 AS ( +table_2 AS ( SELECT t.title, - AVG(table_2._expr_0) AS avg_salary, + AVG(table_1._expr_0) AS avg_salary, dept_emp.dept_no FROM - table_3 AS table_2 - JOIN titles AS t ON table_2.emp_no = t.emp_no - LEFT JOIN dept_emp ON table_2.emp_no = dept_emp.emp_no + table_1 + JOIN titles AS t ON table_1.emp_no = t.emp_no + LEFT JOIN dept_emp ON table_1.emp_no = dept_emp.emp_no GROUP BY dept_emp.dept_no, t.title ) SELECT departments.dept_name, - table_0.title, - table_0.avg_salary + table_2.title, + table_2.avg_salary FROM - table_1 AS table_0 - JOIN departments ON table_0.dept_no = departments.dept_no - + table_2 + JOIN departments ON table_2.dept_no = departments.dept_no diff --git a/book/tests/snapshots/snapshot__@examples__employees-1.prql.snap b/book/tests/snapshots/snapshot__@examples__employees-1.prql.snap index 88f00f10486c..434d377e6067 100644 --- a/book/tests/snapshots/snapshot__@examples__employees-1.prql.snap +++ b/book/tests/snapshots/snapshot__@examples__employees-1.prql.snap @@ -3,7 +3,7 @@ source: book/tests/snapshot.rs expression: "from e=employees\njoin salaries [==emp_no]\ngroup [e.emp_no, e.gender] (\n aggregate [\n emp_salary = average salaries.salary\n ]\n)\njoin de=dept_emp [==emp_no] side:left\ngroup [de.dept_no, gender] (\n aggregate [\n salary_avg = average emp_salary,\n salary_sd = stddev emp_salary,\n ]\n)\njoin departments [==dept_no]\nselect [dept_name, gender, salary_avg, salary_sd]\n" input_file: book/tests/prql/examples/employees-1.prql --- -WITH table_3 AS ( +WITH table_1 AS ( SELECT e.gender, AVG(salaries.salary) AS _expr_0, @@ -15,25 +15,24 @@ WITH table_3 AS ( e.emp_no, e.gender ), -table_1 AS ( +table_2 AS ( SELECT - table_2.gender, - AVG(table_2._expr_0) AS salary_avg, - STDDEV(table_2._expr_0) AS salary_sd, + table_1.gender, + AVG(table_1._expr_0) AS salary_avg, + STDDEV(table_1._expr_0) AS salary_sd, de.dept_no FROM - table_3 AS table_2 - LEFT JOIN dept_emp AS de ON table_2.emp_no = de.emp_no + table_1 + LEFT JOIN dept_emp AS de ON table_1.emp_no = de.emp_no GROUP BY de.dept_no, - table_2.gender + table_1.gender ) SELECT departments.dept_name, - table_0.gender, - table_0.salary_avg, - table_0.salary_sd + table_2.gender, + table_2.salary_avg, + table_2.salary_sd FROM - table_1 AS table_0 - JOIN departments ON table_0.dept_no = departments.dept_no - + table_2 + JOIN departments ON table_2.dept_no = departments.dept_no diff --git a/book/tests/snapshots/snapshot__@examples__employees-2.prql.snap b/book/tests/snapshots/snapshot__@examples__employees-2.prql.snap index 612ece4db0c6..6918730104c0 100644 --- a/book/tests/snapshots/snapshot__@examples__employees-2.prql.snap +++ b/book/tests/snapshots/snapshot__@examples__employees-2.prql.snap @@ -3,7 +3,7 @@ source: book/tests/snapshot.rs expression: "from e=employees\njoin salaries [==emp_no]\ngroup [e.emp_no, e.gender] (\n aggregate [\n emp_salary = average salaries.salary\n ]\n)\njoin de=dept_emp [==emp_no]\njoin dm=dept_manager [\n (dm.dept_no == de.dept_no) and s\"(de.from_date, de.to_date) OVERLAPS (dm.from_date, dm.to_date)\"\n]\ngroup [dm.emp_no, gender] (\n aggregate [\n salary_avg = average emp_salary,\n salary_sd = stddev emp_salary\n ]\n)\nderive mng_no = emp_no\njoin managers=employees [==emp_no]\nderive mng_name = s\"managers.first_name || ' ' || managers.last_name\"\nselect [mng_name, managers.gender, salary_avg, salary_sd]\n" input_file: book/tests/prql/examples/employees-2.prql --- -WITH table_3 AS ( +WITH table_1 AS ( SELECT e.gender, AVG(salaries.salary) AS _expr_0, @@ -15,26 +15,25 @@ WITH table_3 AS ( e.emp_no, e.gender ), -table_1 AS ( +table_2 AS ( SELECT - AVG(table_2._expr_0) AS salary_avg, - STDDEV(table_2._expr_0) AS salary_sd, + AVG(table_1._expr_0) AS salary_avg, + STDDEV(table_1._expr_0) AS salary_sd, dm.emp_no FROM - table_3 AS table_2 - JOIN dept_emp AS de ON table_2.emp_no = de.emp_no + table_1 + JOIN dept_emp AS de ON table_1.emp_no = de.emp_no JOIN dept_manager AS dm ON dm.dept_no = de.dept_no AND (de.from_date, de.to_date) OVERLAPS (dm.from_date, dm.to_date) GROUP BY dm.emp_no, - table_2.gender + table_1.gender ) SELECT managers.first_name || ' ' || managers.last_name AS mng_name, managers.gender, - table_0.salary_avg, - table_0.salary_sd + table_2.salary_avg, + table_2.salary_sd FROM - table_1 AS table_0 - JOIN employees AS managers ON table_0.emp_no = managers.emp_no - + table_2 + JOIN employees AS managers ON table_2.emp_no = managers.emp_no diff --git a/book/tests/snapshots/snapshot__@examples__employees-3.prql.snap b/book/tests/snapshots/snapshot__@examples__employees-3.prql.snap index 68c457076ef7..fa439fbf23c0 100644 --- a/book/tests/snapshots/snapshot__@examples__employees-3.prql.snap +++ b/book/tests/snapshots/snapshot__@examples__employees-3.prql.snap @@ -17,12 +17,11 @@ WITH table_1 AS ( de.dept_no ) SELECT - table_0.dept_no, - table_0.salary, + table_1.dept_no, + table_1.salary, employees.gender, titles.title FROM - table_1 AS table_0 - JOIN employees ON table_0.emp_no = employees.emp_no - JOIN titles ON table_0.emp_no = titles.emp_no - + table_1 + JOIN employees ON table_1.emp_no = employees.emp_no + JOIN titles ON table_1.emp_no = titles.emp_no diff --git a/book/tests/snapshots/snapshot__@examples__misc-0.prql.snap b/book/tests/snapshots/snapshot__@examples__misc-0.prql.snap index 676b3103af9c..b12126c24dd3 100644 --- a/book/tests/snapshots/snapshot__@examples__misc-0.prql.snap +++ b/book/tests/snapshots/snapshot__@examples__misc-0.prql.snap @@ -1,9 +1,15 @@ --- source: book/tests/snapshot.rs -expression: "# TODO: this table should have a column `part` with values 1..5,\n# but such data declaration is not yet supported, see #286\nlet parts = (\n from seq_1_to_5\n)\n\nfrom pl=prospect_lists_prospects\nfilter prospect_list_id == 'cc675eee-8bd1-237f-be5e-622ba511d65e'\njoin a=accounts [a.id == pl.related_id]\njoin er=email_addr_bean_rel [er.bean_id == a.id and er.primary_address == '1']\njoin ea=email_addresses [ea.id == er.email_address_id]\nselect ea.email_address\nderive prefix = s\"regexp_replace(SUBSTRING_INDEX({email_address}, '@', 1), '[.0-9-_:]+', '.')\"\nderive stub = s\"SUBSTRING_INDEX(SUBSTRING_INDEX({prefix}, '.', part), '.', -1)\"\nselect [email_address, stub]\n" +expression: "# TODO: this table should have a column `part` with values 1..5,\n# but such data declaration is not yet supported, see #286\ntable parts = (\n from seq_1_to_5\n)\n\nfrom pl=prospect_lists_prospects\nfilter prospect_list_id == 'cc675eee-8bd1-237f-be5e-622ba511d65e'\njoin a=accounts [a.id == pl.related_id]\njoin er=email_addr_bean_rel [er.bean_id == a.id and er.primary_address == '1']\njoin ea=email_addresses [ea.id == er.email_address_id]\nselect ea.email_address\nderive prefix = s\"regexp_replace(SUBSTRING_INDEX({email_address}, '@', 1), '[.0-9-_:]+', '.')\"\nderive stub = s\"SUBSTRING_INDEX(SUBSTRING_INDEX({prefix}, '.', part), '.', -1)\"\nselect [email_address, stub]\n" input_file: book/tests/prql/examples/misc-0.prql --- -WITH table_1 AS ( +WITH parts AS ( + SELECT + * + FROM + seq_1_to_5 +), +table_1 AS ( SELECT related_id FROM @@ -27,9 +33,8 @@ SELECT -1 ) AS stub FROM - table_1 AS table_0 - JOIN accounts AS a ON a.id = table_0.related_id + table_1 + JOIN accounts AS a ON a.id = table_1.related_id JOIN email_addr_bean_rel AS er ON er.bean_id = a.id AND er.primary_address = '1' JOIN email_addresses AS ea ON ea.id = er.email_address_id - diff --git a/book/tests/snapshots/snapshot__@examples__variables-0.prql.snap b/book/tests/snapshots/snapshot__@examples__variables-0.prql.snap index 69e10cb2c16d..9f7411a758ba 100644 --- a/book/tests/snapshots/snapshot__@examples__variables-0.prql.snap +++ b/book/tests/snapshots/snapshot__@examples__variables-0.prql.snap @@ -26,7 +26,7 @@ SELECT SUM(_expr_0) AS sum_gross_cost, COUNT(*) AS ct FROM - table_1 AS table_0 + table_1 WHERE _expr_0 > 0 GROUP BY @@ -38,4 +38,3 @@ ORDER BY sum_gross_cost LIMIT 20 - diff --git a/book/tests/snapshots/snapshot__@examples__variables-1.prql.snap b/book/tests/snapshots/snapshot__@examples__variables-1.prql.snap index 77b68ee0c7d1..ea3da8460bb5 100644 --- a/book/tests/snapshots/snapshot__@examples__variables-1.prql.snap +++ b/book/tests/snapshots/snapshot__@examples__variables-1.prql.snap @@ -13,13 +13,12 @@ WITH table_1 AS ( emp_no ) SELECT - AVG(table_0._expr_0) / 1000 AS salary_k, - AVG(table_0._expr_0) / 1000 * 1000 AS salary + AVG(table_1._expr_0) / 1000 AS salary_k, + AVG(table_1._expr_0) / 1000 * 1000 AS salary FROM - table_1 AS table_0 - JOIN titles ON table_0.emp_no = titles.emp_no + table_1 + JOIN titles ON table_1.emp_no = titles.emp_no GROUP BY titles.title LIMIT 10 - diff --git a/book/tests/snapshots/snapshot__@introduction-0.prql.snap b/book/tests/snapshots/snapshot__@introduction-0.prql.snap index 2cfecfb1a71d..741163b2be4d 100644 --- a/book/tests/snapshots/snapshot__@introduction-0.prql.snap +++ b/book/tests/snapshots/snapshot__@introduction-0.prql.snap @@ -1,6 +1,6 @@ --- source: book/tests/snapshot.rs -expression: "from employees\nfilter start_date > @2021-01-01 # Clear date syntax\nderive [ # `derive` adds columns / variables\n gross_salary = salary + (tax ?? 0), # Terse coalesce\n gross_cost = gross_salary + benefits_cost, # Variables can use other variables\n]\nfilter gross_cost > 0\ngroup [title, country] ( # `group` runs a pipeline over each group\n aggregate [ # `aggregate` reduces each group to a value\n average gross_salary,\n sum_gross_cost = sum gross_cost, # `=` sets a column name\n ]\n)\nfilter sum_gross_cost > 100_000 # `filter` replaces both of SQL's `WHERE` & `HAVING`\nderive id = f\"{title}_{country}\" # F-strings like Python\nderive country_code = s\"LEFT(country, 2)\" # S-strings allow using SQL as an escape hatch\nsort [sum_gross_cost, -country] # `-country` means descending order\ntake 1..20 # Range expressions (also valid here as `take 20`)\n" +expression: "from employees\nfilter start_date > @2021-01-01 # Clear date syntax\nderive [ # `derive` adds columns / variables\n gross_salary = salary + (tax ?? 0), # Terse coalesce\n gross_cost = gross_salary + benefits_cost, # Variables can use other variables\n]\nfilter gross_cost > 0\ngroup [title, country] ( # `group` runs a pipeline over each group\n aggregate [ # `aggregate` reduces each group to a value\n average gross_salary,\n sum_gross_cost = sum gross_cost, # `=` sets a column name\n ]\n)\nfilter sum_gross_cost > 100_000 # `filter` replaces both of SQL's `WHERE` & `HAVING`\nderive id = f\"{title}_{country}\" # F-strings like python\nderive country_code = s\"LEFT(country, 2)\" # S-strings allow using SQL as an escape hatch\nsort [sum_gross_cost, -country] # `-country` means descending order\ntake 1..20 # Range expressions (also valid here as `take 20`)\n" input_file: book/tests/prql/introduction-0.prql --- WITH table_1 AS ( @@ -22,7 +22,7 @@ SELECT CONCAT(title, '_', country) AS id, LEFT(country, 2) AS country_code FROM - table_1 AS table_0 + table_1 WHERE _expr_0 > 0 GROUP BY @@ -35,4 +35,3 @@ ORDER BY country DESC LIMIT 20 - diff --git a/book/tests/snapshots/snapshot__@language-features__distinct-2.prql.snap b/book/tests/snapshots/snapshot__@language-features__distinct-2.prql.snap index 693c04dcf449..2d9d6d5178f5 100644 --- a/book/tests/snapshots/snapshot__@language-features__distinct-2.prql.snap +++ b/book/tests/snapshots/snapshot__@language-features__distinct-2.prql.snap @@ -17,7 +17,6 @@ WITH table_1 AS ( SELECT * FROM - table_1 AS table_0 + table_1 WHERE _expr_0 <= 1 - diff --git a/book/tests/snapshots/snapshot__@language-features__s-strings-3.prql.snap b/book/tests/snapshots/snapshot__@language-features__s-strings-3.prql.snap index 3d97e867fc17..3f5c880fd181 100644 --- a/book/tests/snapshots/snapshot__@language-features__s-strings-3.prql.snap +++ b/book/tests/snapshots/snapshot__@language-features__s-strings-3.prql.snap @@ -3,7 +3,7 @@ source: book/tests/snapshot.rs expression: "from s\"SELECT DISTINCT ON first_name, id, age FROM employees ORDER BY age ASC\"\njoin s = s\"SELECT * FROM salaries\" [==id]\n" input_file: book/tests/prql/language-features/s-strings-3.prql --- -WITH table_0 AS ( +WITH table_2 AS ( SELECT DISTINCT ON first_name, id, @@ -13,16 +13,15 @@ WITH table_0 AS ( ORDER BY age ASC ), -table_1 AS ( +table_3 AS ( SELECT * FROM salaries ) SELECT - table_2.*, - table_3.* + table_0.*, + table_1.* FROM - table_0 AS table_2 - JOIN table_1 AS table_3 ON table_2.id = table_3.id - + table_2 AS table_0 + JOIN table_3 AS table_1 ON table_0.id = table_1.id diff --git a/book/tests/snapshots/snapshot__@language-features__standard-library__README-0.prql.snap b/book/tests/snapshots/snapshot__@language-features__standard-library-0.prql.snap similarity index 84% rename from book/tests/snapshots/snapshot__@language-features__standard-library__README-0.prql.snap rename to book/tests/snapshots/snapshot__@language-features__standard-library-0.prql.snap index b3a371283e07..31e030d55e0b 100644 --- a/book/tests/snapshots/snapshot__@language-features__standard-library__README-0.prql.snap +++ b/book/tests/snapshots/snapshot__@language-features__standard-library-0.prql.snap @@ -1,7 +1,7 @@ --- source: book/tests/snapshot.rs expression: "from employees\nderive [\n gross_salary = (salary + payroll_tax | as int),\n gross_salary_rounded = (gross_salary | round 0),\n time = s\"NOW()\", # an s-string, given no `now` function exists in PRQL\n]\n" -input_file: book/tests/prql/language-features/standard-library/README-0.prql +input_file: book/tests/prql/language-features/standard-library-0.prql --- SELECT *, @@ -10,4 +10,3 @@ SELECT NOW() AS time FROM employees - diff --git a/book/tests/snapshots/snapshot__@language-features__standard-library__loop-0.prql.snap b/book/tests/snapshots/snapshot__@language-features__standard-library__loop-0.prql.snap deleted file mode 100644 index 5515357a6c0c..000000000000 --- a/book/tests/snapshots/snapshot__@language-features__standard-library__loop-0.prql.snap +++ /dev/null @@ -1,34 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from_text format:json '[{\"n\": 1 }]'\nloop (\n filter n<4\n select n = n+1\n)\n\n# returns [1, 2, 3, 4]\n" -input_file: book/tests/prql/language-features/standard-library/loop-0.prql ---- -WITH table_0 AS ( - SELECT - 1 AS n -), -table_4 AS ( - WITH RECURSIVE loop AS ( - SELECT - n - FROM - table_0 AS table_1 - UNION - ALL - SELECT - n + 1 - FROM - loop AS table_2 - WHERE - n < 4 - ) - SELECT - * - FROM - loop -) -SELECT - n -FROM - table_4 AS table_3 - diff --git a/book/tests/snapshots/snapshot__@queries__pipelines-2.prql.snap b/book/tests/snapshots/snapshot__@queries__pipelines-2.prql.snap index 8a7e0fd99bc5..48c578cb780a 100644 --- a/book/tests/snapshots/snapshot__@queries__pipelines-2.prql.snap +++ b/book/tests/snapshots/snapshot__@queries__pipelines-2.prql.snap @@ -16,10 +16,9 @@ WITH table_1 AS ( 10 ) SELECT - table_0.name, - table_0.gross_salary, + table_1.name, + table_1.gross_salary, d.name FROM - table_1 AS table_0 - JOIN department AS d ON table_0.dept_no = d.dept_no - + table_1 + JOIN department AS d ON table_1.dept_no = d.dept_no diff --git a/book/tests/snapshots/snapshot__@queries__variables-0.prql.snap b/book/tests/snapshots/snapshot__@queries__variables-0.prql.snap index ca97469b4749..e37a88722453 100644 --- a/book/tests/snapshots/snapshot__@queries__variables-0.prql.snap +++ b/book/tests/snapshots/snapshot__@queries__variables-0.prql.snap @@ -3,7 +3,7 @@ source: book/tests/snapshot.rs expression: "let top_50 = (\n from employees\n sort salary\n take 50\n aggregate [total_salary = sum salary]\n)\n\nfrom top_50 # Starts a new pipeline\n" input_file: book/tests/prql/queries/variables-0.prql --- -WITH table_1 AS ( +WITH table_0 AS ( SELECT salary FROM @@ -16,7 +16,7 @@ WITH table_1 AS ( SELECT SUM(salary) AS total_salary FROM - table_1 AS table_0 + table_0 ) SELECT total_salary diff --git a/book/tests/snapshots/snapshot__@syntax-5.prql.snap b/book/tests/snapshots/snapshot__@syntax-5.prql.snap index 9095768d6603..374cbd663cf3 100644 --- a/book/tests/snapshots/snapshot__@syntax-5.prql.snap +++ b/book/tests/snapshots/snapshot__@syntax-5.prql.snap @@ -14,8 +14,7 @@ SELECT circumference, color FROM - table_1 AS table_0 + table_1 WHERE circumference > 10 AND color <> 'red' - diff --git a/book/tests/snapshots/snapshot__@language-features__standard-library__from-text-0.prql.snap b/book/tests/snapshots/snapshot__@transforms__from_text-0.prql.snap similarity index 73% rename from book/tests/snapshots/snapshot__@language-features__standard-library__from-text-0.prql.snap rename to book/tests/snapshots/snapshot__@transforms__from_text-0.prql.snap index 904a45d549da..59de499b2072 100644 --- a/book/tests/snapshots/snapshot__@language-features__standard-library__from-text-0.prql.snap +++ b/book/tests/snapshots/snapshot__@transforms__from_text-0.prql.snap @@ -1,9 +1,9 @@ --- source: book/tests/snapshot.rs expression: "from_text \"\"\"\na,b,c\n1,2,3\n4,5,6\n\"\"\"\nderive [\n d = b + c,\n answer = 20 * 2 + 2,\n]\n" -input_file: book/tests/prql/language-features/standard-library/from-text-0.prql +input_file: book/tests/prql/transforms/from_text-0.prql --- -WITH table_0 AS ( +WITH table_1 AS ( SELECT '1' AS a, '2' AS b, @@ -22,5 +22,5 @@ SELECT b + c AS d, 42 AS answer FROM - table_0 AS table_1 + table_1 AS table_0 diff --git a/book/tests/snapshots/snapshot__@language-features__standard-library__from-text-1.prql.snap b/book/tests/snapshots/snapshot__@transforms__from_text-1.prql.snap similarity index 90% rename from book/tests/snapshots/snapshot__@language-features__standard-library__from-text-1.prql.snap rename to book/tests/snapshots/snapshot__@transforms__from_text-1.prql.snap index 670e58dfc204..9ae070f052eb 100644 --- a/book/tests/snapshots/snapshot__@language-features__standard-library__from-text-1.prql.snap +++ b/book/tests/snapshots/snapshot__@transforms__from_text-1.prql.snap @@ -1,7 +1,7 @@ --- source: book/tests/snapshot.rs expression: "let temp_format_lookup = from_text format:csv \"\"\"\ncountry_code,format\nuk,C\nus,F\nlr,F\nde,C\n\"\"\"\n\nfrom temperatures\njoin temp_format_lookup [==country_code]\n" -input_file: book/tests/prql/language-features/standard-library/from-text-1.prql +input_file: book/tests/prql/transforms/from_text-1.prql --- WITH table_0 AS ( SELECT diff --git a/book/tests/snapshots/snapshot__@language-features__standard-library__from-text-2.prql.snap b/book/tests/snapshots/snapshot__@transforms__from_text-2.prql.snap similarity index 91% rename from book/tests/snapshots/snapshot__@language-features__standard-library__from-text-2.prql.snap rename to book/tests/snapshots/snapshot__@transforms__from_text-2.prql.snap index becf706977bb..085bbccf68f8 100644 --- a/book/tests/snapshots/snapshot__@language-features__standard-library__from-text-2.prql.snap +++ b/book/tests/snapshots/snapshot__@transforms__from_text-2.prql.snap @@ -1,7 +1,7 @@ --- source: book/tests/snapshot.rs expression: "let x = from_text format:json \"\"\"{\n \"columns\": [\"a\", \"b\", \"c\"],\n \"data\": [\n [1, \"x\", false],\n [4, \"y\", null]\n ]\n}\"\"\"\n\nlet y = from_text format:json \"\"\"\n [\n {\"a\": 1, \"m\": \"5\"},\n {\"a\": 4, \"n\": \"6\"}\n ]\n\"\"\"\n\nfrom x | join y [==a]\n" -input_file: book/tests/prql/language-features/standard-library/from-text-2.prql +input_file: book/tests/prql/transforms/from_text-2.prql --- WITH table_0 AS ( SELECT diff --git a/book/tests/snapshots/snapshot__@transforms__group-2.prql.snap b/book/tests/snapshots/snapshot__@transforms__group-2.prql.snap index 03289443cc04..a11503ab56c8 100644 --- a/book/tests/snapshots/snapshot__@transforms__group-2.prql.snap +++ b/book/tests/snapshots/snapshot__@transforms__group-2.prql.snap @@ -17,7 +17,6 @@ WITH table_1 AS ( SELECT * FROM - table_1 AS table_0 + table_1 WHERE _expr_0 <= 1 - diff --git a/book/tests/snapshots/snapshot__@transforms__sort-3.prql.snap b/book/tests/snapshots/snapshot__@transforms__sort-3.prql.snap index fb7acd653ec6..7b6e784e1da0 100644 --- a/book/tests/snapshots/snapshot__@transforms__sort-3.prql.snap +++ b/book/tests/snapshots/snapshot__@transforms__sort-3.prql.snap @@ -3,11 +3,16 @@ source: book/tests/snapshot.rs expression: "from employees\nsort [s\"substr({first_name}, 2, 5)\"]\n" input_file: book/tests/prql/transforms/sort-3.prql --- +WITH table_1 AS ( + SELECT + *, + substr(first_name, 2, 5) AS _expr_0 + FROM + employees + ORDER BY + _expr_0 +) SELECT - *, - substr(first_name, 2, 5) AS _expr_0 + * FROM - employees -ORDER BY - _expr_0 - + table_1 diff --git a/book/tests/snapshots/snapshot__@transforms__sort-5.prql.snap b/book/tests/snapshots/snapshot__@transforms__sort-5.prql.snap index b969c19b2a4d..de8d52ca5f42 100644 --- a/book/tests/snapshots/snapshot__@transforms__sort-5.prql.snap +++ b/book/tests/snapshots/snapshot__@transforms__sort-5.prql.snap @@ -12,9 +12,8 @@ WITH table_1 AS ( tenure ) SELECT - table_0.*, + table_1.*, locations.* FROM - table_1 AS table_0 - JOIN locations ON table_0.employee_id = locations.employee_id - + table_1 + JOIN locations ON table_1.employee_id = locations.employee_id diff --git a/book/tests/snapshots/snapshot__@transforms__window-4.prql.snap b/book/tests/snapshots/snapshot__@transforms__window-4.prql.snap index 0dcf1866c987..13bb14a01bc7 100644 --- a/book/tests/snapshots/snapshot__@transforms__window-4.prql.snap +++ b/book/tests/snapshots/snapshot__@transforms__window-4.prql.snap @@ -13,7 +13,6 @@ WITH table_1 AS ( SELECT * FROM - table_1 AS table_0 + table_1 WHERE salary < _expr_0 - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__standard-library__README-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__standard-library-0.prql.snap similarity index 76% rename from book/tests/snapshots/snapshot__run_display_reference_prql@language-features__standard-library__README-0.prql.snap rename to book/tests/snapshots/snapshot__run_display_reference_prql@language-features__standard-library-0.prql.snap index 7103d173bb5b..691cabab4a62 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__standard-library__README-0.prql.snap +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__standard-library-0.prql.snap @@ -1,7 +1,7 @@ --- source: book/tests/snapshot.rs expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/standard-library/README-0.prql +input_file: book/tests/prql/language-features/standard-library-0.prql --- from employees derive [ diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__standard-library__loop-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__standard-library__loop-0.prql.snap deleted file mode 100644 index b039f259620b..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__standard-library__loop-0.prql.snap +++ /dev/null @@ -1,13 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/standard-library/loop-0.prql ---- -from_text format:json '[{"n": 1 }]' -loop ( - filter n < 4 - select n = n + 1 -) - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__standard-library__from-text-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from_text-0.prql.snap similarity index 69% rename from book/tests/snapshots/snapshot__run_display_reference_prql@language-features__standard-library__from-text-0.prql.snap rename to book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from_text-0.prql.snap index f5eae06d50c6..d86f2e1e86bb 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__standard-library__from-text-0.prql.snap +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from_text-0.prql.snap @@ -1,7 +1,7 @@ --- source: book/tests/snapshot.rs expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/standard-library/from-text-0.prql +input_file: book/tests/prql/transforms/from_text-0.prql --- from_text " a,b,c diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__standard-library__from-text-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from_text-1.prql.snap similarity index 76% rename from book/tests/snapshots/snapshot__run_display_reference_prql@language-features__standard-library__from-text-1.prql.snap rename to book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from_text-1.prql.snap index 8dcf2f21faac..740349748e00 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__standard-library__from-text-1.prql.snap +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from_text-1.prql.snap @@ -1,7 +1,7 @@ --- source: book/tests/snapshot.rs expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/standard-library/from-text-1.prql +input_file: book/tests/prql/transforms/from_text-1.prql --- let temp_format_lookup = ( from_text format:csv " diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__standard-library__from-text-2.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from_text-2.prql.snap similarity index 82% rename from book/tests/snapshots/snapshot__run_display_reference_prql@language-features__standard-library__from-text-2.prql.snap rename to book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from_text-2.prql.snap index 13b437d66562..a0aaabe15cb7 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__standard-library__from-text-2.prql.snap +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from_text-2.prql.snap @@ -1,7 +1,7 @@ --- source: book/tests/snapshot.rs expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/standard-library/from-text-2.prql +input_file: book/tests/prql/transforms/from_text-2.prql --- let x = ( from_text format:json '{ diff --git a/prql-compiler/src/ast/pl/expr.rs b/prql-compiler/src/ast/pl/expr.rs index a3b0b7b9132c..ea3dc6f0a7b7 100644 --- a/prql-compiler/src/ast/pl/expr.rs +++ b/prql-compiler/src/ast/pl/expr.rs @@ -310,7 +310,6 @@ pub enum TransformKind { pipeline: Box, }, Append(Box), - Loop(Box), } #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] diff --git a/prql-compiler/src/ast/pl/fold.rs b/prql-compiler/src/ast/pl/fold.rs index b82f9178a296..3af403b8525d 100644 --- a/prql-compiler/src/ast/pl/fold.rs +++ b/prql-compiler/src/ast/pl/fold.rs @@ -273,7 +273,6 @@ pub fn fold_transform_kind( range: fold_range(fold, range)?, pipeline: Box::new(fold.fold_expr(*pipeline)?), }, - Loop(pipeline) => Loop(Box::new(fold.fold_expr(*pipeline)?)), }) } diff --git a/prql-compiler/src/ast/pl/types.rs b/prql-compiler/src/ast/pl/types.rs index cb1463940c7b..3d4c428d5d75 100644 --- a/prql-compiler/src/ast/pl/types.rs +++ b/prql-compiler/src/ast/pl/types.rs @@ -6,7 +6,7 @@ use serde::{Deserialize, Serialize}; use super::Frame; -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, EnumAsInner)] +#[derive(Clone, PartialEq, Serialize, Deserialize, EnumAsInner)] pub enum Ty { Empty, Literal(TyLit), @@ -162,3 +162,9 @@ impl Display for Ty { } } } + +impl Debug for Ty { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + Display::fmt(self, f) + } +} diff --git a/prql-compiler/src/ast/rq/fold.rs b/prql-compiler/src/ast/rq/fold.rs index 1c799e35dfe0..d84d6385ba37 100644 --- a/prql-compiler/src/ast/rq/fold.rs +++ b/prql-compiler/src/ast/rq/fold.rs @@ -187,7 +187,6 @@ pub fn fold_transform( filter: fold.fold_expr(filter)?, }, Append(bottom) => Append(fold.fold_table_ref(bottom)?), - Loop(transforms) => Loop(fold_transforms(fold, transforms)?), }; Ok(transform) } diff --git a/prql-compiler/src/ast/rq/transform.rs b/prql-compiler/src/ast/rq/transform.rs index 875bc3d922b6..7a946e1d2c13 100644 --- a/prql-compiler/src/ast/rq/transform.rs +++ b/prql-compiler/src/ast/rq/transform.rs @@ -25,7 +25,6 @@ pub enum Transform { filter: Expr, }, Append(TableRef), - Loop(Vec), } #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] diff --git a/prql-compiler/src/semantic/lowering.rs b/prql-compiler/src/semantic/lowering.rs index 25383b9dd744..bb595dd20da0 100644 --- a/prql-compiler/src/semantic/lowering.rs +++ b/prql-compiler/src/semantic/lowering.rs @@ -269,7 +269,7 @@ impl Lowerer { let ty = expr.ty.clone(); let prev_pipeline = self.pipeline.drain(..).collect_vec(); - self.lower_pipeline(expr, None)?; + self.lower_pipeline(expr)?; let mut transforms = self.pipeline.drain(..).collect_vec(); let columns = self.push_select(ty, &mut transforms)?; @@ -284,22 +284,10 @@ impl Lowerer { } // Result is stored in self.pipeline - fn lower_pipeline(&mut self, ast: pl::Expr, closure_param: Option) -> Result<()> { + fn lower_pipeline(&mut self, ast: pl::Expr) -> Result<()> { let transform_call = match ast.kind { pl::ExprKind::TransformCall(transform) => transform, - pl::ExprKind::Closure(closure) => { - let param = closure.params.first(); - let param = param.and_then(|p| p.name.parse::().ok()); - return self.lower_pipeline(*closure.body, param); - } _ => { - if let Some(target) = ast.target_id { - if Some(target) == closure_param { - // ast is a closure param, so we can skip pushing From - return Ok(()); - } - } - let table_ref = self.lower_table_ref(ast)?; self.pipeline.push(Transform::From(table_ref)); return Ok(()); @@ -307,7 +295,7 @@ impl Lowerer { }; // lower input table - self.lower_pipeline(*transform_call.input, closure_param)?; + self.lower_pipeline(*transform_call.input)?; // ... and continues with transforms created in this function @@ -374,16 +362,8 @@ impl Lowerer { pl::TransformKind::Append(bottom) => { let bottom = self.lower_table_ref(*bottom)?; - self.pipeline.push(Transform::Append(bottom)); - } - pl::TransformKind::Loop(pipeline) => { - let relation = self.lower_relation(*pipeline)?; - let mut pipeline = relation.kind.into_pipeline().unwrap(); - - // last select is not needed here - pipeline.pop(); - - self.pipeline.push(Transform::Loop(pipeline)); + let transform = Transform::Append(bottom); + self.pipeline.push(transform); } pl::TransformKind::Group { .. } | pl::TransformKind::Window { .. } => unreachable!( "transform `{}` cannot be lowered.", @@ -700,10 +680,9 @@ impl Lowerer { let name = match name { Some(v) => RelationColumn::Single(Some(v.clone())), None => return Err(Error::new_simple( - "This table contains unnamed columns that need to be referenced by name", + "This table contains unnamed columns, that need to be referenced by name", ) .with_span(self.context.span_map.get(&id).cloned()) - .with_help("The name may have been overridden later in the pipeline.") .into()), }; log::trace!("lookup cid of name={name:?} in input {input_columns:?}"); diff --git a/prql-compiler/src/semantic/std.prql b/prql-compiler/src/semantic/std.prql index 586a9dcaf94f..f906e2dc7b23 100644 --- a/prql-compiler/src/semantic/std.prql +++ b/prql-compiler/src/semantic/std.prql @@ -48,7 +48,6 @@ func remove
`default_db.bottom`
top
-> ( filter (all (map _is_null b.*)) select t.* ) -func loop
pipeline top
-> null # List functions func all list -> null diff --git a/prql-compiler/src/semantic/transforms.rs b/prql-compiler/src/semantic/transforms.rs index 15c73cbbe44f..b517b2a81c33 100644 --- a/prql-compiler/src/semantic/transforms.rs +++ b/prql-compiler/src/semantic/transforms.rs @@ -192,13 +192,6 @@ pub fn cast_transform(resolver: &mut Resolver, closure: Closure) -> Result { - let [pipeline, tbl] = unpack::<2>(closure); - - let pipeline = fold_by_simulating_eval(resolver, pipeline, tbl.ty.clone().unwrap())?; - - (TransformKind::Loop(Box::new(pipeline)), tbl) - } "std.in" => { // yes, this is not a transform, but this is the most appropriate place for it @@ -589,7 +582,6 @@ impl TransformCall { let bottom = ty_frame_or_default(bottom)?; append(top, bottom)? } - Loop(_) => ty_frame_or_default(&self.input)?, Sort { .. } | Filter { .. } | Take { .. } => ty_frame_or_default(&self.input)?, }) } diff --git a/prql-compiler/src/snapshots/prql_compiler__test__prql_to_sql_2.snap b/prql-compiler/src/snapshots/prql_compiler__test__prql_to_sql_2.snap index 23a1cc2ad749..bbc44298cbb5 100644 --- a/prql-compiler/src/snapshots/prql_compiler__test__prql_to_sql_2.snap +++ b/prql-compiler/src/snapshots/prql_compiler__test__prql_to_sql_2.snap @@ -25,7 +25,7 @@ SELECT SUM(_expr_0) AS sum_gross_cost, COUNT(*) AS ct FROM - table_1 AS table_0 + table_1 WHERE _expr_0 > 0 GROUP BY @@ -37,4 +37,3 @@ ORDER BY sum_gross_cost LIMIT 20 - diff --git a/prql-compiler/src/sql/anchor.rs b/prql-compiler/src/sql/anchor.rs index 4c0e0ece9b76..6740cd2cc391 100644 --- a/prql-compiler/src/sql/anchor.rs +++ b/prql-compiler/src/sql/anchor.rs @@ -3,28 +3,28 @@ use itertools::Itertools; use std::collections::{HashMap, HashSet}; use crate::ast::rq::{ - self, fold_transform, CId, Compute, Expr, RelationColumn, RqFold, TableRef, Transform, + self, fold_transform, CId, Compute, Expr, Relation, RelationColumn, RelationKind, RqFold, + TableDecl, TableRef, Transform, }; -use crate::sql::context::SqlTableDecl; -use crate::sql::preprocess::{SqlRelation, SqlRelationKind}; use super::{ context::{AnchorContext, ColumnDecl}, preprocess::{SqlFold, SqlTransform}, }; +type RemainingPipeline = (Vec, Vec); + /// Splits pipeline into two parts, such that the second part contains /// maximum number of transforms while "fitting" into a SELECT query. pub(super) fn split_off_back( - mut pipeline: Vec, ctx: &mut AnchorContext, -) -> (Option>, Vec) { + output: Vec, + mut pipeline: Vec, +) -> (Option, Vec) { if pipeline.is_empty() { return (None, Vec::new()); } - let output = AnchorContext::determine_select_columns(&pipeline); - log::debug!("traversing pipeline to obtain columns: {output:?}"); let mut following_transforms: HashSet = HashSet::new(); @@ -137,9 +137,8 @@ pub(super) fn split_off_back( None } else { // drop inputs that were satisfied in current pipeline - pipeline.push(SqlTransform::Super(Transform::Select(missing))); - Some(pipeline) + Some((pipeline, missing)) }; curr_pipeline_rev.reverse(); @@ -167,23 +166,20 @@ fn can_materialize(compute: &Compute, inputs_required: &[Requirement]) -> bool { } /// Applies adjustments to second part of a pipeline when it's split: -/// - append Select to proceeding pipeline -/// - prepend From to atomic pipeline -/// - redefine columns materialized in atomic pipeline +/// - prepend pipeline with From +/// - redefine columns materialized in preceding pipeline /// - redirect all references to original columns to the new ones pub(super) fn anchor_split( ctx: &mut AnchorContext, - preceding: Vec, - atomic: Vec, + first_table_name: &str, + cols_at_split: &[CId], + second_pipeline: Vec, ) -> Vec { let new_tid = ctx.tid.gen(); - let preceding_select = &preceding.last().unwrap().as_super().unwrap(); - let cols_at_split = preceding_select.as_select().unwrap(); - log::debug!("split pipeline, first pipeline output: {cols_at_split:?}"); - // redefine columns of the atomic pipeline + // define columns of the new CTE let mut cid_redirects = HashMap::::new(); let mut new_columns = Vec::new(); for old_cid in cols_at_split { @@ -208,31 +204,32 @@ pub(super) fn anchor_split( // define a new table ctx.table_decls.insert( new_tid, - SqlTableDecl { + TableDecl { id: new_tid, - name: None, - relation: Some(SqlRelation { - columns: cols_at_split - .iter() - .map(|_| RelationColumn::Single(None)) - .collect_vec(), - kind: SqlRelationKind::PreprocessedPipeline(preceding), - }), + name: Some(first_table_name.to_string()), + // here we should put the pipeline, but because how this function is called, + // we need to return the pipeline directly, so we just insert dummy expr instead + relation: Relation { + kind: RelationKind::SString(vec![]), + columns: vec![], + }, }, ); // define instance of that table - let table_ref = ctx.create_table_instance(TableRef { + let table_ref = TableRef { source: new_tid, - name: None, + name: Some(first_table_name.to_string()), columns: new_columns, - }); + }; + ctx.create_table_instance(table_ref.clone()); // adjust second part: prepend from and rewrite expressions to use new columns - let mut second = atomic; + let mut second = second_pipeline; second.insert(0, SqlTransform::Super(Transform::From(table_ref))); - CidRedirector::redirect(second, cid_redirects, ctx) + let mut redirector = CidRedirector { ctx, cid_redirects }; + redirector.fold_sql_transforms(second).unwrap() } /// Determines whether a pipeline must be split at a transform to @@ -251,7 +248,6 @@ fn is_split_required(transform: &SqlTransform, following: &mut HashSet) // - take (no limit) // - distinct // - append/except/intersect (no limit) - // - loop (max 1x) // // Select is not affected by the order. use SqlTransform::*; @@ -310,7 +306,6 @@ fn is_split_required(transform: &SqlTransform, following: &mut HashSet) "Distinct", ], ), - SqlTransform::Loop(_) => !following.is_empty(), _ => false, }; @@ -392,13 +387,12 @@ pub(super) fn get_requirements( cids } - Super(Aggregate { .. } | Append(_) | Transform::Loop(_)) => unreachable!(), - Super(Select(_) | From(_)) + Super(Append(_)) => unreachable!(), + Super(Select(_) | From(_) | Aggregate { .. }) | Distinct | Union { .. } | Except { .. } - | Intersect { .. } - | SqlTransform::Loop(_) => return Vec::new(), + | Intersect { .. } => return Vec::new(), }; // general case: determine complexity @@ -508,20 +502,9 @@ impl RqFold for CidCollector { } } -pub(super) struct CidRedirector<'a> { - pub ctx: &'a mut AnchorContext, - pub cid_redirects: HashMap, -} - -impl<'a> CidRedirector<'a> { - pub fn redirect( - pipeline: Vec, - cid_redirects: HashMap, - ctx: &mut AnchorContext, - ) -> Vec { - let mut redirector = CidRedirector { ctx, cid_redirects }; - redirector.fold_sql_transforms(pipeline).unwrap() - } +struct CidRedirector<'a> { + ctx: &'a mut AnchorContext, + cid_redirects: HashMap, } impl<'a> RqFold for CidRedirector<'a> { diff --git a/prql-compiler/src/sql/context.rs b/prql-compiler/src/sql/context.rs index b9b38e1ae2bf..4fa41ea51e71 100644 --- a/prql-compiler/src/sql/context.rs +++ b/prql-compiler/src/sql/context.rs @@ -10,19 +10,19 @@ use itertools::Itertools; use crate::ast::pl::TableExternRef; use crate::ast::rq::{ - fold_table, CId, Compute, Query, Relation, RelationColumn, RelationKind, RqFold, TId, - TableDecl, TableRef, Transform, + fold_table, CId, Compute, Query, RelationColumn, RelationKind, RqFold, TId, TableDecl, + TableRef, Transform, }; use crate::utils::{IdGenerator, NameGenerator}; -use super::preprocess::{SqlRelation, SqlTransform}; +use super::preprocess::SqlTransform; #[derive(Default)] pub struct AnchorContext { pub(super) column_decls: HashMap, pub(super) column_names: HashMap, - pub(super) table_decls: HashMap, + pub(super) table_decls: HashMap, pub(super) table_instances: HashMap, @@ -33,20 +33,6 @@ pub struct AnchorContext { pub(super) tid: IdGenerator, pub(super) tiid: IdGenerator, } - -#[derive(Debug, Clone)] -pub(super) struct SqlTableDecl { - #[allow(dead_code)] - pub id: TId, - - pub name: Option, - - /// Relation that still needs to be defined (usually as CTE) so it can be referenced by name. - /// None means that it has already been defined, or was not needed to be defined in the - /// first place. - pub relation: Option, -} - /// Table instance id #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct TIId(usize); @@ -65,7 +51,7 @@ pub enum ColumnDecl { } impl AnchorContext { - pub fn of(query: Query) -> (Self, Relation) { + pub fn of(query: Query) -> (Self, Query) { let (cid, tid, query) = IdGenerator::load(query); let context = AnchorContext { @@ -92,7 +78,7 @@ impl AnchorContext { self.column_decls.insert(id, decl); } - pub fn create_table_instance(&mut self, mut table_ref: TableRef) -> TableRef { + pub fn create_table_instance(&mut self, mut table_ref: TableRef) { let tiid = self.tiid.gen(); for (col, cid) in &table_ref.columns { @@ -104,8 +90,7 @@ impl AnchorContext { table_ref.name = Some(self.table_name.gen()) } - self.table_instances.insert(tiid, table_ref.clone()); - table_ref + self.table_instances.insert(tiid, table_ref); } pub(crate) fn ensure_column_name(&mut self, cid: CId) -> Option<&String> { @@ -208,45 +193,29 @@ struct QueryLoader { } impl QueryLoader { - fn load(context: AnchorContext, query: Query) -> (AnchorContext, Relation) { + fn load(context: AnchorContext, query: Query) -> (AnchorContext, Query) { let mut loader = QueryLoader { context }; - - for t in query.tables { - loader.load_table(t).unwrap(); - } - let relation = loader.fold_relation(query.relation).unwrap(); - (loader.context, relation) + let query = loader.fold_query(query).unwrap(); + (loader.context, query) } +} - fn load_table(&mut self, table: TableDecl) -> Result<()> { +impl RqFold for QueryLoader { + fn fold_table(&mut self, table: TableDecl) -> Result { let mut decl = fold_table(self, table)?; - // assume name of the LocalTable that the relation is referencing if let RelationKind::ExternRef(TableExternRef::LocalTable(table)) = &decl.relation.kind { decl.name = Some(table.clone()); } - // generate name (if not present) if decl.name.is_none() && decl.relation.kind.as_extern_ref().is_none() { decl.name = Some(self.context.table_name.gen()); } - let sql_decl = SqlTableDecl { - id: decl.id, - name: decl.name, - relation: if matches!(decl.relation.kind, RelationKind::ExternRef(_)) { - None - } else { - Some(decl.relation.into()) - }, - }; - - self.context.table_decls.insert(decl.id, sql_decl); - Ok(()) + self.context.table_decls.insert(decl.id, decl.clone()); + Ok(decl) } -} -impl RqFold for QueryLoader { fn fold_compute(&mut self, compute: Compute) -> Result { self.context.register_compute(compute.clone()); Ok(compute) diff --git a/prql-compiler/src/sql/gen_expr.rs b/prql-compiler/src/sql/gen_expr.rs index 271b4a6a1833..51d00a1cdd8a 100644 --- a/prql-compiler/src/sql/gen_expr.rs +++ b/prql-compiler/src/sql/gen_expr.rs @@ -6,7 +6,8 @@ use lazy_static::lazy_static; use regex::Regex; use sqlparser::ast::{ self as sql_ast, BinaryOperator, DateTimeField, Function, FunctionArg, FunctionArgExpr, Ident, - ObjectName, OrderByExpr, SelectItem, Top, UnaryOperator, Value, WindowFrameBound, WindowSpec, + Join, JoinConstraint, JoinOperator, ObjectName, OrderByExpr, SelectItem, TableAlias, + TableFactor, Top, UnaryOperator, Value, WindowFrameBound, WindowSpec, }; use sqlparser::keywords::{ Keyword, ALL_KEYWORDS, ALL_KEYWORDS_INDEX, RESERVED_FOR_COLUMN_ALIAS, RESERVED_FOR_TABLE_ALIAS, @@ -14,7 +15,8 @@ use sqlparser::keywords::{ use std::collections::HashSet; use crate::ast::pl::{ - BinOp, ColumnSort, InterpolateItem, Literal, Range, SortDirection, WindowFrame, WindowKind, + BinOp, ColumnSort, InterpolateItem, JoinSide, Literal, Range, SortDirection, TableExternRef, + WindowFrame, WindowKind, }; use crate::ast::rq::*; use crate::error::{Error, Span}; @@ -185,7 +187,7 @@ pub(super) fn translate_literal(l: Literal, ctx: &Context) -> Result Result { - if ctx.query.pre_projection { + if ctx.pre_projection { log::debug!("translating {cid:?} pre projection"); let decl = ctx.anchor.column_decls.get(&cid).expect("bad RQ ids"); @@ -229,7 +231,7 @@ pub(super) fn translate_cid(cid: CId, ctx: &mut Context) -> Result { let name = ctx.anchor.column_names.get(&cid).cloned(); - name.expect("name of this column has not been to be set before generating SQL") + name.expect("a name of this column to be set before generating SQL") } }; @@ -242,6 +244,38 @@ pub(super) fn translate_cid(cid: CId, ctx: &mut Context) -> Result TableFactor { + let decl = ctx.anchor.table_decls.get(&table_ref.source).unwrap(); + + let name = match &decl.relation.kind { + // special case for anchor + RelationKind::ExternRef(TableExternRef::Anchor(anchor_id)) => { + sql_ast::ObjectName(vec![Ident::new(anchor_id.clone())]) + } + + // base case + _ => { + let decl_name = decl.name.clone().unwrap(); + + sql_ast::ObjectName(translate_ident(Some(decl_name), None, ctx)) + } + }; + + TableFactor::Table { + name, + alias: if decl.name == table_ref.name { + None + } else { + table_ref.name.map(|ident| TableAlias { + name: translate_ident_part(ident, ctx), + columns: vec![], + }) + }, + args: None, + with_hints: vec![], + } +} + pub(super) fn translate_sstring( items: Vec>, ctx: &mut Context, @@ -589,6 +623,23 @@ pub(super) fn translate_column_sort( }) } +pub(super) fn translate_join( + (side, with, filter): (JoinSide, TableRef, Expr), + ctx: &mut Context, +) -> Result { + let constraint = JoinConstraint::On(translate_expr_kind(filter.kind, ctx)?); + + Ok(Join { + relation: table_factor_of_tid(with, ctx), + join_operator: match side { + JoinSide::Inner => JoinOperator::Inner(constraint), + JoinSide::Left => JoinOperator::LeftOuter(constraint), + JoinSide::Right => JoinOperator::RightOuter(constraint), + JoinSide::Full => JoinOperator::FullOuter(constraint), + }, + }) +} + /// Translate a PRQL Ident to a Vec of SQL Idents. // We return a vec of SQL Idents because sqlparser sometimes uses // [ObjectName](sql_ast::ObjectName) and sometimes uses @@ -600,7 +651,7 @@ pub(super) fn translate_ident( ctx: &Context, ) -> Vec { let mut parts = Vec::with_capacity(4); - if !ctx.query.omit_ident_prefix || column.is_none() { + if !ctx.omit_ident_prefix || column.is_none() { if let Some(table) = table_name { #[allow(clippy::if_same_then_else)] if ctx.dialect.big_query_quoting() { @@ -903,12 +954,22 @@ mod test { { let query = resolve(parse("from foo")?)?; let (anchor, _) = AnchorContext::of(query); - context_with_concat_function = Context::new(Box::new(GenericDialect {}), anchor); + context_with_concat_function = Context { + dialect: Box::new(GenericDialect {}), + anchor, + omit_ident_prefix: false, + pre_projection: false, + }; } { let query = resolve(parse("from foo")?)?; let (anchor, _) = AnchorContext::of(query); - context_without_concat_function = Context::new(Box::new(SQLiteDialect {}), anchor); + context_without_concat_function = Context { + dialect: Box::new(SQLiteDialect {}), + anchor, + omit_ident_prefix: false, + pre_projection: false, + }; } fn str_lit(s: &str) -> InterpolateItem { diff --git a/prql-compiler/src/sql/gen_query.rs b/prql-compiler/src/sql/gen_query.rs index fba04d0be692..a109eb8b0aa1 100644 --- a/prql-compiler/src/sql/gen_query.rs +++ b/prql-compiler/src/sql/gen_query.rs @@ -6,23 +6,21 @@ use std::collections::HashSet; use std::str::FromStr; use anyhow::{anyhow, Result}; +use enum_as_inner::EnumAsInner; use itertools::Itertools; use sqlparser::ast::{ - self as sql_ast, Ident, Join, JoinConstraint, JoinOperator, Select, SelectItem, SetExpr, - TableAlias, TableFactor, TableWithJoins, + self as sql_ast, Ident, Select, SelectItem, SetExpr, TableAlias, TableFactor, TableWithJoins, }; -use crate::ast::pl::{BinOp, JoinSide, Literal, RelationLiteral}; -use crate::ast::rq::{CId, Expr, ExprKind, Query, RelationKind, TableRef, Transform}; -use crate::sql::anchor::anchor_split; -use crate::sql::preprocess::SqlRelationKind; +use crate::ast::pl::{BinOp, Literal, RelationLiteral}; +use crate::ast::rq::{CId, Expr, ExprKind, Query, Relation, RelationKind, TableDecl, Transform}; use crate::utils::{BreakUp, IntoOnly, Pluck}; use crate::Target; use super::context::AnchorContext; use super::gen_expr::*; use super::gen_projection::*; -use super::preprocess::{self, SqlRelation, SqlTransform}; +use super::preprocess::{self, SqlTransform}; use super::{anchor, Context, Dialect}; pub fn translate_query(query: Query, dialect: Option) -> Result { @@ -38,17 +36,77 @@ pub fn translate_query(query: Query, dialect: Option) -> Result { + // preprocess + let pipeline = Ok(pipeline) + .map(preprocess::normalize) + .map(preprocess::push_down_selects) + .map(preprocess::prune_inputs) + .map(preprocess::wrap) + .and_then(|p| preprocess::distinct(p, &mut context)) + .map(preprocess::union) + .and_then(|p| preprocess::except(p, &context)) + .and_then(|p| preprocess::intersect(p, &context)) + .map(preprocess::reorder)?; + + // load names of output columns + context.anchor.load_names(&pipeline, table.relation.columns); + + // split to atomics + let ats = split_into_atomics(name, pipeline, &mut context.anchor); + + // ensure names for all columns that need it + ensure_names(&ats, &mut context.anchor); + + atomics.extend(ats); + } + RelationKind::Literal(_) | RelationKind::SString(_) => atomics.push(AtomicQuery { + name, + relation: SqlRelation::Super(table.relation.kind), + }), + RelationKind::ExternRef(_) => { + // ref does not need it's own CTE + } + } + } + + // take last table + let main_query = atomics.remove(atomics.len() - 1); + let ctes = atomics; + + // convert each of the CTEs + let ctes: Vec<_> = ctes + .into_iter() + .map(|t| table_to_sql_cte(t, &mut context)) + .try_collect()?; - // compile main relation that will recursively compile CTEs - let mut main_query = sql_query_of_sql_relation(main_relation.into(), &mut ctx)?; + // convert main query + let mut main_query = sql_query_of_relation(main_query.relation, &mut context)?; // attach CTEs - if !ctx.ctes.is_empty() { + if !ctes.is_empty() { main_query.with = Some(sql_ast::With { - cte_tables: ctx.ctes.drain(..).collect_vec(), + cte_tables: ctes, recursive: false, }); } @@ -56,188 +114,99 @@ pub fn translate_query(query: Query, dialect: Option) -> Result Result { - use RelationKind::*; - - // preprocess & split into atomics - match sql_relation.kind { - // base case - SqlRelationKind::Super(Pipeline(pipeline)) => { - // preprocess - let pipeline = Ok(pipeline) - .map(preprocess::normalize) - .map(preprocess::prune_inputs) - .map(preprocess::wrap) - .and_then(|p| preprocess::distinct(p, ctx)) - .map(preprocess::union) - .and_then(|p| preprocess::except(p, ctx)) - .and_then(|p| preprocess::intersect(p, ctx)) - .map(preprocess::reorder)?; - - // load names of output columns - ctx.anchor.load_names(&pipeline, sql_relation.columns); - - sql_query_of_pipeline(pipeline, ctx) - } - - // no need to preprocess, has been done already - SqlRelationKind::PreprocessedPipeline(pipeline) => sql_query_of_pipeline(pipeline, ctx), - - // special case: literals - SqlRelationKind::Super(Literal(lit)) => sql_of_sample_data(lit, ctx), - - // special case: s-strings - SqlRelationKind::Super(SString(items)) => translate_query_sstring(items, ctx), - - // ref cannot be converted directly into query and does not need it's own CTE - SqlRelationKind::Super(ExternRef(_)) => unreachable!(), - } +/// A query that can be expressed with one SELECT statement +#[derive(Debug)] +pub struct AtomicQuery { + name: String, + relation: SqlRelation, } -fn table_factor_of_table_ref(table_ref: TableRef, ctx: &mut Context) -> Result { - let table_ref_alias = (table_ref.name.clone()) - .map(|ident| translate_ident_part(ident, ctx)) - .map(simple_table_alias); - - let decl = ctx.anchor.table_decls.get_mut(&table_ref.source).unwrap(); +#[derive(Debug, EnumAsInner)] +enum SqlRelation { + Super(RelationKind), + Pipeline(Vec), +} - // prepare names - let table_name = match &decl.name { - None => { - decl.name = Some(ctx.anchor.table_name.gen()); - decl.name.clone().unwrap() - } - Some(n) => n.clone(), +fn into_tables( + main_pipeline: Relation, + tables: Vec, + context: &mut Context, +) -> Result> { + let main = TableDecl { + id: context.anchor.tid.gen(), + name: None, + relation: main_pipeline, }; + Ok([tables, vec![main]].concat()) +} - // ensure that the table is declared - if let Some(sql_relation) = decl.relation.take() { - // if we cannot use CTEs - if ctx.query.forbid_ctes { - // restore relation for other references - decl.relation = Some(sql_relation.clone()); - - // return a sub-query - let query = sql_query_of_sql_relation(sql_relation, ctx)?; - return Ok(TableFactor::Derived { - lateral: false, - subquery: Box::new(query), - alias: table_ref_alias, - }); - } - - let query = sql_query_of_sql_relation(sql_relation, ctx)?; - let alias = sql_ast::TableAlias { - name: translate_ident_part(table_name.clone(), ctx), - columns: vec![], - }; - - ctx.ctes.push(sql_ast::Cte { - alias, - query: Box::new(query), - from: None, - }) - } - - // let name = match &decl.relation { - // // special case for anchor - // // TODO - // // Some(SqlRelationKind::Super(RelationKind::ExternRef(TableExternRef::Anchor( - // // anchor_id, - // // )))) => sql_ast::ObjectName(vec![Ident::new(anchor_id.clone())]), - - // // base case - // _ => { - - // } - // }; - - let name = sql_ast::ObjectName(translate_ident(Some(table_name.clone()), None, ctx)); - - Ok(TableFactor::Table { - name, - alias: if Some(table_name) == table_ref.name { - None - } else { - table_ref_alias - }, - args: None, - with_hints: vec![], +fn table_to_sql_cte(table: AtomicQuery, context: &mut Context) -> Result { + let alias = sql_ast::TableAlias { + name: translate_ident_part(table.name, context), + columns: vec![], + }; + Ok(sql_ast::Cte { + alias, + query: Box::new(sql_query_of_relation(table.relation, context)?), + from: None, }) } -fn translate_join( - (side, with, filter): (JoinSide, TableRef, Expr), - ctx: &mut Context, -) -> Result { - let relation = table_factor_of_table_ref(with, ctx)?; - - let constraint = JoinConstraint::On(translate_expr_kind(filter.kind, ctx)?); - - Ok(Join { - relation, - join_operator: match side { - JoinSide::Inner => JoinOperator::Inner(constraint), - JoinSide::Left => JoinOperator::LeftOuter(constraint), - JoinSide::Right => JoinOperator::RightOuter(constraint), - JoinSide::Full => JoinOperator::FullOuter(constraint), - }, - }) +fn sql_query_of_relation(relation: SqlRelation, context: &mut Context) -> Result { + use RelationKind::*; + + match relation { + SqlRelation::Super(ExternRef(_)) | SqlRelation::Super(Pipeline(_)) => unreachable!(), + SqlRelation::Pipeline(pipeline) => sql_query_of_pipeline(pipeline, context), + SqlRelation::Super(Literal(lit)) => Ok(sql_of_sample_data(lit, context)?), + SqlRelation::Super(SString(items)) => translate_query_sstring(items, context), + } } fn sql_query_of_pipeline( - mut pipeline: Vec, - ctx: &mut Context, + pipeline: Vec, + context: &mut Context, ) -> Result { use SqlTransform::*; - // special case: loop - if pipeline.iter().any(|t| matches!(t, Loop(_))) { - pipeline = sql_of_loop(pipeline, ctx)?; - } - - // extract an atomic pipeline from back of the pipeline and stash preceding part into context - let pipeline = extract_atomic(pipeline, &mut ctx.anchor); - - // ensure names for all columns that need it - ensure_names(&pipeline, &mut ctx.anchor); - let (select, set_ops) = pipeline.break_up(|t| matches!(t, Union { .. } | Except { .. } | Intersect { .. })); - let select = sql_select_query_of_pipeline(select, ctx)?; + let select = sql_select_query_of_pipeline(select, context)?; - sql_set_ops_of_pipeline(select, set_ops, ctx) + sql_set_ops_of_pipeline(select, set_ops, context) } fn sql_select_query_of_pipeline( mut pipeline: Vec, - ctx: &mut Context, + context: &mut Context, ) -> Result { let table_count = count_tables(&pipeline); log::debug!("atomic query contains {table_count} tables"); - ctx.push_query(); - ctx.query.omit_ident_prefix = table_count == 1; - ctx.query.pre_projection = true; + context.omit_ident_prefix = table_count == 1; + + context.pre_projection = true; + + let projection = pipeline + .pluck(|t| t.into_super_and(|t| t.into_select())) + .into_only() + .unwrap(); + let projection = translate_wildcards(&context.anchor, projection); + let projection = translate_select_items(projection.0, projection.1, context)?; - let mut from: Vec<_> = pipeline + let mut from = pipeline .pluck(|t| t.into_super_and(|t| t.into_from())) .into_iter() - .map(|source| -> Result { - Ok(TableWithJoins { - relation: table_factor_of_table_ref(source, ctx)?, - joins: vec![], - }) + .map(|source| TableWithJoins { + relation: table_factor_of_tid(source, context), + joins: vec![], }) - .try_collect()?; + .collect::>(); let joins = pipeline .pluck(|t| t.into_super_and(|t| t.into_join())) .into_iter() - .map(|j| translate_join(j, ctx)) + .map(|j| translate_join(j, context)) .collect::>>()?; if !joins.is_empty() { if let Some(from) = from.last_mut() { @@ -247,13 +216,6 @@ fn sql_select_query_of_pipeline( } } - let projection = pipeline - .pluck(|t| t.into_super_and(|t| t.into_select())) - .into_only() - .unwrap(); - let projection = translate_wildcards(&ctx.anchor, projection); - let projection = translate_select_items(projection.0, projection.1, ctx)?; - let sorts = pipeline.pluck(|t| t.into_super_and(|t| t.into_sort())); let takes = pipeline.pluck(|t| t.into_super_and(|t| t.into_take())); let distinct = pipeline.iter().any(|t| matches!(t, SqlTransform::Distinct)); @@ -269,11 +231,11 @@ fn sql_select_query_of_pipeline( // WHERE and HAVING let where_ = filter_of_conditions( before_agg.pluck(|t| t.into_super_and(|t| t.into_filter())), - ctx, + context, )?; let having = filter_of_conditions( after_agg.pluck(|t| t.into_super_and(|t| t.into_filter())), - ctx, + context, )?; // GROUP BY @@ -282,9 +244,9 @@ fn sql_select_query_of_pipeline( .into_iter() .next(); let group_by: Vec = aggregate.map(|(part, _)| part).unwrap_or_default(); - let group_by = try_into_exprs(group_by, ctx, None)?; + let group_by = try_into_exprs(group_by, context, None)?; - ctx.query.pre_projection = false; + context.pre_projection = false; let ranges = takes.into_iter().map(|x| x.range).collect(); let take = range_of_ranges(ranges)?; @@ -295,7 +257,7 @@ fn sql_select_query_of_pipeline( None } else { Some(sqlparser::ast::Offset { - value: translate_expr_kind(ExprKind::Literal(Literal::Integer(offset)), ctx)?, + value: translate_expr_kind(ExprKind::Literal(Literal::Integer(offset)), context)?, rows: sqlparser::ast::OffsetRows::None, }) }; @@ -306,20 +268,17 @@ fn sql_select_query_of_pipeline( .map(|sorts| { sorts .iter() - .map(|s| translate_column_sort(s, ctx)) + .map(|s| translate_column_sort(s, context)) .try_collect() }) .transpose()? .unwrap_or_default(); - let (top, limit) = if ctx.dialect.use_top() { - (limit.map(|l| top_of_i64(l, ctx)), None) + let (top, limit) = if context.dialect.use_top() { + (limit.map(|l| top_of_i64(l, context)), None) } else { (None, limit.map(expr_of_i64)) }; - - ctx.pop_query(); - Ok(sql_ast::Query { order_by, limit, @@ -363,7 +322,36 @@ fn sql_set_ops_of_pipeline( }; // prepare top - let left = query_to_set_expr(top, context); + let top_is_simple = top.with.is_none() + && top.order_by.is_empty() + && top.limit.is_none() + && top.offset.is_none() + && top.fetch.is_none() + && top.locks.is_empty(); + + let left = if top_is_simple { + top.body + } else { + // top is not simple, so we need to wrap it into + // `SELECT * FROM top` + Box::new(SetExpr::Select(Box::new(Select { + projection: vec![SelectItem::Wildcard( + sql_ast::WildcardAdditionalOptions::default(), + )], + from: vec![TableWithJoins { + relation: TableFactor::Derived { + lateral: false, + subquery: Box::new(top), + alias: Some(TableAlias { + name: Ident::new(context.anchor.table_name.gen()), + columns: Vec::new(), + }), + }, + joins: vec![], + }], + ..default_select() + }))) + }; top = default_query(SetExpr::SetOperation { left, @@ -372,7 +360,7 @@ fn sql_set_ops_of_pipeline( sql_ast::WildcardAdditionalOptions::default(), )], from: vec![TableWithJoins { - relation: table_factor_of_table_ref(bottom, context)?, + relation: table_factor_of_tid(bottom, context), joins: vec![], }], ..default_select() @@ -393,99 +381,6 @@ fn sql_set_ops_of_pipeline( Ok(top) } -fn sql_of_loop(pipeline: Vec, ctx: &mut Context) -> Result> { - // split the pipeline - let (mut initial, mut following) = pipeline.break_up(|t| matches!(t, SqlTransform::Loop(_))); - let loop_ = following.remove(0); - let step = loop_.into_loop().unwrap(); - - // RECURSIVE can only follow WITH directly, which means that if we want to use it for - // an arbitrary query, we have to defined a *nested* WITH RECURSIVE and not use - // the top-level list of CTEs. - - // determine columns of the initial table - let recursive_columns = AnchorContext::determine_select_columns(&initial); - - // do the same thing we do when splitting a pipeline - // (defining new columns, redirecting cids) - let recursive_columns = SqlTransform::Super(Transform::Select(recursive_columns)); - initial.push(recursive_columns.clone()); - let step = anchor_split(&mut ctx.anchor, initial, step); - let from = step.first().unwrap().as_super().unwrap().as_from().unwrap(); - - let initial = ctx.anchor.table_decls.get_mut(&from.source).unwrap(); - initial.name = Some("loop".to_string()); - let initial_relation = initial.relation.take().unwrap(); - - let initial = initial_relation.kind.into_preprocessed_pipeline().unwrap(); - - // compile initial - let initial = query_to_set_expr(sql_query_of_pipeline(initial, ctx)?, ctx); - - // compile step (without producing CTEs) - ctx.push_query(); - ctx.query.forbid_ctes = true; - - let step = query_to_set_expr(sql_query_of_pipeline(step, ctx)?, ctx); - - ctx.pop_query(); - - // build CTE and it's SELECT - let cte = sql_ast::Cte { - alias: simple_table_alias(Ident::new("loop")), - query: Box::new(default_query(SetExpr::SetOperation { - op: sql_ast::SetOperator::Union, - set_quantifier: sql_ast::SetQuantifier::All, - left: initial, - right: step, - })), - from: None, - }; - let query = Box::new(sql_ast::Query { - with: Some(sql_ast::With { - recursive: true, - cte_tables: vec![cte], - }), - ..default_query(sql_ast::SetExpr::Select(Box::new(sql_ast::Select { - projection: vec![SelectItem::Wildcard( - sql_ast::WildcardAdditionalOptions::default(), - )], - from: vec![TableWithJoins { - relation: TableFactor::Table { - name: sql_ast::ObjectName(vec![Ident::new("loop")]), - alias: None, - args: None, - with_hints: Vec::new(), - }, - joins: vec![], - }], - ..default_select() - }))) - }); - - // create a split between the loop SELECT statement and the following pipeline - let mut following = anchor_split(&mut ctx.anchor, vec![recursive_columns], following); - - let from = following.first_mut().unwrap(); - let from = from.as_super().unwrap().as_from().unwrap(); - - // this will be table decl that references the whole loop expression - let loop_decl = ctx.anchor.table_decls.get_mut(&from.source).unwrap(); - - let loop_name = ctx.anchor.table_name.gen(); - loop_decl.name = Some(loop_name.clone()); - loop_decl.relation = None; - - // push the whole thing into WITH of the main query - ctx.ctes.push(sql_ast::Cte { - alias: simple_table_alias(Ident::new(loop_name)), - query, - from: None, - }); - - Ok(following) -} - fn sql_of_sample_data(data: RelationLiteral, ctx: &Context) -> Result { // TODO: this could be made to use VALUES instead of SELECT UNION ALL SELECT // I'm not sure about compatibility though. @@ -521,65 +416,121 @@ fn sql_of_sample_data(data: RelationLiteral, ctx: &Context) -> Result, ctx: &mut AnchorContext) -> Vec { - let (preceding, atomic) = anchor::split_off_back(pipeline, ctx); - - if let Some(preceding) = preceding { - log::debug!( - "pipeline split after {}", - preceding.last().unwrap().as_str() - ); - - anchor::anchor_split(ctx, preceding, atomic) - } else { - atomic +fn split_into_atomics( + name: String, + mut pipeline: Vec, + ctx: &mut AnchorContext, +) -> Vec { + let outputs_cid = AnchorContext::determine_select_columns(&pipeline); + + let mut required_cols = outputs_cid.clone(); + + // split pipeline, back to front + let mut parts_rev = Vec::new(); + loop { + let (preceding, split) = anchor::split_off_back(ctx, required_cols, pipeline); + + if let Some((preceding, cols_at_split)) = preceding { + log::debug!( + "pipeline split after {}", + preceding.last().unwrap().as_str() + ); + parts_rev.push((split, cols_at_split.clone())); + + pipeline = preceding; + required_cols = cols_at_split; + } else { + parts_rev.push((split, Vec::new())); + break; + } } + parts_rev.reverse(); + let mut parts = parts_rev; - // TODO // sometimes, additional columns will be added into select, which have to // be filtered out here, using additional CTE - // if let Some((pipeline, _)) = parts.last() { - // let select_cols = pipeline - // .first() - // .unwrap() - // .as_super() - // .unwrap() - // .as_select() - // .unwrap(); - - // if select_cols.iter().any(|c| !outputs_cid.contains(c)) { - // parts.push(( - // vec![SqlTransform::Super(Transform::Select(outputs_cid))], - // select_cols.clone(), - // )); - // } - // } + if let Some((pipeline, _)) = parts.last() { + let select_cols = pipeline + .first() + .unwrap() + .as_super() + .unwrap() + .as_select() + .unwrap(); + + if select_cols.iter().any(|c| !outputs_cid.contains(c)) { + parts.push(( + vec![SqlTransform::Super(Transform::Select(outputs_cid))], + select_cols.clone(), + )); + } + } + + // add names to pipelines, anchor, front to back + let mut atomics = Vec::with_capacity(parts.len()); + let last = parts.pop().unwrap(); + + let last_pipeline = if parts.is_empty() { + last.0 + } else { + // this code chunk is bloated but I cannot find a more concise alternative + let first = parts.remove(0); + + let first_name = ctx.table_name.gen(); + atomics.push(AtomicQuery { + name: first_name.clone(), + relation: SqlRelation::Pipeline(first.0), + }); + + let mut prev_name = first_name; + for (pipeline, cols_before) in parts.into_iter() { + let name = ctx.table_name.gen(); + let pipeline = anchor::anchor_split(ctx, &prev_name, &cols_before, pipeline); + + atomics.push(AtomicQuery { + name: name.clone(), + relation: SqlRelation::Pipeline(pipeline), + }); + + prev_name = name; + } + + anchor::anchor_split(ctx, &prev_name, &last.1, last.0) + }; + atomics.push(AtomicQuery { + name, + relation: SqlRelation::Pipeline(last_pipeline), + }); + + atomics } -fn ensure_names(transforms: &[SqlTransform], ctx: &mut AnchorContext) { - let empty = HashSet::new(); - for t in transforms { - match t { - SqlTransform::Super(Transform::Sort(_)) => { - for r in anchor::get_requirements(t, &empty) { - ctx.ensure_column_name(r.col); +fn ensure_names(atomics: &[AtomicQuery], ctx: &mut AnchorContext) { + // ensure column names for columns that need it + for a in atomics { + let empty = HashSet::new(); + for t in a.relation.as_pipeline().unwrap() { + match t { + SqlTransform::Super(Transform::Sort(_)) => { + for r in anchor::get_requirements(t, &empty) { + ctx.ensure_column_name(r.col); + } } - } - SqlTransform::Super(Transform::Select(cids)) => { - for cid in cids { - let _decl = &ctx.column_decls[cid]; - //let name = match decl { - // ColumnDecl::RelationColumn(_, _, _) => todo!(), - // ColumnDecl::Compute(_) => ctx.column_names[..], - //}; + SqlTransform::Super(Transform::Select(cids)) => { + for cid in cids { + let _decl = &ctx.column_decls[cid]; + //let name = match decl { + // ColumnDecl::RelationColumn(_, _, _) => todo!(), + // ColumnDecl::Compute(_) => ctx.column_names[..], + //}; + } } + _ => (), } - _ => (), } } } + fn filter_of_conditions(exprs: Vec, context: &mut Context) -> Result> { Ok(if let Some(cond) = all(exprs) { Some(translate_expr_kind(cond.kind, context)?) @@ -633,45 +584,6 @@ fn default_select() -> Select { } } -fn simple_table_alias(name: Ident) -> TableAlias { - TableAlias { - name, - columns: Vec::new(), - } -} - -fn query_to_set_expr(query: sql_ast::Query, context: &mut Context) -> Box { - let is_simple = query.with.is_none() - && query.order_by.is_empty() - && query.limit.is_none() - && query.offset.is_none() - && query.fetch.is_none() - && query.locks.is_empty(); - - if is_simple { - return query.body; - } - - // query is not simple, so we need to wrap it into - // `SELECT * FROM (query)` - Box::new(SetExpr::Select(Box::new(Select { - projection: vec![SelectItem::Wildcard( - sql_ast::WildcardAdditionalOptions::default(), - )], - from: vec![TableWithJoins { - relation: TableFactor::Derived { - lateral: false, - subquery: Box::new(query), - alias: Some(simple_table_alias(Ident::new( - context.anchor.table_name.gen(), - ))), - }, - joins: vec![], - }], - ..default_select() - }))) -} - fn count_tables(transforms: &[SqlTransform]) -> usize { let mut count = 0; for transform in transforms { @@ -691,36 +603,19 @@ mod test { fn parse_and_resolve(prql: &str) -> Result<(Vec, Context)> { let query = resolve(parse(prql)?)?; - let (anchor, main_relation) = AnchorContext::of(query); - let context = Context::new(Box::new(GenericDialect {}), anchor); + let (anchor, query) = AnchorContext::of(query); + let context = Context { + dialect: Box::new(GenericDialect {}), + anchor, + omit_ident_prefix: false, + pre_projection: false, + }; - let pipeline = main_relation.kind.into_pipeline().unwrap(); + let pipeline = query.relation.kind.into_pipeline().unwrap(); Ok((preprocess::reorder(preprocess::wrap(pipeline)), context)) } - fn count_atomics(prql: &str) -> usize { - let (mut pipeline, mut context) = parse_and_resolve(prql).unwrap(); - context.anchor.table_decls.clear(); - - let mut atomics = 0; - loop { - let _ = extract_atomic(pipeline, &mut context.anchor); - atomics += 1; - - if let Some((_, decl)) = context.anchor.table_decls.drain().next() { - if let Some(relation) = decl.relation { - if let SqlRelationKind::PreprocessedPipeline(p) = relation.kind { - pipeline = p; - continue; - } - } - } - break; - } - atomics - } - #[test] fn test_ctes_of_pipeline() { // One aggregate, take at the end @@ -732,7 +627,9 @@ mod test { take 20 "###; - assert_eq!(count_atomics(prql), 1); + let (pipeline, mut context) = parse_and_resolve(prql).unwrap(); + let queries = split_into_atomics("".to_string(), pipeline, &mut context.anchor); + assert_eq!(queries.len(), 1); // One aggregate, but take at the top let prql: &str = r###" @@ -743,7 +640,9 @@ mod test { sort sal "###; - assert_eq!(count_atomics(prql), 2); + let (pipeline, mut context) = parse_and_resolve(prql).unwrap(); + let queries = split_into_atomics("".to_string(), pipeline, &mut context.anchor); + assert_eq!(queries.len(), 2); // A take, then two aggregates let prql: &str = r###" @@ -755,7 +654,9 @@ mod test { sort sal2 "###; - assert_eq!(count_atomics(prql), 3); + let (pipeline, mut context) = parse_and_resolve(prql).unwrap(); + let queries = split_into_atomics("".to_string(), pipeline, &mut context.anchor); + assert_eq!(queries.len(), 3); // A take, then a select let prql: &str = r###" @@ -764,7 +665,9 @@ mod test { select first_name "###; - assert_eq!(count_atomics(prql), 1); + let (pipeline, mut context) = parse_and_resolve(prql).unwrap(); + let queries = split_into_atomics("".to_string(), pipeline, &mut context.anchor); + assert_eq!(queries.len(), 1); } #[test] @@ -816,7 +719,7 @@ mod test { *, RANK() OVER () AS rank FROM - table_1 AS table_0 + table_1 WHERE country = 'USA' "###); @@ -841,7 +744,7 @@ mod test { SELECT * FROM - table_1 AS table_0 + table_1 WHERE _expr_0 > 3 "###); diff --git a/prql-compiler/src/sql/mod.rs b/prql-compiler/src/sql/mod.rs index c49140711390..c109bc0deab0 100644 --- a/prql-compiler/src/sql/mod.rs +++ b/prql-compiler/src/sql/mod.rs @@ -60,18 +60,6 @@ struct Context { pub dialect: Box, pub anchor: AnchorContext, - // stuff regarding current query - query: QueryOpts, - - // stuff regarding parent queries - query_stack: Vec, - - pub ctes: Vec, -} - -#[derive(Default, Clone)] -struct QueryOpts { - /// When true, column references will not include table names prefixes. pub omit_ident_prefix: bool, /// True iff codegen should generate expressions before SELECT's projection is applied. @@ -79,29 +67,6 @@ struct QueryOpts { /// - WHERE needs `pre_projection=true`, but /// - ORDER BY needs `pre_projection=false`. pub pre_projection: bool, - - /// When true, queries will contain nested sub-queries instead of WITH CTEs. - pub forbid_ctes: bool, -} - -impl Context { - fn new(dialect: Box, anchor: AnchorContext) -> Self { - Context { - dialect, - anchor, - query: QueryOpts::default(), - query_stack: Vec::new(), - ctes: Vec::new(), - } - } - - fn push_query(&mut self) { - self.query_stack.push(self.query.clone()); - } - - fn pop_query(&mut self) { - self.query = self.query_stack.pop().unwrap(); - } } #[cfg(test)] diff --git a/prql-compiler/src/sql/preprocess.rs b/prql-compiler/src/sql/preprocess.rs index 035f6858dd30..7c04c4cbf7cb 100644 --- a/prql-compiler/src/sql/preprocess.rs +++ b/prql-compiler/src/sql/preprocess.rs @@ -10,8 +10,7 @@ use crate::ast::pl::{ BinOp, ColumnSort, InterpolateItem, JoinSide, Literal, Range, WindowFrame, WindowKind, }; use crate::ast::rq::{ - self, new_binop, CId, Compute, Expr, ExprKind, Relation, RelationColumn, RelationKind, RqFold, - TableRef, Transform, Window, + self, new_binop, CId, Compute, Expr, ExprKind, RqFold, TableRef, Transform, Window, }; use crate::error::Error; use crate::sql::context::AnchorContext; @@ -19,45 +18,31 @@ use crate::sql::context::AnchorContext; use super::anchor::{infer_complexity, CidCollector, Complexity}; use super::Context; -#[derive(Debug, Clone, EnumAsInner)] -pub(super) enum SqlRelationKind { - Super(RelationKind), - PreprocessedPipeline(Vec), -} - -#[derive(Debug, Clone)] -pub(super) struct SqlRelation { - pub kind: SqlRelationKind, - pub columns: Vec, -} - -#[derive(Debug, Clone, EnumAsInner, strum::AsRefStr)] +#[derive(Debug, EnumAsInner, strum::AsRefStr)] pub(super) enum SqlTransform { Super(Transform), Distinct, Except { bottom: TableRef, distinct: bool }, Intersect { bottom: TableRef, distinct: bool }, Union { bottom: TableRef, distinct: bool }, - Loop(Vec), } -// This function was disabled because it changes semantics of the pipeline in some cases. -// /// Pushes all [Transform::Select]s to the back of the pipeline. -// pub(super) fn push_down_selects(pipeline: Vec) -> Vec { -// let mut select = None; -// let mut res = Vec::with_capacity(pipeline.len()); -// for t in pipeline { -// if let Transform::Select(_) = t { -// select = Some(t); -// } else { -// res.push(t); -// } -// } -// if let Some(select) = select { -// res.push(select); -// } -// res -// } +/// Pushes all [Transform::Select]s to the back of the pipeline. +pub(super) fn push_down_selects(pipeline: Vec) -> Vec { + let mut select = None; + let mut res = Vec::with_capacity(pipeline.len()); + for t in pipeline { + if let Transform::Select(_) = t { + select = Some(t); + } else { + res.push(t); + } + } + if let Some(select) = select { + res.push(select); + } + res +} /// Removes unused relation inputs pub(super) fn prune_inputs(mut pipeline: Vec) -> Vec { @@ -91,12 +76,7 @@ pub(super) fn prune_inputs(mut pipeline: Vec) -> Vec { } pub(super) fn wrap(pipe: Vec) -> Vec { - pipe.into_iter() - .map(|t| match t { - Transform::Loop(pipeline) => SqlTransform::Loop(wrap(pipeline)), - _ => SqlTransform::Super(t), - }) - .collect() + pipe.into_iter().map(SqlTransform::Super).collect() } /// Creates [SqlTransform::Distinct] from [Transform::Take] @@ -577,15 +557,6 @@ impl SqlTransform { } } -impl From for SqlRelation { - fn from(rel: Relation) -> Self { - SqlRelation { - kind: SqlRelationKind::Super(rel.kind), - columns: rel.columns, - } - } -} - pub(super) trait SqlFold: RqFold { fn fold_sql_transforms(&mut self, transforms: Vec) -> Result> { transforms @@ -610,7 +581,6 @@ pub(super) trait SqlFold: RqFold { bottom: self.fold_table_ref(bottom)?, distinct, }, - SqlTransform::Loop(pipeline) => SqlTransform::Loop(self.fold_sql_transforms(pipeline)?), }) } } diff --git a/prql-compiler/src/sql/snapshots/prql_compiler__sql__gen_query__test__variable_after_aggregate.snap b/prql-compiler/src/sql/snapshots/prql_compiler__sql__gen_query__test__variable_after_aggregate.snap index 1164db5605aa..5b7e140a157a 100644 --- a/prql-compiler/src/sql/snapshots/prql_compiler__sql__gen_query__test__variable_after_aggregate.snap +++ b/prql-compiler/src/sql/snapshots/prql_compiler__sql__gen_query__test__variable_after_aggregate.snap @@ -16,7 +16,6 @@ SELECT title, AVG(_expr_0) AS avg_salary FROM - table_1 AS table_0 + table_1 GROUP BY title - diff --git a/prql-compiler/src/test.rs b/prql-compiler/src/test.rs index 16c1d560cf5a..e695ed15b6fd 100644 --- a/prql-compiler/src/test.rs +++ b/prql-compiler/src/test.rs @@ -205,7 +205,7 @@ fn test_append() { take 10 ) "###).unwrap(), @r###" - WITH table_0 AS ( + WITH table_1 AS ( SELECT *, name, @@ -227,13 +227,13 @@ fn test_append() { employees LIMIT 3 - ) AS table_2 + ) AS table_3 UNION ALL SELECT * FROM - table_0 AS table_1 + table_1 AS table_0 "###); assert_display_snapshot!(compile(r###" @@ -310,7 +310,7 @@ fn test_remove() { ) "#).unwrap(), @r###" - WITH table_0 AS ( + WITH table_1 AS ( SELECT artist_id FROM @@ -325,7 +325,7 @@ fn test_remove() { SELECT * FROM - table_0 AS table_1 + table_1 AS table_0 "### ); @@ -337,7 +337,7 @@ fn test_remove() { ) "#).unwrap(), @r###" - WITH table_0 AS ( + WITH table_1 AS ( SELECT artist_id FROM @@ -348,9 +348,9 @@ fn test_remove() { album.title FROM album - LEFT JOIN table_0 AS table_1 ON album.artist_id = table_1.artist_id + LEFT JOIN table_1 AS table_0 ON album.artist_id = table_0.artist_id WHERE - table_1.artist_id IS NULL + table_0.artist_id IS NULL "### ); @@ -382,11 +382,11 @@ fn test_remove() { album ) SELECT - table_0.artist_id, - table_0.title + table_1.artist_id, + table_1.title FROM - table_1 AS table_0 - LEFT JOIN bottom AS b ON table_0.artist_id = b.* + table_1 + LEFT JOIN bottom AS b ON table_1.artist_id = b.* WHERE b.* IS NULL "### @@ -443,7 +443,7 @@ fn test_intersect() { ) "#).unwrap(), @r###" - WITH table_0 AS ( + WITH table_1 AS ( SELECT artist_id FROM @@ -458,7 +458,7 @@ fn test_intersect() { SELECT * FROM - table_0 AS table_1 + table_1 AS table_0 "### ); @@ -474,28 +474,22 @@ fn test_intersect() { distinct "#).unwrap(), @r###" - WITH table_0 AS ( + WITH table_1 AS ( SELECT artist_id FROM artist - ), - table_3 AS ( - SELECT - artist_id - FROM - album - INTERSECT - DISTINCT - SELECT - * - FROM - table_0 AS table_1 ) SELECT - DISTINCT artist_id + artist_id FROM - table_3 AS table_2 + album + INTERSECT + DISTINCT + SELECT + * + FROM + table_1 AS table_0 "### ); @@ -510,28 +504,22 @@ fn test_intersect() { distinct "#).unwrap(), @r###" - WITH table_0 AS ( + WITH table_1 AS ( SELECT artist_id FROM artist - ), - table_3 AS ( - SELECT - artist_id - FROM - album - INTERSECT - ALL - SELECT - * - FROM - table_0 AS table_1 ) SELECT - DISTINCT artist_id + artist_id + FROM + album + INTERSECT + DISTINCT + SELECT + * FROM - table_3 AS table_2 + table_1 AS table_0 "### ); @@ -546,7 +534,7 @@ fn test_intersect() { ) "#).unwrap(), @r###" - WITH table_0 AS ( + WITH table_1 AS ( SELECT artist_id FROM @@ -561,7 +549,7 @@ fn test_intersect() { SELECT * FROM - table_0 AS table_1 + table_1 AS table_0 "### ); @@ -586,28 +574,28 @@ fn test_rn_ids_are_unique() { take 3 ) "###).unwrap()), @r###" - WITH table_3 AS ( + WITH table_1 AS ( SELECT *, - ROW_NUMBER() OVER (PARTITION BY y_id) AS _expr_1 + ROW_NUMBER() OVER (PARTITION BY y_id) AS _expr_0 FROM y_orig ), - table_1 AS ( + table_2 AS ( SELECT *, - ROW_NUMBER() OVER (PARTITION BY x_id) AS _expr_0 + ROW_NUMBER() OVER (PARTITION BY x_id) AS _expr_1 FROM - table_3 AS table_2 + table_1 WHERE - _expr_1 <= 2 + _expr_0 <= 2 ) SELECT * FROM - table_1 AS table_0 + table_2 WHERE - _expr_0 <= 3 + _expr_1 <= 3 "###); } @@ -702,13 +690,19 @@ fn test_sorts() { select [renamed = somefield] "### ).unwrap()), @r###" + WITH table_1 AS ( + SELECT + 'something' AS renamed, + 'something' AS _expr_0 + FROM + x + ORDER BY + _expr_0 + ) SELECT - 'something' AS renamed, - 'something' AS _expr_0 + renamed FROM - x - ORDER BY - _expr_0 + table_1 "###); } @@ -883,7 +877,7 @@ fn test_window_functions_02() { order_day ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ) AS num_books_last_week FROM - table_1 AS table_0 + table_1 ORDER BY order_day "###); @@ -1267,7 +1261,7 @@ fn test_take() { SELECT * FROM - table_1 AS table_0 + table_1 ORDER BY name LIMIT @@ -1346,7 +1340,7 @@ fn test_distinct() { SELECT * FROM - table_1 AS table_0 + table_1 WHERE rn > 2 "###); @@ -1403,7 +1397,7 @@ fn test_distinct() { SELECT * FROM - table_1 AS table_0 + table_1 WHERE _expr_0 <= 3 "###); @@ -1426,7 +1420,7 @@ fn test_distinct() { SELECT * FROM - table_1 AS table_0 + table_1 WHERE _expr_0 BETWEEN 2 AND 3 "###); @@ -1449,7 +1443,7 @@ fn test_distinct() { SELECT * FROM - table_1 AS table_0 + table_1 WHERE _expr_0 = 4 "###); @@ -1825,7 +1819,16 @@ fn test_prql_to_sql_table() { let sql = compile(query).unwrap(); assert_display_snapshot!(sql, @r###" - WITH newest_employees AS ( + WITH average_salaries AS ( + SELECT + country, + AVG(salary) AS average_country_salary + FROM + salaries + GROUP BY + country + ), + newest_employees AS ( SELECT * FROM @@ -1834,14 +1837,6 @@ fn test_prql_to_sql_table() { tenure LIMIT 50 - ), average_salaries AS ( - SELECT - country, - AVG(salary) AS average_country_salary - FROM - salaries - GROUP BY - country ) SELECT newest_employees.name, @@ -1875,7 +1870,7 @@ fn test_nonatomic() { "###; assert_display_snapshot!((compile(query).unwrap()), @r###" - WITH table_3 AS ( + WITH table_1 AS ( SELECT title, country, @@ -1884,13 +1879,13 @@ fn test_nonatomic() { employees LIMIT 20 - ), table_1 AS ( + ), table_2 AS ( SELECT title, country, AVG(salary) AS _expr_0 FROM - table_3 AS table_2 + table_1 WHERE country = 'USA' GROUP BY @@ -1902,7 +1897,7 @@ fn test_nonatomic() { country, AVG(_expr_0) AS sum_gross_cost FROM - table_1 AS table_0 + table_2 GROUP BY title, country @@ -1955,7 +1950,7 @@ fn test_nonatomic_table() { "###; assert_display_snapshot!((compile(query).unwrap()), @r###" - WITH table_1 AS ( + WITH table_0 AS ( SELECT country FROM @@ -1967,7 +1962,7 @@ fn test_nonatomic_table() { country, count(*) FROM - table_1 AS table_0 + table_0 GROUP BY country ) @@ -2004,12 +1999,12 @@ fn test_table_names_between_splits() { 10 ) SELECT - table_0.emp_no, - table_0.name, + table_1.emp_no, + table_1.name, s.salary FROM - table_1 AS table_0 - JOIN salaries AS s ON table_0.emp_no = s.emp_no + table_1 + JOIN salaries AS s ON table_1.emp_no = s.emp_no "###); let prql = r###" @@ -2029,11 +2024,11 @@ fn test_table_names_between_splits() { 10 ) SELECT - table_0.*, + table_1.*, salaries.salary FROM - table_1 AS table_0 - JOIN salaries ON table_0.emp_no = salaries.emp_no + table_1 + JOIN salaries ON table_1.emp_no = salaries.emp_no "###); } @@ -2313,6 +2308,12 @@ fn test_toposort() { * FROM somesource + ), + a AS ( + SELECT + * + FROM + b ) SELECT * @@ -2332,7 +2333,7 @@ fn test_inline_tables() { join s = (from salaries | select [emp_id, salary]) [==emp_id] "###).unwrap(), @r###" - WITH table_0 AS ( + WITH table_1 AS ( SELECT emp_id, salary @@ -2345,11 +2346,11 @@ fn test_inline_tables() { employees.surname, employees.type, employees.amount, - table_1.emp_id, - table_1.salary + table_0.emp_id, + table_0.salary FROM employees - JOIN table_0 AS table_1 ON employees.emp_id = table_1.emp_id + JOIN table_1 AS table_0 ON employees.emp_id = table_0.emp_id "### ); } @@ -2434,7 +2435,7 @@ fn test_table_s_string() { s"SELECT DISTINCT ON first_name, age FROM employees ORDER BY age ASC" "###).unwrap(), @r###" - WITH table_0 AS ( + WITH table_1 AS ( SELECT DISTINCT ON first_name, age @@ -2445,7 +2446,7 @@ fn test_table_s_string() { ) SELECT FROM - table_0 AS table_1 + table_1 AS table_0 "### ); @@ -2456,7 +2457,7 @@ fn test_table_s_string() { join s = s"SELECT * FROM salaries" [==id] "###).unwrap(), @r###" - WITH table_0 AS ( + WITH table_2 AS ( SELECT DISTINCT ON first_name, id, @@ -2466,18 +2467,18 @@ fn test_table_s_string() { ORDER BY age ASC ), - table_1 AS ( + table_3 AS ( SELECT * FROM salaries ) SELECT - table_2.*, - table_3.* + table_0.*, + table_1.* FROM - table_0 AS table_2 - JOIN table_1 AS table_3 ON table_2.id = table_3.id + table_2 AS table_0 + JOIN table_3 AS table_1 ON table_0.id = table_1.id "### ); @@ -2486,7 +2487,7 @@ fn test_table_s_string() { filter country == "USA" "###).unwrap(), @r###" - WITH table_0 AS ( + WITH table_1 AS ( SELECT * FROM @@ -2495,7 +2496,7 @@ fn test_table_s_string() { SELECT * FROM - table_0 AS table_1 + table_1 AS table_0 WHERE country = 'USA' "### @@ -2506,7 +2507,7 @@ fn test_table_s_string() { filter e.country == "USA" "###).unwrap(), @r###" - WITH table_0 AS ( + WITH table_1 AS ( SELECT * FROM @@ -2515,7 +2516,7 @@ fn test_table_s_string() { SELECT * FROM - table_0 AS table_1 + table_1 AS table_0 WHERE country = 'USA' "### @@ -2528,7 +2529,7 @@ fn test_table_s_string() { weeks_between @2022-06-03 (current_week + 4) "###).unwrap(), @r###" - WITH table_0 AS ( + WITH table_1 AS ( SELECT generate_series( DATE '2022-06-03', @@ -2538,7 +2539,7 @@ fn test_table_s_string() { ) SELECT FROM - table_0 AS table_1 + table_1 AS table_0 "### ); @@ -2546,7 +2547,7 @@ fn test_table_s_string() { s"SELECT * FROM {default_db.x}" "###).unwrap(), @r###" - WITH table_0 AS ( + WITH table_1 AS ( SELECT * FROM @@ -2554,7 +2555,7 @@ fn test_table_s_string() { ) SELECT FROM - table_0 AS table_1 + table_1 AS table_0 "### ); } @@ -2654,13 +2655,13 @@ fn test_group_all() { 10 ) SELECT - table_0.*, + table_1.*, SUM(salaries.salary) AS sal FROM - table_1 AS table_0 - JOIN salaries ON table_0.emp_no = salaries.emp_no + table_1 + JOIN salaries ON table_1.emp_no = salaries.emp_no GROUP BY - table_0.* + table_1.* "### ); @@ -2691,7 +2692,7 @@ fn test_output_column_deduplication() { SELECT * FROM - table_1 AS table_0 + table_1 WHERE r = 1 "### @@ -2765,7 +2766,7 @@ fn test_switch() { category, COUNT(*) FROM - table_1 AS table_0 + table_1 GROUP BY category "### @@ -3121,7 +3122,7 @@ a,b,c select [b, c] "#).unwrap(), @r###" - WITH table_0 AS ( + WITH table_1 AS ( SELECT '1' AS a, '2' AS b, @@ -3137,7 +3138,7 @@ a,b,c b, c FROM - table_0 AS table_1 + table_1 AS table_0 "### ); @@ -3148,7 +3149,7 @@ a,b,c select [b, c] "#).unwrap(), @r###" - WITH table_0 AS ( + WITH table_1 AS ( SELECT 1 AS a, 'x' AS b, @@ -3164,7 +3165,7 @@ a,b,c b, c FROM - table_0 AS table_1 + table_1 AS table_0 "### ); @@ -3179,7 +3180,7 @@ a,b,c select [b, c] "#).unwrap(), @r###" - WITH table_0 AS ( + WITH table_1 AS ( SELECT 1 AS a, 'x' AS b, @@ -3195,7 +3196,7 @@ a,b,c b, c FROM - table_0 AS table_1 + table_1 AS table_0 "### ); } @@ -3212,55 +3213,3 @@ fn test_header_target_error() { from a "#).unwrap_err(),@r###"target `"sql.foo"` not found"###) } - -#[test] -fn test_loop() { - assert_display_snapshot!(compile(r#" - from_text format:json '[{"n": 1 }]' - select n = n - 2 - loop ( - select n = n+1 - filter n<5 - ) - select n = n * 2 - take 4 - "#).unwrap(), - @r###" - WITH table_0 AS ( - SELECT - 1 AS n - ), - table_6 AS ( - WITH RECURSIVE loop AS ( - SELECT - n - 2 AS _expr_0 - FROM - table_0 AS table_1 - UNION - ALL - SELECT - _expr_1 - FROM - ( - SELECT - _expr_0 + 1 AS _expr_1 - FROM - loop AS table_2 - ) AS table_3 - WHERE - _expr_1 < 5 - ) - SELECT - * - FROM - loop - ) - SELECT - _expr_0 * 2 AS n - FROM - table_6 AS table_5 - LIMIT - 4 - "### - ); -} diff --git a/prql-compiler/tests/integration/queries/loop.prql b/prql-compiler/tests/integration/queries/loop.prql deleted file mode 100644 index e83d02e37057..000000000000 --- a/prql-compiler/tests/integration/queries/loop.prql +++ /dev/null @@ -1,7 +0,0 @@ -from_text format:json '[{"n": 1 }]' -select n = n - 2 -loop ( - filter n<4 - select n = n+1 -) -select n = n * 2 diff --git a/prql-compiler/tests/integration/snapshots/integration__tests__test@loop.prql.snap b/prql-compiler/tests/integration/snapshots/integration__tests__test@loop.prql.snap deleted file mode 100644 index 482dc9933c4d..000000000000 --- a/prql-compiler/tests/integration/snapshots/integration__tests__test@loop.prql.snap +++ /dev/null @@ -1,12 +0,0 @@ ---- -source: prql-compiler/tests/integration/main.rs -expression: sqlite_out -input_file: prql-compiler/tests/integration/queries/loop.prql ---- -n --2 -0 -2 -4 -6 -8 From af416df18799269039f0b4774c941dd82924740b Mon Sep 17 00:00:00 2001 From: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Date: Sun, 19 Feb 2023 16:53:20 -0800 Subject: [PATCH 009/106] revert: #1894 (#1901) (Possibly fixing would have been easier, sorry if this is creating more work. I do think running all tests is worthwhile with this sort of wide-ranging change...) --- website/content/_index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/content/_index.md b/website/content/_index.md index 349317aaf594..035f4eaedfe2 100644 --- a/website/content/_index.md +++ b/website/content/_index.md @@ -246,7 +246,7 @@ showcase_section: SELECT * FROM - table_1 AS table_0 + table_1 WHERE _expr_0 <= 1 From abc61ff3fd18e6deff9159b9726071705d3a4f29 Mon Sep 17 00:00:00 2001 From: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Date: Sun, 19 Feb 2023 16:57:54 -0800 Subject: [PATCH 010/106] test: Refactor book snapshot tests (#1900) * tests: Refactor book snapshot tests Modularizes these tests, potentially in preparation for https://github.com/PRQL/prql/issues/1895 --- book/tests/snapshot.rs | 172 ++++++++++-------- ...rql@examples__list-equivalence-0.prql.snap | 10 - ...rql@examples__list-equivalence-1.prql.snap | 10 - ..._reference_prql@examples__misc-0.prql.snap | 26 --- ..._reference_prql@examples__misc-1.prql.snap | 13 -- ...rence_prql@examples__variables-0.prql.snap | 32 ---- ...rence_prql@examples__variables-1.prql.snap | 19 -- ...rql@internals__functional-lang-0.prql.snap | 11 -- ...rql@internals__functional-lang-1.prql.snap | 11 -- ...rql@internals__functional-lang-2.prql.snap | 12 -- ...rql@internals__functional-lang-3.prql.snap | 13 -- ...prql@internals__name-resolving-0.prql.snap | 10 - ...ay_reference_prql@introduction-0.prql.snap | 32 ---- ...ql@language-features__coalesce-0.prql.snap | 10 - ...uage-features__dates-and-times-0.prql.snap | 10 - ...uage-features__dates-and-times-1.prql.snap | 10 - ...uage-features__dates-and-times-2.prql.snap | 10 - ...uage-features__dates-and-times-3.prql.snap | 10 - ...ql@language-features__distinct-0.prql.snap | 13 -- ...ql@language-features__distinct-1.prql.snap | 13 -- ...ql@language-features__distinct-2.prql.snap | 13 -- ...l@language-features__f-strings-0.prql.snap | 10 - ...l@language-features__f-strings-1.prql.snap | 10 - ...e_prql@language-features__null-0.prql.snap | 11 -- ...prql@language-features__ranges-1.prql.snap | 14 -- ...l@language-features__s-strings-0.prql.snap | 10 - ...l@language-features__s-strings-1.prql.snap | 10 - ...age-features__standard-library-0.prql.snap | 20 -- ...rql@language-features__strings-0.prql.snap | 10 - ...rql@language-features__strings-1.prql.snap | 10 - ...rql@language-features__strings-2.prql.snap | 10 - ...rql@language-features__strings-3.prql.snap | 10 - ...rql@language-features__strings-4.prql.snap | 10 - ...prql@language-features__target-0.prql.snap | 15 -- ...prql@language-features__target-1.prql.snap | 15 -- ...prql@language-features__target-2.prql.snap | 13 -- ...erence_prql@queries__pipelines-0.prql.snap | 9 - ...erence_prql@queries__pipelines-1.prql.snap | 10 - ...erence_prql@queries__variables-0.prql.snap | 18 -- ...display_reference_prql@syntax-11.prql.snap | 9 - ...display_reference_prql@syntax-13.prql.snap | 9 - ...display_reference_prql@syntax-14.prql.snap | 10 - ..._display_reference_prql@syntax-3.prql.snap | 10 - ..._display_reference_prql@syntax-4.prql.snap | 10 - ..._display_reference_prql@syntax-6.prql.snap | 40 ---- ..._display_reference_prql@syntax-8.prql.snap | 10 - ...nce_prql@transforms__aggregate-0.prql.snap | 13 -- ...nce_prql@transforms__aggregate-2.prql.snap | 10 - ...erence_prql@transforms__append-0.prql.snap | 10 - ...erence_prql@transforms__append-1.prql.snap | 10 - ...erence_prql@transforms__append-2.prql.snap | 10 - ...erence_prql@transforms__derive-0.prql.snap | 10 - ...erence_prql@transforms__filter-0.prql.snap | 10 - ...erence_prql@transforms__filter-1.prql.snap | 10 - ...erence_prql@transforms__filter-2.prql.snap | 13 -- ...eference_prql@transforms__from-0.prql.snap | 9 - ...eference_prql@transforms__from-1.prql.snap | 10 - ...nce_prql@transforms__from_text-2.prql.snap | 33 ---- ...ference_prql@transforms__group-1.prql.snap | 11 -- ...ference_prql@transforms__group-2.prql.snap | 13 -- ...eference_prql@transforms__join-2.prql.snap | 10 - ...erence_prql@transforms__select-0.prql.snap | 10 - ...erence_prql@transforms__select-2.prql.snap | 10 - ...erence_prql@transforms__select-3.prql.snap | 13 -- ...erence_prql@transforms__select-6.prql.snap | 11 -- ...eference_prql@transforms__sort-0.prql.snap | 10 - ...eference_prql@transforms__sort-1.prql.snap | 10 - ...eference_prql@transforms__sort-2.prql.snap | 14 -- ...eference_prql@transforms__sort-3.prql.snap | 10 - ...eference_prql@transforms__sort-5.prql.snap | 11 -- ...eference_prql@transforms__take-0.prql.snap | 10 - ...eference_prql@transforms__take-1.prql.snap | 14 -- ...erence_prql@transforms__window-2.prql.snap | 11 -- ...erence_prql@transforms__window-3.prql.snap | 13 -- ...erence_prql@transforms__window-4.prql.snap | 10 - ...t__tests__prql__examples__cte-0.prql.snap} | 3 +- ...ts__prql__examples__employees-0.prql.snap} | 3 +- ...ts__prql__examples__employees-1.prql.snap} | 3 +- ...ts__prql__examples__employees-2.prql.snap} | 3 +- ...ts__prql__examples__employees-3.prql.snap} | 3 +- ...ql__examples__list-equivalence-0.prql.snap | 9 + ...ql__examples__list-equivalence-1.prql.snap | 9 + ...l__examples__list-equivalence-2.prql.snap} | 3 +- ...l__examples__list-equivalence-3.prql.snap} | 3 +- ...t__tests__prql__examples__misc-0.prql.snap | 25 +++ ...t__tests__prql__examples__misc-1.prql.snap | 12 ++ ...sts__prql__examples__variables-0.prql.snap | 31 ++++ ...sts__prql__examples__variables-1.prql.snap | 18 ++ ...ql__internals__functional-lang-0.prql.snap | 10 + ...ql__internals__functional-lang-1.prql.snap | 10 + ...ql__internals__functional-lang-2.prql.snap | 11 ++ ...ql__internals__functional-lang-3.prql.snap | 12 ++ ...rql__internals__name-resolving-0.prql.snap | 9 + ...ql__internals__name-resolving-1.prql.snap} | 3 +- ...hot__tests__prql__introduction-0.prql.snap | 31 ++++ ...l__language-features__coalesce-0.prql.snap | 9 + ...uage-features__dates-and-times-0.prql.snap | 9 + ...uage-features__dates-and-times-1.prql.snap | 9 + ...uage-features__dates-and-times-2.prql.snap | 9 + ...uage-features__dates-and-times-3.prql.snap | 9 + ...l__language-features__distinct-0.prql.snap | 12 ++ ...l__language-features__distinct-1.prql.snap | 12 ++ ...l__language-features__distinct-2.prql.snap | 12 ++ ...__language-features__f-strings-0.prql.snap | 9 + ...__language-features__f-strings-1.prql.snap | 9 + ..._prql__language-features__null-0.prql.snap | 10 + ...ql__language-features__ranges-0.prql.snap} | 3 +- ...rql__language-features__ranges-1.prql.snap | 13 ++ ...__language-features__s-strings-0.prql.snap | 9 + ...__language-features__s-strings-1.prql.snap | 9 + ..._language-features__s-strings-2.prql.snap} | 3 +- ..._language-features__s-strings-3.prql.snap} | 3 +- ..._language-features__s-strings-4.prql.snap} | 3 +- ..._language-features__s-strings-5.prql.snap} | 3 +- ..._language-features__s-strings-6.prql.snap} | 3 +- ...age-features__standard-library-0.prql.snap | 19 ++ ...ql__language-features__strings-0.prql.snap | 9 + ...ql__language-features__strings-1.prql.snap | 9 + ...ql__language-features__strings-2.prql.snap | 9 + ...ql__language-features__strings-3.prql.snap | 9 + ...ql__language-features__strings-4.prql.snap | 9 + ...ql__language-features__switch-0.prql.snap} | 3 +- ...ql__language-features__switch-1.prql.snap} | 3 +- ...rql__language-features__target-0.prql.snap | 14 ++ ...rql__language-features__target-1.prql.snap | 14 ++ ...rql__language-features__target-2.prql.snap | 12 ++ ...sts__prql__queries__functions-0.prql.snap} | 3 +- ...sts__prql__queries__functions-1.prql.snap} | 3 +- ...sts__prql__queries__functions-2.prql.snap} | 3 +- ...sts__prql__queries__functions-3.prql.snap} | 3 +- ...sts__prql__queries__functions-4.prql.snap} | 3 +- ...ests__prql__queries__pipelines-0.prql.snap | 8 + ...ests__prql__queries__pipelines-1.prql.snap | 9 + ...sts__prql__queries__pipelines-2.prql.snap} | 3 +- ...ests__prql__queries__variables-0.prql.snap | 17 ++ ...sts__prql__queries__variables-1.prql.snap} | 3 +- ...snapshot__tests__prql__syntax-0.prql.snap} | 3 +- ...snapshot__tests__prql__syntax-1.prql.snap} | 3 +- ...napshot__tests__prql__syntax-10.prql.snap} | 3 +- ...snapshot__tests__prql__syntax-11.prql.snap | 8 + ...napshot__tests__prql__syntax-12.prql.snap} | 3 +- ...snapshot__tests__prql__syntax-13.prql.snap | 8 + ...snapshot__tests__prql__syntax-14.prql.snap | 9 + ...napshot__tests__prql__syntax-15.prql.snap} | 3 +- ...snapshot__tests__prql__syntax-2.prql.snap} | 3 +- .../snapshot__tests__prql__syntax-3.prql.snap | 9 + .../snapshot__tests__prql__syntax-4.prql.snap | 9 + ...snapshot__tests__prql__syntax-5.prql.snap} | 3 +- .../snapshot__tests__prql__syntax-6.prql.snap | 39 ++++ ...snapshot__tests__prql__syntax-7.prql.snap} | 3 +- .../snapshot__tests__prql__syntax-8.prql.snap | 9 + ...snapshot__tests__prql__syntax-9.prql.snap} | 3 +- ...s__prql__transforms__aggregate-0.prql.snap | 12 ++ ...__prql__transforms__aggregate-1.prql.snap} | 3 +- ...s__prql__transforms__aggregate-2.prql.snap | 9 + ...ests__prql__transforms__append-0.prql.snap | 9 + ...ests__prql__transforms__append-1.prql.snap | 9 + ...ests__prql__transforms__append-2.prql.snap | 9 + ...ests__prql__transforms__derive-0.prql.snap | 9 + ...sts__prql__transforms__derive-1.prql.snap} | 3 +- ...ests__prql__transforms__filter-0.prql.snap | 9 + ...ests__prql__transforms__filter-1.prql.snap | 9 + ...ests__prql__transforms__filter-2.prql.snap | 12 ++ ..._tests__prql__transforms__from-0.prql.snap | 8 + ..._tests__prql__transforms__from-1.prql.snap | 9 + ...__prql__transforms__from_text-0.prql.snap} | 3 +- ...__prql__transforms__from_text-1.prql.snap} | 3 +- ...s__prql__transforms__from_text-2.prql.snap | 32 ++++ ...ests__prql__transforms__group-0.prql.snap} | 3 +- ...tests__prql__transforms__group-1.prql.snap | 10 + ...tests__prql__transforms__group-2.prql.snap | 12 ++ ...tests__prql__transforms__join-0.prql.snap} | 3 +- ...tests__prql__transforms__join-1.prql.snap} | 3 +- ..._tests__prql__transforms__join-2.prql.snap | 9 + ...ests__prql__transforms__select-0.prql.snap | 9 + ...sts__prql__transforms__select-1.prql.snap} | 3 +- ...ests__prql__transforms__select-2.prql.snap | 9 + ...ests__prql__transforms__select-3.prql.snap | 12 ++ ...sts__prql__transforms__select-4.prql.snap} | 3 +- ...sts__prql__transforms__select-5.prql.snap} | 3 +- ...ests__prql__transforms__select-6.prql.snap | 10 + ..._tests__prql__transforms__sort-0.prql.snap | 9 + ..._tests__prql__transforms__sort-1.prql.snap | 9 + ..._tests__prql__transforms__sort-2.prql.snap | 13 ++ ..._tests__prql__transforms__sort-3.prql.snap | 9 + ...tests__prql__transforms__sort-4.prql.snap} | 3 +- ..._tests__prql__transforms__sort-5.prql.snap | 10 + ..._tests__prql__transforms__take-0.prql.snap | 9 + ..._tests__prql__transforms__take-1.prql.snap | 13 ++ ...sts__prql__transforms__window-0.prql.snap} | 3 +- ...sts__prql__transforms__window-1.prql.snap} | 3 +- ...ests__prql__transforms__window-2.prql.snap | 10 + ...ests__prql__transforms__window-3.prql.snap | 12 ++ ...ests__prql__transforms__window-4.prql.snap | 9 + 194 files changed, 1010 insertions(+), 1103 deletions(-) delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@examples__list-equivalence-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@examples__list-equivalence-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@examples__misc-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@examples__misc-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@examples__variables-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@examples__variables-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@internals__functional-lang-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@internals__functional-lang-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@internals__functional-lang-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@internals__functional-lang-3.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@internals__name-resolving-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@introduction-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__coalesce-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__dates-and-times-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__dates-and-times-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__dates-and-times-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__dates-and-times-3.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__distinct-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__distinct-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__distinct-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__f-strings-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__f-strings-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__null-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__ranges-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__standard-library-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__strings-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__strings-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__strings-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__strings-3.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__strings-4.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__target-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__target-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__target-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@queries__pipelines-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@queries__pipelines-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@queries__variables-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@syntax-11.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@syntax-13.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@syntax-14.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@syntax-3.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@syntax-4.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@syntax-6.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@syntax-8.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__aggregate-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__aggregate-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__append-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__append-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__append-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__derive-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__filter-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__filter-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__filter-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from_text-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__group-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__group-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__join-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-3.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-6.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-3.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-5.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__take-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__take-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__window-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__window-3.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__window-4.prql.snap rename book/tests/snapshots/{snapshot__run_display_reference_prql@examples__cte-0.prql.snap => snapshot__tests__prql__examples__cte-0.prql.snap} (51%) rename book/tests/snapshots/{snapshot__run_display_reference_prql@examples__employees-0.prql.snap => snapshot__tests__prql__examples__employees-0.prql.snap} (52%) rename book/tests/snapshots/{snapshot__run_display_reference_prql@examples__employees-1.prql.snap => snapshot__tests__prql__examples__employees-1.prql.snap} (51%) rename book/tests/snapshots/{snapshot__run_display_reference_prql@examples__employees-2.prql.snap => snapshot__tests__prql__examples__employees-2.prql.snap} (50%) rename book/tests/snapshots/{snapshot__run_display_reference_prql@examples__employees-3.prql.snap => snapshot__tests__prql__examples__employees-3.prql.snap} (52%) create mode 100644 book/tests/snapshots/snapshot__tests__prql__examples__list-equivalence-0.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__examples__list-equivalence-1.prql.snap rename book/tests/snapshots/{snapshot__run_display_reference_prql@examples__list-equivalence-2.prql.snap => snapshot__tests__prql__examples__list-equivalence-2.prql.snap} (54%) rename book/tests/snapshots/{snapshot__run_display_reference_prql@examples__list-equivalence-3.prql.snap => snapshot__tests__prql__examples__list-equivalence-3.prql.snap} (54%) create mode 100644 book/tests/snapshots/snapshot__tests__prql__examples__misc-0.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__examples__misc-1.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__examples__variables-0.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__examples__variables-1.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-0.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-1.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-2.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-3.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__internals__name-resolving-0.prql.snap rename book/tests/snapshots/{snapshot__run_display_reference_prql@internals__name-resolving-1.prql.snap => snapshot__tests__prql__internals__name-resolving-1.prql.snap} (56%) create mode 100644 book/tests/snapshots/snapshot__tests__prql__introduction-0.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__coalesce-0.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-0.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-1.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-2.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-3.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__distinct-0.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__distinct-1.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__distinct-2.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__f-strings-0.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__f-strings-1.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__null-0.prql.snap rename book/tests/snapshots/{snapshot__run_display_reference_prql@language-features__ranges-0.prql.snap => snapshot__tests__prql__language-features__ranges-0.prql.snap} (55%) create mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__ranges-1.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-0.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-1.prql.snap rename book/tests/snapshots/{snapshot__run_display_reference_prql@language-features__s-strings-2.prql.snap => snapshot__tests__prql__language-features__s-strings-2.prql.snap} (51%) rename book/tests/snapshots/{snapshot__run_display_reference_prql@language-features__s-strings-3.prql.snap => snapshot__tests__prql__language-features__s-strings-3.prql.snap} (53%) rename book/tests/snapshots/{snapshot__run_display_reference_prql@language-features__s-strings-4.prql.snap => snapshot__tests__prql__language-features__s-strings-4.prql.snap} (51%) rename book/tests/snapshots/{snapshot__run_display_reference_prql@language-features__s-strings-5.prql.snap => snapshot__tests__prql__language-features__s-strings-5.prql.snap} (53%) rename book/tests/snapshots/{snapshot__run_display_reference_prql@language-features__s-strings-6.prql.snap => snapshot__tests__prql__language-features__s-strings-6.prql.snap} (53%) create mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__standard-library-0.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__strings-0.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__strings-1.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__strings-2.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__strings-3.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__strings-4.prql.snap rename book/tests/snapshots/{snapshot__run_display_reference_prql@language-features__switch-0.prql.snap => snapshot__tests__prql__language-features__switch-0.prql.snap} (53%) rename book/tests/snapshots/{snapshot__run_display_reference_prql@language-features__switch-1.prql.snap => snapshot__tests__prql__language-features__switch-1.prql.snap} (51%) create mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__target-0.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__target-1.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__target-2.prql.snap rename book/tests/snapshots/{snapshot__run_display_reference_prql@queries__functions-0.prql.snap => snapshot__tests__prql__queries__functions-0.prql.snap} (54%) rename book/tests/snapshots/{snapshot__run_display_reference_prql@queries__functions-1.prql.snap => snapshot__tests__prql__queries__functions-1.prql.snap} (51%) rename book/tests/snapshots/{snapshot__run_display_reference_prql@queries__functions-2.prql.snap => snapshot__tests__prql__queries__functions-2.prql.snap} (52%) rename book/tests/snapshots/{snapshot__run_display_reference_prql@queries__functions-3.prql.snap => snapshot__tests__prql__queries__functions-3.prql.snap} (54%) rename book/tests/snapshots/{snapshot__run_display_reference_prql@queries__functions-4.prql.snap => snapshot__tests__prql__queries__functions-4.prql.snap} (52%) create mode 100644 book/tests/snapshots/snapshot__tests__prql__queries__pipelines-0.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__queries__pipelines-1.prql.snap rename book/tests/snapshots/{snapshot__run_display_reference_prql@queries__pipelines-2.prql.snap => snapshot__tests__prql__queries__pipelines-2.prql.snap} (53%) create mode 100644 book/tests/snapshots/snapshot__tests__prql__queries__variables-0.prql.snap rename book/tests/snapshots/{snapshot__run_display_reference_prql@queries__variables-1.prql.snap => snapshot__tests__prql__queries__variables-1.prql.snap} (51%) rename book/tests/snapshots/{snapshot__run_display_reference_prql@syntax-0.prql.snap => snapshot__tests__prql__syntax-0.prql.snap} (55%) rename book/tests/snapshots/{snapshot__run_display_reference_prql@syntax-1.prql.snap => snapshot__tests__prql__syntax-1.prql.snap} (55%) rename book/tests/snapshots/{snapshot__run_display_reference_prql@syntax-10.prql.snap => snapshot__tests__prql__syntax-10.prql.snap} (50%) create mode 100644 book/tests/snapshots/snapshot__tests__prql__syntax-11.prql.snap rename book/tests/snapshots/{snapshot__run_display_reference_prql@syntax-12.prql.snap => snapshot__tests__prql__syntax-12.prql.snap} (55%) create mode 100644 book/tests/snapshots/snapshot__tests__prql__syntax-13.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__syntax-14.prql.snap rename book/tests/snapshots/{snapshot__run_display_reference_prql@syntax-15.prql.snap => snapshot__tests__prql__syntax-15.prql.snap} (50%) rename book/tests/snapshots/{snapshot__run_display_reference_prql@syntax-2.prql.snap => snapshot__tests__prql__syntax-2.prql.snap} (54%) create mode 100644 book/tests/snapshots/snapshot__tests__prql__syntax-3.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__syntax-4.prql.snap rename book/tests/snapshots/{snapshot__run_display_reference_prql@syntax-5.prql.snap => snapshot__tests__prql__syntax-5.prql.snap} (53%) create mode 100644 book/tests/snapshots/snapshot__tests__prql__syntax-6.prql.snap rename book/tests/snapshots/{snapshot__run_display_reference_prql@syntax-7.prql.snap => snapshot__tests__prql__syntax-7.prql.snap} (54%) create mode 100644 book/tests/snapshots/snapshot__tests__prql__syntax-8.prql.snap rename book/tests/snapshots/{snapshot__run_display_reference_prql@syntax-9.prql.snap => snapshot__tests__prql__syntax-9.prql.snap} (50%) create mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__aggregate-0.prql.snap rename book/tests/snapshots/{snapshot__run_display_reference_prql@transforms__aggregate-1.prql.snap => snapshot__tests__prql__transforms__aggregate-1.prql.snap} (54%) create mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__aggregate-2.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__append-0.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__append-1.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__append-2.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__derive-0.prql.snap rename book/tests/snapshots/{snapshot__run_display_reference_prql@transforms__derive-1.prql.snap => snapshot__tests__prql__transforms__derive-1.prql.snap} (54%) create mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__filter-0.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__filter-1.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__filter-2.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__from-0.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__from-1.prql.snap rename book/tests/snapshots/{snapshot__run_display_reference_prql@transforms__from_text-0.prql.snap => snapshot__tests__prql__transforms__from_text-0.prql.snap} (50%) rename book/tests/snapshots/{snapshot__run_display_reference_prql@transforms__from_text-1.prql.snap => snapshot__tests__prql__transforms__from_text-1.prql.snap} (51%) create mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__from_text-2.prql.snap rename book/tests/snapshots/{snapshot__run_display_reference_prql@transforms__group-0.prql.snap => snapshot__tests__prql__transforms__group-0.prql.snap} (54%) create mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__group-1.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__group-2.prql.snap rename book/tests/snapshots/{snapshot__run_display_reference_prql@transforms__join-0.prql.snap => snapshot__tests__prql__transforms__join-0.prql.snap} (52%) rename book/tests/snapshots/{snapshot__run_display_reference_prql@transforms__join-1.prql.snap => snapshot__tests__prql__transforms__join-1.prql.snap} (51%) create mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__join-2.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__select-0.prql.snap rename book/tests/snapshots/{snapshot__run_display_reference_prql@transforms__select-1.prql.snap => snapshot__tests__prql__transforms__select-1.prql.snap} (53%) create mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__select-2.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__select-3.prql.snap rename book/tests/snapshots/{snapshot__run_display_reference_prql@transforms__select-4.prql.snap => snapshot__tests__prql__transforms__select-4.prql.snap} (51%) rename book/tests/snapshots/{snapshot__run_display_reference_prql@transforms__select-5.prql.snap => snapshot__tests__prql__transforms__select-5.prql.snap} (55%) create mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__select-6.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__sort-0.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__sort-1.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__sort-2.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__sort-3.prql.snap rename book/tests/snapshots/{snapshot__run_display_reference_prql@transforms__sort-4.prql.snap => snapshot__tests__prql__transforms__sort-4.prql.snap} (50%) create mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__sort-5.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__take-0.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__take-1.prql.snap rename book/tests/snapshots/{snapshot__run_display_reference_prql@transforms__window-0.prql.snap => snapshot__tests__prql__transforms__window-0.prql.snap} (52%) rename book/tests/snapshots/{snapshot__run_display_reference_prql@transforms__window-1.prql.snap => snapshot__tests__prql__transforms__window-1.prql.snap} (51%) create mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__window-2.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__window-3.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__window-4.prql.snap diff --git a/book/tests/snapshot.rs b/book/tests/snapshot.rs index e86b59ae20fc..d26bfe754dec 100644 --- a/book/tests/snapshot.rs +++ b/book/tests/snapshot.rs @@ -1,6 +1,6 @@ #![cfg(not(target_family = "wasm"))] /// This test: -/// - Extracts PRQL code blocks into the `examples` path. +/// - Extracts PRQL code blocks into files in the `examples` path /// - Converts them to SQL using insta, raising an error if there's a diff. /// - Replaces the PRQL code block with a comparison table. /// @@ -18,69 +18,38 @@ // us. They introduce a bunch of non-rust dependencies, which is not ideal, but // passable. They don't let us customize our formatting (e.g. in a table). // -use anyhow::{bail, Result}; +use anyhow::{bail, Error, Result}; use globset::Glob; -use insta::{assert_display_snapshot, assert_snapshot, glob}; +use insta::{assert_snapshot, glob}; +use itertools::Itertools; use log::warn; use prql_compiler::*; use pulldown_cmark::{CodeBlockKind, Event, Parser, Tag}; -use std::fs; use std::path::Path; +use std::{collections::HashMap, fs}; use walkdir::WalkDir; #[test] -fn run_examples() -> Result<()> { - // TODO: In CI this could pass by replacing incorrect files. To catch that, - // we could check if there are any diffs after this has run? - +fn test_examples() -> Result<()> { // Note that on windows, markdown is read differently, and so // writing on Windows. ref https://github.com/PRQL/prql/issues/356 #[cfg(not(target_family = "windows"))] - write_reference_prql()?; - run_reference_prql(); - - // TODO: Currently we run this in the same test, since we need the - // `write_reference_prql` function to have been run. If we could iterate - // over the PRQL examples without writing them to disk, we could run this as - // a separate test. (Though then we'd lose the deferred failures feature - // that insta's `glob!` macro provides.) - run_display_reference_prql(); + write_prql_examples()?; + test_prql_examples(); Ok(()) } -/// Extract reference examples from the PRQL docs and write them to the -/// `tests/prql` path, one in each file. -// We could alternatively have used something like -// https://github.com/earldouglas/codedown, but it's not much code, and it -// requires no dependencies. -// -// We allow dead_code because of the window issue described above. (Can we allow -// it only for windows?) -#[allow(dead_code)] -fn write_reference_prql() -> Result<()> { - // Remove old .prql files, since we're going to rewrite them, and we don't want - // old files which wouldn't be rewritten from hanging around. - // We use `trash`, since we don't want to be removing files with test code - // in case there's a bug. - // - // A more elegant approach would be to keep a list of the files and remove - // the ones we don't write. - - let examples_path = Path::new("tests/prql"); - if examples_path.exists() { - trash::delete(Path::new("tests/prql")).unwrap_or_else(|e| { - warn!("Failed to delete old examples: {}", e); - }); - } +const ROOT_EXAMPLES_PATH: &str = "tests/prql"; +/// Collect all the PRQL examples in the book, as a map of . +fn collect_book_examples() -> Result> { let glob = Glob::new("**/*.md")?.compile_matcher(); - - WalkDir::new(Path::new("./src/")) + let examples_in_book: HashMap = WalkDir::new(Path::new("./src/")) .into_iter() .flatten() .filter(|x| glob.is_match(x.path())) - .try_for_each(|dir_entry| { + .flat_map(|dir_entry| { let text = fs::read_to_string(dir_entry.path())?; let mut parser = Parser::new(&text); let mut prql_blocks = vec![]; @@ -102,33 +71,85 @@ fn write_reference_prql() -> Result<()> { _ => {} } } - - // Write each one to a new file. - prql_blocks + let snapshot_prefix = &dir_entry + .path() + .strip_prefix("./src/")? + .to_str() + .unwrap() + .trim_end_matches(".md"); + Ok(prql_blocks .iter() .enumerate() - .try_for_each(|(i, example)| { - let file_relative = &dir_entry - .path() - .strip_prefix("./src/")? - .to_str() - .unwrap() - .trim_end_matches(".md"); - let prql_path = format!("tests/prql/{file_relative}-{i}.prql"); - - fs::create_dir_all(Path::new(&prql_path).parent().unwrap())?; - fs::write(prql_path, example.to_string())?; - - Ok::<(), anyhow::Error>(()) - })?; - Ok(()) + .map(|(i, example)| { + ( + format!("{ROOT_EXAMPLES_PATH}/{snapshot_prefix}-{i}.prql"), + example.to_string(), + ) + }) + .collect::>()) + }) + .flatten() + .collect(); + + Ok(examples_in_book) +} + +/// Extract reference examples from the PRQL docs and write them to the +/// `tests/prql` path, one in each file. +// We could alternatively have used something like +// https://github.com/earldouglas/codedown, but it's not much code, and it +// requires no dependencies. +// +// We allow dead_code because of the window issue described above. (Can we allow +// it only for windows?) +#[allow(dead_code)] +fn write_prql_examples() -> Result<()> { + // If we have to modify any files, raise an error at the end, so it fails in CI. + let mut snapshots_updated = false; + + let examples_path = Path::new(ROOT_EXAMPLES_PATH); + let prql_matcher = Glob::new("**.prql")?.compile_matcher(); + let mut existing_snapshots: HashMap<_, _> = WalkDir::new(examples_path) + .into_iter() + .flatten() + .filter(|x| prql_matcher.is_match(x.path())) + .map(|x| x.path().to_owned()) + .map(|x| Ok::<_, Error>((x.to_string_lossy().to_string(), fs::read_to_string(x)?))) + .try_collect()?; + + // Write any new snapshots, or update any that have changed. = + collect_book_examples()? + .iter() + .try_for_each(|(prql_path, example)| { + if existing_snapshots + .remove(prql_path) + .map(|existing| existing != *example) + .unwrap_or(true) + { + snapshots_updated = true; + fs::create_dir_all(Path::new(prql_path).parent().unwrap())?; + fs::write(prql_path, example)?; + } + + Ok::<(), anyhow::Error>(()) })?; + // If there are any files left in `existing_snapshots`, we remove them, since + // they don't reference anything. + existing_snapshots.iter().for_each(|(path, _)| { + trash::delete(path).unwrap_or_else(|e| { + warn!("Failed to delete unreferenced example: {}", e); + }) + }); + + if snapshots_updated { + bail!("Some book snapshots were not consistent with the queries in the book and have been updated. Subsequent runs should pass."); + } Ok(()) } /// Snapshot the output of each example. -fn run_reference_prql() { +fn test_prql_examples() { glob!("prql/**/*.prql", |path| { let prql = fs::read_to_string(path).unwrap(); @@ -147,20 +168,25 @@ fn run_reference_prql() { } /// Snapshot the display trait output of each example. -// Currently not a separate test, see notes in caller. // // TODO: this involves writing out almost the same PRQL again — instead we could // compare the output of Display to the auto-formatted source. But we need an // autoformatter for that (unless we want to raise on any non-matching input, // which seems very strict) -fn run_display_reference_prql() { - glob!("prql/**/*.prql", |path| { - let prql = fs::read_to_string(path).unwrap(); - - if prql.contains("skip_test") { - return; - } +#[test] +fn test_display() -> Result<(), ErrorMessages> { + use prql_compiler::downcast; + collect_book_examples() + .map_err(downcast)? + .iter() + .try_for_each(|(path, example)| { + assert_snapshot!( + path.to_owned(), + prql_to_pl(example).and_then(pl_to_prql)?, + example + ); + Ok::<(), ErrorMessages>(()) + })?; - assert_display_snapshot!(prql_to_pl(&prql).and_then(pl_to_prql).unwrap()); - }); + Ok(()) } diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@examples__list-equivalence-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@examples__list-equivalence-0.prql.snap deleted file mode 100644 index 085bada98319..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@examples__list-equivalence-0.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/examples/list-equivalence-0.prql ---- -from employees -select salary - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@examples__list-equivalence-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@examples__list-equivalence-1.prql.snap deleted file mode 100644 index 6ab6d90cdd10..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@examples__list-equivalence-1.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/examples/list-equivalence-1.prql ---- -from employees -select [salary] - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@examples__misc-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@examples__misc-0.prql.snap deleted file mode 100644 index 930d29f6d477..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@examples__misc-0.prql.snap +++ /dev/null @@ -1,26 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/examples/misc-0.prql ---- -let parts = ( - from seq_1_to_5 -) - - - -from pl = prospect_lists_prospects -filter prospect_list_id == "cc675eee-8bd1-237f-be5e-622ba511d65e" -join a = accounts [a.id == pl.related_id] -join er = email_addr_bean_rel [er.bean_id == a.id and er.primary_address == "1"] -join ea = email_addresses [ea.id == er.email_address_id] -select ea.email_address -derive prefix = s"regexp_replace(SUBSTRING_INDEX({email_address}, '@', 1), '[.0-9-_:]+', '.')" -derive stub = s"SUBSTRING_INDEX(SUBSTRING_INDEX({prefix}, '.', part), '.', -1)" -select [ - email_address, - stub, -] - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@examples__misc-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@examples__misc-1.prql.snap deleted file mode 100644 index d48e3fe1307a..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@examples__misc-1.prql.snap +++ /dev/null @@ -1,13 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/examples/misc-1.prql ---- -from club_ratings -filter rating != null -group year ( - derive [rating_norm = rating - ( average rating ) / ( stddev rating )] -) - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@examples__variables-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@examples__variables-0.prql.snap deleted file mode 100644 index c4e1df527811..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@examples__variables-0.prql.snap +++ /dev/null @@ -1,32 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/examples/variables-0.prql ---- -from employees -filter country == "USA" -derive [ - gross_salary = salary + payroll_tax, - gross_cost = gross_salary + benefits_cost, -] -filter gross_cost > 0 -group [ - title, - country, -] ( - aggregate [ - average salary, - average gross_salary, - sum salary, - sum gross_salary, - average gross_cost, - sum_gross_cost = sum gross_cost, - ct = count, -] -) -sort sum_gross_cost -filter ct > 200 -take 20 - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@examples__variables-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@examples__variables-1.prql.snap deleted file mode 100644 index 1f588bf0d309..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@examples__variables-1.prql.snap +++ /dev/null @@ -1,19 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/examples/variables-1.prql ---- -from employees -group [emp_no] ( - aggregate [emp_salary = average salary] -) -join titles [==emp_no] -group [title] ( - aggregate [avg_salary = average emp_salary] -) -select salary_k = avg_salary / 1000 -take 10 -derive salary = salary_k * 1000 - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@internals__functional-lang-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@internals__functional-lang-0.prql.snap deleted file mode 100644 index 96d5d50a00e1..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@internals__functional-lang-0.prql.snap +++ /dev/null @@ -1,11 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/internals/functional-lang-0.prql ---- -from employees -filter age > 50 -sort name - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@internals__functional-lang-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@internals__functional-lang-1.prql.snap deleted file mode 100644 index ae83420f23d3..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@internals__functional-lang-1.prql.snap +++ /dev/null @@ -1,11 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/internals/functional-lang-1.prql ---- -from employees -filter age > 50 -sort name - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@internals__functional-lang-2.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@internals__functional-lang-2.prql.snap deleted file mode 100644 index f15a84e195b3..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@internals__functional-lang-2.prql.snap +++ /dev/null @@ -1,12 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/internals/functional-lang-2.prql ---- -filter age > 50 ( - from employees -) -sort name - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@internals__functional-lang-3.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@internals__functional-lang-3.prql.snap deleted file mode 100644 index aa777d923706..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@internals__functional-lang-3.prql.snap +++ /dev/null @@ -1,13 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/internals/functional-lang-3.prql ---- -sort name ( - filter age > 50 ( - from employees -) -) - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@internals__name-resolving-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@internals__name-resolving-0.prql.snap deleted file mode 100644 index a7bd8bc3730a..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@internals__name-resolving-0.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/internals/name-resolving-0.prql ---- -from employees -select first_name - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@introduction-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@introduction-0.prql.snap deleted file mode 100644 index bc40a390e21a..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@introduction-0.prql.snap +++ /dev/null @@ -1,32 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/introduction-0.prql ---- -from employees -filter start_date > @2021-01-01 -derive [ - gross_salary = salary + tax ?? 0, - gross_cost = gross_salary + benefits_cost, -] -filter gross_cost > 0 -group [ - title, - country, -] ( - aggregate [ - average gross_salary, - sum_gross_cost = sum gross_cost, -] -) -filter sum_gross_cost > 100000 -derive id = f"{title}_{country}" -derive country_code = s"LEFT(country, 2)" -sort [ - sum_gross_cost, - -country, -] -take 1..20 - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__coalesce-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__coalesce-0.prql.snap deleted file mode 100644 index 16833c5f8cfa..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__coalesce-0.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/coalesce-0.prql ---- -from orders -derive amount ?? 0 - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__dates-and-times-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__dates-and-times-0.prql.snap deleted file mode 100644 index ca08e6d69631..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__dates-and-times-0.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/dates-and-times-0.prql ---- -from employees -derive age_at_year_end = @2022-12-31 - dob - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__dates-and-times-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__dates-and-times-1.prql.snap deleted file mode 100644 index 07d9b568eac6..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__dates-and-times-1.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/dates-and-times-1.prql ---- -from orders -derive should_have_shipped_today = order_time < @08:30 - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__dates-and-times-2.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__dates-and-times-2.prql.snap deleted file mode 100644 index 6e0b688f7f7a..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__dates-and-times-2.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/dates-and-times-2.prql ---- -from commits -derive first_prql_commit = @2020-01-01T13:19:55-0800 - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__dates-and-times-3.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__dates-and-times-3.prql.snap deleted file mode 100644 index 5080f647a12c..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__dates-and-times-3.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/dates-and-times-3.prql ---- -from projects -derive first_check_in = start + 10days - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__distinct-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__distinct-0.prql.snap deleted file mode 100644 index 587f75ff1bd2..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__distinct-0.prql.snap +++ /dev/null @@ -1,13 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/distinct-0.prql ---- -from employees -select department -group department ( - take 1 -) - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__distinct-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__distinct-1.prql.snap deleted file mode 100644 index d6bcee7acf86..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__distinct-1.prql.snap +++ /dev/null @@ -1,13 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/distinct-1.prql ---- -from employees -select department -group department ( - take 1 -) - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__distinct-2.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__distinct-2.prql.snap deleted file mode 100644 index 4f2e5f381a88..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__distinct-2.prql.snap +++ /dev/null @@ -1,13 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/distinct-2.prql ---- -from employees -group department ( - sort age - take 1 -) - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__f-strings-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__f-strings-0.prql.snap deleted file mode 100644 index 2b8a822ba481..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__f-strings-0.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/f-strings-0.prql ---- -from employees -select full_name = f"{first_name} {last_name}" - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__f-strings-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__f-strings-1.prql.snap deleted file mode 100644 index b61f8780aa34..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__f-strings-1.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/f-strings-1.prql ---- -from web -select url = f"http{tls}://www.{domain}.{tld}/{page}" - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__null-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__null-0.prql.snap deleted file mode 100644 index 016809741efe..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__null-0.prql.snap +++ /dev/null @@ -1,11 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/null-0.prql ---- -from employees -filter first_name == null -filter null != last_name - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__ranges-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__ranges-1.prql.snap deleted file mode 100644 index 46ce8b767eb3..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__ranges-1.prql.snap +++ /dev/null @@ -1,14 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/ranges-1.prql ---- -from orders -sort [ - -value, - date, -] -take 101..110 - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-0.prql.snap deleted file mode 100644 index fa9c95fb9f4c..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-0.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/s-strings-0.prql ---- -from my_table -select db_version = s"version()" - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-1.prql.snap deleted file mode 100644 index 7de6990c149c..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-1.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/s-strings-1.prql ---- -from employees -aggregate [average salary] - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__standard-library-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__standard-library-0.prql.snap deleted file mode 100644 index 691cabab4a62..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__standard-library-0.prql.snap +++ /dev/null @@ -1,20 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/standard-library-0.prql ---- -from employees -derive [ - gross_salary = ( - salary + payroll_tax - as int -), - gross_salary_rounded = ( - gross_salary - round 0 -), - time = s"NOW()", -] - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__strings-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__strings-0.prql.snap deleted file mode 100644 index 08b198a45ab3..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__strings-0.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/strings-0.prql ---- -from my_table -select x = "hello world" - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__strings-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__strings-1.prql.snap deleted file mode 100644 index 014e0927ce0e..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__strings-1.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/strings-1.prql ---- -from my_table -select x = "hello world" - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__strings-2.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__strings-2.prql.snap deleted file mode 100644 index 52b190fec22a..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__strings-2.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/strings-2.prql ---- -from my_table -select x = '"hello world"' - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__strings-3.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__strings-3.prql.snap deleted file mode 100644 index eddb87ee8834..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__strings-3.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/strings-3.prql ---- -from my_table -select x = 'I said "hello world"!' - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__strings-4.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__strings-4.prql.snap deleted file mode 100644 index 5966be260e48..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__strings-4.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/strings-4.prql ---- -from my_table -select x = 'I said """hello world"""!' - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__target-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__target-0.prql.snap deleted file mode 100644 index 8d46fc69595c..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__target-0.prql.snap +++ /dev/null @@ -1,15 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/target-0.prql ---- -prql target:sql.postgres - - - -from employees -sort age -take 10 - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__target-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__target-1.prql.snap deleted file mode 100644 index 2719c8e16911..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__target-1.prql.snap +++ /dev/null @@ -1,15 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/target-1.prql ---- -prql target:sql.mssql - - - -from employees -sort age -take 10 - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__target-2.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__target-2.prql.snap deleted file mode 100644 index 5bf77265c6a4..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__target-2.prql.snap +++ /dev/null @@ -1,13 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/target-2.prql ---- -prql version:^0.5 - - - -from employees - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@queries__pipelines-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@queries__pipelines-0.prql.snap deleted file mode 100644 index 7162e861b213..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@queries__pipelines-0.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/queries/pipelines-0.prql ---- -from employees - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@queries__pipelines-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@queries__pipelines-1.prql.snap deleted file mode 100644 index f64f5d68dc56..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@queries__pipelines-1.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/queries/pipelines-1.prql ---- -from employees -derive gross_salary = salary + payroll_tax - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@queries__variables-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@queries__variables-0.prql.snap deleted file mode 100644 index fbb8c9dfa00f..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@queries__variables-0.prql.snap +++ /dev/null @@ -1,18 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/queries/variables-0.prql ---- -let top_50 = ( - from employees - sort salary - take 50 - aggregate [total_salary = sum salary] -) - - - -from top_50 - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-11.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-11.prql.snap deleted file mode 100644 index f719b0acbbd4..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-11.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/syntax-11.prql ---- -from `dir/*.parquet` - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-13.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-13.prql.snap deleted file mode 100644 index 6316d2280516..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-13.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/syntax-13.prql ---- -from `music.albums` - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-14.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-14.prql.snap deleted file mode 100644 index a38f2f750602..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-14.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/syntax-14.prql ---- -from employees -filter id == $1 - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-3.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-3.prql.snap deleted file mode 100644 index 6820f7c5e628..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-3.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/syntax-3.prql ---- -from employees -select [first_name] - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-4.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-4.prql.snap deleted file mode 100644 index 6e06fe3ee2e5..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-4.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/syntax-4.prql ---- -from employees -select first_name - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-6.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-6.prql.snap deleted file mode 100644 index d6668fe305c7..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-6.prql.snap +++ /dev/null @@ -1,40 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/syntax-6.prql ---- -from employees -derive is_proximate = ( - distance - in 0..20 -) -derive ( - total_distance = sum distance -) -derive ( - min_capped_distance = min distance ?? 5 -) -derive travel_time = distance / 40 -derive ( - distance_rounded_2_dp = round 1 + 1 distance -) -derive [ - is_far = ( - distance - in 100.. -), - is_negative = ( - distance - in -100..0 -), - is_negative = ( - distance - in -100..0 -), - average_distance = average distance, -] -sort -distance -sort [-distance] - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-8.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-8.prql.snap deleted file mode 100644 index 55a51e5d833f..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-8.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/syntax-8.prql ---- -from employees -aggregate [average salary] - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__aggregate-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__aggregate-0.prql.snap deleted file mode 100644 index 89e3271c8316..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__aggregate-0.prql.snap +++ /dev/null @@ -1,13 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/aggregate-0.prql ---- -from employees -aggregate [ - average salary, - ct = count, -] - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__aggregate-2.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__aggregate-2.prql.snap deleted file mode 100644 index 21468ff11aeb..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__aggregate-2.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/aggregate-2.prql ---- -from employees -derive [avg_sal = average salary] - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__append-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__append-0.prql.snap deleted file mode 100644 index 821c0f010d36..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__append-0.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/append-0.prql ---- -from employees_1 -append employees_2 - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__append-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__append-1.prql.snap deleted file mode 100644 index 2a61ec1251b1..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__append-1.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/append-1.prql ---- -from employees_1 -remove employees_2 - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__append-2.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__append-2.prql.snap deleted file mode 100644 index dddeb63b7c9f..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__append-2.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/append-2.prql ---- -from employees_1 -intersect employees_2 - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__derive-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__derive-0.prql.snap deleted file mode 100644 index e90d9add3db4..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__derive-0.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/derive-0.prql ---- -from employees -derive gross_salary = salary + payroll_tax - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__filter-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__filter-0.prql.snap deleted file mode 100644 index 8a68bf997bd7..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__filter-0.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/filter-0.prql ---- -from employees -filter age > 25 - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__filter-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__filter-1.prql.snap deleted file mode 100644 index 1bc8cf6d4a34..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__filter-1.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/filter-1.prql ---- -from employees -filter age > 25 or department != "IT" - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__filter-2.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__filter-2.prql.snap deleted file mode 100644 index ad800e09070f..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__filter-2.prql.snap +++ /dev/null @@ -1,13 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/filter-2.prql ---- -from employees -filter ( - age - in 25..40 -) - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from-0.prql.snap deleted file mode 100644 index 0adcf6191d9e..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from-0.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/from-0.prql ---- -from employees - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from-1.prql.snap deleted file mode 100644 index b90898f6f93e..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from-1.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/from-1.prql ---- -from e = employees -select e.first_name - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from_text-2.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from_text-2.prql.snap deleted file mode 100644 index a0aaabe15cb7..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from_text-2.prql.snap +++ /dev/null @@ -1,33 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/from_text-2.prql ---- -let x = ( - from_text format:json '{ - "columns": ["a", "b", "c"], - "data": [ - [1, "x", false], - [4, "y", null] - ] -}' -) - - - -let y = ( - from_text format:json ' - [ - {"a": 1, "m": "5"}, - {"a": 4, "n": "6"} - ] -' -) - - - -from x -join y [==a] - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__group-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__group-1.prql.snap deleted file mode 100644 index f916e255f991..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__group-1.prql.snap +++ /dev/null @@ -1,11 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/group-1.prql ---- -from employees -sort join_date -take 1 - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__group-2.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__group-2.prql.snap deleted file mode 100644 index 6b2cb62586b3..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__group-2.prql.snap +++ /dev/null @@ -1,13 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/group-2.prql ---- -from employees -group role ( - sort join_date - take 1 -) - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__join-2.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__join-2.prql.snap deleted file mode 100644 index 19b950c9d24b..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__join-2.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/join-2.prql ---- -from employees -join positions [==emp_no] - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-0.prql.snap deleted file mode 100644 index 9841ec3d8249..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-0.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/select-0.prql ---- -from employees -select name = f"{first_name} {last_name}" - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-2.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-2.prql.snap deleted file mode 100644 index 522050c7dd99..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-2.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/select-2.prql ---- -from employees -select first_name - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-3.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-3.prql.snap deleted file mode 100644 index d6596a9ce634..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-3.prql.snap +++ /dev/null @@ -1,13 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/select-3.prql ---- -from e = employees -select [ - e.first_name, - e.last_name, -] - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-6.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-6.prql.snap deleted file mode 100644 index 102555240bdb..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-6.prql.snap +++ /dev/null @@ -1,11 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/select-6.prql ---- -from artists -derive nick = name -select not [artists.`*`] - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-0.prql.snap deleted file mode 100644 index 91b36c10532f..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-0.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/sort-0.prql ---- -from employees -sort age - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-1.prql.snap deleted file mode 100644 index d7f443472fc9..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-1.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/sort-1.prql ---- -from employees -sort [-age] - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-2.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-2.prql.snap deleted file mode 100644 index 1df292e0b57f..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-2.prql.snap +++ /dev/null @@ -1,14 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/sort-2.prql ---- -from employees -sort [ - age, - -tenure, - salary, -] - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-3.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-3.prql.snap deleted file mode 100644 index 3ef53a4676e9..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-3.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/sort-3.prql ---- -from employees -sort [s"substr({first_name}, 2, 5)"] - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-5.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-5.prql.snap deleted file mode 100644 index 52f805544586..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-5.prql.snap +++ /dev/null @@ -1,11 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/sort-5.prql ---- -from employees -sort tenure -join locations [==employee_id] - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__take-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__take-0.prql.snap deleted file mode 100644 index 7f798967b647..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__take-0.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/take-0.prql ---- -from employees -take 10 - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__take-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__take-1.prql.snap deleted file mode 100644 index 4107c86bfd92..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__take-1.prql.snap +++ /dev/null @@ -1,14 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/take-1.prql ---- -from orders -sort [ - -value, - date, -] -take 101..110 - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__window-2.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__window-2.prql.snap deleted file mode 100644 index 3015829b90db..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__window-2.prql.snap +++ /dev/null @@ -1,11 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/window-2.prql ---- -from employees -sort age -derive rnk = rank - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__window-3.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__window-3.prql.snap deleted file mode 100644 index 26a5eb5d9d46..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__window-3.prql.snap +++ /dev/null @@ -1,13 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/window-3.prql ---- -from employees -group department ( - sort age - derive rnk = rank -) - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__window-4.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__window-4.prql.snap deleted file mode 100644 index be549656354d..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__window-4.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/window-4.prql ---- -from employees -filter salary < ( average salary ) - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@examples__cte-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__examples__cte-0.prql.snap similarity index 51% rename from book/tests/snapshots/snapshot__run_display_reference_prql@examples__cte-0.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__examples__cte-0.prql.snap index b246de058091..83e9f48a0e9e 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@examples__cte-0.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__examples__cte-0.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/examples/cte-0.prql +expression: "let newest_employees = (\n from employees\n sort tenure\n take 50\n)\n\nlet average_salaries = (\n from salaries\n group country (\n aggregate average_country_salary = (average salary)\n )\n)\n\nfrom newest_employees\njoin average_salaries [==country]\nselect [name, salary, average_country_salary]\n" --- let newest_employees = ( from employees diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@examples__employees-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__examples__employees-0.prql.snap similarity index 52% rename from book/tests/snapshots/snapshot__run_display_reference_prql@examples__employees-0.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__examples__employees-0.prql.snap index 692c476512cc..ac80804d08a1 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@examples__employees-0.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__examples__employees-0.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/examples/employees-0.prql +expression: "from salaries\ngroup [emp_no] (\n aggregate [emp_salary = average salary]\n)\njoin t=titles [==emp_no]\njoin dept_emp side:left [==emp_no]\ngroup [dept_emp.dept_no, t.title] (\n aggregate [avg_salary = average emp_salary]\n)\njoin departments [==dept_no]\nselect [dept_name, title, avg_salary]\n" --- from salaries group [emp_no] ( diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@examples__employees-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__examples__employees-1.prql.snap similarity index 51% rename from book/tests/snapshots/snapshot__run_display_reference_prql@examples__employees-1.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__examples__employees-1.prql.snap index 665754bd3fb5..c5d5366f6306 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@examples__employees-1.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__examples__employees-1.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/examples/employees-1.prql +expression: "from e=employees\njoin salaries [==emp_no]\ngroup [e.emp_no, e.gender] (\n aggregate [\n emp_salary = average salaries.salary\n ]\n)\njoin de=dept_emp [==emp_no] side:left\ngroup [de.dept_no, gender] (\n aggregate [\n salary_avg = average emp_salary,\n salary_sd = stddev emp_salary,\n ]\n)\njoin departments [==dept_no]\nselect [dept_name, gender, salary_avg, salary_sd]\n" --- from e = employees join salaries [==emp_no] diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@examples__employees-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__examples__employees-2.prql.snap similarity index 50% rename from book/tests/snapshots/snapshot__run_display_reference_prql@examples__employees-2.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__examples__employees-2.prql.snap index 3823173006c7..d957c280a5c6 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@examples__employees-2.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__examples__employees-2.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/examples/employees-2.prql +expression: "from e=employees\njoin salaries [==emp_no]\ngroup [e.emp_no, e.gender] (\n aggregate [\n emp_salary = average salaries.salary\n ]\n)\njoin de=dept_emp [==emp_no]\njoin dm=dept_manager [\n (dm.dept_no == de.dept_no) and s\"(de.from_date, de.to_date) OVERLAPS (dm.from_date, dm.to_date)\"\n]\ngroup [dm.emp_no, gender] (\n aggregate [\n salary_avg = average emp_salary,\n salary_sd = stddev emp_salary\n ]\n)\nderive mng_no = emp_no\njoin managers=employees [==emp_no]\nderive mng_name = s\"managers.first_name || ' ' || managers.last_name\"\nselect [mng_name, managers.gender, salary_avg, salary_sd]\n" --- from e = employees join salaries [==emp_no] diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@examples__employees-3.prql.snap b/book/tests/snapshots/snapshot__tests__prql__examples__employees-3.prql.snap similarity index 52% rename from book/tests/snapshots/snapshot__run_display_reference_prql@examples__employees-3.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__examples__employees-3.prql.snap index 611769e8f06d..9cc6115f24bd 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@examples__employees-3.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__examples__employees-3.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/examples/employees-3.prql +expression: "from de=dept_emp\njoin s=salaries side:left [\n (s.emp_no == de.emp_no),\n s\"({s.from_date}, {s.to_date}) OVERLAPS ({de.from_date}, {de.to_date})\"\n]\ngroup [de.emp_no, de.dept_no] (\n aggregate salary = (average s.salary)\n)\njoin employees [==emp_no]\njoin titles [==emp_no]\nselect [dept_no, salary, employees.gender, titles.title]\n" --- from de = dept_emp join side:left s = salaries [ diff --git a/book/tests/snapshots/snapshot__tests__prql__examples__list-equivalence-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__examples__list-equivalence-0.prql.snap new file mode 100644 index 000000000000..8566dfaeb2b2 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__examples__list-equivalence-0.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nselect salary\n" +--- +from employees +select salary + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__examples__list-equivalence-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__examples__list-equivalence-1.prql.snap new file mode 100644 index 000000000000..055af64b363a --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__examples__list-equivalence-1.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nselect [salary]\n" +--- +from employees +select [salary] + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@examples__list-equivalence-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__examples__list-equivalence-2.prql.snap similarity index 54% rename from book/tests/snapshots/snapshot__run_display_reference_prql@examples__list-equivalence-2.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__examples__list-equivalence-2.prql.snap index 5ba483c522d7..3d298b6f9b55 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@examples__list-equivalence-2.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__examples__list-equivalence-2.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/examples/list-equivalence-2.prql +expression: "from employees\nderive [\n gross_salary = salary + payroll_tax,\n gross_cost = gross_salary + benefits_cost\n]\n" --- from employees derive [ diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@examples__list-equivalence-3.prql.snap b/book/tests/snapshots/snapshot__tests__prql__examples__list-equivalence-3.prql.snap similarity index 54% rename from book/tests/snapshots/snapshot__run_display_reference_prql@examples__list-equivalence-3.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__examples__list-equivalence-3.prql.snap index c1c8e138f806..254f07187889 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@examples__list-equivalence-3.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__examples__list-equivalence-3.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/examples/list-equivalence-3.prql +expression: "from employees\nderive gross_salary = salary + payroll_tax\nderive gross_cost = gross_salary + benefits_cost\n" --- from employees derive gross_salary = salary + payroll_tax diff --git a/book/tests/snapshots/snapshot__tests__prql__examples__misc-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__examples__misc-0.prql.snap new file mode 100644 index 000000000000..63b13a31ec56 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__examples__misc-0.prql.snap @@ -0,0 +1,25 @@ +--- +source: book/tests/snapshot.rs +expression: "# TODO: this table should have a column `part` with values 1..5,\n# but such data declaration is not yet supported, see #286\nlet parts = (\n from seq_1_to_5\n)\n\nfrom pl=prospect_lists_prospects\nfilter prospect_list_id == 'cc675eee-8bd1-237f-be5e-622ba511d65e'\njoin a=accounts [a.id == pl.related_id]\njoin er=email_addr_bean_rel [er.bean_id == a.id and er.primary_address == '1']\njoin ea=email_addresses [ea.id == er.email_address_id]\nselect ea.email_address\nderive prefix = s\"regexp_replace(SUBSTRING_INDEX({email_address}, '@', 1), '[.0-9-_:]+', '.')\"\nderive stub = s\"SUBSTRING_INDEX(SUBSTRING_INDEX({prefix}, '.', part), '.', -1)\"\nselect [email_address, stub]\n" +--- +let parts = ( + from seq_1_to_5 +) + + + +from pl = prospect_lists_prospects +filter prospect_list_id == "cc675eee-8bd1-237f-be5e-622ba511d65e" +join a = accounts [a.id == pl.related_id] +join er = email_addr_bean_rel [er.bean_id == a.id and er.primary_address == "1"] +join ea = email_addresses [ea.id == er.email_address_id] +select ea.email_address +derive prefix = s"regexp_replace(SUBSTRING_INDEX({email_address}, '@', 1), '[.0-9-_:]+', '.')" +derive stub = s"SUBSTRING_INDEX(SUBSTRING_INDEX({prefix}, '.', part), '.', -1)" +select [ + email_address, + stub, +] + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__examples__misc-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__examples__misc-1.prql.snap new file mode 100644 index 000000000000..50dcca896ea5 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__examples__misc-1.prql.snap @@ -0,0 +1,12 @@ +--- +source: book/tests/snapshot.rs +expression: "from club_ratings\nfilter rating != null\n# TODO: this is real ugly. `average rating` should not require parenthesis\n# TODO: why cannot we put comments in group's pipeline?\ngroup year (\n derive [rating_norm = rating - (average rating) / (stddev rating)]\n)\n" +--- +from club_ratings +filter rating != null +group year ( + derive [rating_norm = rating - ( average rating ) / ( stddev rating )] +) + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__examples__variables-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__examples__variables-0.prql.snap new file mode 100644 index 000000000000..4b1f4fce84c1 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__examples__variables-0.prql.snap @@ -0,0 +1,31 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nfilter country == \"USA\" # Each line transforms the previous result.\nderive [ # This adds columns / variables.\n gross_salary = salary + payroll_tax,\n gross_cost = gross_salary + benefits_cost # Variables can use other variables.\n]\nfilter gross_cost > 0\ngroup [title, country] ( # For each group use a nested pipeline\n aggregate [ # Aggregate each group to a single row\n average salary,\n average gross_salary,\n sum salary,\n sum gross_salary,\n average gross_cost,\n sum_gross_cost = sum gross_cost,\n ct = count,\n ]\n)\nsort sum_gross_cost\nfilter ct > 200\ntake 20\n" +--- +from employees +filter country == "USA" +derive [ + gross_salary = salary + payroll_tax, + gross_cost = gross_salary + benefits_cost, +] +filter gross_cost > 0 +group [ + title, + country, +] ( + aggregate [ + average salary, + average gross_salary, + sum salary, + sum gross_salary, + average gross_cost, + sum_gross_cost = sum gross_cost, + ct = count, +] +) +sort sum_gross_cost +filter ct > 200 +take 20 + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__examples__variables-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__examples__variables-1.prql.snap new file mode 100644 index 000000000000..cfb45e96a801 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__examples__variables-1.prql.snap @@ -0,0 +1,18 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\ngroup [emp_no] (\n aggregate [\n emp_salary = average salary # average salary resolves to \"AVG(salary)\" (from stdlib)\n ]\n)\njoin titles [==emp_no]\ngroup [title] (\n aggregate [\n avg_salary = average emp_salary\n ]\n)\nselect salary_k = avg_salary / 1000 # avg_salary should resolve to \"AVG(emp_salary)\"\ntake 10 # induces new SELECT\nderive salary = salary_k * 1000 # salary_k should not resolve to \"avg_salary / 1000\"\n" +--- +from employees +group [emp_no] ( + aggregate [emp_salary = average salary] +) +join titles [==emp_no] +group [title] ( + aggregate [avg_salary = average emp_salary] +) +select salary_k = avg_salary / 1000 +take 10 +derive salary = salary_k * 1000 + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-0.prql.snap new file mode 100644 index 000000000000..1bd2d905e16d --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-0.prql.snap @@ -0,0 +1,10 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nfilter age > 50\nsort name\n" +--- +from employees +filter age > 50 +sort name + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-1.prql.snap new file mode 100644 index 000000000000..da4b761a9e4b --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-1.prql.snap @@ -0,0 +1,10 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees | filter age > 50 | sort name\n" +--- +from employees +filter age > 50 +sort name + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-2.prql.snap new file mode 100644 index 000000000000..7da897d0dd14 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-2.prql.snap @@ -0,0 +1,11 @@ +--- +source: book/tests/snapshot.rs +expression: "filter age > 50 (from employees) | sort name\n" +--- +filter age > 50 ( + from employees +) +sort name + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-3.prql.snap b/book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-3.prql.snap new file mode 100644 index 000000000000..045c663815a8 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-3.prql.snap @@ -0,0 +1,12 @@ +--- +source: book/tests/snapshot.rs +expression: "sort name (filter age > 50 (from employees))\n" +--- +sort name ( + filter age > 50 ( + from employees +) +) + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__internals__name-resolving-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__internals__name-resolving-0.prql.snap new file mode 100644 index 000000000000..56e49df27e11 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__internals__name-resolving-0.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nselect first_name\n" +--- +from employees +select first_name + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@internals__name-resolving-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__internals__name-resolving-1.prql.snap similarity index 56% rename from book/tests/snapshots/snapshot__run_display_reference_prql@internals__name-resolving-1.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__internals__name-resolving-1.prql.snap index 6161fd5892e6..a9d9e5bada6d 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@internals__name-resolving-1.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__internals__name-resolving-1.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/internals/name-resolving-1.prql +expression: "from employees\nderive [first_name, dept_id]\njoin d=departments [==dept_id]\nselect [first_name, d.title]\n" --- from employees derive [ diff --git a/book/tests/snapshots/snapshot__tests__prql__introduction-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__introduction-0.prql.snap new file mode 100644 index 000000000000..96f55b8ab057 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__introduction-0.prql.snap @@ -0,0 +1,31 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nfilter start_date > @2021-01-01 # Clear date syntax\nderive [ # `derive` adds columns / variables\n gross_salary = salary + (tax ?? 0), # Terse coalesce\n gross_cost = gross_salary + benefits_cost, # Variables can use other variables\n]\nfilter gross_cost > 0\ngroup [title, country] ( # `group` runs a pipeline over each group\n aggregate [ # `aggregate` reduces each group to a value\n average gross_salary,\n sum_gross_cost = sum gross_cost, # `=` sets a column name\n ]\n)\nfilter sum_gross_cost > 100_000 # `filter` replaces both of SQL's `WHERE` & `HAVING`\nderive id = f\"{title}_{country}\" # F-strings like Python\nderive country_code = s\"LEFT(country, 2)\" # S-strings allow using SQL as an escape hatch\nsort [sum_gross_cost, -country] # `-country` means descending order\ntake 1..20 # Range expressions (also valid here as `take 20`)\n" +--- +from employees +filter start_date > @2021-01-01 +derive [ + gross_salary = salary + tax ?? 0, + gross_cost = gross_salary + benefits_cost, +] +filter gross_cost > 0 +group [ + title, + country, +] ( + aggregate [ + average gross_salary, + sum_gross_cost = sum gross_cost, +] +) +filter sum_gross_cost > 100000 +derive id = f"{title}_{country}" +derive country_code = s"LEFT(country, 2)" +sort [ + sum_gross_cost, + -country, +] +take 1..20 + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__coalesce-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__coalesce-0.prql.snap new file mode 100644 index 000000000000..24ff749cfbc8 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__coalesce-0.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from orders\nderive amount ?? 0\n" +--- +from orders +derive amount ?? 0 + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-0.prql.snap new file mode 100644 index 000000000000..acb71c71fc9a --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-0.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nderive age_at_year_end = (@2022-12-31 - dob)\n" +--- +from employees +derive age_at_year_end = @2022-12-31 - dob + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-1.prql.snap new file mode 100644 index 000000000000..fd2fe52b3f6c --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-1.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from orders\nderive should_have_shipped_today = (order_time < @08:30)\n" +--- +from orders +derive should_have_shipped_today = order_time < @08:30 + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-2.prql.snap new file mode 100644 index 000000000000..1507a39b0252 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-2.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from commits\nderive first_prql_commit = @2020-01-01T13:19:55-0800\n" +--- +from commits +derive first_prql_commit = @2020-01-01T13:19:55-0800 + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-3.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-3.prql.snap new file mode 100644 index 000000000000..70ac66f365a2 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-3.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from projects\nderive first_check_in = start + 10days\n" +--- +from projects +derive first_check_in = start + 10days + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__distinct-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__distinct-0.prql.snap new file mode 100644 index 000000000000..7929401e23b6 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__distinct-0.prql.snap @@ -0,0 +1,12 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nselect department\ngroup department (\n take 1\n)\n" +--- +from employees +select department +group department ( + take 1 +) + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__distinct-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__distinct-1.prql.snap new file mode 100644 index 000000000000..22ba087f087c --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__distinct-1.prql.snap @@ -0,0 +1,12 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nselect department\ngroup department (take 1)\n" +--- +from employees +select department +group department ( + take 1 +) + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__distinct-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__distinct-2.prql.snap new file mode 100644 index 000000000000..ceb0035e6601 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__distinct-2.prql.snap @@ -0,0 +1,12 @@ +--- +source: book/tests/snapshot.rs +expression: "# youngest employee from each department\nfrom employees\ngroup department (\n sort age\n take 1\n)\n" +--- +from employees +group department ( + sort age + take 1 +) + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__f-strings-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__f-strings-0.prql.snap new file mode 100644 index 000000000000..5f490aa52f00 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__f-strings-0.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nselect full_name = f\"{first_name} {last_name}\"\n" +--- +from employees +select full_name = f"{first_name} {last_name}" + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__f-strings-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__f-strings-1.prql.snap new file mode 100644 index 000000000000..f00e2becbab2 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__f-strings-1.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from web\nselect url = f\"http{tls}://www.{domain}.{tld}/{page}\"\n" +--- +from web +select url = f"http{tls}://www.{domain}.{tld}/{page}" + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__null-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__null-0.prql.snap new file mode 100644 index 000000000000..73594522238f --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__null-0.prql.snap @@ -0,0 +1,10 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nfilter first_name == null\nfilter null != last_name\n" +--- +from employees +filter first_name == null +filter null != last_name + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__ranges-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__ranges-0.prql.snap similarity index 55% rename from book/tests/snapshots/snapshot__run_display_reference_prql@language-features__ranges-0.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__language-features__ranges-0.prql.snap index e20b2b97240c..2d5baa98ae2d 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__ranges-0.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__ranges-0.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/ranges-0.prql +expression: "from events\nfilter (date | in @1776-07-04..@1787-09-17)\nfilter (magnitude | in 50..100)\nderive is_northern = (latitude | in 0..)\n" --- from events filter ( diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__ranges-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__ranges-1.prql.snap new file mode 100644 index 000000000000..b68c1920a669 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__ranges-1.prql.snap @@ -0,0 +1,13 @@ +--- +source: book/tests/snapshot.rs +expression: "from orders\nsort [-value, date]\ntake 101..110\n" +--- +from orders +sort [ + -value, + date, +] +take 101..110 + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-0.prql.snap new file mode 100644 index 000000000000..12abfcc2518c --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-0.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from my_table\nselect db_version = s\"version()\"\n" +--- +from my_table +select db_version = s"version()" + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-1.prql.snap new file mode 100644 index 000000000000..c57ed2561d58 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-1.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\naggregate [average salary]\n" +--- +from employees +aggregate [average salary] + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-2.prql.snap similarity index 51% rename from book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-2.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-2.prql.snap index 8d39feed0f0d..e28b7f46ed0a 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-2.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-2.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/s-strings-2.prql +expression: "from de=dept_emp\njoin s=salaries side:left [\n (s.emp_no == de.emp_no),\n s\"\"\"({s.from_date}, {s.to_date})\n OVERLAPS\n ({de.from_date}, {de.to_date})\"\"\"\n]\n" --- from de = dept_emp join side:left s = salaries [ diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-3.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-3.prql.snap similarity index 53% rename from book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-3.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-3.prql.snap index 85661196009c..2cb93849dda8 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-3.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-3.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/s-strings-3.prql +expression: "from s\"SELECT DISTINCT ON first_name, id, age FROM employees ORDER BY age ASC\"\njoin s = s\"SELECT * FROM salaries\" [==id]\n" --- from s"SELECT DISTINCT ON first_name, id, age FROM employees ORDER BY age ASC" join s = s"SELECT * FROM salaries" [==id] diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-4.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-4.prql.snap similarity index 51% rename from book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-4.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-4.prql.snap index d7482d2f4cfb..00c1d5e17349 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-4.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-4.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/s-strings-4.prql +expression: "from employees\nderive [\n has_valid_title = s\"regexp_contains(title, '([a-z0-9]*-){{2,}}')\"\n]\n" --- from employees derive [has_valid_title = s"regexp_contains(title, '([a-z0-9]*-){2,}')"] diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-5.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-5.prql.snap similarity index 53% rename from book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-5.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-5.prql.snap index 4313e1e554a7..9bd3b0d3fe16 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-5.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-5.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/s-strings-5.prql +expression: "from employees\nderive [\n gross_salary = salary + benefits,\n daily_rate = s\"{gross_salary} / 365\"\n]\n" --- from employees derive [ diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-6.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-6.prql.snap similarity index 53% rename from book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-6.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-6.prql.snap index 8ac94b9d968f..3dc30b6885ae 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-6.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-6.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/s-strings-6.prql +expression: "from employees\nderive [\n gross_salary = salary + benefits,\n daily_rate = s\"({gross_salary}) / 365\"\n]\n" --- from employees derive [ diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__standard-library-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__standard-library-0.prql.snap new file mode 100644 index 000000000000..011d5f416c47 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__standard-library-0.prql.snap @@ -0,0 +1,19 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nderive [\n gross_salary = (salary + payroll_tax | as int),\n gross_salary_rounded = (gross_salary | round 0),\n time = s\"NOW()\", # an s-string, given no `now` function exists in PRQL\n]\n" +--- +from employees +derive [ + gross_salary = ( + salary + payroll_tax + as int +), + gross_salary_rounded = ( + gross_salary + round 0 +), + time = s"NOW()", +] + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__strings-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__strings-0.prql.snap new file mode 100644 index 000000000000..6a1d79036036 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__strings-0.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from my_table\nselect x = \"hello world\"\n" +--- +from my_table +select x = "hello world" + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__strings-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__strings-1.prql.snap new file mode 100644 index 000000000000..2da7a07937de --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__strings-1.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from my_table\nselect x = 'hello world'\n" +--- +from my_table +select x = "hello world" + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__strings-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__strings-2.prql.snap new file mode 100644 index 000000000000..8d79cd8cedbc --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__strings-2.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from my_table\nselect x = '\"hello world\"'\n" +--- +from my_table +select x = '"hello world"' + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__strings-3.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__strings-3.prql.snap new file mode 100644 index 000000000000..a681bc62a036 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__strings-3.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from my_table\nselect x = \"\"\"I said \"hello world\"!\"\"\"\n" +--- +from my_table +select x = 'I said "hello world"!' + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__strings-4.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__strings-4.prql.snap new file mode 100644 index 000000000000..0bae3f836774 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__strings-4.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from my_table\nselect x = \"\"\"\"\"I said \"\"\"hello world\"\"\"!\"\"\"\"\"\n" +--- +from my_table +select x = 'I said """hello world"""!' + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__switch-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__switch-0.prql.snap similarity index 53% rename from book/tests/snapshots/snapshot__run_display_reference_prql@language-features__switch-0.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__language-features__switch-0.prql.snap index 85bb6bac32b8..7618b9e71723 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__switch-0.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__switch-0.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/switch-0.prql +expression: "from employees\nderive distance = switch [\n city == \"Calgary\" -> 0,\n city == \"Edmonton\" -> 300,\n]\n" --- from employees derive distance = switch [ diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__switch-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__switch-1.prql.snap similarity index 51% rename from book/tests/snapshots/snapshot__run_display_reference_prql@language-features__switch-1.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__language-features__switch-1.prql.snap index dd4c64e0b6b0..f9ee3312b92b 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__switch-1.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__switch-1.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/switch-1.prql +expression: "from employees\nderive distance = switch [\n city == \"Calgary\" -> 0,\n city == \"Edmonton\" -> 300,\n true -> \"Unknown\",\n]\n" --- from employees derive distance = switch [ diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__target-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__target-0.prql.snap new file mode 100644 index 000000000000..b22539422ae4 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__target-0.prql.snap @@ -0,0 +1,14 @@ +--- +source: book/tests/snapshot.rs +expression: "prql target:sql.postgres\n\nfrom employees\nsort age\ntake 10\n" +--- +prql target:sql.postgres + + + +from employees +sort age +take 10 + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__target-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__target-1.prql.snap new file mode 100644 index 000000000000..ed7e10fd7388 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__target-1.prql.snap @@ -0,0 +1,14 @@ +--- +source: book/tests/snapshot.rs +expression: "prql target:sql.mssql\n\nfrom employees\nsort age\ntake 10\n" +--- +prql target:sql.mssql + + + +from employees +sort age +take 10 + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__target-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__target-2.prql.snap new file mode 100644 index 000000000000..b05787ed8bae --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__target-2.prql.snap @@ -0,0 +1,12 @@ +--- +source: book/tests/snapshot.rs +expression: "prql version:\"0.5\"\n\nfrom employees\n" +--- +prql version:^0.5 + + + +from employees + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@queries__functions-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__queries__functions-0.prql.snap similarity index 54% rename from book/tests/snapshots/snapshot__run_display_reference_prql@queries__functions-0.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__queries__functions-0.prql.snap index bde459b05cf8..e5bb0a64491b 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@queries__functions-0.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__queries__functions-0.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/queries/functions-0.prql +expression: "func fahrenheit_to_celsius temp -> (temp - 32) / 1.8\n\nfrom cities\nderive temp_c = (fahrenheit_to_celsius temp_f)\n" --- func fahrenheit_to_celsius temp -> temp - 32 / 1.8 diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@queries__functions-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__queries__functions-1.prql.snap similarity index 51% rename from book/tests/snapshots/snapshot__run_display_reference_prql@queries__functions-1.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__queries__functions-1.prql.snap index d8d3e0185fd9..ef971e8402bc 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@queries__functions-1.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__queries__functions-1.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/queries/functions-1.prql +expression: "func interp lower:0 higher x -> (x - lower) / (higher - lower)\n\nfrom students\nderive [\n sat_proportion_1 = (interp 1600 sat_score),\n sat_proportion_2 = (interp lower:0 1600 sat_score),\n]\n" --- func interp higher x lower:0 -> x - lower / higher - lower diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@queries__functions-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__queries__functions-2.prql.snap similarity index 52% rename from book/tests/snapshots/snapshot__run_display_reference_prql@queries__functions-2.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__queries__functions-2.prql.snap index 49560fe48496..2e8f243ea009 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@queries__functions-2.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__queries__functions-2.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/queries/functions-2.prql +expression: "func interp lower:0 higher x -> (x - lower) / (higher - lower)\n\nfrom students\nderive [\n sat_proportion_1 = (sat_score | interp 1600),\n sat_proportion_2 = (sat_score | interp lower:0 1600),\n]\n" --- func interp higher x lower:0 -> x - lower / higher - lower diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@queries__functions-3.prql.snap b/book/tests/snapshots/snapshot__tests__prql__queries__functions-3.prql.snap similarity index 54% rename from book/tests/snapshots/snapshot__run_display_reference_prql@queries__functions-3.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__queries__functions-3.prql.snap index 83e91977fe3f..bc1453813dc9 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@queries__functions-3.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__queries__functions-3.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/queries/functions-3.prql +expression: "func fahrenheit_to_celsius temp -> (temp - 32) / 1.8\n\nfrom cities\nderive temp_c = (temp_f | fahrenheit_to_celsius)\n" --- func fahrenheit_to_celsius temp -> temp - 32 / 1.8 diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@queries__functions-4.prql.snap b/book/tests/snapshots/snapshot__tests__prql__queries__functions-4.prql.snap similarity index 52% rename from book/tests/snapshots/snapshot__run_display_reference_prql@queries__functions-4.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__queries__functions-4.prql.snap index 8ed62cca5158..3deae6fcab9c 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@queries__functions-4.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__queries__functions-4.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/queries/functions-4.prql +expression: "func fahrenheit_to_celsius temp -> (temp - 32) / 1.8\nfunc interp lower:0 higher x -> (x - lower) / (higher - lower)\n\nfrom kettles\nderive boiling_proportion = (temp_c | fahrenheit_to_celsius | interp 100)\n" --- func fahrenheit_to_celsius temp -> temp - 32 / 1.8 diff --git a/book/tests/snapshots/snapshot__tests__prql__queries__pipelines-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__queries__pipelines-0.prql.snap new file mode 100644 index 000000000000..8ef6dce0bb66 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__queries__pipelines-0.prql.snap @@ -0,0 +1,8 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\n" +--- +from employees + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__queries__pipelines-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__queries__pipelines-1.prql.snap new file mode 100644 index 000000000000..b2b18409f03a --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__queries__pipelines-1.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nderive gross_salary = (salary + payroll_tax)\n" +--- +from employees +derive gross_salary = salary + payroll_tax + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@queries__pipelines-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__queries__pipelines-2.prql.snap similarity index 53% rename from book/tests/snapshots/snapshot__run_display_reference_prql@queries__pipelines-2.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__queries__pipelines-2.prql.snap index e3ff662251a8..5c74bd2eeb81 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@queries__pipelines-2.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__queries__pipelines-2.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/queries/pipelines-2.prql +expression: "from e = employees\nderive gross_salary = (salary + payroll_tax)\nsort gross_salary\ntake 10\njoin d = department [==dept_no]\nselect [e.name, gross_salary, d.name]\n" --- from e = employees derive gross_salary = salary + payroll_tax diff --git a/book/tests/snapshots/snapshot__tests__prql__queries__variables-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__queries__variables-0.prql.snap new file mode 100644 index 000000000000..3c4edace1010 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__queries__variables-0.prql.snap @@ -0,0 +1,17 @@ +--- +source: book/tests/snapshot.rs +expression: "let top_50 = (\n from employees\n sort salary\n take 50\n aggregate [total_salary = sum salary]\n)\n\nfrom top_50 # Starts a new pipeline\n" +--- +let top_50 = ( + from employees + sort salary + take 50 + aggregate [total_salary = sum salary] +) + + + +from top_50 + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@queries__variables-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__queries__variables-1.prql.snap similarity index 51% rename from book/tests/snapshots/snapshot__run_display_reference_prql@queries__variables-1.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__queries__variables-1.prql.snap index f7a3cbcd9431..dd72ddc9b4bb 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@queries__variables-1.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__queries__variables-1.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/queries/variables-1.prql +expression: "let grouping = s\"\"\"\n SELECT SUM(a)\n FROM tbl\n GROUP BY\n GROUPING SETS\n ((b, c, d), (d), (b, d))\n\"\"\"\n\nfrom grouping\n" --- let grouping = s" SELECT SUM(a) diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-0.prql.snap similarity index 55% rename from book/tests/snapshots/snapshot__run_display_reference_prql@syntax-0.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__syntax-0.prql.snap index 16788f8c5410..ee78d7a29c00 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-0.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__syntax-0.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/syntax-0.prql +expression: "from employees\nfilter department == \"Product\"\nselect [first_name, last_name]\n" --- from employees filter department == "Product" diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-1.prql.snap similarity index 55% rename from book/tests/snapshots/snapshot__run_display_reference_prql@syntax-1.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__syntax-1.prql.snap index 7d3684118966..ae9d7fcbb81c 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-1.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__syntax-1.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/syntax-1.prql +expression: "from employees | filter department == \"Product\" | select [first_name, last_name]\n" --- from employees filter department == "Product" diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-10.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-10.prql.snap similarity index 50% rename from book/tests/snapshots/snapshot__run_display_reference_prql@syntax-10.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__syntax-10.prql.snap index e12239744931..0ef6f6c5ea4e 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-10.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__syntax-10.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/syntax-10.prql +expression: "prql target:sql.postgres\nfrom employees\nselect `first name`\n" --- prql target:sql.postgres diff --git a/book/tests/snapshots/snapshot__tests__prql__syntax-11.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-11.prql.snap new file mode 100644 index 000000000000..acd1651bdbb9 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__syntax-11.prql.snap @@ -0,0 +1,8 @@ +--- +source: book/tests/snapshot.rs +expression: "from `dir/*.parquet`\n" +--- +from `dir/*.parquet` + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-12.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-12.prql.snap similarity index 55% rename from book/tests/snapshots/snapshot__run_display_reference_prql@syntax-12.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__syntax-12.prql.snap index 79ec4c9aa74d..6be462d1cb08 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-12.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__syntax-12.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/syntax-12.prql +expression: "prql target:sql.bigquery\nfrom `project-foo.dataset.table`\njoin `project-bar.dataset.table` [==col_bax]\n" --- prql target:sql.bigquery diff --git a/book/tests/snapshots/snapshot__tests__prql__syntax-13.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-13.prql.snap new file mode 100644 index 000000000000..fc9310bcceea --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__syntax-13.prql.snap @@ -0,0 +1,8 @@ +--- +source: book/tests/snapshot.rs +expression: "from `music.albums`\n" +--- +from `music.albums` + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__syntax-14.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-14.prql.snap new file mode 100644 index 000000000000..429e57d0faf3 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__syntax-14.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nfilter id == $1\n" +--- +from employees +filter id == $1 + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-15.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-15.prql.snap similarity index 50% rename from book/tests/snapshots/snapshot__run_display_reference_prql@syntax-15.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__syntax-15.prql.snap index 34d44267ba17..7aa2caf4c217 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-15.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__syntax-15.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/syntax-15.prql +expression: "from numbers\nselect [\n small = 1.000_000_1,\n big = 5_000_000,\n]\n" --- from numbers select [ diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-2.prql.snap similarity index 54% rename from book/tests/snapshots/snapshot__run_display_reference_prql@syntax-2.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__syntax-2.prql.snap index 8c5b5825e8c4..a12652162d23 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-2.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__syntax-2.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/syntax-2.prql +expression: "from numbers\nderive [x = 1, y = 2]\nderive [\n a = x,\n b = y\n]\nderive [\n c = a,\n d = b,\n]\n" --- from numbers derive [ diff --git a/book/tests/snapshots/snapshot__tests__prql__syntax-3.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-3.prql.snap new file mode 100644 index 000000000000..4077d71aaa9b --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__syntax-3.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nselect [first_name]\n" +--- +from employees +select [first_name] + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__syntax-4.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-4.prql.snap new file mode 100644 index 000000000000..56e49df27e11 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__syntax-4.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nselect first_name\n" +--- +from employees +select first_name + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-5.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-5.prql.snap similarity index 53% rename from book/tests/snapshots/snapshot__run_display_reference_prql@syntax-5.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__syntax-5.prql.snap index f3ebf960c4bf..027e1a5e000f 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-5.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__syntax-5.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/syntax-5.prql +expression: "from foo\nselect [\n circumference = diameter * 3.14159,\n color,\n]\nfilter circumference > 10 and color != \"red\"\n" --- from foo select [ diff --git a/book/tests/snapshots/snapshot__tests__prql__syntax-6.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-6.prql.snap new file mode 100644 index 000000000000..b9f326d968cc --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__syntax-6.prql.snap @@ -0,0 +1,39 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\n# Requires parentheses, because it's contains a pipe\nderive is_proximate = (distance | in 0..20)\n# Requires parentheses, because it's a function call\nderive total_distance = (sum distance)\n# `??` doesn't require parentheses, as it's not a function call\nderive min_capped_distance = (min distance ?? 5)\n# No parentheses needed, because no function call\nderive travel_time = distance / 40\n# No inner parentheses needed around `1+1` because no function call\nderive distance_rounded_2_dp = (round 1+1 distance)\nderive [\n # Requires parentheses, because it contains a pipe\n is_far = (distance | in 100..),\n # The left value of the range requires parentheses,\n # because of the minus sign\n is_negative = (distance | in (-100..0)),\n # ...this is equivalent\n is_negative = (distance | in (-100)..0),\n # Doesn't require parentheses, because it's in a list (confusing, see footnote)!\n average_distance = average distance,\n]\n# Requires parentheses because of the minus sign\nsort (-distance)\n# A list is fine too\nsort [-distance]\n" +--- +from employees +derive is_proximate = ( + distance + in 0..20 +) +derive ( + total_distance = sum distance +) +derive ( + min_capped_distance = min distance ?? 5 +) +derive travel_time = distance / 40 +derive ( + distance_rounded_2_dp = round 1 + 1 distance +) +derive [ + is_far = ( + distance + in 100.. +), + is_negative = ( + distance + in -100..0 +), + is_negative = ( + distance + in -100..0 +), + average_distance = average distance, +] +sort -distance +sort [-distance] + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-7.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-7.prql.snap similarity index 54% rename from book/tests/snapshots/snapshot__run_display_reference_prql@syntax-7.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__syntax-7.prql.snap index 29e0c6d26c1e..81e0a3146955 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-7.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__syntax-7.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/syntax-7.prql +expression: "from employees\ngroup [title, country] (\n aggregate [\n average salary,\n ct = count\n ]\n)\n" --- from employees group [ diff --git a/book/tests/snapshots/snapshot__tests__prql__syntax-8.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-8.prql.snap new file mode 100644 index 000000000000..4f94033b1f86 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__syntax-8.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees # Comment 1\n# Comment 2\naggregate [average salary]\n" +--- +from employees +aggregate [average salary] + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-9.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-9.prql.snap similarity index 50% rename from book/tests/snapshots/snapshot__run_display_reference_prql@syntax-9.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__syntax-9.prql.snap index 9e5a61c3e446..19c4de64822f 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-9.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__syntax-9.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/syntax-9.prql +expression: "prql target:sql.mysql\nfrom employees\nselect `first name`\n" --- prql target:sql.mysql diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__aggregate-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__aggregate-0.prql.snap new file mode 100644 index 000000000000..1c202ec4ba25 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__aggregate-0.prql.snap @@ -0,0 +1,12 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\naggregate [\n average salary,\n ct = count\n]\n" +--- +from employees +aggregate [ + average salary, + ct = count, +] + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__aggregate-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__aggregate-1.prql.snap similarity index 54% rename from book/tests/snapshots/snapshot__run_display_reference_prql@transforms__aggregate-1.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__transforms__aggregate-1.prql.snap index bbf253ec6dd5..81e0a3146955 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__aggregate-1.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__aggregate-1.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/aggregate-1.prql +expression: "from employees\ngroup [title, country] (\n aggregate [\n average salary,\n ct = count\n ]\n)\n" --- from employees group [ diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__aggregate-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__aggregate-2.prql.snap new file mode 100644 index 000000000000..9b49b51df2a5 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__aggregate-2.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nderive [avg_sal = average salary]\n" +--- +from employees +derive [avg_sal = average salary] + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__append-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__append-0.prql.snap new file mode 100644 index 000000000000..cbbd0478001b --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__append-0.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees_1\nappend employees_2\n" +--- +from employees_1 +append employees_2 + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__append-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__append-1.prql.snap new file mode 100644 index 000000000000..e2b9a1338479 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__append-1.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees_1\nremove employees_2\n" +--- +from employees_1 +remove employees_2 + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__append-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__append-2.prql.snap new file mode 100644 index 000000000000..1971d287b890 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__append-2.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees_1\nintersect employees_2\n" +--- +from employees_1 +intersect employees_2 + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__derive-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__derive-0.prql.snap new file mode 100644 index 000000000000..183b59f98112 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__derive-0.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nderive gross_salary = salary + payroll_tax\n" +--- +from employees +derive gross_salary = salary + payroll_tax + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__derive-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__derive-1.prql.snap similarity index 54% rename from book/tests/snapshots/snapshot__run_display_reference_prql@transforms__derive-1.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__transforms__derive-1.prql.snap index f2b9dd7bd20d..3d298b6f9b55 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__derive-1.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__derive-1.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/derive-1.prql +expression: "from employees\nderive [\n gross_salary = salary + payroll_tax,\n gross_cost = gross_salary + benefits_cost\n]\n" --- from employees derive [ diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__filter-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__filter-0.prql.snap new file mode 100644 index 000000000000..bd5e2c425e25 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__filter-0.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nfilter age > 25\n" +--- +from employees +filter age > 25 + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__filter-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__filter-1.prql.snap new file mode 100644 index 000000000000..a6cb5b5b569e --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__filter-1.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nfilter (age > 25 or department != \"IT\")\n" +--- +from employees +filter age > 25 or department != "IT" + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__filter-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__filter-2.prql.snap new file mode 100644 index 000000000000..d3b04cd4de31 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__filter-2.prql.snap @@ -0,0 +1,12 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nfilter (age | in 25..40)\n" +--- +from employees +filter ( + age + in 25..40 +) + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__from-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__from-0.prql.snap new file mode 100644 index 000000000000..8ef6dce0bb66 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__from-0.prql.snap @@ -0,0 +1,8 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\n" +--- +from employees + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__from-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__from-1.prql.snap new file mode 100644 index 000000000000..ef1312a86941 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__from-1.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from e = employees\nselect e.first_name\n" +--- +from e = employees +select e.first_name + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from_text-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__from_text-0.prql.snap similarity index 50% rename from book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from_text-0.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__transforms__from_text-0.prql.snap index d86f2e1e86bb..6a730d3a1f7e 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from_text-0.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__from_text-0.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/from_text-0.prql +expression: "from_text \"\"\"\na,b,c\n1,2,3\n4,5,6\n\"\"\"\nderive [\n d = b + c,\n answer = 20 * 2 + 2,\n]\n" --- from_text " a,b,c diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from_text-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__from_text-1.prql.snap similarity index 51% rename from book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from_text-1.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__transforms__from_text-1.prql.snap index 740349748e00..6f9f848bbd6e 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from_text-1.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__from_text-1.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/from_text-1.prql +expression: "let temp_format_lookup = from_text format:csv \"\"\"\ncountry_code,format\nuk,C\nus,F\nlr,F\nde,C\n\"\"\"\n\nfrom temperatures\njoin temp_format_lookup [==country_code]\n" --- let temp_format_lookup = ( from_text format:csv " diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__from_text-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__from_text-2.prql.snap new file mode 100644 index 000000000000..da17c3b1fe6f --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__from_text-2.prql.snap @@ -0,0 +1,32 @@ +--- +source: book/tests/snapshot.rs +expression: "let x = from_text format:json \"\"\"{\n \"columns\": [\"a\", \"b\", \"c\"],\n \"data\": [\n [1, \"x\", false],\n [4, \"y\", null]\n ]\n}\"\"\"\n\nlet y = from_text format:json \"\"\"\n [\n {\"a\": 1, \"m\": \"5\"},\n {\"a\": 4, \"n\": \"6\"}\n ]\n\"\"\"\n\nfrom x | join y [==a]\n" +--- +let x = ( + from_text format:json '{ + "columns": ["a", "b", "c"], + "data": [ + [1, "x", false], + [4, "y", null] + ] +}' +) + + + +let y = ( + from_text format:json ' + [ + {"a": 1, "m": "5"}, + {"a": 4, "n": "6"} + ] +' +) + + + +from x +join y [==a] + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__group-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__group-0.prql.snap similarity index 54% rename from book/tests/snapshots/snapshot__run_display_reference_prql@transforms__group-0.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__transforms__group-0.prql.snap index 754f23c1d76e..81e0a3146955 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__group-0.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__group-0.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/group-0.prql +expression: "from employees\ngroup [title, country] (\n aggregate [\n average salary,\n ct = count\n ]\n)\n" --- from employees group [ diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__group-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__group-1.prql.snap new file mode 100644 index 000000000000..2517396a1418 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__group-1.prql.snap @@ -0,0 +1,10 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nsort join_date\ntake 1\n" +--- +from employees +sort join_date +take 1 + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__group-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__group-2.prql.snap new file mode 100644 index 000000000000..11467687bbbb --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__group-2.prql.snap @@ -0,0 +1,12 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\ngroup role (\n sort join_date # taken from above\n take 1\n)\n" +--- +from employees +group role ( + sort join_date + take 1 +) + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__join-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__join-0.prql.snap similarity index 52% rename from book/tests/snapshots/snapshot__run_display_reference_prql@transforms__join-0.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__transforms__join-0.prql.snap index 0334411b6614..4d113382409a 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__join-0.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__join-0.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/join-0.prql +expression: "from employees\njoin side:left positions [employees.id==positions.employee_id]\n" --- from employees join side:left positions [employees.id == positions.employee_id] diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__join-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__join-1.prql.snap similarity index 51% rename from book/tests/snapshots/snapshot__run_display_reference_prql@transforms__join-1.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__transforms__join-1.prql.snap index 073e5b79b5ee..b3e13a1d23f8 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__join-1.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__join-1.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/join-1.prql +expression: "from employees\njoin side:left p=positions [employees.id==p.employee_id]\n" --- from employees join side:left p = positions [employees.id == p.employee_id] diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__join-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__join-2.prql.snap new file mode 100644 index 000000000000..ba833fa01b02 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__join-2.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\njoin positions [==emp_no]\n" +--- +from employees +join positions [==emp_no] + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__select-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__select-0.prql.snap new file mode 100644 index 000000000000..ef3e65965333 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__select-0.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nselect name = f\"{first_name} {last_name}\"\n" +--- +from employees +select name = f"{first_name} {last_name}" + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__select-1.prql.snap similarity index 53% rename from book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-1.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__transforms__select-1.prql.snap index 1ecfbb0be8f6..57c345371217 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-1.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__select-1.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/select-1.prql +expression: "from employees\nselect [\n name = f\"{first_name} {last_name}\",\n age_eoy = dob - @2022-12-31,\n]\n" --- from employees select [ diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__select-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__select-2.prql.snap new file mode 100644 index 000000000000..56e49df27e11 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__select-2.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nselect first_name\n" +--- +from employees +select first_name + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__select-3.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__select-3.prql.snap new file mode 100644 index 000000000000..059b92276754 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__select-3.prql.snap @@ -0,0 +1,12 @@ +--- +source: book/tests/snapshot.rs +expression: "from e=employees\nselect [e.first_name, e.last_name]\n" +--- +from e = employees +select [ + e.first_name, + e.last_name, +] + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-4.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__select-4.prql.snap similarity index 51% rename from book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-4.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__transforms__select-4.prql.snap index c8837e7a5780..6445588450d2 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-4.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__select-4.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/select-4.prql +expression: "prql target:sql.bigquery\nfrom tracks\nselect ![milliseconds,bytes]\n" --- prql target:sql.bigquery diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-5.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__select-5.prql.snap similarity index 55% rename from book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-5.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__transforms__select-5.prql.snap index ee470cf35cf6..568bc821ba4f 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-5.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__select-5.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/select-5.prql +expression: "from tracks\nselect [track_id, title, composer, bytes]\nselect ![title, composer]\n" --- from tracks select [ diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__select-6.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__select-6.prql.snap new file mode 100644 index 000000000000..19b65db61c48 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__select-6.prql.snap @@ -0,0 +1,10 @@ +--- +source: book/tests/snapshot.rs +expression: "from artists\nderive nick = name\nselect ![artists.*]\n" +--- +from artists +derive nick = name +select not [artists.`*`] + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__sort-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__sort-0.prql.snap new file mode 100644 index 000000000000..cb41ef4b5ddb --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__sort-0.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nsort age\n" +--- +from employees +sort age + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__sort-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__sort-1.prql.snap new file mode 100644 index 000000000000..12203dcc78d3 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__sort-1.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nsort [-age]\n" +--- +from employees +sort [-age] + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__sort-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__sort-2.prql.snap new file mode 100644 index 000000000000..23c2050900c8 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__sort-2.prql.snap @@ -0,0 +1,13 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nsort [age, -tenure, +salary]\n" +--- +from employees +sort [ + age, + -tenure, + salary, +] + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__sort-3.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__sort-3.prql.snap new file mode 100644 index 000000000000..01b0d75eb4e3 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__sort-3.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nsort [s\"substr({first_name}, 2, 5)\"]\n" +--- +from employees +sort [s"substr({first_name}, 2, 5)"] + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-4.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__sort-4.prql.snap similarity index 50% rename from book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-4.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__transforms__sort-4.prql.snap index 01b5c740c41a..51c71b587af5 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-4.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__sort-4.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/sort-4.prql +expression: "from employees\nsort tenure\nderive name = f\"{first_name} {last_name}\"\n" --- from employees sort tenure diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__sort-5.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__sort-5.prql.snap new file mode 100644 index 000000000000..405c461df7e4 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__sort-5.prql.snap @@ -0,0 +1,10 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nsort tenure\njoin locations [==employee_id]\n" +--- +from employees +sort tenure +join locations [==employee_id] + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__take-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__take-0.prql.snap new file mode 100644 index 000000000000..4c39e0cddcea --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__take-0.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\ntake 10\n" +--- +from employees +take 10 + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__take-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__take-1.prql.snap new file mode 100644 index 000000000000..b68c1920a669 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__take-1.prql.snap @@ -0,0 +1,13 @@ +--- +source: book/tests/snapshot.rs +expression: "from orders\nsort [-value, date]\ntake 101..110\n" +--- +from orders +sort [ + -value, + date, +] +take 101..110 + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__window-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__window-0.prql.snap similarity index 52% rename from book/tests/snapshots/snapshot__run_display_reference_prql@transforms__window-0.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__transforms__window-0.prql.snap index 2366506585b0..08d6e23e2468 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__window-0.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__window-0.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/window-0.prql +expression: "from employees\ngroup employee_id (\n sort month\n window rolling:12 (\n derive [trail_12_m_comp = sum paycheck]\n )\n)\n" --- from employees group employee_id ( diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__window-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__window-1.prql.snap similarity index 51% rename from book/tests/snapshots/snapshot__run_display_reference_prql@transforms__window-1.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__transforms__window-1.prql.snap index afffeb8eb185..c0663a94bc4a 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__window-1.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__window-1.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/window-1.prql +expression: "from orders\nsort day\nwindow rows:-3..3 (\n derive [centered_weekly_average = average value]\n)\ngroup [order_month] (\n sort day\n window expanding:true (\n derive [monthly_running_total = sum value]\n )\n)\n" --- from orders sort day diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__window-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__window-2.prql.snap new file mode 100644 index 000000000000..dc3037c993b3 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__window-2.prql.snap @@ -0,0 +1,10 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nsort age\nderive rnk = rank\n" +--- +from employees +sort age +derive rnk = rank + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__window-3.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__window-3.prql.snap new file mode 100644 index 000000000000..b71455102a11 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__window-3.prql.snap @@ -0,0 +1,12 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\ngroup department (\n sort age\n derive rnk = rank\n)\n" +--- +from employees +group department ( + sort age + derive rnk = rank +) + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__window-4.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__window-4.prql.snap new file mode 100644 index 000000000000..9e104fbe34a9 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__window-4.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nfilter salary < (average salary)\n" +--- +from employees +filter salary < ( average salary ) + + + From 4c3fb3e43806c05728140bb099438719aa91fb6b Mon Sep 17 00:00:00 2001 From: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Date: Sun, 19 Feb 2023 18:05:26 -0800 Subject: [PATCH 011/106] revert: test: Refactor book snapshot tests (#1903) Revert "test: Refactor book snapshot tests (#1900)" This reverts commit abc61ff3fd18e6deff9159b9726071705d3a4f29. --- book/tests/snapshot.rs | 172 ++++++++---------- ..._reference_prql@examples__cte-0.prql.snap} | 3 +- ...ence_prql@examples__employees-0.prql.snap} | 3 +- ...ence_prql@examples__employees-1.prql.snap} | 3 +- ...ence_prql@examples__employees-2.prql.snap} | 3 +- ...ence_prql@examples__employees-3.prql.snap} | 3 +- ...rql@examples__list-equivalence-0.prql.snap | 10 + ...rql@examples__list-equivalence-1.prql.snap | 10 + ...ql@examples__list-equivalence-2.prql.snap} | 3 +- ...ql@examples__list-equivalence-3.prql.snap} | 3 +- ..._reference_prql@examples__misc-0.prql.snap | 26 +++ ..._reference_prql@examples__misc-1.prql.snap | 13 ++ ...rence_prql@examples__variables-0.prql.snap | 32 ++++ ...rence_prql@examples__variables-1.prql.snap | 19 ++ ...rql@internals__functional-lang-0.prql.snap | 11 ++ ...rql@internals__functional-lang-1.prql.snap | 11 ++ ...rql@internals__functional-lang-2.prql.snap | 12 ++ ...rql@internals__functional-lang-3.prql.snap | 13 ++ ...prql@internals__name-resolving-0.prql.snap | 10 + ...rql@internals__name-resolving-1.prql.snap} | 3 +- ...ay_reference_prql@introduction-0.prql.snap | 32 ++++ ...ql@language-features__coalesce-0.prql.snap | 10 + ...uage-features__dates-and-times-0.prql.snap | 10 + ...uage-features__dates-and-times-1.prql.snap | 10 + ...uage-features__dates-and-times-2.prql.snap | 10 + ...uage-features__dates-and-times-3.prql.snap | 10 + ...ql@language-features__distinct-0.prql.snap | 13 ++ ...ql@language-features__distinct-1.prql.snap | 13 ++ ...ql@language-features__distinct-2.prql.snap | 13 ++ ...l@language-features__f-strings-0.prql.snap | 10 + ...l@language-features__f-strings-1.prql.snap | 10 + ...e_prql@language-features__null-0.prql.snap | 11 ++ ...rql@language-features__ranges-0.prql.snap} | 3 +- ...prql@language-features__ranges-1.prql.snap | 14 ++ ...l@language-features__s-strings-0.prql.snap | 10 + ...l@language-features__s-strings-1.prql.snap | 10 + ...@language-features__s-strings-2.prql.snap} | 3 +- ...@language-features__s-strings-3.prql.snap} | 3 +- ...@language-features__s-strings-4.prql.snap} | 3 +- ...@language-features__s-strings-5.prql.snap} | 3 +- ...@language-features__s-strings-6.prql.snap} | 3 +- ...age-features__standard-library-0.prql.snap | 20 ++ ...rql@language-features__strings-0.prql.snap | 10 + ...rql@language-features__strings-1.prql.snap | 10 + ...rql@language-features__strings-2.prql.snap | 10 + ...rql@language-features__strings-3.prql.snap | 10 + ...rql@language-features__strings-4.prql.snap | 10 + ...rql@language-features__switch-0.prql.snap} | 3 +- ...rql@language-features__switch-1.prql.snap} | 3 +- ...prql@language-features__target-0.prql.snap | 15 ++ ...prql@language-features__target-1.prql.snap | 15 ++ ...prql@language-features__target-2.prql.snap | 13 ++ ...rence_prql@queries__functions-0.prql.snap} | 3 +- ...rence_prql@queries__functions-1.prql.snap} | 3 +- ...rence_prql@queries__functions-2.prql.snap} | 3 +- ...rence_prql@queries__functions-3.prql.snap} | 3 +- ...rence_prql@queries__functions-4.prql.snap} | 3 +- ...erence_prql@queries__pipelines-0.prql.snap | 9 + ...erence_prql@queries__pipelines-1.prql.snap | 10 + ...rence_prql@queries__pipelines-2.prql.snap} | 3 +- ...erence_prql@queries__variables-0.prql.snap | 18 ++ ...rence_prql@queries__variables-1.prql.snap} | 3 +- ...display_reference_prql@syntax-0.prql.snap} | 3 +- ...display_reference_prql@syntax-1.prql.snap} | 3 +- ...isplay_reference_prql@syntax-10.prql.snap} | 3 +- ...display_reference_prql@syntax-11.prql.snap | 9 + ...isplay_reference_prql@syntax-12.prql.snap} | 3 +- ...display_reference_prql@syntax-13.prql.snap | 9 + ...display_reference_prql@syntax-14.prql.snap | 10 + ...isplay_reference_prql@syntax-15.prql.snap} | 3 +- ...display_reference_prql@syntax-2.prql.snap} | 3 +- ..._display_reference_prql@syntax-3.prql.snap | 10 + ..._display_reference_prql@syntax-4.prql.snap | 10 + ...display_reference_prql@syntax-5.prql.snap} | 3 +- ..._display_reference_prql@syntax-6.prql.snap | 40 ++++ ...display_reference_prql@syntax-7.prql.snap} | 3 +- ..._display_reference_prql@syntax-8.prql.snap | 10 + ...display_reference_prql@syntax-9.prql.snap} | 3 +- ...nce_prql@transforms__aggregate-0.prql.snap | 13 ++ ...ce_prql@transforms__aggregate-1.prql.snap} | 3 +- ...nce_prql@transforms__aggregate-2.prql.snap | 10 + ...erence_prql@transforms__append-0.prql.snap | 10 + ...erence_prql@transforms__append-1.prql.snap | 10 + ...erence_prql@transforms__append-2.prql.snap | 10 + ...erence_prql@transforms__derive-0.prql.snap | 10 + ...rence_prql@transforms__derive-1.prql.snap} | 3 +- ...erence_prql@transforms__filter-0.prql.snap | 10 + ...erence_prql@transforms__filter-1.prql.snap | 10 + ...erence_prql@transforms__filter-2.prql.snap | 13 ++ ...eference_prql@transforms__from-0.prql.snap | 9 + ...eference_prql@transforms__from-1.prql.snap | 10 + ...ce_prql@transforms__from_text-0.prql.snap} | 3 +- ...ce_prql@transforms__from_text-1.prql.snap} | 3 +- ...nce_prql@transforms__from_text-2.prql.snap | 33 ++++ ...erence_prql@transforms__group-0.prql.snap} | 3 +- ...ference_prql@transforms__group-1.prql.snap | 11 ++ ...ference_prql@transforms__group-2.prql.snap | 13 ++ ...ference_prql@transforms__join-0.prql.snap} | 3 +- ...ference_prql@transforms__join-1.prql.snap} | 3 +- ...eference_prql@transforms__join-2.prql.snap | 10 + ...erence_prql@transforms__select-0.prql.snap | 10 + ...rence_prql@transforms__select-1.prql.snap} | 3 +- ...erence_prql@transforms__select-2.prql.snap | 10 + ...erence_prql@transforms__select-3.prql.snap | 13 ++ ...rence_prql@transforms__select-4.prql.snap} | 3 +- ...rence_prql@transforms__select-5.prql.snap} | 3 +- ...erence_prql@transforms__select-6.prql.snap | 11 ++ ...eference_prql@transforms__sort-0.prql.snap | 10 + ...eference_prql@transforms__sort-1.prql.snap | 10 + ...eference_prql@transforms__sort-2.prql.snap | 14 ++ ...eference_prql@transforms__sort-3.prql.snap | 10 + ...ference_prql@transforms__sort-4.prql.snap} | 3 +- ...eference_prql@transforms__sort-5.prql.snap | 11 ++ ...eference_prql@transforms__take-0.prql.snap | 10 + ...eference_prql@transforms__take-1.prql.snap | 14 ++ ...rence_prql@transforms__window-0.prql.snap} | 3 +- ...rence_prql@transforms__window-1.prql.snap} | 3 +- ...erence_prql@transforms__window-2.prql.snap | 11 ++ ...erence_prql@transforms__window-3.prql.snap | 13 ++ ...erence_prql@transforms__window-4.prql.snap | 10 + ...ql__examples__list-equivalence-0.prql.snap | 9 - ...ql__examples__list-equivalence-1.prql.snap | 9 - ...t__tests__prql__examples__misc-0.prql.snap | 25 --- ...t__tests__prql__examples__misc-1.prql.snap | 12 -- ...sts__prql__examples__variables-0.prql.snap | 31 ---- ...sts__prql__examples__variables-1.prql.snap | 18 -- ...ql__internals__functional-lang-0.prql.snap | 10 - ...ql__internals__functional-lang-1.prql.snap | 10 - ...ql__internals__functional-lang-2.prql.snap | 11 -- ...ql__internals__functional-lang-3.prql.snap | 12 -- ...rql__internals__name-resolving-0.prql.snap | 9 - ...hot__tests__prql__introduction-0.prql.snap | 31 ---- ...l__language-features__coalesce-0.prql.snap | 9 - ...uage-features__dates-and-times-0.prql.snap | 9 - ...uage-features__dates-and-times-1.prql.snap | 9 - ...uage-features__dates-and-times-2.prql.snap | 9 - ...uage-features__dates-and-times-3.prql.snap | 9 - ...l__language-features__distinct-0.prql.snap | 12 -- ...l__language-features__distinct-1.prql.snap | 12 -- ...l__language-features__distinct-2.prql.snap | 12 -- ...__language-features__f-strings-0.prql.snap | 9 - ...__language-features__f-strings-1.prql.snap | 9 - ..._prql__language-features__null-0.prql.snap | 10 - ...rql__language-features__ranges-1.prql.snap | 13 -- ...__language-features__s-strings-0.prql.snap | 9 - ...__language-features__s-strings-1.prql.snap | 9 - ...age-features__standard-library-0.prql.snap | 19 -- ...ql__language-features__strings-0.prql.snap | 9 - ...ql__language-features__strings-1.prql.snap | 9 - ...ql__language-features__strings-2.prql.snap | 9 - ...ql__language-features__strings-3.prql.snap | 9 - ...ql__language-features__strings-4.prql.snap | 9 - ...rql__language-features__target-0.prql.snap | 14 -- ...rql__language-features__target-1.prql.snap | 14 -- ...rql__language-features__target-2.prql.snap | 12 -- ...ests__prql__queries__pipelines-0.prql.snap | 8 - ...ests__prql__queries__pipelines-1.prql.snap | 9 - ...ests__prql__queries__variables-0.prql.snap | 17 -- ...snapshot__tests__prql__syntax-11.prql.snap | 8 - ...snapshot__tests__prql__syntax-13.prql.snap | 8 - ...snapshot__tests__prql__syntax-14.prql.snap | 9 - .../snapshot__tests__prql__syntax-3.prql.snap | 9 - .../snapshot__tests__prql__syntax-4.prql.snap | 9 - .../snapshot__tests__prql__syntax-6.prql.snap | 39 ---- .../snapshot__tests__prql__syntax-8.prql.snap | 9 - ...s__prql__transforms__aggregate-0.prql.snap | 12 -- ...s__prql__transforms__aggregate-2.prql.snap | 9 - ...ests__prql__transforms__append-0.prql.snap | 9 - ...ests__prql__transforms__append-1.prql.snap | 9 - ...ests__prql__transforms__append-2.prql.snap | 9 - ...ests__prql__transforms__derive-0.prql.snap | 9 - ...ests__prql__transforms__filter-0.prql.snap | 9 - ...ests__prql__transforms__filter-1.prql.snap | 9 - ...ests__prql__transforms__filter-2.prql.snap | 12 -- ..._tests__prql__transforms__from-0.prql.snap | 8 - ..._tests__prql__transforms__from-1.prql.snap | 9 - ...s__prql__transforms__from_text-2.prql.snap | 32 ---- ...tests__prql__transforms__group-1.prql.snap | 10 - ...tests__prql__transforms__group-2.prql.snap | 12 -- ..._tests__prql__transforms__join-2.prql.snap | 9 - ...ests__prql__transforms__select-0.prql.snap | 9 - ...ests__prql__transforms__select-2.prql.snap | 9 - ...ests__prql__transforms__select-3.prql.snap | 12 -- ...ests__prql__transforms__select-6.prql.snap | 10 - ..._tests__prql__transforms__sort-0.prql.snap | 9 - ..._tests__prql__transforms__sort-1.prql.snap | 9 - ..._tests__prql__transforms__sort-2.prql.snap | 13 -- ..._tests__prql__transforms__sort-3.prql.snap | 9 - ..._tests__prql__transforms__sort-5.prql.snap | 10 - ..._tests__prql__transforms__take-0.prql.snap | 9 - ..._tests__prql__transforms__take-1.prql.snap | 13 -- ...ests__prql__transforms__window-2.prql.snap | 10 - ...ests__prql__transforms__window-3.prql.snap | 12 -- ...ests__prql__transforms__window-4.prql.snap | 9 - 194 files changed, 1103 insertions(+), 1010 deletions(-) rename book/tests/snapshots/{snapshot__tests__prql__examples__cte-0.prql.snap => snapshot__run_display_reference_prql@examples__cte-0.prql.snap} (51%) rename book/tests/snapshots/{snapshot__tests__prql__examples__employees-0.prql.snap => snapshot__run_display_reference_prql@examples__employees-0.prql.snap} (52%) rename book/tests/snapshots/{snapshot__tests__prql__examples__employees-1.prql.snap => snapshot__run_display_reference_prql@examples__employees-1.prql.snap} (51%) rename book/tests/snapshots/{snapshot__tests__prql__examples__employees-2.prql.snap => snapshot__run_display_reference_prql@examples__employees-2.prql.snap} (50%) rename book/tests/snapshots/{snapshot__tests__prql__examples__employees-3.prql.snap => snapshot__run_display_reference_prql@examples__employees-3.prql.snap} (52%) create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@examples__list-equivalence-0.prql.snap create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@examples__list-equivalence-1.prql.snap rename book/tests/snapshots/{snapshot__tests__prql__examples__list-equivalence-2.prql.snap => snapshot__run_display_reference_prql@examples__list-equivalence-2.prql.snap} (54%) rename book/tests/snapshots/{snapshot__tests__prql__examples__list-equivalence-3.prql.snap => snapshot__run_display_reference_prql@examples__list-equivalence-3.prql.snap} (54%) create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@examples__misc-0.prql.snap create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@examples__misc-1.prql.snap create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@examples__variables-0.prql.snap create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@examples__variables-1.prql.snap create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@internals__functional-lang-0.prql.snap create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@internals__functional-lang-1.prql.snap create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@internals__functional-lang-2.prql.snap create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@internals__functional-lang-3.prql.snap create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@internals__name-resolving-0.prql.snap rename book/tests/snapshots/{snapshot__tests__prql__internals__name-resolving-1.prql.snap => snapshot__run_display_reference_prql@internals__name-resolving-1.prql.snap} (56%) create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@introduction-0.prql.snap create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__coalesce-0.prql.snap create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__dates-and-times-0.prql.snap create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__dates-and-times-1.prql.snap create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__dates-and-times-2.prql.snap create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__dates-and-times-3.prql.snap create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__distinct-0.prql.snap create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__distinct-1.prql.snap create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__distinct-2.prql.snap create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__f-strings-0.prql.snap create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__f-strings-1.prql.snap create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__null-0.prql.snap rename book/tests/snapshots/{snapshot__tests__prql__language-features__ranges-0.prql.snap => snapshot__run_display_reference_prql@language-features__ranges-0.prql.snap} (55%) create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__ranges-1.prql.snap create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-0.prql.snap create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-1.prql.snap rename book/tests/snapshots/{snapshot__tests__prql__language-features__s-strings-2.prql.snap => snapshot__run_display_reference_prql@language-features__s-strings-2.prql.snap} (51%) rename book/tests/snapshots/{snapshot__tests__prql__language-features__s-strings-3.prql.snap => snapshot__run_display_reference_prql@language-features__s-strings-3.prql.snap} (53%) rename book/tests/snapshots/{snapshot__tests__prql__language-features__s-strings-4.prql.snap => snapshot__run_display_reference_prql@language-features__s-strings-4.prql.snap} (51%) rename book/tests/snapshots/{snapshot__tests__prql__language-features__s-strings-5.prql.snap => snapshot__run_display_reference_prql@language-features__s-strings-5.prql.snap} (53%) rename book/tests/snapshots/{snapshot__tests__prql__language-features__s-strings-6.prql.snap => snapshot__run_display_reference_prql@language-features__s-strings-6.prql.snap} (53%) create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__standard-library-0.prql.snap create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__strings-0.prql.snap create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__strings-1.prql.snap create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__strings-2.prql.snap create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__strings-3.prql.snap create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__strings-4.prql.snap rename book/tests/snapshots/{snapshot__tests__prql__language-features__switch-0.prql.snap => snapshot__run_display_reference_prql@language-features__switch-0.prql.snap} (53%) rename book/tests/snapshots/{snapshot__tests__prql__language-features__switch-1.prql.snap => snapshot__run_display_reference_prql@language-features__switch-1.prql.snap} (51%) create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__target-0.prql.snap create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__target-1.prql.snap create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__target-2.prql.snap rename book/tests/snapshots/{snapshot__tests__prql__queries__functions-0.prql.snap => snapshot__run_display_reference_prql@queries__functions-0.prql.snap} (54%) rename book/tests/snapshots/{snapshot__tests__prql__queries__functions-1.prql.snap => snapshot__run_display_reference_prql@queries__functions-1.prql.snap} (51%) rename book/tests/snapshots/{snapshot__tests__prql__queries__functions-2.prql.snap => snapshot__run_display_reference_prql@queries__functions-2.prql.snap} (52%) rename book/tests/snapshots/{snapshot__tests__prql__queries__functions-3.prql.snap => snapshot__run_display_reference_prql@queries__functions-3.prql.snap} (54%) rename book/tests/snapshots/{snapshot__tests__prql__queries__functions-4.prql.snap => snapshot__run_display_reference_prql@queries__functions-4.prql.snap} (52%) create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@queries__pipelines-0.prql.snap create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@queries__pipelines-1.prql.snap rename book/tests/snapshots/{snapshot__tests__prql__queries__pipelines-2.prql.snap => snapshot__run_display_reference_prql@queries__pipelines-2.prql.snap} (53%) create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@queries__variables-0.prql.snap rename book/tests/snapshots/{snapshot__tests__prql__queries__variables-1.prql.snap => snapshot__run_display_reference_prql@queries__variables-1.prql.snap} (51%) rename book/tests/snapshots/{snapshot__tests__prql__syntax-0.prql.snap => snapshot__run_display_reference_prql@syntax-0.prql.snap} (55%) rename book/tests/snapshots/{snapshot__tests__prql__syntax-1.prql.snap => snapshot__run_display_reference_prql@syntax-1.prql.snap} (55%) rename book/tests/snapshots/{snapshot__tests__prql__syntax-10.prql.snap => snapshot__run_display_reference_prql@syntax-10.prql.snap} (50%) create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@syntax-11.prql.snap rename book/tests/snapshots/{snapshot__tests__prql__syntax-12.prql.snap => snapshot__run_display_reference_prql@syntax-12.prql.snap} (55%) create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@syntax-13.prql.snap create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@syntax-14.prql.snap rename book/tests/snapshots/{snapshot__tests__prql__syntax-15.prql.snap => snapshot__run_display_reference_prql@syntax-15.prql.snap} (50%) rename book/tests/snapshots/{snapshot__tests__prql__syntax-2.prql.snap => snapshot__run_display_reference_prql@syntax-2.prql.snap} (54%) create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@syntax-3.prql.snap create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@syntax-4.prql.snap rename book/tests/snapshots/{snapshot__tests__prql__syntax-5.prql.snap => snapshot__run_display_reference_prql@syntax-5.prql.snap} (53%) create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@syntax-6.prql.snap rename book/tests/snapshots/{snapshot__tests__prql__syntax-7.prql.snap => snapshot__run_display_reference_prql@syntax-7.prql.snap} (54%) create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@syntax-8.prql.snap rename book/tests/snapshots/{snapshot__tests__prql__syntax-9.prql.snap => snapshot__run_display_reference_prql@syntax-9.prql.snap} (50%) create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__aggregate-0.prql.snap rename book/tests/snapshots/{snapshot__tests__prql__transforms__aggregate-1.prql.snap => snapshot__run_display_reference_prql@transforms__aggregate-1.prql.snap} (54%) create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__aggregate-2.prql.snap create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__append-0.prql.snap create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__append-1.prql.snap create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__append-2.prql.snap create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__derive-0.prql.snap rename book/tests/snapshots/{snapshot__tests__prql__transforms__derive-1.prql.snap => snapshot__run_display_reference_prql@transforms__derive-1.prql.snap} (54%) create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__filter-0.prql.snap create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__filter-1.prql.snap create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__filter-2.prql.snap create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from-0.prql.snap create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from-1.prql.snap rename book/tests/snapshots/{snapshot__tests__prql__transforms__from_text-0.prql.snap => snapshot__run_display_reference_prql@transforms__from_text-0.prql.snap} (50%) rename book/tests/snapshots/{snapshot__tests__prql__transforms__from_text-1.prql.snap => snapshot__run_display_reference_prql@transforms__from_text-1.prql.snap} (51%) create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from_text-2.prql.snap rename book/tests/snapshots/{snapshot__tests__prql__transforms__group-0.prql.snap => snapshot__run_display_reference_prql@transforms__group-0.prql.snap} (54%) create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__group-1.prql.snap create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__group-2.prql.snap rename book/tests/snapshots/{snapshot__tests__prql__transforms__join-0.prql.snap => snapshot__run_display_reference_prql@transforms__join-0.prql.snap} (52%) rename book/tests/snapshots/{snapshot__tests__prql__transforms__join-1.prql.snap => snapshot__run_display_reference_prql@transforms__join-1.prql.snap} (51%) create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__join-2.prql.snap create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-0.prql.snap rename book/tests/snapshots/{snapshot__tests__prql__transforms__select-1.prql.snap => snapshot__run_display_reference_prql@transforms__select-1.prql.snap} (53%) create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-2.prql.snap create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-3.prql.snap rename book/tests/snapshots/{snapshot__tests__prql__transforms__select-4.prql.snap => snapshot__run_display_reference_prql@transforms__select-4.prql.snap} (51%) rename book/tests/snapshots/{snapshot__tests__prql__transforms__select-5.prql.snap => snapshot__run_display_reference_prql@transforms__select-5.prql.snap} (55%) create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-6.prql.snap create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-0.prql.snap create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-1.prql.snap create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-2.prql.snap create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-3.prql.snap rename book/tests/snapshots/{snapshot__tests__prql__transforms__sort-4.prql.snap => snapshot__run_display_reference_prql@transforms__sort-4.prql.snap} (50%) create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-5.prql.snap create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__take-0.prql.snap create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__take-1.prql.snap rename book/tests/snapshots/{snapshot__tests__prql__transforms__window-0.prql.snap => snapshot__run_display_reference_prql@transforms__window-0.prql.snap} (52%) rename book/tests/snapshots/{snapshot__tests__prql__transforms__window-1.prql.snap => snapshot__run_display_reference_prql@transforms__window-1.prql.snap} (51%) create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__window-2.prql.snap create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__window-3.prql.snap create mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__window-4.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__examples__list-equivalence-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__examples__list-equivalence-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__examples__misc-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__examples__misc-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__examples__variables-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__examples__variables-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-3.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__internals__name-resolving-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__introduction-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__coalesce-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-3.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__distinct-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__distinct-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__distinct-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__f-strings-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__f-strings-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__null-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__ranges-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__standard-library-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__strings-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__strings-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__strings-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__strings-3.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__strings-4.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__target-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__target-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__target-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__queries__pipelines-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__queries__pipelines-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__queries__variables-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__syntax-11.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__syntax-13.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__syntax-14.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__syntax-3.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__syntax-4.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__syntax-6.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__syntax-8.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__aggregate-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__aggregate-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__append-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__append-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__append-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__derive-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__filter-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__filter-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__filter-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__from-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__from-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__from_text-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__group-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__group-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__join-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__select-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__select-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__select-3.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__select-6.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__sort-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__sort-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__sort-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__sort-3.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__sort-5.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__take-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__take-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__window-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__window-3.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__window-4.prql.snap diff --git a/book/tests/snapshot.rs b/book/tests/snapshot.rs index d26bfe754dec..e86b59ae20fc 100644 --- a/book/tests/snapshot.rs +++ b/book/tests/snapshot.rs @@ -1,6 +1,6 @@ #![cfg(not(target_family = "wasm"))] /// This test: -/// - Extracts PRQL code blocks into files in the `examples` path +/// - Extracts PRQL code blocks into the `examples` path. /// - Converts them to SQL using insta, raising an error if there's a diff. /// - Replaces the PRQL code block with a comparison table. /// @@ -18,38 +18,69 @@ // us. They introduce a bunch of non-rust dependencies, which is not ideal, but // passable. They don't let us customize our formatting (e.g. in a table). // -use anyhow::{bail, Error, Result}; +use anyhow::{bail, Result}; use globset::Glob; -use insta::{assert_snapshot, glob}; -use itertools::Itertools; +use insta::{assert_display_snapshot, assert_snapshot, glob}; use log::warn; use prql_compiler::*; use pulldown_cmark::{CodeBlockKind, Event, Parser, Tag}; +use std::fs; use std::path::Path; -use std::{collections::HashMap, fs}; use walkdir::WalkDir; #[test] -fn test_examples() -> Result<()> { +fn run_examples() -> Result<()> { + // TODO: In CI this could pass by replacing incorrect files. To catch that, + // we could check if there are any diffs after this has run? + // Note that on windows, markdown is read differently, and so // writing on Windows. ref https://github.com/PRQL/prql/issues/356 #[cfg(not(target_family = "windows"))] - write_prql_examples()?; - test_prql_examples(); + write_reference_prql()?; + run_reference_prql(); + + // TODO: Currently we run this in the same test, since we need the + // `write_reference_prql` function to have been run. If we could iterate + // over the PRQL examples without writing them to disk, we could run this as + // a separate test. (Though then we'd lose the deferred failures feature + // that insta's `glob!` macro provides.) + run_display_reference_prql(); Ok(()) } -const ROOT_EXAMPLES_PATH: &str = "tests/prql"; +/// Extract reference examples from the PRQL docs and write them to the +/// `tests/prql` path, one in each file. +// We could alternatively have used something like +// https://github.com/earldouglas/codedown, but it's not much code, and it +// requires no dependencies. +// +// We allow dead_code because of the window issue described above. (Can we allow +// it only for windows?) +#[allow(dead_code)] +fn write_reference_prql() -> Result<()> { + // Remove old .prql files, since we're going to rewrite them, and we don't want + // old files which wouldn't be rewritten from hanging around. + // We use `trash`, since we don't want to be removing files with test code + // in case there's a bug. + // + // A more elegant approach would be to keep a list of the files and remove + // the ones we don't write. + + let examples_path = Path::new("tests/prql"); + if examples_path.exists() { + trash::delete(Path::new("tests/prql")).unwrap_or_else(|e| { + warn!("Failed to delete old examples: {}", e); + }); + } -/// Collect all the PRQL examples in the book, as a map of . -fn collect_book_examples() -> Result> { let glob = Glob::new("**/*.md")?.compile_matcher(); - let examples_in_book: HashMap = WalkDir::new(Path::new("./src/")) + + WalkDir::new(Path::new("./src/")) .into_iter() .flatten() .filter(|x| glob.is_match(x.path())) - .flat_map(|dir_entry| { + .try_for_each(|dir_entry| { let text = fs::read_to_string(dir_entry.path())?; let mut parser = Parser::new(&text); let mut prql_blocks = vec![]; @@ -71,85 +102,33 @@ fn collect_book_examples() -> Result> { _ => {} } } - let snapshot_prefix = &dir_entry - .path() - .strip_prefix("./src/")? - .to_str() - .unwrap() - .trim_end_matches(".md"); - Ok(prql_blocks + + // Write each one to a new file. + prql_blocks .iter() .enumerate() - .map(|(i, example)| { - ( - format!("{ROOT_EXAMPLES_PATH}/{snapshot_prefix}-{i}.prql"), - example.to_string(), - ) - }) - .collect::>()) - }) - .flatten() - .collect(); - - Ok(examples_in_book) -} - -/// Extract reference examples from the PRQL docs and write them to the -/// `tests/prql` path, one in each file. -// We could alternatively have used something like -// https://github.com/earldouglas/codedown, but it's not much code, and it -// requires no dependencies. -// -// We allow dead_code because of the window issue described above. (Can we allow -// it only for windows?) -#[allow(dead_code)] -fn write_prql_examples() -> Result<()> { - // If we have to modify any files, raise an error at the end, so it fails in CI. - let mut snapshots_updated = false; - - let examples_path = Path::new(ROOT_EXAMPLES_PATH); - let prql_matcher = Glob::new("**.prql")?.compile_matcher(); - let mut existing_snapshots: HashMap<_, _> = WalkDir::new(examples_path) - .into_iter() - .flatten() - .filter(|x| prql_matcher.is_match(x.path())) - .map(|x| x.path().to_owned()) - .map(|x| Ok::<_, Error>((x.to_string_lossy().to_string(), fs::read_to_string(x)?))) - .try_collect()?; - - // Write any new snapshots, or update any that have changed. = - collect_book_examples()? - .iter() - .try_for_each(|(prql_path, example)| { - if existing_snapshots - .remove(prql_path) - .map(|existing| existing != *example) - .unwrap_or(true) - { - snapshots_updated = true; - fs::create_dir_all(Path::new(prql_path).parent().unwrap())?; - fs::write(prql_path, example)?; - } - - Ok::<(), anyhow::Error>(()) + .try_for_each(|(i, example)| { + let file_relative = &dir_entry + .path() + .strip_prefix("./src/")? + .to_str() + .unwrap() + .trim_end_matches(".md"); + let prql_path = format!("tests/prql/{file_relative}-{i}.prql"); + + fs::create_dir_all(Path::new(&prql_path).parent().unwrap())?; + fs::write(prql_path, example.to_string())?; + + Ok::<(), anyhow::Error>(()) + })?; + Ok(()) })?; - // If there are any files left in `existing_snapshots`, we remove them, since - // they don't reference anything. - existing_snapshots.iter().for_each(|(path, _)| { - trash::delete(path).unwrap_or_else(|e| { - warn!("Failed to delete unreferenced example: {}", e); - }) - }); - - if snapshots_updated { - bail!("Some book snapshots were not consistent with the queries in the book and have been updated. Subsequent runs should pass."); - } Ok(()) } /// Snapshot the output of each example. -fn test_prql_examples() { +fn run_reference_prql() { glob!("prql/**/*.prql", |path| { let prql = fs::read_to_string(path).unwrap(); @@ -168,25 +147,20 @@ fn test_prql_examples() { } /// Snapshot the display trait output of each example. +// Currently not a separate test, see notes in caller. // // TODO: this involves writing out almost the same PRQL again — instead we could // compare the output of Display to the auto-formatted source. But we need an // autoformatter for that (unless we want to raise on any non-matching input, // which seems very strict) -#[test] -fn test_display() -> Result<(), ErrorMessages> { - use prql_compiler::downcast; - collect_book_examples() - .map_err(downcast)? - .iter() - .try_for_each(|(path, example)| { - assert_snapshot!( - path.to_owned(), - prql_to_pl(example).and_then(pl_to_prql)?, - example - ); - Ok::<(), ErrorMessages>(()) - })?; +fn run_display_reference_prql() { + glob!("prql/**/*.prql", |path| { + let prql = fs::read_to_string(path).unwrap(); - Ok(()) + if prql.contains("skip_test") { + return; + } + + assert_display_snapshot!(prql_to_pl(&prql).and_then(pl_to_prql).unwrap()); + }); } diff --git a/book/tests/snapshots/snapshot__tests__prql__examples__cte-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@examples__cte-0.prql.snap similarity index 51% rename from book/tests/snapshots/snapshot__tests__prql__examples__cte-0.prql.snap rename to book/tests/snapshots/snapshot__run_display_reference_prql@examples__cte-0.prql.snap index 83e9f48a0e9e..b246de058091 100644 --- a/book/tests/snapshots/snapshot__tests__prql__examples__cte-0.prql.snap +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@examples__cte-0.prql.snap @@ -1,6 +1,7 @@ --- source: book/tests/snapshot.rs -expression: "let newest_employees = (\n from employees\n sort tenure\n take 50\n)\n\nlet average_salaries = (\n from salaries\n group country (\n aggregate average_country_salary = (average salary)\n )\n)\n\nfrom newest_employees\njoin average_salaries [==country]\nselect [name, salary, average_country_salary]\n" +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/examples/cte-0.prql --- let newest_employees = ( from employees diff --git a/book/tests/snapshots/snapshot__tests__prql__examples__employees-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@examples__employees-0.prql.snap similarity index 52% rename from book/tests/snapshots/snapshot__tests__prql__examples__employees-0.prql.snap rename to book/tests/snapshots/snapshot__run_display_reference_prql@examples__employees-0.prql.snap index ac80804d08a1..692c476512cc 100644 --- a/book/tests/snapshots/snapshot__tests__prql__examples__employees-0.prql.snap +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@examples__employees-0.prql.snap @@ -1,6 +1,7 @@ --- source: book/tests/snapshot.rs -expression: "from salaries\ngroup [emp_no] (\n aggregate [emp_salary = average salary]\n)\njoin t=titles [==emp_no]\njoin dept_emp side:left [==emp_no]\ngroup [dept_emp.dept_no, t.title] (\n aggregate [avg_salary = average emp_salary]\n)\njoin departments [==dept_no]\nselect [dept_name, title, avg_salary]\n" +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/examples/employees-0.prql --- from salaries group [emp_no] ( diff --git a/book/tests/snapshots/snapshot__tests__prql__examples__employees-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@examples__employees-1.prql.snap similarity index 51% rename from book/tests/snapshots/snapshot__tests__prql__examples__employees-1.prql.snap rename to book/tests/snapshots/snapshot__run_display_reference_prql@examples__employees-1.prql.snap index c5d5366f6306..665754bd3fb5 100644 --- a/book/tests/snapshots/snapshot__tests__prql__examples__employees-1.prql.snap +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@examples__employees-1.prql.snap @@ -1,6 +1,7 @@ --- source: book/tests/snapshot.rs -expression: "from e=employees\njoin salaries [==emp_no]\ngroup [e.emp_no, e.gender] (\n aggregate [\n emp_salary = average salaries.salary\n ]\n)\njoin de=dept_emp [==emp_no] side:left\ngroup [de.dept_no, gender] (\n aggregate [\n salary_avg = average emp_salary,\n salary_sd = stddev emp_salary,\n ]\n)\njoin departments [==dept_no]\nselect [dept_name, gender, salary_avg, salary_sd]\n" +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/examples/employees-1.prql --- from e = employees join salaries [==emp_no] diff --git a/book/tests/snapshots/snapshot__tests__prql__examples__employees-2.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@examples__employees-2.prql.snap similarity index 50% rename from book/tests/snapshots/snapshot__tests__prql__examples__employees-2.prql.snap rename to book/tests/snapshots/snapshot__run_display_reference_prql@examples__employees-2.prql.snap index d957c280a5c6..3823173006c7 100644 --- a/book/tests/snapshots/snapshot__tests__prql__examples__employees-2.prql.snap +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@examples__employees-2.prql.snap @@ -1,6 +1,7 @@ --- source: book/tests/snapshot.rs -expression: "from e=employees\njoin salaries [==emp_no]\ngroup [e.emp_no, e.gender] (\n aggregate [\n emp_salary = average salaries.salary\n ]\n)\njoin de=dept_emp [==emp_no]\njoin dm=dept_manager [\n (dm.dept_no == de.dept_no) and s\"(de.from_date, de.to_date) OVERLAPS (dm.from_date, dm.to_date)\"\n]\ngroup [dm.emp_no, gender] (\n aggregate [\n salary_avg = average emp_salary,\n salary_sd = stddev emp_salary\n ]\n)\nderive mng_no = emp_no\njoin managers=employees [==emp_no]\nderive mng_name = s\"managers.first_name || ' ' || managers.last_name\"\nselect [mng_name, managers.gender, salary_avg, salary_sd]\n" +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/examples/employees-2.prql --- from e = employees join salaries [==emp_no] diff --git a/book/tests/snapshots/snapshot__tests__prql__examples__employees-3.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@examples__employees-3.prql.snap similarity index 52% rename from book/tests/snapshots/snapshot__tests__prql__examples__employees-3.prql.snap rename to book/tests/snapshots/snapshot__run_display_reference_prql@examples__employees-3.prql.snap index 9cc6115f24bd..611769e8f06d 100644 --- a/book/tests/snapshots/snapshot__tests__prql__examples__employees-3.prql.snap +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@examples__employees-3.prql.snap @@ -1,6 +1,7 @@ --- source: book/tests/snapshot.rs -expression: "from de=dept_emp\njoin s=salaries side:left [\n (s.emp_no == de.emp_no),\n s\"({s.from_date}, {s.to_date}) OVERLAPS ({de.from_date}, {de.to_date})\"\n]\ngroup [de.emp_no, de.dept_no] (\n aggregate salary = (average s.salary)\n)\njoin employees [==emp_no]\njoin titles [==emp_no]\nselect [dept_no, salary, employees.gender, titles.title]\n" +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/examples/employees-3.prql --- from de = dept_emp join side:left s = salaries [ diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@examples__list-equivalence-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@examples__list-equivalence-0.prql.snap new file mode 100644 index 000000000000..085bada98319 --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@examples__list-equivalence-0.prql.snap @@ -0,0 +1,10 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/examples/list-equivalence-0.prql +--- +from employees +select salary + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@examples__list-equivalence-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@examples__list-equivalence-1.prql.snap new file mode 100644 index 000000000000..6ab6d90cdd10 --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@examples__list-equivalence-1.prql.snap @@ -0,0 +1,10 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/examples/list-equivalence-1.prql +--- +from employees +select [salary] + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__examples__list-equivalence-2.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@examples__list-equivalence-2.prql.snap similarity index 54% rename from book/tests/snapshots/snapshot__tests__prql__examples__list-equivalence-2.prql.snap rename to book/tests/snapshots/snapshot__run_display_reference_prql@examples__list-equivalence-2.prql.snap index 3d298b6f9b55..5ba483c522d7 100644 --- a/book/tests/snapshots/snapshot__tests__prql__examples__list-equivalence-2.prql.snap +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@examples__list-equivalence-2.prql.snap @@ -1,6 +1,7 @@ --- source: book/tests/snapshot.rs -expression: "from employees\nderive [\n gross_salary = salary + payroll_tax,\n gross_cost = gross_salary + benefits_cost\n]\n" +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/examples/list-equivalence-2.prql --- from employees derive [ diff --git a/book/tests/snapshots/snapshot__tests__prql__examples__list-equivalence-3.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@examples__list-equivalence-3.prql.snap similarity index 54% rename from book/tests/snapshots/snapshot__tests__prql__examples__list-equivalence-3.prql.snap rename to book/tests/snapshots/snapshot__run_display_reference_prql@examples__list-equivalence-3.prql.snap index 254f07187889..c1c8e138f806 100644 --- a/book/tests/snapshots/snapshot__tests__prql__examples__list-equivalence-3.prql.snap +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@examples__list-equivalence-3.prql.snap @@ -1,6 +1,7 @@ --- source: book/tests/snapshot.rs -expression: "from employees\nderive gross_salary = salary + payroll_tax\nderive gross_cost = gross_salary + benefits_cost\n" +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/examples/list-equivalence-3.prql --- from employees derive gross_salary = salary + payroll_tax diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@examples__misc-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@examples__misc-0.prql.snap new file mode 100644 index 000000000000..930d29f6d477 --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@examples__misc-0.prql.snap @@ -0,0 +1,26 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/examples/misc-0.prql +--- +let parts = ( + from seq_1_to_5 +) + + + +from pl = prospect_lists_prospects +filter prospect_list_id == "cc675eee-8bd1-237f-be5e-622ba511d65e" +join a = accounts [a.id == pl.related_id] +join er = email_addr_bean_rel [er.bean_id == a.id and er.primary_address == "1"] +join ea = email_addresses [ea.id == er.email_address_id] +select ea.email_address +derive prefix = s"regexp_replace(SUBSTRING_INDEX({email_address}, '@', 1), '[.0-9-_:]+', '.')" +derive stub = s"SUBSTRING_INDEX(SUBSTRING_INDEX({prefix}, '.', part), '.', -1)" +select [ + email_address, + stub, +] + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@examples__misc-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@examples__misc-1.prql.snap new file mode 100644 index 000000000000..d48e3fe1307a --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@examples__misc-1.prql.snap @@ -0,0 +1,13 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/examples/misc-1.prql +--- +from club_ratings +filter rating != null +group year ( + derive [rating_norm = rating - ( average rating ) / ( stddev rating )] +) + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@examples__variables-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@examples__variables-0.prql.snap new file mode 100644 index 000000000000..c4e1df527811 --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@examples__variables-0.prql.snap @@ -0,0 +1,32 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/examples/variables-0.prql +--- +from employees +filter country == "USA" +derive [ + gross_salary = salary + payroll_tax, + gross_cost = gross_salary + benefits_cost, +] +filter gross_cost > 0 +group [ + title, + country, +] ( + aggregate [ + average salary, + average gross_salary, + sum salary, + sum gross_salary, + average gross_cost, + sum_gross_cost = sum gross_cost, + ct = count, +] +) +sort sum_gross_cost +filter ct > 200 +take 20 + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@examples__variables-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@examples__variables-1.prql.snap new file mode 100644 index 000000000000..1f588bf0d309 --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@examples__variables-1.prql.snap @@ -0,0 +1,19 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/examples/variables-1.prql +--- +from employees +group [emp_no] ( + aggregate [emp_salary = average salary] +) +join titles [==emp_no] +group [title] ( + aggregate [avg_salary = average emp_salary] +) +select salary_k = avg_salary / 1000 +take 10 +derive salary = salary_k * 1000 + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@internals__functional-lang-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@internals__functional-lang-0.prql.snap new file mode 100644 index 000000000000..96d5d50a00e1 --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@internals__functional-lang-0.prql.snap @@ -0,0 +1,11 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/internals/functional-lang-0.prql +--- +from employees +filter age > 50 +sort name + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@internals__functional-lang-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@internals__functional-lang-1.prql.snap new file mode 100644 index 000000000000..ae83420f23d3 --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@internals__functional-lang-1.prql.snap @@ -0,0 +1,11 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/internals/functional-lang-1.prql +--- +from employees +filter age > 50 +sort name + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@internals__functional-lang-2.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@internals__functional-lang-2.prql.snap new file mode 100644 index 000000000000..f15a84e195b3 --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@internals__functional-lang-2.prql.snap @@ -0,0 +1,12 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/internals/functional-lang-2.prql +--- +filter age > 50 ( + from employees +) +sort name + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@internals__functional-lang-3.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@internals__functional-lang-3.prql.snap new file mode 100644 index 000000000000..aa777d923706 --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@internals__functional-lang-3.prql.snap @@ -0,0 +1,13 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/internals/functional-lang-3.prql +--- +sort name ( + filter age > 50 ( + from employees +) +) + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@internals__name-resolving-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@internals__name-resolving-0.prql.snap new file mode 100644 index 000000000000..a7bd8bc3730a --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@internals__name-resolving-0.prql.snap @@ -0,0 +1,10 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/internals/name-resolving-0.prql +--- +from employees +select first_name + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__internals__name-resolving-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@internals__name-resolving-1.prql.snap similarity index 56% rename from book/tests/snapshots/snapshot__tests__prql__internals__name-resolving-1.prql.snap rename to book/tests/snapshots/snapshot__run_display_reference_prql@internals__name-resolving-1.prql.snap index a9d9e5bada6d..6161fd5892e6 100644 --- a/book/tests/snapshots/snapshot__tests__prql__internals__name-resolving-1.prql.snap +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@internals__name-resolving-1.prql.snap @@ -1,6 +1,7 @@ --- source: book/tests/snapshot.rs -expression: "from employees\nderive [first_name, dept_id]\njoin d=departments [==dept_id]\nselect [first_name, d.title]\n" +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/internals/name-resolving-1.prql --- from employees derive [ diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@introduction-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@introduction-0.prql.snap new file mode 100644 index 000000000000..bc40a390e21a --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@introduction-0.prql.snap @@ -0,0 +1,32 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/introduction-0.prql +--- +from employees +filter start_date > @2021-01-01 +derive [ + gross_salary = salary + tax ?? 0, + gross_cost = gross_salary + benefits_cost, +] +filter gross_cost > 0 +group [ + title, + country, +] ( + aggregate [ + average gross_salary, + sum_gross_cost = sum gross_cost, +] +) +filter sum_gross_cost > 100000 +derive id = f"{title}_{country}" +derive country_code = s"LEFT(country, 2)" +sort [ + sum_gross_cost, + -country, +] +take 1..20 + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__coalesce-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__coalesce-0.prql.snap new file mode 100644 index 000000000000..16833c5f8cfa --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__coalesce-0.prql.snap @@ -0,0 +1,10 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/language-features/coalesce-0.prql +--- +from orders +derive amount ?? 0 + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__dates-and-times-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__dates-and-times-0.prql.snap new file mode 100644 index 000000000000..ca08e6d69631 --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__dates-and-times-0.prql.snap @@ -0,0 +1,10 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/language-features/dates-and-times-0.prql +--- +from employees +derive age_at_year_end = @2022-12-31 - dob + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__dates-and-times-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__dates-and-times-1.prql.snap new file mode 100644 index 000000000000..07d9b568eac6 --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__dates-and-times-1.prql.snap @@ -0,0 +1,10 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/language-features/dates-and-times-1.prql +--- +from orders +derive should_have_shipped_today = order_time < @08:30 + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__dates-and-times-2.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__dates-and-times-2.prql.snap new file mode 100644 index 000000000000..6e0b688f7f7a --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__dates-and-times-2.prql.snap @@ -0,0 +1,10 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/language-features/dates-and-times-2.prql +--- +from commits +derive first_prql_commit = @2020-01-01T13:19:55-0800 + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__dates-and-times-3.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__dates-and-times-3.prql.snap new file mode 100644 index 000000000000..5080f647a12c --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__dates-and-times-3.prql.snap @@ -0,0 +1,10 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/language-features/dates-and-times-3.prql +--- +from projects +derive first_check_in = start + 10days + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__distinct-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__distinct-0.prql.snap new file mode 100644 index 000000000000..587f75ff1bd2 --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__distinct-0.prql.snap @@ -0,0 +1,13 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/language-features/distinct-0.prql +--- +from employees +select department +group department ( + take 1 +) + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__distinct-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__distinct-1.prql.snap new file mode 100644 index 000000000000..d6bcee7acf86 --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__distinct-1.prql.snap @@ -0,0 +1,13 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/language-features/distinct-1.prql +--- +from employees +select department +group department ( + take 1 +) + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__distinct-2.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__distinct-2.prql.snap new file mode 100644 index 000000000000..4f2e5f381a88 --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__distinct-2.prql.snap @@ -0,0 +1,13 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/language-features/distinct-2.prql +--- +from employees +group department ( + sort age + take 1 +) + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__f-strings-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__f-strings-0.prql.snap new file mode 100644 index 000000000000..2b8a822ba481 --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__f-strings-0.prql.snap @@ -0,0 +1,10 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/language-features/f-strings-0.prql +--- +from employees +select full_name = f"{first_name} {last_name}" + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__f-strings-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__f-strings-1.prql.snap new file mode 100644 index 000000000000..b61f8780aa34 --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__f-strings-1.prql.snap @@ -0,0 +1,10 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/language-features/f-strings-1.prql +--- +from web +select url = f"http{tls}://www.{domain}.{tld}/{page}" + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__null-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__null-0.prql.snap new file mode 100644 index 000000000000..016809741efe --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__null-0.prql.snap @@ -0,0 +1,11 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/language-features/null-0.prql +--- +from employees +filter first_name == null +filter null != last_name + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__ranges-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__ranges-0.prql.snap similarity index 55% rename from book/tests/snapshots/snapshot__tests__prql__language-features__ranges-0.prql.snap rename to book/tests/snapshots/snapshot__run_display_reference_prql@language-features__ranges-0.prql.snap index 2d5baa98ae2d..e20b2b97240c 100644 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__ranges-0.prql.snap +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__ranges-0.prql.snap @@ -1,6 +1,7 @@ --- source: book/tests/snapshot.rs -expression: "from events\nfilter (date | in @1776-07-04..@1787-09-17)\nfilter (magnitude | in 50..100)\nderive is_northern = (latitude | in 0..)\n" +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/language-features/ranges-0.prql --- from events filter ( diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__ranges-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__ranges-1.prql.snap new file mode 100644 index 000000000000..46ce8b767eb3 --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__ranges-1.prql.snap @@ -0,0 +1,14 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/language-features/ranges-1.prql +--- +from orders +sort [ + -value, + date, +] +take 101..110 + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-0.prql.snap new file mode 100644 index 000000000000..fa9c95fb9f4c --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-0.prql.snap @@ -0,0 +1,10 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/language-features/s-strings-0.prql +--- +from my_table +select db_version = s"version()" + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-1.prql.snap new file mode 100644 index 000000000000..7de6990c149c --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-1.prql.snap @@ -0,0 +1,10 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/language-features/s-strings-1.prql +--- +from employees +aggregate [average salary] + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-2.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-2.prql.snap similarity index 51% rename from book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-2.prql.snap rename to book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-2.prql.snap index e28b7f46ed0a..8d39feed0f0d 100644 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-2.prql.snap +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-2.prql.snap @@ -1,6 +1,7 @@ --- source: book/tests/snapshot.rs -expression: "from de=dept_emp\njoin s=salaries side:left [\n (s.emp_no == de.emp_no),\n s\"\"\"({s.from_date}, {s.to_date})\n OVERLAPS\n ({de.from_date}, {de.to_date})\"\"\"\n]\n" +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/language-features/s-strings-2.prql --- from de = dept_emp join side:left s = salaries [ diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-3.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-3.prql.snap similarity index 53% rename from book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-3.prql.snap rename to book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-3.prql.snap index 2cb93849dda8..85661196009c 100644 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-3.prql.snap +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-3.prql.snap @@ -1,6 +1,7 @@ --- source: book/tests/snapshot.rs -expression: "from s\"SELECT DISTINCT ON first_name, id, age FROM employees ORDER BY age ASC\"\njoin s = s\"SELECT * FROM salaries\" [==id]\n" +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/language-features/s-strings-3.prql --- from s"SELECT DISTINCT ON first_name, id, age FROM employees ORDER BY age ASC" join s = s"SELECT * FROM salaries" [==id] diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-4.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-4.prql.snap similarity index 51% rename from book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-4.prql.snap rename to book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-4.prql.snap index 00c1d5e17349..d7482d2f4cfb 100644 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-4.prql.snap +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-4.prql.snap @@ -1,6 +1,7 @@ --- source: book/tests/snapshot.rs -expression: "from employees\nderive [\n has_valid_title = s\"regexp_contains(title, '([a-z0-9]*-){{2,}}')\"\n]\n" +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/language-features/s-strings-4.prql --- from employees derive [has_valid_title = s"regexp_contains(title, '([a-z0-9]*-){2,}')"] diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-5.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-5.prql.snap similarity index 53% rename from book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-5.prql.snap rename to book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-5.prql.snap index 9bd3b0d3fe16..4313e1e554a7 100644 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-5.prql.snap +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-5.prql.snap @@ -1,6 +1,7 @@ --- source: book/tests/snapshot.rs -expression: "from employees\nderive [\n gross_salary = salary + benefits,\n daily_rate = s\"{gross_salary} / 365\"\n]\n" +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/language-features/s-strings-5.prql --- from employees derive [ diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-6.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-6.prql.snap similarity index 53% rename from book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-6.prql.snap rename to book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-6.prql.snap index 3dc30b6885ae..8ac94b9d968f 100644 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-6.prql.snap +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-6.prql.snap @@ -1,6 +1,7 @@ --- source: book/tests/snapshot.rs -expression: "from employees\nderive [\n gross_salary = salary + benefits,\n daily_rate = s\"({gross_salary}) / 365\"\n]\n" +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/language-features/s-strings-6.prql --- from employees derive [ diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__standard-library-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__standard-library-0.prql.snap new file mode 100644 index 000000000000..691cabab4a62 --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__standard-library-0.prql.snap @@ -0,0 +1,20 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/language-features/standard-library-0.prql +--- +from employees +derive [ + gross_salary = ( + salary + payroll_tax + as int +), + gross_salary_rounded = ( + gross_salary + round 0 +), + time = s"NOW()", +] + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__strings-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__strings-0.prql.snap new file mode 100644 index 000000000000..08b198a45ab3 --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__strings-0.prql.snap @@ -0,0 +1,10 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/language-features/strings-0.prql +--- +from my_table +select x = "hello world" + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__strings-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__strings-1.prql.snap new file mode 100644 index 000000000000..014e0927ce0e --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__strings-1.prql.snap @@ -0,0 +1,10 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/language-features/strings-1.prql +--- +from my_table +select x = "hello world" + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__strings-2.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__strings-2.prql.snap new file mode 100644 index 000000000000..52b190fec22a --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__strings-2.prql.snap @@ -0,0 +1,10 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/language-features/strings-2.prql +--- +from my_table +select x = '"hello world"' + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__strings-3.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__strings-3.prql.snap new file mode 100644 index 000000000000..eddb87ee8834 --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__strings-3.prql.snap @@ -0,0 +1,10 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/language-features/strings-3.prql +--- +from my_table +select x = 'I said "hello world"!' + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__strings-4.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__strings-4.prql.snap new file mode 100644 index 000000000000..5966be260e48 --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__strings-4.prql.snap @@ -0,0 +1,10 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/language-features/strings-4.prql +--- +from my_table +select x = 'I said """hello world"""!' + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__switch-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__switch-0.prql.snap similarity index 53% rename from book/tests/snapshots/snapshot__tests__prql__language-features__switch-0.prql.snap rename to book/tests/snapshots/snapshot__run_display_reference_prql@language-features__switch-0.prql.snap index 7618b9e71723..85bb6bac32b8 100644 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__switch-0.prql.snap +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__switch-0.prql.snap @@ -1,6 +1,7 @@ --- source: book/tests/snapshot.rs -expression: "from employees\nderive distance = switch [\n city == \"Calgary\" -> 0,\n city == \"Edmonton\" -> 300,\n]\n" +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/language-features/switch-0.prql --- from employees derive distance = switch [ diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__switch-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__switch-1.prql.snap similarity index 51% rename from book/tests/snapshots/snapshot__tests__prql__language-features__switch-1.prql.snap rename to book/tests/snapshots/snapshot__run_display_reference_prql@language-features__switch-1.prql.snap index f9ee3312b92b..dd4c64e0b6b0 100644 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__switch-1.prql.snap +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__switch-1.prql.snap @@ -1,6 +1,7 @@ --- source: book/tests/snapshot.rs -expression: "from employees\nderive distance = switch [\n city == \"Calgary\" -> 0,\n city == \"Edmonton\" -> 300,\n true -> \"Unknown\",\n]\n" +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/language-features/switch-1.prql --- from employees derive distance = switch [ diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__target-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__target-0.prql.snap new file mode 100644 index 000000000000..8d46fc69595c --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__target-0.prql.snap @@ -0,0 +1,15 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/language-features/target-0.prql +--- +prql target:sql.postgres + + + +from employees +sort age +take 10 + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__target-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__target-1.prql.snap new file mode 100644 index 000000000000..2719c8e16911 --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__target-1.prql.snap @@ -0,0 +1,15 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/language-features/target-1.prql +--- +prql target:sql.mssql + + + +from employees +sort age +take 10 + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__target-2.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__target-2.prql.snap new file mode 100644 index 000000000000..5bf77265c6a4 --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__target-2.prql.snap @@ -0,0 +1,13 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/language-features/target-2.prql +--- +prql version:^0.5 + + + +from employees + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__queries__functions-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@queries__functions-0.prql.snap similarity index 54% rename from book/tests/snapshots/snapshot__tests__prql__queries__functions-0.prql.snap rename to book/tests/snapshots/snapshot__run_display_reference_prql@queries__functions-0.prql.snap index e5bb0a64491b..bde459b05cf8 100644 --- a/book/tests/snapshots/snapshot__tests__prql__queries__functions-0.prql.snap +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@queries__functions-0.prql.snap @@ -1,6 +1,7 @@ --- source: book/tests/snapshot.rs -expression: "func fahrenheit_to_celsius temp -> (temp - 32) / 1.8\n\nfrom cities\nderive temp_c = (fahrenheit_to_celsius temp_f)\n" +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/queries/functions-0.prql --- func fahrenheit_to_celsius temp -> temp - 32 / 1.8 diff --git a/book/tests/snapshots/snapshot__tests__prql__queries__functions-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@queries__functions-1.prql.snap similarity index 51% rename from book/tests/snapshots/snapshot__tests__prql__queries__functions-1.prql.snap rename to book/tests/snapshots/snapshot__run_display_reference_prql@queries__functions-1.prql.snap index ef971e8402bc..d8d3e0185fd9 100644 --- a/book/tests/snapshots/snapshot__tests__prql__queries__functions-1.prql.snap +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@queries__functions-1.prql.snap @@ -1,6 +1,7 @@ --- source: book/tests/snapshot.rs -expression: "func interp lower:0 higher x -> (x - lower) / (higher - lower)\n\nfrom students\nderive [\n sat_proportion_1 = (interp 1600 sat_score),\n sat_proportion_2 = (interp lower:0 1600 sat_score),\n]\n" +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/queries/functions-1.prql --- func interp higher x lower:0 -> x - lower / higher - lower diff --git a/book/tests/snapshots/snapshot__tests__prql__queries__functions-2.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@queries__functions-2.prql.snap similarity index 52% rename from book/tests/snapshots/snapshot__tests__prql__queries__functions-2.prql.snap rename to book/tests/snapshots/snapshot__run_display_reference_prql@queries__functions-2.prql.snap index 2e8f243ea009..49560fe48496 100644 --- a/book/tests/snapshots/snapshot__tests__prql__queries__functions-2.prql.snap +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@queries__functions-2.prql.snap @@ -1,6 +1,7 @@ --- source: book/tests/snapshot.rs -expression: "func interp lower:0 higher x -> (x - lower) / (higher - lower)\n\nfrom students\nderive [\n sat_proportion_1 = (sat_score | interp 1600),\n sat_proportion_2 = (sat_score | interp lower:0 1600),\n]\n" +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/queries/functions-2.prql --- func interp higher x lower:0 -> x - lower / higher - lower diff --git a/book/tests/snapshots/snapshot__tests__prql__queries__functions-3.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@queries__functions-3.prql.snap similarity index 54% rename from book/tests/snapshots/snapshot__tests__prql__queries__functions-3.prql.snap rename to book/tests/snapshots/snapshot__run_display_reference_prql@queries__functions-3.prql.snap index bc1453813dc9..83e91977fe3f 100644 --- a/book/tests/snapshots/snapshot__tests__prql__queries__functions-3.prql.snap +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@queries__functions-3.prql.snap @@ -1,6 +1,7 @@ --- source: book/tests/snapshot.rs -expression: "func fahrenheit_to_celsius temp -> (temp - 32) / 1.8\n\nfrom cities\nderive temp_c = (temp_f | fahrenheit_to_celsius)\n" +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/queries/functions-3.prql --- func fahrenheit_to_celsius temp -> temp - 32 / 1.8 diff --git a/book/tests/snapshots/snapshot__tests__prql__queries__functions-4.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@queries__functions-4.prql.snap similarity index 52% rename from book/tests/snapshots/snapshot__tests__prql__queries__functions-4.prql.snap rename to book/tests/snapshots/snapshot__run_display_reference_prql@queries__functions-4.prql.snap index 3deae6fcab9c..8ed62cca5158 100644 --- a/book/tests/snapshots/snapshot__tests__prql__queries__functions-4.prql.snap +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@queries__functions-4.prql.snap @@ -1,6 +1,7 @@ --- source: book/tests/snapshot.rs -expression: "func fahrenheit_to_celsius temp -> (temp - 32) / 1.8\nfunc interp lower:0 higher x -> (x - lower) / (higher - lower)\n\nfrom kettles\nderive boiling_proportion = (temp_c | fahrenheit_to_celsius | interp 100)\n" +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/queries/functions-4.prql --- func fahrenheit_to_celsius temp -> temp - 32 / 1.8 diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@queries__pipelines-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@queries__pipelines-0.prql.snap new file mode 100644 index 000000000000..7162e861b213 --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@queries__pipelines-0.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/queries/pipelines-0.prql +--- +from employees + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@queries__pipelines-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@queries__pipelines-1.prql.snap new file mode 100644 index 000000000000..f64f5d68dc56 --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@queries__pipelines-1.prql.snap @@ -0,0 +1,10 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/queries/pipelines-1.prql +--- +from employees +derive gross_salary = salary + payroll_tax + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__queries__pipelines-2.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@queries__pipelines-2.prql.snap similarity index 53% rename from book/tests/snapshots/snapshot__tests__prql__queries__pipelines-2.prql.snap rename to book/tests/snapshots/snapshot__run_display_reference_prql@queries__pipelines-2.prql.snap index 5c74bd2eeb81..e3ff662251a8 100644 --- a/book/tests/snapshots/snapshot__tests__prql__queries__pipelines-2.prql.snap +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@queries__pipelines-2.prql.snap @@ -1,6 +1,7 @@ --- source: book/tests/snapshot.rs -expression: "from e = employees\nderive gross_salary = (salary + payroll_tax)\nsort gross_salary\ntake 10\njoin d = department [==dept_no]\nselect [e.name, gross_salary, d.name]\n" +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/queries/pipelines-2.prql --- from e = employees derive gross_salary = salary + payroll_tax diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@queries__variables-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@queries__variables-0.prql.snap new file mode 100644 index 000000000000..fbb8c9dfa00f --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@queries__variables-0.prql.snap @@ -0,0 +1,18 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/queries/variables-0.prql +--- +let top_50 = ( + from employees + sort salary + take 50 + aggregate [total_salary = sum salary] +) + + + +from top_50 + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__queries__variables-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@queries__variables-1.prql.snap similarity index 51% rename from book/tests/snapshots/snapshot__tests__prql__queries__variables-1.prql.snap rename to book/tests/snapshots/snapshot__run_display_reference_prql@queries__variables-1.prql.snap index dd72ddc9b4bb..f7a3cbcd9431 100644 --- a/book/tests/snapshots/snapshot__tests__prql__queries__variables-1.prql.snap +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@queries__variables-1.prql.snap @@ -1,6 +1,7 @@ --- source: book/tests/snapshot.rs -expression: "let grouping = s\"\"\"\n SELECT SUM(a)\n FROM tbl\n GROUP BY\n GROUPING SETS\n ((b, c, d), (d), (b, d))\n\"\"\"\n\nfrom grouping\n" +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/queries/variables-1.prql --- let grouping = s" SELECT SUM(a) diff --git a/book/tests/snapshots/snapshot__tests__prql__syntax-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-0.prql.snap similarity index 55% rename from book/tests/snapshots/snapshot__tests__prql__syntax-0.prql.snap rename to book/tests/snapshots/snapshot__run_display_reference_prql@syntax-0.prql.snap index ee78d7a29c00..16788f8c5410 100644 --- a/book/tests/snapshots/snapshot__tests__prql__syntax-0.prql.snap +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-0.prql.snap @@ -1,6 +1,7 @@ --- source: book/tests/snapshot.rs -expression: "from employees\nfilter department == \"Product\"\nselect [first_name, last_name]\n" +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/syntax-0.prql --- from employees filter department == "Product" diff --git a/book/tests/snapshots/snapshot__tests__prql__syntax-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-1.prql.snap similarity index 55% rename from book/tests/snapshots/snapshot__tests__prql__syntax-1.prql.snap rename to book/tests/snapshots/snapshot__run_display_reference_prql@syntax-1.prql.snap index ae9d7fcbb81c..7d3684118966 100644 --- a/book/tests/snapshots/snapshot__tests__prql__syntax-1.prql.snap +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-1.prql.snap @@ -1,6 +1,7 @@ --- source: book/tests/snapshot.rs -expression: "from employees | filter department == \"Product\" | select [first_name, last_name]\n" +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/syntax-1.prql --- from employees filter department == "Product" diff --git a/book/tests/snapshots/snapshot__tests__prql__syntax-10.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-10.prql.snap similarity index 50% rename from book/tests/snapshots/snapshot__tests__prql__syntax-10.prql.snap rename to book/tests/snapshots/snapshot__run_display_reference_prql@syntax-10.prql.snap index 0ef6f6c5ea4e..e12239744931 100644 --- a/book/tests/snapshots/snapshot__tests__prql__syntax-10.prql.snap +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-10.prql.snap @@ -1,6 +1,7 @@ --- source: book/tests/snapshot.rs -expression: "prql target:sql.postgres\nfrom employees\nselect `first name`\n" +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/syntax-10.prql --- prql target:sql.postgres diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-11.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-11.prql.snap new file mode 100644 index 000000000000..f719b0acbbd4 --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-11.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/syntax-11.prql +--- +from `dir/*.parquet` + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__syntax-12.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-12.prql.snap similarity index 55% rename from book/tests/snapshots/snapshot__tests__prql__syntax-12.prql.snap rename to book/tests/snapshots/snapshot__run_display_reference_prql@syntax-12.prql.snap index 6be462d1cb08..79ec4c9aa74d 100644 --- a/book/tests/snapshots/snapshot__tests__prql__syntax-12.prql.snap +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-12.prql.snap @@ -1,6 +1,7 @@ --- source: book/tests/snapshot.rs -expression: "prql target:sql.bigquery\nfrom `project-foo.dataset.table`\njoin `project-bar.dataset.table` [==col_bax]\n" +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/syntax-12.prql --- prql target:sql.bigquery diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-13.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-13.prql.snap new file mode 100644 index 000000000000..6316d2280516 --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-13.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/syntax-13.prql +--- +from `music.albums` + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-14.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-14.prql.snap new file mode 100644 index 000000000000..a38f2f750602 --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-14.prql.snap @@ -0,0 +1,10 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/syntax-14.prql +--- +from employees +filter id == $1 + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__syntax-15.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-15.prql.snap similarity index 50% rename from book/tests/snapshots/snapshot__tests__prql__syntax-15.prql.snap rename to book/tests/snapshots/snapshot__run_display_reference_prql@syntax-15.prql.snap index 7aa2caf4c217..34d44267ba17 100644 --- a/book/tests/snapshots/snapshot__tests__prql__syntax-15.prql.snap +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-15.prql.snap @@ -1,6 +1,7 @@ --- source: book/tests/snapshot.rs -expression: "from numbers\nselect [\n small = 1.000_000_1,\n big = 5_000_000,\n]\n" +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/syntax-15.prql --- from numbers select [ diff --git a/book/tests/snapshots/snapshot__tests__prql__syntax-2.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-2.prql.snap similarity index 54% rename from book/tests/snapshots/snapshot__tests__prql__syntax-2.prql.snap rename to book/tests/snapshots/snapshot__run_display_reference_prql@syntax-2.prql.snap index a12652162d23..8c5b5825e8c4 100644 --- a/book/tests/snapshots/snapshot__tests__prql__syntax-2.prql.snap +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-2.prql.snap @@ -1,6 +1,7 @@ --- source: book/tests/snapshot.rs -expression: "from numbers\nderive [x = 1, y = 2]\nderive [\n a = x,\n b = y\n]\nderive [\n c = a,\n d = b,\n]\n" +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/syntax-2.prql --- from numbers derive [ diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-3.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-3.prql.snap new file mode 100644 index 000000000000..6820f7c5e628 --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-3.prql.snap @@ -0,0 +1,10 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/syntax-3.prql +--- +from employees +select [first_name] + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-4.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-4.prql.snap new file mode 100644 index 000000000000..6e06fe3ee2e5 --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-4.prql.snap @@ -0,0 +1,10 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/syntax-4.prql +--- +from employees +select first_name + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__syntax-5.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-5.prql.snap similarity index 53% rename from book/tests/snapshots/snapshot__tests__prql__syntax-5.prql.snap rename to book/tests/snapshots/snapshot__run_display_reference_prql@syntax-5.prql.snap index 027e1a5e000f..f3ebf960c4bf 100644 --- a/book/tests/snapshots/snapshot__tests__prql__syntax-5.prql.snap +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-5.prql.snap @@ -1,6 +1,7 @@ --- source: book/tests/snapshot.rs -expression: "from foo\nselect [\n circumference = diameter * 3.14159,\n color,\n]\nfilter circumference > 10 and color != \"red\"\n" +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/syntax-5.prql --- from foo select [ diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-6.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-6.prql.snap new file mode 100644 index 000000000000..d6668fe305c7 --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-6.prql.snap @@ -0,0 +1,40 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/syntax-6.prql +--- +from employees +derive is_proximate = ( + distance + in 0..20 +) +derive ( + total_distance = sum distance +) +derive ( + min_capped_distance = min distance ?? 5 +) +derive travel_time = distance / 40 +derive ( + distance_rounded_2_dp = round 1 + 1 distance +) +derive [ + is_far = ( + distance + in 100.. +), + is_negative = ( + distance + in -100..0 +), + is_negative = ( + distance + in -100..0 +), + average_distance = average distance, +] +sort -distance +sort [-distance] + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__syntax-7.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-7.prql.snap similarity index 54% rename from book/tests/snapshots/snapshot__tests__prql__syntax-7.prql.snap rename to book/tests/snapshots/snapshot__run_display_reference_prql@syntax-7.prql.snap index 81e0a3146955..29e0c6d26c1e 100644 --- a/book/tests/snapshots/snapshot__tests__prql__syntax-7.prql.snap +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-7.prql.snap @@ -1,6 +1,7 @@ --- source: book/tests/snapshot.rs -expression: "from employees\ngroup [title, country] (\n aggregate [\n average salary,\n ct = count\n ]\n)\n" +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/syntax-7.prql --- from employees group [ diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-8.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-8.prql.snap new file mode 100644 index 000000000000..55a51e5d833f --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-8.prql.snap @@ -0,0 +1,10 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/syntax-8.prql +--- +from employees +aggregate [average salary] + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__syntax-9.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-9.prql.snap similarity index 50% rename from book/tests/snapshots/snapshot__tests__prql__syntax-9.prql.snap rename to book/tests/snapshots/snapshot__run_display_reference_prql@syntax-9.prql.snap index 19c4de64822f..9e5a61c3e446 100644 --- a/book/tests/snapshots/snapshot__tests__prql__syntax-9.prql.snap +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-9.prql.snap @@ -1,6 +1,7 @@ --- source: book/tests/snapshot.rs -expression: "prql target:sql.mysql\nfrom employees\nselect `first name`\n" +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/syntax-9.prql --- prql target:sql.mysql diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__aggregate-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__aggregate-0.prql.snap new file mode 100644 index 000000000000..89e3271c8316 --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__aggregate-0.prql.snap @@ -0,0 +1,13 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/transforms/aggregate-0.prql +--- +from employees +aggregate [ + average salary, + ct = count, +] + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__aggregate-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__aggregate-1.prql.snap similarity index 54% rename from book/tests/snapshots/snapshot__tests__prql__transforms__aggregate-1.prql.snap rename to book/tests/snapshots/snapshot__run_display_reference_prql@transforms__aggregate-1.prql.snap index 81e0a3146955..bbf253ec6dd5 100644 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__aggregate-1.prql.snap +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__aggregate-1.prql.snap @@ -1,6 +1,7 @@ --- source: book/tests/snapshot.rs -expression: "from employees\ngroup [title, country] (\n aggregate [\n average salary,\n ct = count\n ]\n)\n" +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/transforms/aggregate-1.prql --- from employees group [ diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__aggregate-2.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__aggregate-2.prql.snap new file mode 100644 index 000000000000..21468ff11aeb --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__aggregate-2.prql.snap @@ -0,0 +1,10 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/transforms/aggregate-2.prql +--- +from employees +derive [avg_sal = average salary] + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__append-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__append-0.prql.snap new file mode 100644 index 000000000000..821c0f010d36 --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__append-0.prql.snap @@ -0,0 +1,10 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/transforms/append-0.prql +--- +from employees_1 +append employees_2 + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__append-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__append-1.prql.snap new file mode 100644 index 000000000000..2a61ec1251b1 --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__append-1.prql.snap @@ -0,0 +1,10 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/transforms/append-1.prql +--- +from employees_1 +remove employees_2 + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__append-2.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__append-2.prql.snap new file mode 100644 index 000000000000..dddeb63b7c9f --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__append-2.prql.snap @@ -0,0 +1,10 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/transforms/append-2.prql +--- +from employees_1 +intersect employees_2 + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__derive-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__derive-0.prql.snap new file mode 100644 index 000000000000..e90d9add3db4 --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__derive-0.prql.snap @@ -0,0 +1,10 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/transforms/derive-0.prql +--- +from employees +derive gross_salary = salary + payroll_tax + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__derive-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__derive-1.prql.snap similarity index 54% rename from book/tests/snapshots/snapshot__tests__prql__transforms__derive-1.prql.snap rename to book/tests/snapshots/snapshot__run_display_reference_prql@transforms__derive-1.prql.snap index 3d298b6f9b55..f2b9dd7bd20d 100644 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__derive-1.prql.snap +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__derive-1.prql.snap @@ -1,6 +1,7 @@ --- source: book/tests/snapshot.rs -expression: "from employees\nderive [\n gross_salary = salary + payroll_tax,\n gross_cost = gross_salary + benefits_cost\n]\n" +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/transforms/derive-1.prql --- from employees derive [ diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__filter-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__filter-0.prql.snap new file mode 100644 index 000000000000..8a68bf997bd7 --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__filter-0.prql.snap @@ -0,0 +1,10 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/transforms/filter-0.prql +--- +from employees +filter age > 25 + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__filter-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__filter-1.prql.snap new file mode 100644 index 000000000000..1bc8cf6d4a34 --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__filter-1.prql.snap @@ -0,0 +1,10 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/transforms/filter-1.prql +--- +from employees +filter age > 25 or department != "IT" + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__filter-2.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__filter-2.prql.snap new file mode 100644 index 000000000000..ad800e09070f --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__filter-2.prql.snap @@ -0,0 +1,13 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/transforms/filter-2.prql +--- +from employees +filter ( + age + in 25..40 +) + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from-0.prql.snap new file mode 100644 index 000000000000..0adcf6191d9e --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from-0.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/transforms/from-0.prql +--- +from employees + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from-1.prql.snap new file mode 100644 index 000000000000..b90898f6f93e --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from-1.prql.snap @@ -0,0 +1,10 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/transforms/from-1.prql +--- +from e = employees +select e.first_name + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__from_text-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from_text-0.prql.snap similarity index 50% rename from book/tests/snapshots/snapshot__tests__prql__transforms__from_text-0.prql.snap rename to book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from_text-0.prql.snap index 6a730d3a1f7e..d86f2e1e86bb 100644 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__from_text-0.prql.snap +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from_text-0.prql.snap @@ -1,6 +1,7 @@ --- source: book/tests/snapshot.rs -expression: "from_text \"\"\"\na,b,c\n1,2,3\n4,5,6\n\"\"\"\nderive [\n d = b + c,\n answer = 20 * 2 + 2,\n]\n" +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/transforms/from_text-0.prql --- from_text " a,b,c diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__from_text-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from_text-1.prql.snap similarity index 51% rename from book/tests/snapshots/snapshot__tests__prql__transforms__from_text-1.prql.snap rename to book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from_text-1.prql.snap index 6f9f848bbd6e..740349748e00 100644 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__from_text-1.prql.snap +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from_text-1.prql.snap @@ -1,6 +1,7 @@ --- source: book/tests/snapshot.rs -expression: "let temp_format_lookup = from_text format:csv \"\"\"\ncountry_code,format\nuk,C\nus,F\nlr,F\nde,C\n\"\"\"\n\nfrom temperatures\njoin temp_format_lookup [==country_code]\n" +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/transforms/from_text-1.prql --- let temp_format_lookup = ( from_text format:csv " diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from_text-2.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from_text-2.prql.snap new file mode 100644 index 000000000000..a0aaabe15cb7 --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from_text-2.prql.snap @@ -0,0 +1,33 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/transforms/from_text-2.prql +--- +let x = ( + from_text format:json '{ + "columns": ["a", "b", "c"], + "data": [ + [1, "x", false], + [4, "y", null] + ] +}' +) + + + +let y = ( + from_text format:json ' + [ + {"a": 1, "m": "5"}, + {"a": 4, "n": "6"} + ] +' +) + + + +from x +join y [==a] + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__group-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__group-0.prql.snap similarity index 54% rename from book/tests/snapshots/snapshot__tests__prql__transforms__group-0.prql.snap rename to book/tests/snapshots/snapshot__run_display_reference_prql@transforms__group-0.prql.snap index 81e0a3146955..754f23c1d76e 100644 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__group-0.prql.snap +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__group-0.prql.snap @@ -1,6 +1,7 @@ --- source: book/tests/snapshot.rs -expression: "from employees\ngroup [title, country] (\n aggregate [\n average salary,\n ct = count\n ]\n)\n" +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/transforms/group-0.prql --- from employees group [ diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__group-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__group-1.prql.snap new file mode 100644 index 000000000000..f916e255f991 --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__group-1.prql.snap @@ -0,0 +1,11 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/transforms/group-1.prql +--- +from employees +sort join_date +take 1 + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__group-2.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__group-2.prql.snap new file mode 100644 index 000000000000..6b2cb62586b3 --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__group-2.prql.snap @@ -0,0 +1,13 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/transforms/group-2.prql +--- +from employees +group role ( + sort join_date + take 1 +) + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__join-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__join-0.prql.snap similarity index 52% rename from book/tests/snapshots/snapshot__tests__prql__transforms__join-0.prql.snap rename to book/tests/snapshots/snapshot__run_display_reference_prql@transforms__join-0.prql.snap index 4d113382409a..0334411b6614 100644 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__join-0.prql.snap +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__join-0.prql.snap @@ -1,6 +1,7 @@ --- source: book/tests/snapshot.rs -expression: "from employees\njoin side:left positions [employees.id==positions.employee_id]\n" +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/transforms/join-0.prql --- from employees join side:left positions [employees.id == positions.employee_id] diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__join-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__join-1.prql.snap similarity index 51% rename from book/tests/snapshots/snapshot__tests__prql__transforms__join-1.prql.snap rename to book/tests/snapshots/snapshot__run_display_reference_prql@transforms__join-1.prql.snap index b3e13a1d23f8..073e5b79b5ee 100644 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__join-1.prql.snap +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__join-1.prql.snap @@ -1,6 +1,7 @@ --- source: book/tests/snapshot.rs -expression: "from employees\njoin side:left p=positions [employees.id==p.employee_id]\n" +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/transforms/join-1.prql --- from employees join side:left p = positions [employees.id == p.employee_id] diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__join-2.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__join-2.prql.snap new file mode 100644 index 000000000000..19b950c9d24b --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__join-2.prql.snap @@ -0,0 +1,10 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/transforms/join-2.prql +--- +from employees +join positions [==emp_no] + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-0.prql.snap new file mode 100644 index 000000000000..9841ec3d8249 --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-0.prql.snap @@ -0,0 +1,10 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/transforms/select-0.prql +--- +from employees +select name = f"{first_name} {last_name}" + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__select-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-1.prql.snap similarity index 53% rename from book/tests/snapshots/snapshot__tests__prql__transforms__select-1.prql.snap rename to book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-1.prql.snap index 57c345371217..1ecfbb0be8f6 100644 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__select-1.prql.snap +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-1.prql.snap @@ -1,6 +1,7 @@ --- source: book/tests/snapshot.rs -expression: "from employees\nselect [\n name = f\"{first_name} {last_name}\",\n age_eoy = dob - @2022-12-31,\n]\n" +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/transforms/select-1.prql --- from employees select [ diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-2.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-2.prql.snap new file mode 100644 index 000000000000..522050c7dd99 --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-2.prql.snap @@ -0,0 +1,10 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/transforms/select-2.prql +--- +from employees +select first_name + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-3.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-3.prql.snap new file mode 100644 index 000000000000..d6596a9ce634 --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-3.prql.snap @@ -0,0 +1,13 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/transforms/select-3.prql +--- +from e = employees +select [ + e.first_name, + e.last_name, +] + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__select-4.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-4.prql.snap similarity index 51% rename from book/tests/snapshots/snapshot__tests__prql__transforms__select-4.prql.snap rename to book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-4.prql.snap index 6445588450d2..c8837e7a5780 100644 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__select-4.prql.snap +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-4.prql.snap @@ -1,6 +1,7 @@ --- source: book/tests/snapshot.rs -expression: "prql target:sql.bigquery\nfrom tracks\nselect ![milliseconds,bytes]\n" +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/transforms/select-4.prql --- prql target:sql.bigquery diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__select-5.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-5.prql.snap similarity index 55% rename from book/tests/snapshots/snapshot__tests__prql__transforms__select-5.prql.snap rename to book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-5.prql.snap index 568bc821ba4f..ee470cf35cf6 100644 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__select-5.prql.snap +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-5.prql.snap @@ -1,6 +1,7 @@ --- source: book/tests/snapshot.rs -expression: "from tracks\nselect [track_id, title, composer, bytes]\nselect ![title, composer]\n" +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/transforms/select-5.prql --- from tracks select [ diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-6.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-6.prql.snap new file mode 100644 index 000000000000..102555240bdb --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-6.prql.snap @@ -0,0 +1,11 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/transforms/select-6.prql +--- +from artists +derive nick = name +select not [artists.`*`] + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-0.prql.snap new file mode 100644 index 000000000000..91b36c10532f --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-0.prql.snap @@ -0,0 +1,10 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/transforms/sort-0.prql +--- +from employees +sort age + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-1.prql.snap new file mode 100644 index 000000000000..d7f443472fc9 --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-1.prql.snap @@ -0,0 +1,10 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/transforms/sort-1.prql +--- +from employees +sort [-age] + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-2.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-2.prql.snap new file mode 100644 index 000000000000..1df292e0b57f --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-2.prql.snap @@ -0,0 +1,14 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/transforms/sort-2.prql +--- +from employees +sort [ + age, + -tenure, + salary, +] + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-3.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-3.prql.snap new file mode 100644 index 000000000000..3ef53a4676e9 --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-3.prql.snap @@ -0,0 +1,10 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/transforms/sort-3.prql +--- +from employees +sort [s"substr({first_name}, 2, 5)"] + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__sort-4.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-4.prql.snap similarity index 50% rename from book/tests/snapshots/snapshot__tests__prql__transforms__sort-4.prql.snap rename to book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-4.prql.snap index 51c71b587af5..01b5c740c41a 100644 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__sort-4.prql.snap +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-4.prql.snap @@ -1,6 +1,7 @@ --- source: book/tests/snapshot.rs -expression: "from employees\nsort tenure\nderive name = f\"{first_name} {last_name}\"\n" +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/transforms/sort-4.prql --- from employees sort tenure diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-5.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-5.prql.snap new file mode 100644 index 000000000000..52f805544586 --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-5.prql.snap @@ -0,0 +1,11 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/transforms/sort-5.prql +--- +from employees +sort tenure +join locations [==employee_id] + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__take-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__take-0.prql.snap new file mode 100644 index 000000000000..7f798967b647 --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__take-0.prql.snap @@ -0,0 +1,10 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/transforms/take-0.prql +--- +from employees +take 10 + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__take-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__take-1.prql.snap new file mode 100644 index 000000000000..4107c86bfd92 --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__take-1.prql.snap @@ -0,0 +1,14 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/transforms/take-1.prql +--- +from orders +sort [ + -value, + date, +] +take 101..110 + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__window-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__window-0.prql.snap similarity index 52% rename from book/tests/snapshots/snapshot__tests__prql__transforms__window-0.prql.snap rename to book/tests/snapshots/snapshot__run_display_reference_prql@transforms__window-0.prql.snap index 08d6e23e2468..2366506585b0 100644 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__window-0.prql.snap +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__window-0.prql.snap @@ -1,6 +1,7 @@ --- source: book/tests/snapshot.rs -expression: "from employees\ngroup employee_id (\n sort month\n window rolling:12 (\n derive [trail_12_m_comp = sum paycheck]\n )\n)\n" +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/transforms/window-0.prql --- from employees group employee_id ( diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__window-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__window-1.prql.snap similarity index 51% rename from book/tests/snapshots/snapshot__tests__prql__transforms__window-1.prql.snap rename to book/tests/snapshots/snapshot__run_display_reference_prql@transforms__window-1.prql.snap index c0663a94bc4a..afffeb8eb185 100644 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__window-1.prql.snap +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__window-1.prql.snap @@ -1,6 +1,7 @@ --- source: book/tests/snapshot.rs -expression: "from orders\nsort day\nwindow rows:-3..3 (\n derive [centered_weekly_average = average value]\n)\ngroup [order_month] (\n sort day\n window expanding:true (\n derive [monthly_running_total = sum value]\n )\n)\n" +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/transforms/window-1.prql --- from orders sort day diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__window-2.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__window-2.prql.snap new file mode 100644 index 000000000000..3015829b90db --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__window-2.prql.snap @@ -0,0 +1,11 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/transforms/window-2.prql +--- +from employees +sort age +derive rnk = rank + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__window-3.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__window-3.prql.snap new file mode 100644 index 000000000000..26a5eb5d9d46 --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__window-3.prql.snap @@ -0,0 +1,13 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/transforms/window-3.prql +--- +from employees +group department ( + sort age + derive rnk = rank +) + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__window-4.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__window-4.prql.snap new file mode 100644 index 000000000000..be549656354d --- /dev/null +++ b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__window-4.prql.snap @@ -0,0 +1,10 @@ +--- +source: book/tests/snapshot.rs +expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() +input_file: book/tests/prql/transforms/window-4.prql +--- +from employees +filter salary < ( average salary ) + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__examples__list-equivalence-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__examples__list-equivalence-0.prql.snap deleted file mode 100644 index 8566dfaeb2b2..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__examples__list-equivalence-0.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nselect salary\n" ---- -from employees -select salary - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__examples__list-equivalence-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__examples__list-equivalence-1.prql.snap deleted file mode 100644 index 055af64b363a..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__examples__list-equivalence-1.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nselect [salary]\n" ---- -from employees -select [salary] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__examples__misc-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__examples__misc-0.prql.snap deleted file mode 100644 index 63b13a31ec56..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__examples__misc-0.prql.snap +++ /dev/null @@ -1,25 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "# TODO: this table should have a column `part` with values 1..5,\n# but such data declaration is not yet supported, see #286\nlet parts = (\n from seq_1_to_5\n)\n\nfrom pl=prospect_lists_prospects\nfilter prospect_list_id == 'cc675eee-8bd1-237f-be5e-622ba511d65e'\njoin a=accounts [a.id == pl.related_id]\njoin er=email_addr_bean_rel [er.bean_id == a.id and er.primary_address == '1']\njoin ea=email_addresses [ea.id == er.email_address_id]\nselect ea.email_address\nderive prefix = s\"regexp_replace(SUBSTRING_INDEX({email_address}, '@', 1), '[.0-9-_:]+', '.')\"\nderive stub = s\"SUBSTRING_INDEX(SUBSTRING_INDEX({prefix}, '.', part), '.', -1)\"\nselect [email_address, stub]\n" ---- -let parts = ( - from seq_1_to_5 -) - - - -from pl = prospect_lists_prospects -filter prospect_list_id == "cc675eee-8bd1-237f-be5e-622ba511d65e" -join a = accounts [a.id == pl.related_id] -join er = email_addr_bean_rel [er.bean_id == a.id and er.primary_address == "1"] -join ea = email_addresses [ea.id == er.email_address_id] -select ea.email_address -derive prefix = s"regexp_replace(SUBSTRING_INDEX({email_address}, '@', 1), '[.0-9-_:]+', '.')" -derive stub = s"SUBSTRING_INDEX(SUBSTRING_INDEX({prefix}, '.', part), '.', -1)" -select [ - email_address, - stub, -] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__examples__misc-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__examples__misc-1.prql.snap deleted file mode 100644 index 50dcca896ea5..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__examples__misc-1.prql.snap +++ /dev/null @@ -1,12 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from club_ratings\nfilter rating != null\n# TODO: this is real ugly. `average rating` should not require parenthesis\n# TODO: why cannot we put comments in group's pipeline?\ngroup year (\n derive [rating_norm = rating - (average rating) / (stddev rating)]\n)\n" ---- -from club_ratings -filter rating != null -group year ( - derive [rating_norm = rating - ( average rating ) / ( stddev rating )] -) - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__examples__variables-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__examples__variables-0.prql.snap deleted file mode 100644 index 4b1f4fce84c1..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__examples__variables-0.prql.snap +++ /dev/null @@ -1,31 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nfilter country == \"USA\" # Each line transforms the previous result.\nderive [ # This adds columns / variables.\n gross_salary = salary + payroll_tax,\n gross_cost = gross_salary + benefits_cost # Variables can use other variables.\n]\nfilter gross_cost > 0\ngroup [title, country] ( # For each group use a nested pipeline\n aggregate [ # Aggregate each group to a single row\n average salary,\n average gross_salary,\n sum salary,\n sum gross_salary,\n average gross_cost,\n sum_gross_cost = sum gross_cost,\n ct = count,\n ]\n)\nsort sum_gross_cost\nfilter ct > 200\ntake 20\n" ---- -from employees -filter country == "USA" -derive [ - gross_salary = salary + payroll_tax, - gross_cost = gross_salary + benefits_cost, -] -filter gross_cost > 0 -group [ - title, - country, -] ( - aggregate [ - average salary, - average gross_salary, - sum salary, - sum gross_salary, - average gross_cost, - sum_gross_cost = sum gross_cost, - ct = count, -] -) -sort sum_gross_cost -filter ct > 200 -take 20 - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__examples__variables-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__examples__variables-1.prql.snap deleted file mode 100644 index cfb45e96a801..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__examples__variables-1.prql.snap +++ /dev/null @@ -1,18 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\ngroup [emp_no] (\n aggregate [\n emp_salary = average salary # average salary resolves to \"AVG(salary)\" (from stdlib)\n ]\n)\njoin titles [==emp_no]\ngroup [title] (\n aggregate [\n avg_salary = average emp_salary\n ]\n)\nselect salary_k = avg_salary / 1000 # avg_salary should resolve to \"AVG(emp_salary)\"\ntake 10 # induces new SELECT\nderive salary = salary_k * 1000 # salary_k should not resolve to \"avg_salary / 1000\"\n" ---- -from employees -group [emp_no] ( - aggregate [emp_salary = average salary] -) -join titles [==emp_no] -group [title] ( - aggregate [avg_salary = average emp_salary] -) -select salary_k = avg_salary / 1000 -take 10 -derive salary = salary_k * 1000 - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-0.prql.snap deleted file mode 100644 index 1bd2d905e16d..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-0.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nfilter age > 50\nsort name\n" ---- -from employees -filter age > 50 -sort name - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-1.prql.snap deleted file mode 100644 index da4b761a9e4b..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-1.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees | filter age > 50 | sort name\n" ---- -from employees -filter age > 50 -sort name - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-2.prql.snap deleted file mode 100644 index 7da897d0dd14..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-2.prql.snap +++ /dev/null @@ -1,11 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "filter age > 50 (from employees) | sort name\n" ---- -filter age > 50 ( - from employees -) -sort name - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-3.prql.snap b/book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-3.prql.snap deleted file mode 100644 index 045c663815a8..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-3.prql.snap +++ /dev/null @@ -1,12 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "sort name (filter age > 50 (from employees))\n" ---- -sort name ( - filter age > 50 ( - from employees -) -) - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__internals__name-resolving-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__internals__name-resolving-0.prql.snap deleted file mode 100644 index 56e49df27e11..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__internals__name-resolving-0.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nselect first_name\n" ---- -from employees -select first_name - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__introduction-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__introduction-0.prql.snap deleted file mode 100644 index 96f55b8ab057..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__introduction-0.prql.snap +++ /dev/null @@ -1,31 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nfilter start_date > @2021-01-01 # Clear date syntax\nderive [ # `derive` adds columns / variables\n gross_salary = salary + (tax ?? 0), # Terse coalesce\n gross_cost = gross_salary + benefits_cost, # Variables can use other variables\n]\nfilter gross_cost > 0\ngroup [title, country] ( # `group` runs a pipeline over each group\n aggregate [ # `aggregate` reduces each group to a value\n average gross_salary,\n sum_gross_cost = sum gross_cost, # `=` sets a column name\n ]\n)\nfilter sum_gross_cost > 100_000 # `filter` replaces both of SQL's `WHERE` & `HAVING`\nderive id = f\"{title}_{country}\" # F-strings like Python\nderive country_code = s\"LEFT(country, 2)\" # S-strings allow using SQL as an escape hatch\nsort [sum_gross_cost, -country] # `-country` means descending order\ntake 1..20 # Range expressions (also valid here as `take 20`)\n" ---- -from employees -filter start_date > @2021-01-01 -derive [ - gross_salary = salary + tax ?? 0, - gross_cost = gross_salary + benefits_cost, -] -filter gross_cost > 0 -group [ - title, - country, -] ( - aggregate [ - average gross_salary, - sum_gross_cost = sum gross_cost, -] -) -filter sum_gross_cost > 100000 -derive id = f"{title}_{country}" -derive country_code = s"LEFT(country, 2)" -sort [ - sum_gross_cost, - -country, -] -take 1..20 - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__coalesce-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__coalesce-0.prql.snap deleted file mode 100644 index 24ff749cfbc8..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__coalesce-0.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from orders\nderive amount ?? 0\n" ---- -from orders -derive amount ?? 0 - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-0.prql.snap deleted file mode 100644 index acb71c71fc9a..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-0.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nderive age_at_year_end = (@2022-12-31 - dob)\n" ---- -from employees -derive age_at_year_end = @2022-12-31 - dob - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-1.prql.snap deleted file mode 100644 index fd2fe52b3f6c..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-1.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from orders\nderive should_have_shipped_today = (order_time < @08:30)\n" ---- -from orders -derive should_have_shipped_today = order_time < @08:30 - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-2.prql.snap deleted file mode 100644 index 1507a39b0252..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-2.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from commits\nderive first_prql_commit = @2020-01-01T13:19:55-0800\n" ---- -from commits -derive first_prql_commit = @2020-01-01T13:19:55-0800 - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-3.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-3.prql.snap deleted file mode 100644 index 70ac66f365a2..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-3.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from projects\nderive first_check_in = start + 10days\n" ---- -from projects -derive first_check_in = start + 10days - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__distinct-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__distinct-0.prql.snap deleted file mode 100644 index 7929401e23b6..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__distinct-0.prql.snap +++ /dev/null @@ -1,12 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nselect department\ngroup department (\n take 1\n)\n" ---- -from employees -select department -group department ( - take 1 -) - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__distinct-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__distinct-1.prql.snap deleted file mode 100644 index 22ba087f087c..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__distinct-1.prql.snap +++ /dev/null @@ -1,12 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nselect department\ngroup department (take 1)\n" ---- -from employees -select department -group department ( - take 1 -) - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__distinct-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__distinct-2.prql.snap deleted file mode 100644 index ceb0035e6601..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__distinct-2.prql.snap +++ /dev/null @@ -1,12 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "# youngest employee from each department\nfrom employees\ngroup department (\n sort age\n take 1\n)\n" ---- -from employees -group department ( - sort age - take 1 -) - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__f-strings-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__f-strings-0.prql.snap deleted file mode 100644 index 5f490aa52f00..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__f-strings-0.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nselect full_name = f\"{first_name} {last_name}\"\n" ---- -from employees -select full_name = f"{first_name} {last_name}" - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__f-strings-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__f-strings-1.prql.snap deleted file mode 100644 index f00e2becbab2..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__f-strings-1.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from web\nselect url = f\"http{tls}://www.{domain}.{tld}/{page}\"\n" ---- -from web -select url = f"http{tls}://www.{domain}.{tld}/{page}" - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__null-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__null-0.prql.snap deleted file mode 100644 index 73594522238f..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__null-0.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nfilter first_name == null\nfilter null != last_name\n" ---- -from employees -filter first_name == null -filter null != last_name - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__ranges-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__ranges-1.prql.snap deleted file mode 100644 index b68c1920a669..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__ranges-1.prql.snap +++ /dev/null @@ -1,13 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from orders\nsort [-value, date]\ntake 101..110\n" ---- -from orders -sort [ - -value, - date, -] -take 101..110 - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-0.prql.snap deleted file mode 100644 index 12abfcc2518c..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-0.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from my_table\nselect db_version = s\"version()\"\n" ---- -from my_table -select db_version = s"version()" - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-1.prql.snap deleted file mode 100644 index c57ed2561d58..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-1.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\naggregate [average salary]\n" ---- -from employees -aggregate [average salary] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__standard-library-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__standard-library-0.prql.snap deleted file mode 100644 index 011d5f416c47..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__standard-library-0.prql.snap +++ /dev/null @@ -1,19 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nderive [\n gross_salary = (salary + payroll_tax | as int),\n gross_salary_rounded = (gross_salary | round 0),\n time = s\"NOW()\", # an s-string, given no `now` function exists in PRQL\n]\n" ---- -from employees -derive [ - gross_salary = ( - salary + payroll_tax - as int -), - gross_salary_rounded = ( - gross_salary - round 0 -), - time = s"NOW()", -] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__strings-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__strings-0.prql.snap deleted file mode 100644 index 6a1d79036036..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__strings-0.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from my_table\nselect x = \"hello world\"\n" ---- -from my_table -select x = "hello world" - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__strings-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__strings-1.prql.snap deleted file mode 100644 index 2da7a07937de..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__strings-1.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from my_table\nselect x = 'hello world'\n" ---- -from my_table -select x = "hello world" - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__strings-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__strings-2.prql.snap deleted file mode 100644 index 8d79cd8cedbc..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__strings-2.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from my_table\nselect x = '\"hello world\"'\n" ---- -from my_table -select x = '"hello world"' - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__strings-3.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__strings-3.prql.snap deleted file mode 100644 index a681bc62a036..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__strings-3.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from my_table\nselect x = \"\"\"I said \"hello world\"!\"\"\"\n" ---- -from my_table -select x = 'I said "hello world"!' - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__strings-4.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__strings-4.prql.snap deleted file mode 100644 index 0bae3f836774..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__strings-4.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from my_table\nselect x = \"\"\"\"\"I said \"\"\"hello world\"\"\"!\"\"\"\"\"\n" ---- -from my_table -select x = 'I said """hello world"""!' - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__target-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__target-0.prql.snap deleted file mode 100644 index b22539422ae4..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__target-0.prql.snap +++ /dev/null @@ -1,14 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "prql target:sql.postgres\n\nfrom employees\nsort age\ntake 10\n" ---- -prql target:sql.postgres - - - -from employees -sort age -take 10 - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__target-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__target-1.prql.snap deleted file mode 100644 index ed7e10fd7388..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__target-1.prql.snap +++ /dev/null @@ -1,14 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "prql target:sql.mssql\n\nfrom employees\nsort age\ntake 10\n" ---- -prql target:sql.mssql - - - -from employees -sort age -take 10 - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__target-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__target-2.prql.snap deleted file mode 100644 index b05787ed8bae..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__target-2.prql.snap +++ /dev/null @@ -1,12 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "prql version:\"0.5\"\n\nfrom employees\n" ---- -prql version:^0.5 - - - -from employees - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__queries__pipelines-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__queries__pipelines-0.prql.snap deleted file mode 100644 index 8ef6dce0bb66..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__queries__pipelines-0.prql.snap +++ /dev/null @@ -1,8 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\n" ---- -from employees - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__queries__pipelines-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__queries__pipelines-1.prql.snap deleted file mode 100644 index b2b18409f03a..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__queries__pipelines-1.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nderive gross_salary = (salary + payroll_tax)\n" ---- -from employees -derive gross_salary = salary + payroll_tax - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__queries__variables-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__queries__variables-0.prql.snap deleted file mode 100644 index 3c4edace1010..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__queries__variables-0.prql.snap +++ /dev/null @@ -1,17 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "let top_50 = (\n from employees\n sort salary\n take 50\n aggregate [total_salary = sum salary]\n)\n\nfrom top_50 # Starts a new pipeline\n" ---- -let top_50 = ( - from employees - sort salary - take 50 - aggregate [total_salary = sum salary] -) - - - -from top_50 - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__syntax-11.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-11.prql.snap deleted file mode 100644 index acd1651bdbb9..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__syntax-11.prql.snap +++ /dev/null @@ -1,8 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from `dir/*.parquet`\n" ---- -from `dir/*.parquet` - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__syntax-13.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-13.prql.snap deleted file mode 100644 index fc9310bcceea..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__syntax-13.prql.snap +++ /dev/null @@ -1,8 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from `music.albums`\n" ---- -from `music.albums` - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__syntax-14.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-14.prql.snap deleted file mode 100644 index 429e57d0faf3..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__syntax-14.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nfilter id == $1\n" ---- -from employees -filter id == $1 - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__syntax-3.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-3.prql.snap deleted file mode 100644 index 4077d71aaa9b..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__syntax-3.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nselect [first_name]\n" ---- -from employees -select [first_name] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__syntax-4.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-4.prql.snap deleted file mode 100644 index 56e49df27e11..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__syntax-4.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nselect first_name\n" ---- -from employees -select first_name - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__syntax-6.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-6.prql.snap deleted file mode 100644 index b9f326d968cc..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__syntax-6.prql.snap +++ /dev/null @@ -1,39 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\n# Requires parentheses, because it's contains a pipe\nderive is_proximate = (distance | in 0..20)\n# Requires parentheses, because it's a function call\nderive total_distance = (sum distance)\n# `??` doesn't require parentheses, as it's not a function call\nderive min_capped_distance = (min distance ?? 5)\n# No parentheses needed, because no function call\nderive travel_time = distance / 40\n# No inner parentheses needed around `1+1` because no function call\nderive distance_rounded_2_dp = (round 1+1 distance)\nderive [\n # Requires parentheses, because it contains a pipe\n is_far = (distance | in 100..),\n # The left value of the range requires parentheses,\n # because of the minus sign\n is_negative = (distance | in (-100..0)),\n # ...this is equivalent\n is_negative = (distance | in (-100)..0),\n # Doesn't require parentheses, because it's in a list (confusing, see footnote)!\n average_distance = average distance,\n]\n# Requires parentheses because of the minus sign\nsort (-distance)\n# A list is fine too\nsort [-distance]\n" ---- -from employees -derive is_proximate = ( - distance - in 0..20 -) -derive ( - total_distance = sum distance -) -derive ( - min_capped_distance = min distance ?? 5 -) -derive travel_time = distance / 40 -derive ( - distance_rounded_2_dp = round 1 + 1 distance -) -derive [ - is_far = ( - distance - in 100.. -), - is_negative = ( - distance - in -100..0 -), - is_negative = ( - distance - in -100..0 -), - average_distance = average distance, -] -sort -distance -sort [-distance] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__syntax-8.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-8.prql.snap deleted file mode 100644 index 4f94033b1f86..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__syntax-8.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees # Comment 1\n# Comment 2\naggregate [average salary]\n" ---- -from employees -aggregate [average salary] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__aggregate-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__aggregate-0.prql.snap deleted file mode 100644 index 1c202ec4ba25..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__aggregate-0.prql.snap +++ /dev/null @@ -1,12 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\naggregate [\n average salary,\n ct = count\n]\n" ---- -from employees -aggregate [ - average salary, - ct = count, -] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__aggregate-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__aggregate-2.prql.snap deleted file mode 100644 index 9b49b51df2a5..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__aggregate-2.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nderive [avg_sal = average salary]\n" ---- -from employees -derive [avg_sal = average salary] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__append-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__append-0.prql.snap deleted file mode 100644 index cbbd0478001b..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__append-0.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees_1\nappend employees_2\n" ---- -from employees_1 -append employees_2 - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__append-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__append-1.prql.snap deleted file mode 100644 index e2b9a1338479..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__append-1.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees_1\nremove employees_2\n" ---- -from employees_1 -remove employees_2 - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__append-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__append-2.prql.snap deleted file mode 100644 index 1971d287b890..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__append-2.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees_1\nintersect employees_2\n" ---- -from employees_1 -intersect employees_2 - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__derive-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__derive-0.prql.snap deleted file mode 100644 index 183b59f98112..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__derive-0.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nderive gross_salary = salary + payroll_tax\n" ---- -from employees -derive gross_salary = salary + payroll_tax - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__filter-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__filter-0.prql.snap deleted file mode 100644 index bd5e2c425e25..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__filter-0.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nfilter age > 25\n" ---- -from employees -filter age > 25 - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__filter-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__filter-1.prql.snap deleted file mode 100644 index a6cb5b5b569e..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__filter-1.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nfilter (age > 25 or department != \"IT\")\n" ---- -from employees -filter age > 25 or department != "IT" - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__filter-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__filter-2.prql.snap deleted file mode 100644 index d3b04cd4de31..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__filter-2.prql.snap +++ /dev/null @@ -1,12 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nfilter (age | in 25..40)\n" ---- -from employees -filter ( - age - in 25..40 -) - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__from-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__from-0.prql.snap deleted file mode 100644 index 8ef6dce0bb66..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__from-0.prql.snap +++ /dev/null @@ -1,8 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\n" ---- -from employees - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__from-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__from-1.prql.snap deleted file mode 100644 index ef1312a86941..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__from-1.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from e = employees\nselect e.first_name\n" ---- -from e = employees -select e.first_name - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__from_text-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__from_text-2.prql.snap deleted file mode 100644 index da17c3b1fe6f..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__from_text-2.prql.snap +++ /dev/null @@ -1,32 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "let x = from_text format:json \"\"\"{\n \"columns\": [\"a\", \"b\", \"c\"],\n \"data\": [\n [1, \"x\", false],\n [4, \"y\", null]\n ]\n}\"\"\"\n\nlet y = from_text format:json \"\"\"\n [\n {\"a\": 1, \"m\": \"5\"},\n {\"a\": 4, \"n\": \"6\"}\n ]\n\"\"\"\n\nfrom x | join y [==a]\n" ---- -let x = ( - from_text format:json '{ - "columns": ["a", "b", "c"], - "data": [ - [1, "x", false], - [4, "y", null] - ] -}' -) - - - -let y = ( - from_text format:json ' - [ - {"a": 1, "m": "5"}, - {"a": 4, "n": "6"} - ] -' -) - - - -from x -join y [==a] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__group-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__group-1.prql.snap deleted file mode 100644 index 2517396a1418..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__group-1.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nsort join_date\ntake 1\n" ---- -from employees -sort join_date -take 1 - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__group-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__group-2.prql.snap deleted file mode 100644 index 11467687bbbb..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__group-2.prql.snap +++ /dev/null @@ -1,12 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\ngroup role (\n sort join_date # taken from above\n take 1\n)\n" ---- -from employees -group role ( - sort join_date - take 1 -) - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__join-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__join-2.prql.snap deleted file mode 100644 index ba833fa01b02..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__join-2.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\njoin positions [==emp_no]\n" ---- -from employees -join positions [==emp_no] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__select-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__select-0.prql.snap deleted file mode 100644 index ef3e65965333..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__select-0.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nselect name = f\"{first_name} {last_name}\"\n" ---- -from employees -select name = f"{first_name} {last_name}" - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__select-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__select-2.prql.snap deleted file mode 100644 index 56e49df27e11..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__select-2.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nselect first_name\n" ---- -from employees -select first_name - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__select-3.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__select-3.prql.snap deleted file mode 100644 index 059b92276754..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__select-3.prql.snap +++ /dev/null @@ -1,12 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from e=employees\nselect [e.first_name, e.last_name]\n" ---- -from e = employees -select [ - e.first_name, - e.last_name, -] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__select-6.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__select-6.prql.snap deleted file mode 100644 index 19b65db61c48..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__select-6.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from artists\nderive nick = name\nselect ![artists.*]\n" ---- -from artists -derive nick = name -select not [artists.`*`] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__sort-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__sort-0.prql.snap deleted file mode 100644 index cb41ef4b5ddb..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__sort-0.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nsort age\n" ---- -from employees -sort age - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__sort-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__sort-1.prql.snap deleted file mode 100644 index 12203dcc78d3..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__sort-1.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nsort [-age]\n" ---- -from employees -sort [-age] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__sort-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__sort-2.prql.snap deleted file mode 100644 index 23c2050900c8..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__sort-2.prql.snap +++ /dev/null @@ -1,13 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nsort [age, -tenure, +salary]\n" ---- -from employees -sort [ - age, - -tenure, - salary, -] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__sort-3.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__sort-3.prql.snap deleted file mode 100644 index 01b0d75eb4e3..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__sort-3.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nsort [s\"substr({first_name}, 2, 5)\"]\n" ---- -from employees -sort [s"substr({first_name}, 2, 5)"] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__sort-5.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__sort-5.prql.snap deleted file mode 100644 index 405c461df7e4..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__sort-5.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nsort tenure\njoin locations [==employee_id]\n" ---- -from employees -sort tenure -join locations [==employee_id] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__take-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__take-0.prql.snap deleted file mode 100644 index 4c39e0cddcea..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__take-0.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\ntake 10\n" ---- -from employees -take 10 - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__take-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__take-1.prql.snap deleted file mode 100644 index b68c1920a669..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__take-1.prql.snap +++ /dev/null @@ -1,13 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from orders\nsort [-value, date]\ntake 101..110\n" ---- -from orders -sort [ - -value, - date, -] -take 101..110 - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__window-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__window-2.prql.snap deleted file mode 100644 index dc3037c993b3..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__window-2.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nsort age\nderive rnk = rank\n" ---- -from employees -sort age -derive rnk = rank - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__window-3.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__window-3.prql.snap deleted file mode 100644 index b71455102a11..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__window-3.prql.snap +++ /dev/null @@ -1,12 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\ngroup department (\n sort age\n derive rnk = rank\n)\n" ---- -from employees -group department ( - sort age - derive rnk = rank -) - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__window-4.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__window-4.prql.snap deleted file mode 100644 index 9e104fbe34a9..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__window-4.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nfilter salary < (average salary)\n" ---- -from employees -filter salary < ( average salary ) - - - From d878788fc84cef86d42f958039451205b8204123 Mon Sep 17 00:00:00 2001 From: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Date: Sun, 19 Feb 2023 19:47:37 -0800 Subject: [PATCH 012/106] build: Disable prql-elixir on Mac (#1902) * build: Disable prql-elixir on Mac A temporary pause on building `prql-elixir` on Mac, as it's causing some build caching issues, as described in the Readme There are lots of ways to re-enable when we're ready. * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .cargo/config.toml | 7 ---- .github/workflows/test-elixir.yaml | 3 +- Taskfile.yml | 40 +++++++--------------- book/book.toml | 5 +-- prql-compiler/Cargo.toml | 2 +- prql-elixir/README.md | 31 +++++++++++++++++ prql-elixir/native/prql/.cargo/config.toml | 3 ++ prql-elixir/native/prql/Cargo.toml | 6 ++-- prql-elixir/native/prql/src/lib.rs | 2 ++ 9 files changed, 57 insertions(+), 42 deletions(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index 22fe7e245bd6..4ec2f3b86203 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,9 +1,2 @@ [target.wasm32-unknown-unknown] runner = 'wasm-bindgen-test-runner' - -[target.'cfg(target_os = "macos")'] -# Required for prql-elixir on Mac -rustflags = [ - "-C", "link-arg=-undefined", - "-C", "link-arg=dynamic_lookup", -] diff --git a/.github/workflows/test-elixir.yaml b/.github/workflows/test-elixir.yaml index 5c091d8e3543..31d4c9caaea9 100644 --- a/.github/workflows/test-elixir.yaml +++ b/.github/workflows/test-elixir.yaml @@ -25,7 +25,8 @@ jobs: test: strategy: matrix: - os: [ubuntu-latest, windows-latest, macos-latest] + # Currently disabling mac tests, see prql-elixir/readme.md for more details. + os: [ubuntu-latest, windows-latest] otp: ["25.1.2"] elixir: ["1.14.2"] runs-on: ${{matrix.os}} diff --git a/Taskfile.yml b/Taskfile.yml index bcdf31a59a4b..ec901be0fa55 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -64,7 +64,7 @@ tasks: # Can't install atm with `--locked` - cargo install mdbook-footnote - cmd: | - [ "$(which default-target)" ] || echo "🔴 Can't find a binary that cargo just installed. Is the cargo bin path (generally at ~/.cargo/bin) on the \$PATH?" + [ "$(which cargo-insta)" ] || echo "🔴 Can't find a binary that cargo just installed. Is the cargo bin path (generally at ~/.cargo/bin) on the \$PATH?" silent: true install-maturin: @@ -151,17 +151,9 @@ tasks: Build everything. Running this isn't required when developing; it's for caching or as a reference. - vars: - default_target: - sh: default-target - targets: | - {{ .default_target }} - wasm32-unknown-unknown cmds: - - | - {{ range ( .targets | trim | splitLines ) -}} - cargo build --all-targets --target={{.}} - {{ end -}} + - cargo build --all-targets --target=wasm32-unknown-unknown + - cargo build --all-targets - task: build-web test-all: @@ -177,14 +169,10 @@ tasks: - task: test-rust - task: build-all - task: test-js - - task: test-elixir - pre-commit run -a test-rust: desc: Test all rust code, accepting snapshots. - vars: - default_target: - sh: default-target # Commenting out the ability to watch, since Task seems to trip over itself, # starting a new process before the old one has finished when a process # changes output files. @@ -212,13 +200,11 @@ tasks: # tests to extract them, which include compiling prql-compiler, c) not # fail other compilation steps if they can't be extracted. - cargo insta test --accept -p mdbook-prql --test snapshot - --target={{.default_target}} # Only delete unreferenced snapshots on the default target — lots are # excluded under wasm. Note that this will also over-delete on Windows. # Note that we need to pass the target explicitly to manage # https://github.com/rust-lang/cargo/issues/8899 - - cargo insta test --accept --target={{.default_target}} - --unreferenced=auto + - cargo insta test --accept --unreferenced=auto - cargo insta test --accept --target=wasm32-unknown-unknown # We build the book too, because that acts as a test - cd book && mdbook build @@ -248,7 +234,6 @@ tasks: - "prql-compiler/**/*.snap" cmds: - cargo insta test --accept -p prql-compiler --lib - --target=$(default-target) build-web: desc: Build the website, including the book & playground. @@ -276,14 +261,15 @@ tasks: - npm run build - npm cit - test-elixir: - dir: prql-elixir - cmds: - # We could move this line into an `install` task - - mix local.hex --force - - mix deps.get --force - - mix compile - - mix test + # Currently disabled; see prql-elixir/README.md for details + # test-elixir: + # dir: prql-elixir + # cmds: + # # We could move this line into an `install` task + # - mix local.hex --force + # - mix deps.get --force + # - mix compile + # - mix test run-website: desc: Build & serve the static website. diff --git a/book/book.toml b/book/book.toml index f503dc2bb7a9..6849dde897c5 100644 --- a/book/book.toml +++ b/book/book.toml @@ -13,10 +13,7 @@ git-repository-url = "https://github.com/PRQL/prql" # This is required because mdbook-prql isn't necessarily installed; maybe # there's a better way. # -# We put the target directory in `target-book` because of -# https://github.com/rust-lang/cargo/issues/8899, as an alternative to requiring -# `default-target` to be installed. -command = "cargo run --bin mdbook-prql --target-dir=target-book" +command = "cargo run --bin mdbook-prql" [preprocessor.admonish] assets_version = "2.0.0" # do not edit: managed by `mdbook-admonish install` diff --git a/prql-compiler/Cargo.toml b/prql-compiler/Cargo.toml index 296cf5b954fe..cd74ecc67c24 100644 --- a/prql-compiler/Cargo.toml +++ b/prql-compiler/Cargo.toml @@ -40,9 +40,9 @@ insta = {version = "1.28", features = ["colors", "glob", "yaml"]} # For integration tests [target.'cfg(not(target_family="wasm"))'.dev-dependencies] chrono = "0.4" -pretty_assertions = "1.3.0" criterion = "0.4.0" postgres = "0.19.3" +pretty_assertions = "1.3.0" rusqlite = {version = "0.28.0", features = ["bundled", "csvtab"]} # Re-enable on windows when duckdb supports it diff --git a/prql-elixir/README.md b/prql-elixir/README.md index 2ff3e499141c..ed30ffa0ab2e 100644 --- a/prql-elixir/README.md +++ b/prql-elixir/README.md @@ -38,3 +38,34 @@ crate from this repo: Future work includes publishing pre-compiled artifacts, so Elixir projects can run PRQL without needing a Rust toolchain. + +## Mac + +We currently don't enable compilation for Mac. This is possible to enable, but +causes some issues with cargo's compilation cache. Briefly: it requires +`RUST_FLAGS` to be set, and because of + & +, any compilation of a different +target will bust the cache. + +The possible future workarounds include: + +- Passing `--target=aarch64-apple-darwin` to every cargo call, which is + inconvenient and can be difficult in some situations; e.g. Rust Analyzer. This + disables passing `RUST_FLAGS` (I'm actually unclear why `prql-elixir` builds + successfully in that case...) +- Directing other cargo calls to different paths, such as `/target-ra` for Rust + Analyzer and `/target-book` for the book building. But one `cargo build` from + the terminal without either the `target` or `target_dir` specified will bust + the cache! +- Never compiling for other targets. But our standard tests run for + `--target=wasm32-unknown-unknown`, so this requires refraining from using + them. +- Removing `prql-elixir` from our workspace, so that `cargo` commands in the + PRQL workspace don't require rust flags. This would work well, but means we + need separate test coverage for this crate, which adds some weight to the + tests. + +If `prql-elixir` becomes more used (for example, we start publishing to Hex, or +Mac developers want to work on it), then we can re-enable and deal with the +caching issues. We can also re-enable them if the `cargo` issue is resolved. diff --git a/prql-elixir/native/prql/.cargo/config.toml b/prql-elixir/native/prql/.cargo/config.toml index 20f03f3d8054..a0a666544142 100644 --- a/prql-elixir/native/prql/.cargo/config.toml +++ b/prql-elixir/native/prql/.cargo/config.toml @@ -1,3 +1,6 @@ +# Note that this doesn't apply when compiling from the workspace root. Because +# we're not currently compiling for Mac, it's also impotent for now. + [target.'cfg(target_os = "macos")'] rustflags = [ "-C", "link-arg=-undefined", diff --git a/prql-elixir/native/prql/Cargo.toml b/prql-elixir/native/prql/Cargo.toml index 51fdb36cc87c..a39a9eee25db 100644 --- a/prql-elixir/native/prql/Cargo.toml +++ b/prql-elixir/native/prql/Cargo.toml @@ -16,6 +16,8 @@ name = "prql" path = "src/lib.rs" [dependencies] -prql-compiler = {path = "../../../prql-compiler", default-features = false, version = "0.5.2" } -[target.'cfg(not(any(target_family="wasm")))'.dependencies] +prql-compiler = {path = "../../../prql-compiler", default-features = false, version = "0.5.2"} + +# See Readme for details on Mac +[target.'cfg(not(any(target_family="wasm", target_os = "macos")))'.dependencies] rustler = "0.27.0" diff --git a/prql-elixir/native/prql/src/lib.rs b/prql-elixir/native/prql/src/lib.rs index 8ff3aeea7303..2a5967eb9ba1 100644 --- a/prql-elixir/native/prql/src/lib.rs +++ b/prql-elixir/native/prql/src/lib.rs @@ -1,3 +1,5 @@ +// See Readme for more information on Mac compiling +#![cfg(not(target_os = "macos"))] // These bindings aren't relevant on wasm #![cfg(not(target_family = "wasm"))] // TODO: unclear why we need this `allow`; it's required in `CompileOptions`, From c186b135ce607fe851e026c037a7ef12cdd228f4 Mon Sep 17 00:00:00 2001 From: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Date: Sun, 19 Feb 2023 20:34:23 -0800 Subject: [PATCH 013/106] test: Refactor book snapshot tests (#1904) * test: Refactor book snapshot tests Re-reverting #1900 --- book/tests/snapshot.rs | 200 +++++++++++------- ...rql@examples__list-equivalence-0.prql.snap | 10 - ...rql@examples__list-equivalence-1.prql.snap | 10 - ..._reference_prql@examples__misc-0.prql.snap | 26 --- ..._reference_prql@examples__misc-1.prql.snap | 13 -- ...rence_prql@examples__variables-0.prql.snap | 32 --- ...rence_prql@examples__variables-1.prql.snap | 19 -- ...rql@internals__functional-lang-0.prql.snap | 11 - ...rql@internals__functional-lang-1.prql.snap | 11 - ...rql@internals__functional-lang-2.prql.snap | 12 -- ...rql@internals__functional-lang-3.prql.snap | 13 -- ...prql@internals__name-resolving-0.prql.snap | 10 - ...ay_reference_prql@introduction-0.prql.snap | 32 --- ...ql@language-features__coalesce-0.prql.snap | 10 - ...uage-features__dates-and-times-0.prql.snap | 10 - ...uage-features__dates-and-times-1.prql.snap | 10 - ...uage-features__dates-and-times-2.prql.snap | 10 - ...uage-features__dates-and-times-3.prql.snap | 10 - ...ql@language-features__distinct-0.prql.snap | 13 -- ...ql@language-features__distinct-1.prql.snap | 13 -- ...ql@language-features__distinct-2.prql.snap | 13 -- ...l@language-features__f-strings-0.prql.snap | 10 - ...l@language-features__f-strings-1.prql.snap | 10 - ...e_prql@language-features__null-0.prql.snap | 11 - ...prql@language-features__ranges-1.prql.snap | 14 -- ...l@language-features__s-strings-0.prql.snap | 10 - ...l@language-features__s-strings-1.prql.snap | 10 - ...age-features__standard-library-0.prql.snap | 20 -- ...rql@language-features__strings-0.prql.snap | 10 - ...rql@language-features__strings-1.prql.snap | 10 - ...rql@language-features__strings-2.prql.snap | 10 - ...rql@language-features__strings-3.prql.snap | 10 - ...rql@language-features__strings-4.prql.snap | 10 - ...prql@language-features__target-0.prql.snap | 15 -- ...prql@language-features__target-1.prql.snap | 15 -- ...prql@language-features__target-2.prql.snap | 13 -- ...erence_prql@queries__pipelines-0.prql.snap | 9 - ...erence_prql@queries__pipelines-1.prql.snap | 10 - ...erence_prql@queries__variables-0.prql.snap | 18 -- ...display_reference_prql@syntax-11.prql.snap | 9 - ...display_reference_prql@syntax-13.prql.snap | 9 - ...display_reference_prql@syntax-14.prql.snap | 10 - ..._display_reference_prql@syntax-3.prql.snap | 10 - ..._display_reference_prql@syntax-4.prql.snap | 10 - ..._display_reference_prql@syntax-6.prql.snap | 40 ---- ..._display_reference_prql@syntax-8.prql.snap | 10 - ...nce_prql@transforms__aggregate-0.prql.snap | 13 -- ...nce_prql@transforms__aggregate-2.prql.snap | 10 - ...erence_prql@transforms__append-0.prql.snap | 10 - ...erence_prql@transforms__append-1.prql.snap | 10 - ...erence_prql@transforms__append-2.prql.snap | 10 - ...erence_prql@transforms__derive-0.prql.snap | 10 - ...erence_prql@transforms__filter-0.prql.snap | 10 - ...erence_prql@transforms__filter-1.prql.snap | 10 - ...erence_prql@transforms__filter-2.prql.snap | 13 -- ...eference_prql@transforms__from-0.prql.snap | 9 - ...eference_prql@transforms__from-1.prql.snap | 10 - ...nce_prql@transforms__from_text-2.prql.snap | 33 --- ...ference_prql@transforms__group-1.prql.snap | 11 - ...ference_prql@transforms__group-2.prql.snap | 13 -- ...eference_prql@transforms__join-2.prql.snap | 10 - ...erence_prql@transforms__select-0.prql.snap | 10 - ...erence_prql@transforms__select-2.prql.snap | 10 - ...erence_prql@transforms__select-3.prql.snap | 13 -- ...erence_prql@transforms__select-6.prql.snap | 11 - ...eference_prql@transforms__sort-0.prql.snap | 10 - ...eference_prql@transforms__sort-1.prql.snap | 10 - ...eference_prql@transforms__sort-2.prql.snap | 14 -- ...eference_prql@transforms__sort-3.prql.snap | 10 - ...eference_prql@transforms__sort-5.prql.snap | 11 - ...eference_prql@transforms__take-0.prql.snap | 10 - ...eference_prql@transforms__take-1.prql.snap | 14 -- ...erence_prql@transforms__window-2.prql.snap | 11 - ...erence_prql@transforms__window-3.prql.snap | 13 -- ...erence_prql@transforms__window-4.prql.snap | 10 - ...t__tests__prql__examples__cte-0.prql.snap} | 3 +- ...ts__prql__examples__employees-0.prql.snap} | 3 +- ...ts__prql__examples__employees-1.prql.snap} | 3 +- ...ts__prql__examples__employees-2.prql.snap} | 3 +- ...ts__prql__examples__employees-3.prql.snap} | 3 +- ...ql__examples__list-equivalence-0.prql.snap | 9 + ...ql__examples__list-equivalence-1.prql.snap | 9 + ...l__examples__list-equivalence-2.prql.snap} | 3 +- ...l__examples__list-equivalence-3.prql.snap} | 3 +- ...t__tests__prql__examples__misc-0.prql.snap | 25 +++ ...t__tests__prql__examples__misc-1.prql.snap | 12 ++ ...sts__prql__examples__variables-0.prql.snap | 31 +++ ...sts__prql__examples__variables-1.prql.snap | 18 ++ ...ql__internals__functional-lang-0.prql.snap | 10 + ...ql__internals__functional-lang-1.prql.snap | 10 + ...ql__internals__functional-lang-2.prql.snap | 11 + ...ql__internals__functional-lang-3.prql.snap | 12 ++ ...rql__internals__name-resolving-0.prql.snap | 9 + ...ql__internals__name-resolving-1.prql.snap} | 3 +- ...hot__tests__prql__introduction-0.prql.snap | 31 +++ ...l__language-features__coalesce-0.prql.snap | 9 + ...uage-features__dates-and-times-0.prql.snap | 9 + ...uage-features__dates-and-times-1.prql.snap | 9 + ...uage-features__dates-and-times-2.prql.snap | 9 + ...uage-features__dates-and-times-3.prql.snap | 9 + ...l__language-features__distinct-0.prql.snap | 12 ++ ...l__language-features__distinct-1.prql.snap | 12 ++ ...l__language-features__distinct-2.prql.snap | 12 ++ ...__language-features__f-strings-0.prql.snap | 9 + ...__language-features__f-strings-1.prql.snap | 9 + ..._prql__language-features__null-0.prql.snap | 10 + ...ql__language-features__ranges-0.prql.snap} | 3 +- ...rql__language-features__ranges-1.prql.snap | 13 ++ ...__language-features__s-strings-0.prql.snap | 9 + ...__language-features__s-strings-1.prql.snap | 9 + ..._language-features__s-strings-2.prql.snap} | 3 +- ..._language-features__s-strings-3.prql.snap} | 3 +- ..._language-features__s-strings-4.prql.snap} | 3 +- ..._language-features__s-strings-5.prql.snap} | 3 +- ..._language-features__s-strings-6.prql.snap} | 3 +- ...age-features__standard-library-0.prql.snap | 19 ++ ...ql__language-features__strings-0.prql.snap | 9 + ...ql__language-features__strings-1.prql.snap | 9 + ...ql__language-features__strings-2.prql.snap | 9 + ...ql__language-features__strings-3.prql.snap | 9 + ...ql__language-features__strings-4.prql.snap | 9 + ...ql__language-features__switch-0.prql.snap} | 3 +- ...ql__language-features__switch-1.prql.snap} | 3 +- ...rql__language-features__target-0.prql.snap | 14 ++ ...rql__language-features__target-1.prql.snap | 14 ++ ...rql__language-features__target-2.prql.snap | 12 ++ ...sts__prql__queries__functions-0.prql.snap} | 3 +- ...sts__prql__queries__functions-1.prql.snap} | 3 +- ...sts__prql__queries__functions-2.prql.snap} | 3 +- ...sts__prql__queries__functions-3.prql.snap} | 3 +- ...sts__prql__queries__functions-4.prql.snap} | 3 +- ...ests__prql__queries__pipelines-0.prql.snap | 8 + ...ests__prql__queries__pipelines-1.prql.snap | 9 + ...sts__prql__queries__pipelines-2.prql.snap} | 3 +- ...ests__prql__queries__variables-0.prql.snap | 17 ++ ...sts__prql__queries__variables-1.prql.snap} | 3 +- ...snapshot__tests__prql__syntax-0.prql.snap} | 3 +- ...snapshot__tests__prql__syntax-1.prql.snap} | 3 +- ...napshot__tests__prql__syntax-10.prql.snap} | 3 +- ...snapshot__tests__prql__syntax-11.prql.snap | 8 + ...napshot__tests__prql__syntax-12.prql.snap} | 3 +- ...snapshot__tests__prql__syntax-13.prql.snap | 8 + ...snapshot__tests__prql__syntax-14.prql.snap | 9 + ...napshot__tests__prql__syntax-15.prql.snap} | 3 +- ...snapshot__tests__prql__syntax-2.prql.snap} | 3 +- .../snapshot__tests__prql__syntax-3.prql.snap | 9 + .../snapshot__tests__prql__syntax-4.prql.snap | 9 + ...snapshot__tests__prql__syntax-5.prql.snap} | 3 +- .../snapshot__tests__prql__syntax-6.prql.snap | 39 ++++ ...snapshot__tests__prql__syntax-7.prql.snap} | 3 +- .../snapshot__tests__prql__syntax-8.prql.snap | 9 + ...snapshot__tests__prql__syntax-9.prql.snap} | 3 +- ...s__prql__transforms__aggregate-0.prql.snap | 12 ++ ...__prql__transforms__aggregate-1.prql.snap} | 3 +- ...s__prql__transforms__aggregate-2.prql.snap | 9 + ...ests__prql__transforms__append-0.prql.snap | 9 + ...ests__prql__transforms__append-1.prql.snap | 9 + ...ests__prql__transforms__append-2.prql.snap | 9 + ...ests__prql__transforms__derive-0.prql.snap | 9 + ...sts__prql__transforms__derive-1.prql.snap} | 3 +- ...ests__prql__transforms__filter-0.prql.snap | 9 + ...ests__prql__transforms__filter-1.prql.snap | 9 + ...ests__prql__transforms__filter-2.prql.snap | 12 ++ ..._tests__prql__transforms__from-0.prql.snap | 8 + ..._tests__prql__transforms__from-1.prql.snap | 9 + ...__prql__transforms__from_text-0.prql.snap} | 3 +- ...__prql__transforms__from_text-1.prql.snap} | 3 +- ...s__prql__transforms__from_text-2.prql.snap | 32 +++ ...ests__prql__transforms__group-0.prql.snap} | 3 +- ...tests__prql__transforms__group-1.prql.snap | 10 + ...tests__prql__transforms__group-2.prql.snap | 12 ++ ...tests__prql__transforms__join-0.prql.snap} | 3 +- ...tests__prql__transforms__join-1.prql.snap} | 3 +- ..._tests__prql__transforms__join-2.prql.snap | 9 + ...ests__prql__transforms__select-0.prql.snap | 9 + ...sts__prql__transforms__select-1.prql.snap} | 3 +- ...ests__prql__transforms__select-2.prql.snap | 9 + ...ests__prql__transforms__select-3.prql.snap | 12 ++ ...sts__prql__transforms__select-4.prql.snap} | 3 +- ...sts__prql__transforms__select-5.prql.snap} | 3 +- ...ests__prql__transforms__select-6.prql.snap | 10 + ..._tests__prql__transforms__sort-0.prql.snap | 9 + ..._tests__prql__transforms__sort-1.prql.snap | 9 + ..._tests__prql__transforms__sort-2.prql.snap | 13 ++ ..._tests__prql__transforms__sort-3.prql.snap | 9 + ...tests__prql__transforms__sort-4.prql.snap} | 3 +- ..._tests__prql__transforms__sort-5.prql.snap | 10 + ..._tests__prql__transforms__take-0.prql.snap | 9 + ..._tests__prql__transforms__take-1.prql.snap | 13 ++ ...sts__prql__transforms__window-0.prql.snap} | 3 +- ...sts__prql__transforms__window-1.prql.snap} | 3 +- ...ests__prql__transforms__window-2.prql.snap | 10 + ...ests__prql__transforms__window-3.prql.snap | 12 ++ ...ests__prql__transforms__window-4.prql.snap | 9 + 194 files changed, 1029 insertions(+), 1112 deletions(-) delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@examples__list-equivalence-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@examples__list-equivalence-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@examples__misc-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@examples__misc-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@examples__variables-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@examples__variables-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@internals__functional-lang-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@internals__functional-lang-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@internals__functional-lang-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@internals__functional-lang-3.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@internals__name-resolving-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@introduction-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__coalesce-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__dates-and-times-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__dates-and-times-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__dates-and-times-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__dates-and-times-3.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__distinct-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__distinct-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__distinct-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__f-strings-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__f-strings-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__null-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__ranges-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__standard-library-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__strings-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__strings-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__strings-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__strings-3.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__strings-4.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__target-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__target-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@language-features__target-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@queries__pipelines-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@queries__pipelines-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@queries__variables-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@syntax-11.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@syntax-13.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@syntax-14.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@syntax-3.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@syntax-4.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@syntax-6.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@syntax-8.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__aggregate-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__aggregate-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__append-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__append-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__append-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__derive-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__filter-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__filter-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__filter-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from_text-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__group-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__group-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__join-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-3.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-6.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-3.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-5.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__take-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__take-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__window-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__window-3.prql.snap delete mode 100644 book/tests/snapshots/snapshot__run_display_reference_prql@transforms__window-4.prql.snap rename book/tests/snapshots/{snapshot__run_display_reference_prql@examples__cte-0.prql.snap => snapshot__tests__prql__examples__cte-0.prql.snap} (51%) rename book/tests/snapshots/{snapshot__run_display_reference_prql@examples__employees-0.prql.snap => snapshot__tests__prql__examples__employees-0.prql.snap} (52%) rename book/tests/snapshots/{snapshot__run_display_reference_prql@examples__employees-1.prql.snap => snapshot__tests__prql__examples__employees-1.prql.snap} (51%) rename book/tests/snapshots/{snapshot__run_display_reference_prql@examples__employees-2.prql.snap => snapshot__tests__prql__examples__employees-2.prql.snap} (50%) rename book/tests/snapshots/{snapshot__run_display_reference_prql@examples__employees-3.prql.snap => snapshot__tests__prql__examples__employees-3.prql.snap} (52%) create mode 100644 book/tests/snapshots/snapshot__tests__prql__examples__list-equivalence-0.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__examples__list-equivalence-1.prql.snap rename book/tests/snapshots/{snapshot__run_display_reference_prql@examples__list-equivalence-2.prql.snap => snapshot__tests__prql__examples__list-equivalence-2.prql.snap} (54%) rename book/tests/snapshots/{snapshot__run_display_reference_prql@examples__list-equivalence-3.prql.snap => snapshot__tests__prql__examples__list-equivalence-3.prql.snap} (54%) create mode 100644 book/tests/snapshots/snapshot__tests__prql__examples__misc-0.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__examples__misc-1.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__examples__variables-0.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__examples__variables-1.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-0.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-1.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-2.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-3.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__internals__name-resolving-0.prql.snap rename book/tests/snapshots/{snapshot__run_display_reference_prql@internals__name-resolving-1.prql.snap => snapshot__tests__prql__internals__name-resolving-1.prql.snap} (56%) create mode 100644 book/tests/snapshots/snapshot__tests__prql__introduction-0.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__coalesce-0.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-0.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-1.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-2.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-3.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__distinct-0.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__distinct-1.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__distinct-2.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__f-strings-0.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__f-strings-1.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__null-0.prql.snap rename book/tests/snapshots/{snapshot__run_display_reference_prql@language-features__ranges-0.prql.snap => snapshot__tests__prql__language-features__ranges-0.prql.snap} (55%) create mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__ranges-1.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-0.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-1.prql.snap rename book/tests/snapshots/{snapshot__run_display_reference_prql@language-features__s-strings-2.prql.snap => snapshot__tests__prql__language-features__s-strings-2.prql.snap} (51%) rename book/tests/snapshots/{snapshot__run_display_reference_prql@language-features__s-strings-3.prql.snap => snapshot__tests__prql__language-features__s-strings-3.prql.snap} (53%) rename book/tests/snapshots/{snapshot__run_display_reference_prql@language-features__s-strings-4.prql.snap => snapshot__tests__prql__language-features__s-strings-4.prql.snap} (51%) rename book/tests/snapshots/{snapshot__run_display_reference_prql@language-features__s-strings-5.prql.snap => snapshot__tests__prql__language-features__s-strings-5.prql.snap} (53%) rename book/tests/snapshots/{snapshot__run_display_reference_prql@language-features__s-strings-6.prql.snap => snapshot__tests__prql__language-features__s-strings-6.prql.snap} (53%) create mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__standard-library-0.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__strings-0.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__strings-1.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__strings-2.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__strings-3.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__strings-4.prql.snap rename book/tests/snapshots/{snapshot__run_display_reference_prql@language-features__switch-0.prql.snap => snapshot__tests__prql__language-features__switch-0.prql.snap} (53%) rename book/tests/snapshots/{snapshot__run_display_reference_prql@language-features__switch-1.prql.snap => snapshot__tests__prql__language-features__switch-1.prql.snap} (51%) create mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__target-0.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__target-1.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__target-2.prql.snap rename book/tests/snapshots/{snapshot__run_display_reference_prql@queries__functions-0.prql.snap => snapshot__tests__prql__queries__functions-0.prql.snap} (54%) rename book/tests/snapshots/{snapshot__run_display_reference_prql@queries__functions-1.prql.snap => snapshot__tests__prql__queries__functions-1.prql.snap} (51%) rename book/tests/snapshots/{snapshot__run_display_reference_prql@queries__functions-2.prql.snap => snapshot__tests__prql__queries__functions-2.prql.snap} (52%) rename book/tests/snapshots/{snapshot__run_display_reference_prql@queries__functions-3.prql.snap => snapshot__tests__prql__queries__functions-3.prql.snap} (54%) rename book/tests/snapshots/{snapshot__run_display_reference_prql@queries__functions-4.prql.snap => snapshot__tests__prql__queries__functions-4.prql.snap} (52%) create mode 100644 book/tests/snapshots/snapshot__tests__prql__queries__pipelines-0.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__queries__pipelines-1.prql.snap rename book/tests/snapshots/{snapshot__run_display_reference_prql@queries__pipelines-2.prql.snap => snapshot__tests__prql__queries__pipelines-2.prql.snap} (53%) create mode 100644 book/tests/snapshots/snapshot__tests__prql__queries__variables-0.prql.snap rename book/tests/snapshots/{snapshot__run_display_reference_prql@queries__variables-1.prql.snap => snapshot__tests__prql__queries__variables-1.prql.snap} (51%) rename book/tests/snapshots/{snapshot__run_display_reference_prql@syntax-0.prql.snap => snapshot__tests__prql__syntax-0.prql.snap} (55%) rename book/tests/snapshots/{snapshot__run_display_reference_prql@syntax-1.prql.snap => snapshot__tests__prql__syntax-1.prql.snap} (55%) rename book/tests/snapshots/{snapshot__run_display_reference_prql@syntax-10.prql.snap => snapshot__tests__prql__syntax-10.prql.snap} (50%) create mode 100644 book/tests/snapshots/snapshot__tests__prql__syntax-11.prql.snap rename book/tests/snapshots/{snapshot__run_display_reference_prql@syntax-12.prql.snap => snapshot__tests__prql__syntax-12.prql.snap} (55%) create mode 100644 book/tests/snapshots/snapshot__tests__prql__syntax-13.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__syntax-14.prql.snap rename book/tests/snapshots/{snapshot__run_display_reference_prql@syntax-15.prql.snap => snapshot__tests__prql__syntax-15.prql.snap} (50%) rename book/tests/snapshots/{snapshot__run_display_reference_prql@syntax-2.prql.snap => snapshot__tests__prql__syntax-2.prql.snap} (54%) create mode 100644 book/tests/snapshots/snapshot__tests__prql__syntax-3.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__syntax-4.prql.snap rename book/tests/snapshots/{snapshot__run_display_reference_prql@syntax-5.prql.snap => snapshot__tests__prql__syntax-5.prql.snap} (53%) create mode 100644 book/tests/snapshots/snapshot__tests__prql__syntax-6.prql.snap rename book/tests/snapshots/{snapshot__run_display_reference_prql@syntax-7.prql.snap => snapshot__tests__prql__syntax-7.prql.snap} (54%) create mode 100644 book/tests/snapshots/snapshot__tests__prql__syntax-8.prql.snap rename book/tests/snapshots/{snapshot__run_display_reference_prql@syntax-9.prql.snap => snapshot__tests__prql__syntax-9.prql.snap} (50%) create mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__aggregate-0.prql.snap rename book/tests/snapshots/{snapshot__run_display_reference_prql@transforms__aggregate-1.prql.snap => snapshot__tests__prql__transforms__aggregate-1.prql.snap} (54%) create mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__aggregate-2.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__append-0.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__append-1.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__append-2.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__derive-0.prql.snap rename book/tests/snapshots/{snapshot__run_display_reference_prql@transforms__derive-1.prql.snap => snapshot__tests__prql__transforms__derive-1.prql.snap} (54%) create mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__filter-0.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__filter-1.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__filter-2.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__from-0.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__from-1.prql.snap rename book/tests/snapshots/{snapshot__run_display_reference_prql@transforms__from_text-0.prql.snap => snapshot__tests__prql__transforms__from_text-0.prql.snap} (50%) rename book/tests/snapshots/{snapshot__run_display_reference_prql@transforms__from_text-1.prql.snap => snapshot__tests__prql__transforms__from_text-1.prql.snap} (51%) create mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__from_text-2.prql.snap rename book/tests/snapshots/{snapshot__run_display_reference_prql@transforms__group-0.prql.snap => snapshot__tests__prql__transforms__group-0.prql.snap} (54%) create mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__group-1.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__group-2.prql.snap rename book/tests/snapshots/{snapshot__run_display_reference_prql@transforms__join-0.prql.snap => snapshot__tests__prql__transforms__join-0.prql.snap} (52%) rename book/tests/snapshots/{snapshot__run_display_reference_prql@transforms__join-1.prql.snap => snapshot__tests__prql__transforms__join-1.prql.snap} (51%) create mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__join-2.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__select-0.prql.snap rename book/tests/snapshots/{snapshot__run_display_reference_prql@transforms__select-1.prql.snap => snapshot__tests__prql__transforms__select-1.prql.snap} (53%) create mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__select-2.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__select-3.prql.snap rename book/tests/snapshots/{snapshot__run_display_reference_prql@transforms__select-4.prql.snap => snapshot__tests__prql__transforms__select-4.prql.snap} (51%) rename book/tests/snapshots/{snapshot__run_display_reference_prql@transforms__select-5.prql.snap => snapshot__tests__prql__transforms__select-5.prql.snap} (55%) create mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__select-6.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__sort-0.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__sort-1.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__sort-2.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__sort-3.prql.snap rename book/tests/snapshots/{snapshot__run_display_reference_prql@transforms__sort-4.prql.snap => snapshot__tests__prql__transforms__sort-4.prql.snap} (50%) create mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__sort-5.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__take-0.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__take-1.prql.snap rename book/tests/snapshots/{snapshot__run_display_reference_prql@transforms__window-0.prql.snap => snapshot__tests__prql__transforms__window-0.prql.snap} (52%) rename book/tests/snapshots/{snapshot__run_display_reference_prql@transforms__window-1.prql.snap => snapshot__tests__prql__transforms__window-1.prql.snap} (51%) create mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__window-2.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__window-3.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__window-4.prql.snap diff --git a/book/tests/snapshot.rs b/book/tests/snapshot.rs index e86b59ae20fc..384b5dd578a4 100644 --- a/book/tests/snapshot.rs +++ b/book/tests/snapshot.rs @@ -1,8 +1,12 @@ #![cfg(not(target_family = "wasm"))] /// This test: -/// - Extracts PRQL code blocks into the `examples` path. -/// - Converts them to SQL using insta, raising an error if there's a diff. -/// - Replaces the PRQL code block with a comparison table. +/// - Extracts PRQL code blocks into files in the `examples` path, skipping +/// where the matching example is already present. +/// - Compiles them to SQL, comparing to a snapshot. Insta raises an error if +/// there's a diff. +/// +/// Then, when the book is built, the PRQL code block in the book is replaced +/// with a comparison table. /// /// We also use this test to run tests on our Display trait output, currently as /// another set of snapshots (more comments inline). @@ -18,69 +22,39 @@ // us. They introduce a bunch of non-rust dependencies, which is not ideal, but // passable. They don't let us customize our formatting (e.g. in a table). // -use anyhow::{bail, Result}; +use anyhow::{bail, Error, Result}; use globset::Glob; -use insta::{assert_display_snapshot, assert_snapshot, glob}; +use insta::{assert_snapshot, glob}; use log::warn; use prql_compiler::*; -use pulldown_cmark::{CodeBlockKind, Event, Parser, Tag}; -use std::fs; -use std::path::Path; +use std::path::{Path, PathBuf}; +use std::{collections::HashMap, fs}; use walkdir::WalkDir; #[test] -fn run_examples() -> Result<()> { - // TODO: In CI this could pass by replacing incorrect files. To catch that, - // we could check if there are any diffs after this has run? - - // Note that on windows, markdown is read differently, and so - // writing on Windows. ref https://github.com/PRQL/prql/issues/356 - #[cfg(not(target_family = "windows"))] - write_reference_prql()?; - run_reference_prql(); - - // TODO: Currently we run this in the same test, since we need the - // `write_reference_prql` function to have been run. If we could iterate - // over the PRQL examples without writing them to disk, we could run this as - // a separate test. (Though then we'd lose the deferred failures feature - // that insta's `glob!` macro provides.) - run_display_reference_prql(); +fn test_examples() -> Result<()> { + // Note that on windows, markdown is read differently, and so we don't write + // on Windows (we write from the same place we read as a workaround). ref + // https://github.com/PRQL/prql/issues/356 + + write_prql_examples(collect_book_examples()?)?; + test_prql_examples(); Ok(()) } -/// Extract reference examples from the PRQL docs and write them to the -/// `tests/prql` path, one in each file. -// We could alternatively have used something like -// https://github.com/earldouglas/codedown, but it's not much code, and it -// requires no dependencies. -// -// We allow dead_code because of the window issue described above. (Can we allow -// it only for windows?) -#[allow(dead_code)] -fn write_reference_prql() -> Result<()> { - // Remove old .prql files, since we're going to rewrite them, and we don't want - // old files which wouldn't be rewritten from hanging around. - // We use `trash`, since we don't want to be removing files with test code - // in case there's a bug. - // - // A more elegant approach would be to keep a list of the files and remove - // the ones we don't write. - - let examples_path = Path::new("tests/prql"); - if examples_path.exists() { - trash::delete(Path::new("tests/prql")).unwrap_or_else(|e| { - warn!("Failed to delete old examples: {}", e); - }); - } +const ROOT_EXAMPLES_PATH: &str = "tests/prql"; +/// Collect all the PRQL examples in the book, as a map of . +#[cfg(not(target_family = "windows"))] +fn collect_book_examples() -> Result> { + use pulldown_cmark::{CodeBlockKind, Event, Parser, Tag}; let glob = Glob::new("**/*.md")?.compile_matcher(); - - WalkDir::new(Path::new("./src/")) + let examples_in_book: HashMap = WalkDir::new(Path::new("./src/")) .into_iter() .flatten() .filter(|x| glob.is_match(x.path())) - .try_for_each(|dir_entry| { + .flat_map(|dir_entry| { let text = fs::read_to_string(dir_entry.path())?; let mut parser = Parser::new(&text); let mut prql_blocks = vec![]; @@ -102,33 +76,90 @@ fn write_reference_prql() -> Result<()> { _ => {} } } - - // Write each one to a new file. - prql_blocks + let snapshot_prefix = &dir_entry + .path() + .strip_prefix("./src/")? + .to_str() + .unwrap() + .trim_end_matches(".md"); + Ok(prql_blocks .iter() .enumerate() - .try_for_each(|(i, example)| { - let file_relative = &dir_entry - .path() - .strip_prefix("./src/")? - .to_str() - .unwrap() - .trim_end_matches(".md"); - let prql_path = format!("tests/prql/{file_relative}-{i}.prql"); - - fs::create_dir_all(Path::new(&prql_path).parent().unwrap())?; - fs::write(prql_path, example.to_string())?; - - Ok::<(), anyhow::Error>(()) - })?; - Ok(()) - })?; + .map(|(i, example)| { + ( + Path::new(&format!("{ROOT_EXAMPLES_PATH}/{snapshot_prefix}-{i}.prql")) + .to_path_buf(), + example.to_string(), + ) + }) + .collect::>()) + }) + .flatten() + .collect(); + + Ok(examples_in_book) +} + +/// Collect examples which we've already written to disk, as a map of . +fn collect_snapshot_examples() -> Result> { + use itertools::Itertools; + let glob = Glob::new("**/*.prql")?.compile_matcher(); + let existing_examples = WalkDir::new(Path::new(ROOT_EXAMPLES_PATH)) + .into_iter() + .flatten() + .filter(|x| glob.is_match(x.path())) + .map(|x| Ok::<_, Error>((x.clone().into_path(), fs::read_to_string(x.path())?))) + .try_collect()?; + + Ok(existing_examples) +} + +// On Windows, we grab them from the written files, because of the markdown issue. +#[cfg(target_family = "windows")] +fn collect_book_examples() -> Result> { + collect_snapshot_examples() +} + +/// Write the passed examples as snapshots to the `tests/prql` path, one in each file. +// We could alternatively have used something like +// https://github.com/earldouglas/codedown, but it's not much code, and it +// requires no dependencies. +fn write_prql_examples(examples: HashMap) -> Result<()> { + // If we have to modify any files, raise an error at the end, so it fails in CI. + let mut is_snapshots_updated = false; + + let mut existing_snapshots: HashMap<_, _> = collect_snapshot_examples()?; + // Write any new snapshots, or update any that have changed + examples.iter().try_for_each(|(prql_path, example)| { + if existing_snapshots + .remove(prql_path) + .map(|existing| existing != *example) + .unwrap_or(true) + { + is_snapshots_updated = true; + fs::create_dir_all(Path::new(prql_path).parent().unwrap())?; + fs::write(prql_path, example)?; + } + + Ok::<(), anyhow::Error>(()) + })?; + // If there are any files left in `existing_snapshots`, we remove them, since + // they don't reference anything. + existing_snapshots.iter().for_each(|(path, _)| { + trash::delete(path).unwrap_or_else(|e| { + warn!("Failed to delete unreferenced example: {}", e); + }) + }); + + if is_snapshots_updated { + bail!("Some book snapshots were not consistent with the queries in the book. The snapshots have now been updated. Subsequent runs should pass."); + } Ok(()) } -/// Snapshot the output of each example. -fn run_reference_prql() { +/// Snapshot the SQL output of each example. +fn test_prql_examples() { glob!("prql/**/*.prql", |path| { let prql = fs::read_to_string(path).unwrap(); @@ -147,20 +178,25 @@ fn run_reference_prql() { } /// Snapshot the display trait output of each example. -// Currently not a separate test, see notes in caller. // // TODO: this involves writing out almost the same PRQL again — instead we could // compare the output of Display to the auto-formatted source. But we need an // autoformatter for that (unless we want to raise on any non-matching input, // which seems very strict) -fn run_display_reference_prql() { - glob!("prql/**/*.prql", |path| { - let prql = fs::read_to_string(path).unwrap(); - - if prql.contains("skip_test") { - return; - } +#[test] +fn test_display() -> Result<(), ErrorMessages> { + use prql_compiler::downcast; + collect_book_examples() + .map_err(downcast)? + .iter() + .try_for_each(|(path, example)| { + assert_snapshot!( + path.to_string_lossy().to_string(), + prql_to_pl(example).and_then(pl_to_prql)?, + example + ); + Ok::<(), ErrorMessages>(()) + })?; - assert_display_snapshot!(prql_to_pl(&prql).and_then(pl_to_prql).unwrap()); - }); + Ok(()) } diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@examples__list-equivalence-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@examples__list-equivalence-0.prql.snap deleted file mode 100644 index 085bada98319..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@examples__list-equivalence-0.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/examples/list-equivalence-0.prql ---- -from employees -select salary - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@examples__list-equivalence-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@examples__list-equivalence-1.prql.snap deleted file mode 100644 index 6ab6d90cdd10..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@examples__list-equivalence-1.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/examples/list-equivalence-1.prql ---- -from employees -select [salary] - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@examples__misc-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@examples__misc-0.prql.snap deleted file mode 100644 index 930d29f6d477..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@examples__misc-0.prql.snap +++ /dev/null @@ -1,26 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/examples/misc-0.prql ---- -let parts = ( - from seq_1_to_5 -) - - - -from pl = prospect_lists_prospects -filter prospect_list_id == "cc675eee-8bd1-237f-be5e-622ba511d65e" -join a = accounts [a.id == pl.related_id] -join er = email_addr_bean_rel [er.bean_id == a.id and er.primary_address == "1"] -join ea = email_addresses [ea.id == er.email_address_id] -select ea.email_address -derive prefix = s"regexp_replace(SUBSTRING_INDEX({email_address}, '@', 1), '[.0-9-_:]+', '.')" -derive stub = s"SUBSTRING_INDEX(SUBSTRING_INDEX({prefix}, '.', part), '.', -1)" -select [ - email_address, - stub, -] - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@examples__misc-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@examples__misc-1.prql.snap deleted file mode 100644 index d48e3fe1307a..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@examples__misc-1.prql.snap +++ /dev/null @@ -1,13 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/examples/misc-1.prql ---- -from club_ratings -filter rating != null -group year ( - derive [rating_norm = rating - ( average rating ) / ( stddev rating )] -) - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@examples__variables-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@examples__variables-0.prql.snap deleted file mode 100644 index c4e1df527811..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@examples__variables-0.prql.snap +++ /dev/null @@ -1,32 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/examples/variables-0.prql ---- -from employees -filter country == "USA" -derive [ - gross_salary = salary + payroll_tax, - gross_cost = gross_salary + benefits_cost, -] -filter gross_cost > 0 -group [ - title, - country, -] ( - aggregate [ - average salary, - average gross_salary, - sum salary, - sum gross_salary, - average gross_cost, - sum_gross_cost = sum gross_cost, - ct = count, -] -) -sort sum_gross_cost -filter ct > 200 -take 20 - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@examples__variables-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@examples__variables-1.prql.snap deleted file mode 100644 index 1f588bf0d309..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@examples__variables-1.prql.snap +++ /dev/null @@ -1,19 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/examples/variables-1.prql ---- -from employees -group [emp_no] ( - aggregate [emp_salary = average salary] -) -join titles [==emp_no] -group [title] ( - aggregate [avg_salary = average emp_salary] -) -select salary_k = avg_salary / 1000 -take 10 -derive salary = salary_k * 1000 - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@internals__functional-lang-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@internals__functional-lang-0.prql.snap deleted file mode 100644 index 96d5d50a00e1..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@internals__functional-lang-0.prql.snap +++ /dev/null @@ -1,11 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/internals/functional-lang-0.prql ---- -from employees -filter age > 50 -sort name - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@internals__functional-lang-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@internals__functional-lang-1.prql.snap deleted file mode 100644 index ae83420f23d3..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@internals__functional-lang-1.prql.snap +++ /dev/null @@ -1,11 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/internals/functional-lang-1.prql ---- -from employees -filter age > 50 -sort name - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@internals__functional-lang-2.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@internals__functional-lang-2.prql.snap deleted file mode 100644 index f15a84e195b3..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@internals__functional-lang-2.prql.snap +++ /dev/null @@ -1,12 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/internals/functional-lang-2.prql ---- -filter age > 50 ( - from employees -) -sort name - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@internals__functional-lang-3.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@internals__functional-lang-3.prql.snap deleted file mode 100644 index aa777d923706..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@internals__functional-lang-3.prql.snap +++ /dev/null @@ -1,13 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/internals/functional-lang-3.prql ---- -sort name ( - filter age > 50 ( - from employees -) -) - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@internals__name-resolving-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@internals__name-resolving-0.prql.snap deleted file mode 100644 index a7bd8bc3730a..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@internals__name-resolving-0.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/internals/name-resolving-0.prql ---- -from employees -select first_name - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@introduction-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@introduction-0.prql.snap deleted file mode 100644 index bc40a390e21a..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@introduction-0.prql.snap +++ /dev/null @@ -1,32 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/introduction-0.prql ---- -from employees -filter start_date > @2021-01-01 -derive [ - gross_salary = salary + tax ?? 0, - gross_cost = gross_salary + benefits_cost, -] -filter gross_cost > 0 -group [ - title, - country, -] ( - aggregate [ - average gross_salary, - sum_gross_cost = sum gross_cost, -] -) -filter sum_gross_cost > 100000 -derive id = f"{title}_{country}" -derive country_code = s"LEFT(country, 2)" -sort [ - sum_gross_cost, - -country, -] -take 1..20 - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__coalesce-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__coalesce-0.prql.snap deleted file mode 100644 index 16833c5f8cfa..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__coalesce-0.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/coalesce-0.prql ---- -from orders -derive amount ?? 0 - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__dates-and-times-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__dates-and-times-0.prql.snap deleted file mode 100644 index ca08e6d69631..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__dates-and-times-0.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/dates-and-times-0.prql ---- -from employees -derive age_at_year_end = @2022-12-31 - dob - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__dates-and-times-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__dates-and-times-1.prql.snap deleted file mode 100644 index 07d9b568eac6..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__dates-and-times-1.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/dates-and-times-1.prql ---- -from orders -derive should_have_shipped_today = order_time < @08:30 - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__dates-and-times-2.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__dates-and-times-2.prql.snap deleted file mode 100644 index 6e0b688f7f7a..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__dates-and-times-2.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/dates-and-times-2.prql ---- -from commits -derive first_prql_commit = @2020-01-01T13:19:55-0800 - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__dates-and-times-3.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__dates-and-times-3.prql.snap deleted file mode 100644 index 5080f647a12c..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__dates-and-times-3.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/dates-and-times-3.prql ---- -from projects -derive first_check_in = start + 10days - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__distinct-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__distinct-0.prql.snap deleted file mode 100644 index 587f75ff1bd2..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__distinct-0.prql.snap +++ /dev/null @@ -1,13 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/distinct-0.prql ---- -from employees -select department -group department ( - take 1 -) - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__distinct-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__distinct-1.prql.snap deleted file mode 100644 index d6bcee7acf86..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__distinct-1.prql.snap +++ /dev/null @@ -1,13 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/distinct-1.prql ---- -from employees -select department -group department ( - take 1 -) - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__distinct-2.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__distinct-2.prql.snap deleted file mode 100644 index 4f2e5f381a88..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__distinct-2.prql.snap +++ /dev/null @@ -1,13 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/distinct-2.prql ---- -from employees -group department ( - sort age - take 1 -) - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__f-strings-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__f-strings-0.prql.snap deleted file mode 100644 index 2b8a822ba481..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__f-strings-0.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/f-strings-0.prql ---- -from employees -select full_name = f"{first_name} {last_name}" - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__f-strings-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__f-strings-1.prql.snap deleted file mode 100644 index b61f8780aa34..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__f-strings-1.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/f-strings-1.prql ---- -from web -select url = f"http{tls}://www.{domain}.{tld}/{page}" - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__null-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__null-0.prql.snap deleted file mode 100644 index 016809741efe..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__null-0.prql.snap +++ /dev/null @@ -1,11 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/null-0.prql ---- -from employees -filter first_name == null -filter null != last_name - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__ranges-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__ranges-1.prql.snap deleted file mode 100644 index 46ce8b767eb3..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__ranges-1.prql.snap +++ /dev/null @@ -1,14 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/ranges-1.prql ---- -from orders -sort [ - -value, - date, -] -take 101..110 - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-0.prql.snap deleted file mode 100644 index fa9c95fb9f4c..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-0.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/s-strings-0.prql ---- -from my_table -select db_version = s"version()" - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-1.prql.snap deleted file mode 100644 index 7de6990c149c..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-1.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/s-strings-1.prql ---- -from employees -aggregate [average salary] - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__standard-library-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__standard-library-0.prql.snap deleted file mode 100644 index 691cabab4a62..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__standard-library-0.prql.snap +++ /dev/null @@ -1,20 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/standard-library-0.prql ---- -from employees -derive [ - gross_salary = ( - salary + payroll_tax - as int -), - gross_salary_rounded = ( - gross_salary - round 0 -), - time = s"NOW()", -] - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__strings-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__strings-0.prql.snap deleted file mode 100644 index 08b198a45ab3..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__strings-0.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/strings-0.prql ---- -from my_table -select x = "hello world" - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__strings-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__strings-1.prql.snap deleted file mode 100644 index 014e0927ce0e..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__strings-1.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/strings-1.prql ---- -from my_table -select x = "hello world" - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__strings-2.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__strings-2.prql.snap deleted file mode 100644 index 52b190fec22a..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__strings-2.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/strings-2.prql ---- -from my_table -select x = '"hello world"' - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__strings-3.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__strings-3.prql.snap deleted file mode 100644 index eddb87ee8834..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__strings-3.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/strings-3.prql ---- -from my_table -select x = 'I said "hello world"!' - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__strings-4.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__strings-4.prql.snap deleted file mode 100644 index 5966be260e48..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__strings-4.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/strings-4.prql ---- -from my_table -select x = 'I said """hello world"""!' - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__target-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__target-0.prql.snap deleted file mode 100644 index 8d46fc69595c..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__target-0.prql.snap +++ /dev/null @@ -1,15 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/target-0.prql ---- -prql target:sql.postgres - - - -from employees -sort age -take 10 - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__target-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__target-1.prql.snap deleted file mode 100644 index 2719c8e16911..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__target-1.prql.snap +++ /dev/null @@ -1,15 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/target-1.prql ---- -prql target:sql.mssql - - - -from employees -sort age -take 10 - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__target-2.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__target-2.prql.snap deleted file mode 100644 index 5bf77265c6a4..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__target-2.prql.snap +++ /dev/null @@ -1,13 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/target-2.prql ---- -prql version:^0.5 - - - -from employees - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@queries__pipelines-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@queries__pipelines-0.prql.snap deleted file mode 100644 index 7162e861b213..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@queries__pipelines-0.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/queries/pipelines-0.prql ---- -from employees - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@queries__pipelines-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@queries__pipelines-1.prql.snap deleted file mode 100644 index f64f5d68dc56..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@queries__pipelines-1.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/queries/pipelines-1.prql ---- -from employees -derive gross_salary = salary + payroll_tax - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@queries__variables-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@queries__variables-0.prql.snap deleted file mode 100644 index fbb8c9dfa00f..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@queries__variables-0.prql.snap +++ /dev/null @@ -1,18 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/queries/variables-0.prql ---- -let top_50 = ( - from employees - sort salary - take 50 - aggregate [total_salary = sum salary] -) - - - -from top_50 - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-11.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-11.prql.snap deleted file mode 100644 index f719b0acbbd4..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-11.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/syntax-11.prql ---- -from `dir/*.parquet` - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-13.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-13.prql.snap deleted file mode 100644 index 6316d2280516..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-13.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/syntax-13.prql ---- -from `music.albums` - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-14.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-14.prql.snap deleted file mode 100644 index a38f2f750602..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-14.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/syntax-14.prql ---- -from employees -filter id == $1 - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-3.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-3.prql.snap deleted file mode 100644 index 6820f7c5e628..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-3.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/syntax-3.prql ---- -from employees -select [first_name] - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-4.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-4.prql.snap deleted file mode 100644 index 6e06fe3ee2e5..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-4.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/syntax-4.prql ---- -from employees -select first_name - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-6.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-6.prql.snap deleted file mode 100644 index d6668fe305c7..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-6.prql.snap +++ /dev/null @@ -1,40 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/syntax-6.prql ---- -from employees -derive is_proximate = ( - distance - in 0..20 -) -derive ( - total_distance = sum distance -) -derive ( - min_capped_distance = min distance ?? 5 -) -derive travel_time = distance / 40 -derive ( - distance_rounded_2_dp = round 1 + 1 distance -) -derive [ - is_far = ( - distance - in 100.. -), - is_negative = ( - distance - in -100..0 -), - is_negative = ( - distance - in -100..0 -), - average_distance = average distance, -] -sort -distance -sort [-distance] - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-8.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-8.prql.snap deleted file mode 100644 index 55a51e5d833f..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-8.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/syntax-8.prql ---- -from employees -aggregate [average salary] - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__aggregate-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__aggregate-0.prql.snap deleted file mode 100644 index 89e3271c8316..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__aggregate-0.prql.snap +++ /dev/null @@ -1,13 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/aggregate-0.prql ---- -from employees -aggregate [ - average salary, - ct = count, -] - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__aggregate-2.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__aggregate-2.prql.snap deleted file mode 100644 index 21468ff11aeb..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__aggregate-2.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/aggregate-2.prql ---- -from employees -derive [avg_sal = average salary] - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__append-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__append-0.prql.snap deleted file mode 100644 index 821c0f010d36..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__append-0.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/append-0.prql ---- -from employees_1 -append employees_2 - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__append-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__append-1.prql.snap deleted file mode 100644 index 2a61ec1251b1..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__append-1.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/append-1.prql ---- -from employees_1 -remove employees_2 - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__append-2.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__append-2.prql.snap deleted file mode 100644 index dddeb63b7c9f..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__append-2.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/append-2.prql ---- -from employees_1 -intersect employees_2 - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__derive-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__derive-0.prql.snap deleted file mode 100644 index e90d9add3db4..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__derive-0.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/derive-0.prql ---- -from employees -derive gross_salary = salary + payroll_tax - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__filter-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__filter-0.prql.snap deleted file mode 100644 index 8a68bf997bd7..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__filter-0.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/filter-0.prql ---- -from employees -filter age > 25 - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__filter-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__filter-1.prql.snap deleted file mode 100644 index 1bc8cf6d4a34..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__filter-1.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/filter-1.prql ---- -from employees -filter age > 25 or department != "IT" - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__filter-2.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__filter-2.prql.snap deleted file mode 100644 index ad800e09070f..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__filter-2.prql.snap +++ /dev/null @@ -1,13 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/filter-2.prql ---- -from employees -filter ( - age - in 25..40 -) - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from-0.prql.snap deleted file mode 100644 index 0adcf6191d9e..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from-0.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/from-0.prql ---- -from employees - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from-1.prql.snap deleted file mode 100644 index b90898f6f93e..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from-1.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/from-1.prql ---- -from e = employees -select e.first_name - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from_text-2.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from_text-2.prql.snap deleted file mode 100644 index a0aaabe15cb7..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from_text-2.prql.snap +++ /dev/null @@ -1,33 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/from_text-2.prql ---- -let x = ( - from_text format:json '{ - "columns": ["a", "b", "c"], - "data": [ - [1, "x", false], - [4, "y", null] - ] -}' -) - - - -let y = ( - from_text format:json ' - [ - {"a": 1, "m": "5"}, - {"a": 4, "n": "6"} - ] -' -) - - - -from x -join y [==a] - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__group-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__group-1.prql.snap deleted file mode 100644 index f916e255f991..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__group-1.prql.snap +++ /dev/null @@ -1,11 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/group-1.prql ---- -from employees -sort join_date -take 1 - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__group-2.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__group-2.prql.snap deleted file mode 100644 index 6b2cb62586b3..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__group-2.prql.snap +++ /dev/null @@ -1,13 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/group-2.prql ---- -from employees -group role ( - sort join_date - take 1 -) - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__join-2.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__join-2.prql.snap deleted file mode 100644 index 19b950c9d24b..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__join-2.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/join-2.prql ---- -from employees -join positions [==emp_no] - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-0.prql.snap deleted file mode 100644 index 9841ec3d8249..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-0.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/select-0.prql ---- -from employees -select name = f"{first_name} {last_name}" - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-2.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-2.prql.snap deleted file mode 100644 index 522050c7dd99..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-2.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/select-2.prql ---- -from employees -select first_name - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-3.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-3.prql.snap deleted file mode 100644 index d6596a9ce634..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-3.prql.snap +++ /dev/null @@ -1,13 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/select-3.prql ---- -from e = employees -select [ - e.first_name, - e.last_name, -] - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-6.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-6.prql.snap deleted file mode 100644 index 102555240bdb..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-6.prql.snap +++ /dev/null @@ -1,11 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/select-6.prql ---- -from artists -derive nick = name -select not [artists.`*`] - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-0.prql.snap deleted file mode 100644 index 91b36c10532f..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-0.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/sort-0.prql ---- -from employees -sort age - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-1.prql.snap deleted file mode 100644 index d7f443472fc9..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-1.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/sort-1.prql ---- -from employees -sort [-age] - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-2.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-2.prql.snap deleted file mode 100644 index 1df292e0b57f..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-2.prql.snap +++ /dev/null @@ -1,14 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/sort-2.prql ---- -from employees -sort [ - age, - -tenure, - salary, -] - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-3.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-3.prql.snap deleted file mode 100644 index 3ef53a4676e9..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-3.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/sort-3.prql ---- -from employees -sort [s"substr({first_name}, 2, 5)"] - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-5.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-5.prql.snap deleted file mode 100644 index 52f805544586..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-5.prql.snap +++ /dev/null @@ -1,11 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/sort-5.prql ---- -from employees -sort tenure -join locations [==employee_id] - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__take-0.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__take-0.prql.snap deleted file mode 100644 index 7f798967b647..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__take-0.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/take-0.prql ---- -from employees -take 10 - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__take-1.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__take-1.prql.snap deleted file mode 100644 index 4107c86bfd92..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__take-1.prql.snap +++ /dev/null @@ -1,14 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/take-1.prql ---- -from orders -sort [ - -value, - date, -] -take 101..110 - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__window-2.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__window-2.prql.snap deleted file mode 100644 index 3015829b90db..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__window-2.prql.snap +++ /dev/null @@ -1,11 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/window-2.prql ---- -from employees -sort age -derive rnk = rank - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__window-3.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__window-3.prql.snap deleted file mode 100644 index 26a5eb5d9d46..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__window-3.prql.snap +++ /dev/null @@ -1,13 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/window-3.prql ---- -from employees -group department ( - sort age - derive rnk = rank -) - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__window-4.prql.snap b/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__window-4.prql.snap deleted file mode 100644 index be549656354d..000000000000 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__window-4.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/window-4.prql ---- -from employees -filter salary < ( average salary ) - - - diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@examples__cte-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__examples__cte-0.prql.snap similarity index 51% rename from book/tests/snapshots/snapshot__run_display_reference_prql@examples__cte-0.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__examples__cte-0.prql.snap index b246de058091..83e9f48a0e9e 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@examples__cte-0.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__examples__cte-0.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/examples/cte-0.prql +expression: "let newest_employees = (\n from employees\n sort tenure\n take 50\n)\n\nlet average_salaries = (\n from salaries\n group country (\n aggregate average_country_salary = (average salary)\n )\n)\n\nfrom newest_employees\njoin average_salaries [==country]\nselect [name, salary, average_country_salary]\n" --- let newest_employees = ( from employees diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@examples__employees-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__examples__employees-0.prql.snap similarity index 52% rename from book/tests/snapshots/snapshot__run_display_reference_prql@examples__employees-0.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__examples__employees-0.prql.snap index 692c476512cc..ac80804d08a1 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@examples__employees-0.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__examples__employees-0.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/examples/employees-0.prql +expression: "from salaries\ngroup [emp_no] (\n aggregate [emp_salary = average salary]\n)\njoin t=titles [==emp_no]\njoin dept_emp side:left [==emp_no]\ngroup [dept_emp.dept_no, t.title] (\n aggregate [avg_salary = average emp_salary]\n)\njoin departments [==dept_no]\nselect [dept_name, title, avg_salary]\n" --- from salaries group [emp_no] ( diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@examples__employees-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__examples__employees-1.prql.snap similarity index 51% rename from book/tests/snapshots/snapshot__run_display_reference_prql@examples__employees-1.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__examples__employees-1.prql.snap index 665754bd3fb5..c5d5366f6306 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@examples__employees-1.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__examples__employees-1.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/examples/employees-1.prql +expression: "from e=employees\njoin salaries [==emp_no]\ngroup [e.emp_no, e.gender] (\n aggregate [\n emp_salary = average salaries.salary\n ]\n)\njoin de=dept_emp [==emp_no] side:left\ngroup [de.dept_no, gender] (\n aggregate [\n salary_avg = average emp_salary,\n salary_sd = stddev emp_salary,\n ]\n)\njoin departments [==dept_no]\nselect [dept_name, gender, salary_avg, salary_sd]\n" --- from e = employees join salaries [==emp_no] diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@examples__employees-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__examples__employees-2.prql.snap similarity index 50% rename from book/tests/snapshots/snapshot__run_display_reference_prql@examples__employees-2.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__examples__employees-2.prql.snap index 3823173006c7..d957c280a5c6 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@examples__employees-2.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__examples__employees-2.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/examples/employees-2.prql +expression: "from e=employees\njoin salaries [==emp_no]\ngroup [e.emp_no, e.gender] (\n aggregate [\n emp_salary = average salaries.salary\n ]\n)\njoin de=dept_emp [==emp_no]\njoin dm=dept_manager [\n (dm.dept_no == de.dept_no) and s\"(de.from_date, de.to_date) OVERLAPS (dm.from_date, dm.to_date)\"\n]\ngroup [dm.emp_no, gender] (\n aggregate [\n salary_avg = average emp_salary,\n salary_sd = stddev emp_salary\n ]\n)\nderive mng_no = emp_no\njoin managers=employees [==emp_no]\nderive mng_name = s\"managers.first_name || ' ' || managers.last_name\"\nselect [mng_name, managers.gender, salary_avg, salary_sd]\n" --- from e = employees join salaries [==emp_no] diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@examples__employees-3.prql.snap b/book/tests/snapshots/snapshot__tests__prql__examples__employees-3.prql.snap similarity index 52% rename from book/tests/snapshots/snapshot__run_display_reference_prql@examples__employees-3.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__examples__employees-3.prql.snap index 611769e8f06d..9cc6115f24bd 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@examples__employees-3.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__examples__employees-3.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/examples/employees-3.prql +expression: "from de=dept_emp\njoin s=salaries side:left [\n (s.emp_no == de.emp_no),\n s\"({s.from_date}, {s.to_date}) OVERLAPS ({de.from_date}, {de.to_date})\"\n]\ngroup [de.emp_no, de.dept_no] (\n aggregate salary = (average s.salary)\n)\njoin employees [==emp_no]\njoin titles [==emp_no]\nselect [dept_no, salary, employees.gender, titles.title]\n" --- from de = dept_emp join side:left s = salaries [ diff --git a/book/tests/snapshots/snapshot__tests__prql__examples__list-equivalence-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__examples__list-equivalence-0.prql.snap new file mode 100644 index 000000000000..8566dfaeb2b2 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__examples__list-equivalence-0.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nselect salary\n" +--- +from employees +select salary + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__examples__list-equivalence-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__examples__list-equivalence-1.prql.snap new file mode 100644 index 000000000000..055af64b363a --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__examples__list-equivalence-1.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nselect [salary]\n" +--- +from employees +select [salary] + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@examples__list-equivalence-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__examples__list-equivalence-2.prql.snap similarity index 54% rename from book/tests/snapshots/snapshot__run_display_reference_prql@examples__list-equivalence-2.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__examples__list-equivalence-2.prql.snap index 5ba483c522d7..3d298b6f9b55 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@examples__list-equivalence-2.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__examples__list-equivalence-2.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/examples/list-equivalence-2.prql +expression: "from employees\nderive [\n gross_salary = salary + payroll_tax,\n gross_cost = gross_salary + benefits_cost\n]\n" --- from employees derive [ diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@examples__list-equivalence-3.prql.snap b/book/tests/snapshots/snapshot__tests__prql__examples__list-equivalence-3.prql.snap similarity index 54% rename from book/tests/snapshots/snapshot__run_display_reference_prql@examples__list-equivalence-3.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__examples__list-equivalence-3.prql.snap index c1c8e138f806..254f07187889 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@examples__list-equivalence-3.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__examples__list-equivalence-3.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/examples/list-equivalence-3.prql +expression: "from employees\nderive gross_salary = salary + payroll_tax\nderive gross_cost = gross_salary + benefits_cost\n" --- from employees derive gross_salary = salary + payroll_tax diff --git a/book/tests/snapshots/snapshot__tests__prql__examples__misc-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__examples__misc-0.prql.snap new file mode 100644 index 000000000000..63b13a31ec56 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__examples__misc-0.prql.snap @@ -0,0 +1,25 @@ +--- +source: book/tests/snapshot.rs +expression: "# TODO: this table should have a column `part` with values 1..5,\n# but such data declaration is not yet supported, see #286\nlet parts = (\n from seq_1_to_5\n)\n\nfrom pl=prospect_lists_prospects\nfilter prospect_list_id == 'cc675eee-8bd1-237f-be5e-622ba511d65e'\njoin a=accounts [a.id == pl.related_id]\njoin er=email_addr_bean_rel [er.bean_id == a.id and er.primary_address == '1']\njoin ea=email_addresses [ea.id == er.email_address_id]\nselect ea.email_address\nderive prefix = s\"regexp_replace(SUBSTRING_INDEX({email_address}, '@', 1), '[.0-9-_:]+', '.')\"\nderive stub = s\"SUBSTRING_INDEX(SUBSTRING_INDEX({prefix}, '.', part), '.', -1)\"\nselect [email_address, stub]\n" +--- +let parts = ( + from seq_1_to_5 +) + + + +from pl = prospect_lists_prospects +filter prospect_list_id == "cc675eee-8bd1-237f-be5e-622ba511d65e" +join a = accounts [a.id == pl.related_id] +join er = email_addr_bean_rel [er.bean_id == a.id and er.primary_address == "1"] +join ea = email_addresses [ea.id == er.email_address_id] +select ea.email_address +derive prefix = s"regexp_replace(SUBSTRING_INDEX({email_address}, '@', 1), '[.0-9-_:]+', '.')" +derive stub = s"SUBSTRING_INDEX(SUBSTRING_INDEX({prefix}, '.', part), '.', -1)" +select [ + email_address, + stub, +] + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__examples__misc-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__examples__misc-1.prql.snap new file mode 100644 index 000000000000..50dcca896ea5 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__examples__misc-1.prql.snap @@ -0,0 +1,12 @@ +--- +source: book/tests/snapshot.rs +expression: "from club_ratings\nfilter rating != null\n# TODO: this is real ugly. `average rating` should not require parenthesis\n# TODO: why cannot we put comments in group's pipeline?\ngroup year (\n derive [rating_norm = rating - (average rating) / (stddev rating)]\n)\n" +--- +from club_ratings +filter rating != null +group year ( + derive [rating_norm = rating - ( average rating ) / ( stddev rating )] +) + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__examples__variables-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__examples__variables-0.prql.snap new file mode 100644 index 000000000000..4b1f4fce84c1 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__examples__variables-0.prql.snap @@ -0,0 +1,31 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nfilter country == \"USA\" # Each line transforms the previous result.\nderive [ # This adds columns / variables.\n gross_salary = salary + payroll_tax,\n gross_cost = gross_salary + benefits_cost # Variables can use other variables.\n]\nfilter gross_cost > 0\ngroup [title, country] ( # For each group use a nested pipeline\n aggregate [ # Aggregate each group to a single row\n average salary,\n average gross_salary,\n sum salary,\n sum gross_salary,\n average gross_cost,\n sum_gross_cost = sum gross_cost,\n ct = count,\n ]\n)\nsort sum_gross_cost\nfilter ct > 200\ntake 20\n" +--- +from employees +filter country == "USA" +derive [ + gross_salary = salary + payroll_tax, + gross_cost = gross_salary + benefits_cost, +] +filter gross_cost > 0 +group [ + title, + country, +] ( + aggregate [ + average salary, + average gross_salary, + sum salary, + sum gross_salary, + average gross_cost, + sum_gross_cost = sum gross_cost, + ct = count, +] +) +sort sum_gross_cost +filter ct > 200 +take 20 + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__examples__variables-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__examples__variables-1.prql.snap new file mode 100644 index 000000000000..cfb45e96a801 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__examples__variables-1.prql.snap @@ -0,0 +1,18 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\ngroup [emp_no] (\n aggregate [\n emp_salary = average salary # average salary resolves to \"AVG(salary)\" (from stdlib)\n ]\n)\njoin titles [==emp_no]\ngroup [title] (\n aggregate [\n avg_salary = average emp_salary\n ]\n)\nselect salary_k = avg_salary / 1000 # avg_salary should resolve to \"AVG(emp_salary)\"\ntake 10 # induces new SELECT\nderive salary = salary_k * 1000 # salary_k should not resolve to \"avg_salary / 1000\"\n" +--- +from employees +group [emp_no] ( + aggregate [emp_salary = average salary] +) +join titles [==emp_no] +group [title] ( + aggregate [avg_salary = average emp_salary] +) +select salary_k = avg_salary / 1000 +take 10 +derive salary = salary_k * 1000 + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-0.prql.snap new file mode 100644 index 000000000000..1bd2d905e16d --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-0.prql.snap @@ -0,0 +1,10 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nfilter age > 50\nsort name\n" +--- +from employees +filter age > 50 +sort name + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-1.prql.snap new file mode 100644 index 000000000000..da4b761a9e4b --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-1.prql.snap @@ -0,0 +1,10 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees | filter age > 50 | sort name\n" +--- +from employees +filter age > 50 +sort name + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-2.prql.snap new file mode 100644 index 000000000000..7da897d0dd14 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-2.prql.snap @@ -0,0 +1,11 @@ +--- +source: book/tests/snapshot.rs +expression: "filter age > 50 (from employees) | sort name\n" +--- +filter age > 50 ( + from employees +) +sort name + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-3.prql.snap b/book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-3.prql.snap new file mode 100644 index 000000000000..045c663815a8 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-3.prql.snap @@ -0,0 +1,12 @@ +--- +source: book/tests/snapshot.rs +expression: "sort name (filter age > 50 (from employees))\n" +--- +sort name ( + filter age > 50 ( + from employees +) +) + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__internals__name-resolving-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__internals__name-resolving-0.prql.snap new file mode 100644 index 000000000000..56e49df27e11 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__internals__name-resolving-0.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nselect first_name\n" +--- +from employees +select first_name + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@internals__name-resolving-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__internals__name-resolving-1.prql.snap similarity index 56% rename from book/tests/snapshots/snapshot__run_display_reference_prql@internals__name-resolving-1.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__internals__name-resolving-1.prql.snap index 6161fd5892e6..a9d9e5bada6d 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@internals__name-resolving-1.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__internals__name-resolving-1.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/internals/name-resolving-1.prql +expression: "from employees\nderive [first_name, dept_id]\njoin d=departments [==dept_id]\nselect [first_name, d.title]\n" --- from employees derive [ diff --git a/book/tests/snapshots/snapshot__tests__prql__introduction-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__introduction-0.prql.snap new file mode 100644 index 000000000000..96f55b8ab057 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__introduction-0.prql.snap @@ -0,0 +1,31 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nfilter start_date > @2021-01-01 # Clear date syntax\nderive [ # `derive` adds columns / variables\n gross_salary = salary + (tax ?? 0), # Terse coalesce\n gross_cost = gross_salary + benefits_cost, # Variables can use other variables\n]\nfilter gross_cost > 0\ngroup [title, country] ( # `group` runs a pipeline over each group\n aggregate [ # `aggregate` reduces each group to a value\n average gross_salary,\n sum_gross_cost = sum gross_cost, # `=` sets a column name\n ]\n)\nfilter sum_gross_cost > 100_000 # `filter` replaces both of SQL's `WHERE` & `HAVING`\nderive id = f\"{title}_{country}\" # F-strings like Python\nderive country_code = s\"LEFT(country, 2)\" # S-strings allow using SQL as an escape hatch\nsort [sum_gross_cost, -country] # `-country` means descending order\ntake 1..20 # Range expressions (also valid here as `take 20`)\n" +--- +from employees +filter start_date > @2021-01-01 +derive [ + gross_salary = salary + tax ?? 0, + gross_cost = gross_salary + benefits_cost, +] +filter gross_cost > 0 +group [ + title, + country, +] ( + aggregate [ + average gross_salary, + sum_gross_cost = sum gross_cost, +] +) +filter sum_gross_cost > 100000 +derive id = f"{title}_{country}" +derive country_code = s"LEFT(country, 2)" +sort [ + sum_gross_cost, + -country, +] +take 1..20 + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__coalesce-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__coalesce-0.prql.snap new file mode 100644 index 000000000000..24ff749cfbc8 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__coalesce-0.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from orders\nderive amount ?? 0\n" +--- +from orders +derive amount ?? 0 + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-0.prql.snap new file mode 100644 index 000000000000..acb71c71fc9a --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-0.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nderive age_at_year_end = (@2022-12-31 - dob)\n" +--- +from employees +derive age_at_year_end = @2022-12-31 - dob + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-1.prql.snap new file mode 100644 index 000000000000..fd2fe52b3f6c --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-1.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from orders\nderive should_have_shipped_today = (order_time < @08:30)\n" +--- +from orders +derive should_have_shipped_today = order_time < @08:30 + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-2.prql.snap new file mode 100644 index 000000000000..1507a39b0252 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-2.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from commits\nderive first_prql_commit = @2020-01-01T13:19:55-0800\n" +--- +from commits +derive first_prql_commit = @2020-01-01T13:19:55-0800 + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-3.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-3.prql.snap new file mode 100644 index 000000000000..70ac66f365a2 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-3.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from projects\nderive first_check_in = start + 10days\n" +--- +from projects +derive first_check_in = start + 10days + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__distinct-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__distinct-0.prql.snap new file mode 100644 index 000000000000..7929401e23b6 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__distinct-0.prql.snap @@ -0,0 +1,12 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nselect department\ngroup department (\n take 1\n)\n" +--- +from employees +select department +group department ( + take 1 +) + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__distinct-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__distinct-1.prql.snap new file mode 100644 index 000000000000..22ba087f087c --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__distinct-1.prql.snap @@ -0,0 +1,12 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nselect department\ngroup department (take 1)\n" +--- +from employees +select department +group department ( + take 1 +) + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__distinct-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__distinct-2.prql.snap new file mode 100644 index 000000000000..ceb0035e6601 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__distinct-2.prql.snap @@ -0,0 +1,12 @@ +--- +source: book/tests/snapshot.rs +expression: "# youngest employee from each department\nfrom employees\ngroup department (\n sort age\n take 1\n)\n" +--- +from employees +group department ( + sort age + take 1 +) + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__f-strings-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__f-strings-0.prql.snap new file mode 100644 index 000000000000..5f490aa52f00 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__f-strings-0.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nselect full_name = f\"{first_name} {last_name}\"\n" +--- +from employees +select full_name = f"{first_name} {last_name}" + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__f-strings-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__f-strings-1.prql.snap new file mode 100644 index 000000000000..f00e2becbab2 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__f-strings-1.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from web\nselect url = f\"http{tls}://www.{domain}.{tld}/{page}\"\n" +--- +from web +select url = f"http{tls}://www.{domain}.{tld}/{page}" + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__null-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__null-0.prql.snap new file mode 100644 index 000000000000..73594522238f --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__null-0.prql.snap @@ -0,0 +1,10 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nfilter first_name == null\nfilter null != last_name\n" +--- +from employees +filter first_name == null +filter null != last_name + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__ranges-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__ranges-0.prql.snap similarity index 55% rename from book/tests/snapshots/snapshot__run_display_reference_prql@language-features__ranges-0.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__language-features__ranges-0.prql.snap index e20b2b97240c..2d5baa98ae2d 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__ranges-0.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__ranges-0.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/ranges-0.prql +expression: "from events\nfilter (date | in @1776-07-04..@1787-09-17)\nfilter (magnitude | in 50..100)\nderive is_northern = (latitude | in 0..)\n" --- from events filter ( diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__ranges-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__ranges-1.prql.snap new file mode 100644 index 000000000000..b68c1920a669 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__ranges-1.prql.snap @@ -0,0 +1,13 @@ +--- +source: book/tests/snapshot.rs +expression: "from orders\nsort [-value, date]\ntake 101..110\n" +--- +from orders +sort [ + -value, + date, +] +take 101..110 + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-0.prql.snap new file mode 100644 index 000000000000..12abfcc2518c --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-0.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from my_table\nselect db_version = s\"version()\"\n" +--- +from my_table +select db_version = s"version()" + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-1.prql.snap new file mode 100644 index 000000000000..c57ed2561d58 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-1.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\naggregate [average salary]\n" +--- +from employees +aggregate [average salary] + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-2.prql.snap similarity index 51% rename from book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-2.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-2.prql.snap index 8d39feed0f0d..e28b7f46ed0a 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-2.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-2.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/s-strings-2.prql +expression: "from de=dept_emp\njoin s=salaries side:left [\n (s.emp_no == de.emp_no),\n s\"\"\"({s.from_date}, {s.to_date})\n OVERLAPS\n ({de.from_date}, {de.to_date})\"\"\"\n]\n" --- from de = dept_emp join side:left s = salaries [ diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-3.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-3.prql.snap similarity index 53% rename from book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-3.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-3.prql.snap index 85661196009c..2cb93849dda8 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-3.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-3.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/s-strings-3.prql +expression: "from s\"SELECT DISTINCT ON first_name, id, age FROM employees ORDER BY age ASC\"\njoin s = s\"SELECT * FROM salaries\" [==id]\n" --- from s"SELECT DISTINCT ON first_name, id, age FROM employees ORDER BY age ASC" join s = s"SELECT * FROM salaries" [==id] diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-4.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-4.prql.snap similarity index 51% rename from book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-4.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-4.prql.snap index d7482d2f4cfb..00c1d5e17349 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-4.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-4.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/s-strings-4.prql +expression: "from employees\nderive [\n has_valid_title = s\"regexp_contains(title, '([a-z0-9]*-){{2,}}')\"\n]\n" --- from employees derive [has_valid_title = s"regexp_contains(title, '([a-z0-9]*-){2,}')"] diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-5.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-5.prql.snap similarity index 53% rename from book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-5.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-5.prql.snap index 4313e1e554a7..9bd3b0d3fe16 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-5.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-5.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/s-strings-5.prql +expression: "from employees\nderive [\n gross_salary = salary + benefits,\n daily_rate = s\"{gross_salary} / 365\"\n]\n" --- from employees derive [ diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-6.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-6.prql.snap similarity index 53% rename from book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-6.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-6.prql.snap index 8ac94b9d968f..3dc30b6885ae 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__s-strings-6.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-6.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/s-strings-6.prql +expression: "from employees\nderive [\n gross_salary = salary + benefits,\n daily_rate = s\"({gross_salary}) / 365\"\n]\n" --- from employees derive [ diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__standard-library-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__standard-library-0.prql.snap new file mode 100644 index 000000000000..011d5f416c47 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__standard-library-0.prql.snap @@ -0,0 +1,19 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nderive [\n gross_salary = (salary + payroll_tax | as int),\n gross_salary_rounded = (gross_salary | round 0),\n time = s\"NOW()\", # an s-string, given no `now` function exists in PRQL\n]\n" +--- +from employees +derive [ + gross_salary = ( + salary + payroll_tax + as int +), + gross_salary_rounded = ( + gross_salary + round 0 +), + time = s"NOW()", +] + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__strings-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__strings-0.prql.snap new file mode 100644 index 000000000000..6a1d79036036 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__strings-0.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from my_table\nselect x = \"hello world\"\n" +--- +from my_table +select x = "hello world" + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__strings-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__strings-1.prql.snap new file mode 100644 index 000000000000..2da7a07937de --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__strings-1.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from my_table\nselect x = 'hello world'\n" +--- +from my_table +select x = "hello world" + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__strings-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__strings-2.prql.snap new file mode 100644 index 000000000000..8d79cd8cedbc --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__strings-2.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from my_table\nselect x = '\"hello world\"'\n" +--- +from my_table +select x = '"hello world"' + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__strings-3.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__strings-3.prql.snap new file mode 100644 index 000000000000..a681bc62a036 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__strings-3.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from my_table\nselect x = \"\"\"I said \"hello world\"!\"\"\"\n" +--- +from my_table +select x = 'I said "hello world"!' + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__strings-4.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__strings-4.prql.snap new file mode 100644 index 000000000000..0bae3f836774 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__strings-4.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from my_table\nselect x = \"\"\"\"\"I said \"\"\"hello world\"\"\"!\"\"\"\"\"\n" +--- +from my_table +select x = 'I said """hello world"""!' + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__switch-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__switch-0.prql.snap similarity index 53% rename from book/tests/snapshots/snapshot__run_display_reference_prql@language-features__switch-0.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__language-features__switch-0.prql.snap index 85bb6bac32b8..7618b9e71723 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__switch-0.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__switch-0.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/switch-0.prql +expression: "from employees\nderive distance = switch [\n city == \"Calgary\" -> 0,\n city == \"Edmonton\" -> 300,\n]\n" --- from employees derive distance = switch [ diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__switch-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__switch-1.prql.snap similarity index 51% rename from book/tests/snapshots/snapshot__run_display_reference_prql@language-features__switch-1.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__language-features__switch-1.prql.snap index dd4c64e0b6b0..f9ee3312b92b 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@language-features__switch-1.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__switch-1.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/language-features/switch-1.prql +expression: "from employees\nderive distance = switch [\n city == \"Calgary\" -> 0,\n city == \"Edmonton\" -> 300,\n true -> \"Unknown\",\n]\n" --- from employees derive distance = switch [ diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__target-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__target-0.prql.snap new file mode 100644 index 000000000000..b22539422ae4 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__target-0.prql.snap @@ -0,0 +1,14 @@ +--- +source: book/tests/snapshot.rs +expression: "prql target:sql.postgres\n\nfrom employees\nsort age\ntake 10\n" +--- +prql target:sql.postgres + + + +from employees +sort age +take 10 + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__target-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__target-1.prql.snap new file mode 100644 index 000000000000..ed7e10fd7388 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__target-1.prql.snap @@ -0,0 +1,14 @@ +--- +source: book/tests/snapshot.rs +expression: "prql target:sql.mssql\n\nfrom employees\nsort age\ntake 10\n" +--- +prql target:sql.mssql + + + +from employees +sort age +take 10 + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__target-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__target-2.prql.snap new file mode 100644 index 000000000000..b05787ed8bae --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__target-2.prql.snap @@ -0,0 +1,12 @@ +--- +source: book/tests/snapshot.rs +expression: "prql version:\"0.5\"\n\nfrom employees\n" +--- +prql version:^0.5 + + + +from employees + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@queries__functions-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__queries__functions-0.prql.snap similarity index 54% rename from book/tests/snapshots/snapshot__run_display_reference_prql@queries__functions-0.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__queries__functions-0.prql.snap index bde459b05cf8..e5bb0a64491b 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@queries__functions-0.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__queries__functions-0.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/queries/functions-0.prql +expression: "func fahrenheit_to_celsius temp -> (temp - 32) / 1.8\n\nfrom cities\nderive temp_c = (fahrenheit_to_celsius temp_f)\n" --- func fahrenheit_to_celsius temp -> temp - 32 / 1.8 diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@queries__functions-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__queries__functions-1.prql.snap similarity index 51% rename from book/tests/snapshots/snapshot__run_display_reference_prql@queries__functions-1.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__queries__functions-1.prql.snap index d8d3e0185fd9..ef971e8402bc 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@queries__functions-1.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__queries__functions-1.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/queries/functions-1.prql +expression: "func interp lower:0 higher x -> (x - lower) / (higher - lower)\n\nfrom students\nderive [\n sat_proportion_1 = (interp 1600 sat_score),\n sat_proportion_2 = (interp lower:0 1600 sat_score),\n]\n" --- func interp higher x lower:0 -> x - lower / higher - lower diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@queries__functions-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__queries__functions-2.prql.snap similarity index 52% rename from book/tests/snapshots/snapshot__run_display_reference_prql@queries__functions-2.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__queries__functions-2.prql.snap index 49560fe48496..2e8f243ea009 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@queries__functions-2.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__queries__functions-2.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/queries/functions-2.prql +expression: "func interp lower:0 higher x -> (x - lower) / (higher - lower)\n\nfrom students\nderive [\n sat_proportion_1 = (sat_score | interp 1600),\n sat_proportion_2 = (sat_score | interp lower:0 1600),\n]\n" --- func interp higher x lower:0 -> x - lower / higher - lower diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@queries__functions-3.prql.snap b/book/tests/snapshots/snapshot__tests__prql__queries__functions-3.prql.snap similarity index 54% rename from book/tests/snapshots/snapshot__run_display_reference_prql@queries__functions-3.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__queries__functions-3.prql.snap index 83e91977fe3f..bc1453813dc9 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@queries__functions-3.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__queries__functions-3.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/queries/functions-3.prql +expression: "func fahrenheit_to_celsius temp -> (temp - 32) / 1.8\n\nfrom cities\nderive temp_c = (temp_f | fahrenheit_to_celsius)\n" --- func fahrenheit_to_celsius temp -> temp - 32 / 1.8 diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@queries__functions-4.prql.snap b/book/tests/snapshots/snapshot__tests__prql__queries__functions-4.prql.snap similarity index 52% rename from book/tests/snapshots/snapshot__run_display_reference_prql@queries__functions-4.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__queries__functions-4.prql.snap index 8ed62cca5158..3deae6fcab9c 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@queries__functions-4.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__queries__functions-4.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/queries/functions-4.prql +expression: "func fahrenheit_to_celsius temp -> (temp - 32) / 1.8\nfunc interp lower:0 higher x -> (x - lower) / (higher - lower)\n\nfrom kettles\nderive boiling_proportion = (temp_c | fahrenheit_to_celsius | interp 100)\n" --- func fahrenheit_to_celsius temp -> temp - 32 / 1.8 diff --git a/book/tests/snapshots/snapshot__tests__prql__queries__pipelines-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__queries__pipelines-0.prql.snap new file mode 100644 index 000000000000..8ef6dce0bb66 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__queries__pipelines-0.prql.snap @@ -0,0 +1,8 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\n" +--- +from employees + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__queries__pipelines-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__queries__pipelines-1.prql.snap new file mode 100644 index 000000000000..b2b18409f03a --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__queries__pipelines-1.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nderive gross_salary = (salary + payroll_tax)\n" +--- +from employees +derive gross_salary = salary + payroll_tax + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@queries__pipelines-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__queries__pipelines-2.prql.snap similarity index 53% rename from book/tests/snapshots/snapshot__run_display_reference_prql@queries__pipelines-2.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__queries__pipelines-2.prql.snap index e3ff662251a8..5c74bd2eeb81 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@queries__pipelines-2.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__queries__pipelines-2.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/queries/pipelines-2.prql +expression: "from e = employees\nderive gross_salary = (salary + payroll_tax)\nsort gross_salary\ntake 10\njoin d = department [==dept_no]\nselect [e.name, gross_salary, d.name]\n" --- from e = employees derive gross_salary = salary + payroll_tax diff --git a/book/tests/snapshots/snapshot__tests__prql__queries__variables-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__queries__variables-0.prql.snap new file mode 100644 index 000000000000..3c4edace1010 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__queries__variables-0.prql.snap @@ -0,0 +1,17 @@ +--- +source: book/tests/snapshot.rs +expression: "let top_50 = (\n from employees\n sort salary\n take 50\n aggregate [total_salary = sum salary]\n)\n\nfrom top_50 # Starts a new pipeline\n" +--- +let top_50 = ( + from employees + sort salary + take 50 + aggregate [total_salary = sum salary] +) + + + +from top_50 + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@queries__variables-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__queries__variables-1.prql.snap similarity index 51% rename from book/tests/snapshots/snapshot__run_display_reference_prql@queries__variables-1.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__queries__variables-1.prql.snap index f7a3cbcd9431..dd72ddc9b4bb 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@queries__variables-1.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__queries__variables-1.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/queries/variables-1.prql +expression: "let grouping = s\"\"\"\n SELECT SUM(a)\n FROM tbl\n GROUP BY\n GROUPING SETS\n ((b, c, d), (d), (b, d))\n\"\"\"\n\nfrom grouping\n" --- let grouping = s" SELECT SUM(a) diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-0.prql.snap similarity index 55% rename from book/tests/snapshots/snapshot__run_display_reference_prql@syntax-0.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__syntax-0.prql.snap index 16788f8c5410..ee78d7a29c00 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-0.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__syntax-0.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/syntax-0.prql +expression: "from employees\nfilter department == \"Product\"\nselect [first_name, last_name]\n" --- from employees filter department == "Product" diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-1.prql.snap similarity index 55% rename from book/tests/snapshots/snapshot__run_display_reference_prql@syntax-1.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__syntax-1.prql.snap index 7d3684118966..ae9d7fcbb81c 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-1.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__syntax-1.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/syntax-1.prql +expression: "from employees | filter department == \"Product\" | select [first_name, last_name]\n" --- from employees filter department == "Product" diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-10.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-10.prql.snap similarity index 50% rename from book/tests/snapshots/snapshot__run_display_reference_prql@syntax-10.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__syntax-10.prql.snap index e12239744931..0ef6f6c5ea4e 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-10.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__syntax-10.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/syntax-10.prql +expression: "prql target:sql.postgres\nfrom employees\nselect `first name`\n" --- prql target:sql.postgres diff --git a/book/tests/snapshots/snapshot__tests__prql__syntax-11.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-11.prql.snap new file mode 100644 index 000000000000..acd1651bdbb9 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__syntax-11.prql.snap @@ -0,0 +1,8 @@ +--- +source: book/tests/snapshot.rs +expression: "from `dir/*.parquet`\n" +--- +from `dir/*.parquet` + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-12.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-12.prql.snap similarity index 55% rename from book/tests/snapshots/snapshot__run_display_reference_prql@syntax-12.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__syntax-12.prql.snap index 79ec4c9aa74d..6be462d1cb08 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-12.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__syntax-12.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/syntax-12.prql +expression: "prql target:sql.bigquery\nfrom `project-foo.dataset.table`\njoin `project-bar.dataset.table` [==col_bax]\n" --- prql target:sql.bigquery diff --git a/book/tests/snapshots/snapshot__tests__prql__syntax-13.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-13.prql.snap new file mode 100644 index 000000000000..fc9310bcceea --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__syntax-13.prql.snap @@ -0,0 +1,8 @@ +--- +source: book/tests/snapshot.rs +expression: "from `music.albums`\n" +--- +from `music.albums` + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__syntax-14.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-14.prql.snap new file mode 100644 index 000000000000..429e57d0faf3 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__syntax-14.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nfilter id == $1\n" +--- +from employees +filter id == $1 + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-15.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-15.prql.snap similarity index 50% rename from book/tests/snapshots/snapshot__run_display_reference_prql@syntax-15.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__syntax-15.prql.snap index 34d44267ba17..7aa2caf4c217 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-15.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__syntax-15.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/syntax-15.prql +expression: "from numbers\nselect [\n small = 1.000_000_1,\n big = 5_000_000,\n]\n" --- from numbers select [ diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-2.prql.snap similarity index 54% rename from book/tests/snapshots/snapshot__run_display_reference_prql@syntax-2.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__syntax-2.prql.snap index 8c5b5825e8c4..a12652162d23 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-2.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__syntax-2.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/syntax-2.prql +expression: "from numbers\nderive [x = 1, y = 2]\nderive [\n a = x,\n b = y\n]\nderive [\n c = a,\n d = b,\n]\n" --- from numbers derive [ diff --git a/book/tests/snapshots/snapshot__tests__prql__syntax-3.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-3.prql.snap new file mode 100644 index 000000000000..4077d71aaa9b --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__syntax-3.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nselect [first_name]\n" +--- +from employees +select [first_name] + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__syntax-4.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-4.prql.snap new file mode 100644 index 000000000000..56e49df27e11 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__syntax-4.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nselect first_name\n" +--- +from employees +select first_name + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-5.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-5.prql.snap similarity index 53% rename from book/tests/snapshots/snapshot__run_display_reference_prql@syntax-5.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__syntax-5.prql.snap index f3ebf960c4bf..027e1a5e000f 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-5.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__syntax-5.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/syntax-5.prql +expression: "from foo\nselect [\n circumference = diameter * 3.14159,\n color,\n]\nfilter circumference > 10 and color != \"red\"\n" --- from foo select [ diff --git a/book/tests/snapshots/snapshot__tests__prql__syntax-6.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-6.prql.snap new file mode 100644 index 000000000000..b9f326d968cc --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__syntax-6.prql.snap @@ -0,0 +1,39 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\n# Requires parentheses, because it's contains a pipe\nderive is_proximate = (distance | in 0..20)\n# Requires parentheses, because it's a function call\nderive total_distance = (sum distance)\n# `??` doesn't require parentheses, as it's not a function call\nderive min_capped_distance = (min distance ?? 5)\n# No parentheses needed, because no function call\nderive travel_time = distance / 40\n# No inner parentheses needed around `1+1` because no function call\nderive distance_rounded_2_dp = (round 1+1 distance)\nderive [\n # Requires parentheses, because it contains a pipe\n is_far = (distance | in 100..),\n # The left value of the range requires parentheses,\n # because of the minus sign\n is_negative = (distance | in (-100..0)),\n # ...this is equivalent\n is_negative = (distance | in (-100)..0),\n # Doesn't require parentheses, because it's in a list (confusing, see footnote)!\n average_distance = average distance,\n]\n# Requires parentheses because of the minus sign\nsort (-distance)\n# A list is fine too\nsort [-distance]\n" +--- +from employees +derive is_proximate = ( + distance + in 0..20 +) +derive ( + total_distance = sum distance +) +derive ( + min_capped_distance = min distance ?? 5 +) +derive travel_time = distance / 40 +derive ( + distance_rounded_2_dp = round 1 + 1 distance +) +derive [ + is_far = ( + distance + in 100.. +), + is_negative = ( + distance + in -100..0 +), + is_negative = ( + distance + in -100..0 +), + average_distance = average distance, +] +sort -distance +sort [-distance] + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-7.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-7.prql.snap similarity index 54% rename from book/tests/snapshots/snapshot__run_display_reference_prql@syntax-7.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__syntax-7.prql.snap index 29e0c6d26c1e..81e0a3146955 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-7.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__syntax-7.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/syntax-7.prql +expression: "from employees\ngroup [title, country] (\n aggregate [\n average salary,\n ct = count\n ]\n)\n" --- from employees group [ diff --git a/book/tests/snapshots/snapshot__tests__prql__syntax-8.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-8.prql.snap new file mode 100644 index 000000000000..4f94033b1f86 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__syntax-8.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees # Comment 1\n# Comment 2\naggregate [average salary]\n" +--- +from employees +aggregate [average salary] + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-9.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-9.prql.snap similarity index 50% rename from book/tests/snapshots/snapshot__run_display_reference_prql@syntax-9.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__syntax-9.prql.snap index 9e5a61c3e446..19c4de64822f 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@syntax-9.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__syntax-9.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/syntax-9.prql +expression: "prql target:sql.mysql\nfrom employees\nselect `first name`\n" --- prql target:sql.mysql diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__aggregate-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__aggregate-0.prql.snap new file mode 100644 index 000000000000..1c202ec4ba25 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__aggregate-0.prql.snap @@ -0,0 +1,12 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\naggregate [\n average salary,\n ct = count\n]\n" +--- +from employees +aggregate [ + average salary, + ct = count, +] + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__aggregate-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__aggregate-1.prql.snap similarity index 54% rename from book/tests/snapshots/snapshot__run_display_reference_prql@transforms__aggregate-1.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__transforms__aggregate-1.prql.snap index bbf253ec6dd5..81e0a3146955 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__aggregate-1.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__aggregate-1.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/aggregate-1.prql +expression: "from employees\ngroup [title, country] (\n aggregate [\n average salary,\n ct = count\n ]\n)\n" --- from employees group [ diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__aggregate-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__aggregate-2.prql.snap new file mode 100644 index 000000000000..9b49b51df2a5 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__aggregate-2.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nderive [avg_sal = average salary]\n" +--- +from employees +derive [avg_sal = average salary] + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__append-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__append-0.prql.snap new file mode 100644 index 000000000000..cbbd0478001b --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__append-0.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees_1\nappend employees_2\n" +--- +from employees_1 +append employees_2 + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__append-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__append-1.prql.snap new file mode 100644 index 000000000000..e2b9a1338479 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__append-1.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees_1\nremove employees_2\n" +--- +from employees_1 +remove employees_2 + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__append-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__append-2.prql.snap new file mode 100644 index 000000000000..1971d287b890 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__append-2.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees_1\nintersect employees_2\n" +--- +from employees_1 +intersect employees_2 + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__derive-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__derive-0.prql.snap new file mode 100644 index 000000000000..183b59f98112 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__derive-0.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nderive gross_salary = salary + payroll_tax\n" +--- +from employees +derive gross_salary = salary + payroll_tax + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__derive-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__derive-1.prql.snap similarity index 54% rename from book/tests/snapshots/snapshot__run_display_reference_prql@transforms__derive-1.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__transforms__derive-1.prql.snap index f2b9dd7bd20d..3d298b6f9b55 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__derive-1.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__derive-1.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/derive-1.prql +expression: "from employees\nderive [\n gross_salary = salary + payroll_tax,\n gross_cost = gross_salary + benefits_cost\n]\n" --- from employees derive [ diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__filter-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__filter-0.prql.snap new file mode 100644 index 000000000000..bd5e2c425e25 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__filter-0.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nfilter age > 25\n" +--- +from employees +filter age > 25 + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__filter-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__filter-1.prql.snap new file mode 100644 index 000000000000..a6cb5b5b569e --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__filter-1.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nfilter (age > 25 or department != \"IT\")\n" +--- +from employees +filter age > 25 or department != "IT" + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__filter-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__filter-2.prql.snap new file mode 100644 index 000000000000..d3b04cd4de31 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__filter-2.prql.snap @@ -0,0 +1,12 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nfilter (age | in 25..40)\n" +--- +from employees +filter ( + age + in 25..40 +) + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__from-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__from-0.prql.snap new file mode 100644 index 000000000000..8ef6dce0bb66 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__from-0.prql.snap @@ -0,0 +1,8 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\n" +--- +from employees + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__from-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__from-1.prql.snap new file mode 100644 index 000000000000..ef1312a86941 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__from-1.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from e = employees\nselect e.first_name\n" +--- +from e = employees +select e.first_name + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from_text-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__from_text-0.prql.snap similarity index 50% rename from book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from_text-0.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__transforms__from_text-0.prql.snap index d86f2e1e86bb..6a730d3a1f7e 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from_text-0.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__from_text-0.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/from_text-0.prql +expression: "from_text \"\"\"\na,b,c\n1,2,3\n4,5,6\n\"\"\"\nderive [\n d = b + c,\n answer = 20 * 2 + 2,\n]\n" --- from_text " a,b,c diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from_text-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__from_text-1.prql.snap similarity index 51% rename from book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from_text-1.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__transforms__from_text-1.prql.snap index 740349748e00..6f9f848bbd6e 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__from_text-1.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__from_text-1.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/from_text-1.prql +expression: "let temp_format_lookup = from_text format:csv \"\"\"\ncountry_code,format\nuk,C\nus,F\nlr,F\nde,C\n\"\"\"\n\nfrom temperatures\njoin temp_format_lookup [==country_code]\n" --- let temp_format_lookup = ( from_text format:csv " diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__from_text-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__from_text-2.prql.snap new file mode 100644 index 000000000000..da17c3b1fe6f --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__from_text-2.prql.snap @@ -0,0 +1,32 @@ +--- +source: book/tests/snapshot.rs +expression: "let x = from_text format:json \"\"\"{\n \"columns\": [\"a\", \"b\", \"c\"],\n \"data\": [\n [1, \"x\", false],\n [4, \"y\", null]\n ]\n}\"\"\"\n\nlet y = from_text format:json \"\"\"\n [\n {\"a\": 1, \"m\": \"5\"},\n {\"a\": 4, \"n\": \"6\"}\n ]\n\"\"\"\n\nfrom x | join y [==a]\n" +--- +let x = ( + from_text format:json '{ + "columns": ["a", "b", "c"], + "data": [ + [1, "x", false], + [4, "y", null] + ] +}' +) + + + +let y = ( + from_text format:json ' + [ + {"a": 1, "m": "5"}, + {"a": 4, "n": "6"} + ] +' +) + + + +from x +join y [==a] + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__group-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__group-0.prql.snap similarity index 54% rename from book/tests/snapshots/snapshot__run_display_reference_prql@transforms__group-0.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__transforms__group-0.prql.snap index 754f23c1d76e..81e0a3146955 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__group-0.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__group-0.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/group-0.prql +expression: "from employees\ngroup [title, country] (\n aggregate [\n average salary,\n ct = count\n ]\n)\n" --- from employees group [ diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__group-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__group-1.prql.snap new file mode 100644 index 000000000000..2517396a1418 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__group-1.prql.snap @@ -0,0 +1,10 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nsort join_date\ntake 1\n" +--- +from employees +sort join_date +take 1 + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__group-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__group-2.prql.snap new file mode 100644 index 000000000000..11467687bbbb --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__group-2.prql.snap @@ -0,0 +1,12 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\ngroup role (\n sort join_date # taken from above\n take 1\n)\n" +--- +from employees +group role ( + sort join_date + take 1 +) + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__join-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__join-0.prql.snap similarity index 52% rename from book/tests/snapshots/snapshot__run_display_reference_prql@transforms__join-0.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__transforms__join-0.prql.snap index 0334411b6614..4d113382409a 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__join-0.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__join-0.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/join-0.prql +expression: "from employees\njoin side:left positions [employees.id==positions.employee_id]\n" --- from employees join side:left positions [employees.id == positions.employee_id] diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__join-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__join-1.prql.snap similarity index 51% rename from book/tests/snapshots/snapshot__run_display_reference_prql@transforms__join-1.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__transforms__join-1.prql.snap index 073e5b79b5ee..b3e13a1d23f8 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__join-1.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__join-1.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/join-1.prql +expression: "from employees\njoin side:left p=positions [employees.id==p.employee_id]\n" --- from employees join side:left p = positions [employees.id == p.employee_id] diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__join-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__join-2.prql.snap new file mode 100644 index 000000000000..ba833fa01b02 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__join-2.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\njoin positions [==emp_no]\n" +--- +from employees +join positions [==emp_no] + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__select-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__select-0.prql.snap new file mode 100644 index 000000000000..ef3e65965333 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__select-0.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nselect name = f\"{first_name} {last_name}\"\n" +--- +from employees +select name = f"{first_name} {last_name}" + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__select-1.prql.snap similarity index 53% rename from book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-1.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__transforms__select-1.prql.snap index 1ecfbb0be8f6..57c345371217 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-1.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__select-1.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/select-1.prql +expression: "from employees\nselect [\n name = f\"{first_name} {last_name}\",\n age_eoy = dob - @2022-12-31,\n]\n" --- from employees select [ diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__select-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__select-2.prql.snap new file mode 100644 index 000000000000..56e49df27e11 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__select-2.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nselect first_name\n" +--- +from employees +select first_name + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__select-3.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__select-3.prql.snap new file mode 100644 index 000000000000..059b92276754 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__select-3.prql.snap @@ -0,0 +1,12 @@ +--- +source: book/tests/snapshot.rs +expression: "from e=employees\nselect [e.first_name, e.last_name]\n" +--- +from e = employees +select [ + e.first_name, + e.last_name, +] + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-4.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__select-4.prql.snap similarity index 51% rename from book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-4.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__transforms__select-4.prql.snap index c8837e7a5780..6445588450d2 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-4.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__select-4.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/select-4.prql +expression: "prql target:sql.bigquery\nfrom tracks\nselect ![milliseconds,bytes]\n" --- prql target:sql.bigquery diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-5.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__select-5.prql.snap similarity index 55% rename from book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-5.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__transforms__select-5.prql.snap index ee470cf35cf6..568bc821ba4f 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__select-5.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__select-5.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/select-5.prql +expression: "from tracks\nselect [track_id, title, composer, bytes]\nselect ![title, composer]\n" --- from tracks select [ diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__select-6.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__select-6.prql.snap new file mode 100644 index 000000000000..19b65db61c48 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__select-6.prql.snap @@ -0,0 +1,10 @@ +--- +source: book/tests/snapshot.rs +expression: "from artists\nderive nick = name\nselect ![artists.*]\n" +--- +from artists +derive nick = name +select not [artists.`*`] + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__sort-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__sort-0.prql.snap new file mode 100644 index 000000000000..cb41ef4b5ddb --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__sort-0.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nsort age\n" +--- +from employees +sort age + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__sort-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__sort-1.prql.snap new file mode 100644 index 000000000000..12203dcc78d3 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__sort-1.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nsort [-age]\n" +--- +from employees +sort [-age] + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__sort-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__sort-2.prql.snap new file mode 100644 index 000000000000..23c2050900c8 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__sort-2.prql.snap @@ -0,0 +1,13 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nsort [age, -tenure, +salary]\n" +--- +from employees +sort [ + age, + -tenure, + salary, +] + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__sort-3.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__sort-3.prql.snap new file mode 100644 index 000000000000..01b0d75eb4e3 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__sort-3.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nsort [s\"substr({first_name}, 2, 5)\"]\n" +--- +from employees +sort [s"substr({first_name}, 2, 5)"] + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-4.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__sort-4.prql.snap similarity index 50% rename from book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-4.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__transforms__sort-4.prql.snap index 01b5c740c41a..51c71b587af5 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__sort-4.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__sort-4.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/sort-4.prql +expression: "from employees\nsort tenure\nderive name = f\"{first_name} {last_name}\"\n" --- from employees sort tenure diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__sort-5.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__sort-5.prql.snap new file mode 100644 index 000000000000..405c461df7e4 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__sort-5.prql.snap @@ -0,0 +1,10 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nsort tenure\njoin locations [==employee_id]\n" +--- +from employees +sort tenure +join locations [==employee_id] + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__take-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__take-0.prql.snap new file mode 100644 index 000000000000..4c39e0cddcea --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__take-0.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\ntake 10\n" +--- +from employees +take 10 + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__take-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__take-1.prql.snap new file mode 100644 index 000000000000..b68c1920a669 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__take-1.prql.snap @@ -0,0 +1,13 @@ +--- +source: book/tests/snapshot.rs +expression: "from orders\nsort [-value, date]\ntake 101..110\n" +--- +from orders +sort [ + -value, + date, +] +take 101..110 + + + diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__window-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__window-0.prql.snap similarity index 52% rename from book/tests/snapshots/snapshot__run_display_reference_prql@transforms__window-0.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__transforms__window-0.prql.snap index 2366506585b0..08d6e23e2468 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__window-0.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__window-0.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/window-0.prql +expression: "from employees\ngroup employee_id (\n sort month\n window rolling:12 (\n derive [trail_12_m_comp = sum paycheck]\n )\n)\n" --- from employees group employee_id ( diff --git a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__window-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__window-1.prql.snap similarity index 51% rename from book/tests/snapshots/snapshot__run_display_reference_prql@transforms__window-1.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__transforms__window-1.prql.snap index afffeb8eb185..c0663a94bc4a 100644 --- a/book/tests/snapshots/snapshot__run_display_reference_prql@transforms__window-1.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__window-1.prql.snap @@ -1,7 +1,6 @@ --- source: book/tests/snapshot.rs -expression: prql_to_pl(&prql).and_then(pl_to_prql).unwrap() -input_file: book/tests/prql/transforms/window-1.prql +expression: "from orders\nsort day\nwindow rows:-3..3 (\n derive [centered_weekly_average = average value]\n)\ngroup [order_month] (\n sort day\n window expanding:true (\n derive [monthly_running_total = sum value]\n )\n)\n" --- from orders sort day diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__window-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__window-2.prql.snap new file mode 100644 index 000000000000..dc3037c993b3 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__window-2.prql.snap @@ -0,0 +1,10 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nsort age\nderive rnk = rank\n" +--- +from employees +sort age +derive rnk = rank + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__window-3.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__window-3.prql.snap new file mode 100644 index 000000000000..b71455102a11 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__window-3.prql.snap @@ -0,0 +1,12 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\ngroup department (\n sort age\n derive rnk = rank\n)\n" +--- +from employees +group department ( + sort age + derive rnk = rank +) + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__window-4.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__window-4.prql.snap new file mode 100644 index 000000000000..9e104fbe34a9 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__window-4.prql.snap @@ -0,0 +1,9 @@ +--- +source: book/tests/snapshot.rs +expression: "from employees\nfilter salary < (average salary)\n" +--- +from employees +filter salary < ( average salary ) + + + From 950996a1bfe4ca2033b1b53cdd23194163e54078 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alja=C5=BE=20Mur=20Er=C5=BEen?= Date: Mon, 20 Feb 2023 09:40:23 +0100 Subject: [PATCH 014/106] build: use released minijinja (#1906) --- Cargo.lock | 5 +++-- prql-compiler/prqlc/Cargo.toml | 2 +- prql-compiler/prqlc/src/jinja.rs | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f94ad387bfbf..5eb860296819 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1671,8 +1671,9 @@ dependencies = [ [[package]] name = "minijinja" -version = "0.30.2" -source = "git+https://github.com/aljazerzen/minijinja#af5a4fd89e5ee5455d673a23098dcbc3d8444229" +version = "0.30.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f95c8f0999f88dd509934824ce03582ffbbcabf8af6484107572618732660c54" dependencies = [ "serde", ] diff --git a/prql-compiler/prqlc/Cargo.toml b/prql-compiler/prqlc/Cargo.toml index 621fdc071a43..a90627b1530d 100644 --- a/prql-compiler/prqlc/Cargo.toml +++ b/prql-compiler/prqlc/Cargo.toml @@ -18,7 +18,7 @@ color-eyre = "0.6.1" env_logger = {version = "0.9.1", features = ["termcolor"]} itertools = "0.10.3" notify = "^5.1.0" -minijinja = {git = "https://github.com/aljazerzen/minijinja"} +minijinja = {version = "0.30.4", features = ["unstable_machinery"]} prql-compiler = {path = '..', version = "0.5.2"} regex = {version = "1.7.1", features = ["std", "unicode"]} serde_json = "1.0.81" diff --git a/prql-compiler/prqlc/src/jinja.rs b/prql-compiler/prqlc/src/jinja.rs index ac8835747a37..6bec828644c8 100644 --- a/prql-compiler/prqlc/src/jinja.rs +++ b/prql-compiler/prqlc/src/jinja.rs @@ -18,7 +18,7 @@ use std::collections::HashMap; use anyhow::Result; -use minijinja::compiler::tokens::{Span, Token}; +use minijinja::machinery::{Span, Token}; use regex::Regex; const ANCHOR_PREFIX: &str = "_jinja_"; @@ -41,7 +41,7 @@ pub fn pre_process(source: &str) -> Result<(String, JinjaContext)> { let mut blocks = Vec::new(); let mut current_block = Vec::new(); - for res in minijinja::compiler::lexer::tokenize(source, false) { + for res in minijinja::machinery::tokenize(source, false) { let (token, span) = res?; if let Token::TemplateData(data) = token { From c6c73ef3631b414730cc14aa1fa4130183f6519f Mon Sep 17 00:00:00 2001 From: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Date: Mon, 20 Feb 2023 01:23:31 -0800 Subject: [PATCH 015/106] refactor: Options as &Options (#1905) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: Options as &Options Not sure if this is worthwhile — I started in one function and then kept on replacing. Fine to close if not an improvement. * . --- book/src/lib.rs | 2 +- book/tests/snapshot.rs | 4 ++-- prql-compiler/README.md | 6 +++--- prql-compiler/benches/bench.rs | 2 +- prql-compiler/examples/compile-files/build.rs | 2 +- prql-compiler/prql-compiler-macros/src/lib.rs | 2 +- prql-compiler/prqlc/src/cli.rs | 2 +- prql-compiler/prqlc/src/watch.rs | 2 +- prql-compiler/src/lib.rs | 12 ++++++------ prql-compiler/src/sql/dialect.rs | 1 + prql-compiler/src/sql/mod.rs | 6 +++--- prql-compiler/src/test.rs | 12 ++++++------ prql-compiler/tests/integration/main.rs | 6 +++--- prql-elixir/native/prql/src/lib.rs | 4 ++-- prql-java/src/lib.rs | 2 +- prql-js/src/lib.rs | 4 ++-- prql-lib/src/lib.rs | 2 +- prql-python/src/lib.rs | 4 ++-- 18 files changed, 38 insertions(+), 37 deletions(-) diff --git a/book/src/lib.rs b/book/src/lib.rs index 9c69858dc66a..1d8a8e067edc 100644 --- a/book/src/lib.rs +++ b/book/src/lib.rs @@ -109,7 +109,7 @@ fn replace_examples(text: &str) -> Result { let options = prql_compiler::Options::default().no_signature(); let html = table_of_comparison( text.as_str().unwrap(), - &compile(&prql, options).unwrap(), + &compile(&prql, &options).unwrap(), ); cmark_acc.push(Event::Html(html.into())); diff --git a/book/tests/snapshot.rs b/book/tests/snapshot.rs index 384b5dd578a4..a454da7c80da 100644 --- a/book/tests/snapshot.rs +++ b/book/tests/snapshot.rs @@ -160,6 +160,7 @@ fn write_prql_examples(examples: HashMap) -> Result<()> { /// Snapshot the SQL output of each example. fn test_prql_examples() { + let opts = Options::default().no_signature(); glob!("prql/**/*.prql", |path| { let prql = fs::read_to_string(path).unwrap(); @@ -167,8 +168,7 @@ fn test_prql_examples() { return; } - let opts = Options::default().no_signature(); - let sql = compile(&prql, opts).unwrap_or_else(|e| format!("{prql}\n\n{e}")); + let sql = compile(&prql, &opts).unwrap_or_else(|e| format!("{prql}\n\n{e}")); // `glob!` gives us the file path in the test name anyway, so we pass an // empty name. We pass `&prql` so the prql is in the snapshot (albeit in // a single line, and, in the rare case that the SQL doesn't change, the diff --git a/prql-compiler/README.md b/prql-compiler/README.md index 900be541dc03..abcdc1202bbe 100644 --- a/prql-compiler/README.md +++ b/prql-compiler/README.md @@ -8,7 +8,7 @@ For more on PRQL, check out the [PRQL website](https://prql-lang.org) or the For more usage examples and the library documentation, check out the [`prql-compiler` documentation](https://docs.rs/prql-compiler/latest/prql_compiler/). -# Installation +## Installation ```shell cargo add prql-compiler @@ -24,12 +24,12 @@ Compile a PRQL string to a SQLite dialect string. use prql_compiler::{compile, Options, Target, sql::Dialect}; let prql = "from employees | select [name, age]"; -let opt = Options { +let opts = &Options { format: false, target: Target::Sql(Some(Dialect::SQLite)), signature_comment: false }; -let sql = compile(&prql, opt).unwrap(); +let sql = compile(&prql, opts).unwrap(); assert_eq!("SELECT name, age FROM employees", sql); ``` diff --git a/prql-compiler/benches/bench.rs b/prql-compiler/benches/bench.rs index 8ab830c42513..bda16db184c0 100644 --- a/prql-compiler/benches/bench.rs +++ b/prql-compiler/benches/bench.rs @@ -18,7 +18,7 @@ cfg_if::cfg_if! { const CONTENT: &str = include_str!("../../book/tests/prql/examples/variables-0.prql"); fn compile_query() -> Result { - compile(CONTENT, Options::default()) + compile(CONTENT, &Options::default()) } fn criterion_benchmark(c: &mut Criterion) { diff --git a/prql-compiler/examples/compile-files/build.rs b/prql-compiler/examples/compile-files/build.rs index 6eb9eea9ee68..6edbd2f1d397 100644 --- a/prql-compiler/examples/compile-files/build.rs +++ b/prql-compiler/examples/compile-files/build.rs @@ -19,7 +19,7 @@ fn main() { let prql_string = fs::read_to_string(prql_path).unwrap(); // compile - let sql_string = compile(&prql_string, Options::default()).unwrap(); + let sql_string = compile(&prql_string, &Options::default()).unwrap(); // write file fs::write(sql_path, sql_string).unwrap(); diff --git a/prql-compiler/prql-compiler-macros/src/lib.rs b/prql-compiler/prql-compiler-macros/src/lib.rs index 2e36ebf24760..88e65b2eb281 100644 --- a/prql-compiler/prql-compiler-macros/src/lib.rs +++ b/prql-compiler/prql-compiler-macros/src/lib.rs @@ -26,7 +26,7 @@ pub fn prql_to_sql(input: TokenStream) -> TokenStream { let opts = prql_compiler::Options::default().no_format().no_signature(); - let sql_string = match prql_compiler::compile(&prql_string, opts) { + let sql_string = match prql_compiler::compile(&prql_string, &opts) { Ok(r) => r, Err(err) => { panic!("{}", err); diff --git a/prql-compiler/prqlc/src/cli.rs b/prql-compiler/prqlc/src/cli.rs index 555b4c4aa479..0ea1694b5bf1 100644 --- a/prql-compiler/prqlc/src/cli.rs +++ b/prql-compiler/prqlc/src/cli.rs @@ -136,7 +136,7 @@ impl Cli { serde_json::to_string_pretty(&ir)?.into_bytes() } - Cli::Compile(_) => compile(source, Options::default()) + Cli::Compile(_) => compile(source, &Options::default()) .map_or_else(|x| x.to_string(), |x| x) .as_bytes() .to_vec(), diff --git a/prql-compiler/prqlc/src/watch.rs b/prql-compiler/prqlc/src/watch.rs index 6c0f70121372..4084439627ba 100644 --- a/prql-compiler/prqlc/src/watch.rs +++ b/prql-compiler/prqlc/src/watch.rs @@ -115,7 +115,7 @@ fn compile_path(path: &Path, opt: &prql_compiler::Options) -> Result<()> { // compile println!("Compiling {}", prql_path.display()); - let sql_string = match prql_compiler::compile(&prql_string, opt.clone()) { + let sql_string = match prql_compiler::compile(&prql_string, opt) { Ok(sql_string) => sql_string, Err(err) => { let source_id = &prql_path.to_str().unwrap_or_default(); diff --git a/prql-compiler/src/lib.rs b/prql-compiler/src/lib.rs index 2288b537b201..25d50b652745 100644 --- a/prql-compiler/src/lib.rs +++ b/prql-compiler/src/lib.rs @@ -42,7 +42,7 @@ //! # fn main() -> Result<(), prql_compiler::ErrorMessages> { //! let sql = prql_compiler::compile( //! "from albums | select [title, artist_id]", -//! prql_compiler::Options::default().no_format() +//! &prql_compiler::Options::default().no_format() //! )?; //! assert_eq!(&sql[..35], "SELECT title, artist_id FROM albums"); //! # Ok(()) @@ -109,19 +109,19 @@ pub static PRQL_VERSION: Lazy = /// ``` /// use prql_compiler::{compile, Options, Target, sql::Dialect}; /// -/// let prql = "from employees | select [name,age] "; -/// let opt = Options { +/// let prql = "from employees | select [name,age]"; +/// let opts = Options { /// format: false, /// target: Target::Sql(Some(Dialect::SQLite)), /// signature_comment: false /// }; -/// let sql = compile(&prql, opt).unwrap(); +/// let sql = compile(&prql, &opts).unwrap(); /// println!("PRQL: {}\nSQLite: {}", prql, &sql); /// assert_eq!("SELECT name, age FROM employees", sql) /// /// ``` /// See [`sql::Options`](sql/struct.Options.html) and [`sql::Dialect`](sql/enum.Dialect.html) for options and supported SQL dialects. -pub fn compile(prql: &str, options: Options) -> Result { +pub fn compile(prql: &str, options: &Options) -> Result { parser::parse(prql) .and_then(semantic::resolve) .and_then(|rq| sql::compile(rq, options)) @@ -237,7 +237,7 @@ pub fn pl_to_rq(pl: Vec) -> Result } /// Generate SQL from RQ. -pub fn rq_to_sql(rq: ast::rq::Query, options: Options) -> Result { +pub fn rq_to_sql(rq: ast::rq::Query, options: &Options) -> Result { sql::compile(rq, options).map_err(error::downcast) } diff --git a/prql-compiler/src/sql/dialect.rs b/prql-compiler/src/sql/dialect.rs index ecf767817cff..6bc52b2859c7 100644 --- a/prql-compiler/src/sql/dialect.rs +++ b/prql-compiler/src/sql/dialect.rs @@ -28,6 +28,7 @@ use strum::{EnumMessage, IntoEnumIterator}; PartialEq, Eq, Clone, + Copy, Serialize, Deserialize, strum::Display, diff --git a/prql-compiler/src/sql/mod.rs b/prql-compiler/src/sql/mod.rs index c109bc0deab0..76b8fe6b11dc 100644 --- a/prql-compiler/src/sql/mod.rs +++ b/prql-compiler/src/sql/mod.rs @@ -18,9 +18,9 @@ use crate::{ast::rq::Query, Options, PRQL_VERSION}; use self::{context::AnchorContext, dialect::DialectHandler}; /// Translate a PRQL AST into a SQL string. -pub fn compile(query: Query, options: Options) -> Result { +pub fn compile(query: Query, options: &Options) -> Result { let crate::Target::Sql(dialect) = options.target; - let sql_ast = gen_query::translate_query(query, dialect.clone())?; + let sql_ast = gen_query::translate_query(query, dialect)?; let sql = sql_ast.to_string(); @@ -76,7 +76,7 @@ mod test { #[test] fn test_end_with_new_line() { - let sql = compile("from a", Options::default().no_signature()).unwrap(); + let sql = compile("from a", &Options::default().no_signature()).unwrap(); assert_eq!(sql, "SELECT\n *\nFROM\n a\n") } } diff --git a/prql-compiler/src/test.rs b/prql-compiler/src/test.rs index e695ed15b6fd..170c8cd42f45 100644 --- a/prql-compiler/src/test.rs +++ b/prql-compiler/src/test.rs @@ -4,7 +4,7 @@ use crate::{parser::parse, sql, Options, Target}; use insta::{assert_display_snapshot, assert_snapshot}; pub fn compile(prql: &str) -> Result { - crate::compile(prql, Options::default().no_signature()) + crate::compile(prql, &Options::default().no_signature()) } #[test] @@ -1493,14 +1493,14 @@ select [mng_name, managers.gender, salary_avg, salary_sd]"#; let sql_from_prql = parse(original_prql) .and_then(crate::semantic::resolve) - .and_then(|rq| sql::compile(rq, Options::default())) + .and_then(|rq| sql::compile(rq, &Options::default())) .unwrap(); let sql_from_json = crate::prql_to_pl(original_prql) .and_then(crate::json::from_pl) .and_then(|json| crate::json::to_pl(&json)) .and_then(crate::pl_to_rq) - .and_then(|rq| crate::rq_to_sql(rq, Options::default())) + .and_then(|rq| crate::rq_to_sql(rq, &Options::default())) .unwrap(); assert_eq!(sql_from_prql, sql_from_json); @@ -1537,7 +1537,7 @@ fn test_f_string() { assert_display_snapshot!( crate::compile( query, - Options::default() + &Options::default() .no_signature() .with_target(Target::Sql(Some(sql::Dialect::SQLite))) @@ -2776,13 +2776,13 @@ fn test_switch() { #[test] fn test_sql_options() { let options = Options::default(); - let sql = crate::compile("from x", options).unwrap(); + let sql = crate::compile("from x", &options).unwrap(); assert!(sql.contains('\n')); assert!(sql.contains("-- Generated by")); let options = Options::default().no_signature().no_format(); - let sql = crate::compile("from x", options).unwrap(); + let sql = crate::compile("from x", &options).unwrap(); assert!(!sql.contains('\n')); assert!(!sql.contains("-- Generated by")); diff --git a/prql-compiler/tests/integration/main.rs b/prql-compiler/tests/integration/main.rs index c51ae2fd1dc7..484e05bc124d 100644 --- a/prql-compiler/tests/integration/main.rs +++ b/prql-compiler/tests/integration/main.rs @@ -34,14 +34,14 @@ mod tests { let opts = Options::default() .with_target(Target::Sql(Some(Dialect::SQLite))) .no_format(); - let sql = prql_compiler::compile(&prql, opts).unwrap(); + let sql = prql_compiler::compile(&prql, &opts).unwrap(); let sqlite_out = sqlite::query_csv(&sqlite_conn, &sql); // save both csv files as same snapshot let opts = Options::default() .with_target(Target::Sql(Some(Dialect::DuckDb))) .no_format(); - let sql = prql_compiler::compile(&prql, opts).unwrap(); + let sql = prql_compiler::compile(&prql, &opts).unwrap(); let duckdb_out = duckdb::query_csv(&duckdb_conn, &sql); pretty_assertions::assert_eq!(sqlite_out, duckdb_out, "SQLite == DuckDB: {test_name}"); @@ -49,7 +49,7 @@ mod tests { let opts = Options::default() .with_target(Target::Sql(Some(Dialect::PostgreSql))) .no_format(); - let sql = prql_compiler::compile(&prql, opts).unwrap(); + let sql = prql_compiler::compile(&prql, &opts).unwrap(); let pg_out = postgres::query_csv(pg_client, &sql); pretty_assertions::assert_eq!(sqlite_out, pg_out, "SQLite == PG: {test_name}"); } diff --git a/prql-elixir/native/prql/src/lib.rs b/prql-elixir/native/prql/src/lib.rs index 2a5967eb9ba1..97eaa11f1c97 100644 --- a/prql-elixir/native/prql/src/lib.rs +++ b/prql-elixir/native/prql/src/lib.rs @@ -120,7 +120,7 @@ pub struct Response { #[rustler::nif] /// compile a prql query into sql pub fn compile(prql_query: &str, options: CompileOptions) -> NifResult { - to_result_tuple(prql_compiler::compile(prql_query, options.into())) + to_result_tuple(prql_compiler::compile(prql_query, &options.into())) } #[rustler::nif] @@ -152,7 +152,7 @@ pub fn rq_to_sql(rq_json: &str) -> NifResult { .and_then(prql_compiler::json::to_rq) // Currently just using default options here; probably should pass // an argument from this func. - .and_then(|x| prql_compiler::rq_to_sql(x, prql_compiler::Options::default())), + .and_then(|x| prql_compiler::rq_to_sql(x, &prql_compiler::Options::default())), ) } diff --git a/prql-java/src/lib.rs b/prql-java/src/lib.rs index b4238032486c..6c59dfa9fb24 100644 --- a/prql-java/src/lib.rs +++ b/prql-java/src/lib.rs @@ -14,7 +14,7 @@ pub extern "system" fn Java_org_prql_prql4j_PrqlCompiler_toSql( .get_string(query) .expect("Couldn't get java string!") .into(); - let rs_sql_str: String = prql_compiler::compile(&prql_query, Options::default()) + let rs_sql_str: String = prql_compiler::compile(&prql_query, &Options::default()) .expect("Couldn't compile query to prql!"); env.new_string(rs_sql_str) .expect("Couldn't create java string!") diff --git a/prql-js/src/lib.rs b/prql-js/src/lib.rs index aa4caca95c46..2e17e7e48703 100644 --- a/prql-js/src/lib.rs +++ b/prql-js/src/lib.rs @@ -10,7 +10,7 @@ use wasm_bindgen::prelude::*; #[wasm_bindgen] pub fn compile(prql_query: &str, options: Option) -> Option { return_or_throw( - prql_compiler::compile(prql_query, options.map(|x| x.into()).unwrap_or_default()) + prql_compiler::compile(prql_query, &options.map(|x| x.into()).unwrap_or_default()) .map_err(|e| e.composed("", prql_query, false)), ) } @@ -39,7 +39,7 @@ pub fn rq_to_sql(rq_json: &str) -> Option { return_or_throw( Ok(rq_json) .and_then(prql_compiler::json::to_rq) - .and_then(|x| prql_compiler::rq_to_sql(x, prql_compiler::Options::default())), + .and_then(|x| prql_compiler::rq_to_sql(x, &prql_compiler::Options::default())), ) } diff --git a/prql-lib/src/lib.rs b/prql-lib/src/lib.rs index 2d920ad2474c..2f741b3a40ac 100644 --- a/prql-lib/src/lib.rs +++ b/prql-lib/src/lib.rs @@ -16,7 +16,7 @@ use std::ffi::CString; pub unsafe extern "C" fn to_sql(query: *const c_char, out: *mut c_char) -> c_int { let prql_query: String = CStr::from_ptr(query).to_string_lossy().into_owned(); - let (isErr, sql_result) = match prql_compiler::compile(&prql_query, Options::default()) { + let (isErr, sql_result) = match prql_compiler::compile(&prql_query, &Options::default()) { Ok(sql_str) => (false, sql_str), Err(err) => { //let err_str = format!("{}", err); diff --git a/prql-python/src/lib.rs b/prql-python/src/lib.rs index 4e7919d3aff7..1202df209d82 100644 --- a/prql-python/src/lib.rs +++ b/prql-python/src/lib.rs @@ -9,7 +9,7 @@ pub fn compile(prql_query: &str, options: Option) -> PyResult(e.into_only().unwrap().reason))) } @@ -35,7 +35,7 @@ pub fn pl_to_rq(pl_json: &str) -> PyResult { pub fn rq_to_sql(rq_json: &str) -> PyResult { Ok(rq_json) .and_then(prql_compiler::json::to_rq) - .and_then(|x| prql_compiler::rq_to_sql(x, prql_compiler::Options::default())) + .and_then(|x| prql_compiler::rq_to_sql(x, &prql_compiler::Options::default())) .map_err(|err| (PyErr::new::(err.to_json()))) } From 311ccd92ded62b151dc034708002824df4014a69 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 20 Feb 2023 11:02:59 -0800 Subject: [PATCH 016/106] chore: pre-commit autoupdate (#1908) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/charliermarsh/ruff-pre-commit: v0.0.246 → v0.0.248](https://github.com/charliermarsh/ruff-pre-commit/compare/v0.0.246...v0.0.248) - [github.com/pre-commit/mirrors-mypy: v1.0.0 → v1.0.1](https://github.com/pre-commit/mirrors-mypy/compare/v1.0.0...v1.0.1) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a2623a4cf4ae..5f4006248d49 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -21,7 +21,7 @@ repos: - prettier - prettier-plugin-go-template - repo: https://github.com/charliermarsh/ruff-pre-commit - rev: v0.0.246 + rev: v0.0.248 hooks: - id: ruff - repo: https://github.com/psf/black @@ -34,7 +34,7 @@ repos: - id: fmt - id: clippy - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.0.0 + rev: v1.0.1 hooks: - id: mypy additional_dependencies: ["types-PyYAML==6.0.12.4"] From 043f401cedb4e1a72f8fa01d9d08d3ab6626ef92 Mon Sep 17 00:00:00 2001 From: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Date: Mon, 20 Feb 2023 12:16:23 -0800 Subject: [PATCH 017/106] docs: Add a doc on `prql-elixir` on Mac (#1909) * docs: Add a doc on `prql-elixir` on Mac --- prql-elixir/README.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/prql-elixir/README.md b/prql-elixir/README.md index ed30ffa0ab2e..e3b7c7e0b956 100644 --- a/prql-elixir/README.md +++ b/prql-elixir/README.md @@ -69,3 +69,34 @@ The possible future workarounds include: If `prql-elixir` becomes more used (for example, we start publishing to Hex, or Mac developers want to work on it), then we can re-enable and deal with the caching issues. We can also re-enable them if the `cargo` issue is resolved. + +To test on Mac temporarily — for example if there's an error in GHA and we're on +a Mac locally — apply a diff like this, and then run `cargo build` from the +`prql-elixir` path, which will enable the local +[`.cargo/config.toml`](native/prql/.cargo/config.toml)). (We could also make a +feature like `elixir-mac` which enabled building on Mac). + +```diff +diff --git a/prql-elixir/native/prql/Cargo.toml b/prql-elixir/native/prql/Cargo.toml +index a39a9ee..218abad 100644 +--- a/prql-elixir/native/prql/Cargo.toml ++++ b/prql-elixir/native/prql/Cargo.toml +@@ -17,7 +17,4 @@ path = "src/lib.rs" + + [dependencies] + prql-compiler = {path = "../../../prql-compiler", default-features = false, version = "0.5.2"} +- +-# See Readme for details on Mac +-[target.'cfg(not(any(target_family="wasm", target_os = "macos")))'.dependencies] + rustler = "0.27.0" +diff --git a/prql-elixir/native/prql/src/lib.rs b/prql-elixir/native/prql/src/lib.rs +index 97eaa11..7525479 100644 +--- a/prql-elixir/native/prql/src/lib.rs ++++ b/prql-elixir/native/prql/src/lib.rs +@@ -1,5 +1,3 @@ +-// See Readme for more information on Mac compiling +-#![cfg(not(target_os = "macos"))] + // These bindings aren't relevant on wasm + #![cfg(not(target_family = "wasm"))] + // TODO: unclear why we need this `allow`; it's required in `CompileOptions`, +``` From cab50cccae8d1f6c3d47759b1a22c0d508a732ba Mon Sep 17 00:00:00 2001 From: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Date: Mon, 20 Feb 2023 13:29:58 -0800 Subject: [PATCH 018/106] ci: Run non-core tests through `test-all.yaml` (#1911) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ci: Run non-core tests through `test-all.yaml` As pointed out in https://github.com/PRQL/prql/pull/1860/files#r1112279486, we're currently running these tests twice — once because they're in the `test-all.yaml` workflow, which is called on `main` commits, and once because they're called on `main` themselves. This disables them being called by `main` commits. It's possible the existing mode is required to generate caches; let's try disabling and assess, though. --- .github/workflows/test-elixir.yaml | 3 --- .github/workflows/test-java.yaml | 3 --- .github/workflows/test-js.yaml | 3 --- .github/workflows/test-python.yaml | 3 --- .github/workflows/test-taskfile.yaml | 4 ---- 5 files changed, 16 deletions(-) diff --git a/.github/workflows/test-elixir.yaml b/.github/workflows/test-elixir.yaml index 31d4c9caaea9..89b0b34097ac 100644 --- a/.github/workflows/test-elixir.yaml +++ b/.github/workflows/test-elixir.yaml @@ -1,9 +1,6 @@ name: test-elixir on: - push: - branches: - - main pull_request: paths: - "prql-elixir/**" diff --git a/.github/workflows/test-java.yaml b/.github/workflows/test-java.yaml index 7eac03959c0c..780c87f3da28 100644 --- a/.github/workflows/test-java.yaml +++ b/.github/workflows/test-java.yaml @@ -1,9 +1,6 @@ name: test-java on: - push: - branches: - - main pull_request: paths: - "prql-java/**" diff --git a/.github/workflows/test-js.yaml b/.github/workflows/test-js.yaml index bb25f46cc634..dd2e4892b4fb 100644 --- a/.github/workflows/test-js.yaml +++ b/.github/workflows/test-js.yaml @@ -1,9 +1,6 @@ name: test-js on: - push: - branches: - - main pull_request: paths: - "prql-js/**" diff --git a/.github/workflows/test-python.yaml b/.github/workflows/test-python.yaml index fd00d6c82242..212967b4928a 100644 --- a/.github/workflows/test-python.yaml +++ b/.github/workflows/test-python.yaml @@ -1,9 +1,6 @@ name: test-python on: - push: - branches: - - main pull_request: paths: - "prql-python/**" diff --git a/.github/workflows/test-taskfile.yaml b/.github/workflows/test-taskfile.yaml index cb6ab15be302..5a9fe8c3449c 100644 --- a/.github/workflows/test-taskfile.yaml +++ b/.github/workflows/test-taskfile.yaml @@ -2,11 +2,7 @@ name: test-taskfile on: - push: - branches: - - main pull_request: - types: [opened, reopened, synchronize, labeled] paths: - Taskfile.yml - .github/workflows/test-taskfile.yaml From 4a8b915eef940b5ef1231b915ceaa210b7a1e86b Mon Sep 17 00:00:00 2001 From: Jonathan Date: Mon, 20 Feb 2023 22:41:05 +0100 Subject: [PATCH 019/106] build: Add PHP binding (#1860) * Update README.md * Create php.md * Create .gitignore * Add files via upload * Update composer.json * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Update composer.json * Update Compiler.php * Update prql-php/.gitignore Co-authored-by: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> * Add composer lock file * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Create test-php.yaml * Update test-php.yaml * Update test-php.yaml * Update composer.json * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Update composer.json * Update test-php.yaml * Update test-php.yaml * Update test-php.yaml * Update test-php.yaml * Update test-php.yaml * Uncomment unit tests * Pass test dir as args * Bootstrap the autoloader * Build library and copy library file * Update test-php.yaml * Update test-php.yaml * Update test-php.yaml * Update test-php.yaml * Update test-php.yaml * Update test-php.yaml * Update test-php.yaml * Add more unit tests * Update CompilerTest.php * Update test-php.yaml * Update CompilerTest.php * Update test-php.yaml * Add test-php * Add concurrency thing Co-authored-by: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> * Remove php-actions/phpunit * Update .github/workflows/test-php.yaml --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Co-authored-by: Maximilian Roos --- .github/workflows/test-all.yaml | 3 + .github/workflows/test-php.yaml | 42 + book/src/bindings/README.md | 1 + book/src/bindings/php.md | 1 + prql-php/.gitignore | 1 + prql-php/README.md | 25 + prql-php/composer.json | 37 + prql-php/composer.lock | 1471 +++++++++++++++++++++++++++++++ prql-php/src/Compiler.php | 162 ++++ prql-php/src/Options.php | 54 ++ prql-php/tests/CompilerTest.php | 49 + 11 files changed, 1846 insertions(+) create mode 100644 .github/workflows/test-php.yaml create mode 100644 book/src/bindings/php.md create mode 100644 prql-php/.gitignore create mode 100644 prql-php/README.md create mode 100644 prql-php/composer.json create mode 100644 prql-php/composer.lock create mode 100644 prql-php/src/Compiler.php create mode 100644 prql-php/src/Options.php create mode 100644 prql-php/tests/CompilerTest.php diff --git a/.github/workflows/test-all.yaml b/.github/workflows/test-all.yaml index 3646199f3c43..065698e9baca 100644 --- a/.github/workflows/test-all.yaml +++ b/.github/workflows/test-all.yaml @@ -32,6 +32,9 @@ jobs: os: ${{ matrix.os }} target_option: ${{ matrix.target_option }} + test-php: + uses: ./.github/workflows/test-php.yaml + test-python: uses: ./.github/workflows/test-python.yaml diff --git a/.github/workflows/test-php.yaml b/.github/workflows/test-php.yaml new file mode 100644 index 000000000000..af2b19202350 --- /dev/null +++ b/.github/workflows/test-php.yaml @@ -0,0 +1,42 @@ +name: test-php + +on: + pull_request: + paths: + - "prql-php/**" + - ".github/workflows/test-php.yaml" + workflow_call: + +concurrency: + # See notes in `pull-request.yaml` + group: ${{ github.workflow }}-${{ github.ref }}-php + cancel-in-progress: true + +jobs: + test: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest] + steps: + - name: 📂 Checkout code + uses: actions/checkout@v3 + - uses: actions-rs/toolchain@v1 + with: + toolchain: stable + - run: cargo build + working-directory: prql-lib + - run: | + mv ../target/debug/libprql_lib.so ../prql-php/src/libprql_lib.so + ls -l ../target/debug/ + uname -a + ls -lR ../prql-php/ + working-directory: prql-lib + - name: 📦 Install dependencies using Composer + uses: php-actions/composer@v6 + with: + args: --working-dir=prql-php + php_extensions: FFI + - name: 🧪 Run tests using PHPUnit + run: vendor/bin/phpunit tests + working-directory: prql-php diff --git a/book/src/bindings/README.md b/book/src/bindings/README.md index f7056439154f..7d02f68f90dc 100644 --- a/book/src/bindings/README.md +++ b/book/src/bindings/README.md @@ -4,6 +4,7 @@ PRQL has bindings for many languages. These include: - [Java](./java.md) - [JavaScript](./javascript.md) +- [PHP](./php.md) - [Python](./python.md) - [R](./r.md) - [Rust](./rust.md) diff --git a/book/src/bindings/php.md b/book/src/bindings/php.md new file mode 100644 index 000000000000..e168db425270 --- /dev/null +++ b/book/src/bindings/php.md @@ -0,0 +1 @@ +{{#include ../../../prql-php/README.md}} diff --git a/prql-php/.gitignore b/prql-php/.gitignore new file mode 100644 index 000000000000..61ead86667ca --- /dev/null +++ b/prql-php/.gitignore @@ -0,0 +1 @@ +/vendor diff --git a/prql-php/README.md b/prql-php/README.md new file mode 100644 index 000000000000..3b417479a4c4 --- /dev/null +++ b/prql-php/README.md @@ -0,0 +1,25 @@ +# prql-php + +`prql-php` offers PHP bindings through FFI. + +It provides the `Compiler` class which contains the `toJson` and `toSql` +methods. + +It's still at an early stage, and isn't published to Composer. Contributions are +welcome. + +## Installation + +The [PHP FFI extension](https://www.php.net/manual/en/book.ffi.php) needs to be +enabled. Set `ffi.enable` in your php.ini configuration file to `"true"`. + +## Usage + +```php +toSql("from employees"); +``` diff --git a/prql-php/composer.json b/prql-php/composer.json new file mode 100644 index 000000000000..7fad323e451e --- /dev/null +++ b/prql-php/composer.json @@ -0,0 +1,37 @@ +{ + "name": "prql/compiler", + "description": "PRQL compiler bindings.", + "keywords": [ + "prql", + "sql" + ], + "homepage": "https://prql-lang.org/", + "type": "library", + "license": "Apache-2.0", + "autoload": { + "psr-4": { + "Prql\\Compiler\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "Prql\\Tests\\": "tests/" + } + }, + "authors": [ + { + "name": "Jonathan" + } + ], + "support": { + "issues": "https://github.com/PRQL/prql/issues", + "source": "https://github.com/PRQL/prql", + "docs": "https://prql-lang.org/book/" + }, + "require": { + "ext-ffi": "*" + }, + "require-dev": { + "phpunit/phpunit": "^10" + } +} diff --git a/prql-php/composer.lock b/prql-php/composer.lock new file mode 100644 index 000000000000..bb8cb1d27700 --- /dev/null +++ b/prql-php/composer.lock @@ -0,0 +1,1471 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "a4068cec0f3425baf61d7b880f827bea", + "packages": [], + "packages-dev": [ + { + "name": "myclabs/deep-copy", + "version": "1.11.0", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/14daed4296fae74d9e3201d2c4925d1acb7aa614", + "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "conflict": { + "doctrine/collections": "<1.6.8", + "doctrine/common": "<2.13.3 || >=3,<3.2.2" + }, + "require-dev": { + "doctrine/collections": "^1.6.8", + "doctrine/common": "^2.13.3 || ^3.2.2", + "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" + }, + "type": "library", + "autoload": { + "files": ["src/DeepCopy/deep_copy.php"], + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": ["MIT"], + "description": "Create deep copies (clones) of your objects", + "keywords": ["clone", "copy", "duplicate", "object", "object graph"], + "support": { + "issues": "https://github.com/myclabs/DeepCopy/issues", + "source": "https://github.com/myclabs/DeepCopy/tree/1.11.0" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" + } + ], + "time": "2022-03-03T13:19:32+00:00" + }, + { + "name": "nikic/php-parser", + "version": "v4.15.3", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "570e980a201d8ed0236b0a62ddf2c9cbb2034039" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/570e980a201d8ed0236b0a62ddf2c9cbb2034039", + "reference": "570e980a201d8ed0236b0a62ddf2c9cbb2034039", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=7.0" + }, + "require-dev": { + "ircmaxell/php-yacc": "^0.0.7", + "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" + }, + "bin": ["bin/php-parse"], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.9-dev" + } + }, + "autoload": { + "psr-4": { + "PhpParser\\": "lib/PhpParser" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": ["BSD-3-Clause"], + "authors": [ + { + "name": "Nikita Popov" + } + ], + "description": "A PHP parser written in PHP", + "keywords": ["parser", "php"], + "support": { + "issues": "https://github.com/nikic/PHP-Parser/issues", + "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.3" + }, + "time": "2023-01-16T22:05:37+00:00" + }, + { + "name": "phar-io/manifest", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/phar-io/manifest.git", + "reference": "97803eca37d319dfa7826cc2437fc020857acb53" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53", + "reference": "97803eca37d319dfa7826cc2437fc020857acb53", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-phar": "*", + "ext-xmlwriter": "*", + "phar-io/version": "^3.0.1", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": ["src/"] + }, + "notification-url": "https://packagist.org/downloads/", + "license": ["BSD-3-Clause"], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "support": { + "issues": "https://github.com/phar-io/manifest/issues", + "source": "https://github.com/phar-io/manifest/tree/2.0.3" + }, + "time": "2021-07-20T11:28:43+00:00" + }, + { + "name": "phar-io/version", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/version.git", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": ["src/"] + }, + "notification-url": "https://packagist.org/downloads/", + "license": ["BSD-3-Clause"], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Library for handling version information and constraints", + "support": { + "issues": "https://github.com/phar-io/version/issues", + "source": "https://github.com/phar-io/version/tree/3.2.1" + }, + "time": "2022-02-21T01:04:05+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "10.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "bf4fbc9c13af7da12b3ea807574fb460f255daba" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/bf4fbc9c13af7da12b3ea807574fb460f255daba", + "reference": "bf4fbc9c13af7da12b3ea807574fb460f255daba", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-xmlwriter": "*", + "nikic/php-parser": "^4.14", + "php": ">=8.1", + "phpunit/php-file-iterator": "^4.0", + "phpunit/php-text-template": "^3.0", + "sebastian/code-unit-reverse-lookup": "^3.0", + "sebastian/complexity": "^3.0", + "sebastian/environment": "^6.0", + "sebastian/lines-of-code": "^2.0", + "sebastian/version": "^4.0", + "theseer/tokenizer": "^1.2.0" + }, + "require-dev": { + "phpunit/phpunit": "^10.0" + }, + "suggest": { + "ext-pcov": "*", + "ext-xdebug": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "10.0-dev" + } + }, + "autoload": { + "classmap": ["src/"] + }, + "notification-url": "https://packagist.org/downloads/", + "license": ["BSD-3-Clause"], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": ["coverage", "testing", "xunit"], + "support": { + "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T07:14:34+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "4.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "fd9329ab3368f59fe1fe808a189c51086bd4b6bd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/fd9329ab3368f59fe1fe808a189c51086bd4b6bd", + "reference": "fd9329ab3368f59fe1fe808a189c51086bd4b6bd", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "phpunit/phpunit": "^10.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": ["src/"] + }, + "notification-url": "https://packagist.org/downloads/", + "license": ["BSD-3-Clause"], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": ["filesystem", "iterator"], + "support": { + "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/4.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-10T16:53:14+00:00" + }, + { + "name": "phpunit/php-invoker", + "version": "4.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-invoker.git", + "reference": "f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7", + "reference": "f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "ext-pcntl": "*", + "phpunit/phpunit": "^10.0" + }, + "suggest": { + "ext-pcntl": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": ["src/"] + }, + "notification-url": "https://packagist.org/downloads/", + "license": ["BSD-3-Clause"], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Invoke callables with a timeout", + "homepage": "https://github.com/sebastianbergmann/php-invoker/", + "keywords": ["process"], + "support": { + "issues": "https://github.com/sebastianbergmann/php-invoker/issues", + "source": "https://github.com/sebastianbergmann/php-invoker/tree/4.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:56:09+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "9f3d3709577a527025f55bcf0f7ab8052c8bb37d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/9f3d3709577a527025f55bcf0f7ab8052c8bb37d", + "reference": "9f3d3709577a527025f55bcf0f7ab8052c8bb37d", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "phpunit/phpunit": "^10.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.0-dev" + } + }, + "autoload": { + "classmap": ["src/"] + }, + "notification-url": "https://packagist.org/downloads/", + "license": ["BSD-3-Clause"], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": ["template"], + "support": { + "issues": "https://github.com/sebastianbergmann/php-text-template/issues", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/3.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:56:46+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "6.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "e2a2d67966e740530f4a3343fe2e030ffdc1161d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/e2a2d67966e740530f4a3343fe2e030ffdc1161d", + "reference": "e2a2d67966e740530f4a3343fe2e030ffdc1161d", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "phpunit/phpunit": "^10.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": ["src/"] + }, + "notification-url": "https://packagist.org/downloads/", + "license": ["BSD-3-Clause"], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": ["timer"], + "support": { + "issues": "https://github.com/sebastianbergmann/php-timer/issues", + "source": "https://github.com/sebastianbergmann/php-timer/tree/6.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:57:52+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "10.0.7", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "a6f61c5629dd95db79af72f1e94d56702187479a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a6f61c5629dd95db79af72f1e94d56702187479a", + "reference": "a6f61c5629dd95db79af72f1e94d56702187479a", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "ext-xmlwriter": "*", + "myclabs/deep-copy": "^1.10.1", + "phar-io/manifest": "^2.0.3", + "phar-io/version": "^3.0.2", + "php": ">=8.1", + "phpunit/php-code-coverage": "^10.0", + "phpunit/php-file-iterator": "^4.0", + "phpunit/php-invoker": "^4.0", + "phpunit/php-text-template": "^3.0", + "phpunit/php-timer": "^6.0", + "sebastian/cli-parser": "^2.0", + "sebastian/code-unit": "^2.0", + "sebastian/comparator": "^5.0", + "sebastian/diff": "^5.0", + "sebastian/environment": "^6.0", + "sebastian/exporter": "^5.0", + "sebastian/global-state": "^6.0", + "sebastian/object-enumerator": "^5.0", + "sebastian/recursion-context": "^5.0", + "sebastian/type": "^4.0", + "sebastian/version": "^4.0" + }, + "suggest": { + "ext-soap": "*" + }, + "bin": ["phpunit"], + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "10.0-dev" + } + }, + "autoload": { + "files": ["src/Framework/Assert/Functions.php"], + "classmap": ["src/"] + }, + "notification-url": "https://packagist.org/downloads/", + "license": ["BSD-3-Clause"], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": ["phpunit", "testing", "xunit"], + "support": { + "issues": "https://github.com/sebastianbergmann/phpunit/issues", + "source": "https://github.com/sebastianbergmann/phpunit/tree/10.0.7" + }, + "funding": [ + { + "url": "https://phpunit.de/sponsors.html", + "type": "custom" + }, + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", + "type": "tidelift" + } + ], + "time": "2023-02-08T15:16:31+00:00" + }, + { + "name": "sebastian/cli-parser", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/cli-parser.git", + "reference": "efdc130dbbbb8ef0b545a994fd811725c5282cae" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/efdc130dbbbb8ef0b545a994fd811725c5282cae", + "reference": "efdc130dbbbb8ef0b545a994fd811725c5282cae", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "phpunit/phpunit": "^10.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.0-dev" + } + }, + "autoload": { + "classmap": ["src/"] + }, + "notification-url": "https://packagist.org/downloads/", + "license": ["BSD-3-Clause"], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for parsing CLI options", + "homepage": "https://github.com/sebastianbergmann/cli-parser", + "support": { + "issues": "https://github.com/sebastianbergmann/cli-parser/issues", + "source": "https://github.com/sebastianbergmann/cli-parser/tree/2.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:58:15+00:00" + }, + { + "name": "sebastian/code-unit", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit.git", + "reference": "a81fee9eef0b7a76af11d121767abc44c104e503" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/a81fee9eef0b7a76af11d121767abc44c104e503", + "reference": "a81fee9eef0b7a76af11d121767abc44c104e503", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "phpunit/phpunit": "^10.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.0-dev" + } + }, + "autoload": { + "classmap": ["src/"] + }, + "notification-url": "https://packagist.org/downloads/", + "license": ["BSD-3-Clause"], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the PHP code units", + "homepage": "https://github.com/sebastianbergmann/code-unit", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit/issues", + "source": "https://github.com/sebastianbergmann/code-unit/tree/2.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:58:43+00:00" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "5e3a687f7d8ae33fb362c5c0743794bbb2420a1d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/5e3a687f7d8ae33fb362c5c0743794bbb2420a1d", + "reference": "5e3a687f7d8ae33fb362c5c0743794bbb2420a1d", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "phpunit/phpunit": "^10.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.0-dev" + } + }, + "autoload": { + "classmap": ["src/"] + }, + "notification-url": "https://packagist.org/downloads/", + "license": ["BSD-3-Clause"], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Looks up which function or method a line of code belongs to", + "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/3.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:59:15+00:00" + }, + { + "name": "sebastian/comparator", + "version": "5.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "72f01e6586e0caf6af81297897bd112eb7e9627c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/72f01e6586e0caf6af81297897bd112eb7e9627c", + "reference": "72f01e6586e0caf6af81297897bd112eb7e9627c", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-mbstring": "*", + "php": ">=8.1", + "sebastian/diff": "^5.0", + "sebastian/exporter": "^5.0" + }, + "require-dev": { + "phpunit/phpunit": "^10.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.0-dev" + } + }, + "autoload": { + "classmap": ["src/"] + }, + "notification-url": "https://packagist.org/downloads/", + "license": ["BSD-3-Clause"], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "https://github.com/sebastianbergmann/comparator", + "keywords": ["comparator", "compare", "equality"], + "support": { + "issues": "https://github.com/sebastianbergmann/comparator/issues", + "source": "https://github.com/sebastianbergmann/comparator/tree/5.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T07:07:16+00:00" + }, + { + "name": "sebastian/complexity", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/complexity.git", + "reference": "e67d240970c9dc7ea7b2123a6d520e334dd61dc6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/e67d240970c9dc7ea7b2123a6d520e334dd61dc6", + "reference": "e67d240970c9dc7ea7b2123a6d520e334dd61dc6", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^4.10", + "php": ">=8.1" + }, + "require-dev": { + "phpunit/phpunit": "^10.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.0-dev" + } + }, + "autoload": { + "classmap": ["src/"] + }, + "notification-url": "https://packagist.org/downloads/", + "license": ["BSD-3-Clause"], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for calculating the complexity of PHP code units", + "homepage": "https://github.com/sebastianbergmann/complexity", + "support": { + "issues": "https://github.com/sebastianbergmann/complexity/issues", + "source": "https://github.com/sebastianbergmann/complexity/tree/3.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:59:47+00:00" + }, + { + "name": "sebastian/diff", + "version": "5.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "70dd1b20bc198da394ad542e988381b44e64e39f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/70dd1b20bc198da394ad542e988381b44e64e39f", + "reference": "70dd1b20bc198da394ad542e988381b44e64e39f", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "phpunit/phpunit": "^10.0", + "symfony/process": "^4.2 || ^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.0-dev" + } + }, + "autoload": { + "classmap": ["src/"] + }, + "notification-url": "https://packagist.org/downloads/", + "license": ["BSD-3-Clause"], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": ["diff", "udiff", "unidiff", "unified diff"], + "support": { + "issues": "https://github.com/sebastianbergmann/diff/issues", + "source": "https://github.com/sebastianbergmann/diff/tree/5.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T07:00:31+00:00" + }, + { + "name": "sebastian/environment", + "version": "6.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "b6f3694c6386c7959915a0037652e0c40f6f69cc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/b6f3694c6386c7959915a0037652e0c40f6f69cc", + "reference": "b6f3694c6386c7959915a0037652e0c40f6f69cc", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "phpunit/phpunit": "^10.0" + }, + "suggest": { + "ext-posix": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": ["src/"] + }, + "notification-url": "https://packagist.org/downloads/", + "license": ["BSD-3-Clause"], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "https://github.com/sebastianbergmann/environment", + "keywords": ["Xdebug", "environment", "hhvm"], + "support": { + "issues": "https://github.com/sebastianbergmann/environment/issues", + "source": "https://github.com/sebastianbergmann/environment/tree/6.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T07:03:04+00:00" + }, + { + "name": "sebastian/exporter", + "version": "5.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "f3ec4bf931c0b31e5b413f5b4fc970a7d03338c0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/f3ec4bf931c0b31e5b413f5b4fc970a7d03338c0", + "reference": "f3ec4bf931c0b31e5b413f5b4fc970a7d03338c0", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": ">=8.1", + "sebastian/recursion-context": "^5.0" + }, + "require-dev": { + "phpunit/phpunit": "^10.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.0-dev" + } + }, + "autoload": { + "classmap": ["src/"] + }, + "notification-url": "https://packagist.org/downloads/", + "license": ["BSD-3-Clause"], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "https://www.github.com/sebastianbergmann/exporter", + "keywords": ["export", "exporter"], + "support": { + "issues": "https://github.com/sebastianbergmann/exporter/issues", + "source": "https://github.com/sebastianbergmann/exporter/tree/5.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T07:06:49+00:00" + }, + { + "name": "sebastian/global-state", + "version": "6.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "aab257c712de87b90194febd52e4d184551c2d44" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/aab257c712de87b90194febd52e4d184551c2d44", + "reference": "aab257c712de87b90194febd52e4d184551c2d44", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "sebastian/object-reflector": "^3.0", + "sebastian/recursion-context": "^5.0" + }, + "require-dev": { + "ext-dom": "*", + "phpunit/phpunit": "^10.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": ["src/"] + }, + "notification-url": "https://packagist.org/downloads/", + "license": ["BSD-3-Clause"], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", + "keywords": ["global state"], + "support": { + "issues": "https://github.com/sebastianbergmann/global-state/issues", + "source": "https://github.com/sebastianbergmann/global-state/tree/6.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T07:07:38+00:00" + }, + { + "name": "sebastian/lines-of-code", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/lines-of-code.git", + "reference": "17c4d940ecafb3d15d2cf916f4108f664e28b130" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/17c4d940ecafb3d15d2cf916f4108f664e28b130", + "reference": "17c4d940ecafb3d15d2cf916f4108f664e28b130", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^4.10", + "php": ">=8.1" + }, + "require-dev": { + "phpunit/phpunit": "^10.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.0-dev" + } + }, + "autoload": { + "classmap": ["src/"] + }, + "notification-url": "https://packagist.org/downloads/", + "license": ["BSD-3-Clause"], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for counting the lines of code in PHP source code", + "homepage": "https://github.com/sebastianbergmann/lines-of-code", + "support": { + "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/2.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T07:08:02+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "5.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "202d0e344a580d7f7d04b3fafce6933e59dae906" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/202d0e344a580d7f7d04b3fafce6933e59dae906", + "reference": "202d0e344a580d7f7d04b3fafce6933e59dae906", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "sebastian/object-reflector": "^3.0", + "sebastian/recursion-context": "^5.0" + }, + "require-dev": { + "phpunit/phpunit": "^10.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.0-dev" + } + }, + "autoload": { + "classmap": ["src/"] + }, + "notification-url": "https://packagist.org/downloads/", + "license": ["BSD-3-Clause"], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/5.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T07:08:32+00:00" + }, + { + "name": "sebastian/object-reflector", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "24ed13d98130f0e7122df55d06c5c4942a577957" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/24ed13d98130f0e7122df55d06c5c4942a577957", + "reference": "24ed13d98130f0e7122df55d06c5c4942a577957", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "phpunit/phpunit": "^10.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.0-dev" + } + }, + "autoload": { + "classmap": ["src/"] + }, + "notification-url": "https://packagist.org/downloads/", + "license": ["BSD-3-Clause"], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Allows reflection of object attributes, including inherited and non-public ones", + "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-reflector/issues", + "source": "https://github.com/sebastianbergmann/object-reflector/tree/3.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T07:06:18+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "5.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "05909fb5bc7df4c52992396d0116aed689f93712" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/05909fb5bc7df4c52992396d0116aed689f93712", + "reference": "05909fb5bc7df4c52992396d0116aed689f93712", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "phpunit/phpunit": "^10.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.0-dev" + } + }, + "autoload": { + "classmap": ["src/"] + }, + "notification-url": "https://packagist.org/downloads/", + "license": ["BSD-3-Clause"], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "https://github.com/sebastianbergmann/recursion-context", + "support": { + "issues": "https://github.com/sebastianbergmann/recursion-context/issues", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/5.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T07:05:40+00:00" + }, + { + "name": "sebastian/type", + "version": "4.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "462699a16464c3944eefc02ebdd77882bd3925bf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/462699a16464c3944eefc02ebdd77882bd3925bf", + "reference": "462699a16464c3944eefc02ebdd77882bd3925bf", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "phpunit/phpunit": "^10.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": ["src/"] + }, + "notification-url": "https://packagist.org/downloads/", + "license": ["BSD-3-Clause"], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the types of the PHP type system", + "homepage": "https://github.com/sebastianbergmann/type", + "support": { + "issues": "https://github.com/sebastianbergmann/type/issues", + "source": "https://github.com/sebastianbergmann/type/tree/4.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T07:10:45+00:00" + }, + { + "name": "sebastian/version", + "version": "4.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "c51fa83a5d8f43f1402e3f32a005e6262244ef17" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c51fa83a5d8f43f1402e3f32a005e6262244ef17", + "reference": "c51fa83a5d8f43f1402e3f32a005e6262244ef17", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": ["src/"] + }, + "notification-url": "https://packagist.org/downloads/", + "license": ["BSD-3-Clause"], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "support": { + "issues": "https://github.com/sebastianbergmann/version/issues", + "source": "https://github.com/sebastianbergmann/version/tree/4.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-07T11:34:05+00:00" + }, + { + "name": "theseer/tokenizer", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/theseer/tokenizer.git", + "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e", + "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": ["src/"] + }, + "notification-url": "https://packagist.org/downloads/", + "license": ["BSD-3-Clause"], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + } + ], + "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", + "support": { + "issues": "https://github.com/theseer/tokenizer/issues", + "source": "https://github.com/theseer/tokenizer/tree/1.2.1" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2021-07-28T10:34:58+00:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "ext-ffi": "*" + }, + "platform-dev": [], + "plugin-api-version": "2.3.0" +} diff --git a/prql-php/src/Compiler.php b/prql-php/src/Compiler.php new file mode 100644 index 000000000000..5be55ea51962 --- /dev/null +++ b/prql-php/src/Compiler.php @@ -0,0 +1,162 @@ +new("struct options"); + $ffi_options->format = $options->format; + $ffi_options->signature_comment = $options->signature_comment; + + if (isset($options->target)) { + $target_len = strlen($options->target); + $ffi_options->target = $ffi->new('char[$target_len]', 0); + FFI::memcpy($ffi_options->target, $options->target, $target_len); + FFI::free($ffi_options->target); + } + + $out = str_pad("", 1024); + if ($libprql->compile($prql_query, \FFI::addr($$ffi_options)) !== 0) { + throw new \InvalidArgumentException("Could not compile query."); + } + + return trim($out); + } + + /** + * Compile a PRQL string into a JSON string. + * + * @param string $prql_query A PRQL query. + * + * @return string JSON string. + * @throws \InvalidArgumentException If no query is given or the query cannot + * be compiled. + * @api + */ + function toJson(string $prql_query): string + { + if (!$prql_query) { + throw new \InvalidArgumentException("No query given."); + } + + $library = "/libprql_lib.so"; + + if (PHP_OS_FAMILY === "Windows") { + $library = "\libprql_lib.dll"; + } + + $libprql = \FFI::cdef( + "int to_json(char *prql_query, char *json_query);", + __DIR__ . $library + ); + + $out = str_pad("", 1024); + if ($libprql->to_json($prql_query, $out) !== 0) { + throw new \InvalidArgumentException("Could not compile query."); + } + + return trim($out); + } + + /** + * Compile a PRQL string into a SQL string. + * + * @param string $prql_query A PRQL query. + * + * @return string SQL query. + * @throws \InvalidArgumentException If no query is given or the query cannot + * be compiled. + * @api + */ + function toSql(string $prql_query): string + { + if (!$prql_query) { + throw new \InvalidArgumentException("No query given."); + } + + $library = "/libprql_lib.so"; + + if (PHP_OS_FAMILY === "Windows") { + $library = "\libprql_lib.dll"; + } + + $libprql = \FFI::cdef( + "int to_sql(char *prql_query, char *sql_query);", + __DIR__ . $library + ); + + $out = str_pad("", 1024); + if ($libprql->to_sql($prql_query, $out) !== 0) { + throw new \InvalidArgumentException("Could not compile query."); + } + + return trim($out); + } +} diff --git a/prql-php/src/Options.php b/prql-php/src/Options.php new file mode 100644 index 000000000000..3b76344df3e2 --- /dev/null +++ b/prql-php/src/Options.php @@ -0,0 +1,54 @@ +assertTrue(extension_loaded("ffi")); + } + + public function testPrqlLibraryFileExists(): void + { + $this->assertFileExists("src/libprql_lib.so"); + } + + public function testPrqlLibraryLoads(): void + { + $code = "int to_sql(char *prql_query, char *sql_query);"; + $ffi = FFI::cdef($code, "src/libprql_lib.so"); + $this->assertInstanceOf(FFI::class, $ffi); + } + + public function testInvalidQueryThrows(): void + { + $this->expectException(\InvalidArgumentException::class); + + $prql = new Compiler(); + $prql->toSql("invalid"); + } + + public function testToSqlWorks(): void + { + $expected = <<<'EOD' +SELECT + * +FROM + employees + +-- Generated by PRQL compiler version:0.5.0 (https://prql-lang.org) +EOD; + $expected = substr($expected, 0, strpos($expected, "Generated by PRQL compiler")); + $prql = new Compiler(); + $actual = $prql->toSql("from employees"); + $actual = substr($actual, 0, strpos($actual, "Generated by PRQL compiler")); + $this->assertEquals($expected, $actual); + } +} From b965aba270777f811897cec2678cc98c537e9a0a Mon Sep 17 00:00:00 2001 From: Jonathan Date: Tue, 21 Feb 2023 01:53:53 +0100 Subject: [PATCH 020/106] chore: Add PHP bindings changelog (#1914) Add PHP bindings --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fa1d666d8796..81379273a7f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ **Integrations**: +- [prql-php] Added PHP bindings (@vanillajonathan, #1860) - [prql-lib] Added C header file (@vanillajonathan, #1879) **Internal changes**: From 2ecdfaac4796e12772afd0394268fdd9f366ab02 Mon Sep 17 00:00:00 2001 From: Jonathan Date: Tue, 21 Feb 2023 02:16:33 +0100 Subject: [PATCH 021/106] build: Package prqlc as .deb package (#1883) * Create create-deb.yaml * Update create-deb.yaml * Update create-deb.yaml * Update create-deb.yaml * Add build-deb-package job * Delete create-deb.yaml * Update .github/workflows/release.yaml * Update .github/workflows/release.yaml * Update .github/workflows/release.yaml --------- Co-authored-by: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Co-authored-by: Maximilian Roos --- .github/workflows/release.yaml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index d7d944410b54..252d16dbabdb 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -24,6 +24,30 @@ jobs: } }) + build-deb-package: + # TODO: currently this doesn't publish it as an artifact; would be a welcome contribution + # to add that (and eventually as a release asset) + runs-on: ubuntu-latest + steps: + - name: 📂 Checkout code + uses: actions/checkout@v3 + - name: 👷 Build prql-compiler + run: cargo build --release + - name: Copy files into .deb package + run: | + mkdir -p .debpkg/usr/bin + cp target/release/prqlc .debpkg/usr/bin/prqlc + chmod +x .debpkg/usr/bin/prqlc + - name: 📦 Build .deb package + uses: jiro4989/build-deb-action@v2 + with: + package: prqlc + package_root: .debpkg + maintainer: The PRQL Project + version: "${{ github.ref }}" + desc: + prqlc is the CLI for PRQL, a modern language for transforming data + build-python-wheels: runs-on: ${{ matrix.os }} strategy: From 68752b7806cee40af10b22d44609230ed2a78dc1 Mon Sep 17 00:00:00 2001 From: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Date: Mon, 20 Feb 2023 23:48:07 -0800 Subject: [PATCH 022/106] test: Add `--quiet` to fast-loop taskfile command (#1916) Otherwise cargo lists the name of every test; very verbose IMO. --- Taskfile.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Taskfile.yml b/Taskfile.yml index ec901be0fa55..15995412728a 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -233,7 +233,7 @@ tasks: - "prql-compiler/**/*.pest" - "prql-compiler/**/*.snap" cmds: - - cargo insta test --accept -p prql-compiler --lib + - cargo insta test --accept -p prql-compiler --lib -- --quiet build-web: desc: Build the website, including the book & playground. From f489690d0db2ddd391f229002509fa8fb97b8469 Mon Sep 17 00:00:00 2001 From: Jonathan Date: Tue, 21 Feb 2023 18:58:42 +0100 Subject: [PATCH 023/106] build: Package`prqlc` as Snap (#1881) * Create snapcraft.yaml * Update snapcraft.yaml * Create publish-snap.yaml * Update publish-snap.yaml * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Update prql-compiler/snap/snapcraft.yaml Co-authored-by: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> * Update publish-snap.yaml * Update snapcraft.yaml * Update and rename prql-compiler/snap/snapcraft.yaml to snap/snapcraft.yaml * Update publish-snap.yaml * Update snap/snapcraft.yaml Co-authored-by: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> * Add step to build and publish Snap * Delete publish-snap.yaml --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> --- .github/workflows/release.yaml | 19 +++++++++++++++++++ snap/snapcraft.yaml | 28 ++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 snap/snapcraft.yaml diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 252d16dbabdb..d743b489baf7 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -48,6 +48,25 @@ jobs: desc: prqlc is the CLI for PRQL, a modern language for transforming data + build-and-publish-snap: + runs-on: ubuntu-latest + + # Skip running workflow on forks + if: github.repository_owner == 'prql' + + steps: + - name: 📂 Checkout code + uses: actions/checkout@v3 + - name: 📦 Build Snap + uses: snapcore/action-build@v1 + - name: 🆙 Publish Snap + uses: snapcore/action-publish@v1 + env: + SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.STORE_LOGIN }} + with: + snap: ${{ steps.build.outputs.snap }} + release: edge + build-python-wheels: runs-on: ${{ matrix.os }} strategy: diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml new file mode 100644 index 000000000000..6f9bda5cd9a7 --- /dev/null +++ b/snap/snapcraft.yaml @@ -0,0 +1,28 @@ +name: prqlc # you probably want to 'snapcraft register ' +title: PRQL Compiler +base: core20 # the base snap is the execution environment for this snap +version: git +summary: PRQL is a modern language for transforming data +description: | + PRQL is a modern language for transforming data — a simple, powerful, + pipelined SQL replacement. +issues: https://github.com/PRQL/prql/issues +source-code: https://github.com/PRQL/prql +contact: https://twitter.com/prql_lang +website: https://prql-lang.org/ +license: Apache-2.0 +grade: devel # must be 'stable' to release into candidate/stable channels +confinement: strict +icon: website/themes/prql-theme/static/icon.svg + +parts: + prqlc: + plugin: rust + source: . + rust-path: [prql-compiler/prqlc] + +apps: + prqlc: + command: bin/prqlc + plugs: + - home From f765378e654f520173ef38e3cddedc4a64096a41 Mon Sep 17 00:00:00 2001 From: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Date: Tue, 21 Feb 2023 10:33:18 -0800 Subject: [PATCH 024/106] chore: Add changelog for #1883 (#1920) As requested by @vanillajonathan. @vanillajonathan one thing we could add for all these is to upload them as artifacts, as an easy way to have them published, using something like https://github.com/PRQL/prql/pull/1883#discussion_r1112342801. It's less permanent than publishing them as release assets, but we can do the artifact upload now without changing our release process. --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 81379273a7f8..80645f98bf6d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,8 @@ - [prql-php] Added PHP bindings (@vanillajonathan, #1860) - [prql-lib] Added C header file (@vanillajonathan, #1879) +- Added a workflow building a `.deb` on each release. (Note that it's not yet + published on each release). (@vanillajonathan, #1883) **Internal changes**: From ba2c01c7a7ed013ff3cf4f9ec80a7a08024df16b Mon Sep 17 00:00:00 2001 From: Jonathan Date: Tue, 21 Feb 2023 21:47:13 +0100 Subject: [PATCH 025/106] chore: Add Snap package changelog (#1921) * Add Snap package * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- CHANGELOG.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 80645f98bf6d..340164cfa4a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,10 +12,12 @@ **Integrations**: -- [prql-php] Added PHP bindings (@vanillajonathan, #1860) -- [prql-lib] Added C header file (@vanillajonathan, #1879) +- [prql-php] Added PHP bindings. (@vanillajonathan, #1860) +- [prql-lib] Added C header file. (@vanillajonathan, #1879) - Added a workflow building a `.deb` on each release. (Note that it's not yet published on each release). (@vanillajonathan, #1883) +- Added a workflow building a Snap package on each release. (@vanillajonathan, + #1881) **Internal changes**: From 83b5a79c19d5fc89742e450626b6ab6883b0f18c Mon Sep 17 00:00:00 2001 From: Jonathan Date: Tue, 21 Feb 2023 21:55:32 +0100 Subject: [PATCH 026/106] build: Package prqlc as .rpm package (#1918) * Create create-rpm.yaml * Update create-rpm.yaml * Add job for building .rpm package * Delete create-rpm.yaml * Update .github/workflows/release.yaml Co-authored-by: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> * Update .github/workflows/release.yaml Co-authored-by: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> * Update release.yaml * Update .github/workflows/release.yaml Co-authored-by: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> * Update .github/workflows/release.yaml * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Co-authored-by: Maximilian Roos Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .github/workflows/release.yaml | 29 ++++++++++++++++++++++++++++- prql-compiler/prqlc/x.prql | 3 +++ 2 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 prql-compiler/prqlc/x.prql diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index d743b489baf7..854963fbb02a 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -44,10 +44,37 @@ jobs: package: prqlc package_root: .debpkg maintainer: The PRQL Project - version: "${{ github.ref }}" + version: ${{ github.ref }} desc: prqlc is the CLI for PRQL, a modern language for transforming data + build-rpm-package: + # TODO: This doesn't publish the rpm yet, that would be a welcome follow-up (even as a CI artifact) + runs-on: ubuntu-latest + steps: + - name: 📂 Checkout code + uses: actions/checkout@v3 + - name: 👷 Build prqlc + run: cargo build --bin prqlc --release + - name: Copy files into .rpm package + run: | + mkdir -p .rpmpkg/usr/bin + cp target/release/prqlc .rpmpkg/usr/bin/prqlc + chmod +x .rpmpkg/usr/bin/prqlc + - name: 📦 Build .rpm package + uses: jiro4989/build-rpm-action@v2 + with: + summary: CLI for PRQL, a modern language for transforming data + package: prqlc + package_root: .rpmpkg + maintainer: The PRQL Project + version: ${{ github.ref }} + desc: | + prqlc is the CLI for the PRQL compiler. It compiles PRQL to SQL, and offers various diagnostics. + + PRQL is a modern language for transforming data — a simple, powerful, pipelined SQL replacement. + license: Apache-2.0 + build-and-publish-snap: runs-on: ubuntu-latest diff --git a/prql-compiler/prqlc/x.prql b/prql-compiler/prqlc/x.prql new file mode 100644 index 000000000000..ed56de0b1bc9 --- /dev/null +++ b/prql-compiler/prqlc/x.prql @@ -0,0 +1,3 @@ +let x = 2 + 2 + +from x From 36a0a1e7a26fff594043cf26575ba1dd378d4d7a Mon Sep 17 00:00:00 2001 From: Jonathan Date: Tue, 21 Feb 2023 22:51:35 +0100 Subject: [PATCH 027/106] feat: Add .NET bindings (#1917) --- .github/workflows/test-dotnet.yaml | 33 +++++ CHANGELOG.md | 1 + book/src/bindings/README.md | 1 + book/src/bindings/net.md | 1 + .../PrqlCompiler.Tests/CompilerTest.cs | 23 ++++ .../PrqlCompiler.Tests.csproj | 28 +++++ prql-dotnet/PrqlCompiler.Tests/Usings.cs | 1 + prql-dotnet/PrqlCompiler/PrqlCompiler.cs | 113 ++++++++++++++++++ prql-dotnet/PrqlCompiler/PrqlCompiler.csproj | 28 +++++ .../PrqlCompiler/PrqlCompilerOptions.cs | 26 ++++ prql-dotnet/README.md | 33 +++++ prql-dotnet/prql-net.sln | 28 +++++ 12 files changed, 316 insertions(+) create mode 100644 .github/workflows/test-dotnet.yaml create mode 100644 book/src/bindings/net.md create mode 100644 prql-dotnet/PrqlCompiler.Tests/CompilerTest.cs create mode 100644 prql-dotnet/PrqlCompiler.Tests/PrqlCompiler.Tests.csproj create mode 100644 prql-dotnet/PrqlCompiler.Tests/Usings.cs create mode 100644 prql-dotnet/PrqlCompiler/PrqlCompiler.cs create mode 100644 prql-dotnet/PrqlCompiler/PrqlCompiler.csproj create mode 100644 prql-dotnet/PrqlCompiler/PrqlCompilerOptions.cs create mode 100644 prql-dotnet/README.md create mode 100644 prql-dotnet/prql-net.sln diff --git a/.github/workflows/test-dotnet.yaml b/.github/workflows/test-dotnet.yaml new file mode 100644 index 000000000000..eae9601d8d02 --- /dev/null +++ b/.github/workflows/test-dotnet.yaml @@ -0,0 +1,33 @@ +name: test-dotnet + +on: + pull_request: + paths: + - "prql-dotnet/**" + - ".github/workflows/test-dotnet.yaml" + workflow_call: + +concurrency: + # See notes in `pull-request.yaml` + group: ${{ github.workflow }}-${{ github.ref }}-dotnet + cancel-in-progress: true + +jobs: + test: + runs-on: ubuntu-latest + steps: + - name: 📂 Checkout code + uses: actions/checkout@v3 + - name: 🏗 Build prql-lib + run: cargo build + working-directory: prql-lib + - name: 🔧 Setup dotnet + uses: actions/setup-dotnet@v3 + with: + dotnet-version: 7 + - name: 🧪 Build and test + run: | + dotnet build prql-dotnet + cp target/debug/libprql_lib.* prql-dotnet/PrqlCompiler/bin/Debug/net*/ + cp target/debug/libprql_lib.* prql-dotnet/PrqlCompiler.Tests/bin/Debug/net*/ + dotnet test prql-dotnet diff --git a/CHANGELOG.md b/CHANGELOG.md index 340164cfa4a6..f0908cbf315b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ **Integrations**: - [prql-php] Added PHP bindings. (@vanillajonathan, #1860) +- [prql-dotnet] Added .NET bindings. (@vanillajonathan, #1917) - [prql-lib] Added C header file. (@vanillajonathan, #1879) - Added a workflow building a `.deb` on each release. (Note that it's not yet published on each release). (@vanillajonathan, #1883) diff --git a/book/src/bindings/README.md b/book/src/bindings/README.md index 7d02f68f90dc..216ac63f40aa 100644 --- a/book/src/bindings/README.md +++ b/book/src/bindings/README.md @@ -4,6 +4,7 @@ PRQL has bindings for many languages. These include: - [Java](./java.md) - [JavaScript](./javascript.md) +- [.NET](./net.md) - [PHP](./php.md) - [Python](./python.md) - [R](./r.md) diff --git a/book/src/bindings/net.md b/book/src/bindings/net.md new file mode 100644 index 000000000000..a1cdb27aa1e3 --- /dev/null +++ b/book/src/bindings/net.md @@ -0,0 +1 @@ +{{#include ../../../prql-net/README.md}} diff --git a/prql-dotnet/PrqlCompiler.Tests/CompilerTest.cs b/prql-dotnet/PrqlCompiler.Tests/CompilerTest.cs new file mode 100644 index 000000000000..a5afa68f0942 --- /dev/null +++ b/prql-dotnet/PrqlCompiler.Tests/CompilerTest.cs @@ -0,0 +1,23 @@ +using Prql.Compiler; + +namespace Prql.Compiler.Tests; + +sealed public class CompilerTest +{ + [Fact] + public void ToSql_Works() + { + // Arrange + var expected = "SELECT\n *\nFROM\n employees\n\n" + + "-- Generated by PRQL compiler version:x.y.z (https://prql-lang.org)\n"; + var signature = "-- Generated by PRQL compiler"; + expected = expected.Substring(0, expected.IndexOf(signature)); + + // Act + var sqlQuery = PrqlCompiler.ToSql("from employees"); + sqlQuery = sqlQuery.Substring(0, sqlQuery.IndexOf(signature)); + + // Assert + Assert.Equal(expected, sqlQuery); + } +} diff --git a/prql-dotnet/PrqlCompiler.Tests/PrqlCompiler.Tests.csproj b/prql-dotnet/PrqlCompiler.Tests/PrqlCompiler.Tests.csproj new file mode 100644 index 000000000000..9fb2ba1630fb --- /dev/null +++ b/prql-dotnet/PrqlCompiler.Tests/PrqlCompiler.Tests.csproj @@ -0,0 +1,28 @@ + + + + net7.0 + enable + enable + + false + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + diff --git a/prql-dotnet/PrqlCompiler.Tests/Usings.cs b/prql-dotnet/PrqlCompiler.Tests/Usings.cs new file mode 100644 index 000000000000..c802f4480b19 --- /dev/null +++ b/prql-dotnet/PrqlCompiler.Tests/Usings.cs @@ -0,0 +1 @@ +global using Xunit; diff --git a/prql-dotnet/PrqlCompiler/PrqlCompiler.cs b/prql-dotnet/PrqlCompiler/PrqlCompiler.cs new file mode 100644 index 000000000000..04843d088d05 --- /dev/null +++ b/prql-dotnet/PrqlCompiler/PrqlCompiler.cs @@ -0,0 +1,113 @@ +using System; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; + +namespace Prql.Compiler +{ + /// + /// The PRQL compiler transpiles RPQL queries. + /// + public static class PrqlCompiler + { + /// + /// Compile a PRQL string into a SQL string. + /// + /// A PRQL query. + /// SQL query. + /// is null or empty. + /// cannot be compiled. + public static string Compile(string prqlQuery) + { + if (string.IsNullOrEmpty(prqlQuery)) + { + throw new ArgumentException(nameof(prqlQuery)); + } + + return CompileExtern(prqlQuery); + } + + /// + /// Compile a PRQL string into a SQL string. + /// + /// A PRQL query. + /// PRQL compiler options. + /// SQL query. + /// is null or empty. + /// is null. + /// cannot be compiled. + public static string Compile(string prqlQuery, PrqlCompilerOptions options) + { + if (string.IsNullOrEmpty(prqlQuery)) + { + throw new ArgumentException(nameof(prqlQuery)); + } + + if (options == null) + { + throw new ArgumentNullException(nameof(options)); + } + + return CompileExtern(prqlQuery); + } + + /// + /// Compile a PRQL string into a JSON string. + /// + /// A PRQL query. + /// JSON. + /// is null or empty. + /// cannot be compiled. + public static string ToJson(string prqlQuery) + { + if (string.IsNullOrEmpty(prqlQuery)) + { + throw new ArgumentException(nameof(prqlQuery)); + } + + byte[] bytes = new byte[1024]; + if (ToJsonExtern(prqlQuery, bytes) != 0) + { + throw new FormatException("Could not compile query."); + } + + bytes = bytes.TakeWhile(x => ((char)x) != '\0').ToArray(); + + return Encoding.UTF8.GetString(bytes); + } + + /// + /// Compile a PRQL string into a SQL query. + /// + /// A PRQL query. + /// SQL query. + /// is null or empty. + /// cannot be compiled. + public static string ToSql(string prqlQuery) + { + if (string.IsNullOrEmpty(prqlQuery)) + { + throw new ArgumentException(nameof(prqlQuery)); + } + + byte[] bytes = new byte[1024]; + if (ToSqlExtern(prqlQuery, bytes) != 0) + { + throw new FormatException("Could not compile query."); + } + + bytes = bytes.TakeWhile(x => ((char)x) != '\0').ToArray(); + + return Encoding.UTF8.GetString(bytes); + } + + [DllImport("libprql_lib", EntryPoint = "compile")] + private static extern string CompileExtern(string prql_query); + + [DllImport("libprql_lib", EntryPoint = "to_json")] + private static extern int ToJsonExtern(string prql_query, byte[] json); + + [DllImport("libprql_lib", EntryPoint = "to_sql")] + private static extern int ToSqlExtern(string prql_query, byte[] sql_query); + } +} diff --git a/prql-dotnet/PrqlCompiler/PrqlCompiler.csproj b/prql-dotnet/PrqlCompiler/PrqlCompiler.csproj new file mode 100644 index 000000000000..2d530e70a232 --- /dev/null +++ b/prql-dotnet/PrqlCompiler/PrqlCompiler.csproj @@ -0,0 +1,28 @@ + + + + netstandard2.0 + + + + Prql.Compiler + 0.1.0 + PRQL Compiler + PRQL + Copyright © The PRQL Project 2023 + .NET bindings for the PRQL compiler. PRQL is a modern language for transforming data + Apache-2.0 + https://prql-lang.org/ + README.md + prql;sql + https://github.com/PRQL/prql + + + + + True + \ + + + + diff --git a/prql-dotnet/PrqlCompiler/PrqlCompilerOptions.cs b/prql-dotnet/PrqlCompiler/PrqlCompilerOptions.cs new file mode 100644 index 000000000000..0dc48e2169af --- /dev/null +++ b/prql-dotnet/PrqlCompiler/PrqlCompilerOptions.cs @@ -0,0 +1,26 @@ +namespace Prql.Compiler +{ + /// + /// Compilation options for SQL backend of the compiler. + /// + public class PrqlCompilerOptions + { + /// + /// Pass generated SQL string trough a formatter that splits it into + /// multiple lines and prettifies indentation and spacing. + /// + /// Defaults to true. + public bool Format { get; set; } = true; + + /// + /// Target and dialect to compile to. + /// + public string Target { get; set; } + + /// + /// Emits the compiler signature as a comment after generated SQL. + /// + /// Defaults to true. + public bool SignatureComment { get; set; } = true; + } +} diff --git a/prql-dotnet/README.md b/prql-dotnet/README.md new file mode 100644 index 000000000000..7b81f6cfdd23 --- /dev/null +++ b/prql-dotnet/README.md @@ -0,0 +1,33 @@ +# prql-dotnet + +`prql-net` offers PRQL bindings for .NET bindings as a `netstandard2.0` library. + +It provides the `PrqlCompiler` class which contains the `ToJson` and `ToSql` +static methods. + +It's still at an early stage, and isn't published to NuGet. Contributions are +welcome. + +## Installation + +Make sure that `libprql_lib.so` (Linux), `libprql_lib.dylib` (macOS) or +`libprql_lib.dll` (Windows) is in your project's `bin` directory together with +`PrqlCompiler.dll` and the rest of your project's compiled files. I.e. +`{your_project}/bin/Debug/net7.0/`. + +The `libprql_lib` library gets dynamically imported at runtime. + +## Usage + +```csharp +using Prql.Compiler; + +var sql = PrqlCompiler.ToSql("from employees"); +Console.WriteLine(sql); +``` + +# TODO + +This is currently at 0.1.0 because we're waiting to update prql-lib for the +latest API. When we've done that, we can match the version here with the broader +PRQL version. diff --git a/prql-dotnet/prql-net.sln b/prql-dotnet/prql-net.sln new file mode 100644 index 000000000000..ce6fc11ae756 --- /dev/null +++ b/prql-dotnet/prql-net.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PrqlCompiler", "PrqlCompiler\PrqlCompiler.csproj", "{339EA2A6-23D2-4938-884F-052431AC0674}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PrqlCompiler.Tests", "PrqlCompiler.Tests\PrqlCompiler.Tests.csproj", "{78C1AD08-6FF5-444E-9298-385887ABAA80}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {339EA2A6-23D2-4938-884F-052431AC0674}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {339EA2A6-23D2-4938-884F-052431AC0674}.Debug|Any CPU.Build.0 = Debug|Any CPU + {339EA2A6-23D2-4938-884F-052431AC0674}.Release|Any CPU.ActiveCfg = Release|Any CPU + {339EA2A6-23D2-4938-884F-052431AC0674}.Release|Any CPU.Build.0 = Release|Any CPU + {78C1AD08-6FF5-444E-9298-385887ABAA80}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {78C1AD08-6FF5-444E-9298-385887ABAA80}.Debug|Any CPU.Build.0 = Debug|Any CPU + {78C1AD08-6FF5-444E-9298-385887ABAA80}.Release|Any CPU.ActiveCfg = Release|Any CPU + {78C1AD08-6FF5-444E-9298-385887ABAA80}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal From 16e6340a82c2a80324837ec2681fe25d3ebda539 Mon Sep 17 00:00:00 2001 From: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Date: Tue, 21 Feb 2023 19:54:43 -0800 Subject: [PATCH 028/106] fix: Return a non-zero exit code for `prqlc compile` errors (#1924) * fix: Return a non-zero exit code for `prqlc compile` errors * . --- CHANGELOG.md | 3 +++ prql-compiler/prqlc/src/cli.rs | 23 +++++++++++++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f0908cbf315b..f7780ba05e38 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ **Fixes**: +- `prqlc compile` returns a non-zero exit code for invalid queries. (@max-sixty, + #1924) + **Documentation**: **Web**: diff --git a/prql-compiler/prqlc/src/cli.rs b/prql-compiler/prqlc/src/cli.rs index 0ea1694b5bf1..bfecee864a5b 100644 --- a/prql-compiler/prqlc/src/cli.rs +++ b/prql-compiler/prqlc/src/cli.rs @@ -94,6 +94,8 @@ impl Cli { } fn execute(&self, source: &str) -> Result> { + // TODO: there's some repetiton here around converting strings to bytes; + // we could possibly extract that, but not sure it would neatly . Ok(match self { Cli::Parse(_) => { let ast = prql_to_pl(source).map_err(|e| anyhow!(e))?; @@ -137,7 +139,7 @@ impl Cli { serde_json::to_string_pretty(&ir)?.into_bytes() } Cli::Compile(_) => compile(source, &Options::default()) - .map_or_else(|x| x.to_string(), |x| x) + .map_err(|x| anyhow!(x))? .as_bytes() .to_vec(), Cli::Watch(_) => unreachable!(), @@ -208,7 +210,7 @@ fn combine_prql_and_frames(source: &str, frames: Vec<(Span, Frame)>) -> String { #[cfg(test)] mod tests { - use insta::assert_snapshot; + use insta::{assert_display_snapshot, assert_snapshot}; use super::*; @@ -267,4 +269,21 @@ group a_column (take 10 | sort b_column | derive [the_number = rank, last = lag ) "###); } + + #[test] + fn compile() { + // Check we get an error on a bad input + let input = "asdf"; + let result = Cli::execute(&Cli::Compile(CommandIO::default()), input); + assert!(result.is_err()); + assert_display_snapshot!(result.unwrap_err(), @r###" + Error: + ╭─[:1:1] + │ + 1 │ asdf + · ──┬─ + · ╰─── Unknown name asdf + ───╯ + "###); + } } From 3f7585ea0fbe3fc588faae0d14e23b2940e325d0 Mon Sep 17 00:00:00 2001 From: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Date: Tue, 21 Feb 2023 20:32:42 -0800 Subject: [PATCH 029/106] ci: Add `internal` & `devops` to semantic commit options (#1926) * ci: Add `internal` & `devops` to semantic commit options --- .github/workflows/pull-request-target.yaml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/.github/workflows/pull-request-target.yaml b/.github/workflows/pull-request-target.yaml index 0793964f36d0..21e238992728 100644 --- a/.github/workflows/pull-request-target.yaml +++ b/.github/workflows/pull-request-target.yaml @@ -19,6 +19,22 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: requireScope: false + # The standard ones plus "internal", for code quality / ergonomics + # improvements, and "devops" for developer ergonomics. + types: | + feat + fix + docs + style + refactor + perf + test + build + ci + chore + revert + internal + devops backport: # Backport to `web` branch on `pr-backport-web` From 6e79a28f927dbd1d2efb0147b94a748d3f918037 Mon Sep 17 00:00:00 2001 From: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Date: Wed, 22 Feb 2023 00:35:23 -0800 Subject: [PATCH 030/106] internal: Enable auto-conversion of anyhow's error to `ErrorMessages` (#1913) --- book/tests/snapshot.rs | 4 +--- prql-compiler/src/error.rs | 6 ++++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/book/tests/snapshot.rs b/book/tests/snapshot.rs index a454da7c80da..0d8479b528fc 100644 --- a/book/tests/snapshot.rs +++ b/book/tests/snapshot.rs @@ -185,9 +185,7 @@ fn test_prql_examples() { // which seems very strict) #[test] fn test_display() -> Result<(), ErrorMessages> { - use prql_compiler::downcast; - collect_book_examples() - .map_err(downcast)? + collect_book_examples()? .iter() .try_for_each(|(path, example)| { assert_snapshot!( diff --git a/prql-compiler/src/error.rs b/prql-compiler/src/error.rs index e9f9d9d78839..7f75045572f1 100644 --- a/prql-compiler/src/error.rs +++ b/prql-compiler/src/error.rs @@ -181,6 +181,12 @@ pub fn downcast(error: anyhow::Error) -> ErrorMessages { .into() } +impl From for ErrorMessages { + fn from(e: anyhow::Error) -> Self { + downcast(e) + } +} + impl ErrorMessages { pub fn to_json(&self) -> String { serde_json::to_string(self).unwrap() From 883a12312eda66513241ba6cbe767e312e38bb3a Mon Sep 17 00:00:00 2001 From: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Date: Wed, 22 Feb 2023 00:35:50 -0800 Subject: [PATCH 031/106] internal: Implement std::error::Error for ErrorMessages (#1925) --- prql-compiler/prqlc/src/cli.rs | 21 +++++++-------------- prql-compiler/src/ast/pl/expr.rs | 2 -- prql-compiler/src/error.rs | 1 + 3 files changed, 8 insertions(+), 16 deletions(-) diff --git a/prql-compiler/prqlc/src/cli.rs b/prql-compiler/prqlc/src/cli.rs index bfecee864a5b..06c2361b9c52 100644 --- a/prql-compiler/prqlc/src/cli.rs +++ b/prql-compiler/prqlc/src/cli.rs @@ -1,4 +1,4 @@ -use anyhow::{anyhow, Result}; +use anyhow::Result; use ariadne::Source; use clap::Parser; use clio::{Input, Output}; @@ -98,17 +98,13 @@ impl Cli { // we could possibly extract that, but not sure it would neatly . Ok(match self { Cli::Parse(_) => { - let ast = prql_to_pl(source).map_err(|e| anyhow!(e))?; + let ast = prql_to_pl(source)?; serde_yaml::to_string(&ast)?.into_bytes() } - Cli::Format(_) => prql_to_pl(source) - .and_then(pl_to_prql) - .map_err(|x| anyhow!(x))? - .as_bytes() - .to_vec(), + Cli::Format(_) => prql_to_pl(source).and_then(pl_to_prql)?.as_bytes().to_vec(), Cli::Debug(_) => { - let stmts = prql_to_pl(source).map_err(|x| anyhow!(x))?; + let stmts = prql_to_pl(source)?; let (stmts, context) = semantic::resolve_only(stmts, None)?; let (references, stmts) = @@ -122,7 +118,7 @@ impl Cli { .concat() } Cli::Annotate(_) => { - let stmts = prql_to_pl(source).map_err(|x| anyhow!(x))?; + let stmts = prql_to_pl(source)?; // resolve let (stmts, _) = semantic::resolve_only(stmts, None)?; @@ -133,15 +129,12 @@ impl Cli { combine_prql_and_frames(source, frames).as_bytes().to_vec() } Cli::Resolve(_) => { - let ast = prql_to_pl(source).map_err(|x| anyhow!(x))?; + let ast = prql_to_pl(source)?; let ir = semantic::resolve(ast)?; serde_json::to_string_pretty(&ir)?.into_bytes() } - Cli::Compile(_) => compile(source, &Options::default()) - .map_err(|x| anyhow!(x))? - .as_bytes() - .to_vec(), + Cli::Compile(_) => compile(source, &Options::default())?.as_bytes().to_vec(), Cli::Watch(_) => unreachable!(), }) } diff --git a/prql-compiler/src/ast/pl/expr.rs b/prql-compiler/src/ast/pl/expr.rs index ea3dc6f0a7b7..630d4725f32f 100644 --- a/prql-compiler/src/ast/pl/expr.rs +++ b/prql-compiler/src/ast/pl/expr.rs @@ -430,7 +430,6 @@ impl From for anyhow::Error { // https://github.com/bluejekyll/enum-as-inner/issues/84 #[allow(unreachable_code)] fn from(kind: ExprKind) -> Self { - // panic!("Failed to convert {item}") anyhow!("Failed to convert `{}`", Expr::from(kind)) } } @@ -439,7 +438,6 @@ impl From for anyhow::Error { // https://github.com/bluejekyll/enum-as-inner/issues/84 #[allow(unreachable_code)] fn from(kind: TransformKind) -> Self { - // panic!("Failed to convert {item}") anyhow!("Failed to convert `{kind:?}`") } } diff --git a/prql-compiler/src/error.rs b/prql-compiler/src/error.rs index 7f75045572f1..4d0151b3ff6e 100644 --- a/prql-compiler/src/error.rs +++ b/prql-compiler/src/error.rs @@ -120,6 +120,7 @@ impl Display for Error { pub struct ErrorMessages { pub inner: Vec, } +impl StdError for ErrorMessages {} impl From for ErrorMessages { fn from(e: ErrorMessage) -> Self { From 7c317ad7ebcf7de340641a103dd7d18418b8d8dc Mon Sep 17 00:00:00 2001 From: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Date: Wed, 22 Feb 2023 01:33:20 -0800 Subject: [PATCH 032/106] build: Bump dependencies (#1927) --- Cargo.lock | 508 ++++++++++++++++----------------- prql-compiler/prqlc/Cargo.toml | 6 +- 2 files changed, 255 insertions(+), 259 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5eb860296819..ae6103343766 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -39,9 +39,9 @@ dependencies = [ [[package]] name = "ahash" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf6ccdb167abbf410dcb915cabd428929d7f6a04980b54a11f26a39f1c7f7107" +checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" dependencies = [ "cfg-if", "const-random", @@ -76,9 +76,9 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anyhow" -version = "1.0.68" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61" +checksum = "224afbd727c3d6e4b90103ece64b8d1b67fbb1973b1046c2281eed3f3803f800" dependencies = [ "backtrace", ] @@ -104,7 +104,7 @@ version = "32.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87d948f553cf556656eb89265700258e1032d26fec9b7920cd20319336e06afd" dependencies = [ - "ahash 0.8.2", + "ahash 0.8.3", "arrow-arith", "arrow-array", "arrow-buffer", @@ -130,7 +130,7 @@ dependencies = [ "arrow-data", "arrow-schema", "chrono", - "half 2.1.0", + "half 2.2.1", "num", ] @@ -140,13 +140,13 @@ version = "32.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fe66ec388d882a61fff3eb613b5266af133aa08a3318e5e493daf0f5c1696cb" dependencies = [ - "ahash 0.8.2", + "ahash 0.8.3", "arrow-buffer", "arrow-data", "arrow-schema", "chrono", - "half 2.1.0", - "hashbrown 0.13.1", + "half 2.2.1", + "hashbrown 0.13.2", "num", ] @@ -156,7 +156,7 @@ version = "32.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ef967dadbccd4586ec8d7aab27d7033ecb5dfae8a605c839613039eac227bda" dependencies = [ - "half 2.1.0", + "half 2.2.1", "num", ] @@ -184,7 +184,7 @@ checksum = "ee0c0e3c5d3b80be8f267f4b2af714c08cad630569be01a8379cfe27b4866495" dependencies = [ "arrow-buffer", "arrow-schema", - "half 2.1.0", + "half 2.2.1", "num", ] @@ -208,13 +208,13 @@ version = "32.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e064ac4e64960ebfbe35f218f5e7d9dc9803b59c2e56f611da28ce6d008f839e" dependencies = [ - "ahash 0.8.2", + "ahash 0.8.3", "arrow-array", "arrow-buffer", "arrow-data", "arrow-schema", - "half 2.1.0", - "hashbrown 0.13.1", + "half 2.2.1", + "hashbrown 0.13.2", ] [[package]] @@ -253,9 +253,9 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.60" +version = "0.1.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d1d8ab452a3936018a687b20e6f7cf5363d713b732b8884001317b0e48aa3" +checksum = "1cd7fce9ba8c3c042128ce72d8b2ddbf3a05747efb67ea0313c635e10bda47a2" dependencies = [ "proc-macro2", "quote", @@ -317,19 +317,19 @@ dependencies = [ [[package]] name = "borsh" -version = "0.9.3" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15bf3650200d8bffa99015595e10f1fbd17de07abbc25bb067da79e769939bfa" +checksum = "40f9ca3698b2e4cb7c15571db0abc5551dca417a21ae8140460b50309bb2cc62" dependencies = [ "borsh-derive", - "hashbrown 0.11.2", + "hashbrown 0.13.2", ] [[package]] name = "borsh-derive" -version = "0.9.3" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6441c552f230375d18e3cc377677914d2ca2b0d36e52129fe15450a2dce46775" +checksum = "598b3eacc6db9c3ee57b22707ad8f6a8d2f6d442bfe24ffeb8cbb70ca59e6a35" dependencies = [ "borsh-derive-internal", "borsh-schema-derive-internal", @@ -340,9 +340,9 @@ dependencies = [ [[package]] name = "borsh-derive-internal" -version = "0.9.3" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5449c28a7b352f2d1e592a8a28bf139bc71afb0764a14f3c02500935d8c44065" +checksum = "186b734fa1c9f6743e90c95d7233c9faab6360d1a96d4ffa19d9cfd1e9350f8a" dependencies = [ "proc-macro2", "quote", @@ -351,9 +351,9 @@ dependencies = [ [[package]] name = "borsh-schema-derive-internal" -version = "0.9.3" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdbd5696d8bfa21d53d9fe39a714a18538bad11492a42d066dbbc395fb1951c0" +checksum = "99b7ff1008316626f485991b960ade129253d4034014616b94f309a15366cc49" dependencies = [ "proc-macro2", "quote", @@ -362,20 +362,21 @@ dependencies = [ [[package]] name = "bstr" -version = "0.2.17" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" +checksum = "5ffdb39cb703212f3c11973452c2861b972f757b021158f3516ba10f2fa8b2c1" dependencies = [ - "lazy_static", "memchr", + "once_cell", "regex-automata", + "serde", ] [[package]] name = "bumpalo" -version = "3.11.1" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" +checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" [[package]] name = "bytecheck" @@ -406,9 +407,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" +checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" [[package]] name = "cast" @@ -418,9 +419,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.0.78" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" dependencies = [ "jobserver", ] @@ -502,13 +503,13 @@ dependencies = [ [[package]] name = "clap" -version = "4.1.1" +version = "4.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec7a4128863c188deefe750ac1d1dfe66c236909f845af04beed823638dc1b2" +checksum = "ec0b0588d44d4d63a87dbd75c136c166bbfd9a86a31cb89e09906521c7d3f5e3" dependencies = [ "bitflags", "clap_derive", - "clap_lex 0.3.0", + "clap_lex 0.3.1", "is-terminal", "once_cell", "strsim", @@ -518,11 +519,11 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.0.6" +version = "4.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7b3c9eae0de7bf8e3f904a5e40612b21fb2e2e566456d177809a48b892d24da" +checksum = "bd125be87bf4c255ebc50de0b7f4d2a6201e8ac3dc86e39c0ad081dc5e7236fe" dependencies = [ - "clap 4.1.1", + "clap 4.1.6", ] [[package]] @@ -549,9 +550,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8" +checksum = "783fe232adfca04f90f56201b26d79682d4cd2625e0bc7290b95123afe558ade" dependencies = [ "os_str_bytes", ] @@ -562,9 +563,9 @@ version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94b38784f05c5e908bb8751e9b9f29fbcd470f636c0d0a76a0f90c0c823f3b68" dependencies = [ - "clap 4.1.1", + "clap 4.1.6", "libc", - "windows-sys", + "windows-sys 0.42.0", ] [[package]] @@ -616,9 +617,9 @@ dependencies = [ [[package]] name = "comfy-table" -version = "6.1.3" +version = "6.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e621e7e86c46fd8a14c32c6ae3cb95656621b4743a27d0cffedb831d46e7ad21" +checksum = "6e7b787b0dc42e8111badfdbe4c3059158ccb2db8780352fa1b01e8ccf45cc4d" dependencies = [ "strum", "strum_macros", @@ -634,14 +635,14 @@ dependencies = [ [[package]] name = "console" -version = "0.15.4" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9b6515d269224923b26b5febea2ed42b2d5f2ce37284a4dd670fedd6cb8347a" +checksum = "c3d79fbe8970a77e3e34151cc13d3b3e248aa0faaecb9f6091fa07ebefe5ad60" dependencies = [ "encode_unicode", "lazy_static", "libc", - "windows-sys", + "windows-sys 0.42.0", ] [[package]] @@ -819,9 +820,9 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.85" +version = "1.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5add3fc1717409d029b20c5b6903fc0c0b02fa6741d820054f4a2efa5e5816fd" +checksum = "86d3488e7665a7a483b57e25bdd90d0aeb2bc7608c8d0346acf2ad3f1caf1d62" dependencies = [ "cc", "cxxbridge-flags", @@ -831,9 +832,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.85" +version = "1.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4c87959ba14bc6fbc61df77c3fcfe180fc32b93538c4f1031dd802ccb5f2ff0" +checksum = "48fcaf066a053a41a81dfb14d57d99738b767febb8b735c3016e469fac5da690" dependencies = [ "cc", "codespan-reporting", @@ -846,15 +847,15 @@ dependencies = [ [[package]] name = "cxxbridge-flags" -version = "1.0.85" +version = "1.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69a3e162fde4e594ed2b07d0f83c6c67b745e7f28ce58c6df5e6b6bef99dfb59" +checksum = "a2ef98b8b717a829ca5603af80e1f9e2e48013ab227b68ef37872ef84ee479bf" [[package]] name = "cxxbridge-macro" -version = "1.0.85" +version = "1.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e7e2adeb6a0d4a282e581096b06e1791532b7d576dcde5ccd9382acf55db8e6" +checksum = "086c685979a698443656e5cf7856c95c642295a38599f12fb1ff76fb28d19892" dependencies = [ "proc-macro2", "quote", @@ -899,9 +900,9 @@ dependencies = [ [[package]] name = "either" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" [[package]] name = "encode_unicode" @@ -921,19 +922,6 @@ dependencies = [ "syn", ] -[[package]] -name = "env_logger" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" -dependencies = [ - "atty", - "humantime", - "log", - "regex", - "termcolor", -] - [[package]] name = "env_logger" version = "0.10.0" @@ -992,23 +980,23 @@ checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" [[package]] name = "fastrand" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" dependencies = [ "instant", ] [[package]] name = "filetime" -version = "0.2.19" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e884668cd0c7480504233e951174ddc3b382f7c2666e3b7310b5c4e7b0c37f9" +checksum = "8a3de6e8d11b22ff9edc6d916f890800597d60f8b2da1caf2955c274638d6412" dependencies = [ "cfg-if", "libc", "redox_syscall", - "windows-sys", + "windows-sys 0.45.0", ] [[package]] @@ -1037,9 +1025,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed" +checksum = "2e5317663a9089767a1ec00a487df42e0ca174b61b4483213ac24448e4664df5" dependencies = [ "futures-core", "futures-sink", @@ -1047,15 +1035,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac" +checksum = "ec90ff4d0fe1f57d600049061dc6bb68ed03c7d2fbd697274c41805dcb3f8608" [[package]] name = "futures-macro" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d" +checksum = "95a73af87da33b5acf53acfebdc339fe592ecf5357ac7c0a7734ab9d8c876a70" dependencies = [ "proc-macro2", "quote", @@ -1064,21 +1052,21 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9" +checksum = "f310820bb3e8cfd46c80db4d7fb8353e15dfff853a127158425f31e0be6c8364" [[package]] name = "futures-task" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea" +checksum = "dcf79a1bf610b10f42aea489289c5a2c478a786509693b80cd39c44ccd936366" [[package]] name = "futures-util" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6" +checksum = "9c1d6de3acfef38d2be4b1f543f553131788603495be83da675e180c8d6b7bd1" dependencies = [ "futures-core", "futures-macro", @@ -1121,15 +1109,15 @@ dependencies = [ [[package]] name = "gimli" -version = "0.27.0" +version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dec7af912d60cdbd3677c1af9352ebae6fb8394d165568a2234df0fa00f87793" +checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" [[package]] name = "globset" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a1e17342619edbc21a964c2afbeb6c820c6a2560032872f397bb97ea127bd0a" +checksum = "029d74589adefde59de1a0c4f4732695c32805624aec7b68d91503d4dba79afc" dependencies = [ "aho-corasick", "bstr", @@ -1146,9 +1134,9 @@ checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" [[package]] name = "half" -version = "2.1.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad6a9459c9c30b177b925162351f97e7d967c7ea8bab3b8352805327daf45554" +checksum = "02b4af3693f1b705df946e9fe5631932443781d0aabb423b62fcd4d73f6d2fd0" dependencies = [ "crunchy", "num-traits", @@ -1168,15 +1156,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "hashbrown" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" -dependencies = [ - "ahash 0.7.6", -] - [[package]] name = "hashbrown" version = "0.12.3" @@ -1188,9 +1167,12 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.13.1" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ff8ae62cd3a9102e5637afc8452c55acf3844001bd5374e0b0bd7b6616c038" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash 0.8.3", +] [[package]] name = "hashlink" @@ -1203,9 +1185,9 @@ dependencies = [ [[package]] name = "heck" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" @@ -1225,6 +1207,12 @@ dependencies = [ "libc", ] +[[package]] +name = "hermit-abi" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" + [[package]] name = "hmac" version = "0.12.1" @@ -1292,9 +1280,9 @@ dependencies = [ [[package]] name = "indoc" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da2d6f23ffea9d7e76c53eee25dfb67bcd8fde7f1198b0855350698c9f07c780" +checksum = "bfa799dd5ed20a7e349f3b4639aa80d74549c81716d9ec4f994c9b5815598306" [[package]] name = "inotify" @@ -1343,24 +1331,24 @@ dependencies = [ [[package]] name = "io-lifetimes" -version = "1.0.3" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46112a93252b123d31a119a8d1a1ac19deac4fac6e0e8b0df58f0d4e5870e63c" +checksum = "1abeb7a0dd0f8181267ff8adc397075586500b81b28a73e8a0208b00fc170fb3" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.45.0", ] [[package]] name = "is-terminal" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189" +checksum = "22e18b0a45d56fe973d6db23972bf5bc46f988a4a2385deac9cc29572f09daef" dependencies = [ - "hermit-abi 0.2.6", + "hermit-abi 0.3.1", "io-lifetimes", "rustix", - "windows-sys", + "windows-sys 0.45.0", ] [[package]] @@ -1409,9 +1397,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.60" +version = "0.3.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" +checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" dependencies = [ "wasm-bindgen", ] @@ -1508,9 +1496,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.138" +version = "0.2.139" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8" +checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" [[package]] name = "libduckdb-sys" @@ -1600,15 +1588,15 @@ dependencies = [ [[package]] name = "mdbook" -version = "0.4.25" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1ed28d5903dde77bd5182645078a37ee57014cac6ccb2d54e1d6496386648e4" +checksum = "0f387adfd85d2eeebe3d47d67b1e3f8c9d83ef327582558c5ca88f78d171e73a" dependencies = [ "anyhow", "chrono", - "clap 4.1.1", + "clap 4.1.6", "clap_complete", - "env_logger 0.10.0", + "env_logger", "handlebars", "log", "memchr", @@ -1629,7 +1617,7 @@ name = "mdbook-prql" version = "0.5.2" dependencies = [ "anyhow", - "clap 4.1.1", + "clap 4.1.6", "globset", "insta", "itertools", @@ -1695,21 +1683,21 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" +checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" dependencies = [ "libc", "log", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys", + "windows-sys 0.45.0", ] [[package]] name = "nom" -version = "7.1.1" +version = "7.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" dependencies = [ "memchr", "minimal-lexical", @@ -1730,7 +1718,7 @@ dependencies = [ "libc", "mio", "walkdir", - "windows-sys", + "windows-sys 0.42.0", ] [[package]] @@ -1760,9 +1748,9 @@ dependencies = [ [[package]] name = "num-complex" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ae39348c8bc5fbd7f40c727a9925f03517afd2ab27d46702108b6a7e5414c19" +checksum = "02e0d21255c828d6f128a1e41534206671e8c3ea0c62f32291e808dc82cff17d" dependencies = [ "num-traits", ] @@ -1831,18 +1819,18 @@ dependencies = [ [[package]] name = "object" -version = "0.30.0" +version = "0.30.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "239da7f290cfa979f43f85a8efeee9a8a76d0827c356d37f9d3d7254d6b537fb" +checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.17.0" +version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" +checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" [[package]] name = "oorandom" @@ -1852,9 +1840,9 @@ checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" [[package]] name = "opener" -version = "0.5.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ea3ebcd72a54701f56345f16785a6d3ac2df7e986d273eb4395c0b01db17952" +checksum = "293c15678e37254c15bd2f092314abb4e51d7fdde05c2021279c12631b54f005" dependencies = [ "bstr", "winapi", @@ -1893,15 +1881,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.5" +version = "0.9.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ff9f3fef3968a3ec5945535ed654cb38ff72d7495a25619e2247fb15a2ed9ba" +checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-sys", + "windows-sys 0.45.0", ] [[package]] @@ -1912,9 +1900,9 @@ checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" [[package]] name = "pest" -version = "2.5.1" +version = "2.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc8bed3549e0f9b0a2a78bf7c0018237a2cdf085eecbbc048e52612438e4e9d0" +checksum = "028accff104c4e513bad663bbcd2ad7cfd5304144404c31ed0a77ac103d00660" dependencies = [ "thiserror", "ucd-trie", @@ -1922,9 +1910,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.5.1" +version = "2.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdc078600d06ff90d4ed238f0119d84ab5d43dbaad278b0e33a8820293b32344" +checksum = "2ac3922aac69a40733080f53c1ce7f91dcf57e1a5f6c52f421fadec7fbdc4b69" dependencies = [ "pest", "pest_generator", @@ -1932,9 +1920,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.5.1" +version = "2.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28a1af60b1c4148bb269006a750cff8e2ea36aff34d2d96cf7be0b14d1bed23c" +checksum = "d06646e185566b5961b4058dd107e0a7f56e77c3f484549fb119867773c0f202" dependencies = [ "pest", "pest_meta", @@ -1945,13 +1933,13 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.5.1" +version = "2.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fec8605d59fc2ae0c6c1aefc0c7c7a9769732017c0ce07f7a9cfffa7b4404f20" +checksum = "e6f60b2ba541577e2a0c307c8f39d1439108120eb7903adeb6497fa880c59616" dependencies = [ "once_cell", "pest", - "sha1", + "sha2", ] [[package]] @@ -2120,9 +2108,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" -version = "1.0.49" +version = "1.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5" +checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6" dependencies = [ "unicode-ident", ] @@ -2220,10 +2208,10 @@ dependencies = [ "anyhow", "ariadne", "atty", - "clap 4.1.1", + "clap 4.1.6", "clio", "color-eyre", - "env_logger 0.9.3", + "env_logger", "insta", "itertools", "minijinja", @@ -2279,9 +2267,9 @@ dependencies = [ [[package]] name = "pyo3" -version = "0.18.0" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccd4149c8c3975099622b4e1962dac27565cf5663b76452c3e2b66e0b6824277" +checksum = "06a3d8e8a46ab2738109347433cb7b96dffda2e4a218b03ef27090238886b147" dependencies = [ "cfg-if", "indoc", @@ -2296,9 +2284,9 @@ dependencies = [ [[package]] name = "pyo3-build-config" -version = "0.18.0" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cd09fe469834db21ee60e0051030339e5d361293d8cb5ec02facf7fdcf52dbf" +checksum = "75439f995d07ddfad42b192dfcf3bc66a7ecfd8b4a1f5f6f046aa5c2c5d7677d" dependencies = [ "once_cell", "target-lexicon", @@ -2306,9 +2294,9 @@ dependencies = [ [[package]] name = "pyo3-ffi" -version = "0.18.0" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c427c9a96b9c5b12156dbc11f76b14f49e9aae8905ca783ea87c249044ef137" +checksum = "839526a5c07a17ff44823679b68add4a58004de00512a95b6c1c98a6dcac0ee5" dependencies = [ "libc", "pyo3-build-config", @@ -2316,9 +2304,9 @@ dependencies = [ [[package]] name = "pyo3-macros" -version = "0.18.0" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b822bbba9d60630a44d2109bc410489bb2f439b33e3a14ddeb8a40b378a7c4" +checksum = "bd44cf207476c6a9760c4653559be4f206efafb924d3e4cbf2721475fc0d6cc5" dependencies = [ "proc-macro2", "pyo3-macros-backend", @@ -2328,9 +2316,9 @@ dependencies = [ [[package]] name = "pyo3-macros-backend" -version = "0.18.0" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84ae898104f7c99db06231160770f3e40dad6eb9021daddc0fedfa3e41dff10a" +checksum = "dc1f43d8e30460f36350d18631ccf85ded64c059829208fe680904c65bcd0a4c" dependencies = [ "proc-macro2", "quote", @@ -2388,9 +2376,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.10.1" +version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cac410af5d00ab6884528b4ab69d1e8e146e8d471201800fa1b4524126de6ad3" +checksum = "356a0625f1954f730c0201cdab48611198dc6ce21f4acff55089b5a78e6e835b" dependencies = [ "crossbeam-channel", "crossbeam-deque", @@ -2441,18 +2429,18 @@ dependencies = [ [[package]] name = "rend" -version = "0.3.6" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79af64b4b6362ffba04eef3a4e10829718a4896dac19daa741851c86781edf95" +checksum = "581008d2099240d37fb08d77ad713bcaec2c4d89d50b5b21a8bb1996bbab68ab" dependencies = [ "bytecheck", ] [[package]] name = "rkyv" -version = "0.7.39" +version = "0.7.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cec2b3485b07d96ddfd3134767b8a447b45ea4eb91448d0a35180ec0ffd5ed15" +checksum = "c30f1d45d9aa61cbc8cd1eb87705470892289bb2d01943e7803b873a57404dc3" dependencies = [ "bytecheck", "hashbrown 0.12.3", @@ -2464,9 +2452,9 @@ dependencies = [ [[package]] name = "rkyv_derive" -version = "0.7.39" +version = "0.7.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eaedadc88b53e36dd32d940ed21ae4d850d5916f2581526921f553a72ac34c4" +checksum = "ff26ed6c7c4dfc2aa9480b86a60e3c7233543a270a680e10758a507c5a4ce476" dependencies = [ "proc-macro2", "quote", @@ -2490,9 +2478,9 @@ dependencies = [ [[package]] name = "rust_decimal" -version = "1.27.0" +version = "1.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33c321ee4e17d2b7abe12b5d20c1231db708dd36185c8a21e9de5fed6da4dbe9" +checksum = "e13cf35f7140155d02ba4ec3294373d513a3c7baa8364c162b030e33c61520a8" dependencies = [ "arrayvec", "borsh", @@ -2514,16 +2502,16 @@ checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" [[package]] name = "rustix" -version = "0.36.5" +version = "0.36.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3807b5d10909833d3e9acd1eb5fb988f79376ff10fce42937de71a449c4c588" +checksum = "f43abb88211988493c1abb44a70efa56ff0ce98f233b7b276146f1f3f7ba9644" dependencies = [ "bitflags", "errno", "io-lifetimes", "libc", "linux-raw-sys", - "windows-sys", + "windows-sys 0.45.0", ] [[package]] @@ -2615,18 +2603,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.151" +version = "1.0.152" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97fed41fc1a24994d044e6db6935e69511a1153b52c15eb42493b26fa87feba0" +checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.151" +version = "1.0.152" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "255abe9a125a985c05190d687b320c12f9b1f0b99445e608c21ba0782c719ad8" +checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" dependencies = [ "proc-macro2", "quote", @@ -2635,9 +2623,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.91" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883" +checksum = "cad406b69c91885b5107daf2c29572f6c8cdb3c66826821e286c533490c0bc76" dependencies = [ "itoa", "ryu", @@ -2646,9 +2634,9 @@ dependencies = [ [[package]] name = "serde_yaml" -version = "0.9.16" +version = "0.9.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92b5b431e8907b50339b51223b97d102db8d987ced36f6e4d03621db9316c834" +checksum = "8fb06d4b6cdaef0e0c51fa881acb721bed3c924cfaa71d9c94a3b771dfdf6567" dependencies = [ "indexmap", "itoa", @@ -2657,17 +2645,6 @@ dependencies = [ "unsafe-libyaml", ] -[[package]] -name = "sha1" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - [[package]] name = "sha2" version = "0.10.6" @@ -2708,9 +2685,9 @@ checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" [[package]] name = "slab" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" dependencies = [ "autocfg", ] @@ -2815,9 +2792,9 @@ dependencies = [ [[package]] name = "target-lexicon" -version = "0.12.5" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9410d0f6853b1d94f0e519fb95df60f29d2c1eff2d921ffdf01a4c8a3b54f12d" +checksum = "8ae9980cab1db3fceee2f6c6f643d5d8de2997c58ee8d25fb0cc8a9e9e7348e5" [[package]] name = "tempfile" @@ -2835,21 +2812,21 @@ dependencies = [ [[package]] name = "termcolor" -version = "1.1.3" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" dependencies = [ "winapi-util", ] [[package]] name = "terminal_size" -version = "0.2.3" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb20089a8ba2b69debd491f8d2d023761cbf196e999218c591fa1e7e15a21907" +checksum = "4c9afddd2cec1c0909f06b00ef33f94ab2cc0578c4a610aa208ddfec8aa2b43a" dependencies = [ "rustix", - "windows-sys", + "windows-sys 0.45.0", ] [[package]] @@ -2880,10 +2857,11 @@ dependencies = [ [[package]] name = "thread_local" -version = "1.1.4" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" dependencies = [ + "cfg-if", "once_cell", ] @@ -2928,9 +2906,9 @@ dependencies = [ [[package]] name = "tinyvec_macros" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" @@ -2945,7 +2923,7 @@ dependencies = [ "mio", "pin-project-lite", "socket2", - "windows-sys", + "windows-sys 0.42.0", ] [[package]] @@ -2974,9 +2952,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.4" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bb2e075f03b3d66d8d8785356224ba688d2906a371015e225beeb65ca92c740" +checksum = "5427d89453009325de0d8f342c9490009f76e999cb7672d77e46267448f7e6b2" dependencies = [ "bytes", "futures-core", @@ -2988,9 +2966,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.5.10" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1333c76748e868a4d9d1017b5ab53171dfd095f70c712fdb4653a406547f598f" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" dependencies = [ "serde", ] @@ -3045,9 +3023,9 @@ dependencies = [ [[package]] name = "trash" -version = "3.0.0" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f74274f95c7e7340d7c5bcd4863af87a9ed6a117cf73cf483c71cb4d744a948" +checksum = "a27b2a127810fceb959593bbc6c7b8e0282c2d318d76f0749252197c52a1dd0c" dependencies = [ "chrono", "libc", @@ -3082,9 +3060,9 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.8" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" +checksum = "d54675592c1dbefd78cbd98db9bacd89886e1ca50692a0692baefffdeb92dd58" [[package]] name = "unicode-ident" @@ -3194,9 +3172,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" +checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -3204,9 +3182,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" +checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" dependencies = [ "bumpalo", "log", @@ -3219,9 +3197,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.33" +version = "0.4.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23639446165ca5a5de86ae1d8896b737ae80319560fbaa4c2887b7da6e7ebd7d" +checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454" dependencies = [ "cfg-if", "js-sys", @@ -3231,9 +3209,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" +checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3241,9 +3219,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" +checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" dependencies = [ "proc-macro2", "quote", @@ -3254,15 +3232,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" +checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" [[package]] name = "wasm-bindgen-test" -version = "0.3.33" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09d2fff962180c3fadf677438054b1db62bee4aa32af26a45388af07d1287e1d" +checksum = "6db36fc0f9fb209e88fb3642590ae0205bb5a56216dabd963ba15879fe53a30b" dependencies = [ "console_error_panic_hook", "js-sys", @@ -3274,9 +3252,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-test-macro" -version = "0.3.33" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4683da3dfc016f704c9f82cf401520c4f1cb3ee440f7f52b3d6ac29506a49ca7" +checksum = "0734759ae6b3b1717d661fe4f016efcfb9828f5edb4520c18eaee05af3b43be9" dependencies = [ "proc-macro2", "quote", @@ -3284,9 +3262,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.60" +version = "0.3.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" +checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" dependencies = [ "js-sys", "wasm-bindgen", @@ -3325,9 +3303,18 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows" -version = "0.43.0" +version = "0.44.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e745dab35a0c4c77aa3ce42d595e13d2003d6902d6b08c9ef5fc326d08da12b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04662ed0e3e5630dfa9b26e4cb823b817f1a9addda855d973a9458c236556244" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", @@ -3340,9 +3327,18 @@ dependencies = [ [[package]] name = "windows-sys" -version = "0.42.0" +version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", @@ -3355,45 +3351,45 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" +checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" [[package]] name = "windows_aarch64_msvc" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" +checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" [[package]] name = "windows_i686_gnu" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" +checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" [[package]] name = "windows_i686_msvc" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" +checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" [[package]] name = "windows_x86_64_gnu" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" +checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" +checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" [[package]] name = "windows_x86_64_msvc" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" +checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" [[package]] name = "yaml-rust" diff --git a/prql-compiler/prqlc/Cargo.toml b/prql-compiler/prqlc/Cargo.toml index a90627b1530d..371096c04967 100644 --- a/prql-compiler/prqlc/Cargo.toml +++ b/prql-compiler/prqlc/Cargo.toml @@ -15,15 +15,15 @@ atty = "0.2.14" clap = {version = "4.1.1", features = ["derive"]} clio = {version = "0.2.4", features = ['clap-parse']} color-eyre = "0.6.1" -env_logger = {version = "0.9.1", features = ["termcolor"]} +env_logger = {version = "0.10.0", features = ["color"]} itertools = "0.10.3" -notify = "^5.1.0" minijinja = {version = "0.30.4", features = ["unstable_machinery"]} +notify = "^5.1.0" prql-compiler = {path = '..', version = "0.5.2"} regex = {version = "1.7.1", features = ["std", "unicode"]} +serde = "^1" serde_json = "1.0.81" serde_yaml = "0.9.1" -serde = "^1" walkdir = "^2.3.2" [target.'cfg(not(target_family="wasm"))'.dev-dependencies] From 14f6e7180cd8e10ddea8ecbae731b044fdd758d6 Mon Sep 17 00:00:00 2001 From: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Date: Wed, 22 Feb 2023 01:35:35 -0800 Subject: [PATCH 033/106] docs: Embolden `prqlc` description (#1919) --- .github/workflows/release.yaml | 6 ++++-- prql-compiler/prqlc/Cargo.toml | 2 +- snap/snapcraft.yaml | 7 ++++--- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 854963fbb02a..add1048a8405 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -45,8 +45,10 @@ jobs: package_root: .debpkg maintainer: The PRQL Project version: ${{ github.ref }} - desc: - prqlc is the CLI for PRQL, a modern language for transforming data + desc: | + prqlc is the CLI for the PRQL compiler. It compiles PRQL to SQL, and offers various diagnostics. + + PRQL is a modern language for transforming data — a simple, powerful, pipelined SQL replacement. build-rpm-package: # TODO: This doesn't publish the rpm yet, that would be a welcome follow-up (even as a CI artifact) diff --git a/prql-compiler/prqlc/Cargo.toml b/prql-compiler/prqlc/Cargo.toml index 371096c04967..40b0ced399be 100644 --- a/prql-compiler/prqlc/Cargo.toml +++ b/prql-compiler/prqlc/Cargo.toml @@ -1,5 +1,5 @@ [package] -description = "CLI interface for the PRQL compiler" +description = "CLI for the PRQL compiler" name = "prqlc" edition.workspace = true diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 6f9bda5cd9a7..dfa1fd7c1fa4 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -2,10 +2,11 @@ name: prqlc # you probably want to 'snapcraft register ' title: PRQL Compiler base: core20 # the base snap is the execution environment for this snap version: git -summary: PRQL is a modern language for transforming data +summary: CLI for PRQL, a modern language for transforming data description: | - PRQL is a modern language for transforming data — a simple, powerful, - pipelined SQL replacement. + prqlc is the CLI for the PRQL compiler. It compiles PRQL to SQL, and offers various diagnostics. + + PRQL is a modern language for transforming data — a simple, powerful, pipelined SQL replacement. issues: https://github.com/PRQL/prql/issues source-code: https://github.com/PRQL/prql contact: https://twitter.com/prql_lang From 4d02cf35cd3e3a8100afece5d776a4cd9df25a0f Mon Sep 17 00:00:00 2001 From: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Date: Wed, 22 Feb 2023 11:36:34 -0800 Subject: [PATCH 034/106] revert: "build: Bump dependencies (#1927)" (#1935) Revert "build: Bump dependencies (#1927)" This reverts commit 7c317ad7ebcf7de340641a103dd7d18418b8d8dc. --- Cargo.lock | 508 +++++++++++++++++---------------- prql-compiler/prqlc/Cargo.toml | 6 +- 2 files changed, 259 insertions(+), 255 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ae6103343766..5eb860296819 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -39,9 +39,9 @@ dependencies = [ [[package]] name = "ahash" -version = "0.8.3" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +checksum = "bf6ccdb167abbf410dcb915cabd428929d7f6a04980b54a11f26a39f1c7f7107" dependencies = [ "cfg-if", "const-random", @@ -76,9 +76,9 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anyhow" -version = "1.0.69" +version = "1.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "224afbd727c3d6e4b90103ece64b8d1b67fbb1973b1046c2281eed3f3803f800" +checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61" dependencies = [ "backtrace", ] @@ -104,7 +104,7 @@ version = "32.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87d948f553cf556656eb89265700258e1032d26fec9b7920cd20319336e06afd" dependencies = [ - "ahash 0.8.3", + "ahash 0.8.2", "arrow-arith", "arrow-array", "arrow-buffer", @@ -130,7 +130,7 @@ dependencies = [ "arrow-data", "arrow-schema", "chrono", - "half 2.2.1", + "half 2.1.0", "num", ] @@ -140,13 +140,13 @@ version = "32.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fe66ec388d882a61fff3eb613b5266af133aa08a3318e5e493daf0f5c1696cb" dependencies = [ - "ahash 0.8.3", + "ahash 0.8.2", "arrow-buffer", "arrow-data", "arrow-schema", "chrono", - "half 2.2.1", - "hashbrown 0.13.2", + "half 2.1.0", + "hashbrown 0.13.1", "num", ] @@ -156,7 +156,7 @@ version = "32.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ef967dadbccd4586ec8d7aab27d7033ecb5dfae8a605c839613039eac227bda" dependencies = [ - "half 2.2.1", + "half 2.1.0", "num", ] @@ -184,7 +184,7 @@ checksum = "ee0c0e3c5d3b80be8f267f4b2af714c08cad630569be01a8379cfe27b4866495" dependencies = [ "arrow-buffer", "arrow-schema", - "half 2.2.1", + "half 2.1.0", "num", ] @@ -208,13 +208,13 @@ version = "32.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e064ac4e64960ebfbe35f218f5e7d9dc9803b59c2e56f611da28ce6d008f839e" dependencies = [ - "ahash 0.8.3", + "ahash 0.8.2", "arrow-array", "arrow-buffer", "arrow-data", "arrow-schema", - "half 2.2.1", - "hashbrown 0.13.2", + "half 2.1.0", + "hashbrown 0.13.1", ] [[package]] @@ -253,9 +253,9 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.64" +version = "0.1.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd7fce9ba8c3c042128ce72d8b2ddbf3a05747efb67ea0313c635e10bda47a2" +checksum = "677d1d8ab452a3936018a687b20e6f7cf5363d713b732b8884001317b0e48aa3" dependencies = [ "proc-macro2", "quote", @@ -317,19 +317,19 @@ dependencies = [ [[package]] name = "borsh" -version = "0.10.2" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40f9ca3698b2e4cb7c15571db0abc5551dca417a21ae8140460b50309bb2cc62" +checksum = "15bf3650200d8bffa99015595e10f1fbd17de07abbc25bb067da79e769939bfa" dependencies = [ "borsh-derive", - "hashbrown 0.13.2", + "hashbrown 0.11.2", ] [[package]] name = "borsh-derive" -version = "0.10.2" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "598b3eacc6db9c3ee57b22707ad8f6a8d2f6d442bfe24ffeb8cbb70ca59e6a35" +checksum = "6441c552f230375d18e3cc377677914d2ca2b0d36e52129fe15450a2dce46775" dependencies = [ "borsh-derive-internal", "borsh-schema-derive-internal", @@ -340,9 +340,9 @@ dependencies = [ [[package]] name = "borsh-derive-internal" -version = "0.10.2" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "186b734fa1c9f6743e90c95d7233c9faab6360d1a96d4ffa19d9cfd1e9350f8a" +checksum = "5449c28a7b352f2d1e592a8a28bf139bc71afb0764a14f3c02500935d8c44065" dependencies = [ "proc-macro2", "quote", @@ -351,9 +351,9 @@ dependencies = [ [[package]] name = "borsh-schema-derive-internal" -version = "0.10.2" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99b7ff1008316626f485991b960ade129253d4034014616b94f309a15366cc49" +checksum = "cdbd5696d8bfa21d53d9fe39a714a18538bad11492a42d066dbbc395fb1951c0" dependencies = [ "proc-macro2", "quote", @@ -362,21 +362,20 @@ dependencies = [ [[package]] name = "bstr" -version = "1.3.0" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ffdb39cb703212f3c11973452c2861b972f757b021158f3516ba10f2fa8b2c1" +checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" dependencies = [ + "lazy_static", "memchr", - "once_cell", "regex-automata", - "serde", ] [[package]] name = "bumpalo" -version = "3.12.0" +version = "3.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" +checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" [[package]] name = "bytecheck" @@ -407,9 +406,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" -version = "1.4.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" [[package]] name = "cast" @@ -419,9 +418,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.0.79" +version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d" dependencies = [ "jobserver", ] @@ -503,13 +502,13 @@ dependencies = [ [[package]] name = "clap" -version = "4.1.6" +version = "4.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0b0588d44d4d63a87dbd75c136c166bbfd9a86a31cb89e09906521c7d3f5e3" +checksum = "4ec7a4128863c188deefe750ac1d1dfe66c236909f845af04beed823638dc1b2" dependencies = [ "bitflags", "clap_derive", - "clap_lex 0.3.1", + "clap_lex 0.3.0", "is-terminal", "once_cell", "strsim", @@ -519,11 +518,11 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.1.2" +version = "4.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd125be87bf4c255ebc50de0b7f4d2a6201e8ac3dc86e39c0ad081dc5e7236fe" +checksum = "b7b3c9eae0de7bf8e3f904a5e40612b21fb2e2e566456d177809a48b892d24da" dependencies = [ - "clap 4.1.6", + "clap 4.1.1", ] [[package]] @@ -550,9 +549,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.3.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "783fe232adfca04f90f56201b26d79682d4cd2625e0bc7290b95123afe558ade" +checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8" dependencies = [ "os_str_bytes", ] @@ -563,9 +562,9 @@ version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94b38784f05c5e908bb8751e9b9f29fbcd470f636c0d0a76a0f90c0c823f3b68" dependencies = [ - "clap 4.1.6", + "clap 4.1.1", "libc", - "windows-sys 0.42.0", + "windows-sys", ] [[package]] @@ -617,9 +616,9 @@ dependencies = [ [[package]] name = "comfy-table" -version = "6.1.4" +version = "6.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e7b787b0dc42e8111badfdbe4c3059158ccb2db8780352fa1b01e8ccf45cc4d" +checksum = "e621e7e86c46fd8a14c32c6ae3cb95656621b4743a27d0cffedb831d46e7ad21" dependencies = [ "strum", "strum_macros", @@ -635,14 +634,14 @@ dependencies = [ [[package]] name = "console" -version = "0.15.5" +version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d79fbe8970a77e3e34151cc13d3b3e248aa0faaecb9f6091fa07ebefe5ad60" +checksum = "c9b6515d269224923b26b5febea2ed42b2d5f2ce37284a4dd670fedd6cb8347a" dependencies = [ "encode_unicode", "lazy_static", "libc", - "windows-sys 0.42.0", + "windows-sys", ] [[package]] @@ -820,9 +819,9 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.91" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86d3488e7665a7a483b57e25bdd90d0aeb2bc7608c8d0346acf2ad3f1caf1d62" +checksum = "5add3fc1717409d029b20c5b6903fc0c0b02fa6741d820054f4a2efa5e5816fd" dependencies = [ "cc", "cxxbridge-flags", @@ -832,9 +831,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.91" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48fcaf066a053a41a81dfb14d57d99738b767febb8b735c3016e469fac5da690" +checksum = "b4c87959ba14bc6fbc61df77c3fcfe180fc32b93538c4f1031dd802ccb5f2ff0" dependencies = [ "cc", "codespan-reporting", @@ -847,15 +846,15 @@ dependencies = [ [[package]] name = "cxxbridge-flags" -version = "1.0.91" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2ef98b8b717a829ca5603af80e1f9e2e48013ab227b68ef37872ef84ee479bf" +checksum = "69a3e162fde4e594ed2b07d0f83c6c67b745e7f28ce58c6df5e6b6bef99dfb59" [[package]] name = "cxxbridge-macro" -version = "1.0.91" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "086c685979a698443656e5cf7856c95c642295a38599f12fb1ff76fb28d19892" +checksum = "3e7e2adeb6a0d4a282e581096b06e1791532b7d576dcde5ccd9382acf55db8e6" dependencies = [ "proc-macro2", "quote", @@ -900,9 +899,9 @@ dependencies = [ [[package]] name = "either" -version = "1.8.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" +checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" [[package]] name = "encode_unicode" @@ -922,6 +921,19 @@ dependencies = [ "syn", ] +[[package]] +name = "env_logger" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + [[package]] name = "env_logger" version = "0.10.0" @@ -980,23 +992,23 @@ checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" [[package]] name = "fastrand" -version = "1.9.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" dependencies = [ "instant", ] [[package]] name = "filetime" -version = "0.2.20" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a3de6e8d11b22ff9edc6d916f890800597d60f8b2da1caf2955c274638d6412" +checksum = "4e884668cd0c7480504233e951174ddc3b382f7c2666e3b7310b5c4e7b0c37f9" dependencies = [ "cfg-if", "libc", "redox_syscall", - "windows-sys 0.45.0", + "windows-sys", ] [[package]] @@ -1025,9 +1037,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.26" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e5317663a9089767a1ec00a487df42e0ca174b61b4483213ac24448e4664df5" +checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed" dependencies = [ "futures-core", "futures-sink", @@ -1035,15 +1047,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.26" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec90ff4d0fe1f57d600049061dc6bb68ed03c7d2fbd697274c41805dcb3f8608" +checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac" [[package]] name = "futures-macro" -version = "0.3.26" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95a73af87da33b5acf53acfebdc339fe592ecf5357ac7c0a7734ab9d8c876a70" +checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d" dependencies = [ "proc-macro2", "quote", @@ -1052,21 +1064,21 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.26" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f310820bb3e8cfd46c80db4d7fb8353e15dfff853a127158425f31e0be6c8364" +checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9" [[package]] name = "futures-task" -version = "0.3.26" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf79a1bf610b10f42aea489289c5a2c478a786509693b80cd39c44ccd936366" +checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea" [[package]] name = "futures-util" -version = "0.3.26" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c1d6de3acfef38d2be4b1f543f553131788603495be83da675e180c8d6b7bd1" +checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6" dependencies = [ "futures-core", "futures-macro", @@ -1109,15 +1121,15 @@ dependencies = [ [[package]] name = "gimli" -version = "0.27.2" +version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" +checksum = "dec7af912d60cdbd3677c1af9352ebae6fb8394d165568a2234df0fa00f87793" [[package]] name = "globset" -version = "0.4.10" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "029d74589adefde59de1a0c4f4732695c32805624aec7b68d91503d4dba79afc" +checksum = "0a1e17342619edbc21a964c2afbeb6c820c6a2560032872f397bb97ea127bd0a" dependencies = [ "aho-corasick", "bstr", @@ -1134,9 +1146,9 @@ checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" [[package]] name = "half" -version = "2.2.1" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b4af3693f1b705df946e9fe5631932443781d0aabb423b62fcd4d73f6d2fd0" +checksum = "ad6a9459c9c30b177b925162351f97e7d967c7ea8bab3b8352805327daf45554" dependencies = [ "crunchy", "num-traits", @@ -1158,22 +1170,28 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.12.3" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" dependencies = [ "ahash 0.7.6", ] [[package]] name = "hashbrown" -version = "0.13.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" dependencies = [ - "ahash 0.8.3", + "ahash 0.7.6", ] +[[package]] +name = "hashbrown" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ff8ae62cd3a9102e5637afc8452c55acf3844001bd5374e0b0bd7b6616c038" + [[package]] name = "hashlink" version = "0.8.1" @@ -1185,9 +1203,9 @@ dependencies = [ [[package]] name = "heck" -version = "0.4.1" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" [[package]] name = "hermit-abi" @@ -1207,12 +1225,6 @@ dependencies = [ "libc", ] -[[package]] -name = "hermit-abi" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" - [[package]] name = "hmac" version = "0.12.1" @@ -1280,9 +1292,9 @@ dependencies = [ [[package]] name = "indoc" -version = "1.0.9" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa799dd5ed20a7e349f3b4639aa80d74549c81716d9ec4f994c9b5815598306" +checksum = "da2d6f23ffea9d7e76c53eee25dfb67bcd8fde7f1198b0855350698c9f07c780" [[package]] name = "inotify" @@ -1331,24 +1343,24 @@ dependencies = [ [[package]] name = "io-lifetimes" -version = "1.0.5" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1abeb7a0dd0f8181267ff8adc397075586500b81b28a73e8a0208b00fc170fb3" +checksum = "46112a93252b123d31a119a8d1a1ac19deac4fac6e0e8b0df58f0d4e5870e63c" dependencies = [ "libc", - "windows-sys 0.45.0", + "windows-sys", ] [[package]] name = "is-terminal" -version = "0.4.3" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22e18b0a45d56fe973d6db23972bf5bc46f988a4a2385deac9cc29572f09daef" +checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189" dependencies = [ - "hermit-abi 0.3.1", + "hermit-abi 0.2.6", "io-lifetimes", "rustix", - "windows-sys 0.45.0", + "windows-sys", ] [[package]] @@ -1397,9 +1409,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.61" +version = "0.3.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" +checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" dependencies = [ "wasm-bindgen", ] @@ -1496,9 +1508,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.139" +version = "0.2.138" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" +checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8" [[package]] name = "libduckdb-sys" @@ -1588,15 +1600,15 @@ dependencies = [ [[package]] name = "mdbook" -version = "0.4.27" +version = "0.4.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f387adfd85d2eeebe3d47d67b1e3f8c9d83ef327582558c5ca88f78d171e73a" +checksum = "d1ed28d5903dde77bd5182645078a37ee57014cac6ccb2d54e1d6496386648e4" dependencies = [ "anyhow", "chrono", - "clap 4.1.6", + "clap 4.1.1", "clap_complete", - "env_logger", + "env_logger 0.10.0", "handlebars", "log", "memchr", @@ -1617,7 +1629,7 @@ name = "mdbook-prql" version = "0.5.2" dependencies = [ "anyhow", - "clap 4.1.6", + "clap 4.1.1", "globset", "insta", "itertools", @@ -1683,21 +1695,21 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.6" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" +checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" dependencies = [ "libc", "log", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.45.0", + "windows-sys", ] [[package]] name = "nom" -version = "7.1.3" +version = "7.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36" dependencies = [ "memchr", "minimal-lexical", @@ -1718,7 +1730,7 @@ dependencies = [ "libc", "mio", "walkdir", - "windows-sys 0.42.0", + "windows-sys", ] [[package]] @@ -1748,9 +1760,9 @@ dependencies = [ [[package]] name = "num-complex" -version = "0.4.3" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02e0d21255c828d6f128a1e41534206671e8c3ea0c62f32291e808dc82cff17d" +checksum = "7ae39348c8bc5fbd7f40c727a9925f03517afd2ab27d46702108b6a7e5414c19" dependencies = [ "num-traits", ] @@ -1819,18 +1831,18 @@ dependencies = [ [[package]] name = "object" -version = "0.30.3" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439" +checksum = "239da7f290cfa979f43f85a8efeee9a8a76d0827c356d37f9d3d7254d6b537fb" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.17.1" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" [[package]] name = "oorandom" @@ -1840,9 +1852,9 @@ checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" [[package]] name = "opener" -version = "0.5.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "293c15678e37254c15bd2f092314abb4e51d7fdde05c2021279c12631b54f005" +checksum = "4ea3ebcd72a54701f56345f16785a6d3ac2df7e986d273eb4395c0b01db17952" dependencies = [ "bstr", "winapi", @@ -1881,15 +1893,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.7" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" +checksum = "7ff9f3fef3968a3ec5945535ed654cb38ff72d7495a25619e2247fb15a2ed9ba" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-sys 0.45.0", + "windows-sys", ] [[package]] @@ -1900,9 +1912,9 @@ checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" [[package]] name = "pest" -version = "2.5.5" +version = "2.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "028accff104c4e513bad663bbcd2ad7cfd5304144404c31ed0a77ac103d00660" +checksum = "cc8bed3549e0f9b0a2a78bf7c0018237a2cdf085eecbbc048e52612438e4e9d0" dependencies = [ "thiserror", "ucd-trie", @@ -1910,9 +1922,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.5.5" +version = "2.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ac3922aac69a40733080f53c1ce7f91dcf57e1a5f6c52f421fadec7fbdc4b69" +checksum = "cdc078600d06ff90d4ed238f0119d84ab5d43dbaad278b0e33a8820293b32344" dependencies = [ "pest", "pest_generator", @@ -1920,9 +1932,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.5.5" +version = "2.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d06646e185566b5961b4058dd107e0a7f56e77c3f484549fb119867773c0f202" +checksum = "28a1af60b1c4148bb269006a750cff8e2ea36aff34d2d96cf7be0b14d1bed23c" dependencies = [ "pest", "pest_meta", @@ -1933,13 +1945,13 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.5.5" +version = "2.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6f60b2ba541577e2a0c307c8f39d1439108120eb7903adeb6497fa880c59616" +checksum = "fec8605d59fc2ae0c6c1aefc0c7c7a9769732017c0ce07f7a9cfffa7b4404f20" dependencies = [ "once_cell", "pest", - "sha2", + "sha1", ] [[package]] @@ -2108,9 +2120,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" -version = "1.0.51" +version = "1.0.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6" +checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5" dependencies = [ "unicode-ident", ] @@ -2208,10 +2220,10 @@ dependencies = [ "anyhow", "ariadne", "atty", - "clap 4.1.6", + "clap 4.1.1", "clio", "color-eyre", - "env_logger", + "env_logger 0.9.3", "insta", "itertools", "minijinja", @@ -2267,9 +2279,9 @@ dependencies = [ [[package]] name = "pyo3" -version = "0.18.1" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06a3d8e8a46ab2738109347433cb7b96dffda2e4a218b03ef27090238886b147" +checksum = "ccd4149c8c3975099622b4e1962dac27565cf5663b76452c3e2b66e0b6824277" dependencies = [ "cfg-if", "indoc", @@ -2284,9 +2296,9 @@ dependencies = [ [[package]] name = "pyo3-build-config" -version = "0.18.1" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75439f995d07ddfad42b192dfcf3bc66a7ecfd8b4a1f5f6f046aa5c2c5d7677d" +checksum = "9cd09fe469834db21ee60e0051030339e5d361293d8cb5ec02facf7fdcf52dbf" dependencies = [ "once_cell", "target-lexicon", @@ -2294,9 +2306,9 @@ dependencies = [ [[package]] name = "pyo3-ffi" -version = "0.18.1" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "839526a5c07a17ff44823679b68add4a58004de00512a95b6c1c98a6dcac0ee5" +checksum = "0c427c9a96b9c5b12156dbc11f76b14f49e9aae8905ca783ea87c249044ef137" dependencies = [ "libc", "pyo3-build-config", @@ -2304,9 +2316,9 @@ dependencies = [ [[package]] name = "pyo3-macros" -version = "0.18.1" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd44cf207476c6a9760c4653559be4f206efafb924d3e4cbf2721475fc0d6cc5" +checksum = "16b822bbba9d60630a44d2109bc410489bb2f439b33e3a14ddeb8a40b378a7c4" dependencies = [ "proc-macro2", "pyo3-macros-backend", @@ -2316,9 +2328,9 @@ dependencies = [ [[package]] name = "pyo3-macros-backend" -version = "0.18.1" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc1f43d8e30460f36350d18631ccf85ded64c059829208fe680904c65bcd0a4c" +checksum = "84ae898104f7c99db06231160770f3e40dad6eb9021daddc0fedfa3e41dff10a" dependencies = [ "proc-macro2", "quote", @@ -2376,9 +2388,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.10.2" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "356a0625f1954f730c0201cdab48611198dc6ce21f4acff55089b5a78e6e835b" +checksum = "cac410af5d00ab6884528b4ab69d1e8e146e8d471201800fa1b4524126de6ad3" dependencies = [ "crossbeam-channel", "crossbeam-deque", @@ -2429,18 +2441,18 @@ dependencies = [ [[package]] name = "rend" -version = "0.4.0" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581008d2099240d37fb08d77ad713bcaec2c4d89d50b5b21a8bb1996bbab68ab" +checksum = "79af64b4b6362ffba04eef3a4e10829718a4896dac19daa741851c86781edf95" dependencies = [ "bytecheck", ] [[package]] name = "rkyv" -version = "0.7.40" +version = "0.7.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c30f1d45d9aa61cbc8cd1eb87705470892289bb2d01943e7803b873a57404dc3" +checksum = "cec2b3485b07d96ddfd3134767b8a447b45ea4eb91448d0a35180ec0ffd5ed15" dependencies = [ "bytecheck", "hashbrown 0.12.3", @@ -2452,9 +2464,9 @@ dependencies = [ [[package]] name = "rkyv_derive" -version = "0.7.40" +version = "0.7.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff26ed6c7c4dfc2aa9480b86a60e3c7233543a270a680e10758a507c5a4ce476" +checksum = "6eaedadc88b53e36dd32d940ed21ae4d850d5916f2581526921f553a72ac34c4" dependencies = [ "proc-macro2", "quote", @@ -2478,9 +2490,9 @@ dependencies = [ [[package]] name = "rust_decimal" -version = "1.28.1" +version = "1.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13cf35f7140155d02ba4ec3294373d513a3c7baa8364c162b030e33c61520a8" +checksum = "33c321ee4e17d2b7abe12b5d20c1231db708dd36185c8a21e9de5fed6da4dbe9" dependencies = [ "arrayvec", "borsh", @@ -2502,16 +2514,16 @@ checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" [[package]] name = "rustix" -version = "0.36.8" +version = "0.36.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43abb88211988493c1abb44a70efa56ff0ce98f233b7b276146f1f3f7ba9644" +checksum = "a3807b5d10909833d3e9acd1eb5fb988f79376ff10fce42937de71a449c4c588" dependencies = [ "bitflags", "errno", "io-lifetimes", "libc", "linux-raw-sys", - "windows-sys 0.45.0", + "windows-sys", ] [[package]] @@ -2603,18 +2615,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.152" +version = "1.0.151" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" +checksum = "97fed41fc1a24994d044e6db6935e69511a1153b52c15eb42493b26fa87feba0" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.152" +version = "1.0.151" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" +checksum = "255abe9a125a985c05190d687b320c12f9b1f0b99445e608c21ba0782c719ad8" dependencies = [ "proc-macro2", "quote", @@ -2623,9 +2635,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.93" +version = "1.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cad406b69c91885b5107daf2c29572f6c8cdb3c66826821e286c533490c0bc76" +checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883" dependencies = [ "itoa", "ryu", @@ -2634,9 +2646,9 @@ dependencies = [ [[package]] name = "serde_yaml" -version = "0.9.17" +version = "0.9.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fb06d4b6cdaef0e0c51fa881acb721bed3c924cfaa71d9c94a3b771dfdf6567" +checksum = "92b5b431e8907b50339b51223b97d102db8d987ced36f6e4d03621db9316c834" dependencies = [ "indexmap", "itoa", @@ -2645,6 +2657,17 @@ dependencies = [ "unsafe-libyaml", ] +[[package]] +name = "sha1" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "sha2" version = "0.10.6" @@ -2685,9 +2708,9 @@ checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" [[package]] name = "slab" -version = "0.4.8" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" dependencies = [ "autocfg", ] @@ -2792,9 +2815,9 @@ dependencies = [ [[package]] name = "target-lexicon" -version = "0.12.6" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae9980cab1db3fceee2f6c6f643d5d8de2997c58ee8d25fb0cc8a9e9e7348e5" +checksum = "9410d0f6853b1d94f0e519fb95df60f29d2c1eff2d921ffdf01a4c8a3b54f12d" [[package]] name = "tempfile" @@ -2812,21 +2835,21 @@ dependencies = [ [[package]] name = "termcolor" -version = "1.2.0" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" dependencies = [ "winapi-util", ] [[package]] name = "terminal_size" -version = "0.2.5" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c9afddd2cec1c0909f06b00ef33f94ab2cc0578c4a610aa208ddfec8aa2b43a" +checksum = "cb20089a8ba2b69debd491f8d2d023761cbf196e999218c591fa1e7e15a21907" dependencies = [ "rustix", - "windows-sys 0.45.0", + "windows-sys", ] [[package]] @@ -2857,11 +2880,10 @@ dependencies = [ [[package]] name = "thread_local" -version = "1.1.7" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" dependencies = [ - "cfg-if", "once_cell", ] @@ -2906,9 +2928,9 @@ dependencies = [ [[package]] name = "tinyvec_macros" -version = "0.1.1" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" @@ -2923,7 +2945,7 @@ dependencies = [ "mio", "pin-project-lite", "socket2", - "windows-sys 0.42.0", + "windows-sys", ] [[package]] @@ -2952,9 +2974,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.7" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5427d89453009325de0d8f342c9490009f76e999cb7672d77e46267448f7e6b2" +checksum = "0bb2e075f03b3d66d8d8785356224ba688d2906a371015e225beeb65ca92c740" dependencies = [ "bytes", "futures-core", @@ -2966,9 +2988,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.5.11" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +checksum = "1333c76748e868a4d9d1017b5ab53171dfd095f70c712fdb4653a406547f598f" dependencies = [ "serde", ] @@ -3023,9 +3045,9 @@ dependencies = [ [[package]] name = "trash" -version = "3.0.1" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a27b2a127810fceb959593bbc6c7b8e0282c2d318d76f0749252197c52a1dd0c" +checksum = "6f74274f95c7e7340d7c5bcd4863af87a9ed6a117cf73cf483c71cb4d744a948" dependencies = [ "chrono", "libc", @@ -3060,9 +3082,9 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.10" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54675592c1dbefd78cbd98db9bacd89886e1ca50692a0692baefffdeb92dd58" +checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" [[package]] name = "unicode-ident" @@ -3172,9 +3194,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.84" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" +checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -3182,9 +3204,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.84" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" +checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" dependencies = [ "bumpalo", "log", @@ -3197,9 +3219,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.34" +version = "0.4.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454" +checksum = "23639446165ca5a5de86ae1d8896b737ae80319560fbaa4c2887b7da6e7ebd7d" dependencies = [ "cfg-if", "js-sys", @@ -3209,9 +3231,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.84" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" +checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3219,9 +3241,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.84" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" +checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" dependencies = [ "proc-macro2", "quote", @@ -3232,15 +3254,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.84" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" +checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" [[package]] name = "wasm-bindgen-test" -version = "0.3.34" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db36fc0f9fb209e88fb3642590ae0205bb5a56216dabd963ba15879fe53a30b" +checksum = "09d2fff962180c3fadf677438054b1db62bee4aa32af26a45388af07d1287e1d" dependencies = [ "console_error_panic_hook", "js-sys", @@ -3252,9 +3274,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-test-macro" -version = "0.3.34" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0734759ae6b3b1717d661fe4f016efcfb9828f5edb4520c18eaee05af3b43be9" +checksum = "4683da3dfc016f704c9f82cf401520c4f1cb3ee440f7f52b3d6ac29506a49ca7" dependencies = [ "proc-macro2", "quote", @@ -3262,9 +3284,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.61" +version = "0.3.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" +checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" dependencies = [ "js-sys", "wasm-bindgen", @@ -3303,18 +3325,9 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows" -version = "0.44.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e745dab35a0c4c77aa3ce42d595e13d2003d6902d6b08c9ef5fc326d08da12b" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-sys" -version = "0.42.0" +version = "0.43.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +checksum = "04662ed0e3e5630dfa9b26e4cb823b817f1a9addda855d973a9458c236556244" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", @@ -3327,18 +3340,9 @@ dependencies = [ [[package]] name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-targets" -version = "0.42.1" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", @@ -3351,45 +3355,45 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.1" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" +checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" [[package]] name = "windows_aarch64_msvc" -version = "0.42.1" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" +checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" [[package]] name = "windows_i686_gnu" -version = "0.42.1" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" +checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" [[package]] name = "windows_i686_msvc" -version = "0.42.1" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" +checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" [[package]] name = "windows_x86_64_gnu" -version = "0.42.1" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" +checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.1" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" +checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" [[package]] name = "windows_x86_64_msvc" -version = "0.42.1" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" +checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" [[package]] name = "yaml-rust" diff --git a/prql-compiler/prqlc/Cargo.toml b/prql-compiler/prqlc/Cargo.toml index 40b0ced399be..f159b4c20431 100644 --- a/prql-compiler/prqlc/Cargo.toml +++ b/prql-compiler/prqlc/Cargo.toml @@ -15,15 +15,15 @@ atty = "0.2.14" clap = {version = "4.1.1", features = ["derive"]} clio = {version = "0.2.4", features = ['clap-parse']} color-eyre = "0.6.1" -env_logger = {version = "0.10.0", features = ["color"]} +env_logger = {version = "0.9.1", features = ["termcolor"]} itertools = "0.10.3" -minijinja = {version = "0.30.4", features = ["unstable_machinery"]} notify = "^5.1.0" +minijinja = {version = "0.30.4", features = ["unstable_machinery"]} prql-compiler = {path = '..', version = "0.5.2"} regex = {version = "1.7.1", features = ["std", "unicode"]} -serde = "^1" serde_json = "1.0.81" serde_yaml = "0.9.1" +serde = "^1" walkdir = "^2.3.2" [target.'cfg(not(target_family="wasm"))'.dev-dependencies] From 7bac7f89d22735a02a2fec00cbf887760caf6e49 Mon Sep 17 00:00:00 2001 From: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Date: Wed, 22 Feb 2023 16:04:13 -0800 Subject: [PATCH 035/106] devops: Add `web` to semantic commit categories (#1938) --- .github/workflows/pull-request-target.yaml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pull-request-target.yaml b/.github/workflows/pull-request-target.yaml index 21e238992728..81b8762bf0d7 100644 --- a/.github/workflows/pull-request-target.yaml +++ b/.github/workflows/pull-request-target.yaml @@ -19,8 +19,10 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: requireScope: false - # The standard ones plus "internal", for code quality / ergonomics - # improvements, and "devops" for developer ergonomics. + # The standard ones plus + # - "internal" for code quality / ergonomics improvements + # - "devops" for developer ergonomics + # - "web" for playground / website (but not docs) types: | feat fix @@ -35,6 +37,7 @@ jobs: revert internal devops + web backport: # Backport to `web` branch on `pr-backport-web` From 5cf0779e148e436b90e19e211120e28a8972f768 Mon Sep 17 00:00:00 2001 From: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Date: Wed, 22 Feb 2023 16:04:34 -0800 Subject: [PATCH 036/106] build: Re-revert #1935 (#1937) Locked wasm-bindgen, I think because of a wasm-pack problem --- Cargo.lock | 468 +++++++++--------- prql-compiler/prql-compiler-macros/Cargo.toml | 6 +- prql-compiler/prqlc/Cargo.toml | 6 +- prql-js/Cargo.toml | 7 +- 4 files changed, 245 insertions(+), 242 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5eb860296819..754ecb3bc58f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -39,9 +39,9 @@ dependencies = [ [[package]] name = "ahash" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf6ccdb167abbf410dcb915cabd428929d7f6a04980b54a11f26a39f1c7f7107" +checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" dependencies = [ "cfg-if", "const-random", @@ -76,9 +76,9 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anyhow" -version = "1.0.68" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61" +checksum = "224afbd727c3d6e4b90103ece64b8d1b67fbb1973b1046c2281eed3f3803f800" dependencies = [ "backtrace", ] @@ -104,7 +104,7 @@ version = "32.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87d948f553cf556656eb89265700258e1032d26fec9b7920cd20319336e06afd" dependencies = [ - "ahash 0.8.2", + "ahash 0.8.3", "arrow-arith", "arrow-array", "arrow-buffer", @@ -130,7 +130,7 @@ dependencies = [ "arrow-data", "arrow-schema", "chrono", - "half 2.1.0", + "half 2.2.1", "num", ] @@ -140,13 +140,13 @@ version = "32.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fe66ec388d882a61fff3eb613b5266af133aa08a3318e5e493daf0f5c1696cb" dependencies = [ - "ahash 0.8.2", + "ahash 0.8.3", "arrow-buffer", "arrow-data", "arrow-schema", "chrono", - "half 2.1.0", - "hashbrown 0.13.1", + "half 2.2.1", + "hashbrown 0.13.2", "num", ] @@ -156,7 +156,7 @@ version = "32.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ef967dadbccd4586ec8d7aab27d7033ecb5dfae8a605c839613039eac227bda" dependencies = [ - "half 2.1.0", + "half 2.2.1", "num", ] @@ -184,7 +184,7 @@ checksum = "ee0c0e3c5d3b80be8f267f4b2af714c08cad630569be01a8379cfe27b4866495" dependencies = [ "arrow-buffer", "arrow-schema", - "half 2.1.0", + "half 2.2.1", "num", ] @@ -208,13 +208,13 @@ version = "32.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e064ac4e64960ebfbe35f218f5e7d9dc9803b59c2e56f611da28ce6d008f839e" dependencies = [ - "ahash 0.8.2", + "ahash 0.8.3", "arrow-array", "arrow-buffer", "arrow-data", "arrow-schema", - "half 2.1.0", - "hashbrown 0.13.1", + "half 2.2.1", + "hashbrown 0.13.2", ] [[package]] @@ -253,9 +253,9 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.60" +version = "0.1.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d1d8ab452a3936018a687b20e6f7cf5363d713b732b8884001317b0e48aa3" +checksum = "1cd7fce9ba8c3c042128ce72d8b2ddbf3a05747efb67ea0313c635e10bda47a2" dependencies = [ "proc-macro2", "quote", @@ -317,19 +317,19 @@ dependencies = [ [[package]] name = "borsh" -version = "0.9.3" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15bf3650200d8bffa99015595e10f1fbd17de07abbc25bb067da79e769939bfa" +checksum = "40f9ca3698b2e4cb7c15571db0abc5551dca417a21ae8140460b50309bb2cc62" dependencies = [ "borsh-derive", - "hashbrown 0.11.2", + "hashbrown 0.13.2", ] [[package]] name = "borsh-derive" -version = "0.9.3" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6441c552f230375d18e3cc377677914d2ca2b0d36e52129fe15450a2dce46775" +checksum = "598b3eacc6db9c3ee57b22707ad8f6a8d2f6d442bfe24ffeb8cbb70ca59e6a35" dependencies = [ "borsh-derive-internal", "borsh-schema-derive-internal", @@ -340,9 +340,9 @@ dependencies = [ [[package]] name = "borsh-derive-internal" -version = "0.9.3" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5449c28a7b352f2d1e592a8a28bf139bc71afb0764a14f3c02500935d8c44065" +checksum = "186b734fa1c9f6743e90c95d7233c9faab6360d1a96d4ffa19d9cfd1e9350f8a" dependencies = [ "proc-macro2", "quote", @@ -351,9 +351,9 @@ dependencies = [ [[package]] name = "borsh-schema-derive-internal" -version = "0.9.3" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdbd5696d8bfa21d53d9fe39a714a18538bad11492a42d066dbbc395fb1951c0" +checksum = "99b7ff1008316626f485991b960ade129253d4034014616b94f309a15366cc49" dependencies = [ "proc-macro2", "quote", @@ -362,20 +362,21 @@ dependencies = [ [[package]] name = "bstr" -version = "0.2.17" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" +checksum = "5ffdb39cb703212f3c11973452c2861b972f757b021158f3516ba10f2fa8b2c1" dependencies = [ - "lazy_static", "memchr", + "once_cell", "regex-automata", + "serde", ] [[package]] name = "bumpalo" -version = "3.11.1" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" +checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" [[package]] name = "bytecheck" @@ -406,9 +407,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" +checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" [[package]] name = "cast" @@ -418,9 +419,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.0.78" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" dependencies = [ "jobserver", ] @@ -502,13 +503,13 @@ dependencies = [ [[package]] name = "clap" -version = "4.1.1" +version = "4.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec7a4128863c188deefe750ac1d1dfe66c236909f845af04beed823638dc1b2" +checksum = "ec0b0588d44d4d63a87dbd75c136c166bbfd9a86a31cb89e09906521c7d3f5e3" dependencies = [ "bitflags", "clap_derive", - "clap_lex 0.3.0", + "clap_lex 0.3.1", "is-terminal", "once_cell", "strsim", @@ -518,11 +519,11 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.0.6" +version = "4.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7b3c9eae0de7bf8e3f904a5e40612b21fb2e2e566456d177809a48b892d24da" +checksum = "bd125be87bf4c255ebc50de0b7f4d2a6201e8ac3dc86e39c0ad081dc5e7236fe" dependencies = [ - "clap 4.1.1", + "clap 4.1.6", ] [[package]] @@ -549,9 +550,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8" +checksum = "783fe232adfca04f90f56201b26d79682d4cd2625e0bc7290b95123afe558ade" dependencies = [ "os_str_bytes", ] @@ -562,9 +563,9 @@ version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94b38784f05c5e908bb8751e9b9f29fbcd470f636c0d0a76a0f90c0c823f3b68" dependencies = [ - "clap 4.1.1", + "clap 4.1.6", "libc", - "windows-sys", + "windows-sys 0.42.0", ] [[package]] @@ -616,9 +617,9 @@ dependencies = [ [[package]] name = "comfy-table" -version = "6.1.3" +version = "6.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e621e7e86c46fd8a14c32c6ae3cb95656621b4743a27d0cffedb831d46e7ad21" +checksum = "6e7b787b0dc42e8111badfdbe4c3059158ccb2db8780352fa1b01e8ccf45cc4d" dependencies = [ "strum", "strum_macros", @@ -634,14 +635,14 @@ dependencies = [ [[package]] name = "console" -version = "0.15.4" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9b6515d269224923b26b5febea2ed42b2d5f2ce37284a4dd670fedd6cb8347a" +checksum = "c3d79fbe8970a77e3e34151cc13d3b3e248aa0faaecb9f6091fa07ebefe5ad60" dependencies = [ "encode_unicode", "lazy_static", "libc", - "windows-sys", + "windows-sys 0.42.0", ] [[package]] @@ -819,9 +820,9 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.85" +version = "1.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5add3fc1717409d029b20c5b6903fc0c0b02fa6741d820054f4a2efa5e5816fd" +checksum = "86d3488e7665a7a483b57e25bdd90d0aeb2bc7608c8d0346acf2ad3f1caf1d62" dependencies = [ "cc", "cxxbridge-flags", @@ -831,9 +832,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.85" +version = "1.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4c87959ba14bc6fbc61df77c3fcfe180fc32b93538c4f1031dd802ccb5f2ff0" +checksum = "48fcaf066a053a41a81dfb14d57d99738b767febb8b735c3016e469fac5da690" dependencies = [ "cc", "codespan-reporting", @@ -846,15 +847,15 @@ dependencies = [ [[package]] name = "cxxbridge-flags" -version = "1.0.85" +version = "1.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69a3e162fde4e594ed2b07d0f83c6c67b745e7f28ce58c6df5e6b6bef99dfb59" +checksum = "a2ef98b8b717a829ca5603af80e1f9e2e48013ab227b68ef37872ef84ee479bf" [[package]] name = "cxxbridge-macro" -version = "1.0.85" +version = "1.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e7e2adeb6a0d4a282e581096b06e1791532b7d576dcde5ccd9382acf55db8e6" +checksum = "086c685979a698443656e5cf7856c95c642295a38599f12fb1ff76fb28d19892" dependencies = [ "proc-macro2", "quote", @@ -899,9 +900,9 @@ dependencies = [ [[package]] name = "either" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" [[package]] name = "encode_unicode" @@ -921,19 +922,6 @@ dependencies = [ "syn", ] -[[package]] -name = "env_logger" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" -dependencies = [ - "atty", - "humantime", - "log", - "regex", - "termcolor", -] - [[package]] name = "env_logger" version = "0.10.0" @@ -992,23 +980,23 @@ checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" [[package]] name = "fastrand" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" dependencies = [ "instant", ] [[package]] name = "filetime" -version = "0.2.19" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e884668cd0c7480504233e951174ddc3b382f7c2666e3b7310b5c4e7b0c37f9" +checksum = "8a3de6e8d11b22ff9edc6d916f890800597d60f8b2da1caf2955c274638d6412" dependencies = [ "cfg-if", "libc", "redox_syscall", - "windows-sys", + "windows-sys 0.45.0", ] [[package]] @@ -1037,9 +1025,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed" +checksum = "2e5317663a9089767a1ec00a487df42e0ca174b61b4483213ac24448e4664df5" dependencies = [ "futures-core", "futures-sink", @@ -1047,15 +1035,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac" +checksum = "ec90ff4d0fe1f57d600049061dc6bb68ed03c7d2fbd697274c41805dcb3f8608" [[package]] name = "futures-macro" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d" +checksum = "95a73af87da33b5acf53acfebdc339fe592ecf5357ac7c0a7734ab9d8c876a70" dependencies = [ "proc-macro2", "quote", @@ -1064,21 +1052,21 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9" +checksum = "f310820bb3e8cfd46c80db4d7fb8353e15dfff853a127158425f31e0be6c8364" [[package]] name = "futures-task" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea" +checksum = "dcf79a1bf610b10f42aea489289c5a2c478a786509693b80cd39c44ccd936366" [[package]] name = "futures-util" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6" +checksum = "9c1d6de3acfef38d2be4b1f543f553131788603495be83da675e180c8d6b7bd1" dependencies = [ "futures-core", "futures-macro", @@ -1121,15 +1109,15 @@ dependencies = [ [[package]] name = "gimli" -version = "0.27.0" +version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dec7af912d60cdbd3677c1af9352ebae6fb8394d165568a2234df0fa00f87793" +checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" [[package]] name = "globset" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a1e17342619edbc21a964c2afbeb6c820c6a2560032872f397bb97ea127bd0a" +checksum = "029d74589adefde59de1a0c4f4732695c32805624aec7b68d91503d4dba79afc" dependencies = [ "aho-corasick", "bstr", @@ -1146,9 +1134,9 @@ checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" [[package]] name = "half" -version = "2.1.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad6a9459c9c30b177b925162351f97e7d967c7ea8bab3b8352805327daf45554" +checksum = "02b4af3693f1b705df946e9fe5631932443781d0aabb423b62fcd4d73f6d2fd0" dependencies = [ "crunchy", "num-traits", @@ -1168,15 +1156,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "hashbrown" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" -dependencies = [ - "ahash 0.7.6", -] - [[package]] name = "hashbrown" version = "0.12.3" @@ -1188,9 +1167,12 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.13.1" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ff8ae62cd3a9102e5637afc8452c55acf3844001bd5374e0b0bd7b6616c038" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash 0.8.3", +] [[package]] name = "hashlink" @@ -1203,9 +1185,9 @@ dependencies = [ [[package]] name = "heck" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" @@ -1225,6 +1207,12 @@ dependencies = [ "libc", ] +[[package]] +name = "hermit-abi" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" + [[package]] name = "hmac" version = "0.12.1" @@ -1292,9 +1280,9 @@ dependencies = [ [[package]] name = "indoc" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da2d6f23ffea9d7e76c53eee25dfb67bcd8fde7f1198b0855350698c9f07c780" +checksum = "bfa799dd5ed20a7e349f3b4639aa80d74549c81716d9ec4f994c9b5815598306" [[package]] name = "inotify" @@ -1343,24 +1331,24 @@ dependencies = [ [[package]] name = "io-lifetimes" -version = "1.0.3" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46112a93252b123d31a119a8d1a1ac19deac4fac6e0e8b0df58f0d4e5870e63c" +checksum = "1abeb7a0dd0f8181267ff8adc397075586500b81b28a73e8a0208b00fc170fb3" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.45.0", ] [[package]] name = "is-terminal" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189" +checksum = "22e18b0a45d56fe973d6db23972bf5bc46f988a4a2385deac9cc29572f09daef" dependencies = [ - "hermit-abi 0.2.6", + "hermit-abi 0.3.1", "io-lifetimes", "rustix", - "windows-sys", + "windows-sys 0.45.0", ] [[package]] @@ -1508,9 +1496,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.138" +version = "0.2.139" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8" +checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" [[package]] name = "libduckdb-sys" @@ -1600,15 +1588,15 @@ dependencies = [ [[package]] name = "mdbook" -version = "0.4.25" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1ed28d5903dde77bd5182645078a37ee57014cac6ccb2d54e1d6496386648e4" +checksum = "0f387adfd85d2eeebe3d47d67b1e3f8c9d83ef327582558c5ca88f78d171e73a" dependencies = [ "anyhow", "chrono", - "clap 4.1.1", + "clap 4.1.6", "clap_complete", - "env_logger 0.10.0", + "env_logger", "handlebars", "log", "memchr", @@ -1629,7 +1617,7 @@ name = "mdbook-prql" version = "0.5.2" dependencies = [ "anyhow", - "clap 4.1.1", + "clap 4.1.6", "globset", "insta", "itertools", @@ -1695,21 +1683,21 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" +checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" dependencies = [ "libc", "log", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys", + "windows-sys 0.45.0", ] [[package]] name = "nom" -version = "7.1.1" +version = "7.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" dependencies = [ "memchr", "minimal-lexical", @@ -1730,7 +1718,7 @@ dependencies = [ "libc", "mio", "walkdir", - "windows-sys", + "windows-sys 0.42.0", ] [[package]] @@ -1760,9 +1748,9 @@ dependencies = [ [[package]] name = "num-complex" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ae39348c8bc5fbd7f40c727a9925f03517afd2ab27d46702108b6a7e5414c19" +checksum = "02e0d21255c828d6f128a1e41534206671e8c3ea0c62f32291e808dc82cff17d" dependencies = [ "num-traits", ] @@ -1831,18 +1819,18 @@ dependencies = [ [[package]] name = "object" -version = "0.30.0" +version = "0.30.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "239da7f290cfa979f43f85a8efeee9a8a76d0827c356d37f9d3d7254d6b537fb" +checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.17.0" +version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" +checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" [[package]] name = "oorandom" @@ -1852,9 +1840,9 @@ checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" [[package]] name = "opener" -version = "0.5.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ea3ebcd72a54701f56345f16785a6d3ac2df7e986d273eb4395c0b01db17952" +checksum = "293c15678e37254c15bd2f092314abb4e51d7fdde05c2021279c12631b54f005" dependencies = [ "bstr", "winapi", @@ -1893,15 +1881,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.5" +version = "0.9.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ff9f3fef3968a3ec5945535ed654cb38ff72d7495a25619e2247fb15a2ed9ba" +checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-sys", + "windows-sys 0.45.0", ] [[package]] @@ -1912,9 +1900,9 @@ checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" [[package]] name = "pest" -version = "2.5.1" +version = "2.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc8bed3549e0f9b0a2a78bf7c0018237a2cdf085eecbbc048e52612438e4e9d0" +checksum = "028accff104c4e513bad663bbcd2ad7cfd5304144404c31ed0a77ac103d00660" dependencies = [ "thiserror", "ucd-trie", @@ -1922,9 +1910,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.5.1" +version = "2.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdc078600d06ff90d4ed238f0119d84ab5d43dbaad278b0e33a8820293b32344" +checksum = "2ac3922aac69a40733080f53c1ce7f91dcf57e1a5f6c52f421fadec7fbdc4b69" dependencies = [ "pest", "pest_generator", @@ -1932,9 +1920,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.5.1" +version = "2.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28a1af60b1c4148bb269006a750cff8e2ea36aff34d2d96cf7be0b14d1bed23c" +checksum = "d06646e185566b5961b4058dd107e0a7f56e77c3f484549fb119867773c0f202" dependencies = [ "pest", "pest_meta", @@ -1945,13 +1933,13 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.5.1" +version = "2.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fec8605d59fc2ae0c6c1aefc0c7c7a9769732017c0ce07f7a9cfffa7b4404f20" +checksum = "e6f60b2ba541577e2a0c307c8f39d1439108120eb7903adeb6497fa880c59616" dependencies = [ "once_cell", "pest", - "sha1", + "sha2", ] [[package]] @@ -2120,9 +2108,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" -version = "1.0.49" +version = "1.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5" +checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6" dependencies = [ "unicode-ident", ] @@ -2220,10 +2208,10 @@ dependencies = [ "anyhow", "ariadne", "atty", - "clap 4.1.1", + "clap 4.1.6", "clio", "color-eyre", - "env_logger 0.9.3", + "env_logger", "insta", "itertools", "minijinja", @@ -2279,9 +2267,9 @@ dependencies = [ [[package]] name = "pyo3" -version = "0.18.0" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccd4149c8c3975099622b4e1962dac27565cf5663b76452c3e2b66e0b6824277" +checksum = "06a3d8e8a46ab2738109347433cb7b96dffda2e4a218b03ef27090238886b147" dependencies = [ "cfg-if", "indoc", @@ -2296,9 +2284,9 @@ dependencies = [ [[package]] name = "pyo3-build-config" -version = "0.18.0" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cd09fe469834db21ee60e0051030339e5d361293d8cb5ec02facf7fdcf52dbf" +checksum = "75439f995d07ddfad42b192dfcf3bc66a7ecfd8b4a1f5f6f046aa5c2c5d7677d" dependencies = [ "once_cell", "target-lexicon", @@ -2306,9 +2294,9 @@ dependencies = [ [[package]] name = "pyo3-ffi" -version = "0.18.0" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c427c9a96b9c5b12156dbc11f76b14f49e9aae8905ca783ea87c249044ef137" +checksum = "839526a5c07a17ff44823679b68add4a58004de00512a95b6c1c98a6dcac0ee5" dependencies = [ "libc", "pyo3-build-config", @@ -2316,9 +2304,9 @@ dependencies = [ [[package]] name = "pyo3-macros" -version = "0.18.0" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b822bbba9d60630a44d2109bc410489bb2f439b33e3a14ddeb8a40b378a7c4" +checksum = "bd44cf207476c6a9760c4653559be4f206efafb924d3e4cbf2721475fc0d6cc5" dependencies = [ "proc-macro2", "pyo3-macros-backend", @@ -2328,9 +2316,9 @@ dependencies = [ [[package]] name = "pyo3-macros-backend" -version = "0.18.0" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84ae898104f7c99db06231160770f3e40dad6eb9021daddc0fedfa3e41dff10a" +checksum = "dc1f43d8e30460f36350d18631ccf85ded64c059829208fe680904c65bcd0a4c" dependencies = [ "proc-macro2", "quote", @@ -2388,9 +2376,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.10.1" +version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cac410af5d00ab6884528b4ab69d1e8e146e8d471201800fa1b4524126de6ad3" +checksum = "356a0625f1954f730c0201cdab48611198dc6ce21f4acff55089b5a78e6e835b" dependencies = [ "crossbeam-channel", "crossbeam-deque", @@ -2441,18 +2429,18 @@ dependencies = [ [[package]] name = "rend" -version = "0.3.6" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79af64b4b6362ffba04eef3a4e10829718a4896dac19daa741851c86781edf95" +checksum = "581008d2099240d37fb08d77ad713bcaec2c4d89d50b5b21a8bb1996bbab68ab" dependencies = [ "bytecheck", ] [[package]] name = "rkyv" -version = "0.7.39" +version = "0.7.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cec2b3485b07d96ddfd3134767b8a447b45ea4eb91448d0a35180ec0ffd5ed15" +checksum = "c30f1d45d9aa61cbc8cd1eb87705470892289bb2d01943e7803b873a57404dc3" dependencies = [ "bytecheck", "hashbrown 0.12.3", @@ -2464,9 +2452,9 @@ dependencies = [ [[package]] name = "rkyv_derive" -version = "0.7.39" +version = "0.7.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eaedadc88b53e36dd32d940ed21ae4d850d5916f2581526921f553a72ac34c4" +checksum = "ff26ed6c7c4dfc2aa9480b86a60e3c7233543a270a680e10758a507c5a4ce476" dependencies = [ "proc-macro2", "quote", @@ -2490,9 +2478,9 @@ dependencies = [ [[package]] name = "rust_decimal" -version = "1.27.0" +version = "1.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33c321ee4e17d2b7abe12b5d20c1231db708dd36185c8a21e9de5fed6da4dbe9" +checksum = "e13cf35f7140155d02ba4ec3294373d513a3c7baa8364c162b030e33c61520a8" dependencies = [ "arrayvec", "borsh", @@ -2514,16 +2502,16 @@ checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" [[package]] name = "rustix" -version = "0.36.5" +version = "0.36.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3807b5d10909833d3e9acd1eb5fb988f79376ff10fce42937de71a449c4c588" +checksum = "f43abb88211988493c1abb44a70efa56ff0ce98f233b7b276146f1f3f7ba9644" dependencies = [ "bitflags", "errno", "io-lifetimes", "libc", "linux-raw-sys", - "windows-sys", + "windows-sys 0.45.0", ] [[package]] @@ -2615,18 +2603,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.151" +version = "1.0.152" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97fed41fc1a24994d044e6db6935e69511a1153b52c15eb42493b26fa87feba0" +checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.151" +version = "1.0.152" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "255abe9a125a985c05190d687b320c12f9b1f0b99445e608c21ba0782c719ad8" +checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" dependencies = [ "proc-macro2", "quote", @@ -2635,9 +2623,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.91" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883" +checksum = "cad406b69c91885b5107daf2c29572f6c8cdb3c66826821e286c533490c0bc76" dependencies = [ "itoa", "ryu", @@ -2646,9 +2634,9 @@ dependencies = [ [[package]] name = "serde_yaml" -version = "0.9.16" +version = "0.9.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92b5b431e8907b50339b51223b97d102db8d987ced36f6e4d03621db9316c834" +checksum = "8fb06d4b6cdaef0e0c51fa881acb721bed3c924cfaa71d9c94a3b771dfdf6567" dependencies = [ "indexmap", "itoa", @@ -2657,17 +2645,6 @@ dependencies = [ "unsafe-libyaml", ] -[[package]] -name = "sha1" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - [[package]] name = "sha2" version = "0.10.6" @@ -2708,9 +2685,9 @@ checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" [[package]] name = "slab" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" dependencies = [ "autocfg", ] @@ -2815,9 +2792,9 @@ dependencies = [ [[package]] name = "target-lexicon" -version = "0.12.5" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9410d0f6853b1d94f0e519fb95df60f29d2c1eff2d921ffdf01a4c8a3b54f12d" +checksum = "8ae9980cab1db3fceee2f6c6f643d5d8de2997c58ee8d25fb0cc8a9e9e7348e5" [[package]] name = "tempfile" @@ -2835,21 +2812,21 @@ dependencies = [ [[package]] name = "termcolor" -version = "1.1.3" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" dependencies = [ "winapi-util", ] [[package]] name = "terminal_size" -version = "0.2.3" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb20089a8ba2b69debd491f8d2d023761cbf196e999218c591fa1e7e15a21907" +checksum = "4c9afddd2cec1c0909f06b00ef33f94ab2cc0578c4a610aa208ddfec8aa2b43a" dependencies = [ "rustix", - "windows-sys", + "windows-sys 0.45.0", ] [[package]] @@ -2880,10 +2857,11 @@ dependencies = [ [[package]] name = "thread_local" -version = "1.1.4" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" dependencies = [ + "cfg-if", "once_cell", ] @@ -2928,9 +2906,9 @@ dependencies = [ [[package]] name = "tinyvec_macros" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" @@ -2945,7 +2923,7 @@ dependencies = [ "mio", "pin-project-lite", "socket2", - "windows-sys", + "windows-sys 0.42.0", ] [[package]] @@ -2974,9 +2952,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.4" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bb2e075f03b3d66d8d8785356224ba688d2906a371015e225beeb65ca92c740" +checksum = "5427d89453009325de0d8f342c9490009f76e999cb7672d77e46267448f7e6b2" dependencies = [ "bytes", "futures-core", @@ -2988,9 +2966,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.5.10" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1333c76748e868a4d9d1017b5ab53171dfd095f70c712fdb4653a406547f598f" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" dependencies = [ "serde", ] @@ -3045,9 +3023,9 @@ dependencies = [ [[package]] name = "trash" -version = "3.0.0" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f74274f95c7e7340d7c5bcd4863af87a9ed6a117cf73cf483c71cb4d744a948" +checksum = "a27b2a127810fceb959593bbc6c7b8e0282c2d318d76f0749252197c52a1dd0c" dependencies = [ "chrono", "libc", @@ -3082,9 +3060,9 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.8" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" +checksum = "d54675592c1dbefd78cbd98db9bacd89886e1ca50692a0692baefffdeb92dd58" [[package]] name = "unicode-ident" @@ -3325,9 +3303,18 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows" -version = "0.43.0" +version = "0.44.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e745dab35a0c4c77aa3ce42d595e13d2003d6902d6b08c9ef5fc326d08da12b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04662ed0e3e5630dfa9b26e4cb823b817f1a9addda855d973a9458c236556244" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", @@ -3340,9 +3327,18 @@ dependencies = [ [[package]] name = "windows-sys" -version = "0.42.0" +version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", @@ -3355,45 +3351,45 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" +checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" [[package]] name = "windows_aarch64_msvc" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" +checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" [[package]] name = "windows_i686_gnu" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" +checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" [[package]] name = "windows_i686_msvc" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" +checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" [[package]] name = "windows_x86_64_gnu" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" +checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" +checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" [[package]] name = "windows_x86_64_msvc" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" +checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" [[package]] name = "yaml-rust" diff --git a/prql-compiler/prql-compiler-macros/Cargo.toml b/prql-compiler/prql-compiler-macros/Cargo.toml index 460ff18a7d27..2244c503b04d 100644 --- a/prql-compiler/prql-compiler-macros/Cargo.toml +++ b/prql-compiler/prql-compiler-macros/Cargo.toml @@ -14,8 +14,10 @@ proc_macro = true test = false [dependencies] -prql-compiler = {path = "..", default-features = false, version = "0.5.2" } -syn = "1.0" +prql-compiler = {path = "..", default-features = false, version = "0.5.2"} +# Was getting build errors with more recent versions; can remove pin if it +# successfully builds. +syn = "=1.0.107" [package.metadata.release] tag-name = "{{version}}" diff --git a/prql-compiler/prqlc/Cargo.toml b/prql-compiler/prqlc/Cargo.toml index f159b4c20431..40b0ced399be 100644 --- a/prql-compiler/prqlc/Cargo.toml +++ b/prql-compiler/prqlc/Cargo.toml @@ -15,15 +15,15 @@ atty = "0.2.14" clap = {version = "4.1.1", features = ["derive"]} clio = {version = "0.2.4", features = ['clap-parse']} color-eyre = "0.6.1" -env_logger = {version = "0.9.1", features = ["termcolor"]} +env_logger = {version = "0.10.0", features = ["color"]} itertools = "0.10.3" -notify = "^5.1.0" minijinja = {version = "0.30.4", features = ["unstable_machinery"]} +notify = "^5.1.0" prql-compiler = {path = '..', version = "0.5.2"} regex = {version = "1.7.1", features = ["std", "unicode"]} +serde = "^1" serde_json = "1.0.81" serde_yaml = "0.9.1" -serde = "^1" walkdir = "^2.3.2" [target.'cfg(not(target_family="wasm"))'.dev-dependencies] diff --git a/prql-js/Cargo.toml b/prql-js/Cargo.toml index ef5a64a6610a..c74ee4057dec 100644 --- a/prql-js/Cargo.toml +++ b/prql-js/Cargo.toml @@ -23,7 +23,12 @@ default = ["console_error_panic_hook"] [dependencies] prql-compiler = {path = "../prql-compiler", default-features = false} -wasm-bindgen = "0.2.80" +# This was preventing the playground from working. It's possibly +# https://github.com/rustwasm/wasm-bindgen/issues/3276 +# If the playground works with a later version, we can unpin this. It's likely +# related to wasm-pack. So https://github.com/PRQL/prql/issues/1836 would likely +# solve it, along with simplifying the build process. +wasm-bindgen = "=0.2.83" # The `console_error_panic_hook` crate provides better debugging of panics by # logging them with `console.error`. This is great for development, but requires From ce8bdb40fbadefcc5cbdf2ee35375355f4f7d41f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alja=C5=BE=20Mur=20Er=C5=BEen?= Date: Thu, 23 Feb 2023 14:42:17 +0100 Subject: [PATCH 037/106] refactor: remove trailing whitespace (#1943) --- .../PrqlCompiler.Tests/CompilerTest.cs | 46 +++++++-------- .../PrqlCompiler.Tests.csproj | 56 +++++++++---------- prql-dotnet/prql-net.sln | 56 +++++++++---------- 3 files changed, 79 insertions(+), 79 deletions(-) diff --git a/prql-dotnet/PrqlCompiler.Tests/CompilerTest.cs b/prql-dotnet/PrqlCompiler.Tests/CompilerTest.cs index a5afa68f0942..a405d2c75fa5 100644 --- a/prql-dotnet/PrqlCompiler.Tests/CompilerTest.cs +++ b/prql-dotnet/PrqlCompiler.Tests/CompilerTest.cs @@ -1,23 +1,23 @@ -using Prql.Compiler; - -namespace Prql.Compiler.Tests; - -sealed public class CompilerTest -{ - [Fact] - public void ToSql_Works() - { - // Arrange - var expected = "SELECT\n *\nFROM\n employees\n\n" + - "-- Generated by PRQL compiler version:x.y.z (https://prql-lang.org)\n"; - var signature = "-- Generated by PRQL compiler"; - expected = expected.Substring(0, expected.IndexOf(signature)); - - // Act - var sqlQuery = PrqlCompiler.ToSql("from employees"); - sqlQuery = sqlQuery.Substring(0, sqlQuery.IndexOf(signature)); - - // Assert - Assert.Equal(expected, sqlQuery); - } -} +using Prql.Compiler; + +namespace Prql.Compiler.Tests; + +sealed public class CompilerTest +{ + [Fact] + public void ToSql_Works() + { + // Arrange + var expected = "SELECT\n *\nFROM\n employees\n\n" + + "-- Generated by PRQL compiler version:x.y.z (https://prql-lang.org)\n"; + var signature = "-- Generated by PRQL compiler"; + expected = expected.Substring(0, expected.IndexOf(signature)); + + // Act + var sqlQuery = PrqlCompiler.ToSql("from employees"); + sqlQuery = sqlQuery.Substring(0, sqlQuery.IndexOf(signature)); + + // Assert + Assert.Equal(expected, sqlQuery); + } +} diff --git a/prql-dotnet/PrqlCompiler.Tests/PrqlCompiler.Tests.csproj b/prql-dotnet/PrqlCompiler.Tests/PrqlCompiler.Tests.csproj index 9fb2ba1630fb..eeddc9523e9a 100644 --- a/prql-dotnet/PrqlCompiler.Tests/PrqlCompiler.Tests.csproj +++ b/prql-dotnet/PrqlCompiler.Tests/PrqlCompiler.Tests.csproj @@ -1,28 +1,28 @@ - - - - net7.0 - enable - enable - - false - - - - - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - - - - - - + + + + net7.0 + enable + enable + + false + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + diff --git a/prql-dotnet/prql-net.sln b/prql-dotnet/prql-net.sln index ce6fc11ae756..76842e4e1189 100644 --- a/prql-dotnet/prql-net.sln +++ b/prql-dotnet/prql-net.sln @@ -1,28 +1,28 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.0.31903.59 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PrqlCompiler", "PrqlCompiler\PrqlCompiler.csproj", "{339EA2A6-23D2-4938-884F-052431AC0674}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PrqlCompiler.Tests", "PrqlCompiler.Tests\PrqlCompiler.Tests.csproj", "{78C1AD08-6FF5-444E-9298-385887ABAA80}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {339EA2A6-23D2-4938-884F-052431AC0674}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {339EA2A6-23D2-4938-884F-052431AC0674}.Debug|Any CPU.Build.0 = Debug|Any CPU - {339EA2A6-23D2-4938-884F-052431AC0674}.Release|Any CPU.ActiveCfg = Release|Any CPU - {339EA2A6-23D2-4938-884F-052431AC0674}.Release|Any CPU.Build.0 = Release|Any CPU - {78C1AD08-6FF5-444E-9298-385887ABAA80}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {78C1AD08-6FF5-444E-9298-385887ABAA80}.Debug|Any CPU.Build.0 = Debug|Any CPU - {78C1AD08-6FF5-444E-9298-385887ABAA80}.Release|Any CPU.ActiveCfg = Release|Any CPU - {78C1AD08-6FF5-444E-9298-385887ABAA80}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PrqlCompiler", "PrqlCompiler\PrqlCompiler.csproj", "{339EA2A6-23D2-4938-884F-052431AC0674}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PrqlCompiler.Tests", "PrqlCompiler.Tests\PrqlCompiler.Tests.csproj", "{78C1AD08-6FF5-444E-9298-385887ABAA80}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {339EA2A6-23D2-4938-884F-052431AC0674}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {339EA2A6-23D2-4938-884F-052431AC0674}.Debug|Any CPU.Build.0 = Debug|Any CPU + {339EA2A6-23D2-4938-884F-052431AC0674}.Release|Any CPU.ActiveCfg = Release|Any CPU + {339EA2A6-23D2-4938-884F-052431AC0674}.Release|Any CPU.Build.0 = Release|Any CPU + {78C1AD08-6FF5-444E-9298-385887ABAA80}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {78C1AD08-6FF5-444E-9298-385887ABAA80}.Debug|Any CPU.Build.0 = Debug|Any CPU + {78C1AD08-6FF5-444E-9298-385887ABAA80}.Release|Any CPU.ActiveCfg = Release|Any CPU + {78C1AD08-6FF5-444E-9298-385887ABAA80}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal From 6846d6a983bff32210b003fc7f2bfda158a1c83a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alja=C5=BE=20Mur=20Er=C5=BEen?= Date: Thu, 23 Feb 2023 15:10:26 +0100 Subject: [PATCH 038/106] build: update prql-lib API (#1941) --- .github/workflows/test-lib.yaml | 28 +++ .gitignore | 4 + .../PrqlCompiler.Tests/CompilerTest.cs | 29 ++-- prql-lib/README.md | 15 +- prql-lib/examples/minimal-c/Makefile | 14 ++ prql-lib/examples/minimal-c/README.md | 7 + prql-lib/examples/minimal-c/main.c | 47 +++++ prql-lib/libprql_lib.h | 58 ++++++- prql-lib/src/lib.rs | 161 +++++++++++++----- 9 files changed, 301 insertions(+), 62 deletions(-) create mode 100644 .github/workflows/test-lib.yaml create mode 100644 prql-lib/examples/minimal-c/Makefile create mode 100644 prql-lib/examples/minimal-c/README.md create mode 100644 prql-lib/examples/minimal-c/main.c diff --git a/.github/workflows/test-lib.yaml b/.github/workflows/test-lib.yaml new file mode 100644 index 000000000000..7937d0066449 --- /dev/null +++ b/.github/workflows/test-lib.yaml @@ -0,0 +1,28 @@ +name: test-lib + +on: + pull_request: + paths: + - "prql-lib/**" + - ".github/workflows/test-lib.yaml" + workflow_call: + +jobs: + test: + runs-on: ubuntu-latest + steps: + - name: 📂 Checkout code + uses: actions/checkout@v3 + - name: 💰 Cache + uses: Swatinem/rust-cache@v2 + with: + key: ${{ inputs.target_option }} + save-if: ${{ github.ref == 'refs/heads/main' }} + - name: Build + uses: richb-hanover/cargo@v1.1.0 + with: + command: build + args: --release -p prql-lib + - name: Run basic C example + working-directory: prql-lib/examples/minimal-c + run: make run diff --git a/.gitignore b/.gitignore index 362d0c3c3c71..51c4f04938a9 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ dist target* +*.out lcov.info @@ -19,3 +20,6 @@ _*.prql **/node_modules/ .task + +prql-dotnet/**/bin +prql-dotnet/**/obj diff --git a/prql-dotnet/PrqlCompiler.Tests/CompilerTest.cs b/prql-dotnet/PrqlCompiler.Tests/CompilerTest.cs index a405d2c75fa5..2505b7a7350e 100644 --- a/prql-dotnet/PrqlCompiler.Tests/CompilerTest.cs +++ b/prql-dotnet/PrqlCompiler.Tests/CompilerTest.cs @@ -4,20 +4,21 @@ namespace Prql.Compiler.Tests; sealed public class CompilerTest { - [Fact] - public void ToSql_Works() - { - // Arrange - var expected = "SELECT\n *\nFROM\n employees\n\n" + - "-- Generated by PRQL compiler version:x.y.z (https://prql-lang.org)\n"; - var signature = "-- Generated by PRQL compiler"; - expected = expected.Substring(0, expected.IndexOf(signature)); + // TODO: update to the new c-api + // [Fact] + // public void ToSql_Works() + // { + // // Arrange + // var expected = "SELECT\n *\nFROM\n employees\n\n" + + // "-- Generated by PRQL compiler version:x.y.z (https://prql-lang.org)\n"; + // var signature = "-- Generated by PRQL compiler"; + // expected = expected.Substring(0, expected.IndexOf(signature)); - // Act - var sqlQuery = PrqlCompiler.ToSql("from employees"); - sqlQuery = sqlQuery.Substring(0, sqlQuery.IndexOf(signature)); + // // Act + // var sqlQuery = PrqlCompiler.ToSql("from employees"); + // sqlQuery = sqlQuery.Substring(0, sqlQuery.IndexOf(signature)); - // Assert - Assert.Equal(expected, sqlQuery); - } + // // Assert + // Assert.Equal(expected, sqlQuery); + // } } diff --git a/prql-lib/README.md b/prql-lib/README.md index ba49ff9fffa5..b56e0cb8e1ba 100644 --- a/prql-lib/README.md +++ b/prql-lib/README.md @@ -1,18 +1,23 @@ -# PRQL library target +# PRQL C library ## Description This module compiles PRQL as a library (both `.a` and `.so` are generated). This allows embedding in languages that support FFI - looking at Golang. -## Usage +## Linking + +See [examples/minimal-c/Makefile](examples/minimal-c/Makefile). Copy the `.a` and `.so` files in a convenient place and add the following compile flags to Go (cgo): `CGO_LDFLAGS="-L/path/to/libprql_lib.a -lprql_lib -pthread -ldl" go build` -## Code +## Examples + +For a minimal example, see +[examples/minimal-c/main.c](examples/minimal-c/main.c). Below is an example from an actual application that is using PRQL in Go. @@ -83,7 +88,9 @@ func ToJSON(prql string) (string, error) { } ``` -## C header file +## Development + +### C header file The C header file `libprql_lib.h` was generated using [cbindgen](https://github.com/eqrion/cbindgen). To generate a new one run: diff --git a/prql-lib/examples/minimal-c/Makefile b/prql-lib/examples/minimal-c/Makefile new file mode 100644 index 000000000000..e1ceb0b6c435 --- /dev/null +++ b/prql-lib/examples/minimal-c/Makefile @@ -0,0 +1,14 @@ +PRQL_PROJECT=../../.. + +build-prql: + cargo build -p prql-lib --release + +build: main.c build-prql + gcc main.c -o main.out \ + -I${PRQL_PROJECT}/prql-lib \ + -L${PRQL_PROJECT}/target/release \ + -l:libprql_lib.a \ + -pthread -ldl -lm + +run: build + ./main.out diff --git a/prql-lib/examples/minimal-c/README.md b/prql-lib/examples/minimal-c/README.md new file mode 100644 index 000000000000..b1762921ca3f --- /dev/null +++ b/prql-lib/examples/minimal-c/README.md @@ -0,0 +1,7 @@ +# Basic C example + +A minimal example for using prql-lib with `gcc` and `make`. + +## How to run + + make run diff --git a/prql-lib/examples/minimal-c/main.c b/prql-lib/examples/minimal-c/main.c new file mode 100644 index 000000000000..62d57dbc78a5 --- /dev/null +++ b/prql-lib/examples/minimal-c/main.c @@ -0,0 +1,47 @@ +#include + +#include + +int main() { + char *prql_query; + prql_query = "from albums | select [album_id, title] | take 3"; + + int res; + char res_buffer[256]; + + // default compile option + res = compile(prql_query, NULL, res_buffer); + printf("%s\n\n", res_buffer); + + // custom compile options + Options opts; + opts.format = false; + opts.signature_comment = false; + opts.target = "sql.mssql"; + res = compile(prql_query, &opts, res_buffer); + printf("%s\n\n", res_buffer); + + // error handling + res = compile("from album | select [album_id] | select [title]", NULL, res_buffer); + if (res == 0) { + printf("success\n\n"); + } + if (res < 0) { + printf("error with code %d!\n%s\n\n", res, res_buffer); + } + + // intermediate results + char* pl_buffer = (char*) malloc(sizeof(char) * 512); + char* rq_buffer = (char*) malloc(sizeof(char) * 512); + + res = prql_to_pl(prql_query, pl_buffer); + printf("PL JSON: %s\n\n", pl_buffer); + + res = pl_to_rq(pl_buffer, rq_buffer); + printf("RQ JSON: %s\n\n", rq_buffer); + + free(pl_buffer); + free(rq_buffer); + + return 0; +} diff --git a/prql-lib/libprql_lib.h b/prql-lib/libprql_lib.h index 8a1ed325e4f0..7667c24dca1b 100644 --- a/prql-lib/libprql_lib.h +++ b/prql-lib/libprql_lib.h @@ -4,15 +4,61 @@ #include /** - * # Safety + * Compilation options + */ +typedef struct Options { + /** + * Pass generated SQL string trough a formatter that splits it + * into multiple lines and prettifies indentation and spacing. + * + * Defaults to true. + */ + bool format; + /** + * Target and dialect to compile to. + */ + char *target; + /** + * Emits the compiler signature as a comment after generated SQL + * + * Defaults to true. + */ + bool signature_comment; +} Options; + +/** + * Compile a PRQL string into a SQL string. + * + * This is a wrapper for: `prql_to_pl`, `pl_to_rq` and `rq_to_sql` without converting to JSON + * between each of the functions. * - * This function is inherently unsafe because it is using C ABI. + * See `Options` struct for available compilation options. */ -int to_sql(const char *query, char *out); +int compile(const char *prql_query, const struct Options *options, char *out); /** - * # Safety + * Build PL AST from a PRQL string + * + * Takes PRQL source buffer and writes PL serialized as JSON to `out` buffer. + * + * Returns 0 on success and a negative number -1 on failure. + */ +int prql_to_pl(const char *prql_query, char *out); + +/** + * Finds variable references, validates functions calls, determines frames and converts PL to RQ. + * + * Takes PL serialized as JSON buffer and writes RQ serialized as JSON to `out` buffer. + * + * Returns 0 on success and a negative number -1 on failure. + */ +int pl_to_rq(const char *pl_json, char *out); + +/** + * Convert RQ AST into an SQL string. + * + * Takes RQ serialized as JSON buffer and writes SQL source to `out` buffer. * - * This function is inherently unsafe because it using C ABI. + * Returns 0 on success and a negative number -1 on failure. */ -int to_json(const char *query, char *out); +int rq_to_sql(const char *rq_json, char *out); diff --git a/prql-lib/src/lib.rs b/prql-lib/src/lib.rs index 2f741b3a40ac..cf0fac70f5e8 100644 --- a/prql-lib/src/lib.rs +++ b/prql-lib/src/lib.rs @@ -3,65 +3,150 @@ extern crate libc; use libc::{c_char, c_int}; -use prql_compiler::Options; -use prql_compiler::{json, prql_to_pl}; +use prql_compiler::ErrorMessages; +use prql_compiler::Target; use std::ffi::CStr; use std::ffi::CString; +use std::str::FromStr; -#[no_mangle] -#[allow(non_snake_case)] +/// Compile a PRQL string into a SQL string. +/// +/// This is a wrapper for: `prql_to_pl`, `pl_to_rq` and `rq_to_sql` without converting to JSON +/// between each of the functions. +/// +/// See `Options` struct for available compilation options. +/// /// # Safety /// -/// This function is inherently unsafe because it is using C ABI. -pub unsafe extern "C" fn to_sql(query: *const c_char, out: *mut c_char) -> c_int { - let prql_query: String = CStr::from_ptr(query).to_string_lossy().into_owned(); +/// This function assumes zero-terminated strings and sufficiently large output buffers. +#[no_mangle] +pub unsafe extern "C" fn compile( + prql_query: *const c_char, + options: *const Options, + out: *mut c_char, +) -> c_int { + let prql_query: String = c_str_to_string(prql_query); - let (isErr, sql_result) = match prql_compiler::compile(&prql_query, &Options::default()) { - Ok(sql_str) => (false, sql_str), - Err(err) => { - //let err_str = format!("{}", err); - (true, err.to_string()) - } - }; + let result = Ok(prql_query.as_str()) + .and_then(prql_compiler::prql_to_pl) + .and_then(prql_compiler::pl_to_rq) + .and_then(|rq| { + prql_compiler::rq_to_sql(rq, &options.as_ref().map(|o| o.into()).unwrap_or_default()) + }) + .map_err(|e| e.composed("", &prql_query, false)); - let copylen = sql_result.len(); - let c_str = CString::new(sql_result).unwrap(); + result_into_c_str(result, out) +} - out.copy_from(c_str.as_ptr(), copylen); - let end_of_string_ptr = out.add(copylen); - *end_of_string_ptr = 0; +/// Build PL AST from a PRQL string +/// +/// Takes PRQL source buffer and writes PL serialized as JSON to `out` buffer. +/// +/// Returns 0 on success and a negative number -1 on failure. +/// +/// # Safety +/// +/// This function assumes zero-terminated strings and sufficiently large output buffers. +#[no_mangle] +pub unsafe extern "C" fn prql_to_pl(prql_query: *const c_char, out: *mut c_char) -> c_int { + let prql_query: String = c_str_to_string(prql_query); - match isErr { - true => -1, - false => 0, - } + let result = Ok(prql_query.as_str()) + .and_then(prql_compiler::prql_to_pl) + .and_then(prql_compiler::json::from_pl); + result_into_c_str(result, out) } +/// Finds variable references, validates functions calls, determines frames and converts PL to RQ. +/// +/// Takes PL serialized as JSON buffer and writes RQ serialized as JSON to `out` buffer. +/// +/// Returns 0 on success and a negative number -1 on failure. +/// +/// # Safety +/// +/// This function assumes zero-terminated strings and sufficiently large output buffers. #[no_mangle] -#[allow(non_snake_case)] +pub unsafe extern "C" fn pl_to_rq(pl_json: *const c_char, out: *mut c_char) -> c_int { + let pl_json: String = c_str_to_string(pl_json); + + let result = Ok(pl_json.as_str()) + .and_then(prql_compiler::json::to_pl) + .and_then(prql_compiler::pl_to_rq) + .and_then(prql_compiler::json::from_rq); + result_into_c_str(result, out) +} + +/// Convert RQ AST into an SQL string. +/// +/// Takes RQ serialized as JSON buffer and writes SQL source to `out` buffer. +/// +/// Returns 0 on success and a negative number -1 on failure. +/// /// # Safety /// -/// This function is inherently unsafe because it using C ABI. -pub unsafe extern "C" fn to_json(query: *const c_char, out: *mut c_char) -> c_int { - let prql_query: String = CStr::from_ptr(query).to_string_lossy().into_owned(); +/// This function assumes zero-terminated strings and sufficiently large output buffers. +#[no_mangle] +pub unsafe extern "C" fn rq_to_sql(rq_json: *const c_char, out: *mut c_char) -> c_int { + let rq_json: String = c_str_to_string(rq_json); - let (isErr, sql_result) = match prql_to_pl(&prql_query).and_then(json::from_pl) { - Ok(sql_str) => (false, sql_str), - Err(err) => { - //let err_str = format!("{}", err); - (true, err.to_string()) - } + let result = Ok(rq_json.as_str()) + .and_then(prql_compiler::json::to_rq) + .and_then(|x| prql_compiler::rq_to_sql(x, &prql_compiler::Options::default())); + result_into_c_str(result, out) +} + +/// Compilation options +#[repr(C)] +pub struct Options { + /// Pass generated SQL string trough a formatter that splits it + /// into multiple lines and prettifies indentation and spacing. + /// + /// Defaults to true. + pub format: bool, + + /// Target and dialect to compile to. + pub target: *mut c_char, + + /// Emits the compiler signature as a comment after generated SQL + /// + /// Defaults to true. + pub signature_comment: bool, +} + +unsafe fn result_into_c_str(result: Result, out: *mut c_char) -> i32 { + let (is_err, string) = match result { + Ok(string) => (false, string), + Err(err) => (true, err.to_string()), }; - let copylen = sql_result.len(); - let c_str = CString::new(sql_result).unwrap(); + let copy_len = string.bytes().len(); + let c_str = CString::new(string).unwrap(); - out.copy_from(c_str.as_ptr(), copylen); - let end_of_string_ptr = out.add(copylen); + out.copy_from(c_str.as_ptr(), copy_len); + let end_of_string_ptr = out.add(copy_len); *end_of_string_ptr = 0; - match isErr { + match is_err { true => -1, false => 0, } } + +unsafe fn c_str_to_string(c_str: *const c_char) -> String { + // inefficient, but simple + CStr::from_ptr(c_str).to_string_lossy().into_owned() +} + +impl From<&Options> for prql_compiler::Options { + fn from(o: &Options) -> Self { + let target = unsafe { c_str_to_string(o.target) }; + let target = Target::from_str(&target).unwrap_or_default(); + + prql_compiler::Options { + format: o.format, + target, + signature_comment: o.signature_comment, + } + } +} From 40f65710c2cb99d5949d9e1e47a69e488e18fc04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alja=C5=BE=20Mur=20Er=C5=BEen?= Date: Thu, 23 Feb 2023 16:34:57 +0100 Subject: [PATCH 039/106] docs: prql-lib docs (#1945) --- prql-lib/libprql_lib.h | 24 ++++++++++++++++++++++-- prql-lib/src/lib.rs | 8 ++++++-- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/prql-lib/libprql_lib.h b/prql-lib/libprql_lib.h index 7667c24dca1b..e605d46b9987 100644 --- a/prql-lib/libprql_lib.h +++ b/prql-lib/libprql_lib.h @@ -33,32 +33,52 @@ typedef struct Options { * between each of the functions. * * See `Options` struct for available compilation options. + * + * # Safety + * + * This function assumes zero-terminated strings and sufficiently large output buffers. */ int compile(const char *prql_query, const struct Options *options, char *out); /** - * Build PL AST from a PRQL string + * Build PL AST from a PRQL string. PL in documented in the + * [prql-compiler Rust crate](https://docs.rs/prql-compiler/latest/prql_compiler/ast/pl). * * Takes PRQL source buffer and writes PL serialized as JSON to `out` buffer. * * Returns 0 on success and a negative number -1 on failure. + * + * # Safety + * + * This function assumes zero-terminated strings and sufficiently large output buffers. */ int prql_to_pl(const char *prql_query, char *out); /** * Finds variable references, validates functions calls, determines frames and converts PL to RQ. + * PL and RQ are documented in the + * [prql-compiler Rust crate](https://docs.rs/prql-compiler/latest/prql_compiler/ast). * * Takes PL serialized as JSON buffer and writes RQ serialized as JSON to `out` buffer. * * Returns 0 on success and a negative number -1 on failure. + * + * # Safety + * + * This function assumes zero-terminated strings and sufficiently large output buffers. */ int pl_to_rq(const char *pl_json, char *out); /** - * Convert RQ AST into an SQL string. + * Convert RQ AST into an SQL string. RQ is documented in the + * [prql-compiler Rust crate](https://docs.rs/prql-compiler/latest/prql_compiler/ast/rq). * * Takes RQ serialized as JSON buffer and writes SQL source to `out` buffer. * * Returns 0 on success and a negative number -1 on failure. + * + * # Safety + * + * This function assumes zero-terminated strings and sufficiently large output buffers. */ int rq_to_sql(const char *rq_json, char *out); diff --git a/prql-lib/src/lib.rs b/prql-lib/src/lib.rs index cf0fac70f5e8..ef00c96d5ccd 100644 --- a/prql-lib/src/lib.rs +++ b/prql-lib/src/lib.rs @@ -38,7 +38,8 @@ pub unsafe extern "C" fn compile( result_into_c_str(result, out) } -/// Build PL AST from a PRQL string +/// Build PL AST from a PRQL string. PL in documented in the +/// [prql-compiler Rust crate](https://docs.rs/prql-compiler/latest/prql_compiler/ast/pl). /// /// Takes PRQL source buffer and writes PL serialized as JSON to `out` buffer. /// @@ -58,6 +59,8 @@ pub unsafe extern "C" fn prql_to_pl(prql_query: *const c_char, out: *mut c_char) } /// Finds variable references, validates functions calls, determines frames and converts PL to RQ. +/// PL and RQ are documented in the +/// [prql-compiler Rust crate](https://docs.rs/prql-compiler/latest/prql_compiler/ast). /// /// Takes PL serialized as JSON buffer and writes RQ serialized as JSON to `out` buffer. /// @@ -77,7 +80,8 @@ pub unsafe extern "C" fn pl_to_rq(pl_json: *const c_char, out: *mut c_char) -> c result_into_c_str(result, out) } -/// Convert RQ AST into an SQL string. +/// Convert RQ AST into an SQL string. RQ is documented in the +/// [prql-compiler Rust crate](https://docs.rs/prql-compiler/latest/prql_compiler/ast/rq). /// /// Takes RQ serialized as JSON buffer and writes SQL source to `out` buffer. /// From 61dc66395143db5ffea0c3f60c142d0adaa43567 Mon Sep 17 00:00:00 2001 From: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Date: Thu, 23 Feb 2023 08:28:30 -0800 Subject: [PATCH 040/106] fix: Panic with multiple terms after a `from` transform (#1928) --- prql-compiler/src/semantic/resolver.rs | 12 ++++++++++- prql-compiler/src/test.rs | 29 ++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/prql-compiler/src/semantic/resolver.rs b/prql-compiler/src/semantic/resolver.rs index dcc68bdf1b62..b0cd8af29b40 100644 --- a/prql-compiler/src/semantic/resolver.rs +++ b/prql-compiler/src/semantic/resolver.rs @@ -409,7 +409,17 @@ impl Resolver { closure.args.len(), closure.params.len() ); - let enough_args = closure.args.len() >= closure.params.len(); + + if closure.args.len() > closure.params.len() { + return Err(Error::new_simple(format!( + "Too many arguments to function `{}`", + closure.as_debug_name() + )) + .with_span(span) + .into()); + } + + let enough_args = closure.args.len() == closure.params.len(); let mut r = if enough_args { // push the env diff --git a/prql-compiler/src/test.rs b/prql-compiler/src/test.rs index 170c8cd42f45..fbe73829bf12 100644 --- a/prql-compiler/src/test.rs +++ b/prql-compiler/src/test.rs @@ -2883,6 +2883,35 @@ fn test_closures_and_pipelines() { /// Start testing some error messages. This can hopefully be expanded significantly. // It's also fine to put errors by the things that they're testing. fn test_errors() { + assert_display_snapshot!(compile(r###" + func addadd a b -> a + b + + from x + derive y = (addadd 4 5 6) + "###).unwrap_err(), + @r###" + Error: + ╭─[:5:12] + │ + 5 │ derive y = (addadd 4 5 6) + · ─────────┬──────── + · ╰────────── Too many arguments to function `addadd` + ───╯ + "###); + + assert_display_snapshot!(compile(r###" + from a select b + "###).unwrap_err(), + @r###" + Error: + ╭─[:2:5] + │ + 2 │ from a select b + · ───────┬─────── + · ╰───────── Too many arguments to function `from` + ───╯ + "###); + assert_display_snapshot!(compile(r###" from x select a From 473170251d1482aa17f7534b4d98d835432bc8c7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 23 Feb 2023 17:31:19 +0100 Subject: [PATCH 041/106] chore: bump chumsky from 0.8.0 to 0.9.0 (#1723) --- Cargo.lock | 15 +++------------ prql-compiler/Cargo.toml | 4 +++- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 754ecb3bc58f..013e31762293 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,15 +17,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" -[[package]] -name = "ahash" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8fd72866655d1904d6b0997d0b07ba561047d070fbe29de039031c641b61217" -dependencies = [ - "const-random", -] - [[package]] name = "ahash" version = "0.7.6" @@ -455,11 +446,11 @@ dependencies = [ [[package]] name = "chumsky" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d02796e4586c6c41aeb68eae9bfb4558a522c35f1430c14b40136c3706e09e4" +checksum = "c4d619fba796986dd538d82660b76e0b9756c6e19b2e4d4559ba5a57f9f00810" dependencies = [ - "ahash 0.3.8", + "hashbrown 0.12.3", ] [[package]] diff --git a/prql-compiler/Cargo.toml b/prql-compiler/Cargo.toml index cd74ecc67c24..9323ff5f59d3 100644 --- a/prql-compiler/Cargo.toml +++ b/prql-compiler/Cargo.toml @@ -15,7 +15,9 @@ metadata.msrv = "1.65.0" [dependencies] anyhow = {version = "1.0.57", features = ["backtrace"]} ariadne = "0.1.5" -chumsky = "0.8.0" +# We don't include the `spill-stack` feature, since it causes builds in GHA to +# fail. If that no longer happens, we can re-enable it. +chumsky = {version = "0.9.0", features = ["ahash", "std"], default-features = false } csv = "1.2.0" enum-as-inner = "0.5.0" itertools = "0.10.3" From de474182a23ccc7de70b417692228905e717a697 Mon Sep 17 00:00:00 2001 From: Jonathan Date: Thu, 23 Feb 2023 18:45:05 +0100 Subject: [PATCH 042/106] build: Fix .NET bindings (#1946) * Update CompilerTest.cs * Update README.md * Update PrqlCompilerOptions.cs * Update PrqlCompiler.cs --- .../PrqlCompiler.Tests/CompilerTest.cs | 30 +++++++------- prql-dotnet/PrqlCompiler/PrqlCompiler.cs | 41 ++++--------------- .../PrqlCompiler/PrqlCompilerOptions.cs | 3 ++ prql-dotnet/README.md | 7 +++- 4 files changed, 33 insertions(+), 48 deletions(-) diff --git a/prql-dotnet/PrqlCompiler.Tests/CompilerTest.cs b/prql-dotnet/PrqlCompiler.Tests/CompilerTest.cs index 2505b7a7350e..3b07fb20b183 100644 --- a/prql-dotnet/PrqlCompiler.Tests/CompilerTest.cs +++ b/prql-dotnet/PrqlCompiler.Tests/CompilerTest.cs @@ -4,21 +4,21 @@ namespace Prql.Compiler.Tests; sealed public class CompilerTest { - // TODO: update to the new c-api - // [Fact] - // public void ToSql_Works() - // { - // // Arrange - // var expected = "SELECT\n *\nFROM\n employees\n\n" + - // "-- Generated by PRQL compiler version:x.y.z (https://prql-lang.org)\n"; - // var signature = "-- Generated by PRQL compiler"; - // expected = expected.Substring(0, expected.IndexOf(signature)); + [Fact] + public void ToCompile_Works() + { + // Arrange + var expected = "SELECT * FROM employees"; - // // Act - // var sqlQuery = PrqlCompiler.ToSql("from employees"); - // sqlQuery = sqlQuery.Substring(0, sqlQuery.IndexOf(signature)); + // Act + var options = new PrqlCompilerOptions + { + Format = false, + SignatureComment = false, + }; + var sqlQuery = PrqlCompiler.Compile("from employees", options); - // // Assert - // Assert.Equal(expected, sqlQuery); - // } + // Assert + Assert.Equal(expected, sqlQuery); + } } diff --git a/prql-dotnet/PrqlCompiler/PrqlCompiler.cs b/prql-dotnet/PrqlCompiler/PrqlCompiler.cs index 04843d088d05..500fb4c7ea70 100644 --- a/prql-dotnet/PrqlCompiler/PrqlCompiler.cs +++ b/prql-dotnet/PrqlCompiler/PrqlCompiler.cs @@ -24,7 +24,9 @@ public static string Compile(string prqlQuery) throw new ArgumentException(nameof(prqlQuery)); } - return CompileExtern(prqlQuery); + var options = new PrqlCompilerOptions(); + + return Compile(prqlQuery, options); } /// @@ -43,30 +45,8 @@ public static string Compile(string prqlQuery, PrqlCompilerOptions options) throw new ArgumentException(nameof(prqlQuery)); } - if (options == null) - { - throw new ArgumentNullException(nameof(options)); - } - - return CompileExtern(prqlQuery); - } - - /// - /// Compile a PRQL string into a JSON string. - /// - /// A PRQL query. - /// JSON. - /// is null or empty. - /// cannot be compiled. - public static string ToJson(string prqlQuery) - { - if (string.IsNullOrEmpty(prqlQuery)) - { - throw new ArgumentException(nameof(prqlQuery)); - } - byte[] bytes = new byte[1024]; - if (ToJsonExtern(prqlQuery, bytes) != 0) + if (CompileExtern(prqlQuery, ref options, bytes) != 0) { throw new FormatException("Could not compile query."); } @@ -77,13 +57,13 @@ public static string ToJson(string prqlQuery) } /// - /// Compile a PRQL string into a SQL query. + /// Compile a PRQL string into a JSON string. /// /// A PRQL query. - /// SQL query. + /// JSON. /// is null or empty. /// cannot be compiled. - public static string ToSql(string prqlQuery) + public static string ToJson(string prqlQuery) { if (string.IsNullOrEmpty(prqlQuery)) { @@ -91,7 +71,7 @@ public static string ToSql(string prqlQuery) } byte[] bytes = new byte[1024]; - if (ToSqlExtern(prqlQuery, bytes) != 0) + if (ToJsonExtern(prqlQuery, bytes) != 0) { throw new FormatException("Could not compile query."); } @@ -102,12 +82,9 @@ public static string ToSql(string prqlQuery) } [DllImport("libprql_lib", EntryPoint = "compile")] - private static extern string CompileExtern(string prql_query); + private static extern int CompileExtern(string prql_query, ref PrqlCompilerOptions options, byte[] sql_query); [DllImport("libprql_lib", EntryPoint = "to_json")] private static extern int ToJsonExtern(string prql_query, byte[] json); - - [DllImport("libprql_lib", EntryPoint = "to_sql")] - private static extern int ToSqlExtern(string prql_query, byte[] sql_query); } } diff --git a/prql-dotnet/PrqlCompiler/PrqlCompilerOptions.cs b/prql-dotnet/PrqlCompiler/PrqlCompilerOptions.cs index 0dc48e2169af..4b827e91073f 100644 --- a/prql-dotnet/PrqlCompiler/PrqlCompilerOptions.cs +++ b/prql-dotnet/PrqlCompiler/PrqlCompilerOptions.cs @@ -1,8 +1,11 @@ +using System.Runtime.InteropServices; + namespace Prql.Compiler { /// /// Compilation options for SQL backend of the compiler. /// + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] public class PrqlCompilerOptions { /// diff --git a/prql-dotnet/README.md b/prql-dotnet/README.md index 7b81f6cfdd23..6021e017b360 100644 --- a/prql-dotnet/README.md +++ b/prql-dotnet/README.md @@ -22,7 +22,12 @@ The `libprql_lib` library gets dynamically imported at runtime. ```csharp using Prql.Compiler; -var sql = PrqlCompiler.ToSql("from employees"); +var options = new PrqlCompilerOptions +{ + Format = false, + SignatureComment = false, +}; +var sql = PrqlCompiler.Compile("from employees", options); Console.WriteLine(sql); ``` From 7fec008a04847fdb391b76750fea97e6fefd6eed Mon Sep 17 00:00:00 2001 From: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Date: Thu, 23 Feb 2023 10:18:01 -0800 Subject: [PATCH 043/106] test: Disable PHP tests until aligned with `prql-lib` (#1947) Just to ensure the build stays green as discussed in https://discord.com/channels/936728116712316989/1078360136978022510. Thanks to @aljazerzen & @vanillajonathan for the changes. --- .github/workflows/test-php.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/test-php.yaml b/.github/workflows/test-php.yaml index af2b19202350..97f1e72bd1be 100644 --- a/.github/workflows/test-php.yaml +++ b/.github/workflows/test-php.yaml @@ -38,5 +38,7 @@ jobs: args: --working-dir=prql-php php_extensions: FFI - name: 🧪 Run tests using PHPUnit + # TODO: enable when aligned with https://github.com/PRQL/prql/pull/1941 + if: false run: vendor/bin/phpunit tests working-directory: prql-php From e3988c809aaadab83e8deb6de8bbbd4188817252 Mon Sep 17 00:00:00 2001 From: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Date: Thu, 23 Feb 2023 12:06:49 -0800 Subject: [PATCH 044/106] chore: Add `testng` to typos exclusion (#1948) Required in https://github.com/PRQL/prql/pull/1929#issuecomment-1441671378 --- _typos.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/_typos.toml b/_typos.toml index 1480bde0ec83..2038bb357644 100644 --- a/_typos.toml +++ b/_typos.toml @@ -5,3 +5,7 @@ extend-exclude = [ "website/themes/prql-theme/static/plugins/bootstrap", "website/themes/prql-theme/static/plugins/highlight/highlight.min.js", ] + +[default.extend-words] +# Java test framework +testng = "testng" From b52df6f0478e9c1d51e11df16f7792347dfae337 Mon Sep 17 00:00:00 2001 From: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Date: Thu, 23 Feb 2023 19:50:20 -0800 Subject: [PATCH 045/106] docs: Add a note re reverting (#1952) --- book/src/contributing/development.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/book/src/contributing/development.md b/book/src/contributing/development.md index cca2d9145743..2f482a58f65d 100644 --- a/book/src/contributing/development.md +++ b/book/src/contributing/development.md @@ -182,7 +182,9 @@ change! - We should revert quickly if the impact of a PR turns out not to be consistent with our expectations, or there isn't as much consensus on a decision as we had hoped. It's very easy to revert code and then re-revert when we've - resolved the issue; it's a sign of moving quickly. + resolved the issue; it's a sign of moving quickly. Other options which resolve + the build immediately are also fine, such as commenting out an incorrect test + or adding a quick fix for the underlying issue. ## Components of PRQL From 6388d7c05dea77908c95e55a42018d699ba75212 Mon Sep 17 00:00:00 2001 From: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Date: Thu, 23 Feb 2023 20:12:02 -0800 Subject: [PATCH 046/106] revert: re-revert loop (#1951) * revert: re-revert loop Re-reverts #1899 & #1901 * fix book link --- .github/workflows/test-all.yaml | 6 + .github/workflows/test-dotnet.yaml | 1 + .github/workflows/test-java.yaml | 1 + .github/workflows/test-lib.yaml | 6 + .github/workflows/test-php.yaml | 1 + CHANGELOG.md | 2 + book/README.md | 2 +- book/book.toml | 2 +- book/src/SUMMARY.md | 4 +- book/src/integrations/jupyter.md | 2 +- book/src/integrations/rill.md | 2 +- book/src/internals/name-resolving.md | 2 +- book/src/language-features/README.md | 1 - .../README.md} | 4 +- .../standard-library/from-text.md | 63 ++ .../standard-library/loop.md | 50 ++ book/src/syntax.md | 2 +- book/src/transforms/from_text.md | 61 -- .../README-0.prql} | 0 .../standard-library/from-text-0.prql} | 0 .../standard-library/from-text-1.prql} | 0 .../standard-library/from-text-2.prql} | 0 .../standard-library/loop-0.prql | 7 + .../snapshot__@examples__cte-0.prql.snap | 22 +- ...snapshot__@examples__employees-0.prql.snap | 21 +- ...snapshot__@examples__employees-1.prql.snap | 27 +- ...snapshot__@examples__employees-2.prql.snap | 23 +- ...snapshot__@examples__employees-3.prql.snap | 11 +- .../snapshot__@examples__misc-0.prql.snap | 15 +- ...snapshot__@examples__variables-0.prql.snap | 3 +- ...snapshot__@examples__variables-1.prql.snap | 9 +- .../snapshot__@introduction-0.prql.snap | 5 +- ...__@language-features__distinct-2.prql.snap | 3 +- ..._@language-features__s-strings-3.prql.snap | 13 +- ...res__standard-library__README-0.prql.snap} | 3 +- ...__standard-library__from-text-0.prql.snap} | 6 +- ...__standard-library__from-text-1.prql.snap} | 2 +- ...__standard-library__from-text-2.prql.snap} | 2 +- ...atures__standard-library__loop-0.prql.snap | 34 + .../snapshot__@queries__pipelines-2.prql.snap | 9 +- .../snapshot__@queries__variables-0.prql.snap | 4 +- .../snapshots/snapshot__@syntax-5.prql.snap | 3 +- .../snapshot__@transforms__group-2.prql.snap | 3 +- .../snapshot__@transforms__sort-3.prql.snap | 17 +- .../snapshot__@transforms__sort-5.prql.snap | 7 +- .../snapshot__@transforms__window-4.prql.snap | 3 +- ...res__standard-library__README-0.prql.snap} | 0 ...__standard-library__from-text-0.prql.snap} | 0 ...__standard-library__from-text-1.prql.snap} | 0 ...__standard-library__from-text-2.prql.snap} | 0 ...atures__standard-library__loop-0.prql.snap | 12 + prql-compiler/src/ast/pl/expr.rs | 1 + prql-compiler/src/ast/pl/fold.rs | 1 + prql-compiler/src/ast/pl/types.rs | 8 +- prql-compiler/src/ast/rq/fold.rs | 1 + prql-compiler/src/ast/rq/transform.rs | 1 + prql-compiler/src/semantic/lowering.rs | 33 +- prql-compiler/src/semantic/std.prql | 1 + prql-compiler/src/semantic/transforms.rs | 8 + .../prql_compiler__test__prql_to_sql_2.snap | 3 +- prql-compiler/src/sql/anchor.rs | 87 ++- prql-compiler/src/sql/context.rs | 61 +- prql-compiler/src/sql/gen_expr.rs | 75 +- prql-compiler/src/sql/gen_query.rs | 687 ++++++++++-------- prql-compiler/src/sql/mod.rs | 35 + prql-compiler/src/sql/preprocess.rs | 68 +- ...query__test__variable_after_aggregate.snap | 3 +- prql-compiler/src/test.rs | 291 +++++--- .../tests/integration/queries/loop.prql | 7 + .../integration__tests__test@loop.prql.snap | 12 + website/content/_index.md | 2 +- 71 files changed, 1119 insertions(+), 742 deletions(-) rename book/src/language-features/{standard-library.md => standard-library/README.md} (92%) create mode 100644 book/src/language-features/standard-library/from-text.md create mode 100644 book/src/language-features/standard-library/loop.md rename book/tests/prql/language-features/{standard-library-0.prql => standard-library/README-0.prql} (100%) rename book/tests/prql/{transforms/from_text-0.prql => language-features/standard-library/from-text-0.prql} (100%) rename book/tests/prql/{transforms/from_text-1.prql => language-features/standard-library/from-text-1.prql} (100%) rename book/tests/prql/{transforms/from_text-2.prql => language-features/standard-library/from-text-2.prql} (100%) create mode 100644 book/tests/prql/language-features/standard-library/loop-0.prql rename book/tests/snapshots/{snapshot__@language-features__standard-library-0.prql.snap => snapshot__@language-features__standard-library__README-0.prql.snap} (84%) rename book/tests/snapshots/{snapshot__@transforms__from_text-0.prql.snap => snapshot__@language-features__standard-library__from-text-0.prql.snap} (73%) rename book/tests/snapshots/{snapshot__@transforms__from_text-1.prql.snap => snapshot__@language-features__standard-library__from-text-1.prql.snap} (90%) rename book/tests/snapshots/{snapshot__@transforms__from_text-2.prql.snap => snapshot__@language-features__standard-library__from-text-2.prql.snap} (91%) create mode 100644 book/tests/snapshots/snapshot__@language-features__standard-library__loop-0.prql.snap rename book/tests/snapshots/{snapshot__tests__prql__language-features__standard-library-0.prql.snap => snapshot__tests__prql__language-features__standard-library__README-0.prql.snap} (100%) rename book/tests/snapshots/{snapshot__tests__prql__transforms__from_text-0.prql.snap => snapshot__tests__prql__language-features__standard-library__from-text-0.prql.snap} (100%) rename book/tests/snapshots/{snapshot__tests__prql__transforms__from_text-1.prql.snap => snapshot__tests__prql__language-features__standard-library__from-text-1.prql.snap} (100%) rename book/tests/snapshots/{snapshot__tests__prql__transforms__from_text-2.prql.snap => snapshot__tests__prql__language-features__standard-library__from-text-2.prql.snap} (100%) create mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__standard-library__loop-0.prql.snap create mode 100644 prql-compiler/tests/integration/queries/loop.prql create mode 100644 prql-compiler/tests/integration/snapshots/integration__tests__test@loop.prql.snap diff --git a/.github/workflows/test-all.yaml b/.github/workflows/test-all.yaml index 065698e9baca..34ea805c7de4 100644 --- a/.github/workflows/test-all.yaml +++ b/.github/workflows/test-all.yaml @@ -47,6 +47,12 @@ jobs: test-elixir: uses: ./.github/workflows/test-elixir.yaml + test-dotnet: + uses: ./.github/workflows/test-dotnet.yaml + + test-lib: + uses: ./.github/workflows/test-lib.yaml + measure-code-cov: # Currently disabled due to https://github.com/actions-rs/tarpaulin/issues/21 if: false diff --git a/.github/workflows/test-dotnet.yaml b/.github/workflows/test-dotnet.yaml index eae9601d8d02..402f9a7046f9 100644 --- a/.github/workflows/test-dotnet.yaml +++ b/.github/workflows/test-dotnet.yaml @@ -4,6 +4,7 @@ on: pull_request: paths: - "prql-dotnet/**" + - "prql-lib/**" - ".github/workflows/test-dotnet.yaml" workflow_call: diff --git a/.github/workflows/test-java.yaml b/.github/workflows/test-java.yaml index 780c87f3da28..ed3a8754510f 100644 --- a/.github/workflows/test-java.yaml +++ b/.github/workflows/test-java.yaml @@ -4,6 +4,7 @@ on: pull_request: paths: - "prql-java/**" + - "prql-lib/**" - ".github/workflows/test-java.yaml" workflow_call: diff --git a/.github/workflows/test-lib.yaml b/.github/workflows/test-lib.yaml index 7937d0066449..7bd0f8d36c19 100644 --- a/.github/workflows/test-lib.yaml +++ b/.github/workflows/test-lib.yaml @@ -3,10 +3,16 @@ name: test-lib on: pull_request: paths: + # We also run the tests for the libraries that depend on this, from their workflow files. - "prql-lib/**" - ".github/workflows/test-lib.yaml" workflow_call: +concurrency: + # See notes in `pull-request.yaml` + group: ${{ github.workflow }}-${{ github.ref }}-lib + cancel-in-progress: true + jobs: test: runs-on: ubuntu-latest diff --git a/.github/workflows/test-php.yaml b/.github/workflows/test-php.yaml index 97f1e72bd1be..608b5d20e114 100644 --- a/.github/workflows/test-php.yaml +++ b/.github/workflows/test-php.yaml @@ -4,6 +4,7 @@ on: pull_request: paths: - "prql-php/**" + - "prql-lib/**" - ".github/workflows/test-php.yaml" workflow_call: diff --git a/CHANGELOG.md b/CHANGELOG.md index f7780ba05e38..47a1ba3bf508 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ **Features**: +- `loop`, which translates to `WITH RECURSIVE` (#1642, @aljazerzen) + **Fixes**: - `prqlc compile` returns a non-zero exit code for invalid queries. (@max-sixty, diff --git a/book/README.md b/book/README.md index ec088b512dcb..57b803d93865 100644 --- a/book/README.md +++ b/book/README.md @@ -1,4 +1,4 @@ -# PRQL Language Book +# PRQL language book These docs serve as a language book, for users of the language. They should be friendly & accessible, at a minimum to those who understand basic SQL. diff --git a/book/book.toml b/book/book.toml index 6849dde897c5..1ce7a8769425 100644 --- a/book/book.toml +++ b/book/book.toml @@ -2,7 +2,7 @@ description = "Modern language for transforming data — a simple, powerful, pipelined SQL replacement" language = "en" multilingual = false -title = "PRQL Language Book" +title = "PRQL language book" [output.html] additional-css = ["comparison-table.css", "mdbook-admonish.css"] diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md index 153e70bdb090..cc27566b74a2 100644 --- a/book/src/SUMMARY.md +++ b/book/src/SUMMARY.md @@ -36,7 +36,9 @@ - [Ranges](./language-features/ranges.md) - [Regex](./language-features/regex.md) - - [Stdlib](./language-features/standard-library.md) + - [Standard library](./language-features/standard-library/README.md) + - [From text](./language-features/standard-library/from-text.md) + - [Loop](./language-features/standard-library/loop.md) - [Strings](./language-features/strings.md) - [S-strings](./language-features/s-strings.md) - [F-strings](./language-features/f-strings.md) diff --git a/book/src/integrations/jupyter.md b/book/src/integrations/jupyter.md index 176a47ac11ad..7b0bdd3c063d 100644 --- a/book/src/integrations/jupyter.md +++ b/book/src/integrations/jupyter.md @@ -24,7 +24,7 @@ could to go! We bundle in `IPython` and `pandas`, though you'll need to install pip install pyprql ``` -### Set Up +### Set up Open up either an `IPython` terminal or `Jupyter` notebook. First, we need to load the extension and connect to a database. diff --git a/book/src/integrations/rill.md b/book/src/integrations/rill.md index 950e0b5fb50d..0e2f4729e32e 100644 --- a/book/src/integrations/rill.md +++ b/book/src/integrations/rill.md @@ -1,5 +1,5 @@ # Rill PRQL has had some work to integrate with Rill. See the -[Rill Issues](https://github.com/PRQL/prql/issues?q=is%3Aissue+rill) for more +[Rill ssues](https://github.com/PRQL/prql/issues?q=is%3Aissue+rill) for more details. diff --git a/book/src/internals/name-resolving.md b/book/src/internals/name-resolving.md index 74b590e93a14..78a153358959 100644 --- a/book/src/internals/name-resolving.md +++ b/book/src/internals/name-resolving.md @@ -50,7 +50,7 @@ three things can happen: ## Translating to SQL -When translating into a SQL statement which references only one table, there is +When translating into an SQL statement which references only one table, there is no need to reference column names with table prefix. ```prql diff --git a/book/src/language-features/README.md b/book/src/language-features/README.md index c03c67d19706..45b07178b7d4 100644 --- a/book/src/language-features/README.md +++ b/book/src/language-features/README.md @@ -11,7 +11,6 @@ language. | Null handling | [Handle `NULL` values](./null.md) | | Ranges | [Syntax for all forms of ranges](./ranges.md) | | Regex | [Handle regular expressions](./regex.md) | -| Stdlib | [PRQL's "builtin" set of functions](./standard-library.md) | | Strings | [Rules for creating strings](./strings.md) | | S-strings | [Insert SQL directly into a query with an S-string](./s-strings.md) | | F-strings | [Combine several column's data with F-strings](./f-strings.md) | diff --git a/book/src/language-features/standard-library.md b/book/src/language-features/standard-library/README.md similarity index 92% rename from book/src/language-features/standard-library.md rename to book/src/language-features/standard-library/README.md index 220565d5cf3d..d4dbec6dbf5f 100644 --- a/book/src/language-features/standard-library.md +++ b/book/src/language-features/standard-library/README.md @@ -1,4 +1,4 @@ -# Standard Library +# Standard library The standard library currently contains commonly used functions that are used in SQL. It's not yet as broad as we'd like, and we're very open to expanding it. @@ -17,7 +17,7 @@ Here's the source of the current [PRQL `std`](https://github.com/PRQL/prql/blob/main/prql-compiler/src/semantic/std.prql): ```prql_no_test -{{#include ../../../prql-compiler/src/semantic/std.prql}} +{{#include ../../../../prql-compiler/src/semantic/std.prql}} ``` And a couple of examples: diff --git a/book/src/language-features/standard-library/from-text.md b/book/src/language-features/standard-library/from-text.md new file mode 100644 index 000000000000..29229f6db0ef --- /dev/null +++ b/book/src/language-features/standard-library/from-text.md @@ -0,0 +1,63 @@ +# From text + +It's often useful to make a small table inline, for example when exploring how a +database will evaluate an expression, or to have a small lookup table inline. +This can be quite verbose in SQL. + +PRQL uses `from_text` for this. + +It accepts a few formats: + +- `format:csv` parses CSV (default), +- `format:json` parses either: + - an array of objects each of which represents a row, or + - an object with fields `columns` & `data`, where `columns` take an array of + column names and `data` takes an array of arrays. + +```prql +from_text """ +a,b,c +1,2,3 +4,5,6 +""" +derive [ + d = b + c, + answer = 20 * 2 + 2, +] +``` + +An example of adding a small lookup table: + +```prql +let temp_format_lookup = from_text format:csv """ +country_code,format +uk,C +us,F +lr,F +de,C +""" + +from temperatures +join temp_format_lookup [==country_code] +``` + +And JSON: + +```prql +let x = from_text format:json """{ + "columns": ["a", "b", "c"], + "data": [ + [1, "x", false], + [4, "y", null] + ] +}""" + +let y = from_text format:json """ + [ + {"a": 1, "m": "5"}, + {"a": 4, "n": "6"} + ] +""" + +from x | join y [==a] +``` diff --git a/book/src/language-features/standard-library/loop.md b/book/src/language-features/standard-library/loop.md new file mode 100644 index 000000000000..97f462a8b5cc --- /dev/null +++ b/book/src/language-features/standard-library/loop.md @@ -0,0 +1,50 @@ +# Loop + +> _experimental_ + +```prql_no_test +loop {step_function} {initial_relation} +``` + +Iteratively applies `step` function to `initial` relation until the `step` +returns an empty table. Returns a relation that contains rows of initial +relation and all intermediate relations. + +This behavior could be expressed with following pseudo-code: + +``` +def loop(step, initial): + result = [] + current = initial + while current is not empty: + result = append(result, current) + current = step(current) + + return result +``` + +## Examples + +```prql +from_text format:json '[{"n": 1 }]' +loop ( + filter n<4 + select n = n+1 +) + +# returns [1, 2, 3, 4] +``` + +```admonish +Behavior of WITH RECURSIVE may depend on database configuration (MySQL). +prql-compiler assumes behavior described by +[Postgres documentation](https://www.postgresql.org/docs/15/queries-with.html#QUERIES-WITH-RECURSIVE) +and will not produce correct results for +[alternative configurations of MySQL](https://dev.mysql.com/doc/refman/8.0/en/with.html#common-table-expressions-recursive). +``` + +```admonish +Currently, `loop` may produce references to the recursive CTE in sub-queries, +which is not supported by some database engines (SQLite). For now, we suggest you keep step +functions simple enough to fit into a single SELECT statement. +``` diff --git a/book/src/syntax.md b/book/src/syntax.md index 3c0afc5dd5b7..b23537228f4c 100644 --- a/book/src/syntax.md +++ b/book/src/syntax.md @@ -166,7 +166,7 @@ sort (-distance) sort [-distance] ``` -## Inner Transforms +## Inner transforms Parentheses are also used for transforms (such as `group` and `window`) that pass their result to an "inner transform". The example below applies the diff --git a/book/src/transforms/from_text.md b/book/src/transforms/from_text.md index 0a9b51160ca7..a05d2a4b011d 100644 --- a/book/src/transforms/from_text.md +++ b/book/src/transforms/from_text.md @@ -1,62 +1 @@ # From Text - -It's often useful to make a small table inline, for example when exploring how a -database will evaluate an expression, or to have a small lookup table inline. -This can be quite verbose in SQL. - -PRQL uses `from_text` for this. - -It accepts a few formats: - -- `format:csv`; also the default, for CSV. -- `format:json` for either: - - A list of dicts, - - or a schema of `columns` & `data>`. - -```prql -from_text """ -a,b,c -1,2,3 -4,5,6 -""" -derive [ - d = b + c, - answer = 20 * 2 + 2, -] -``` - -An example of adding a small lookup table: - -```prql -let temp_format_lookup = from_text format:csv """ -country_code,format -uk,C -us,F -lr,F -de,C -""" - -from temperatures -join temp_format_lookup [==country_code] -``` - -And JSON: - -```prql -let x = from_text format:json """{ - "columns": ["a", "b", "c"], - "data": [ - [1, "x", false], - [4, "y", null] - ] -}""" - -let y = from_text format:json """ - [ - {"a": 1, "m": "5"}, - {"a": 4, "n": "6"} - ] -""" - -from x | join y [==a] -``` diff --git a/book/tests/prql/language-features/standard-library-0.prql b/book/tests/prql/language-features/standard-library/README-0.prql similarity index 100% rename from book/tests/prql/language-features/standard-library-0.prql rename to book/tests/prql/language-features/standard-library/README-0.prql diff --git a/book/tests/prql/transforms/from_text-0.prql b/book/tests/prql/language-features/standard-library/from-text-0.prql similarity index 100% rename from book/tests/prql/transforms/from_text-0.prql rename to book/tests/prql/language-features/standard-library/from-text-0.prql diff --git a/book/tests/prql/transforms/from_text-1.prql b/book/tests/prql/language-features/standard-library/from-text-1.prql similarity index 100% rename from book/tests/prql/transforms/from_text-1.prql rename to book/tests/prql/language-features/standard-library/from-text-1.prql diff --git a/book/tests/prql/transforms/from_text-2.prql b/book/tests/prql/language-features/standard-library/from-text-2.prql similarity index 100% rename from book/tests/prql/transforms/from_text-2.prql rename to book/tests/prql/language-features/standard-library/from-text-2.prql diff --git a/book/tests/prql/language-features/standard-library/loop-0.prql b/book/tests/prql/language-features/standard-library/loop-0.prql new file mode 100644 index 000000000000..5dccfdba14ae --- /dev/null +++ b/book/tests/prql/language-features/standard-library/loop-0.prql @@ -0,0 +1,7 @@ +from_text format:json '[{"n": 1 }]' +loop ( + filter n<4 + select n = n+1 +) + +# returns [1, 2, 3, 4] diff --git a/book/tests/snapshots/snapshot__@examples__cte-0.prql.snap b/book/tests/snapshots/snapshot__@examples__cte-0.prql.snap index 5e55e6c27d2b..36a99fd31e3f 100644 --- a/book/tests/snapshots/snapshot__@examples__cte-0.prql.snap +++ b/book/tests/snapshots/snapshot__@examples__cte-0.prql.snap @@ -1,18 +1,9 @@ --- source: book/tests/snapshot.rs -expression: "table newest_employees = (\n from employees\n sort tenure\n take 50\n)\n\ntable average_salaries = (\n from salaries\n group country (\n aggregate average_country_salary = (average salary)\n )\n)\n\nfrom newest_employees\njoin average_salaries [==country]\nselect [name, salary, average_country_salary]\n" +expression: "let newest_employees = (\n from employees\n sort tenure\n take 50\n)\n\nlet average_salaries = (\n from salaries\n group country (\n aggregate average_country_salary = (average salary)\n )\n)\n\nfrom newest_employees\njoin average_salaries [==country]\nselect [name, salary, average_country_salary]\n" input_file: book/tests/prql/examples/cte-0.prql --- -WITH average_salaries AS ( - SELECT - country, - AVG(salary) AS average_country_salary - FROM - salaries - GROUP BY - country -), -newest_employees AS ( +WITH newest_employees AS ( SELECT * FROM @@ -21,6 +12,14 @@ newest_employees AS ( tenure LIMIT 50 +), average_salaries AS ( + SELECT + country, + AVG(salary) AS average_country_salary + FROM + salaries + GROUP BY + country ) SELECT newest_employees.name, @@ -29,3 +28,4 @@ SELECT FROM newest_employees JOIN average_salaries ON newest_employees.country = average_salaries.country + diff --git a/book/tests/snapshots/snapshot__@examples__employees-0.prql.snap b/book/tests/snapshots/snapshot__@examples__employees-0.prql.snap index 2ed2d4eba75e..47650f37675d 100644 --- a/book/tests/snapshots/snapshot__@examples__employees-0.prql.snap +++ b/book/tests/snapshots/snapshot__@examples__employees-0.prql.snap @@ -3,7 +3,7 @@ source: book/tests/snapshot.rs expression: "from salaries\ngroup [emp_no] (\n aggregate [emp_salary = average salary]\n)\njoin t=titles [==emp_no]\njoin dept_emp side:left [==emp_no]\ngroup [dept_emp.dept_no, t.title] (\n aggregate [avg_salary = average emp_salary]\n)\njoin departments [==dept_no]\nselect [dept_name, title, avg_salary]\n" input_file: book/tests/prql/examples/employees-0.prql --- -WITH table_1 AS ( +WITH table_3 AS ( SELECT AVG(salary) AS _expr_0, emp_no @@ -12,23 +12,24 @@ WITH table_1 AS ( GROUP BY emp_no ), -table_2 AS ( +table_1 AS ( SELECT t.title, - AVG(table_1._expr_0) AS avg_salary, + AVG(table_2._expr_0) AS avg_salary, dept_emp.dept_no FROM - table_1 - JOIN titles AS t ON table_1.emp_no = t.emp_no - LEFT JOIN dept_emp ON table_1.emp_no = dept_emp.emp_no + table_3 AS table_2 + JOIN titles AS t ON table_2.emp_no = t.emp_no + LEFT JOIN dept_emp ON table_2.emp_no = dept_emp.emp_no GROUP BY dept_emp.dept_no, t.title ) SELECT departments.dept_name, - table_2.title, - table_2.avg_salary + table_0.title, + table_0.avg_salary FROM - table_2 - JOIN departments ON table_2.dept_no = departments.dept_no + table_1 AS table_0 + JOIN departments ON table_0.dept_no = departments.dept_no + diff --git a/book/tests/snapshots/snapshot__@examples__employees-1.prql.snap b/book/tests/snapshots/snapshot__@examples__employees-1.prql.snap index 434d377e6067..88f00f10486c 100644 --- a/book/tests/snapshots/snapshot__@examples__employees-1.prql.snap +++ b/book/tests/snapshots/snapshot__@examples__employees-1.prql.snap @@ -3,7 +3,7 @@ source: book/tests/snapshot.rs expression: "from e=employees\njoin salaries [==emp_no]\ngroup [e.emp_no, e.gender] (\n aggregate [\n emp_salary = average salaries.salary\n ]\n)\njoin de=dept_emp [==emp_no] side:left\ngroup [de.dept_no, gender] (\n aggregate [\n salary_avg = average emp_salary,\n salary_sd = stddev emp_salary,\n ]\n)\njoin departments [==dept_no]\nselect [dept_name, gender, salary_avg, salary_sd]\n" input_file: book/tests/prql/examples/employees-1.prql --- -WITH table_1 AS ( +WITH table_3 AS ( SELECT e.gender, AVG(salaries.salary) AS _expr_0, @@ -15,24 +15,25 @@ WITH table_1 AS ( e.emp_no, e.gender ), -table_2 AS ( +table_1 AS ( SELECT - table_1.gender, - AVG(table_1._expr_0) AS salary_avg, - STDDEV(table_1._expr_0) AS salary_sd, + table_2.gender, + AVG(table_2._expr_0) AS salary_avg, + STDDEV(table_2._expr_0) AS salary_sd, de.dept_no FROM - table_1 - LEFT JOIN dept_emp AS de ON table_1.emp_no = de.emp_no + table_3 AS table_2 + LEFT JOIN dept_emp AS de ON table_2.emp_no = de.emp_no GROUP BY de.dept_no, - table_1.gender + table_2.gender ) SELECT departments.dept_name, - table_2.gender, - table_2.salary_avg, - table_2.salary_sd + table_0.gender, + table_0.salary_avg, + table_0.salary_sd FROM - table_2 - JOIN departments ON table_2.dept_no = departments.dept_no + table_1 AS table_0 + JOIN departments ON table_0.dept_no = departments.dept_no + diff --git a/book/tests/snapshots/snapshot__@examples__employees-2.prql.snap b/book/tests/snapshots/snapshot__@examples__employees-2.prql.snap index 6918730104c0..612ece4db0c6 100644 --- a/book/tests/snapshots/snapshot__@examples__employees-2.prql.snap +++ b/book/tests/snapshots/snapshot__@examples__employees-2.prql.snap @@ -3,7 +3,7 @@ source: book/tests/snapshot.rs expression: "from e=employees\njoin salaries [==emp_no]\ngroup [e.emp_no, e.gender] (\n aggregate [\n emp_salary = average salaries.salary\n ]\n)\njoin de=dept_emp [==emp_no]\njoin dm=dept_manager [\n (dm.dept_no == de.dept_no) and s\"(de.from_date, de.to_date) OVERLAPS (dm.from_date, dm.to_date)\"\n]\ngroup [dm.emp_no, gender] (\n aggregate [\n salary_avg = average emp_salary,\n salary_sd = stddev emp_salary\n ]\n)\nderive mng_no = emp_no\njoin managers=employees [==emp_no]\nderive mng_name = s\"managers.first_name || ' ' || managers.last_name\"\nselect [mng_name, managers.gender, salary_avg, salary_sd]\n" input_file: book/tests/prql/examples/employees-2.prql --- -WITH table_1 AS ( +WITH table_3 AS ( SELECT e.gender, AVG(salaries.salary) AS _expr_0, @@ -15,25 +15,26 @@ WITH table_1 AS ( e.emp_no, e.gender ), -table_2 AS ( +table_1 AS ( SELECT - AVG(table_1._expr_0) AS salary_avg, - STDDEV(table_1._expr_0) AS salary_sd, + AVG(table_2._expr_0) AS salary_avg, + STDDEV(table_2._expr_0) AS salary_sd, dm.emp_no FROM - table_1 - JOIN dept_emp AS de ON table_1.emp_no = de.emp_no + table_3 AS table_2 + JOIN dept_emp AS de ON table_2.emp_no = de.emp_no JOIN dept_manager AS dm ON dm.dept_no = de.dept_no AND (de.from_date, de.to_date) OVERLAPS (dm.from_date, dm.to_date) GROUP BY dm.emp_no, - table_1.gender + table_2.gender ) SELECT managers.first_name || ' ' || managers.last_name AS mng_name, managers.gender, - table_2.salary_avg, - table_2.salary_sd + table_0.salary_avg, + table_0.salary_sd FROM - table_2 - JOIN employees AS managers ON table_2.emp_no = managers.emp_no + table_1 AS table_0 + JOIN employees AS managers ON table_0.emp_no = managers.emp_no + diff --git a/book/tests/snapshots/snapshot__@examples__employees-3.prql.snap b/book/tests/snapshots/snapshot__@examples__employees-3.prql.snap index fa439fbf23c0..68c457076ef7 100644 --- a/book/tests/snapshots/snapshot__@examples__employees-3.prql.snap +++ b/book/tests/snapshots/snapshot__@examples__employees-3.prql.snap @@ -17,11 +17,12 @@ WITH table_1 AS ( de.dept_no ) SELECT - table_1.dept_no, - table_1.salary, + table_0.dept_no, + table_0.salary, employees.gender, titles.title FROM - table_1 - JOIN employees ON table_1.emp_no = employees.emp_no - JOIN titles ON table_1.emp_no = titles.emp_no + table_1 AS table_0 + JOIN employees ON table_0.emp_no = employees.emp_no + JOIN titles ON table_0.emp_no = titles.emp_no + diff --git a/book/tests/snapshots/snapshot__@examples__misc-0.prql.snap b/book/tests/snapshots/snapshot__@examples__misc-0.prql.snap index b12126c24dd3..676b3103af9c 100644 --- a/book/tests/snapshots/snapshot__@examples__misc-0.prql.snap +++ b/book/tests/snapshots/snapshot__@examples__misc-0.prql.snap @@ -1,15 +1,9 @@ --- source: book/tests/snapshot.rs -expression: "# TODO: this table should have a column `part` with values 1..5,\n# but such data declaration is not yet supported, see #286\ntable parts = (\n from seq_1_to_5\n)\n\nfrom pl=prospect_lists_prospects\nfilter prospect_list_id == 'cc675eee-8bd1-237f-be5e-622ba511d65e'\njoin a=accounts [a.id == pl.related_id]\njoin er=email_addr_bean_rel [er.bean_id == a.id and er.primary_address == '1']\njoin ea=email_addresses [ea.id == er.email_address_id]\nselect ea.email_address\nderive prefix = s\"regexp_replace(SUBSTRING_INDEX({email_address}, '@', 1), '[.0-9-_:]+', '.')\"\nderive stub = s\"SUBSTRING_INDEX(SUBSTRING_INDEX({prefix}, '.', part), '.', -1)\"\nselect [email_address, stub]\n" +expression: "# TODO: this table should have a column `part` with values 1..5,\n# but such data declaration is not yet supported, see #286\nlet parts = (\n from seq_1_to_5\n)\n\nfrom pl=prospect_lists_prospects\nfilter prospect_list_id == 'cc675eee-8bd1-237f-be5e-622ba511d65e'\njoin a=accounts [a.id == pl.related_id]\njoin er=email_addr_bean_rel [er.bean_id == a.id and er.primary_address == '1']\njoin ea=email_addresses [ea.id == er.email_address_id]\nselect ea.email_address\nderive prefix = s\"regexp_replace(SUBSTRING_INDEX({email_address}, '@', 1), '[.0-9-_:]+', '.')\"\nderive stub = s\"SUBSTRING_INDEX(SUBSTRING_INDEX({prefix}, '.', part), '.', -1)\"\nselect [email_address, stub]\n" input_file: book/tests/prql/examples/misc-0.prql --- -WITH parts AS ( - SELECT - * - FROM - seq_1_to_5 -), -table_1 AS ( +WITH table_1 AS ( SELECT related_id FROM @@ -33,8 +27,9 @@ SELECT -1 ) AS stub FROM - table_1 - JOIN accounts AS a ON a.id = table_1.related_id + table_1 AS table_0 + JOIN accounts AS a ON a.id = table_0.related_id JOIN email_addr_bean_rel AS er ON er.bean_id = a.id AND er.primary_address = '1' JOIN email_addresses AS ea ON ea.id = er.email_address_id + diff --git a/book/tests/snapshots/snapshot__@examples__variables-0.prql.snap b/book/tests/snapshots/snapshot__@examples__variables-0.prql.snap index 9f7411a758ba..69e10cb2c16d 100644 --- a/book/tests/snapshots/snapshot__@examples__variables-0.prql.snap +++ b/book/tests/snapshots/snapshot__@examples__variables-0.prql.snap @@ -26,7 +26,7 @@ SELECT SUM(_expr_0) AS sum_gross_cost, COUNT(*) AS ct FROM - table_1 + table_1 AS table_0 WHERE _expr_0 > 0 GROUP BY @@ -38,3 +38,4 @@ ORDER BY sum_gross_cost LIMIT 20 + diff --git a/book/tests/snapshots/snapshot__@examples__variables-1.prql.snap b/book/tests/snapshots/snapshot__@examples__variables-1.prql.snap index ea3da8460bb5..77b68ee0c7d1 100644 --- a/book/tests/snapshots/snapshot__@examples__variables-1.prql.snap +++ b/book/tests/snapshots/snapshot__@examples__variables-1.prql.snap @@ -13,12 +13,13 @@ WITH table_1 AS ( emp_no ) SELECT - AVG(table_1._expr_0) / 1000 AS salary_k, - AVG(table_1._expr_0) / 1000 * 1000 AS salary + AVG(table_0._expr_0) / 1000 AS salary_k, + AVG(table_0._expr_0) / 1000 * 1000 AS salary FROM - table_1 - JOIN titles ON table_1.emp_no = titles.emp_no + table_1 AS table_0 + JOIN titles ON table_0.emp_no = titles.emp_no GROUP BY titles.title LIMIT 10 + diff --git a/book/tests/snapshots/snapshot__@introduction-0.prql.snap b/book/tests/snapshots/snapshot__@introduction-0.prql.snap index 741163b2be4d..2cfecfb1a71d 100644 --- a/book/tests/snapshots/snapshot__@introduction-0.prql.snap +++ b/book/tests/snapshots/snapshot__@introduction-0.prql.snap @@ -1,6 +1,6 @@ --- source: book/tests/snapshot.rs -expression: "from employees\nfilter start_date > @2021-01-01 # Clear date syntax\nderive [ # `derive` adds columns / variables\n gross_salary = salary + (tax ?? 0), # Terse coalesce\n gross_cost = gross_salary + benefits_cost, # Variables can use other variables\n]\nfilter gross_cost > 0\ngroup [title, country] ( # `group` runs a pipeline over each group\n aggregate [ # `aggregate` reduces each group to a value\n average gross_salary,\n sum_gross_cost = sum gross_cost, # `=` sets a column name\n ]\n)\nfilter sum_gross_cost > 100_000 # `filter` replaces both of SQL's `WHERE` & `HAVING`\nderive id = f\"{title}_{country}\" # F-strings like python\nderive country_code = s\"LEFT(country, 2)\" # S-strings allow using SQL as an escape hatch\nsort [sum_gross_cost, -country] # `-country` means descending order\ntake 1..20 # Range expressions (also valid here as `take 20`)\n" +expression: "from employees\nfilter start_date > @2021-01-01 # Clear date syntax\nderive [ # `derive` adds columns / variables\n gross_salary = salary + (tax ?? 0), # Terse coalesce\n gross_cost = gross_salary + benefits_cost, # Variables can use other variables\n]\nfilter gross_cost > 0\ngroup [title, country] ( # `group` runs a pipeline over each group\n aggregate [ # `aggregate` reduces each group to a value\n average gross_salary,\n sum_gross_cost = sum gross_cost, # `=` sets a column name\n ]\n)\nfilter sum_gross_cost > 100_000 # `filter` replaces both of SQL's `WHERE` & `HAVING`\nderive id = f\"{title}_{country}\" # F-strings like Python\nderive country_code = s\"LEFT(country, 2)\" # S-strings allow using SQL as an escape hatch\nsort [sum_gross_cost, -country] # `-country` means descending order\ntake 1..20 # Range expressions (also valid here as `take 20`)\n" input_file: book/tests/prql/introduction-0.prql --- WITH table_1 AS ( @@ -22,7 +22,7 @@ SELECT CONCAT(title, '_', country) AS id, LEFT(country, 2) AS country_code FROM - table_1 + table_1 AS table_0 WHERE _expr_0 > 0 GROUP BY @@ -35,3 +35,4 @@ ORDER BY country DESC LIMIT 20 + diff --git a/book/tests/snapshots/snapshot__@language-features__distinct-2.prql.snap b/book/tests/snapshots/snapshot__@language-features__distinct-2.prql.snap index 2d9d6d5178f5..693c04dcf449 100644 --- a/book/tests/snapshots/snapshot__@language-features__distinct-2.prql.snap +++ b/book/tests/snapshots/snapshot__@language-features__distinct-2.prql.snap @@ -17,6 +17,7 @@ WITH table_1 AS ( SELECT * FROM - table_1 + table_1 AS table_0 WHERE _expr_0 <= 1 + diff --git a/book/tests/snapshots/snapshot__@language-features__s-strings-3.prql.snap b/book/tests/snapshots/snapshot__@language-features__s-strings-3.prql.snap index 3f5c880fd181..3d97e867fc17 100644 --- a/book/tests/snapshots/snapshot__@language-features__s-strings-3.prql.snap +++ b/book/tests/snapshots/snapshot__@language-features__s-strings-3.prql.snap @@ -3,7 +3,7 @@ source: book/tests/snapshot.rs expression: "from s\"SELECT DISTINCT ON first_name, id, age FROM employees ORDER BY age ASC\"\njoin s = s\"SELECT * FROM salaries\" [==id]\n" input_file: book/tests/prql/language-features/s-strings-3.prql --- -WITH table_2 AS ( +WITH table_0 AS ( SELECT DISTINCT ON first_name, id, @@ -13,15 +13,16 @@ WITH table_2 AS ( ORDER BY age ASC ), -table_3 AS ( +table_1 AS ( SELECT * FROM salaries ) SELECT - table_0.*, - table_1.* + table_2.*, + table_3.* FROM - table_2 AS table_0 - JOIN table_3 AS table_1 ON table_0.id = table_1.id + table_0 AS table_2 + JOIN table_1 AS table_3 ON table_2.id = table_3.id + diff --git a/book/tests/snapshots/snapshot__@language-features__standard-library-0.prql.snap b/book/tests/snapshots/snapshot__@language-features__standard-library__README-0.prql.snap similarity index 84% rename from book/tests/snapshots/snapshot__@language-features__standard-library-0.prql.snap rename to book/tests/snapshots/snapshot__@language-features__standard-library__README-0.prql.snap index 31e030d55e0b..b3a371283e07 100644 --- a/book/tests/snapshots/snapshot__@language-features__standard-library-0.prql.snap +++ b/book/tests/snapshots/snapshot__@language-features__standard-library__README-0.prql.snap @@ -1,7 +1,7 @@ --- source: book/tests/snapshot.rs expression: "from employees\nderive [\n gross_salary = (salary + payroll_tax | as int),\n gross_salary_rounded = (gross_salary | round 0),\n time = s\"NOW()\", # an s-string, given no `now` function exists in PRQL\n]\n" -input_file: book/tests/prql/language-features/standard-library-0.prql +input_file: book/tests/prql/language-features/standard-library/README-0.prql --- SELECT *, @@ -10,3 +10,4 @@ SELECT NOW() AS time FROM employees + diff --git a/book/tests/snapshots/snapshot__@transforms__from_text-0.prql.snap b/book/tests/snapshots/snapshot__@language-features__standard-library__from-text-0.prql.snap similarity index 73% rename from book/tests/snapshots/snapshot__@transforms__from_text-0.prql.snap rename to book/tests/snapshots/snapshot__@language-features__standard-library__from-text-0.prql.snap index 59de499b2072..904a45d549da 100644 --- a/book/tests/snapshots/snapshot__@transforms__from_text-0.prql.snap +++ b/book/tests/snapshots/snapshot__@language-features__standard-library__from-text-0.prql.snap @@ -1,9 +1,9 @@ --- source: book/tests/snapshot.rs expression: "from_text \"\"\"\na,b,c\n1,2,3\n4,5,6\n\"\"\"\nderive [\n d = b + c,\n answer = 20 * 2 + 2,\n]\n" -input_file: book/tests/prql/transforms/from_text-0.prql +input_file: book/tests/prql/language-features/standard-library/from-text-0.prql --- -WITH table_1 AS ( +WITH table_0 AS ( SELECT '1' AS a, '2' AS b, @@ -22,5 +22,5 @@ SELECT b + c AS d, 42 AS answer FROM - table_1 AS table_0 + table_0 AS table_1 diff --git a/book/tests/snapshots/snapshot__@transforms__from_text-1.prql.snap b/book/tests/snapshots/snapshot__@language-features__standard-library__from-text-1.prql.snap similarity index 90% rename from book/tests/snapshots/snapshot__@transforms__from_text-1.prql.snap rename to book/tests/snapshots/snapshot__@language-features__standard-library__from-text-1.prql.snap index 9ae070f052eb..670e58dfc204 100644 --- a/book/tests/snapshots/snapshot__@transforms__from_text-1.prql.snap +++ b/book/tests/snapshots/snapshot__@language-features__standard-library__from-text-1.prql.snap @@ -1,7 +1,7 @@ --- source: book/tests/snapshot.rs expression: "let temp_format_lookup = from_text format:csv \"\"\"\ncountry_code,format\nuk,C\nus,F\nlr,F\nde,C\n\"\"\"\n\nfrom temperatures\njoin temp_format_lookup [==country_code]\n" -input_file: book/tests/prql/transforms/from_text-1.prql +input_file: book/tests/prql/language-features/standard-library/from-text-1.prql --- WITH table_0 AS ( SELECT diff --git a/book/tests/snapshots/snapshot__@transforms__from_text-2.prql.snap b/book/tests/snapshots/snapshot__@language-features__standard-library__from-text-2.prql.snap similarity index 91% rename from book/tests/snapshots/snapshot__@transforms__from_text-2.prql.snap rename to book/tests/snapshots/snapshot__@language-features__standard-library__from-text-2.prql.snap index 085bbccf68f8..becf706977bb 100644 --- a/book/tests/snapshots/snapshot__@transforms__from_text-2.prql.snap +++ b/book/tests/snapshots/snapshot__@language-features__standard-library__from-text-2.prql.snap @@ -1,7 +1,7 @@ --- source: book/tests/snapshot.rs expression: "let x = from_text format:json \"\"\"{\n \"columns\": [\"a\", \"b\", \"c\"],\n \"data\": [\n [1, \"x\", false],\n [4, \"y\", null]\n ]\n}\"\"\"\n\nlet y = from_text format:json \"\"\"\n [\n {\"a\": 1, \"m\": \"5\"},\n {\"a\": 4, \"n\": \"6\"}\n ]\n\"\"\"\n\nfrom x | join y [==a]\n" -input_file: book/tests/prql/transforms/from_text-2.prql +input_file: book/tests/prql/language-features/standard-library/from-text-2.prql --- WITH table_0 AS ( SELECT diff --git a/book/tests/snapshots/snapshot__@language-features__standard-library__loop-0.prql.snap b/book/tests/snapshots/snapshot__@language-features__standard-library__loop-0.prql.snap new file mode 100644 index 000000000000..5515357a6c0c --- /dev/null +++ b/book/tests/snapshots/snapshot__@language-features__standard-library__loop-0.prql.snap @@ -0,0 +1,34 @@ +--- +source: book/tests/snapshot.rs +expression: "from_text format:json '[{\"n\": 1 }]'\nloop (\n filter n<4\n select n = n+1\n)\n\n# returns [1, 2, 3, 4]\n" +input_file: book/tests/prql/language-features/standard-library/loop-0.prql +--- +WITH table_0 AS ( + SELECT + 1 AS n +), +table_4 AS ( + WITH RECURSIVE loop AS ( + SELECT + n + FROM + table_0 AS table_1 + UNION + ALL + SELECT + n + 1 + FROM + loop AS table_2 + WHERE + n < 4 + ) + SELECT + * + FROM + loop +) +SELECT + n +FROM + table_4 AS table_3 + diff --git a/book/tests/snapshots/snapshot__@queries__pipelines-2.prql.snap b/book/tests/snapshots/snapshot__@queries__pipelines-2.prql.snap index 48c578cb780a..8a7e0fd99bc5 100644 --- a/book/tests/snapshots/snapshot__@queries__pipelines-2.prql.snap +++ b/book/tests/snapshots/snapshot__@queries__pipelines-2.prql.snap @@ -16,9 +16,10 @@ WITH table_1 AS ( 10 ) SELECT - table_1.name, - table_1.gross_salary, + table_0.name, + table_0.gross_salary, d.name FROM - table_1 - JOIN department AS d ON table_1.dept_no = d.dept_no + table_1 AS table_0 + JOIN department AS d ON table_0.dept_no = d.dept_no + diff --git a/book/tests/snapshots/snapshot__@queries__variables-0.prql.snap b/book/tests/snapshots/snapshot__@queries__variables-0.prql.snap index e37a88722453..ca97469b4749 100644 --- a/book/tests/snapshots/snapshot__@queries__variables-0.prql.snap +++ b/book/tests/snapshots/snapshot__@queries__variables-0.prql.snap @@ -3,7 +3,7 @@ source: book/tests/snapshot.rs expression: "let top_50 = (\n from employees\n sort salary\n take 50\n aggregate [total_salary = sum salary]\n)\n\nfrom top_50 # Starts a new pipeline\n" input_file: book/tests/prql/queries/variables-0.prql --- -WITH table_0 AS ( +WITH table_1 AS ( SELECT salary FROM @@ -16,7 +16,7 @@ WITH table_0 AS ( SELECT SUM(salary) AS total_salary FROM - table_0 + table_1 AS table_0 ) SELECT total_salary diff --git a/book/tests/snapshots/snapshot__@syntax-5.prql.snap b/book/tests/snapshots/snapshot__@syntax-5.prql.snap index 374cbd663cf3..9095768d6603 100644 --- a/book/tests/snapshots/snapshot__@syntax-5.prql.snap +++ b/book/tests/snapshots/snapshot__@syntax-5.prql.snap @@ -14,7 +14,8 @@ SELECT circumference, color FROM - table_1 + table_1 AS table_0 WHERE circumference > 10 AND color <> 'red' + diff --git a/book/tests/snapshots/snapshot__@transforms__group-2.prql.snap b/book/tests/snapshots/snapshot__@transforms__group-2.prql.snap index a11503ab56c8..03289443cc04 100644 --- a/book/tests/snapshots/snapshot__@transforms__group-2.prql.snap +++ b/book/tests/snapshots/snapshot__@transforms__group-2.prql.snap @@ -17,6 +17,7 @@ WITH table_1 AS ( SELECT * FROM - table_1 + table_1 AS table_0 WHERE _expr_0 <= 1 + diff --git a/book/tests/snapshots/snapshot__@transforms__sort-3.prql.snap b/book/tests/snapshots/snapshot__@transforms__sort-3.prql.snap index 7b6e784e1da0..fb7acd653ec6 100644 --- a/book/tests/snapshots/snapshot__@transforms__sort-3.prql.snap +++ b/book/tests/snapshots/snapshot__@transforms__sort-3.prql.snap @@ -3,16 +3,11 @@ source: book/tests/snapshot.rs expression: "from employees\nsort [s\"substr({first_name}, 2, 5)\"]\n" input_file: book/tests/prql/transforms/sort-3.prql --- -WITH table_1 AS ( - SELECT - *, - substr(first_name, 2, 5) AS _expr_0 - FROM - employees - ORDER BY - _expr_0 -) SELECT - * + *, + substr(first_name, 2, 5) AS _expr_0 FROM - table_1 + employees +ORDER BY + _expr_0 + diff --git a/book/tests/snapshots/snapshot__@transforms__sort-5.prql.snap b/book/tests/snapshots/snapshot__@transforms__sort-5.prql.snap index de8d52ca5f42..b969c19b2a4d 100644 --- a/book/tests/snapshots/snapshot__@transforms__sort-5.prql.snap +++ b/book/tests/snapshots/snapshot__@transforms__sort-5.prql.snap @@ -12,8 +12,9 @@ WITH table_1 AS ( tenure ) SELECT - table_1.*, + table_0.*, locations.* FROM - table_1 - JOIN locations ON table_1.employee_id = locations.employee_id + table_1 AS table_0 + JOIN locations ON table_0.employee_id = locations.employee_id + diff --git a/book/tests/snapshots/snapshot__@transforms__window-4.prql.snap b/book/tests/snapshots/snapshot__@transforms__window-4.prql.snap index 13bb14a01bc7..0dcf1866c987 100644 --- a/book/tests/snapshots/snapshot__@transforms__window-4.prql.snap +++ b/book/tests/snapshots/snapshot__@transforms__window-4.prql.snap @@ -13,6 +13,7 @@ WITH table_1 AS ( SELECT * FROM - table_1 + table_1 AS table_0 WHERE salary < _expr_0 + diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__standard-library-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__standard-library__README-0.prql.snap similarity index 100% rename from book/tests/snapshots/snapshot__tests__prql__language-features__standard-library-0.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__language-features__standard-library__README-0.prql.snap diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__from_text-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__standard-library__from-text-0.prql.snap similarity index 100% rename from book/tests/snapshots/snapshot__tests__prql__transforms__from_text-0.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__language-features__standard-library__from-text-0.prql.snap diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__from_text-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__standard-library__from-text-1.prql.snap similarity index 100% rename from book/tests/snapshots/snapshot__tests__prql__transforms__from_text-1.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__language-features__standard-library__from-text-1.prql.snap diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__from_text-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__standard-library__from-text-2.prql.snap similarity index 100% rename from book/tests/snapshots/snapshot__tests__prql__transforms__from_text-2.prql.snap rename to book/tests/snapshots/snapshot__tests__prql__language-features__standard-library__from-text-2.prql.snap diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__standard-library__loop-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__standard-library__loop-0.prql.snap new file mode 100644 index 000000000000..0c143248892b --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__standard-library__loop-0.prql.snap @@ -0,0 +1,12 @@ +--- +source: book/tests/snapshot.rs +expression: "from_text format:json '[{\"n\": 1 }]'\nloop (\n filter n<4\n select n = n+1\n)\n\n# returns [1, 2, 3, 4]\n" +--- +from_text format:json '[{"n": 1 }]' +loop ( + filter n < 4 + select n = n + 1 +) + + + diff --git a/prql-compiler/src/ast/pl/expr.rs b/prql-compiler/src/ast/pl/expr.rs index 630d4725f32f..e6792d7d8f10 100644 --- a/prql-compiler/src/ast/pl/expr.rs +++ b/prql-compiler/src/ast/pl/expr.rs @@ -310,6 +310,7 @@ pub enum TransformKind { pipeline: Box, }, Append(Box), + Loop(Box), } #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] diff --git a/prql-compiler/src/ast/pl/fold.rs b/prql-compiler/src/ast/pl/fold.rs index 3af403b8525d..b82f9178a296 100644 --- a/prql-compiler/src/ast/pl/fold.rs +++ b/prql-compiler/src/ast/pl/fold.rs @@ -273,6 +273,7 @@ pub fn fold_transform_kind( range: fold_range(fold, range)?, pipeline: Box::new(fold.fold_expr(*pipeline)?), }, + Loop(pipeline) => Loop(Box::new(fold.fold_expr(*pipeline)?)), }) } diff --git a/prql-compiler/src/ast/pl/types.rs b/prql-compiler/src/ast/pl/types.rs index 3d4c428d5d75..cb1463940c7b 100644 --- a/prql-compiler/src/ast/pl/types.rs +++ b/prql-compiler/src/ast/pl/types.rs @@ -6,7 +6,7 @@ use serde::{Deserialize, Serialize}; use super::Frame; -#[derive(Clone, PartialEq, Serialize, Deserialize, EnumAsInner)] +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, EnumAsInner)] pub enum Ty { Empty, Literal(TyLit), @@ -162,9 +162,3 @@ impl Display for Ty { } } } - -impl Debug for Ty { - fn fmt(&self, f: &mut Formatter<'_>) -> Result { - Display::fmt(self, f) - } -} diff --git a/prql-compiler/src/ast/rq/fold.rs b/prql-compiler/src/ast/rq/fold.rs index d84d6385ba37..1c799e35dfe0 100644 --- a/prql-compiler/src/ast/rq/fold.rs +++ b/prql-compiler/src/ast/rq/fold.rs @@ -187,6 +187,7 @@ pub fn fold_transform( filter: fold.fold_expr(filter)?, }, Append(bottom) => Append(fold.fold_table_ref(bottom)?), + Loop(transforms) => Loop(fold_transforms(fold, transforms)?), }; Ok(transform) } diff --git a/prql-compiler/src/ast/rq/transform.rs b/prql-compiler/src/ast/rq/transform.rs index 7a946e1d2c13..875bc3d922b6 100644 --- a/prql-compiler/src/ast/rq/transform.rs +++ b/prql-compiler/src/ast/rq/transform.rs @@ -25,6 +25,7 @@ pub enum Transform { filter: Expr, }, Append(TableRef), + Loop(Vec), } #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] diff --git a/prql-compiler/src/semantic/lowering.rs b/prql-compiler/src/semantic/lowering.rs index bb595dd20da0..25383b9dd744 100644 --- a/prql-compiler/src/semantic/lowering.rs +++ b/prql-compiler/src/semantic/lowering.rs @@ -269,7 +269,7 @@ impl Lowerer { let ty = expr.ty.clone(); let prev_pipeline = self.pipeline.drain(..).collect_vec(); - self.lower_pipeline(expr)?; + self.lower_pipeline(expr, None)?; let mut transforms = self.pipeline.drain(..).collect_vec(); let columns = self.push_select(ty, &mut transforms)?; @@ -284,10 +284,22 @@ impl Lowerer { } // Result is stored in self.pipeline - fn lower_pipeline(&mut self, ast: pl::Expr) -> Result<()> { + fn lower_pipeline(&mut self, ast: pl::Expr, closure_param: Option) -> Result<()> { let transform_call = match ast.kind { pl::ExprKind::TransformCall(transform) => transform, + pl::ExprKind::Closure(closure) => { + let param = closure.params.first(); + let param = param.and_then(|p| p.name.parse::().ok()); + return self.lower_pipeline(*closure.body, param); + } _ => { + if let Some(target) = ast.target_id { + if Some(target) == closure_param { + // ast is a closure param, so we can skip pushing From + return Ok(()); + } + } + let table_ref = self.lower_table_ref(ast)?; self.pipeline.push(Transform::From(table_ref)); return Ok(()); @@ -295,7 +307,7 @@ impl Lowerer { }; // lower input table - self.lower_pipeline(*transform_call.input)?; + self.lower_pipeline(*transform_call.input, closure_param)?; // ... and continues with transforms created in this function @@ -362,8 +374,16 @@ impl Lowerer { pl::TransformKind::Append(bottom) => { let bottom = self.lower_table_ref(*bottom)?; - let transform = Transform::Append(bottom); - self.pipeline.push(transform); + self.pipeline.push(Transform::Append(bottom)); + } + pl::TransformKind::Loop(pipeline) => { + let relation = self.lower_relation(*pipeline)?; + let mut pipeline = relation.kind.into_pipeline().unwrap(); + + // last select is not needed here + pipeline.pop(); + + self.pipeline.push(Transform::Loop(pipeline)); } pl::TransformKind::Group { .. } | pl::TransformKind::Window { .. } => unreachable!( "transform `{}` cannot be lowered.", @@ -680,9 +700,10 @@ impl Lowerer { let name = match name { Some(v) => RelationColumn::Single(Some(v.clone())), None => return Err(Error::new_simple( - "This table contains unnamed columns, that need to be referenced by name", + "This table contains unnamed columns that need to be referenced by name", ) .with_span(self.context.span_map.get(&id).cloned()) + .with_help("The name may have been overridden later in the pipeline.") .into()), }; log::trace!("lookup cid of name={name:?} in input {input_columns:?}"); diff --git a/prql-compiler/src/semantic/std.prql b/prql-compiler/src/semantic/std.prql index f906e2dc7b23..586a9dcaf94f 100644 --- a/prql-compiler/src/semantic/std.prql +++ b/prql-compiler/src/semantic/std.prql @@ -48,6 +48,7 @@ func remove
`default_db.bottom`
top
-> ( filter (all (map _is_null b.*)) select t.* ) +func loop
pipeline top
-> null # List functions func all list -> null diff --git a/prql-compiler/src/semantic/transforms.rs b/prql-compiler/src/semantic/transforms.rs index b517b2a81c33..15c73cbbe44f 100644 --- a/prql-compiler/src/semantic/transforms.rs +++ b/prql-compiler/src/semantic/transforms.rs @@ -192,6 +192,13 @@ pub fn cast_transform(resolver: &mut Resolver, closure: Closure) -> Result { + let [pipeline, tbl] = unpack::<2>(closure); + + let pipeline = fold_by_simulating_eval(resolver, pipeline, tbl.ty.clone().unwrap())?; + + (TransformKind::Loop(Box::new(pipeline)), tbl) + } "std.in" => { // yes, this is not a transform, but this is the most appropriate place for it @@ -582,6 +589,7 @@ impl TransformCall { let bottom = ty_frame_or_default(bottom)?; append(top, bottom)? } + Loop(_) => ty_frame_or_default(&self.input)?, Sort { .. } | Filter { .. } | Take { .. } => ty_frame_or_default(&self.input)?, }) } diff --git a/prql-compiler/src/snapshots/prql_compiler__test__prql_to_sql_2.snap b/prql-compiler/src/snapshots/prql_compiler__test__prql_to_sql_2.snap index bbc44298cbb5..23a1cc2ad749 100644 --- a/prql-compiler/src/snapshots/prql_compiler__test__prql_to_sql_2.snap +++ b/prql-compiler/src/snapshots/prql_compiler__test__prql_to_sql_2.snap @@ -25,7 +25,7 @@ SELECT SUM(_expr_0) AS sum_gross_cost, COUNT(*) AS ct FROM - table_1 + table_1 AS table_0 WHERE _expr_0 > 0 GROUP BY @@ -37,3 +37,4 @@ ORDER BY sum_gross_cost LIMIT 20 + diff --git a/prql-compiler/src/sql/anchor.rs b/prql-compiler/src/sql/anchor.rs index 6740cd2cc391..4c0e0ece9b76 100644 --- a/prql-compiler/src/sql/anchor.rs +++ b/prql-compiler/src/sql/anchor.rs @@ -3,28 +3,28 @@ use itertools::Itertools; use std::collections::{HashMap, HashSet}; use crate::ast::rq::{ - self, fold_transform, CId, Compute, Expr, Relation, RelationColumn, RelationKind, RqFold, - TableDecl, TableRef, Transform, + self, fold_transform, CId, Compute, Expr, RelationColumn, RqFold, TableRef, Transform, }; +use crate::sql::context::SqlTableDecl; +use crate::sql::preprocess::{SqlRelation, SqlRelationKind}; use super::{ context::{AnchorContext, ColumnDecl}, preprocess::{SqlFold, SqlTransform}, }; -type RemainingPipeline = (Vec, Vec); - /// Splits pipeline into two parts, such that the second part contains /// maximum number of transforms while "fitting" into a SELECT query. pub(super) fn split_off_back( - ctx: &mut AnchorContext, - output: Vec, mut pipeline: Vec, -) -> (Option, Vec) { + ctx: &mut AnchorContext, +) -> (Option>, Vec) { if pipeline.is_empty() { return (None, Vec::new()); } + let output = AnchorContext::determine_select_columns(&pipeline); + log::debug!("traversing pipeline to obtain columns: {output:?}"); let mut following_transforms: HashSet = HashSet::new(); @@ -137,8 +137,9 @@ pub(super) fn split_off_back( None } else { // drop inputs that were satisfied in current pipeline + pipeline.push(SqlTransform::Super(Transform::Select(missing))); - Some((pipeline, missing)) + Some(pipeline) }; curr_pipeline_rev.reverse(); @@ -166,20 +167,23 @@ fn can_materialize(compute: &Compute, inputs_required: &[Requirement]) -> bool { } /// Applies adjustments to second part of a pipeline when it's split: -/// - prepend pipeline with From -/// - redefine columns materialized in preceding pipeline +/// - append Select to proceeding pipeline +/// - prepend From to atomic pipeline +/// - redefine columns materialized in atomic pipeline /// - redirect all references to original columns to the new ones pub(super) fn anchor_split( ctx: &mut AnchorContext, - first_table_name: &str, - cols_at_split: &[CId], - second_pipeline: Vec, + preceding: Vec, + atomic: Vec, ) -> Vec { let new_tid = ctx.tid.gen(); + let preceding_select = &preceding.last().unwrap().as_super().unwrap(); + let cols_at_split = preceding_select.as_select().unwrap(); + log::debug!("split pipeline, first pipeline output: {cols_at_split:?}"); - // define columns of the new CTE + // redefine columns of the atomic pipeline let mut cid_redirects = HashMap::::new(); let mut new_columns = Vec::new(); for old_cid in cols_at_split { @@ -204,32 +208,31 @@ pub(super) fn anchor_split( // define a new table ctx.table_decls.insert( new_tid, - TableDecl { + SqlTableDecl { id: new_tid, - name: Some(first_table_name.to_string()), - // here we should put the pipeline, but because how this function is called, - // we need to return the pipeline directly, so we just insert dummy expr instead - relation: Relation { - kind: RelationKind::SString(vec![]), - columns: vec![], - }, + name: None, + relation: Some(SqlRelation { + columns: cols_at_split + .iter() + .map(|_| RelationColumn::Single(None)) + .collect_vec(), + kind: SqlRelationKind::PreprocessedPipeline(preceding), + }), }, ); // define instance of that table - let table_ref = TableRef { + let table_ref = ctx.create_table_instance(TableRef { source: new_tid, - name: Some(first_table_name.to_string()), + name: None, columns: new_columns, - }; - ctx.create_table_instance(table_ref.clone()); + }); // adjust second part: prepend from and rewrite expressions to use new columns - let mut second = second_pipeline; + let mut second = atomic; second.insert(0, SqlTransform::Super(Transform::From(table_ref))); - let mut redirector = CidRedirector { ctx, cid_redirects }; - redirector.fold_sql_transforms(second).unwrap() + CidRedirector::redirect(second, cid_redirects, ctx) } /// Determines whether a pipeline must be split at a transform to @@ -248,6 +251,7 @@ fn is_split_required(transform: &SqlTransform, following: &mut HashSet) // - take (no limit) // - distinct // - append/except/intersect (no limit) + // - loop (max 1x) // // Select is not affected by the order. use SqlTransform::*; @@ -306,6 +310,7 @@ fn is_split_required(transform: &SqlTransform, following: &mut HashSet) "Distinct", ], ), + SqlTransform::Loop(_) => !following.is_empty(), _ => false, }; @@ -387,12 +392,13 @@ pub(super) fn get_requirements( cids } - Super(Append(_)) => unreachable!(), - Super(Select(_) | From(_) | Aggregate { .. }) + Super(Aggregate { .. } | Append(_) | Transform::Loop(_)) => unreachable!(), + Super(Select(_) | From(_)) | Distinct | Union { .. } | Except { .. } - | Intersect { .. } => return Vec::new(), + | Intersect { .. } + | SqlTransform::Loop(_) => return Vec::new(), }; // general case: determine complexity @@ -502,9 +508,20 @@ impl RqFold for CidCollector { } } -struct CidRedirector<'a> { - ctx: &'a mut AnchorContext, - cid_redirects: HashMap, +pub(super) struct CidRedirector<'a> { + pub ctx: &'a mut AnchorContext, + pub cid_redirects: HashMap, +} + +impl<'a> CidRedirector<'a> { + pub fn redirect( + pipeline: Vec, + cid_redirects: HashMap, + ctx: &mut AnchorContext, + ) -> Vec { + let mut redirector = CidRedirector { ctx, cid_redirects }; + redirector.fold_sql_transforms(pipeline).unwrap() + } } impl<'a> RqFold for CidRedirector<'a> { diff --git a/prql-compiler/src/sql/context.rs b/prql-compiler/src/sql/context.rs index 4fa41ea51e71..b9b38e1ae2bf 100644 --- a/prql-compiler/src/sql/context.rs +++ b/prql-compiler/src/sql/context.rs @@ -10,19 +10,19 @@ use itertools::Itertools; use crate::ast::pl::TableExternRef; use crate::ast::rq::{ - fold_table, CId, Compute, Query, RelationColumn, RelationKind, RqFold, TId, TableDecl, - TableRef, Transform, + fold_table, CId, Compute, Query, Relation, RelationColumn, RelationKind, RqFold, TId, + TableDecl, TableRef, Transform, }; use crate::utils::{IdGenerator, NameGenerator}; -use super::preprocess::SqlTransform; +use super::preprocess::{SqlRelation, SqlTransform}; #[derive(Default)] pub struct AnchorContext { pub(super) column_decls: HashMap, pub(super) column_names: HashMap, - pub(super) table_decls: HashMap, + pub(super) table_decls: HashMap, pub(super) table_instances: HashMap, @@ -33,6 +33,20 @@ pub struct AnchorContext { pub(super) tid: IdGenerator, pub(super) tiid: IdGenerator, } + +#[derive(Debug, Clone)] +pub(super) struct SqlTableDecl { + #[allow(dead_code)] + pub id: TId, + + pub name: Option, + + /// Relation that still needs to be defined (usually as CTE) so it can be referenced by name. + /// None means that it has already been defined, or was not needed to be defined in the + /// first place. + pub relation: Option, +} + /// Table instance id #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct TIId(usize); @@ -51,7 +65,7 @@ pub enum ColumnDecl { } impl AnchorContext { - pub fn of(query: Query) -> (Self, Query) { + pub fn of(query: Query) -> (Self, Relation) { let (cid, tid, query) = IdGenerator::load(query); let context = AnchorContext { @@ -78,7 +92,7 @@ impl AnchorContext { self.column_decls.insert(id, decl); } - pub fn create_table_instance(&mut self, mut table_ref: TableRef) { + pub fn create_table_instance(&mut self, mut table_ref: TableRef) -> TableRef { let tiid = self.tiid.gen(); for (col, cid) in &table_ref.columns { @@ -90,7 +104,8 @@ impl AnchorContext { table_ref.name = Some(self.table_name.gen()) } - self.table_instances.insert(tiid, table_ref); + self.table_instances.insert(tiid, table_ref.clone()); + table_ref } pub(crate) fn ensure_column_name(&mut self, cid: CId) -> Option<&String> { @@ -193,29 +208,45 @@ struct QueryLoader { } impl QueryLoader { - fn load(context: AnchorContext, query: Query) -> (AnchorContext, Query) { + fn load(context: AnchorContext, query: Query) -> (AnchorContext, Relation) { let mut loader = QueryLoader { context }; - let query = loader.fold_query(query).unwrap(); - (loader.context, query) + + for t in query.tables { + loader.load_table(t).unwrap(); + } + let relation = loader.fold_relation(query.relation).unwrap(); + (loader.context, relation) } -} -impl RqFold for QueryLoader { - fn fold_table(&mut self, table: TableDecl) -> Result { + fn load_table(&mut self, table: TableDecl) -> Result<()> { let mut decl = fold_table(self, table)?; + // assume name of the LocalTable that the relation is referencing if let RelationKind::ExternRef(TableExternRef::LocalTable(table)) = &decl.relation.kind { decl.name = Some(table.clone()); } + // generate name (if not present) if decl.name.is_none() && decl.relation.kind.as_extern_ref().is_none() { decl.name = Some(self.context.table_name.gen()); } - self.context.table_decls.insert(decl.id, decl.clone()); - Ok(decl) + let sql_decl = SqlTableDecl { + id: decl.id, + name: decl.name, + relation: if matches!(decl.relation.kind, RelationKind::ExternRef(_)) { + None + } else { + Some(decl.relation.into()) + }, + }; + + self.context.table_decls.insert(decl.id, sql_decl); + Ok(()) } +} +impl RqFold for QueryLoader { fn fold_compute(&mut self, compute: Compute) -> Result { self.context.register_compute(compute.clone()); Ok(compute) diff --git a/prql-compiler/src/sql/gen_expr.rs b/prql-compiler/src/sql/gen_expr.rs index 51d00a1cdd8a..271b4a6a1833 100644 --- a/prql-compiler/src/sql/gen_expr.rs +++ b/prql-compiler/src/sql/gen_expr.rs @@ -6,8 +6,7 @@ use lazy_static::lazy_static; use regex::Regex; use sqlparser::ast::{ self as sql_ast, BinaryOperator, DateTimeField, Function, FunctionArg, FunctionArgExpr, Ident, - Join, JoinConstraint, JoinOperator, ObjectName, OrderByExpr, SelectItem, TableAlias, - TableFactor, Top, UnaryOperator, Value, WindowFrameBound, WindowSpec, + ObjectName, OrderByExpr, SelectItem, Top, UnaryOperator, Value, WindowFrameBound, WindowSpec, }; use sqlparser::keywords::{ Keyword, ALL_KEYWORDS, ALL_KEYWORDS_INDEX, RESERVED_FOR_COLUMN_ALIAS, RESERVED_FOR_TABLE_ALIAS, @@ -15,8 +14,7 @@ use sqlparser::keywords::{ use std::collections::HashSet; use crate::ast::pl::{ - BinOp, ColumnSort, InterpolateItem, JoinSide, Literal, Range, SortDirection, TableExternRef, - WindowFrame, WindowKind, + BinOp, ColumnSort, InterpolateItem, Literal, Range, SortDirection, WindowFrame, WindowKind, }; use crate::ast::rq::*; use crate::error::{Error, Span}; @@ -187,7 +185,7 @@ pub(super) fn translate_literal(l: Literal, ctx: &Context) -> Result Result { - if ctx.pre_projection { + if ctx.query.pre_projection { log::debug!("translating {cid:?} pre projection"); let decl = ctx.anchor.column_decls.get(&cid).expect("bad RQ ids"); @@ -231,7 +229,7 @@ pub(super) fn translate_cid(cid: CId, ctx: &mut Context) -> Result { let name = ctx.anchor.column_names.get(&cid).cloned(); - name.expect("a name of this column to be set before generating SQL") + name.expect("name of this column has not been to be set before generating SQL") } }; @@ -244,38 +242,6 @@ pub(super) fn translate_cid(cid: CId, ctx: &mut Context) -> Result TableFactor { - let decl = ctx.anchor.table_decls.get(&table_ref.source).unwrap(); - - let name = match &decl.relation.kind { - // special case for anchor - RelationKind::ExternRef(TableExternRef::Anchor(anchor_id)) => { - sql_ast::ObjectName(vec![Ident::new(anchor_id.clone())]) - } - - // base case - _ => { - let decl_name = decl.name.clone().unwrap(); - - sql_ast::ObjectName(translate_ident(Some(decl_name), None, ctx)) - } - }; - - TableFactor::Table { - name, - alias: if decl.name == table_ref.name { - None - } else { - table_ref.name.map(|ident| TableAlias { - name: translate_ident_part(ident, ctx), - columns: vec![], - }) - }, - args: None, - with_hints: vec![], - } -} - pub(super) fn translate_sstring( items: Vec>, ctx: &mut Context, @@ -623,23 +589,6 @@ pub(super) fn translate_column_sort( }) } -pub(super) fn translate_join( - (side, with, filter): (JoinSide, TableRef, Expr), - ctx: &mut Context, -) -> Result { - let constraint = JoinConstraint::On(translate_expr_kind(filter.kind, ctx)?); - - Ok(Join { - relation: table_factor_of_tid(with, ctx), - join_operator: match side { - JoinSide::Inner => JoinOperator::Inner(constraint), - JoinSide::Left => JoinOperator::LeftOuter(constraint), - JoinSide::Right => JoinOperator::RightOuter(constraint), - JoinSide::Full => JoinOperator::FullOuter(constraint), - }, - }) -} - /// Translate a PRQL Ident to a Vec of SQL Idents. // We return a vec of SQL Idents because sqlparser sometimes uses // [ObjectName](sql_ast::ObjectName) and sometimes uses @@ -651,7 +600,7 @@ pub(super) fn translate_ident( ctx: &Context, ) -> Vec { let mut parts = Vec::with_capacity(4); - if !ctx.omit_ident_prefix || column.is_none() { + if !ctx.query.omit_ident_prefix || column.is_none() { if let Some(table) = table_name { #[allow(clippy::if_same_then_else)] if ctx.dialect.big_query_quoting() { @@ -954,22 +903,12 @@ mod test { { let query = resolve(parse("from foo")?)?; let (anchor, _) = AnchorContext::of(query); - context_with_concat_function = Context { - dialect: Box::new(GenericDialect {}), - anchor, - omit_ident_prefix: false, - pre_projection: false, - }; + context_with_concat_function = Context::new(Box::new(GenericDialect {}), anchor); } { let query = resolve(parse("from foo")?)?; let (anchor, _) = AnchorContext::of(query); - context_without_concat_function = Context { - dialect: Box::new(SQLiteDialect {}), - anchor, - omit_ident_prefix: false, - pre_projection: false, - }; + context_without_concat_function = Context::new(Box::new(SQLiteDialect {}), anchor); } fn str_lit(s: &str) -> InterpolateItem { diff --git a/prql-compiler/src/sql/gen_query.rs b/prql-compiler/src/sql/gen_query.rs index a109eb8b0aa1..fba04d0be692 100644 --- a/prql-compiler/src/sql/gen_query.rs +++ b/prql-compiler/src/sql/gen_query.rs @@ -6,21 +6,23 @@ use std::collections::HashSet; use std::str::FromStr; use anyhow::{anyhow, Result}; -use enum_as_inner::EnumAsInner; use itertools::Itertools; use sqlparser::ast::{ - self as sql_ast, Ident, Select, SelectItem, SetExpr, TableAlias, TableFactor, TableWithJoins, + self as sql_ast, Ident, Join, JoinConstraint, JoinOperator, Select, SelectItem, SetExpr, + TableAlias, TableFactor, TableWithJoins, }; -use crate::ast::pl::{BinOp, Literal, RelationLiteral}; -use crate::ast::rq::{CId, Expr, ExprKind, Query, Relation, RelationKind, TableDecl, Transform}; +use crate::ast::pl::{BinOp, JoinSide, Literal, RelationLiteral}; +use crate::ast::rq::{CId, Expr, ExprKind, Query, RelationKind, TableRef, Transform}; +use crate::sql::anchor::anchor_split; +use crate::sql::preprocess::SqlRelationKind; use crate::utils::{BreakUp, IntoOnly, Pluck}; use crate::Target; use super::context::AnchorContext; use super::gen_expr::*; use super::gen_projection::*; -use super::preprocess::{self, SqlTransform}; +use super::preprocess::{self, SqlRelation, SqlTransform}; use super::{anchor, Context, Dialect}; pub fn translate_query(query: Query, dialect: Option) -> Result { @@ -36,77 +38,17 @@ pub fn translate_query(query: Query, dialect: Option) -> Result { - // preprocess - let pipeline = Ok(pipeline) - .map(preprocess::normalize) - .map(preprocess::push_down_selects) - .map(preprocess::prune_inputs) - .map(preprocess::wrap) - .and_then(|p| preprocess::distinct(p, &mut context)) - .map(preprocess::union) - .and_then(|p| preprocess::except(p, &context)) - .and_then(|p| preprocess::intersect(p, &context)) - .map(preprocess::reorder)?; - - // load names of output columns - context.anchor.load_names(&pipeline, table.relation.columns); - - // split to atomics - let ats = split_into_atomics(name, pipeline, &mut context.anchor); - - // ensure names for all columns that need it - ensure_names(&ats, &mut context.anchor); - - atomics.extend(ats); - } - RelationKind::Literal(_) | RelationKind::SString(_) => atomics.push(AtomicQuery { - name, - relation: SqlRelation::Super(table.relation.kind), - }), - RelationKind::ExternRef(_) => { - // ref does not need it's own CTE - } - } - } - - // take last table - let main_query = atomics.remove(atomics.len() - 1); - let ctes = atomics; - - // convert each of the CTEs - let ctes: Vec<_> = ctes - .into_iter() - .map(|t| table_to_sql_cte(t, &mut context)) - .try_collect()?; + let mut ctx = Context::new(dialect, anchor); - // convert main query - let mut main_query = sql_query_of_relation(main_query.relation, &mut context)?; + // compile main relation that will recursively compile CTEs + let mut main_query = sql_query_of_sql_relation(main_relation.into(), &mut ctx)?; // attach CTEs - if !ctes.is_empty() { + if !ctx.ctes.is_empty() { main_query.with = Some(sql_ast::With { - cte_tables: ctes, + cte_tables: ctx.ctes.drain(..).collect_vec(), recursive: false, }); } @@ -114,99 +56,188 @@ pub fn translate_query(query: Query, dialect: Option) -> Result Result { + use RelationKind::*; -#[derive(Debug, EnumAsInner)] -enum SqlRelation { - Super(RelationKind), - Pipeline(Vec), -} + // preprocess & split into atomics + match sql_relation.kind { + // base case + SqlRelationKind::Super(Pipeline(pipeline)) => { + // preprocess + let pipeline = Ok(pipeline) + .map(preprocess::normalize) + .map(preprocess::prune_inputs) + .map(preprocess::wrap) + .and_then(|p| preprocess::distinct(p, ctx)) + .map(preprocess::union) + .and_then(|p| preprocess::except(p, ctx)) + .and_then(|p| preprocess::intersect(p, ctx)) + .map(preprocess::reorder)?; + + // load names of output columns + ctx.anchor.load_names(&pipeline, sql_relation.columns); + + sql_query_of_pipeline(pipeline, ctx) + } -fn into_tables( - main_pipeline: Relation, - tables: Vec, - context: &mut Context, -) -> Result> { - let main = TableDecl { - id: context.anchor.tid.gen(), - name: None, - relation: main_pipeline, - }; - Ok([tables, vec![main]].concat()) + // no need to preprocess, has been done already + SqlRelationKind::PreprocessedPipeline(pipeline) => sql_query_of_pipeline(pipeline, ctx), + + // special case: literals + SqlRelationKind::Super(Literal(lit)) => sql_of_sample_data(lit, ctx), + + // special case: s-strings + SqlRelationKind::Super(SString(items)) => translate_query_sstring(items, ctx), + + // ref cannot be converted directly into query and does not need it's own CTE + SqlRelationKind::Super(ExternRef(_)) => unreachable!(), + } } -fn table_to_sql_cte(table: AtomicQuery, context: &mut Context) -> Result { - let alias = sql_ast::TableAlias { - name: translate_ident_part(table.name, context), - columns: vec![], +fn table_factor_of_table_ref(table_ref: TableRef, ctx: &mut Context) -> Result { + let table_ref_alias = (table_ref.name.clone()) + .map(|ident| translate_ident_part(ident, ctx)) + .map(simple_table_alias); + + let decl = ctx.anchor.table_decls.get_mut(&table_ref.source).unwrap(); + + // prepare names + let table_name = match &decl.name { + None => { + decl.name = Some(ctx.anchor.table_name.gen()); + decl.name.clone().unwrap() + } + Some(n) => n.clone(), }; - Ok(sql_ast::Cte { - alias, - query: Box::new(sql_query_of_relation(table.relation, context)?), - from: None, - }) -} -fn sql_query_of_relation(relation: SqlRelation, context: &mut Context) -> Result { - use RelationKind::*; + // ensure that the table is declared + if let Some(sql_relation) = decl.relation.take() { + // if we cannot use CTEs + if ctx.query.forbid_ctes { + // restore relation for other references + decl.relation = Some(sql_relation.clone()); + + // return a sub-query + let query = sql_query_of_sql_relation(sql_relation, ctx)?; + return Ok(TableFactor::Derived { + lateral: false, + subquery: Box::new(query), + alias: table_ref_alias, + }); + } + + let query = sql_query_of_sql_relation(sql_relation, ctx)?; + let alias = sql_ast::TableAlias { + name: translate_ident_part(table_name.clone(), ctx), + columns: vec![], + }; - match relation { - SqlRelation::Super(ExternRef(_)) | SqlRelation::Super(Pipeline(_)) => unreachable!(), - SqlRelation::Pipeline(pipeline) => sql_query_of_pipeline(pipeline, context), - SqlRelation::Super(Literal(lit)) => Ok(sql_of_sample_data(lit, context)?), - SqlRelation::Super(SString(items)) => translate_query_sstring(items, context), + ctx.ctes.push(sql_ast::Cte { + alias, + query: Box::new(query), + from: None, + }) } + + // let name = match &decl.relation { + // // special case for anchor + // // TODO + // // Some(SqlRelationKind::Super(RelationKind::ExternRef(TableExternRef::Anchor( + // // anchor_id, + // // )))) => sql_ast::ObjectName(vec![Ident::new(anchor_id.clone())]), + + // // base case + // _ => { + + // } + // }; + + let name = sql_ast::ObjectName(translate_ident(Some(table_name.clone()), None, ctx)); + + Ok(TableFactor::Table { + name, + alias: if Some(table_name) == table_ref.name { + None + } else { + table_ref_alias + }, + args: None, + with_hints: vec![], + }) +} + +fn translate_join( + (side, with, filter): (JoinSide, TableRef, Expr), + ctx: &mut Context, +) -> Result { + let relation = table_factor_of_table_ref(with, ctx)?; + + let constraint = JoinConstraint::On(translate_expr_kind(filter.kind, ctx)?); + + Ok(Join { + relation, + join_operator: match side { + JoinSide::Inner => JoinOperator::Inner(constraint), + JoinSide::Left => JoinOperator::LeftOuter(constraint), + JoinSide::Right => JoinOperator::RightOuter(constraint), + JoinSide::Full => JoinOperator::FullOuter(constraint), + }, + }) } fn sql_query_of_pipeline( - pipeline: Vec, - context: &mut Context, + mut pipeline: Vec, + ctx: &mut Context, ) -> Result { use SqlTransform::*; + // special case: loop + if pipeline.iter().any(|t| matches!(t, Loop(_))) { + pipeline = sql_of_loop(pipeline, ctx)?; + } + + // extract an atomic pipeline from back of the pipeline and stash preceding part into context + let pipeline = extract_atomic(pipeline, &mut ctx.anchor); + + // ensure names for all columns that need it + ensure_names(&pipeline, &mut ctx.anchor); + let (select, set_ops) = pipeline.break_up(|t| matches!(t, Union { .. } | Except { .. } | Intersect { .. })); - let select = sql_select_query_of_pipeline(select, context)?; + let select = sql_select_query_of_pipeline(select, ctx)?; - sql_set_ops_of_pipeline(select, set_ops, context) + sql_set_ops_of_pipeline(select, set_ops, ctx) } fn sql_select_query_of_pipeline( mut pipeline: Vec, - context: &mut Context, + ctx: &mut Context, ) -> Result { let table_count = count_tables(&pipeline); log::debug!("atomic query contains {table_count} tables"); - context.omit_ident_prefix = table_count == 1; - - context.pre_projection = true; - - let projection = pipeline - .pluck(|t| t.into_super_and(|t| t.into_select())) - .into_only() - .unwrap(); - let projection = translate_wildcards(&context.anchor, projection); - let projection = translate_select_items(projection.0, projection.1, context)?; + ctx.push_query(); + ctx.query.omit_ident_prefix = table_count == 1; + ctx.query.pre_projection = true; - let mut from = pipeline + let mut from: Vec<_> = pipeline .pluck(|t| t.into_super_and(|t| t.into_from())) .into_iter() - .map(|source| TableWithJoins { - relation: table_factor_of_tid(source, context), - joins: vec![], + .map(|source| -> Result { + Ok(TableWithJoins { + relation: table_factor_of_table_ref(source, ctx)?, + joins: vec![], + }) }) - .collect::>(); + .try_collect()?; let joins = pipeline .pluck(|t| t.into_super_and(|t| t.into_join())) .into_iter() - .map(|j| translate_join(j, context)) + .map(|j| translate_join(j, ctx)) .collect::>>()?; if !joins.is_empty() { if let Some(from) = from.last_mut() { @@ -216,6 +247,13 @@ fn sql_select_query_of_pipeline( } } + let projection = pipeline + .pluck(|t| t.into_super_and(|t| t.into_select())) + .into_only() + .unwrap(); + let projection = translate_wildcards(&ctx.anchor, projection); + let projection = translate_select_items(projection.0, projection.1, ctx)?; + let sorts = pipeline.pluck(|t| t.into_super_and(|t| t.into_sort())); let takes = pipeline.pluck(|t| t.into_super_and(|t| t.into_take())); let distinct = pipeline.iter().any(|t| matches!(t, SqlTransform::Distinct)); @@ -231,11 +269,11 @@ fn sql_select_query_of_pipeline( // WHERE and HAVING let where_ = filter_of_conditions( before_agg.pluck(|t| t.into_super_and(|t| t.into_filter())), - context, + ctx, )?; let having = filter_of_conditions( after_agg.pluck(|t| t.into_super_and(|t| t.into_filter())), - context, + ctx, )?; // GROUP BY @@ -244,9 +282,9 @@ fn sql_select_query_of_pipeline( .into_iter() .next(); let group_by: Vec = aggregate.map(|(part, _)| part).unwrap_or_default(); - let group_by = try_into_exprs(group_by, context, None)?; + let group_by = try_into_exprs(group_by, ctx, None)?; - context.pre_projection = false; + ctx.query.pre_projection = false; let ranges = takes.into_iter().map(|x| x.range).collect(); let take = range_of_ranges(ranges)?; @@ -257,7 +295,7 @@ fn sql_select_query_of_pipeline( None } else { Some(sqlparser::ast::Offset { - value: translate_expr_kind(ExprKind::Literal(Literal::Integer(offset)), context)?, + value: translate_expr_kind(ExprKind::Literal(Literal::Integer(offset)), ctx)?, rows: sqlparser::ast::OffsetRows::None, }) }; @@ -268,17 +306,20 @@ fn sql_select_query_of_pipeline( .map(|sorts| { sorts .iter() - .map(|s| translate_column_sort(s, context)) + .map(|s| translate_column_sort(s, ctx)) .try_collect() }) .transpose()? .unwrap_or_default(); - let (top, limit) = if context.dialect.use_top() { - (limit.map(|l| top_of_i64(l, context)), None) + let (top, limit) = if ctx.dialect.use_top() { + (limit.map(|l| top_of_i64(l, ctx)), None) } else { (None, limit.map(expr_of_i64)) }; + + ctx.pop_query(); + Ok(sql_ast::Query { order_by, limit, @@ -322,36 +363,7 @@ fn sql_set_ops_of_pipeline( }; // prepare top - let top_is_simple = top.with.is_none() - && top.order_by.is_empty() - && top.limit.is_none() - && top.offset.is_none() - && top.fetch.is_none() - && top.locks.is_empty(); - - let left = if top_is_simple { - top.body - } else { - // top is not simple, so we need to wrap it into - // `SELECT * FROM top` - Box::new(SetExpr::Select(Box::new(Select { - projection: vec![SelectItem::Wildcard( - sql_ast::WildcardAdditionalOptions::default(), - )], - from: vec![TableWithJoins { - relation: TableFactor::Derived { - lateral: false, - subquery: Box::new(top), - alias: Some(TableAlias { - name: Ident::new(context.anchor.table_name.gen()), - columns: Vec::new(), - }), - }, - joins: vec![], - }], - ..default_select() - }))) - }; + let left = query_to_set_expr(top, context); top = default_query(SetExpr::SetOperation { left, @@ -360,7 +372,7 @@ fn sql_set_ops_of_pipeline( sql_ast::WildcardAdditionalOptions::default(), )], from: vec![TableWithJoins { - relation: table_factor_of_tid(bottom, context), + relation: table_factor_of_table_ref(bottom, context)?, joins: vec![], }], ..default_select() @@ -381,6 +393,99 @@ fn sql_set_ops_of_pipeline( Ok(top) } +fn sql_of_loop(pipeline: Vec, ctx: &mut Context) -> Result> { + // split the pipeline + let (mut initial, mut following) = pipeline.break_up(|t| matches!(t, SqlTransform::Loop(_))); + let loop_ = following.remove(0); + let step = loop_.into_loop().unwrap(); + + // RECURSIVE can only follow WITH directly, which means that if we want to use it for + // an arbitrary query, we have to defined a *nested* WITH RECURSIVE and not use + // the top-level list of CTEs. + + // determine columns of the initial table + let recursive_columns = AnchorContext::determine_select_columns(&initial); + + // do the same thing we do when splitting a pipeline + // (defining new columns, redirecting cids) + let recursive_columns = SqlTransform::Super(Transform::Select(recursive_columns)); + initial.push(recursive_columns.clone()); + let step = anchor_split(&mut ctx.anchor, initial, step); + let from = step.first().unwrap().as_super().unwrap().as_from().unwrap(); + + let initial = ctx.anchor.table_decls.get_mut(&from.source).unwrap(); + initial.name = Some("loop".to_string()); + let initial_relation = initial.relation.take().unwrap(); + + let initial = initial_relation.kind.into_preprocessed_pipeline().unwrap(); + + // compile initial + let initial = query_to_set_expr(sql_query_of_pipeline(initial, ctx)?, ctx); + + // compile step (without producing CTEs) + ctx.push_query(); + ctx.query.forbid_ctes = true; + + let step = query_to_set_expr(sql_query_of_pipeline(step, ctx)?, ctx); + + ctx.pop_query(); + + // build CTE and it's SELECT + let cte = sql_ast::Cte { + alias: simple_table_alias(Ident::new("loop")), + query: Box::new(default_query(SetExpr::SetOperation { + op: sql_ast::SetOperator::Union, + set_quantifier: sql_ast::SetQuantifier::All, + left: initial, + right: step, + })), + from: None, + }; + let query = Box::new(sql_ast::Query { + with: Some(sql_ast::With { + recursive: true, + cte_tables: vec![cte], + }), + ..default_query(sql_ast::SetExpr::Select(Box::new(sql_ast::Select { + projection: vec![SelectItem::Wildcard( + sql_ast::WildcardAdditionalOptions::default(), + )], + from: vec![TableWithJoins { + relation: TableFactor::Table { + name: sql_ast::ObjectName(vec![Ident::new("loop")]), + alias: None, + args: None, + with_hints: Vec::new(), + }, + joins: vec![], + }], + ..default_select() + }))) + }); + + // create a split between the loop SELECT statement and the following pipeline + let mut following = anchor_split(&mut ctx.anchor, vec![recursive_columns], following); + + let from = following.first_mut().unwrap(); + let from = from.as_super().unwrap().as_from().unwrap(); + + // this will be table decl that references the whole loop expression + let loop_decl = ctx.anchor.table_decls.get_mut(&from.source).unwrap(); + + let loop_name = ctx.anchor.table_name.gen(); + loop_decl.name = Some(loop_name.clone()); + loop_decl.relation = None; + + // push the whole thing into WITH of the main query + ctx.ctes.push(sql_ast::Cte { + alias: simple_table_alias(Ident::new(loop_name)), + query, + from: None, + }); + + Ok(following) +} + fn sql_of_sample_data(data: RelationLiteral, ctx: &Context) -> Result { // TODO: this could be made to use VALUES instead of SELECT UNION ALL SELECT // I'm not sure about compatibility though. @@ -416,121 +521,65 @@ fn sql_of_sample_data(data: RelationLiteral, ctx: &Context) -> Result, - ctx: &mut AnchorContext, -) -> Vec { - let outputs_cid = AnchorContext::determine_select_columns(&pipeline); - - let mut required_cols = outputs_cid.clone(); - - // split pipeline, back to front - let mut parts_rev = Vec::new(); - loop { - let (preceding, split) = anchor::split_off_back(ctx, required_cols, pipeline); - - if let Some((preceding, cols_at_split)) = preceding { - log::debug!( - "pipeline split after {}", - preceding.last().unwrap().as_str() - ); - parts_rev.push((split, cols_at_split.clone())); - - pipeline = preceding; - required_cols = cols_at_split; - } else { - parts_rev.push((split, Vec::new())); - break; - } - } - parts_rev.reverse(); - let mut parts = parts_rev; +/// Extract last part of pipeline that is able to "fit" into a single SELECT statement. +/// Remaining proceeding pipeline is declared as a table and stored in AnchorContext. +fn extract_atomic(pipeline: Vec, ctx: &mut AnchorContext) -> Vec { + let (preceding, atomic) = anchor::split_off_back(pipeline, ctx); - // sometimes, additional columns will be added into select, which have to - // be filtered out here, using additional CTE - if let Some((pipeline, _)) = parts.last() { - let select_cols = pipeline - .first() - .unwrap() - .as_super() - .unwrap() - .as_select() - .unwrap(); - - if select_cols.iter().any(|c| !outputs_cid.contains(c)) { - parts.push(( - vec![SqlTransform::Super(Transform::Select(outputs_cid))], - select_cols.clone(), - )); - } - } + if let Some(preceding) = preceding { + log::debug!( + "pipeline split after {}", + preceding.last().unwrap().as_str() + ); - // add names to pipelines, anchor, front to back - let mut atomics = Vec::with_capacity(parts.len()); - let last = parts.pop().unwrap(); - - let last_pipeline = if parts.is_empty() { - last.0 + anchor::anchor_split(ctx, preceding, atomic) } else { - // this code chunk is bloated but I cannot find a more concise alternative - let first = parts.remove(0); - - let first_name = ctx.table_name.gen(); - atomics.push(AtomicQuery { - name: first_name.clone(), - relation: SqlRelation::Pipeline(first.0), - }); - - let mut prev_name = first_name; - for (pipeline, cols_before) in parts.into_iter() { - let name = ctx.table_name.gen(); - let pipeline = anchor::anchor_split(ctx, &prev_name, &cols_before, pipeline); - - atomics.push(AtomicQuery { - name: name.clone(), - relation: SqlRelation::Pipeline(pipeline), - }); - - prev_name = name; - } - - anchor::anchor_split(ctx, &prev_name, &last.1, last.0) - }; - atomics.push(AtomicQuery { - name, - relation: SqlRelation::Pipeline(last_pipeline), - }); + atomic + } - atomics + // TODO + // sometimes, additional columns will be added into select, which have to + // be filtered out here, using additional CTE + // if let Some((pipeline, _)) = parts.last() { + // let select_cols = pipeline + // .first() + // .unwrap() + // .as_super() + // .unwrap() + // .as_select() + // .unwrap(); + + // if select_cols.iter().any(|c| !outputs_cid.contains(c)) { + // parts.push(( + // vec![SqlTransform::Super(Transform::Select(outputs_cid))], + // select_cols.clone(), + // )); + // } + // } } -fn ensure_names(atomics: &[AtomicQuery], ctx: &mut AnchorContext) { - // ensure column names for columns that need it - for a in atomics { - let empty = HashSet::new(); - for t in a.relation.as_pipeline().unwrap() { - match t { - SqlTransform::Super(Transform::Sort(_)) => { - for r in anchor::get_requirements(t, &empty) { - ctx.ensure_column_name(r.col); - } +fn ensure_names(transforms: &[SqlTransform], ctx: &mut AnchorContext) { + let empty = HashSet::new(); + for t in transforms { + match t { + SqlTransform::Super(Transform::Sort(_)) => { + for r in anchor::get_requirements(t, &empty) { + ctx.ensure_column_name(r.col); } - SqlTransform::Super(Transform::Select(cids)) => { - for cid in cids { - let _decl = &ctx.column_decls[cid]; - //let name = match decl { - // ColumnDecl::RelationColumn(_, _, _) => todo!(), - // ColumnDecl::Compute(_) => ctx.column_names[..], - //}; - } + } + SqlTransform::Super(Transform::Select(cids)) => { + for cid in cids { + let _decl = &ctx.column_decls[cid]; + //let name = match decl { + // ColumnDecl::RelationColumn(_, _, _) => todo!(), + // ColumnDecl::Compute(_) => ctx.column_names[..], + //}; } - _ => (), } + _ => (), } } } - fn filter_of_conditions(exprs: Vec, context: &mut Context) -> Result> { Ok(if let Some(cond) = all(exprs) { Some(translate_expr_kind(cond.kind, context)?) @@ -584,6 +633,45 @@ fn default_select() -> Select { } } +fn simple_table_alias(name: Ident) -> TableAlias { + TableAlias { + name, + columns: Vec::new(), + } +} + +fn query_to_set_expr(query: sql_ast::Query, context: &mut Context) -> Box { + let is_simple = query.with.is_none() + && query.order_by.is_empty() + && query.limit.is_none() + && query.offset.is_none() + && query.fetch.is_none() + && query.locks.is_empty(); + + if is_simple { + return query.body; + } + + // query is not simple, so we need to wrap it into + // `SELECT * FROM (query)` + Box::new(SetExpr::Select(Box::new(Select { + projection: vec![SelectItem::Wildcard( + sql_ast::WildcardAdditionalOptions::default(), + )], + from: vec![TableWithJoins { + relation: TableFactor::Derived { + lateral: false, + subquery: Box::new(query), + alias: Some(simple_table_alias(Ident::new( + context.anchor.table_name.gen(), + ))), + }, + joins: vec![], + }], + ..default_select() + }))) +} + fn count_tables(transforms: &[SqlTransform]) -> usize { let mut count = 0; for transform in transforms { @@ -603,19 +691,36 @@ mod test { fn parse_and_resolve(prql: &str) -> Result<(Vec, Context)> { let query = resolve(parse(prql)?)?; - let (anchor, query) = AnchorContext::of(query); - let context = Context { - dialect: Box::new(GenericDialect {}), - anchor, - omit_ident_prefix: false, - pre_projection: false, - }; + let (anchor, main_relation) = AnchorContext::of(query); + let context = Context::new(Box::new(GenericDialect {}), anchor); - let pipeline = query.relation.kind.into_pipeline().unwrap(); + let pipeline = main_relation.kind.into_pipeline().unwrap(); Ok((preprocess::reorder(preprocess::wrap(pipeline)), context)) } + fn count_atomics(prql: &str) -> usize { + let (mut pipeline, mut context) = parse_and_resolve(prql).unwrap(); + context.anchor.table_decls.clear(); + + let mut atomics = 0; + loop { + let _ = extract_atomic(pipeline, &mut context.anchor); + atomics += 1; + + if let Some((_, decl)) = context.anchor.table_decls.drain().next() { + if let Some(relation) = decl.relation { + if let SqlRelationKind::PreprocessedPipeline(p) = relation.kind { + pipeline = p; + continue; + } + } + } + break; + } + atomics + } + #[test] fn test_ctes_of_pipeline() { // One aggregate, take at the end @@ -627,9 +732,7 @@ mod test { take 20 "###; - let (pipeline, mut context) = parse_and_resolve(prql).unwrap(); - let queries = split_into_atomics("".to_string(), pipeline, &mut context.anchor); - assert_eq!(queries.len(), 1); + assert_eq!(count_atomics(prql), 1); // One aggregate, but take at the top let prql: &str = r###" @@ -640,9 +743,7 @@ mod test { sort sal "###; - let (pipeline, mut context) = parse_and_resolve(prql).unwrap(); - let queries = split_into_atomics("".to_string(), pipeline, &mut context.anchor); - assert_eq!(queries.len(), 2); + assert_eq!(count_atomics(prql), 2); // A take, then two aggregates let prql: &str = r###" @@ -654,9 +755,7 @@ mod test { sort sal2 "###; - let (pipeline, mut context) = parse_and_resolve(prql).unwrap(); - let queries = split_into_atomics("".to_string(), pipeline, &mut context.anchor); - assert_eq!(queries.len(), 3); + assert_eq!(count_atomics(prql), 3); // A take, then a select let prql: &str = r###" @@ -665,9 +764,7 @@ mod test { select first_name "###; - let (pipeline, mut context) = parse_and_resolve(prql).unwrap(); - let queries = split_into_atomics("".to_string(), pipeline, &mut context.anchor); - assert_eq!(queries.len(), 1); + assert_eq!(count_atomics(prql), 1); } #[test] @@ -719,7 +816,7 @@ mod test { *, RANK() OVER () AS rank FROM - table_1 + table_1 AS table_0 WHERE country = 'USA' "###); @@ -744,7 +841,7 @@ mod test { SELECT * FROM - table_1 + table_1 AS table_0 WHERE _expr_0 > 3 "###); diff --git a/prql-compiler/src/sql/mod.rs b/prql-compiler/src/sql/mod.rs index 76b8fe6b11dc..8e3c3da14c36 100644 --- a/prql-compiler/src/sql/mod.rs +++ b/prql-compiler/src/sql/mod.rs @@ -60,6 +60,18 @@ struct Context { pub dialect: Box, pub anchor: AnchorContext, + // stuff regarding current query + query: QueryOpts, + + // stuff regarding parent queries + query_stack: Vec, + + pub ctes: Vec, +} + +#[derive(Default, Clone)] +struct QueryOpts { + /// When true, column references will not include table names prefixes. pub omit_ident_prefix: bool, /// True iff codegen should generate expressions before SELECT's projection is applied. @@ -67,6 +79,29 @@ struct Context { /// - WHERE needs `pre_projection=true`, but /// - ORDER BY needs `pre_projection=false`. pub pre_projection: bool, + + /// When true, queries will contain nested sub-queries instead of WITH CTEs. + pub forbid_ctes: bool, +} + +impl Context { + fn new(dialect: Box, anchor: AnchorContext) -> Self { + Context { + dialect, + anchor, + query: QueryOpts::default(), + query_stack: Vec::new(), + ctes: Vec::new(), + } + } + + fn push_query(&mut self) { + self.query_stack.push(self.query.clone()); + } + + fn pop_query(&mut self) { + self.query = self.query_stack.pop().unwrap(); + } } #[cfg(test)] diff --git a/prql-compiler/src/sql/preprocess.rs b/prql-compiler/src/sql/preprocess.rs index 7c04c4cbf7cb..035f6858dd30 100644 --- a/prql-compiler/src/sql/preprocess.rs +++ b/prql-compiler/src/sql/preprocess.rs @@ -10,7 +10,8 @@ use crate::ast::pl::{ BinOp, ColumnSort, InterpolateItem, JoinSide, Literal, Range, WindowFrame, WindowKind, }; use crate::ast::rq::{ - self, new_binop, CId, Compute, Expr, ExprKind, RqFold, TableRef, Transform, Window, + self, new_binop, CId, Compute, Expr, ExprKind, Relation, RelationColumn, RelationKind, RqFold, + TableRef, Transform, Window, }; use crate::error::Error; use crate::sql::context::AnchorContext; @@ -18,31 +19,45 @@ use crate::sql::context::AnchorContext; use super::anchor::{infer_complexity, CidCollector, Complexity}; use super::Context; -#[derive(Debug, EnumAsInner, strum::AsRefStr)] +#[derive(Debug, Clone, EnumAsInner)] +pub(super) enum SqlRelationKind { + Super(RelationKind), + PreprocessedPipeline(Vec), +} + +#[derive(Debug, Clone)] +pub(super) struct SqlRelation { + pub kind: SqlRelationKind, + pub columns: Vec, +} + +#[derive(Debug, Clone, EnumAsInner, strum::AsRefStr)] pub(super) enum SqlTransform { Super(Transform), Distinct, Except { bottom: TableRef, distinct: bool }, Intersect { bottom: TableRef, distinct: bool }, Union { bottom: TableRef, distinct: bool }, + Loop(Vec), } -/// Pushes all [Transform::Select]s to the back of the pipeline. -pub(super) fn push_down_selects(pipeline: Vec) -> Vec { - let mut select = None; - let mut res = Vec::with_capacity(pipeline.len()); - for t in pipeline { - if let Transform::Select(_) = t { - select = Some(t); - } else { - res.push(t); - } - } - if let Some(select) = select { - res.push(select); - } - res -} +// This function was disabled because it changes semantics of the pipeline in some cases. +// /// Pushes all [Transform::Select]s to the back of the pipeline. +// pub(super) fn push_down_selects(pipeline: Vec) -> Vec { +// let mut select = None; +// let mut res = Vec::with_capacity(pipeline.len()); +// for t in pipeline { +// if let Transform::Select(_) = t { +// select = Some(t); +// } else { +// res.push(t); +// } +// } +// if let Some(select) = select { +// res.push(select); +// } +// res +// } /// Removes unused relation inputs pub(super) fn prune_inputs(mut pipeline: Vec) -> Vec { @@ -76,7 +91,12 @@ pub(super) fn prune_inputs(mut pipeline: Vec) -> Vec { } pub(super) fn wrap(pipe: Vec) -> Vec { - pipe.into_iter().map(SqlTransform::Super).collect() + pipe.into_iter() + .map(|t| match t { + Transform::Loop(pipeline) => SqlTransform::Loop(wrap(pipeline)), + _ => SqlTransform::Super(t), + }) + .collect() } /// Creates [SqlTransform::Distinct] from [Transform::Take] @@ -557,6 +577,15 @@ impl SqlTransform { } } +impl From for SqlRelation { + fn from(rel: Relation) -> Self { + SqlRelation { + kind: SqlRelationKind::Super(rel.kind), + columns: rel.columns, + } + } +} + pub(super) trait SqlFold: RqFold { fn fold_sql_transforms(&mut self, transforms: Vec) -> Result> { transforms @@ -581,6 +610,7 @@ pub(super) trait SqlFold: RqFold { bottom: self.fold_table_ref(bottom)?, distinct, }, + SqlTransform::Loop(pipeline) => SqlTransform::Loop(self.fold_sql_transforms(pipeline)?), }) } } diff --git a/prql-compiler/src/sql/snapshots/prql_compiler__sql__gen_query__test__variable_after_aggregate.snap b/prql-compiler/src/sql/snapshots/prql_compiler__sql__gen_query__test__variable_after_aggregate.snap index 5b7e140a157a..1164db5605aa 100644 --- a/prql-compiler/src/sql/snapshots/prql_compiler__sql__gen_query__test__variable_after_aggregate.snap +++ b/prql-compiler/src/sql/snapshots/prql_compiler__sql__gen_query__test__variable_after_aggregate.snap @@ -16,6 +16,7 @@ SELECT title, AVG(_expr_0) AS avg_salary FROM - table_1 + table_1 AS table_0 GROUP BY title + diff --git a/prql-compiler/src/test.rs b/prql-compiler/src/test.rs index fbe73829bf12..4b3f16018b5f 100644 --- a/prql-compiler/src/test.rs +++ b/prql-compiler/src/test.rs @@ -205,7 +205,7 @@ fn test_append() { take 10 ) "###).unwrap(), @r###" - WITH table_1 AS ( + WITH table_0 AS ( SELECT *, name, @@ -227,13 +227,13 @@ fn test_append() { employees LIMIT 3 - ) AS table_3 + ) AS table_2 UNION ALL SELECT * FROM - table_1 AS table_0 + table_0 AS table_1 "###); assert_display_snapshot!(compile(r###" @@ -310,7 +310,7 @@ fn test_remove() { ) "#).unwrap(), @r###" - WITH table_1 AS ( + WITH table_0 AS ( SELECT artist_id FROM @@ -325,7 +325,7 @@ fn test_remove() { SELECT * FROM - table_1 AS table_0 + table_0 AS table_1 "### ); @@ -337,7 +337,7 @@ fn test_remove() { ) "#).unwrap(), @r###" - WITH table_1 AS ( + WITH table_0 AS ( SELECT artist_id FROM @@ -348,9 +348,9 @@ fn test_remove() { album.title FROM album - LEFT JOIN table_1 AS table_0 ON album.artist_id = table_0.artist_id + LEFT JOIN table_0 AS table_1 ON album.artist_id = table_1.artist_id WHERE - table_0.artist_id IS NULL + table_1.artist_id IS NULL "### ); @@ -382,11 +382,11 @@ fn test_remove() { album ) SELECT - table_1.artist_id, - table_1.title + table_0.artist_id, + table_0.title FROM - table_1 - LEFT JOIN bottom AS b ON table_1.artist_id = b.* + table_1 AS table_0 + LEFT JOIN bottom AS b ON table_0.artist_id = b.* WHERE b.* IS NULL "### @@ -443,7 +443,7 @@ fn test_intersect() { ) "#).unwrap(), @r###" - WITH table_1 AS ( + WITH table_0 AS ( SELECT artist_id FROM @@ -458,7 +458,7 @@ fn test_intersect() { SELECT * FROM - table_1 AS table_0 + table_0 AS table_1 "### ); @@ -474,22 +474,28 @@ fn test_intersect() { distinct "#).unwrap(), @r###" - WITH table_1 AS ( + WITH table_0 AS ( SELECT artist_id FROM artist + ), + table_3 AS ( + SELECT + artist_id + FROM + album + INTERSECT + DISTINCT + SELECT + * + FROM + table_0 AS table_1 ) SELECT - artist_id + DISTINCT artist_id FROM - album - INTERSECT - DISTINCT - SELECT - * - FROM - table_1 AS table_0 + table_3 AS table_2 "### ); @@ -504,22 +510,28 @@ fn test_intersect() { distinct "#).unwrap(), @r###" - WITH table_1 AS ( + WITH table_0 AS ( SELECT artist_id FROM artist + ), + table_3 AS ( + SELECT + artist_id + FROM + album + INTERSECT + ALL + SELECT + * + FROM + table_0 AS table_1 ) SELECT - artist_id - FROM - album - INTERSECT - DISTINCT - SELECT - * + DISTINCT artist_id FROM - table_1 AS table_0 + table_3 AS table_2 "### ); @@ -534,7 +546,7 @@ fn test_intersect() { ) "#).unwrap(), @r###" - WITH table_1 AS ( + WITH table_0 AS ( SELECT artist_id FROM @@ -549,7 +561,7 @@ fn test_intersect() { SELECT * FROM - table_1 AS table_0 + table_0 AS table_1 "### ); @@ -574,28 +586,28 @@ fn test_rn_ids_are_unique() { take 3 ) "###).unwrap()), @r###" - WITH table_1 AS ( + WITH table_3 AS ( SELECT *, - ROW_NUMBER() OVER (PARTITION BY y_id) AS _expr_0 + ROW_NUMBER() OVER (PARTITION BY y_id) AS _expr_1 FROM y_orig ), - table_2 AS ( + table_1 AS ( SELECT *, - ROW_NUMBER() OVER (PARTITION BY x_id) AS _expr_1 + ROW_NUMBER() OVER (PARTITION BY x_id) AS _expr_0 FROM - table_1 + table_3 AS table_2 WHERE - _expr_0 <= 2 + _expr_1 <= 2 ) SELECT * FROM - table_2 + table_1 AS table_0 WHERE - _expr_1 <= 3 + _expr_0 <= 3 "###); } @@ -690,19 +702,13 @@ fn test_sorts() { select [renamed = somefield] "### ).unwrap()), @r###" - WITH table_1 AS ( - SELECT - 'something' AS renamed, - 'something' AS _expr_0 - FROM - x - ORDER BY - _expr_0 - ) SELECT - renamed + 'something' AS renamed, + 'something' AS _expr_0 FROM - table_1 + x + ORDER BY + _expr_0 "###); } @@ -877,7 +883,7 @@ fn test_window_functions_02() { order_day ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ) AS num_books_last_week FROM - table_1 + table_1 AS table_0 ORDER BY order_day "###); @@ -1261,7 +1267,7 @@ fn test_take() { SELECT * FROM - table_1 + table_1 AS table_0 ORDER BY name LIMIT @@ -1340,7 +1346,7 @@ fn test_distinct() { SELECT * FROM - table_1 + table_1 AS table_0 WHERE rn > 2 "###); @@ -1397,7 +1403,7 @@ fn test_distinct() { SELECT * FROM - table_1 + table_1 AS table_0 WHERE _expr_0 <= 3 "###); @@ -1420,7 +1426,7 @@ fn test_distinct() { SELECT * FROM - table_1 + table_1 AS table_0 WHERE _expr_0 BETWEEN 2 AND 3 "###); @@ -1443,7 +1449,7 @@ fn test_distinct() { SELECT * FROM - table_1 + table_1 AS table_0 WHERE _expr_0 = 4 "###); @@ -1819,16 +1825,7 @@ fn test_prql_to_sql_table() { let sql = compile(query).unwrap(); assert_display_snapshot!(sql, @r###" - WITH average_salaries AS ( - SELECT - country, - AVG(salary) AS average_country_salary - FROM - salaries - GROUP BY - country - ), - newest_employees AS ( + WITH newest_employees AS ( SELECT * FROM @@ -1837,6 +1834,14 @@ fn test_prql_to_sql_table() { tenure LIMIT 50 + ), average_salaries AS ( + SELECT + country, + AVG(salary) AS average_country_salary + FROM + salaries + GROUP BY + country ) SELECT newest_employees.name, @@ -1870,7 +1875,7 @@ fn test_nonatomic() { "###; assert_display_snapshot!((compile(query).unwrap()), @r###" - WITH table_1 AS ( + WITH table_3 AS ( SELECT title, country, @@ -1879,13 +1884,13 @@ fn test_nonatomic() { employees LIMIT 20 - ), table_2 AS ( + ), table_1 AS ( SELECT title, country, AVG(salary) AS _expr_0 FROM - table_1 + table_3 AS table_2 WHERE country = 'USA' GROUP BY @@ -1897,7 +1902,7 @@ fn test_nonatomic() { country, AVG(_expr_0) AS sum_gross_cost FROM - table_2 + table_1 AS table_0 GROUP BY title, country @@ -1950,7 +1955,7 @@ fn test_nonatomic_table() { "###; assert_display_snapshot!((compile(query).unwrap()), @r###" - WITH table_0 AS ( + WITH table_1 AS ( SELECT country FROM @@ -1962,7 +1967,7 @@ fn test_nonatomic_table() { country, count(*) FROM - table_0 + table_1 AS table_0 GROUP BY country ) @@ -1999,12 +2004,12 @@ fn test_table_names_between_splits() { 10 ) SELECT - table_1.emp_no, - table_1.name, + table_0.emp_no, + table_0.name, s.salary FROM - table_1 - JOIN salaries AS s ON table_1.emp_no = s.emp_no + table_1 AS table_0 + JOIN salaries AS s ON table_0.emp_no = s.emp_no "###); let prql = r###" @@ -2024,11 +2029,11 @@ fn test_table_names_between_splits() { 10 ) SELECT - table_1.*, + table_0.*, salaries.salary FROM - table_1 - JOIN salaries ON table_1.emp_no = salaries.emp_no + table_1 AS table_0 + JOIN salaries ON table_0.emp_no = salaries.emp_no "###); } @@ -2308,12 +2313,6 @@ fn test_toposort() { * FROM somesource - ), - a AS ( - SELECT - * - FROM - b ) SELECT * @@ -2333,7 +2332,7 @@ fn test_inline_tables() { join s = (from salaries | select [emp_id, salary]) [==emp_id] "###).unwrap(), @r###" - WITH table_1 AS ( + WITH table_0 AS ( SELECT emp_id, salary @@ -2346,11 +2345,11 @@ fn test_inline_tables() { employees.surname, employees.type, employees.amount, - table_0.emp_id, - table_0.salary + table_1.emp_id, + table_1.salary FROM employees - JOIN table_1 AS table_0 ON employees.emp_id = table_0.emp_id + JOIN table_0 AS table_1 ON employees.emp_id = table_1.emp_id "### ); } @@ -2435,7 +2434,7 @@ fn test_table_s_string() { s"SELECT DISTINCT ON first_name, age FROM employees ORDER BY age ASC" "###).unwrap(), @r###" - WITH table_1 AS ( + WITH table_0 AS ( SELECT DISTINCT ON first_name, age @@ -2446,7 +2445,7 @@ fn test_table_s_string() { ) SELECT FROM - table_1 AS table_0 + table_0 AS table_1 "### ); @@ -2457,7 +2456,7 @@ fn test_table_s_string() { join s = s"SELECT * FROM salaries" [==id] "###).unwrap(), @r###" - WITH table_2 AS ( + WITH table_0 AS ( SELECT DISTINCT ON first_name, id, @@ -2467,18 +2466,18 @@ fn test_table_s_string() { ORDER BY age ASC ), - table_3 AS ( + table_1 AS ( SELECT * FROM salaries ) SELECT - table_0.*, - table_1.* + table_2.*, + table_3.* FROM - table_2 AS table_0 - JOIN table_3 AS table_1 ON table_0.id = table_1.id + table_0 AS table_2 + JOIN table_1 AS table_3 ON table_2.id = table_3.id "### ); @@ -2487,7 +2486,7 @@ fn test_table_s_string() { filter country == "USA" "###).unwrap(), @r###" - WITH table_1 AS ( + WITH table_0 AS ( SELECT * FROM @@ -2496,7 +2495,7 @@ fn test_table_s_string() { SELECT * FROM - table_1 AS table_0 + table_0 AS table_1 WHERE country = 'USA' "### @@ -2507,7 +2506,7 @@ fn test_table_s_string() { filter e.country == "USA" "###).unwrap(), @r###" - WITH table_1 AS ( + WITH table_0 AS ( SELECT * FROM @@ -2516,7 +2515,7 @@ fn test_table_s_string() { SELECT * FROM - table_1 AS table_0 + table_0 AS table_1 WHERE country = 'USA' "### @@ -2529,7 +2528,7 @@ fn test_table_s_string() { weeks_between @2022-06-03 (current_week + 4) "###).unwrap(), @r###" - WITH table_1 AS ( + WITH table_0 AS ( SELECT generate_series( DATE '2022-06-03', @@ -2539,7 +2538,7 @@ fn test_table_s_string() { ) SELECT FROM - table_1 AS table_0 + table_0 AS table_1 "### ); @@ -2547,7 +2546,7 @@ fn test_table_s_string() { s"SELECT * FROM {default_db.x}" "###).unwrap(), @r###" - WITH table_1 AS ( + WITH table_0 AS ( SELECT * FROM @@ -2555,7 +2554,7 @@ fn test_table_s_string() { ) SELECT FROM - table_1 AS table_0 + table_0 AS table_1 "### ); } @@ -2655,13 +2654,13 @@ fn test_group_all() { 10 ) SELECT - table_1.*, + table_0.*, SUM(salaries.salary) AS sal FROM - table_1 - JOIN salaries ON table_1.emp_no = salaries.emp_no + table_1 AS table_0 + JOIN salaries ON table_0.emp_no = salaries.emp_no GROUP BY - table_1.* + table_0.* "### ); @@ -2692,7 +2691,7 @@ fn test_output_column_deduplication() { SELECT * FROM - table_1 + table_1 AS table_0 WHERE r = 1 "### @@ -2766,7 +2765,7 @@ fn test_switch() { category, COUNT(*) FROM - table_1 + table_1 AS table_0 GROUP BY category "### @@ -3151,7 +3150,7 @@ a,b,c select [b, c] "#).unwrap(), @r###" - WITH table_1 AS ( + WITH table_0 AS ( SELECT '1' AS a, '2' AS b, @@ -3167,7 +3166,7 @@ a,b,c b, c FROM - table_1 AS table_0 + table_0 AS table_1 "### ); @@ -3178,7 +3177,7 @@ a,b,c select [b, c] "#).unwrap(), @r###" - WITH table_1 AS ( + WITH table_0 AS ( SELECT 1 AS a, 'x' AS b, @@ -3194,7 +3193,7 @@ a,b,c b, c FROM - table_1 AS table_0 + table_0 AS table_1 "### ); @@ -3209,7 +3208,7 @@ a,b,c select [b, c] "#).unwrap(), @r###" - WITH table_1 AS ( + WITH table_0 AS ( SELECT 1 AS a, 'x' AS b, @@ -3225,7 +3224,7 @@ a,b,c b, c FROM - table_1 AS table_0 + table_0 AS table_1 "### ); } @@ -3242,3 +3241,55 @@ fn test_header_target_error() { from a "#).unwrap_err(),@r###"target `"sql.foo"` not found"###) } + +#[test] +fn test_loop() { + assert_display_snapshot!(compile(r#" + from_text format:json '[{"n": 1 }]' + select n = n - 2 + loop ( + select n = n+1 + filter n<5 + ) + select n = n * 2 + take 4 + "#).unwrap(), + @r###" + WITH table_0 AS ( + SELECT + 1 AS n + ), + table_6 AS ( + WITH RECURSIVE loop AS ( + SELECT + n - 2 AS _expr_0 + FROM + table_0 AS table_1 + UNION + ALL + SELECT + _expr_1 + FROM + ( + SELECT + _expr_0 + 1 AS _expr_1 + FROM + loop AS table_2 + ) AS table_3 + WHERE + _expr_1 < 5 + ) + SELECT + * + FROM + loop + ) + SELECT + _expr_0 * 2 AS n + FROM + table_6 AS table_5 + LIMIT + 4 + "### + ); +} diff --git a/prql-compiler/tests/integration/queries/loop.prql b/prql-compiler/tests/integration/queries/loop.prql new file mode 100644 index 000000000000..e83d02e37057 --- /dev/null +++ b/prql-compiler/tests/integration/queries/loop.prql @@ -0,0 +1,7 @@ +from_text format:json '[{"n": 1 }]' +select n = n - 2 +loop ( + filter n<4 + select n = n+1 +) +select n = n * 2 diff --git a/prql-compiler/tests/integration/snapshots/integration__tests__test@loop.prql.snap b/prql-compiler/tests/integration/snapshots/integration__tests__test@loop.prql.snap new file mode 100644 index 000000000000..482dc9933c4d --- /dev/null +++ b/prql-compiler/tests/integration/snapshots/integration__tests__test@loop.prql.snap @@ -0,0 +1,12 @@ +--- +source: prql-compiler/tests/integration/main.rs +expression: sqlite_out +input_file: prql-compiler/tests/integration/queries/loop.prql +--- +n +-2 +0 +2 +4 +6 +8 diff --git a/website/content/_index.md b/website/content/_index.md index 035f4eaedfe2..349317aaf594 100644 --- a/website/content/_index.md +++ b/website/content/_index.md @@ -246,7 +246,7 @@ showcase_section: SELECT * FROM - table_1 + table_1 AS table_0 WHERE _expr_0 <= 1 From 5a382e759d959e0a9101fd0b97d5c118b229208a Mon Sep 17 00:00:00 2001 From: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Date: Thu, 23 Feb 2023 22:06:32 -0800 Subject: [PATCH 047/106] ci: Only cache docker on main branch (#1953) --- .github/workflows/test-all.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/test-all.yaml b/.github/workflows/test-all.yaml index 34ea805c7de4..9c3e24912499 100644 --- a/.github/workflows/test-all.yaml +++ b/.github/workflows/test-all.yaml @@ -105,6 +105,8 @@ jobs: load: true cache-from: type=gha cache-to: type=gha,mode=max + # Don't cache if the branch isn't main... + no-cache: ${{ github.ref != 'refs/heads/main' }} test-min-rust-version: runs-on: ubuntu-latest From c3d777b7cbe433b2b6e8ec0a43e0b8e43928b60f Mon Sep 17 00:00:00 2001 From: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Date: Thu, 23 Feb 2023 22:16:51 -0800 Subject: [PATCH 048/106] revert: #1953 (#1954) Revert "ci: Only cache docker on main branch (#1953)" This reverts commit 5a382e759d959e0a9101fd0b97d5c118b229208a. --- .github/workflows/test-all.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/test-all.yaml b/.github/workflows/test-all.yaml index 9c3e24912499..34ea805c7de4 100644 --- a/.github/workflows/test-all.yaml +++ b/.github/workflows/test-all.yaml @@ -105,8 +105,6 @@ jobs: load: true cache-from: type=gha cache-to: type=gha,mode=max - # Don't cache if the branch isn't main... - no-cache: ${{ github.ref != 'refs/heads/main' }} test-min-rust-version: runs-on: ubuntu-latest From b0276bcbfcca93f7db1b8d695181c1afa0b6f45e Mon Sep 17 00:00:00 2001 From: Jonathan Date: Fri, 24 Feb 2023 11:32:44 +0100 Subject: [PATCH 049/106] refactor: Improve PHP bindings (#1949) --- prql-php/src/Compiler.php | 133 +++++++++++++++++++------------- prql-php/src/Options.php | 2 +- prql-php/tests/CompilerTest.php | 35 +++++---- 3 files changed, 101 insertions(+), 69 deletions(-) diff --git a/prql-php/src/Compiler.php b/prql-php/src/Compiler.php index 5be55ea51962..baa470c4fa29 100644 --- a/prql-php/src/Compiler.php +++ b/prql-php/src/Compiler.php @@ -30,6 +30,45 @@ */ final class Compiler { + private \FFI $_libprql; + + /** + * Initializes a new instance of the Compiler. + * + * @param ?string|null $lib_path Path to the libprql library. + */ + function __construct(?string $lib_path = null) + { + $library = $lib_path; + + if ($lib_path === null) { + $library = __DIR__; + } + + if (PHP_OS_FAMILY === "Windows") { + $library .= "\libprql_lib.dll"; + } elseif (PHP_OS_FAMILY === "Darwin") { + $library .= "/libprql_lib.dylib"; + } else { + $library .= "/libprql_lib.so"; + } + + $this->_libprql = \FFI::cdef( + " + typedef struct Options { + bool format; + char *target; + bool signature_comment; + } Options; + + int compile(const char *prql_query, const struct Options *options, char *out); + int prql_to_pl(const char *prql_query, char *out); + int pl_to_rq(const char *pl_json, char *out); + int rq_to_sql(const char *rq_json, char *out); + ", $library + ); + } + /** * Compile a PRQL string into a SQL string. * @@ -37,9 +76,9 @@ final class Compiler * @param Options|null $options PRQL compiler options. * * @return string SQL query. - * @throws \InvalidArgumentException If no query is given or the query cannot - * @api + * @throws \InvalidArgumentException If no query is given or the query canno * be compiled. + * @api * @todo FIX THIS. THIS DOES NOT WORK! * @ignore Ignore this function until fixed. */ @@ -53,72 +92,45 @@ function compile(string $prql_query, ?Options $options = null): string $options = new Options(); } - $library = "/libprql_lib.so"; - - if (PHP_OS_FAMILY === "Windows") { - $library = "\libprql_lib.dll"; - } - - $libprql = \FFI::cdef( - " - struct options { - bool format; - char* target; - bool signature_comment; - }; - - char* compile(const char *prql_query, struct options *opt); - ", __DIR__ . $library - ); - - $ffi_options = $libprql->new("struct options"); + $ffi_options = $this->_libprql->new("struct Options"); $ffi_options->format = $options->format; $ffi_options->signature_comment = $options->signature_comment; if (isset($options->target)) { $target_len = strlen($options->target); - $ffi_options->target = $ffi->new('char[$target_len]', 0); - FFI::memcpy($ffi_options->target, $options->target, $target_len); - FFI::free($ffi_options->target); + $ffi_options->target = \FFI::new("char[$target_len]", false); + \FFI::memcpy($ffi_options->target, $options->target, $target_len); + \FFI::free($ffi_options->target); } $out = str_pad("", 1024); - if ($libprql->compile($prql_query, \FFI::addr($$ffi_options)) !== 0) { + if ($this->_libprql->compile($prql_query, \FFI::addr($ffi_options), $out) !== 0) { throw new \InvalidArgumentException("Could not compile query."); } + unset($ffi_options); + return trim($out); } /** - * Compile a PRQL string into a JSON string. + * Compile a PRQL string into PL. * * @param string $prql_query A PRQL query. * - * @return string JSON string. + * @return string Pipelined Language (PL) JSON string. * @throws \InvalidArgumentException If no query is given or the query cannot * be compiled. * @api */ - function toJson(string $prql_query): string + function prqlToPL(string $prql_query): string { if (!$prql_query) { throw new \InvalidArgumentException("No query given."); } - $library = "/libprql_lib.so"; - - if (PHP_OS_FAMILY === "Windows") { - $library = "\libprql_lib.dll"; - } - - $libprql = \FFI::cdef( - "int to_json(char *prql_query, char *json_query);", - __DIR__ . $library - ); - $out = str_pad("", 1024); - if ($libprql->to_json($prql_query, $out) !== 0) { + if ($this->_libprql->prql_to_pl($prql_query, $out) !== 0) { throw new \InvalidArgumentException("Could not compile query."); } @@ -126,35 +138,48 @@ function toJson(string $prql_query): string } /** - * Compile a PRQL string into a SQL string. + * Converts PL to RQ. * - * @param string $prql_query A PRQL query. + * @param string $pl_json PL in JSON format. * - * @return string SQL query. + * @return string RQ string. * @throws \InvalidArgumentException If no query is given or the query cannot * be compiled. * @api */ - function toSql(string $prql_query): string + function plToRQ(string $pl_json): string { if (!$prql_query) { throw new \InvalidArgumentException("No query given."); } - $library = "/libprql_lib.so"; - - if (PHP_OS_FAMILY === "Windows") { - $library = "\libprql_lib.dll"; + $out = str_pad("", 1024); + if ($this->_libprql->pl_to_rq($pl_json, $out) !== 0) { + throw new \InvalidArgumentException("Could not convert PL."); } - $libprql = \FFI::cdef( - "int to_sql(char *prql_query, char *sql_query);", - __DIR__ . $library - ); + return trim($out); + } + + /** + * Converts RQ to SQL. + * + * @param string $rq_json PL in JSON format. + * + * @return string SQL string. + * @throws \InvalidArgumentException If no query is given or the query cannot + * be compiled. + * @api + */ + function rQToSql(string $rq_json): string + { + if (!$prql_query) { + throw new \InvalidArgumentException("No query given."); + } $out = str_pad("", 1024); - if ($libprql->to_sql($prql_query, $out) !== 0) { - throw new \InvalidArgumentException("Could not compile query."); + if ($this->_libprql->rq_to_sql($rq_json, $out) !== 0) { + throw new \InvalidArgumentException("Could not convert RQ."); } return trim($out); diff --git a/prql-php/src/Options.php b/prql-php/src/Options.php index 3b76344df3e2..574d59075a8c 100644 --- a/prql-php/src/Options.php +++ b/prql-php/src/Options.php @@ -28,7 +28,7 @@ * @license https://spdx.org/licenses/Apache-2.0.html Apache License 2.0 * @link https://prql-lang.org/ */ -class Options +final class Options { /** * Pass generated SQL string trough a formatter that splits it into diff --git a/prql-php/tests/CompilerTest.php b/prql-php/tests/CompilerTest.php index a21957c17b47..de0d28131e43 100644 --- a/prql-php/tests/CompilerTest.php +++ b/prql-php/tests/CompilerTest.php @@ -1,6 +1,7 @@ assertInstanceOf(FFI::class, $ffi); } @@ -27,23 +28,29 @@ public function testInvalidQueryThrows(): void $this->expectException(\InvalidArgumentException::class); $prql = new Compiler(); - $prql->toSql("invalid"); + $prql->compile("invalid"); } - public function testToSqlWorks(): void + public function testCompileWorks(): void { - $expected = <<<'EOD' -SELECT - * -FROM - employees - --- Generated by PRQL compiler version:0.5.0 (https://prql-lang.org) -EOD; - $expected = substr($expected, 0, strpos($expected, "Generated by PRQL compiler")); + $options = new Options(); + $options->format = false; + $options->signature_comment = false; + $options->target = "sql.mssql"; $prql = new Compiler(); - $actual = $prql->toSql("from employees"); - $actual = substr($actual, 0, strpos($actual, "Generated by PRQL compiler")); + + $expected = "SELECT * FROM employees"; + $actual = $prql->compile("from employees", $options); + $this->assertEquals($expected, $actual); } + + public function testPrqlToPLWorks(): void + { + $prql = new Compiler(); + + $pl = $prql->prqlToPL("from employees"); + + $this->assertNotNull($pl); + } } From 8e2360f5710ad6df25ce3c691f9e67a63987b1b2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 24 Feb 2023 11:33:26 -0800 Subject: [PATCH 050/106] chore: bump monaco-editor from 0.35.0 to 0.36.0 in /playground (#1955) Bumps [monaco-editor](https://github.com/microsoft/monaco-editor) from 0.35.0 to 0.36.0. - [Release notes](https://github.com/microsoft/monaco-editor/releases) - [Changelog](https://github.com/microsoft/monaco-editor/blob/main/CHANGELOG.md) - [Commits](https://github.com/microsoft/monaco-editor/compare/v0.35.0...v0.36.0) --- updated-dependencies: - dependency-name: monaco-editor dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- playground/package-lock.json | 586 ++++++++++++++++++++++++++++++++++- playground/package.json | 2 +- 2 files changed, 580 insertions(+), 8 deletions(-) diff --git a/playground/package-lock.json b/playground/package-lock.json index a7e16715fc2f..3e8d7dd2ad9b 100644 --- a/playground/package-lock.json +++ b/playground/package-lock.json @@ -14,7 +14,7 @@ "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.4.3", - "monaco-editor": "^0.35.0", + "monaco-editor": "^0.36.0", "prql-js": "file:../prql-js", "react": "^18.2.0", "react-dom": "^18.2.0", @@ -3330,6 +3330,126 @@ "node": ">= 8" } }, + "node_modules/@octokit/auth-token": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz", + "integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==", + "dependencies": { + "@octokit/types": "^6.0.3" + } + }, + "node_modules/@octokit/core": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.6.0.tgz", + "integrity": "sha512-7RKRKuA4xTjMhY+eG3jthb3hlZCsOwg3rztWh75Xc+ShDWOfDDATWbeZpAHBNRpm4Tv9WgBMOy1zEJYXG6NJ7Q==", + "dependencies": { + "@octokit/auth-token": "^2.4.4", + "@octokit/graphql": "^4.5.8", + "@octokit/request": "^5.6.3", + "@octokit/request-error": "^2.0.5", + "@octokit/types": "^6.0.3", + "before-after-hook": "^2.2.0", + "universal-user-agent": "^6.0.0" + } + }, + "node_modules/@octokit/endpoint": { + "version": "6.0.12", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.12.tgz", + "integrity": "sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==", + "dependencies": { + "@octokit/types": "^6.0.3", + "is-plain-object": "^5.0.0", + "universal-user-agent": "^6.0.0" + } + }, + "node_modules/@octokit/graphql": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz", + "integrity": "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==", + "dependencies": { + "@octokit/request": "^5.6.0", + "@octokit/types": "^6.0.3", + "universal-user-agent": "^6.0.0" + } + }, + "node_modules/@octokit/openapi-types": { + "version": "12.11.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-12.11.0.tgz", + "integrity": "sha512-VsXyi8peyRq9PqIz/tpqiL2w3w80OgVMwBHltTml3LmVvXiphgeqmY9mvBw9Wu7e0QWk/fqD37ux8yP5uVekyQ==" + }, + "node_modules/@octokit/plugin-paginate-rest": { + "version": "2.21.3", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.21.3.tgz", + "integrity": "sha512-aCZTEf0y2h3OLbrgKkrfFdjRL6eSOo8komneVQJnYecAxIej7Bafor2xhuDJOIFau4pk0i/P28/XgtbyPF0ZHw==", + "dependencies": { + "@octokit/types": "^6.40.0" + }, + "peerDependencies": { + "@octokit/core": ">=2" + } + }, + "node_modules/@octokit/plugin-request-log": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz", + "integrity": "sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA==", + "peerDependencies": { + "@octokit/core": ">=3" + } + }, + "node_modules/@octokit/plugin-rest-endpoint-methods": { + "version": "5.16.2", + "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.16.2.tgz", + "integrity": "sha512-8QFz29Fg5jDuTPXVtey05BLm7OB+M8fnvE64RNegzX7U+5NUXcOcnpTIK0YfSHBg8gYd0oxIq3IZTe9SfPZiRw==", + "dependencies": { + "@octokit/types": "^6.39.0", + "deprecation": "^2.3.1" + }, + "peerDependencies": { + "@octokit/core": ">=3" + } + }, + "node_modules/@octokit/request": { + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.6.3.tgz", + "integrity": "sha512-bFJl0I1KVc9jYTe9tdGGpAMPy32dLBXXo1dS/YwSCTL/2nd9XeHsY616RE3HPXDVk+a+dBuzyz5YdlXwcDTr2A==", + "dependencies": { + "@octokit/endpoint": "^6.0.1", + "@octokit/request-error": "^2.1.0", + "@octokit/types": "^6.16.1", + "is-plain-object": "^5.0.0", + "node-fetch": "^2.6.7", + "universal-user-agent": "^6.0.0" + } + }, + "node_modules/@octokit/request-error": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz", + "integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==", + "dependencies": { + "@octokit/types": "^6.0.3", + "deprecation": "^2.0.0", + "once": "^1.4.0" + } + }, + "node_modules/@octokit/rest": { + "version": "18.12.0", + "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-18.12.0.tgz", + "integrity": "sha512-gDPiOHlyGavxr72y0guQEhLsemgVjwRePayJ+FcKc2SJqKUbxbkvf5kAZEWA/MKvsfYlQAMVzNJE3ezQcxMJ2Q==", + "dependencies": { + "@octokit/core": "^3.5.1", + "@octokit/plugin-paginate-rest": "^2.16.8", + "@octokit/plugin-request-log": "^1.0.4", + "@octokit/plugin-rest-endpoint-methods": "^5.12.0" + } + }, + "node_modules/@octokit/types": { + "version": "6.41.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.41.0.tgz", + "integrity": "sha512-eJ2jbzjdijiL3B4PrSQaSjuF2sPEQPVCPzBvTHJD9Nz+9dw2SGH4K4xeQJ77YfTq5bRQ+bD8wT11JbeDPmxmGg==", + "dependencies": { + "@octokit/openapi-types": "^12.11.0" + } + }, "node_modules/@pmmmwh/react-refresh-webpack-plugin": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.7.tgz", @@ -3928,6 +4048,15 @@ "resolved": "https://registry.npmjs.org/@types/flatbuffers/-/flatbuffers-1.10.0.tgz", "integrity": "sha512-7btbphLrKvo5yl/5CC2OCxUSMx1wV1wvGT1qDXkSt7yi00/YW7E8k6qzXqJHsp+WU0eoG7r6MTQQXI9lIvd0qA==" }, + "node_modules/@types/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w==", + "dependencies": { + "@types/minimatch": "^5.1.2", + "@types/node": "*" + } + }, "node_modules/@types/graceful-fs": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", @@ -4031,6 +4160,11 @@ "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==" }, + "node_modules/@types/minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==" + }, "node_modules/@types/node": { "version": "18.8.3", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.8.3.tgz", @@ -4124,6 +4258,15 @@ "@types/node": "*" } }, + "node_modules/@types/shelljs": { + "version": "0.8.11", + "resolved": "https://registry.npmjs.org/@types/shelljs/-/shelljs-0.8.11.tgz", + "integrity": "sha512-x9yaMvEh5BEaZKeVQC4vp3l+QoFj3BXcd4aYfuKSzIIyihjdVARAadYy3SMNIz0WCCdS2vB9JL/U6GQk5PaxQw==", + "dependencies": { + "@types/glob": "*", + "@types/node": "*" + } + }, "node_modules/@types/sockjs": { "version": "0.3.33", "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.33.tgz", @@ -5380,6 +5523,11 @@ "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==" }, + "node_modules/before-after-hook": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz", + "integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==" + }, "node_modules/bfj": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/bfj/-/bfj-7.0.2.tgz", @@ -6775,6 +6923,11 @@ "node": ">= 0.8" } }, + "node_modules/deprecation": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", + "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==" + }, "node_modules/destroy": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", @@ -9250,6 +9403,14 @@ "node": ">= 0.4" } }, + "node_modules/interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "engines": { + "node": ">= 0.10" + } + }, "node_modules/ipaddr.js": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.0.1.tgz", @@ -9482,6 +9643,14 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-potential-custom-element-name": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", @@ -12026,6 +12195,31 @@ "tmpl": "1.0.5" } }, + "node_modules/matcher": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/matcher/-/matcher-4.0.0.tgz", + "integrity": "sha512-S6x5wmcDmsDRRU/c2dkccDwQPXoFczc5+HpQ2lON8pnvHlnvHAHj5WlLVvw6n6vNyHuVugYrFohYxbS+pvFpKQ==", + "dependencies": { + "escape-string-regexp": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/matcher/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/mdn-data": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", @@ -12234,9 +12428,14 @@ } }, "node_modules/monaco-editor": { - "version": "0.35.0", - "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.35.0.tgz", - "integrity": "sha512-BJfkAZ0EJ7JgrgWzqjfBNP9hPSS8NlfECEDMEIIiozV2UaPq22yeuOjgbd3TwMh3anH0krWZirXZfn8KUSxiOA==" + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.36.0.tgz", + "integrity": "sha512-1Pn3AatfK88flUigyBozA4mt8+SB5xlgloQDu1RqivARw9yKaml/jceIvndae7Z2Nq8T7xZccFlmH+n6rkFg6g==", + "dependencies": { + "@types/shelljs": "^0.8.11", + "pin-github-action": "^1.8.0", + "shelljs": "^0.8.5" + } }, "node_modules/ms": { "version": "2.1.3", @@ -12310,6 +12509,44 @@ "tslib": "^2.0.3" } }, + "node_modules/node-fetch": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.9.tgz", + "integrity": "sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-fetch/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/node-fetch/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/node-fetch/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/node-forge": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", @@ -12874,6 +13111,50 @@ "node": ">=0.10.0" } }, + "node_modules/pin-github-action": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/pin-github-action/-/pin-github-action-1.8.0.tgz", + "integrity": "sha512-8QMKGbDUmMLFSyeV7hDIVmlI8B3ThJed1uFYuhcCBLi/w8xHPbrPhnCvJndYdugNc8aj1FrijrOMDLQ93ATc7A==", + "dependencies": { + "@octokit/rest": "^18", + "commander": "^9", + "debug": "^4.3.4", + "matcher": "^4.0.0", + "yaml": "^2.1.3" + }, + "bin": { + "pin-github-action": "bin.js" + } + }, + "node_modules/pin-github-action/node_modules/commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", + "engines": { + "node": "^12.20.0 || >=14" + } + }, + "node_modules/pin-github-action/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/pin-github-action/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, "node_modules/pirates": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", @@ -14627,6 +14908,17 @@ "node": ">=8.10.0" } }, + "node_modules/rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", + "dependencies": { + "resolve": "^1.1.6" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/recursive-readdir": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.2.tgz", @@ -15344,6 +15636,22 @@ "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.3.tgz", "integrity": "sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw==" }, + "node_modules/shelljs": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", + "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", + "dependencies": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + }, + "bin": { + "shjs": "bin/shjs" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/side-channel": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", @@ -16468,6 +16776,11 @@ "node": ">=8" } }, + "node_modules/universal-user-agent": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz", + "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==" + }, "node_modules/universalify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", @@ -19904,6 +20217,118 @@ "fastq": "^1.6.0" } }, + "@octokit/auth-token": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz", + "integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==", + "requires": { + "@octokit/types": "^6.0.3" + } + }, + "@octokit/core": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.6.0.tgz", + "integrity": "sha512-7RKRKuA4xTjMhY+eG3jthb3hlZCsOwg3rztWh75Xc+ShDWOfDDATWbeZpAHBNRpm4Tv9WgBMOy1zEJYXG6NJ7Q==", + "requires": { + "@octokit/auth-token": "^2.4.4", + "@octokit/graphql": "^4.5.8", + "@octokit/request": "^5.6.3", + "@octokit/request-error": "^2.0.5", + "@octokit/types": "^6.0.3", + "before-after-hook": "^2.2.0", + "universal-user-agent": "^6.0.0" + } + }, + "@octokit/endpoint": { + "version": "6.0.12", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.12.tgz", + "integrity": "sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==", + "requires": { + "@octokit/types": "^6.0.3", + "is-plain-object": "^5.0.0", + "universal-user-agent": "^6.0.0" + } + }, + "@octokit/graphql": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz", + "integrity": "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==", + "requires": { + "@octokit/request": "^5.6.0", + "@octokit/types": "^6.0.3", + "universal-user-agent": "^6.0.0" + } + }, + "@octokit/openapi-types": { + "version": "12.11.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-12.11.0.tgz", + "integrity": "sha512-VsXyi8peyRq9PqIz/tpqiL2w3w80OgVMwBHltTml3LmVvXiphgeqmY9mvBw9Wu7e0QWk/fqD37ux8yP5uVekyQ==" + }, + "@octokit/plugin-paginate-rest": { + "version": "2.21.3", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.21.3.tgz", + "integrity": "sha512-aCZTEf0y2h3OLbrgKkrfFdjRL6eSOo8komneVQJnYecAxIej7Bafor2xhuDJOIFau4pk0i/P28/XgtbyPF0ZHw==", + "requires": { + "@octokit/types": "^6.40.0" + } + }, + "@octokit/plugin-request-log": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz", + "integrity": "sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA==", + "requires": {} + }, + "@octokit/plugin-rest-endpoint-methods": { + "version": "5.16.2", + "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.16.2.tgz", + "integrity": "sha512-8QFz29Fg5jDuTPXVtey05BLm7OB+M8fnvE64RNegzX7U+5NUXcOcnpTIK0YfSHBg8gYd0oxIq3IZTe9SfPZiRw==", + "requires": { + "@octokit/types": "^6.39.0", + "deprecation": "^2.3.1" + } + }, + "@octokit/request": { + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.6.3.tgz", + "integrity": "sha512-bFJl0I1KVc9jYTe9tdGGpAMPy32dLBXXo1dS/YwSCTL/2nd9XeHsY616RE3HPXDVk+a+dBuzyz5YdlXwcDTr2A==", + "requires": { + "@octokit/endpoint": "^6.0.1", + "@octokit/request-error": "^2.1.0", + "@octokit/types": "^6.16.1", + "is-plain-object": "^5.0.0", + "node-fetch": "^2.6.7", + "universal-user-agent": "^6.0.0" + } + }, + "@octokit/request-error": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz", + "integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==", + "requires": { + "@octokit/types": "^6.0.3", + "deprecation": "^2.0.0", + "once": "^1.4.0" + } + }, + "@octokit/rest": { + "version": "18.12.0", + "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-18.12.0.tgz", + "integrity": "sha512-gDPiOHlyGavxr72y0guQEhLsemgVjwRePayJ+FcKc2SJqKUbxbkvf5kAZEWA/MKvsfYlQAMVzNJE3ezQcxMJ2Q==", + "requires": { + "@octokit/core": "^3.5.1", + "@octokit/plugin-paginate-rest": "^2.16.8", + "@octokit/plugin-request-log": "^1.0.4", + "@octokit/plugin-rest-endpoint-methods": "^5.12.0" + } + }, + "@octokit/types": { + "version": "6.41.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.41.0.tgz", + "integrity": "sha512-eJ2jbzjdijiL3B4PrSQaSjuF2sPEQPVCPzBvTHJD9Nz+9dw2SGH4K4xeQJ77YfTq5bRQ+bD8wT11JbeDPmxmGg==", + "requires": { + "@octokit/openapi-types": "^12.11.0" + } + }, "@pmmmwh/react-refresh-webpack-plugin": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.7.tgz", @@ -20317,6 +20742,15 @@ "resolved": "https://registry.npmjs.org/@types/flatbuffers/-/flatbuffers-1.10.0.tgz", "integrity": "sha512-7btbphLrKvo5yl/5CC2OCxUSMx1wV1wvGT1qDXkSt7yi00/YW7E8k6qzXqJHsp+WU0eoG7r6MTQQXI9lIvd0qA==" }, + "@types/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w==", + "requires": { + "@types/minimatch": "^5.1.2", + "@types/node": "*" + } + }, "@types/graceful-fs": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", @@ -20413,6 +20847,11 @@ "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==" }, + "@types/minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==" + }, "@types/node": { "version": "18.8.3", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.8.3.tgz", @@ -20506,6 +20945,15 @@ "@types/node": "*" } }, + "@types/shelljs": { + "version": "0.8.11", + "resolved": "https://registry.npmjs.org/@types/shelljs/-/shelljs-0.8.11.tgz", + "integrity": "sha512-x9yaMvEh5BEaZKeVQC4vp3l+QoFj3BXcd4aYfuKSzIIyihjdVARAadYy3SMNIz0WCCdS2vB9JL/U6GQk5PaxQw==", + "requires": { + "@types/glob": "*", + "@types/node": "*" + } + }, "@types/sockjs": { "version": "0.3.33", "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.33.tgz", @@ -21435,6 +21883,11 @@ "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==" }, + "before-after-hook": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz", + "integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==" + }, "bfj": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/bfj/-/bfj-7.0.2.tgz", @@ -22452,6 +22905,11 @@ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" }, + "deprecation": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", + "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==" + }, "destroy": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", @@ -24243,6 +24701,11 @@ "side-channel": "^1.0.4" } }, + "interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==" + }, "ipaddr.js": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.0.1.tgz", @@ -24384,6 +24847,11 @@ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==" }, + "is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==" + }, "is-potential-custom-element-name": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", @@ -26390,6 +26858,21 @@ "tmpl": "1.0.5" } }, + "matcher": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/matcher/-/matcher-4.0.0.tgz", + "integrity": "sha512-S6x5wmcDmsDRRU/c2dkccDwQPXoFczc5+HpQ2lON8pnvHlnvHAHj5WlLVvw6n6vNyHuVugYrFohYxbS+pvFpKQ==", + "requires": { + "escape-string-regexp": "^4.0.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" + } + } + }, "mdn-data": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", @@ -26537,9 +27020,14 @@ } }, "monaco-editor": { - "version": "0.35.0", - "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.35.0.tgz", - "integrity": "sha512-BJfkAZ0EJ7JgrgWzqjfBNP9hPSS8NlfECEDMEIIiozV2UaPq22yeuOjgbd3TwMh3anH0krWZirXZfn8KUSxiOA==" + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.36.0.tgz", + "integrity": "sha512-1Pn3AatfK88flUigyBozA4mt8+SB5xlgloQDu1RqivARw9yKaml/jceIvndae7Z2Nq8T7xZccFlmH+n6rkFg6g==", + "requires": { + "@types/shelljs": "^0.8.11", + "pin-github-action": "^1.8.0", + "shelljs": "^0.8.5" + } }, "ms": { "version": "2.1.3", @@ -26595,6 +27083,35 @@ "tslib": "^2.0.3" } }, + "node-fetch": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.9.tgz", + "integrity": "sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==", + "requires": { + "whatwg-url": "^5.0.0" + }, + "dependencies": { + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + } + } + }, "node-forge": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", @@ -26991,6 +27508,38 @@ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==" }, + "pin-github-action": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/pin-github-action/-/pin-github-action-1.8.0.tgz", + "integrity": "sha512-8QMKGbDUmMLFSyeV7hDIVmlI8B3ThJed1uFYuhcCBLi/w8xHPbrPhnCvJndYdugNc8aj1FrijrOMDLQ93ATc7A==", + "requires": { + "@octokit/rest": "^18", + "commander": "^9", + "debug": "^4.3.4", + "matcher": "^4.0.0", + "yaml": "^2.1.3" + }, + "dependencies": { + "commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==" + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, "pirates": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", @@ -28091,6 +28640,14 @@ "picomatch": "^2.2.1" } }, + "rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", + "requires": { + "resolve": "^1.1.6" + } + }, "recursive-readdir": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.2.tgz", @@ -28605,6 +29162,16 @@ "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.3.tgz", "integrity": "sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw==" }, + "shelljs": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", + "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", + "requires": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + } + }, "side-channel": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", @@ -29450,6 +30017,11 @@ "crypto-random-string": "^2.0.0" } }, + "universal-user-agent": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz", + "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==" + }, "universalify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", diff --git a/playground/package.json b/playground/package.json index 8a2295b250b7..1de1b6c79627 100644 --- a/playground/package.json +++ b/playground/package.json @@ -17,7 +17,7 @@ "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.4.3", - "monaco-editor": "^0.35.0", + "monaco-editor": "^0.36.0", "prql-js": "file:../prql-js", "react": "^18.2.0", "react-dom": "^18.2.0", From 9c5f2d59940c531d380e13336c5b7828bfc60b27 Mon Sep 17 00:00:00 2001 From: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Date: Fri, 24 Feb 2023 17:04:36 -0800 Subject: [PATCH 051/106] internal: Defer to auto-conversion of some errors (#1931) Follow-up to #1914 --- prql-compiler/src/lib.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/prql-compiler/src/lib.rs b/prql-compiler/src/lib.rs index 25d50b652745..18894b6b5348 100644 --- a/prql-compiler/src/lib.rs +++ b/prql-compiler/src/lib.rs @@ -233,12 +233,12 @@ pub fn prql_to_pl(prql: &str) -> Result, ErrorMessages> { /// Perform semantic analysis and convert PL to RQ. pub fn pl_to_rq(pl: Vec) -> Result { - semantic::resolve(pl).map_err(error::downcast) + semantic::resolve(pl).map_err(|e| e.into()) } /// Generate SQL from RQ. pub fn rq_to_sql(rq: ast::rq::Query, options: &Options) -> Result { - sql::compile(rq, options).map_err(error::downcast) + sql::compile(rq, options).map_err(|e| e.into()) } /// Generate PRQL code from PL AST @@ -252,22 +252,22 @@ pub mod json { /// JSON serialization pub fn from_pl(pl: Vec) -> Result { - serde_json::to_string(&pl).map_err(|e| error::downcast(anyhow::anyhow!(e))) + serde_json::to_string(&pl).map_err(|e| anyhow::anyhow!(e).into()) } /// JSON deserialization pub fn to_pl(json: &str) -> Result, ErrorMessages> { - serde_json::from_str(json).map_err(|e| error::downcast(anyhow::anyhow!(e))) + serde_json::from_str(json).map_err(|e| anyhow::anyhow!(e).into()) } /// JSON serialization pub fn from_rq(rq: ast::rq::Query) -> Result { - serde_json::to_string(&rq).map_err(|e| error::downcast(anyhow::anyhow!(e))) + serde_json::to_string(&rq).map_err(|e| anyhow::anyhow!(e).into()) } /// JSON deserialization pub fn to_rq(json: &str) -> Result { - serde_json::from_str(json).map_err(|e| error::downcast(anyhow::anyhow!(e))) + serde_json::from_str(json).map_err(|e| anyhow::anyhow!(e).into()) } } From 7281e34a5c7661f905caa8f2500b5f811e56af6a Mon Sep 17 00:00:00 2001 From: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Date: Fri, 24 Feb 2023 23:04:43 -0800 Subject: [PATCH 052/106] web: Attempt to default to the SQL view in playground (#1939) web: Default to the SQL view in playground --- playground/src/examples.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/playground/src/examples.js b/playground/src/examples.js index 751c1434e64a..e9955d897e75 100644 --- a/playground/src/examples.js +++ b/playground/src/examples.js @@ -1,6 +1,6 @@ const examples = { "introduction.prql": [ - "arrow", + "sql", `from invoices filter invoice_date >= @1970-01-16 derive [ # This adds columns @@ -27,7 +27,7 @@ derive db_version = s"version()" # S-string, escape hatch to SQL ], "let-table-0.prql": [ - "arrow", + "sql", `let soundtracks = ( from playlists filter name == 'TV Shows' @@ -56,7 +56,7 @@ take 10 ], "artists-0.prql": [ - "arrow", + "sql", `from tracks select [album_id, name, unit_price] sort [-unit_price, name] From ed8a1c0f2b8623dc91411503a6f6516e476e7cba Mon Sep 17 00:00:00 2001 From: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Date: Sun, 26 Feb 2023 10:02:00 -0800 Subject: [PATCH 053/106] feat: Add a `--format=yaml` option to `prqlc parse` (#1962) --- prql-compiler/prqlc/src/cli.rs | 93 ++++++++++++++++++++++++++++---- prql-compiler/prqlc/src/watch.rs | 2 +- 2 files changed, 83 insertions(+), 12 deletions(-) diff --git a/prql-compiler/prqlc/src/cli.rs b/prql-compiler/prqlc/src/cli.rs index 06c2361b9c52..9bac892e1c28 100644 --- a/prql-compiler/prqlc/src/cli.rs +++ b/prql-compiler/prqlc/src/cli.rs @@ -14,6 +14,7 @@ use prql_compiler::{downcast, Options}; use crate::watch; +/// Entrypoint called by [main::main] pub fn main() -> color_eyre::eyre::Result<()> { env_logger::builder().format_timestamp(None).init(); color_eyre::install()?; @@ -27,7 +28,7 @@ pub fn main() -> color_eyre::eyre::Result<()> { Ok(()) } -#[derive(Parser)] +#[derive(Parser, Debug)] #[clap(name = env!("CARGO_PKG_NAME"), about, version)] pub enum Cli { /// Parse PL AST @@ -53,13 +54,26 @@ pub enum Cli { Watch(watch::WatchCommand), } -#[derive(clap::Args, Default)] +// TODO: Should this be named `IoArgs`? IIUC it's just the args; its parent +// represents the Command. I struggled mapping this to clap docs for a while. +#[derive(clap::Args, Default, Debug)] pub struct CommandIO { #[clap(value_parser, default_value = "-")] input: Input, #[clap(value_parser, default_value = "-")] output: Output, + + // TODO: This should be only on some commands, is there an elegant way of + // doing that in Clap without lots of duplication? + #[arg(value_enum, long)] + format: Option, +} + +#[derive(clap::ValueEnum, Clone, Debug)] +enum Format { + Json, + Yaml, } fn is_stdin(input: &Input) -> bool { @@ -67,6 +81,7 @@ fn is_stdin(input: &Input) -> bool { } impl Cli { + /// Entrypoint called by [`main`] pub fn run(&mut self) -> Result<()> { if let Cli::Watch(command) = self { return watch::run(command); @@ -94,13 +109,13 @@ impl Cli { } fn execute(&self, source: &str) -> Result> { - // TODO: there's some repetiton here around converting strings to bytes; - // we could possibly extract that, but not sure it would neatly . Ok(match self { - Cli::Parse(_) => { + Cli::Parse(args) => { let ast = prql_to_pl(source)?; - - serde_yaml::to_string(&ast)?.into_bytes() + match args.format { + Some(Format::Json) | None => serde_json::to_string_pretty(&ast)?.into_bytes(), + Some(Format::Yaml) => serde_yaml::to_string(&ast)?.into_bytes(), + } } Cli::Format(_) => prql_to_pl(source).and_then(pl_to_prql)?.as_bytes().to_vec(), Cli::Debug(_) => { @@ -118,6 +133,9 @@ impl Cli { .concat() } Cli::Annotate(_) => { + // TODO: potentially if there is code performing a role beyond + // presentation, it should be a library function; and we could + // promote it to the `prql-compiler` crate. let stmts = prql_to_pl(source)?; // resolve @@ -128,12 +146,16 @@ impl Cli { // combine with source combine_prql_and_frames(source, frames).as_bytes().to_vec() } - Cli::Resolve(_) => { + Cli::Resolve(args) => { let ast = prql_to_pl(source)?; let ir = semantic::resolve(ast)?; - - serde_json::to_string_pretty(&ir)?.into_bytes() + match args.format { + Some(Format::Json) | None => serde_json::to_string_pretty(&ir)?.into_bytes(), + Some(Format::Yaml) => anyhow::bail!("YAML output is not yet supported for PL"), + // Some(Format::Yaml) => serde_yaml::to_string(&ir)?.into_bytes(), + } } + // TODO: Allow passing the `Options` to the CLI; map those through. Cli::Compile(_) => compile(source, &Options::default())?.as_bytes().to_vec(), Cli::Watch(_) => unreachable!(), }) @@ -268,7 +290,6 @@ group a_column (take 10 | sort b_column | derive [the_number = rank, last = lag // Check we get an error on a bad input let input = "asdf"; let result = Cli::execute(&Cli::Compile(CommandIO::default()), input); - assert!(result.is_err()); assert_display_snapshot!(result.unwrap_err(), @r###" Error: ╭─[:1:1] @@ -279,4 +300,54 @@ group a_column (take 10 | sort b_column | derive [the_number = rank, last = lag ───╯ "###); } + + #[test] + // Currently failing based on serde_yaml not being able to serialize an + // Enum of an Enum; from https://github.com/dtolnay/serde-yaml/blob/68a9e95c9fd639498c85f55b5485f446b3f8465c/tests/test_error.rs#L175 + #[should_panic] + fn resolve() { + let _output = Cli::execute( + &Cli::Resolve(CommandIO { + input: CommandIO::default().input, + output: CommandIO::default().output, + format: Some(Format::Yaml), + }), + "from x | select y", + ) + .unwrap(); + } + #[test] + fn parse() { + let output = Cli::execute( + &Cli::Parse(CommandIO { + input: CommandIO::default().input, + output: CommandIO::default().output, + format: Some(Format::Yaml), + }), + "from x | select y", + ) + .unwrap(); + + assert_display_snapshot!(String::from_utf8(output).unwrap().trim(), @r###" + - Main: + Pipeline: + exprs: + - FuncCall: + name: + Ident: + - from + args: + - Ident: + - x + named_args: {} + - FuncCall: + name: + Ident: + - select + args: + - Ident: + - y + named_args: {} + "###); + } } diff --git a/prql-compiler/prqlc/src/watch.rs b/prql-compiler/prqlc/src/watch.rs index 4084439627ba..3383592170e6 100644 --- a/prql-compiler/prqlc/src/watch.rs +++ b/prql-compiler/prqlc/src/watch.rs @@ -10,7 +10,7 @@ use walkdir::WalkDir; use crate::jinja; -#[derive(Parser)] +#[derive(Parser, Debug)] pub struct WatchCommand { /// Directory or file to watch for changes pub path: OsString, From 84a74e2862054ea61c99ffa12f06191161d47621 Mon Sep 17 00:00:00 2001 From: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Date: Sun, 26 Feb 2023 13:32:00 -0800 Subject: [PATCH 054/106] refactor: Refactor CLI arg handling (#1963) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: Add a `--format=yaml` option to `prqlc parse` * refactor: Refactor CLI arg handling Based of #1912 * Update prql-compiler/prqlc/src/cli.rs Co-authored-by: Aljaž Mur Eržen * . --------- Co-authored-by: Aljaž Mur Eržen --- prql-compiler/prqlc/src/cli.rs | 177 +++++++++++++++++-------------- prql-compiler/prqlc/src/watch.rs | 6 +- 2 files changed, 100 insertions(+), 83 deletions(-) diff --git a/prql-compiler/prqlc/src/cli.rs b/prql-compiler/prqlc/src/cli.rs index 9bac892e1c28..c8f03ec9d9e8 100644 --- a/prql-compiler/prqlc/src/cli.rs +++ b/prql-compiler/prqlc/src/cli.rs @@ -1,6 +1,6 @@ use anyhow::Result; use ariadne::Source; -use clap::Parser; +use clap::{Parser, Subcommand}; use clio::{Input, Output}; use itertools::Itertools; use std::io::{Read, Write}; @@ -14,13 +14,13 @@ use prql_compiler::{downcast, Options}; use crate::watch; -/// Entrypoint called by [main::main] +/// Entrypoint called by [crate::main] pub fn main() -> color_eyre::eyre::Result<()> { env_logger::builder().format_timestamp(None).init(); color_eyre::install()?; let mut cli = Cli::parse(); - if let Err(error) = cli.run() { + if let Err(error) = cli.command.run() { eprintln!("{error}"); exit(1) } @@ -28,36 +28,47 @@ pub fn main() -> color_eyre::eyre::Result<()> { Ok(()) } -#[derive(Parser, Debug)] +#[derive(Parser, Debug, Clone)] +struct Cli { + #[command(subcommand)] + command: Command, +} + +#[derive(Subcommand, Debug, Clone)] #[clap(name = env!("CARGO_PKG_NAME"), about, version)] -pub enum Cli { - /// Parse PL AST - Parse(CommandIO), +enum Command { + /// Parse into PL AST + Parse { + #[clap(value_parser, default_value = "-")] + input: Input, + #[clap(value_parser, default_value = "-")] + output: Output, + #[arg(value_enum, long)] + format: Option, + }, /// Parse & generate PRQL code back #[clap(name = "fmt")] - Format(CommandIO), + Format(IoArgs), /// Parse, resolve & combine source with comments annotating relation type - Annotate(CommandIO), + Annotate(IoArgs), /// Parse & resolve, but don't lower into RQ - Debug(CommandIO), + Debug(IoArgs), /// Parse, resolve & lower into RQ - Resolve(CommandIO), + Resolve(IoArgs), /// Parse, resolve, lower into RQ & compile to SQL - Compile(CommandIO), + Compile(IoArgs), /// Watch a directory and compile .prql files to .sql files - Watch(watch::WatchCommand), + Watch(watch::WatchArgs), } -// TODO: Should this be named `IoArgs`? IIUC it's just the args; its parent -// represents the Command. I struggled mapping this to clap docs for a while. -#[derive(clap::Args, Default, Debug)] -pub struct CommandIO { +#[derive(clap::Args, Default, Debug, Clone)] +pub struct IoArgs { #[clap(value_parser, default_value = "-")] input: Input, @@ -80,10 +91,10 @@ fn is_stdin(input: &Input) -> bool { input.path() == "-" } -impl Cli { +impl Command { /// Entrypoint called by [`main`] pub fn run(&mut self) -> Result<()> { - if let Cli::Watch(command) = self { + if let Command::Watch(command) = self { return watch::run(command); }; @@ -110,15 +121,15 @@ impl Cli { fn execute(&self, source: &str) -> Result> { Ok(match self { - Cli::Parse(args) => { + Command::Parse { format, .. } => { let ast = prql_to_pl(source)?; - match args.format { + match format { Some(Format::Json) | None => serde_json::to_string_pretty(&ast)?.into_bytes(), Some(Format::Yaml) => serde_yaml::to_string(&ast)?.into_bytes(), } } - Cli::Format(_) => prql_to_pl(source).and_then(pl_to_prql)?.as_bytes().to_vec(), - Cli::Debug(_) => { + Command::Format(_) => prql_to_pl(source).and_then(pl_to_prql)?.as_bytes().to_vec(), + Command::Debug(_) => { let stmts = prql_to_pl(source)?; let (stmts, context) = semantic::resolve_only(stmts, None)?; @@ -132,7 +143,7 @@ impl Cli { ] .concat() } - Cli::Annotate(_) => { + Command::Annotate(_) => { // TODO: potentially if there is code performing a role beyond // presentation, it should be a library function; and we could // promote it to the `prql-compiler` crate. @@ -146,50 +157,55 @@ impl Cli { // combine with source combine_prql_and_frames(source, frames).as_bytes().to_vec() } - Cli::Resolve(args) => { + Command::Resolve(_) => { + // We can't currently have `--format=yaml` here, because + // serde_yaml is unable to serialize an Enum of an Enum; from + // https://github.com/dtolnay/serde-yaml/blob/68a9e95c9fd639498c85f55b5485f446b3f8465c/tests/test_error.rs#L175 let ast = prql_to_pl(source)?; let ir = semantic::resolve(ast)?; - match args.format { - Some(Format::Json) | None => serde_json::to_string_pretty(&ir)?.into_bytes(), - Some(Format::Yaml) => anyhow::bail!("YAML output is not yet supported for PL"), - // Some(Format::Yaml) => serde_yaml::to_string(&ir)?.into_bytes(), - } + serde_json::to_string_pretty(&ir)?.into_bytes() } // TODO: Allow passing the `Options` to the CLI; map those through. - Cli::Compile(_) => compile(source, &Options::default())?.as_bytes().to_vec(), - Cli::Watch(_) => unreachable!(), + // We already do this in Watch. + Command::Compile(_) => compile(source, &Options::default())?.as_bytes().to_vec(), + Command::Watch(_) => unreachable!(), }) } fn read_input(&mut self) -> Result<(String, String)> { - use Cli::*; - match self { - Parse(io) | Format(io) | Debug(io) | Annotate(io) | Resolve(io) | Compile(io) => { - // Don't wait without a prompt when running `prql-compiler compile` — - // it's confusing whether it's waiting for input or not. This - // offers the prompt. - if is_stdin(&io.input) && atty::is(atty::Stream::Stdin) { - println!("Enter PRQL, then ctrl-d:"); - println!(); - } - - let mut source = String::new(); - io.input.read_to_string(&mut source)?; - let source_id = (*io.input.path()).to_str().unwrap().to_string(); - Ok((source, source_id)) - } - Cli::Watch(_) => unreachable!(), + // TODO: possibly this should be called by the relevant subcommands + // passing in `input`, rather than matching on them and grabbing `input` + // from `self`. + use Command::*; + let mut input = match self { + Parse { input, .. } => input.clone(), + Format(io) | Debug(io) | Annotate(io) | Resolve(io) | Compile(io) => io.input.clone(), + Watch(_) => unreachable!(), + }; + // Don't wait without a prompt when running `prqlc compile` — + // it's confusing whether it's waiting for input or not. This + // offers the prompt. + if is_stdin(&input) && atty::is(atty::Stream::Stdin) { + println!("Enter PRQL, then ctrl-d:"); + println!(); } + + let mut source = String::new(); + (input).read_to_string(&mut source)?; + let source_id = (input.path()).to_str().unwrap().to_string(); + Ok((source, source_id)) } fn write_output(&mut self, data: &[u8]) -> std::io::Result<()> { - use Cli::*; - match self { - Parse(io) | Format(io) | Debug(io) | Annotate(io) | Resolve(io) | Compile(io) => { - io.output.write_all(data) + use Command::*; + let mut output = match self { + Parse { output, .. } => output.to_owned(), + Format(io) | Debug(io) | Annotate(io) | Resolve(io) | Compile(io) => { + io.output.to_owned() } - Cli::Watch(_) => unreachable!(), - } + Watch(_) => unreachable!(), + }; + output.write_all(data) } } @@ -227,12 +243,28 @@ fn combine_prql_and_frames(source: &str, frames: Vec<(Span, Frame)>) -> String { mod tests { use insta::{assert_display_snapshot, assert_snapshot}; + // TODO: would be good to test the basic CLI interface — i.e. snapshotting this: + + // $ prqlc parse --help + // + // Parse PL AST + // + // Usage: prqlc parse [OPTIONS] [INPUT] [OUTPUT] + // + // Arguments: + // [INPUT] [default: -] + // [OUTPUT] [default: -] + // + // Options: + // --format [possible values: json, yaml] + // -h, --help Print help + use super::*; #[test] fn layouts() { - let output = Cli::execute( - &Cli::Annotate(CommandIO::default()), + let output = Command::execute( + &Command::Annotate(IoArgs::default()), r#" from initial_table select [f = first_name, l = last_name, gender] @@ -256,8 +288,8 @@ sort full #[test] fn format() { - let output = Cli::execute( - &Cli::Format(CommandIO::default()), + let output = Command::execute( + &Command::Format(IoArgs::default()), r#" from table.subdivision derive `želva_means_turtle` = (`column with spaces` + 1) * 3 @@ -289,7 +321,7 @@ group a_column (take 10 | sort b_column | derive [the_number = rank, last = lag fn compile() { // Check we get an error on a bad input let input = "asdf"; - let result = Cli::execute(&Cli::Compile(CommandIO::default()), input); + let result = Command::execute(&Command::Compile(IoArgs::default()), input); assert_display_snapshot!(result.unwrap_err(), @r###" Error: ╭─[:1:1] @@ -301,29 +333,14 @@ group a_column (take 10 | sort b_column | derive [the_number = rank, last = lag "###); } - #[test] - // Currently failing based on serde_yaml not being able to serialize an - // Enum of an Enum; from https://github.com/dtolnay/serde-yaml/blob/68a9e95c9fd639498c85f55b5485f446b3f8465c/tests/test_error.rs#L175 - #[should_panic] - fn resolve() { - let _output = Cli::execute( - &Cli::Resolve(CommandIO { - input: CommandIO::default().input, - output: CommandIO::default().output, - format: Some(Format::Yaml), - }), - "from x | select y", - ) - .unwrap(); - } #[test] fn parse() { - let output = Cli::execute( - &Cli::Parse(CommandIO { - input: CommandIO::default().input, - output: CommandIO::default().output, + let output = Command::execute( + &Command::Parse { + input: IoArgs::default().input, + output: IoArgs::default().output, format: Some(Format::Yaml), - }), + }, "from x | select y", ) .unwrap(); diff --git a/prql-compiler/prqlc/src/watch.rs b/prql-compiler/prqlc/src/watch.rs index 3383592170e6..a57322e116af 100644 --- a/prql-compiler/prqlc/src/watch.rs +++ b/prql-compiler/prqlc/src/watch.rs @@ -10,8 +10,8 @@ use walkdir::WalkDir; use crate::jinja; -#[derive(Parser, Debug)] -pub struct WatchCommand { +#[derive(Parser, Debug, Clone)] +pub struct WatchArgs { /// Directory or file to watch for changes pub path: OsString, @@ -22,7 +22,7 @@ pub struct WatchCommand { pub no_signature: bool, } -pub fn run(command: &mut WatchCommand) -> Result<()> { +pub fn run(command: &mut WatchArgs) -> Result<()> { let opt = prql_compiler::Options { format: !command.no_format, target: prql_compiler::Target::Sql(None), From 002b10654da515c90df946c102e3ad535021e125 Mon Sep 17 00:00:00 2001 From: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Date: Sun, 26 Feb 2023 13:39:01 -0800 Subject: [PATCH 055/106] chore: Add changelog for `--format` (#1968) --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 47a1ba3bf508..1a24f5f12bda 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ **Features**: - `loop`, which translates to `WITH RECURSIVE` (#1642, @aljazerzen) +- Add a `--format` option to `prqlc parse` which can return the AST in YAML + (@max-sixty, #1962) **Fixes**: From 0e625be63ed983044f1376e476dd51ce8069d5a7 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 27 Feb 2023 11:06:07 -0800 Subject: [PATCH 056/106] chore: pre-commit autoupdate (#1975) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/crate-ci/typos: typos-dict-v0.9.16 → v1.13.12](https://github.com/crate-ci/typos/compare/typos-dict-v0.9.16...v1.13.12) - [github.com/charliermarsh/ruff-pre-commit: v0.0.248 → v0.0.252](https://github.com/charliermarsh/ruff-pre-commit/compare/v0.0.248...v0.0.252) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 5f4006248d49..5c1f89d13d77 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -8,7 +8,7 @@ repos: - id: check-yaml - id: mixed-line-ending - repo: https://github.com/crate-ci/typos - rev: typos-dict-v0.9.16 + rev: v1.13.12 hooks: - id: typos # https://github.com/crate-ci/typos/issues/347 @@ -21,7 +21,7 @@ repos: - prettier - prettier-plugin-go-template - repo: https://github.com/charliermarsh/ruff-pre-commit - rev: v0.0.248 + rev: v0.0.252 hooks: - id: ruff - repo: https://github.com/psf/black From ced220bf28c2a1a6ef0c012ac0422a7923ed543e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alja=C5=BE=20Mur=20Er=C5=BEen?= Date: Mon, 27 Feb 2023 21:21:42 +0100 Subject: [PATCH 057/106] feat: rewrite parser with chumsky (#1818) --- .github/workflows/test-all.yaml | 5 + .github/workflows/test-js.yaml | 4 + CHANGELOG.md | 15 + Cargo.lock | 39 +- book/src/language-features/dates-and-times.md | 2 +- book/src/language-features/f-strings.md | 3 + book/src/language-features/s-strings.md | 7 +- book/src/language-features/strings.md | 16 +- book/src/syntax.md | 39 +- .../language-features/dates-and-times-2.prql | 2 +- .../prql/language-features/strings-5.prql | 2 + book/tests/prql/syntax-16.prql | 3 + ...uage-features__dates-and-times-2.prql.snap | 5 +- ...t__@language-features__strings-5.prql.snap | 11 + .../snapshots/snapshot__@syntax-16.prql.snap | 13 + ...uage-features__dates-and-times-2.prql.snap | 4 +- ...ql__language-features__strings-5.prql.snap | 10 + ...snapshot__tests__prql__syntax-16.prql.snap | 13 + ..._tests__prql__transforms__sort-2.prql.snap | 2 +- prql-compiler/Cargo.toml | 8 +- prql-compiler/prqlc/src/cli.rs | 2 - prql-compiler/src/ast/pl/expr.rs | 16 +- prql-compiler/src/error.rs | 97 +- prql-compiler/src/parser/chumsky.rs | 80 - prql-compiler/src/parser/expr.rs | 305 ++++ prql-compiler/src/parser/interpolation.rs | 55 + prql-compiler/src/parser/lexer.rs | 399 ++++ prql-compiler/src/parser/mod.rs | 1616 +++++++---------- prql-compiler/src/parser/prql.pest | 150 -- ...r__parser__test__pipeline_parse_tree.snap} | 17 +- prql-compiler/src/parser/stmt.rs | 154 ++ prql-compiler/src/semantic/resolver.rs | 5 + ...tic__resolver__test__functions_nested.snap | 70 +- prql-compiler/src/test.rs | 22 +- 34 files changed, 1871 insertions(+), 1320 deletions(-) create mode 100644 book/tests/prql/language-features/strings-5.prql create mode 100644 book/tests/prql/syntax-16.prql create mode 100644 book/tests/snapshots/snapshot__@language-features__strings-5.prql.snap create mode 100644 book/tests/snapshots/snapshot__@syntax-16.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__strings-5.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__syntax-16.prql.snap delete mode 100644 prql-compiler/src/parser/chumsky.rs create mode 100644 prql-compiler/src/parser/expr.rs create mode 100644 prql-compiler/src/parser/interpolation.rs create mode 100644 prql-compiler/src/parser/lexer.rs delete mode 100644 prql-compiler/src/parser/prql.pest rename prql-compiler/src/parser/snapshots/{prql_compiler__parser__test__parse_pipeline_parse_tree.snap => prql_compiler__parser__test__pipeline_parse_tree.snap} (85%) create mode 100644 prql-compiler/src/parser/stmt.rs diff --git a/.github/workflows/test-all.yaml b/.github/workflows/test-all.yaml index 34ea805c7de4..0582d00a4983 100644 --- a/.github/workflows/test-all.yaml +++ b/.github/workflows/test-all.yaml @@ -27,6 +27,11 @@ jobs: matrix: os: [ubuntu-latest, windows-latest, macos-latest] target_option: ["", --target=wasm32-unknown-unknown] + + # Combination of macos and wasm32 has a problem with crate psm, a dependency of chumsky + exclude: + - os: macos-latest + target_option: --target=wasm32-unknown-unknown uses: ./.github/workflows/test-rust.yaml with: os: ${{ matrix.os }} diff --git a/.github/workflows/test-js.yaml b/.github/workflows/test-js.yaml index dd2e4892b4fb..baa88eeda2b2 100644 --- a/.github/workflows/test-js.yaml +++ b/.github/workflows/test-js.yaml @@ -17,6 +17,10 @@ jobs: strategy: matrix: os: [ubuntu-latest, macos-latest, windows-latest] + + # Combination of macos and wasm32 has a problem with crate psm, a dependency of chumsky + exclude: + - os: macos-latest steps: - name: 📂 Checkout code uses: actions/checkout@v3 diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a24f5f12bda..c60fe61f27a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,19 @@ **Features**: - `loop`, which translates to `WITH RECURSIVE` (#1642, @aljazerzen) +- Convert parser from pest to Chumsky (@aljazerzen, #1818) + - Improved error messages, and the potential to make even better in the + future. Many of these improvements come from error recovery. + - String escapes (`\n \t`). + - Raw strings that don't escape backslashes. + - String interpolations can only contain identifiers and not any expression. + - Operator associativity has been changed from right-to-left to left-to-right + to be more similar to other conventional languages. + - `and` now has a higher precedence than `or` (of same reason as the previous + point). + - Dates, times and timestamps have a stricter parsing rules. + - `let`, `func`, `prql`, `switch` are now treated as keywords. + - Float literals without fraction part are not allowed anymore (`1.`). - Add a `--format` option to `prqlc parse` which can return the AST in YAML (@max-sixty, #1962) @@ -15,6 +28,8 @@ **Documentation**: +- Operator precedence (@aljazerzen, #1818) + **Web**: **Integrations**: diff --git a/Cargo.lock b/Cargo.lock index 013e31762293..e23cb065dab2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -451,6 +451,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4d619fba796986dd538d82660b76e0b9756c6e19b2e4d4559ba5a57f9f00810" dependencies = [ "hashbrown 0.12.3", + "stacker", ] [[package]] @@ -500,7 +501,7 @@ checksum = "ec0b0588d44d4d63a87dbd75c136c166bbfd9a86a31cb89e09906521c7d3f5e3" dependencies = [ "bitflags", "clap_derive", - "clap_lex 0.3.1", + "clap_lex 0.3.2", "is-terminal", "once_cell", "strsim", @@ -510,9 +511,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.1.2" +version = "4.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd125be87bf4c255ebc50de0b7f4d2a6201e8ac3dc86e39c0ad081dc5e7236fe" +checksum = "0012995dc3a54314f4710f5631d74767e73c534b8757221708303e48eef7a19b" dependencies = [ "clap 4.1.6", ] @@ -541,9 +542,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "783fe232adfca04f90f56201b26d79682d4cd2625e0bc7290b95123afe558ade" +checksum = "350b9cf31731f9957399229e9b2adc51eeabdfbe9d71d9a0552275fd12710d09" dependencies = [ "os_str_bytes", ] @@ -1332,9 +1333,9 @@ dependencies = [ [[package]] name = "is-terminal" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22e18b0a45d56fe973d6db23972bf5bc46f988a4a2385deac9cc29572f09daef" +checksum = "21b6b32576413a8e69b90e952e4a026476040d81017b80445deda5f2d3921857" dependencies = [ "hermit-abi 0.3.1", "io-lifetimes", @@ -2132,8 +2133,6 @@ dependencies = [ "lazy_static", "log", "once_cell", - "pest", - "pest_derive", "postgres", "pretty_assertions", "regex", @@ -2215,6 +2214,15 @@ dependencies = [ "walkdir", ] +[[package]] +name = "psm" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5787f7cda34e3033a72192c018bc5883100330f362ef279a8cbccfce8bb4e874" +dependencies = [ + "cc", +] + [[package]] name = "ptr_meta" version = "0.1.4" @@ -2720,6 +2728,19 @@ dependencies = [ "serde", ] +[[package]] +name = "stacker" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c886bd4480155fd3ef527d45e9ac8dd7118a898a46530b7b94c3e21866259fce" +dependencies = [ + "cc", + "cfg-if", + "libc", + "psm", + "winapi", +] + [[package]] name = "static_assertions" version = "1.1.0" diff --git a/book/src/language-features/dates-and-times.md b/book/src/language-features/dates-and-times.md index 55d26e009a67..529eda6a6521 100644 --- a/book/src/language-features/dates-and-times.md +++ b/book/src/language-features/dates-and-times.md @@ -41,7 +41,7 @@ ISO8601 datetime format, which uses `T` to separate date & time. ```prql from commits -derive first_prql_commit = @2020-01-01T13:19:55-0800 +derive first_prql_commit = @2020-01-01T13:19:55-08:00 ``` ## Intervals diff --git a/book/src/language-features/f-strings.md b/book/src/language-features/f-strings.md index 1e1ada7cae71..24df646f9c8e 100644 --- a/book/src/language-features/f-strings.md +++ b/book/src/language-features/f-strings.md @@ -16,6 +16,9 @@ from web select url = f"http{tls}://www.{domain}.{tld}/{page}" ``` +Note that interpolations can only contain plain variable names and not whole +expression like Python. + ## Roadmap In the future, f-strings may incorporate string formatting such as datetimes, diff --git a/book/src/language-features/s-strings.md b/book/src/language-features/s-strings.md index fe2d133ef001..ed70b1923dbe 100644 --- a/book/src/language-features/s-strings.md +++ b/book/src/language-features/s-strings.md @@ -38,8 +38,11 @@ join s=salaries side:left [ For those who have used Python, s-strings are similar to Python's f-strings, but the result is SQL code, rather than a string literal. For example, a Python -f-string of `f"average{col}"` would produce `"average(salary)"`, with quotes; -while in PRQL, `s"average{col}"` produces `average(salary)`, without quotes. +f-string of `f"average({col})"` would produce `"average(salary)"`, with quotes; +while in PRQL, `s"average({col})"` produces `average(salary)`, without quotes. + +Note that interpolations can only contain plain variable names and not whole +expression like Python. We can also use s-strings to produce a full table: diff --git a/book/src/language-features/strings.md b/book/src/language-features/strings.md index db4b9d9e07db..922c5cac5e76 100644 --- a/book/src/language-features/strings.md +++ b/book/src/language-features/strings.md @@ -13,7 +13,7 @@ select x = 'hello world' ``` To quote a string containing quotes, either use the "other" type of quote, or -use three-or-more quotes, and close with the same number. +use 3, 4, 5 or 6 quotes, and close with the same number. ```prql from my_table @@ -30,7 +30,15 @@ from my_table select x = """""I said """hello world"""!""""" ``` -## F-strings and s-strings +Strings can also contain any escape defined by +[JSON standard](https://www.ecma-international.org/publications-and-standards/standards/ecma-404/). + +```prql +from my_table +select x = "\t\tline ends here\n \\ " +``` + +## F-Strings and S-Strings These special case strings can be used to: @@ -40,10 +48,6 @@ values [S-strings](./s-strings.md) - Insert SQL statements directly into the query. Use when PRQL doesn't have an equivalent facility. -```admonish note -Currently PRQL does not adjust escape characters. -``` - ```admonish warning Currently PRQL allows multiline strings with either a single character or multiple character quotes. This may change for strings using a single character diff --git a/book/src/syntax.md b/book/src/syntax.md index b23537228f4c..4c7ca169eccc 100644 --- a/book/src/syntax.md +++ b/book/src/syntax.md @@ -166,7 +166,24 @@ sort (-distance) sort [-distance] ``` -## Inner transforms +For a more formal definition, refer to this precedence table. Because function +call has the lowest precedence, nested function calls or arguments that start or +end with an operator require parenthesis. + +| Group | Operators | Precedence | Associativity | +| -------------- | ----------------- | ---------- | ------------- | +| identifier dot | `.` | 1 | | +| unary | `- + ! ==` | 2 | | +| range | `..` | 3 | | +| mul | `* / %` | 4 | left-to-right | +| add | `+ -` | 5 | left-to-right | +| compare | `== != <= >= < >` | 6 | left-to-right | +| coalesce | `??` | 7 | left-to-right | +| and | `and` | 8 | left-to-right | +| or | `or` | 9 | left-to-right | +| function call | | 10 | | + +## Inner Transforms Parentheses are also used for transforms (such as `group` and `window`) that pass their result to an "inner transform". The example below applies the @@ -261,3 +278,23 @@ select [ big = 5_000_000, ] ``` + +## Keywords + +At the moment, PRQL uses only four keywords: + +- `prql` +- `let` +- `func` +- `switch` + +To use these names as columns or relations, use backticks: `` `switch` ``. + +It may seem that transforms are also keywords, but they are normal function +within std namespace: + +```prql +std.from my_table +std.select [from = my_table.a, take = my_table.b] +std.take 3 +``` diff --git a/book/tests/prql/language-features/dates-and-times-2.prql b/book/tests/prql/language-features/dates-and-times-2.prql index 12687310b181..9efc7883716b 100644 --- a/book/tests/prql/language-features/dates-and-times-2.prql +++ b/book/tests/prql/language-features/dates-and-times-2.prql @@ -1,2 +1,2 @@ from commits -derive first_prql_commit = @2020-01-01T13:19:55-0800 +derive first_prql_commit = @2020-01-01T13:19:55-08:00 diff --git a/book/tests/prql/language-features/strings-5.prql b/book/tests/prql/language-features/strings-5.prql new file mode 100644 index 000000000000..491c9f04bdd1 --- /dev/null +++ b/book/tests/prql/language-features/strings-5.prql @@ -0,0 +1,2 @@ +from my_table +select x = "\t\tline ends here\n \\ " diff --git a/book/tests/prql/syntax-16.prql b/book/tests/prql/syntax-16.prql new file mode 100644 index 000000000000..029a0ea82464 --- /dev/null +++ b/book/tests/prql/syntax-16.prql @@ -0,0 +1,3 @@ +std.from my_table +std.select [from = my_table.a, take = my_table.b] +std.take 3 diff --git a/book/tests/snapshots/snapshot__@language-features__dates-and-times-2.prql.snap b/book/tests/snapshots/snapshot__@language-features__dates-and-times-2.prql.snap index c7886ddfa16a..55668e17d93e 100644 --- a/book/tests/snapshots/snapshot__@language-features__dates-and-times-2.prql.snap +++ b/book/tests/snapshots/snapshot__@language-features__dates-and-times-2.prql.snap @@ -1,10 +1,11 @@ --- source: book/tests/snapshot.rs -expression: "from commits\nderive first_prql_commit = @2020-01-01T13:19:55-0800\n" +expression: "from commits\nderive first_prql_commit = @2020-01-01T13:19:55-08:00\n" input_file: book/tests/prql/language-features/dates-and-times-2.prql --- SELECT *, - TIMESTAMP '2020-01-01T13:19:55-0800' AS first_prql_commit + TIMESTAMP '2020-01-01T13:19:55-08:00' AS first_prql_commit FROM commits + diff --git a/book/tests/snapshots/snapshot__@language-features__strings-5.prql.snap b/book/tests/snapshots/snapshot__@language-features__strings-5.prql.snap new file mode 100644 index 000000000000..1e5ef589937a --- /dev/null +++ b/book/tests/snapshots/snapshot__@language-features__strings-5.prql.snap @@ -0,0 +1,11 @@ +--- +source: book/tests/snapshot.rs +expression: "from my_table\nselect x = \"\\t\\tline ends here\\n \\\\ \"\n" +input_file: book/tests/prql/language-features/strings-5.prql +--- +SELECT + ' line ends here + \ ' AS x +FROM + my_table + diff --git a/book/tests/snapshots/snapshot__@syntax-16.prql.snap b/book/tests/snapshots/snapshot__@syntax-16.prql.snap new file mode 100644 index 000000000000..e62eb76cf856 --- /dev/null +++ b/book/tests/snapshots/snapshot__@syntax-16.prql.snap @@ -0,0 +1,13 @@ +--- +source: book/tests/snapshot.rs +expression: "std.from my_table\nstd.select [from = my_table.a, take = my_table.b]\nstd.take 3\n" +input_file: book/tests/prql/syntax-16.prql +--- +SELECT + a AS "from", + b AS take +FROM + my_table +LIMIT + 3 + diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-2.prql.snap index 1507a39b0252..a2f42142ebb6 100644 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-2.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-2.prql.snap @@ -1,9 +1,9 @@ --- source: book/tests/snapshot.rs -expression: "from commits\nderive first_prql_commit = @2020-01-01T13:19:55-0800\n" +expression: "from commits\nderive first_prql_commit = @2020-01-01T13:19:55-08:00\n" --- from commits -derive first_prql_commit = @2020-01-01T13:19:55-0800 +derive first_prql_commit = @2020-01-01T13:19:55-08:00 diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__strings-5.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__strings-5.prql.snap new file mode 100644 index 000000000000..4a0b8ddabd77 --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__language-features__strings-5.prql.snap @@ -0,0 +1,10 @@ +--- +source: book/tests/snapshot.rs +expression: "from my_table\nselect x = \"\\t\\tline ends here\\n \\\\ \"\n" +--- +from my_table +select x = " line ends here + \ " + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__syntax-16.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-16.prql.snap new file mode 100644 index 000000000000..ddc2d6ddb49a --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__syntax-16.prql.snap @@ -0,0 +1,13 @@ +--- +source: book/tests/snapshot.rs +expression: "std.from my_table\nstd.select [from = my_table.a, take = my_table.b]\nstd.take 3\n" +--- +std.from my_table +std.select [ + from = my_table.a, + take = my_table.b, +] +std.take 3 + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__sort-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__sort-2.prql.snap index 23c2050900c8..a7ddb76e2ecc 100644 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__sort-2.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__transforms__sort-2.prql.snap @@ -6,7 +6,7 @@ from employees sort [ age, -tenure, - salary, + +salary, ] diff --git a/prql-compiler/Cargo.toml b/prql-compiler/Cargo.toml index 9323ff5f59d3..3faa6d29a725 100644 --- a/prql-compiler/Cargo.toml +++ b/prql-compiler/Cargo.toml @@ -15,17 +15,13 @@ metadata.msrv = "1.65.0" [dependencies] anyhow = {version = "1.0.57", features = ["backtrace"]} ariadne = "0.1.5" -# We don't include the `spill-stack` feature, since it causes builds in GHA to -# fail. If that no longer happens, we can re-enable it. -chumsky = {version = "0.9.0", features = ["ahash", "std"], default-features = false } +chumsky = "0.9.0" csv = "1.2.0" enum-as-inner = "0.5.0" itertools = "0.10.3" lazy_static = "1.4.0" log = "0.4.17" once_cell = "1.17.0" -pest = "2.5.0" -pest_derive = "2.5.0" regex = "1.7.0" semver = {version = "1.0.14", features = ["serde"]} serde = {version = "1.0.137", features = ["derive"]} @@ -41,7 +37,7 @@ insta = {version = "1.28", features = ["colors", "glob", "yaml"]} # For integration tests [target.'cfg(not(target_family="wasm"))'.dev-dependencies] -chrono = "0.4" +chrono = {version = "0.4", features = [], default-features = false } criterion = "0.4.0" postgres = "0.19.3" pretty_assertions = "1.3.0" diff --git a/prql-compiler/prqlc/src/cli.rs b/prql-compiler/prqlc/src/cli.rs index c8f03ec9d9e8..41db7dc8825a 100644 --- a/prql-compiler/prqlc/src/cli.rs +++ b/prql-compiler/prqlc/src/cli.rs @@ -356,7 +356,6 @@ group a_column (take 10 | sort b_column | derive [the_number = rank, last = lag args: - Ident: - x - named_args: {} - FuncCall: name: Ident: @@ -364,7 +363,6 @@ group a_column (take 10 | sort b_column | derive [the_number = rank, last = lag args: - Ident: - y - named_args: {} "###); } } diff --git a/prql-compiler/src/ast/pl/expr.rs b/prql-compiler/src/ast/pl/expr.rs index e6792d7d8f10..cfba08fc4934 100644 --- a/prql-compiler/src/ast/pl/expr.rs +++ b/prql-compiler/src/ast/pl/expr.rs @@ -89,7 +89,16 @@ impl ExprKind { } #[derive( - Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize, strum::Display, strum::EnumString, + Debug, + PartialEq, + Eq, + Clone, + Copy, + Hash, + Serialize, + Deserialize, + strum::Display, + strum::EnumString, )] pub enum BinOp { #[strum(to_string = "*")] @@ -122,12 +131,12 @@ pub enum BinOp { Coalesce, } -#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize, strum::EnumString)] +#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Serialize, Deserialize, strum::EnumString)] pub enum UnOp { #[strum(to_string = "-")] Neg, #[strum(to_string = "+")] - Add, + Add, // TODO: rename to Pos #[strum(to_string = "!")] Not, #[strum(to_string = "==")] @@ -142,6 +151,7 @@ pub struct ListItem(pub Expr); pub struct FuncCall { pub name: Box, pub args: Vec, + #[serde(default, skip_serializing_if = "HashMap::is_empty")] pub named_args: HashMap, } diff --git a/prql-compiler/src/error.rs b/prql-compiler/src/error.rs index 4d0151b3ff6e..92f3f3492210 100644 --- a/prql-compiler/src/error.rs +++ b/prql-compiler/src/error.rs @@ -6,7 +6,6 @@ use std::error::Error as StdError; use std::fmt::{self, Debug, Display, Formatter}; use std::ops::{Add, Range}; -use crate::parser::PestError; use crate::utils::IntoOnly; #[derive(Clone, PartialEq, Eq, Copy, Serialize, Deserialize)] @@ -22,6 +21,9 @@ pub struct Error { pub help: Option, } +#[derive(Debug, Clone)] +pub struct Errors(pub Vec); + /// Location within the source file. /// Tuples contain: /// - line number (0-based), @@ -109,6 +111,9 @@ impl Display for ErrorMessage { // Needed for anyhow impl StdError for Error {} +// Needed for anyhow +impl StdError for Errors {} + // Needed for StdError impl Display for Error { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { @@ -116,6 +121,13 @@ impl Display for Error { } } +// Needed for StdError +impl Display for Errors { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + Debug::fmt(&self, f) + } +} + #[derive(Debug, Clone, Serialize)] pub struct ErrorMessages { pub inner: Vec, @@ -146,6 +158,19 @@ pub fn downcast(error: anyhow::Error) -> ErrorMessages { Err(error) => error, }; + let error = match error.downcast::() { + Ok(messages) => { + return ErrorMessages { + inner: messages + .0 + .into_iter() + .flat_map(|e| downcast(e.into()).inner) + .collect(), + } + } + Err(error) => error, + }; + let reason = match error.downcast::() { Ok(error) => { span = error.span; @@ -154,21 +179,8 @@ pub fn downcast(error: anyhow::Error) -> ErrorMessages { error.reason.message() } Err(error) => { - match error.downcast::() { - Ok(error) => { - let range = pest::as_range(&error); - span = Some(Span { - start: range.start, - end: range.end, - }); - - pest::as_message(&error) - } - Err(error) => { - // default to basic Display - format!("{:#?}", error) - } - } + // default to basic Display + format!("{:#?}", error) } }; @@ -267,59 +279,6 @@ impl Reason { } } -mod pest { - use pest::error::{ErrorVariant, InputLocation}; - use std::ops::Range; - - use crate::parser::{PestError, PestRule}; - - pub fn as_range(error: &PestError) -> Range { - match error.location { - InputLocation::Pos(r) => r..r + 1, - InputLocation::Span(r) => r.0..r.1, - } - } - - pub fn as_message(error: &PestError) -> String { - match error.variant { - ErrorVariant::ParsingError { - ref positives, - ref negatives, - } => parsing_error_message(positives, negatives), - ErrorVariant::CustomError { ref message } => message.clone(), - } - } - - fn parsing_error_message(positives: &[PestRule], negatives: &[PestRule]) -> String { - match (negatives.is_empty(), positives.is_empty()) { - (false, false) => format!( - "unexpected {}; expected {}", - enumerate(negatives), - enumerate(positives) - ), - (false, true) => format!("unexpected {}", enumerate(negatives)), - (true, false) => format!("expected {}", enumerate(positives)), - (true, true) => "unknown parsing error".to_owned(), - } - } - - fn enumerate(rules: &[PestRule]) -> String { - match rules.len() { - 1 => format!("{:?}", rules[0]), - 2 => format!("{:?} or {:?}", rules[0], rules[1]), - l => { - let separated = rules - .iter() - .take(l - 1) - .map(|x| format!("{:?}", x)) - .collect::>() - .join(", "); - format!("{}, or {:?}", separated, rules[l - 1]) - } - } - } -} - impl From for Range { fn from(a: Span) -> Self { a.start..a.end diff --git a/prql-compiler/src/parser/chumsky.rs b/prql-compiler/src/parser/chumsky.rs deleted file mode 100644 index 95c031453c5e..000000000000 --- a/prql-compiler/src/parser/chumsky.rs +++ /dev/null @@ -1,80 +0,0 @@ -#![allow(dead_code)] - -use chumsky::prelude::*; - -use crate::ast::pl::*; - -fn str(chars: &str) -> impl Parser> + '_ { - just(chars).to(()) -} - -fn operator() -> impl Parser> { - operator_binary().to(()).or(operator_unary().to(())) -} - -fn operator_binary() -> impl Parser> { - operator_mul() - .or(operator_add()) - .or(operator_compare()) - .or(operator_logical()) - .or(operator_coalesce()) -} -fn operator_unary() -> impl Parser> { - just('-') - .to(UnOp::Neg) - .or(just('+').to(UnOp::Add)) - .or(just('!').to(UnOp::Not)) - .or(str("==").to(UnOp::EqSelf)) -} -fn operator_mul() -> impl Parser> { - (just('*').to(BinOp::Mul)) - .or(just('/').to(BinOp::Div)) - .or(just('%').to(BinOp::Mod)) -} -fn operator_add() -> impl Parser> { - just('+').to(BinOp::Add).or(just('-').to(BinOp::Sub)) -} -fn operator_compare() -> impl Parser> { - str("==") - .to(BinOp::Eq) - .or(str("!=").to(BinOp::Ne)) - .or(str(">=").to(BinOp::Gte)) - .or(str("<=").to(BinOp::Lte)) - .or(str(">").to(BinOp::Gt)) - .or(str("<").to(BinOp::Lt)) -} -fn operator_logical() -> impl Parser> { - (just("and").to(BinOp::Add)) - .or(just("or").to(BinOp::Or)) - .then_ignore(text::whitespace()) -} -fn operator_coalesce() -> impl Parser> { - just("??").map(|_| BinOp::Coalesce) -} - -fn ident_part() -> impl Parser> { - let plain = filter(|c: &char| c.is_ascii_alphabetic() || *c == '_' || *c == '$') - .map(Some) - .chain::, _>( - filter(|c: &char| c.is_ascii_alphanumeric() || *c == '_').repeated(), - ) - .collect(); - - let backticks = just('`') - .ignore_then(filter(|c| *c != '`').repeated()) - .then_ignore(just('`')) - .collect::(); - - plain.or(backticks) -} - -pub fn ident() -> impl Parser> { - let star = just('*').map(|c| c.to_string()); - - // TODO: !operator ~ !(keyword ~ WHITESPACE) - // we probably need combinator::Not, which has not been released yet. - - ident_part() - .chain(just('.').ignore_then(ident_part().or(star)).repeated()) - .map(Ident::from_path::) -} diff --git a/prql-compiler/src/parser/expr.rs b/prql-compiler/src/parser/expr.rs new file mode 100644 index 000000000000..ea9c2d32cbc7 --- /dev/null +++ b/prql-compiler/src/parser/expr.rs @@ -0,0 +1,305 @@ +use std::collections::HashMap; + +use chumsky::prelude::*; + +use crate::ast::pl::*; + +use super::common::*; +use super::interpolation; +use super::lexer::Token; + +pub fn expr_call() -> impl Parser> { + func_call(expr()) +} + +pub fn expr() -> impl Parser> + Clone { + recursive(|expr| { + let literal = select! { Token::Literal(lit) => ExprKind::Literal(lit) }; + + let ident_kind = ident().map(ExprKind::Ident); + + let nested_expr = pipeline(func_call(expr.clone())).boxed(); + + let list = ident_part() + .then_ignore(ctrl('=')) + .or_not() + .then(nested_expr.clone().map_with_span(into_expr)) + .map(|(alias, expr)| Expr { alias, ..expr }) + .padded_by(new_line().repeated()) + .separated_by(ctrl(',')) + .allow_trailing() + .then_ignore(new_line().repeated()) + .delimited_by(ctrl('['), ctrl(']')) + .recover_with(nested_delimiters( + Token::Control('['), + Token::Control(']'), + [ + (Token::Control('['), Token::Control(']')), + (Token::Control('('), Token::Control(')')), + ], + |_| vec![], + )) + .map(ExprKind::List) + .labelled("list"); + + let pipeline = + nested_expr + .delimited_by(ctrl('('), ctrl(')')) + .recover_with(nested_delimiters( + Token::Control('('), + Token::Control(')'), + [ + (Token::Control('['), Token::Control(']')), + (Token::Control('('), Token::Control(')')), + ], + |_| Expr::null().kind, + )); + + let interpolation = + select! { + Token::Interpolation('s', string) => (ExprKind::SString as fn(_) -> _, string), + Token::Interpolation('f', string) => (ExprKind::FString as fn(_) -> _, string), + } + .validate(|(finish, string), span: std::ops::Range, emit| { + match interpolation::parse(string, span.start + 2) { + Ok(items) => finish(items), + Err(errors) => { + for err in errors { + emit(err) + } + finish(vec![]) + } + } + }); + + let switch = keyword("switch") + .ignore_then( + func_call(expr.clone()) + .then_ignore(just(Token::Arrow)) + .then(func_call(expr)) + .map(|(condition, value)| SwitchCase { condition, value }) + .padded_by(new_line().repeated()) + .separated_by(ctrl(',')) + .allow_trailing() + .then_ignore(new_line().repeated()) + .delimited_by(ctrl('['), ctrl(']')), + ) + .map(ExprKind::Switch); + + let term = choice((literal, list, pipeline, interpolation, ident_kind, switch)) + .map_with_span(into_expr) + .boxed(); + + // Unary operators + let term = term + .clone() + .or(operator_unary() + .then(term.map(Box::new)) + .map(|(op, expr)| ExprKind::Unary { op, expr }) + .map_with_span(into_expr)) + .boxed(); + + // Ranges have five cases we need to parse: + // x..y (bounded) + // x.. (only start bound) + // x (no-op) + // ..y (only end bound) + // .. (unbounded) + #[derive(Clone)] + enum RangeCase { + NoOp(Expr), + Range(Option, Option), + } + let term = choice(( + // with start bound (first 3 cases) + term.clone() + .then(choice(( + // range and end bound + just(Token::range(true, true)) + .ignore_then(term.clone()) + .map(|x| Some(Some(x))), + // range and no end bound + select! { Token::Range { bind_left: true, .. } => Some(None) }, + // no range + empty().to(None), + ))) + .map(|(start, range)| { + if let Some(end) = range { + RangeCase::Range(Some(start), end) + } else { + RangeCase::NoOp(start) + } + }), + // only end bound + select! { Token::Range { bind_right: true, .. } => () } + .ignore_then(term) + .map(|range| RangeCase::Range(None, Some(range))), + // unbounded + select! { Token::Range { .. } => RangeCase::Range(None, None) }, + )) + .map_with_span(|case, span| match case { + RangeCase::NoOp(x) => x, + RangeCase::Range(start, end) => { + let kind = ExprKind::Range(Range { + start: start.map(Box::new), + end: end.map(Box::new), + }); + into_expr(kind, span) + } + }) + .boxed(); + + // Binary operators + let expr = term; + let expr = binary_op_parser(expr, operator_mul()); + let expr = binary_op_parser(expr, operator_add()); + let expr = binary_op_parser(expr, operator_compare()); + let expr = binary_op_parser(expr, operator_coalesce()); + let expr = binary_op_parser(expr, operator_and()); + + binary_op_parser(expr, operator_or()) + }) +} + +pub fn pipeline(expr: E) -> impl Parser> +where + E: Parser>, +{ + // expr has to be a param, because it can be either a normal expr() or + // a recursive expr called from within expr() + + new_line() + .repeated() + .ignore_then( + expr.separated_by(ctrl('|').or(new_line().repeated().at_least(1).ignored())) + .at_least(1) + .map(|mut exprs| { + if exprs.len() == 1 { + exprs.remove(0).kind + } else { + ExprKind::Pipeline(Pipeline { exprs }) + } + }), + ) + .then_ignore(new_line().repeated()) + .labelled("pipeline") +} + +fn binary_op_parser<'a, Term, Op>( + term: Term, + op: Op, +) -> impl Parser> + 'a +where + Term: Parser> + 'a, + Op: Parser> + 'a, +{ + let term = term.map_with_span(|e, s| (e, s)).boxed(); + + (term.clone()) + .then(op.then(term).repeated()) + .foldl(|left, (op, right)| { + let span = left.1.start..right.1.end; + let kind = ExprKind::Binary { + left: Box::new(left.0), + op, + right: Box::new(right.0), + }; + (into_expr(kind, span.clone()), span) + }) + .map(|(e, _)| e) + .boxed() +} + +fn func_call(expr: E) -> impl Parser> +where + E: Parser> + Clone, +{ + let func = expr.clone(); + + let named_arg = ident_part() + .map(Some) + .then_ignore(ctrl(':')) + .then(expr.clone()); + + let assign_call = + ident_part() + .then_ignore(ctrl('=')) + .then(expr.clone()) + .map(|(alias, expr)| Expr { + alias: Some(alias), + ..expr + }); + let positional_arg = assign_call.or(expr).map(|expr| (None, expr)); + + let args = named_arg.or(positional_arg).repeated(); + + func.then(args) + .validate(|(name, args), span, emit| { + if args.is_empty() { + return name.kind; + } + + let mut named_args = HashMap::new(); + let mut positional = Vec::new(); + for (name, arg) in args { + if let Some(name) = name { + if named_args.contains_key(&name) { + let err = Simple::custom(span.clone(), "argument is used multiple times"); + emit(err) + } + named_args.insert(name, arg); + } else { + positional.push(arg); + } + } + + ExprKind::FuncCall(FuncCall { + name: Box::new(name), + args: positional, + named_args, + }) + }) + .map_with_span(into_expr) + .labelled("function call") +} + +pub fn ident() -> impl Parser> { + let star = ctrl('*').to("*".to_string()); + + ident_part() + .chain(ctrl('.').ignore_then(ident_part().or(star)).repeated()) + .map(Ident::from_path::) + .labelled("identifier") +} + +fn operator_unary() -> impl Parser> { + (ctrl('+').to(UnOp::Add)) + .or(ctrl('-').to(UnOp::Neg)) + .or(ctrl('!').to(UnOp::Not)) + .or(just(Token::Eq).to(UnOp::EqSelf)) +} +fn operator_mul() -> impl Parser> { + (ctrl('*').to(BinOp::Mul)) + .or(ctrl('/').to(BinOp::Div)) + .or(ctrl('%').to(BinOp::Mod)) +} +fn operator_add() -> impl Parser> { + (ctrl('+').to(BinOp::Add)).or(ctrl('-').to(BinOp::Sub)) +} +fn operator_compare() -> impl Parser> { + (just(Token::Eq).to(BinOp::Eq)) + .or(just(Token::Ne).to(BinOp::Ne)) + .or(just(Token::Lte).to(BinOp::Lte)) + .or(just(Token::Gte).to(BinOp::Gte)) + .or(ctrl('<').to(BinOp::Lt)) + .or(ctrl('>').to(BinOp::Gt)) +} +fn operator_and() -> impl Parser> { + just(Token::And).to(BinOp::And) +} +fn operator_or() -> impl Parser> { + just(Token::Or).to(BinOp::Or) +} +fn operator_coalesce() -> impl Parser> { + just(Token::Coalesce).to(BinOp::Coalesce) +} diff --git a/prql-compiler/src/parser/interpolation.rs b/prql-compiler/src/parser/interpolation.rs new file mode 100644 index 000000000000..2b3c75f92f5a --- /dev/null +++ b/prql-compiler/src/parser/interpolation.rs @@ -0,0 +1,55 @@ +use chumsky::{error::Cheap, prelude::*}; +use itertools::Itertools; + +use crate::ast::pl::*; + +use super::{common::into_expr, lexer::*}; + +/// Parses interpolated strings +pub fn parse( + string: String, + span_offset: usize, +) -> Result, Vec>> { + let res = parser(span_offset).parse(string); + + match res { + Ok(items) => Ok(items), + Err(errors) => Err(errors + .into_iter() + .map(|err| { + Simple::expected_input_found(offset_span(err.span(), span_offset), None, None) + }) + .collect_vec()), + } +} + +fn parser(span_offset: usize) -> impl Parser, Error = Cheap> { + let expr = ident_part() + .separated_by(just('.')) + .delimited_by(just('{'), just('}')) + .map(Ident::from_path) + .map(ExprKind::Ident) + .map_with_span(move |e, s| into_expr(e, offset_span(s, span_offset))) + .map(Box::new) + .map(InterpolateItem::Expr); + + let escape = (just("{{").to('{')) + .chain(just("}}").not().repeated()) + .chain(just("}}").to('}')) + .collect::() + .map(InterpolateItem::String); + + let string = none_of('{') + .repeated() + .at_least(1) + .collect::() + .map(InterpolateItem::String); + + escape.or(expr).or(string).repeated().then_ignore(end()) +} + +fn offset_span(mut span: std::ops::Range, span_offset: usize) -> std::ops::Range { + span.start += span_offset; + span.end += span_offset; + span +} diff --git a/prql-compiler/src/parser/lexer.rs b/prql-compiler/src/parser/lexer.rs new file mode 100644 index 000000000000..11d63f491300 --- /dev/null +++ b/prql-compiler/src/parser/lexer.rs @@ -0,0 +1,399 @@ +use chumsky::{error::Cheap, prelude::*}; + +use crate::ast::pl::*; + +#[derive(Clone, PartialEq, Debug)] +pub enum Token { + NewLine, + + Ident(String), + Keyword(String), + Literal(Literal), + + Range { + bind_left: bool, + bind_right: bool, + }, + Interpolation(char, String), + + /// single-char control tokens + Control(char), + + Arrow, // -> + ArrowDouble, // => + Eq, // == + Ne, // != + Gte, // >= + Lte, // <= + And, // and + Or, // or + Coalesce, // ?? +} + +pub fn lexer() -> impl Parser)>, Error = Cheap> { + let new_line = just('\n').to(Token::NewLine); + let whitespace = one_of("\t \r").repeated().at_least(1).ignored(); + + let control_multi = choice(( + just("->").to(Token::Arrow), + just("=>").to(Token::ArrowDouble), + just("==").to(Token::Eq), + just("!=").to(Token::Ne), + just(">=").to(Token::Gte), + just("<=").to(Token::Lte), + just("and").then_ignore(end_expr()).to(Token::And), + just("or").then_ignore(end_expr()).to(Token::Or), + just("??").to(Token::Coalesce), + )); + + let control = one_of("> impl Parser> { + let plain = filter(|c: &char| c.is_ascii_alphabetic() || *c == '_' || *c == '$') + .map(Some) + .chain::, _>( + filter(|c: &char| c.is_ascii_alphanumeric() || *c == '_').repeated(), + ) + .collect(); + + let backticks = just('`') + .ignore_then(none_of('`').repeated()) + .then_ignore(just('`')) + .collect::(); + + plain.or(backticks) +} + +fn literal() -> impl Parser> { + let exp = just('e').or(just('E')).ignore_then( + just('+') + .or(just('-')) + .or_not() + .chain::(text::digits(10)), + ); + + let integer = filter(|c: &char| c.is_ascii_digit() && *c != '0') + .chain::<_, Vec, _>(filter(|c: &char| c.is_ascii_digit() || *c == '_').repeated()) + .or(just('0').map(|c| vec![c])); + + let frac = just('.') + .chain::(filter(|c: &char| c.is_ascii_digit())) + .chain::(filter(|c: &char| c.is_ascii_digit() || *c == '_').repeated()); + + let number = just('+') + .or(just('-')) + .or_not() + .chain::(integer) + .chain::(frac.or_not().flatten()) + .chain::(exp.or_not().flatten()) + .try_map(|chars, span| { + let str = chars.into_iter().filter(|c| *c != '_').collect::(); + + if let Ok(i) = str.parse::() { + Ok(Literal::Integer(i)) + } else if let Ok(f) = str.parse::() { + Ok(Literal::Float(f)) + } else { + Err(Cheap::expected_input_found(span, None, None)) + } + }) + .labelled("number"); + + let string = quoted_string(true).map(Literal::String); + + let raw_string = just("r") + .ignore_then(quoted_string(false)) + .map(Literal::String); + + let bool = (just("true").to(true)) + .or(just("false").to(false)) + .then_ignore(end_expr()) + .map(Literal::Boolean); + + let null = just("null").to(Literal::Null).then_ignore(end_expr()); + + let value_and_unit = integer + .then(choice(( + just("microseconds"), + just("milliseconds"), + just("seconds"), + just("minutes"), + just("hours"), + just("days"), + just("weeks"), + just("months"), + just("years"), + ))) + .then_ignore(end_expr()) + .try_map(|(number, unit), span| { + let str = number.into_iter().filter(|c| *c != '_').collect::(); + if let Ok(n) = str.parse::() { + let unit = unit.to_string(); + Ok(ValueAndUnit { n, unit }) + } else { + Err(Cheap::expected_input_found(span, None, None)) + } + }) + .map(Literal::ValueAndUnit); + + let date_inner = digits(4) + .chain(just('-')) + .chain::(digits(2)) + .chain::(just('-')) + .chain::(digits(2)) + .boxed(); + + let time_inner = digits(2) + // minutes + .chain::(just(':').chain(digits(2)).or_not().flatten()) + // seconds + .chain::(just(':').chain(digits(2)).or_not().flatten()) + // milliseconds + .chain::( + just('.') + .chain( + filter(|c: &char| c.is_ascii_digit()) + .repeated() + .at_least(1) + .at_most(6), + ) + .or_not() + .flatten(), + ) + // timezone offset + .chain::( + one_of("-+") + .chain( + digits(2) + .chain(just(':')) + .chain(digits(2)) + .or(just('Z').map(|x| vec![x])), + ) + .or_not() + .flatten(), + ) + .boxed(); + + let date = just('@') + .ignore_then(date_inner.clone()) + .then_ignore(end_expr()) + .collect::() + .map(Literal::Date); + + let time = just('@') + .ignore_then(time_inner.clone()) + .then_ignore(end_expr()) + .collect::() + .map(Literal::Time); + + let datetime = just('@') + .ignore_then(date_inner) + .chain(just('T')) + .chain::(time_inner) + .then_ignore(end_expr()) + .collect::() + .map(Literal::Timestamp); + + choice(( + string, + raw_string, + value_and_unit, + number, + bool, + null, + datetime, + date, + time, + )) +} + +fn quoted_string(escaped: bool) -> impl Parser> { + // I don't know how this could be simplified and implemented for n>3 in general + choice(( + quoted_string_inner(r#""""""""#, escaped), + quoted_string_inner(r#"""""""#, escaped), + quoted_string_inner(r#""""""#, escaped), + quoted_string_inner(r#"""""#, escaped), + quoted_string_inner(r#"""#, escaped), + quoted_string_inner(r#"''''''"#, escaped), + quoted_string_inner(r#"'''''"#, escaped), + quoted_string_inner(r#"''''"#, escaped), + quoted_string_inner(r#"'''"#, escaped), + quoted_string_inner(r#"'"#, escaped), + )) + .collect::() + .labelled("string") +} + +fn quoted_string_inner( + quotes: &str, + escaping: bool, +) -> impl Parser, Error = Cheap> + '_ { + let mut forbidden = just(quotes).boxed(); + + if escaping { + forbidden = just(quotes).or(just("\\")).boxed() + }; + + let mut inner = forbidden.not().boxed(); + + if escaping { + inner = inner + .or(just('\\').ignore_then( + just('\\') + .or(just('/')) + .or(just('"')) + .or(just('b').to('\x08')) + .or(just('f').to('\x0C')) + .or(just('n').to('\n')) + .or(just('r').to('\r')) + .or(just('t').to('\t')) + .or(just('u').ignore_then( + filter(|c: &char| c.is_ascii_hexdigit()) + .repeated() + .exactly(4) + .collect::() + .validate(|digits, span, emit| { + char::from_u32(u32::from_str_radix(&digits, 16).unwrap()) + .unwrap_or_else(|| { + emit(Cheap::expected_input_found(span, None, None)); + '\u{FFFD}' // unicode replacement character + }) + }), + )), + )) + .boxed(); + } + + inner.repeated().delimited_by(just(quotes), just(quotes)) +} + +fn digits(count: usize) -> impl Parser, Error = Cheap> { + filter(|c: &char| c.is_ascii_digit()) + .repeated() + .exactly(count) +} + +fn end_expr() -> impl Parser> { + choice((end(), one_of(",)]\r\n\t ").ignored(), just("..").ignored())).rewind() +} + +impl Token { + pub fn range(bind_left: bool, bind_right: bool) -> Self { + Token::Range { + bind_left, + bind_right, + } + } +} + +// This is here because Literal::Float(f64) does not implement Hash, so we cannot simply derive it. +// There are reasons for that, but chumsky::Error needs Hash for the Token, so it can deduplicate +// tokens in error. +// So this hack could lead to duplicated tokens in error messages. Oh no. +#[allow(clippy::derive_hash_xor_eq)] +impl std::hash::Hash for Token { + fn hash(&self, state: &mut H) { + core::mem::discriminant(self).hash(state); + } +} + +impl std::cmp::Eq for Token {} + +impl std::fmt::Display for Token { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::NewLine => write!(f, "new line"), + Self::Ident(arg0) => { + if arg0.is_empty() { + write!(f, "an identifier") + } else { + write!(f, "`{arg0}`") + } + } + Self::Keyword(arg0) => write!(f, "keyword {arg0}"), + Self::Literal(arg0) => write!(f, "{arg0}"), + Self::Control(arg0) => write!(f, "{arg0}"), + + Self::Arrow => f.write_str("->"), + Self::ArrowDouble => f.write_str("=>"), + Self::Eq => f.write_str("=="), + Self::Ne => f.write_str("!="), + Self::Gte => f.write_str(">="), + Self::Lte => f.write_str("<="), + Self::And => f.write_str("and"), + Self::Or => f.write_str("or"), + Self::Coalesce => f.write_str("??"), + + Self::Range { + bind_left, + bind_right, + } => write!( + f, + "'{}..{}'", + if *bind_left { "" } else { " " }, + if *bind_right { "" } else { " " } + ), + Self::Interpolation(c, s) => { + write!(f, "{c}\"{}\"", s) + } + } + } +} diff --git a/prql-compiler/src/parser/mod.rs b/prql-compiler/src/parser/mod.rs index 4483911c5604..461cc0eb5d5f 100644 --- a/prql-compiler/src/parser/mod.rs +++ b/prql-compiler/src/parser/mod.rs @@ -2,453 +2,210 @@ //! of pest pairs into a tree of AST Items. It has a small function to call into //! pest to get the parse tree / concrete syntax tree, and then a large //! function for turning that into PRQL AST. -mod chumsky; - -use std::collections::HashMap; -use std::str::FromStr; - -use anyhow::bail; -use anyhow::{anyhow, Result}; +mod expr; +mod interpolation; +mod lexer; +mod stmt; + +use anyhow::Result; +use chumsky::{ + error::{Cheap, SimpleReason}, + prelude::*, + Stream, +}; use itertools::Itertools; -use pest::iterators::Pair; -use pest::iterators::Pairs; -use pest::Parser; -use pest_derive::Parser; -use super::ast::pl::*; -use super::utils::*; -use crate::error::Span; +use self::lexer::Token; -#[derive(Parser)] -#[grammar = "parser/prql.pest"] -struct PrqlParser; +use super::ast::pl::*; -pub(crate) type PestError = pest::error::Error; -pub(crate) type PestRule = Rule; +use crate::error::{Error, Errors, Reason}; /// Build PL AST from a PRQL query string. -pub fn parse(string: &str) -> Result> { - let pairs = parse_tree_of_str(string, Rule::statements)?; - - stmts_of_parse_pairs(pairs) -} - -/// Parse a string into a parse tree / concrete syntax tree, made up of pest Pairs. -fn parse_tree_of_str(source: &str, rule: Rule) -> Result> { - Ok(PrqlParser::parse(rule, source)?) -} +pub fn parse(source: &str) -> Result> { + let mut errors = Vec::new(); -/// Parses a parse tree of pest Pairs into a list of statements. -fn stmts_of_parse_pairs(pairs: Pairs) -> Result> { - pairs - .filter(|p| !matches!(p.as_rule(), Rule::EOI)) - .map(stmt_of_parse_pair) - .collect() -} + let (tokens, lex_errors) = ::chumsky::Parser::parse_recovery(&lexer::lexer(), source); -fn stmt_of_parse_pair(pair: Pair) -> Result { - let span = pair.as_span(); - let rule = pair.as_rule(); + errors.extend( + lex_errors + .into_iter() + .map(|e| convert_lexer_error(source, e)), + ); - let kind = match rule { - Rule::pipeline_stmt => { - let pipeline = expr_of_parse_pair(pair.into_inner().next().unwrap())?; - StmtKind::Main(Box::new(pipeline)) - } - Rule::query_def => { - let mut params: HashMap<_, _> = pair - .into_inner() - .map(|x| parse_named(x.into_inner())) - .try_collect()?; - - let version = params - .remove("version") - .map(|v| v.try_cast(|i| i.parse_version(), None, "semver version number string")) - .transpose()?; - - let other = params - .into_iter() - .flat_map(|(key, value)| match value.kind { - ExprKind::Ident(value) => Some((key, value.to_string())), - _ => None, - }) - .collect(); - - StmtKind::QueryDef(QueryDef { version, other }) - } - Rule::func_def => { - let mut pairs = pair.into_inner(); - let name = pairs.next().unwrap(); - let params = pairs.next().unwrap(); - let body = pairs.next().unwrap(); - - let (name, return_type, _) = parse_typed_ident(name)?; - - let params: Vec<_> = params - .into_inner() - .into_iter() - .map(parse_typed_ident) - .try_collect()?; - - let mut positional_params = vec![]; - let mut named_params = vec![]; - for (name, ty, default_value) in params { - let param = FuncParam { - name, - ty, - default_value, - }; - if param.default_value.is_some() { - named_params.push(param) - } else { - positional_params.push(param) - } - } + let ast = if let Some(tokens) = tokens { + let len = source.chars().count(); + let stream = Stream::from_iter(len..len + 1, tokens.into_iter()); - StmtKind::FuncDef(FuncDef { - name, - positional_params, - named_params, - body: Box::from(expr_of_parse_pair(body)?), - return_ty: return_type, - }) - } - Rule::var_def => { - let mut pairs = pair.into_inner(); + let (ast, parse_errors) = ::chumsky::Parser::parse_recovery(&stmt::source(), stream); - let name = parse_ident_part(pairs.next().unwrap()); - let value = Box::new(expr_of_parse_pair(pairs.next().unwrap())?); + errors.extend(parse_errors.into_iter().map(convert_parser_error)); - StmtKind::VarDef(VarDef { name, value }) - } - _ => unreachable!("{pair}"), + ast + } else { + None }; - let mut stmt = Stmt::from(kind); - stmt.span = Some(Span { - start: span.start(), - end: span.end(), - }); - Ok(stmt) -} -/// Parses a parse tree of pest Pairs into an AST. -fn exprs_of_parse_pairs(pairs: Pairs) -> Result> { - pairs - .filter(|p| !matches!(p.as_rule(), Rule::EOI)) - .map(expr_of_parse_pair) - .collect() + if errors.is_empty() { + Ok(ast.unwrap_or_default()) + } else { + Err(Errors(errors).into()) + } } -fn expr_of_parse_pair(pair: Pair) -> Result { - let span = pair.as_span(); - let rule = pair.as_rule(); - let mut alias = None; - - let kind = match rule { - Rule::list => ExprKind::List(exprs_of_parse_pairs(pair.into_inner())?), - Rule::expr_mul | Rule::expr_add | Rule::expr_compare | Rule::expr => { - let mut pairs = pair.into_inner(); - - let mut expr = expr_of_parse_pair(pairs.next().unwrap())?; - if let Some(op) = pairs.next() { - let op = BinOp::from_str(op.as_str())?; - - expr = Expr::from(ExprKind::Binary { - op, - left: Box::new(expr), - right: Box::new(expr_of_parse_pair(pairs.next().unwrap())?), - }); - } +fn convert_lexer_error(source: &str, e: Cheap) -> Error { + let found = source[e.span()].to_string(); + let span = common::into_span(e.span()); - expr.kind - } - Rule::expr_unary => { - let mut pairs = pair.into_inner(); - - let op = pairs.next().unwrap(); - - let expr = expr_of_parse_pair(pairs.next().unwrap())?; - let op = UnOp::from_str(op.as_str()).unwrap(); - match op { - UnOp::Add => expr.kind, - _ => ExprKind::Unary { - op, - expr: Box::new(expr), - }, - } - } + Error::new(Reason::Unexpected { found }).with_span(span) +} - // With coalesce, we need to grab the left and the right, - // because we're transforming it into a function call rather - // than passing along the operator. So this is unlike the rest - // of the parsing (and maybe isn't optimal). - Rule::expr_coalesce => { - let mut pairs = pair.into_inner(); - let left = expr_of_parse_pair(pairs.next().unwrap())?; - - if pairs.next().is_none() { - // If there's no coalescing, just return the single expression. - left.kind +fn convert_parser_error(e: Simple) -> Error { + let just_whitespace = e + .expected() + .all(|t| matches!(t, None | Some(Token::NewLine))); + let expected = e + .expected() + .filter(|t| { + if just_whitespace { + true } else { - let right = expr_of_parse_pair(pairs.next().unwrap())?; - ExprKind::Binary { - left: Box::new(left), - op: BinOp::Coalesce, - right: Box::new(right), - } - } - } - // This makes the previous parsing a bit easier, but is hacky; - // ideally find a better way (but it doesn't seem that easy to - // parse parts of a Pairs). - Rule::operator_coalesce => ExprKind::Ident(Ident::from_name("-")), - - Rule::assign | Rule::alias => { - let (a, expr) = parse_named(pair.into_inner())?; - alias = Some(a); - expr.kind - } - Rule::func_call => { - let mut pairs = pair.into_inner(); - - let name = expr_of_parse_pair(pairs.next().unwrap())?; - - let mut named = HashMap::new(); - let mut positional = Vec::new(); - for arg in pairs { - match arg.as_rule() { - Rule::named_arg => { - let (a, expr) = parse_named(arg.into_inner())?; - named.insert(a, expr); - } - _ => { - positional.push(expr_of_parse_pair(arg)?); - } - } + !matches!(t, None | Some(Token::NewLine)) } + }) + .map(|t| match t { + Some(t) => t.to_string(), + None => "end of input".to_string(), + }) + .collect_vec(); - ExprKind::FuncCall(FuncCall { - name: Box::new(name), - args: positional, - named_args: named, - }) - } - Rule::ident => { - // Pest has already parsed, so Chumsky should never fail - let ident = ::chumsky::Parser::parse(&chumsky::ident(), pair.as_str()).unwrap(); + let found = e.found().map(|c| c.to_string()).unwrap_or_default(); - ExprKind::Ident(ident) - } + let span = common::into_span(e.span()); - Rule::number => { - // pest is responsible for ensuring these are in the correct place, - // so we just need to remove them. - let str = pair.as_str().replace('_', ""); + if let SimpleReason::Custom(message) = e.reason() { + return Error::new_simple(message).with_span(span); + } - let lit = if let Ok(i) = str.parse::() { - Literal::Integer(i) - } else if let Ok(f) = str.parse::() { - Literal::Float(f) - } else { - bail!("cannot parse {str} as number") - }; - ExprKind::Literal(lit) - } - Rule::null => ExprKind::Literal(Literal::Null), - Rule::boolean => ExprKind::Literal(Literal::Boolean(pair.as_str() == "true")), - Rule::string => { - // Takes the string_inner, without the quotes - let inner = pair.into_inner().into_only(); - let inner = inner.map(|x| x.as_str().to_string()).unwrap_or_default(); - ExprKind::Literal(Literal::String(inner)) - } - Rule::s_string => ExprKind::SString(ast_of_interpolate_items(pair)?), - Rule::f_string => ExprKind::FString(ast_of_interpolate_items(pair)?), - Rule::pipeline => { - let mut nodes = exprs_of_parse_pairs(pair.into_inner())?; - match nodes.len() { - 0 => unreachable!(), - 1 => nodes.remove(0).kind, - _ => ExprKind::Pipeline(Pipeline { exprs: nodes }), - } - } - Rule::nested_pipeline => { - if let Some(pipeline) = pair.into_inner().next() { - expr_of_parse_pair(pipeline)?.kind - } else { - ExprKind::Literal(Literal::Null) + if expected.is_empty() || expected.len() > 10 { + Error::new(Reason::Unexpected { found }) + } else { + let mut expected = expected; + let expected = match expected.len() { + 1 => expected.remove(0), + 2 => expected.join(" or "), + _ => { + let last = expected.pop().unwrap(); + format!("one of {} or {last}", expected.join(", ")) } - } - Rule::range => { - let [start, end]: [Option>; 2] = pair - .into_inner() - // Iterate over `start` & `end` (separator is not a term). - .into_iter() - .map(|x| { - // Parse & Box each one. - exprs_of_parse_pairs(x.into_inner()) - .and_then(|x| x.into_only()) - .map(Box::new) - .ok() - }) - .collect::>() - .try_into() - .map_err(|e| anyhow!("Expected start, separator, end; {e:?}"))?; - ExprKind::Range(Range { start, end }) - } + }; - Rule::value_and_unit => { - let pairs: Vec<_> = pair.into_inner().into_iter().collect(); - let [n, unit]: [Pair; 2] = pairs - .try_into() - .map_err(|e| anyhow!("Expected two items; {e:?}"))?; - - ExprKind::Literal(Literal::ValueAndUnit(ValueAndUnit { - n: n.as_str().parse()?, - unit: unit.as_str().to_owned(), - })) - } - - Rule::date | Rule::time | Rule::timestamp => { - let inner = pair.into_inner().into_only()?.as_str().to_string(); - - ExprKind::Literal(match rule { - Rule::date => Literal::Date(inner), - Rule::time => Literal::Time(inner), - Rule::timestamp => Literal::Timestamp(inner), - _ => unreachable!(), - }) - } + Error::new(Reason::Expected { + who: e.label().map(|x| x.to_string()), + expected, + found, + }) + } + .with_span(span) +} - Rule::switch => { - let cases = pair - .into_inner() - .map(|pair| -> Result<_> { - let [condition, value]: [Expr; 2] = pair - .into_inner() - .map(expr_of_parse_pair) - .collect::>>()? - .try_into() - .unwrap(); - Ok(SwitchCase { condition, value }) - }) - .try_collect()?; - - ExprKind::Switch(cases) - } +mod common { + use chumsky::prelude::*; - _ => unreachable!("{pair}"), - }; - Ok(Expr { - span: Some(Span { - start: span.start(), - end: span.end(), - }), - alias, - ..Expr::from(kind) - }) -} + use super::lexer::Token; + use crate::{ast::pl::*, Span}; -fn type_of_parse_pair(pair: Pair) -> Result { - let any_of_terms: Vec<_> = pair - .into_inner() - .into_iter() - .map(|pair| -> Result { - let mut pairs = pair.into_inner(); - let name = parse_ident_part(pairs.next().unwrap()); - let typ = match TyLit::from_str(&name) { - Ok(t) => Ty::from(t), - Err(_) if name == "table" => Ty::Table(Frame::default()), - Err(_) => { - eprintln!("named type: {}", name); - Ty::Named(name.to_string()) - } - }; - - let param = pairs.next().map(type_of_parse_pair).transpose()?; - - Ok(if let Some(param) = param { - Ty::Parameterized(Box::new(typ), Box::new(param)) - } else { - typ - }) + pub fn ident_part() -> impl Parser> { + select! { Token::Ident(ident) => ident }.map_err(|e: Simple| { + Simple::expected_input_found( + e.span(), + [Some(Token::Ident("".to_string()))], + e.found().cloned(), + ) }) - .try_collect()?; + } - // is there only a single element? - Ok(match <[_; 1]>::try_from(any_of_terms) { - Ok([only]) => only, - Err(many) => Ty::AnyOf(many), - }) -} + pub fn keyword(kw: &'static str) -> impl Parser> + Clone { + just(Token::Keyword(kw.to_string())).ignored() + } -fn parse_typed_ident(pair: Pair) -> Result<(String, Option, Option)> { - let mut pairs = pair.into_inner(); + pub fn new_line() -> impl Parser> + Clone { + just(Token::NewLine).ignored() + } - let name = parse_ident_part(pairs.next().unwrap()); + pub fn ctrl(char: char) -> impl Parser> + Clone { + just(Token::Control(char)).ignored() + } - let mut ty = None; - let mut default = None; - for pair in pairs { - if matches!(pair.as_rule(), Rule::type_def) { - ty = Some(type_of_parse_pair(pair)?); - } else { - default = Some(expr_of_parse_pair(pair)?); + pub fn into_stmt(kind: StmtKind, span: std::ops::Range) -> Stmt { + Stmt { + span: into_span(span), + ..Stmt::from(kind) } } - Ok((name, ty, default)) -} - -fn parse_named(mut pairs: Pairs) -> Result<(String, Expr)> { - let alias = parse_ident_part(pairs.next().unwrap()); - let expr = expr_of_parse_pair(pairs.next().unwrap())?; - - Ok((alias, expr)) -} - -fn parse_ident_part(pair: Pair) -> String { - pair.into_inner().next().unwrap().as_str().to_string() -} + pub fn into_expr(kind: ExprKind, span: std::ops::Range) -> Expr { + Expr { + span: into_span(span), + ..Expr::from(kind) + } + } -fn ast_of_interpolate_items(pair: Pair) -> Result> { - pair.into_inner() - .map(|x| { - Ok(match x.as_rule() { - Rule::interpolate_string_inner_literal => { - InterpolateItem::String(x.as_str().to_string()) - } - Rule::double_open_bracket => InterpolateItem::String("{".to_string()), - Rule::double_close_bracket => InterpolateItem::String("}".to_string()), - _ => InterpolateItem::Expr(Box::new(expr_of_parse_pair(x)?)), - }) + pub fn into_span(span: std::ops::Range) -> Option { + Some(Span { + start: span.start, + end: span.end, }) - .collect::>() + } } #[cfg(test)] mod test { use super::*; + use anyhow::anyhow; use insta::assert_yaml_snapshot; - fn stmts_of_string(string: &str) -> Result> { - let pairs = parse_tree_of_str(string, Rule::statements)?; - - stmts_of_parse_pairs(pairs) + fn parse_expr(source: &str) -> Result> { + let tokens = Parser::parse(&lexer::lexer(), source).map_err(|errs| { + errs.into_iter() + .map(|e| anyhow!(convert_lexer_error(source, e))) + .collect_vec() + })?; + + let len = source.chars().count(); + let stream = Stream::from_iter(len..len + 1, tokens.into_iter()); + Parser::parse(&expr::expr_call().then_ignore(end()), stream) + .map_err(|errs| errs.into_iter().map(|e| anyhow!(e)).collect_vec()) } - fn expr_of_string(string: &str, rule: Rule) -> Result { - let mut pairs = parse_tree_of_str(string, rule)?; - - expr_of_parse_pair(pairs.next().unwrap()) + #[test] + fn test_pipeline_parse_tree() { + assert_yaml_snapshot!(parse( + // It's useful to have canonical examples rather than copy-pasting + // everything, so we reference the prql file here. But a downside of + // this implementation is: if there's an error in extracting the + // example from the docs into the file specified here, this test + // won't compile. Because `cargo insta test --accept` on the + // workspace — which extracts the example — requires compiling this, + // we can get stuck. + // + // Breaking out of that requires running this `cargo insta test + // --accept` within `book`, and then running it on the workspace. + // `task test-all` does this. + // + // If we change this, it would great if we can retain having + // examples tested in the docs. + include_str!("../../../book/tests/prql/examples/variables-0.prql"), + ) + .unwrap()); } #[test] - fn test_parse_take() -> Result<()> { - parse_tree_of_str("take 10", Rule::statements)?; + fn test_take() { + parse("take 10").unwrap(); - assert_yaml_snapshot!(stmts_of_string(r#"take 10"#)?, @r###" + assert_yaml_snapshot!(parse(r#"take 10"#).unwrap(), @r###" --- - Main: FuncCall: @@ -458,10 +215,24 @@ mod test { args: - Literal: Integer: 10 - named_args: {} "###); - assert_yaml_snapshot!(stmts_of_string(r#"take 1..10"#)?, @r###" + assert_yaml_snapshot!(parse(r#"take ..10"#).unwrap(), @r###" + --- + - Main: + FuncCall: + name: + Ident: + - take + args: + - Range: + start: ~ + end: + Literal: + Integer: 10 + "###); + + assert_yaml_snapshot!(parse(r#"take 1..10"#).unwrap(), @r###" --- - Main: FuncCall: @@ -476,44 +247,128 @@ mod test { end: Literal: Integer: 10 - named_args: {} "###); - - Ok(()) } #[test] - fn test_parse_pipeline_parse_tree() { - assert_yaml_snapshot!(stmts_of_parse_pairs( - parse_tree_of_str( - // It's useful to have canonical examples rather than copy-pasting - // everything, so we reference the prql file here. But a downside of - // this implementation is: if there's an error in extracting the - // example from the docs into the file specified here, this test - // won't compile. Because `cargo insta test --accept` on the - // workspace — which extracts the example — requires compiling this, - // we can get stuck. - // - // Breaking out of that requires running this `cargo insta test - // --accept` within `book`, and then running it on the workspace. - // `task test-all` does this. - // - // If we change this, it would great if we can retain having - // examples tested in the docs. - &include_str!("../../../book/tests/prql/examples/variables-0.prql") - .trim() - // Required for Windows - .replace("\r\n", "\n"), - Rule::statements - ) - .unwrap() - ) - .unwrap()); + fn test_ranges() { + assert_yaml_snapshot!(parse_expr(r#"3..5"#).unwrap(), @r###" + --- + Range: + start: + Literal: + Integer: 3 + end: + Literal: + Integer: 5 + "###); + + assert_yaml_snapshot!(parse_expr(r#"-2..-5"#).unwrap(), @r###" + --- + Range: + start: + Unary: + op: Neg + expr: + Literal: + Integer: 2 + end: + Unary: + op: Neg + expr: + Literal: + Integer: 5 + "###); + + assert_yaml_snapshot!(parse_expr(r#"(-2..(-5 | abs))"#).unwrap(), @r###" + --- + Range: + start: + Unary: + op: Neg + expr: + Literal: + Integer: 2 + end: + Pipeline: + exprs: + - Unary: + op: Neg + expr: + Literal: + Integer: 5 + - Ident: + - abs + "###); + + assert_yaml_snapshot!(parse_expr(r#"(2 + 5)..'a'"#).unwrap(), @r###" + --- + Range: + start: + Binary: + left: + Literal: + Integer: 2 + op: Add + right: + Literal: + Integer: 5 + end: + Literal: + String: a + "###); + + assert_yaml_snapshot!(parse_expr(r#"1.6..rel.col"#).unwrap(), @r###" + --- + Range: + start: + Literal: + Float: 1.6 + end: + Ident: + - rel + - col + "###); + + assert_yaml_snapshot!(parse_expr(r#"6.."#).unwrap(), @r###" + --- + Range: + start: + Literal: + Integer: 6 + end: ~ + "###); + assert_yaml_snapshot!(parse_expr(r#"..7"#).unwrap(), @r###" + --- + Range: + start: ~ + end: + Literal: + Integer: 7 + "###); + + assert_yaml_snapshot!(parse_expr(r#".."#).unwrap(), @r###" + --- + Range: + start: ~ + end: ~ + "###); + + assert_yaml_snapshot!(parse_expr(r#"@2020-01-01..@2021-01-01"#).unwrap(), @r###" + --- + Range: + start: + Literal: + Date: 2020-01-01 + end: + Literal: + Date: 2021-01-01 + "###); } #[test] - fn test_parse_basic_exprs() -> Result<()> { - assert_yaml_snapshot!(expr_of_string(r#"country == "USA""#, Rule::expr)?, @r###" + fn test_basic_exprs() { + assert_yaml_snapshot!(parse_expr(r#"country == "USA""#).unwrap(), @r###" --- Binary: left: @@ -524,7 +379,7 @@ mod test { Literal: String: USA "###); - assert_yaml_snapshot!(expr_of_string("select [a, b, c]", Rule::func_call)?, @r###" + assert_yaml_snapshot!(parse_expr("select [a, b, c]").unwrap(), @r###" --- FuncCall: name: @@ -538,14 +393,12 @@ mod test { - b - Ident: - c - named_args: {} "###); - assert_yaml_snapshot!(expr_of_string( + assert_yaml_snapshot!(parse_expr( "group [title, country] ( aggregate [sum salary] - )", - Rule::pipeline - )?, @r###" + )" + ).unwrap(), @r###" --- FuncCall: name: @@ -570,14 +423,10 @@ mod test { args: - Ident: - salary - named_args: {} - named_args: {} - named_args: {} "###); - assert_yaml_snapshot!(expr_of_string( - r#" filter country == "USA""#, - Rule::pipeline - )?, @r###" + assert_yaml_snapshot!(parse_expr( + r#" filter country == "USA""# + ).unwrap(), @r###" --- FuncCall: name: @@ -592,9 +441,8 @@ mod test { right: Literal: String: USA - named_args: {} "###); - assert_yaml_snapshot!(expr_of_string("[a, b, c,]", Rule::list)?, @r###" + assert_yaml_snapshot!(parse_expr("[a, b, c,]").unwrap(), @r###" --- List: - Ident: @@ -604,13 +452,12 @@ mod test { - Ident: - c "###); - assert_yaml_snapshot!(expr_of_string( + assert_yaml_snapshot!(parse_expr( r#"[ gross_salary = salary + payroll_tax, gross_cost = gross_salary + benefits_cost -]"#, - Rule::list - )?, @r###" +]"# + ).unwrap(), @r###" --- List: - Binary: @@ -633,10 +480,10 @@ mod test { alias: gross_cost "###); // Currently not putting comments in our parse tree, so this is blank. - assert_yaml_snapshot!(stmts_of_string( + assert_yaml_snapshot!(parse( r#"# this is a comment select a"# - )?, @r###" + ).unwrap(), @r###" --- - Main: FuncCall: @@ -646,12 +493,10 @@ mod test { args: - Ident: - a - named_args: {} "###); - assert_yaml_snapshot!(expr_of_string( - "join side:left country [id==employee_id]", - Rule::func_call - )?, @r###" + assert_yaml_snapshot!(parse_expr( + "join side:left country [id==employee_id]" + ).unwrap(), @r###" --- FuncCall: name: @@ -674,7 +519,7 @@ mod test { Ident: - left "###); - assert_yaml_snapshot!(expr_of_string("1 + 2", Rule::expr)?, @r###" + assert_yaml_snapshot!(parse_expr("1 + 2").unwrap(), @r###" --- Binary: left: @@ -684,101 +529,73 @@ mod test { right: Literal: Integer: 2 - "###); - Ok(()) + "###) } #[test] - fn test_parse_string() -> Result<()> { - let double_quoted_ast = expr_of_string(r#"" U S A ""#, Rule::string)?; + fn test_string() { + let double_quoted_ast = parse_expr(r#"" U S A ""#).unwrap(); assert_yaml_snapshot!(double_quoted_ast, @r###" --- Literal: String: " U S A " "###); - let single_quoted_ast = expr_of_string(r#"' U S A '"#, Rule::string)?; + let single_quoted_ast = parse_expr(r#"' U S A '"#).unwrap(); assert_eq!(single_quoted_ast, double_quoted_ast); // Single quotes within double quotes should produce a string containing // the single quotes (and vice versa). - assert_yaml_snapshot!(expr_of_string(r#""' U S A '""#, Rule::string)? , @r###" + assert_yaml_snapshot!(parse_expr(r#""' U S A '""#).unwrap(), @r###" --- Literal: String: "' U S A '" "###); - assert_yaml_snapshot!(expr_of_string(r#"'" U S A "'"#, Rule::string)? , @r###" + assert_yaml_snapshot!(parse_expr(r#"'" U S A "'"#).unwrap(), @r###" --- Literal: String: "\" U S A \"" "###); - assert!(expr_of_string(r#"" U S A"#, Rule::string).is_err()); - assert!(expr_of_string(r#"" U S A '"#, Rule::string).is_err()); + parse_expr(r#"" U S A"#).unwrap_err(); + parse_expr(r#"" U S A '"#).unwrap_err(); - // Escapes get passed through (the insta snapshot has them escaped I - // think, which isn't that clear, so repeated below). - let escaped_string = expr_of_string(r#"" \U S A ""#, Rule::string)?; - assert_yaml_snapshot!(escaped_string, @r###" + assert_yaml_snapshot!(parse_expr(r#"" \nU S A ""#).unwrap(), @r###" --- Literal: - String: " \\U S A " - "###); - assert_eq!( - escaped_string - .kind - .as_literal() - .unwrap() - .as_string() - .unwrap(), - r#" \U S A "# - ); + String: " \nU S A " + "###); - // Currently we don't allow escaping closing quotes — because it's not - // trivial to do in pest, and I'm not sure it's a great idea either — we - // should arguably encourage multiline-strings. (Though no objection if - // someone wants to implement it, this test is recording current - // behavior rather than maintaining a contract). - let escaped_quotes = expr_of_string(r#"" Canada \""#, Rule::string)?; - assert_yaml_snapshot!(escaped_quotes, @r###" + assert_yaml_snapshot!(parse_expr(r#"r" \nU S A ""#).unwrap(), @r###" --- Literal: - String: " Canada \\" - "###); - assert_eq!( - escaped_quotes - .kind - .as_literal() - .unwrap() - .as_string() - .unwrap(), - r#" Canada \"# - ); + String: " \\nU S A " + "###); - let multi_double = expr_of_string( + let multi_double = parse_expr( r#"""" '' Canada " """"#, - Rule::string, - )?; + ) + .unwrap(); assert_yaml_snapshot!(multi_double, @r###" --- Literal: String: "\n''\nCanada\n\"\n\n" "###); - let multi_single = expr_of_string( + let multi_single = parse_expr( r#"''' Canada " """ '''"#, - Rule::string, - )?; + ) + .unwrap(); assert_yaml_snapshot!(multi_single, @r###" --- Literal: @@ -786,19 +603,17 @@ Canada "###); assert_yaml_snapshot!( - expr_of_string("''", Rule::string).unwrap(), + parse_expr("''").unwrap(), @r###" --- Literal: String: "" "###); - - Ok(()) } #[test] - fn test_parse_s_string() -> Result<()> { - assert_yaml_snapshot!(expr_of_string(r#"s"SUM({col})""#, Rule::expr_call)?, @r###" + fn test_s_string() { + assert_yaml_snapshot!(parse_expr(r#"s"SUM({col})""#).unwrap(), @r###" --- SString: - String: SUM( @@ -807,47 +622,32 @@ Canada - col - String: ) "###); - assert_yaml_snapshot!(expr_of_string(r#"s"SUM({2 + 2})""#, Rule::expr_call)?, @r###" + assert_yaml_snapshot!(parse_expr(r#"s"SUM({rel.`Col name`})""#).unwrap(), @r###" --- SString: - String: SUM( - Expr: - Binary: - left: - Literal: - Integer: 2 - op: Add - right: - Literal: - Integer: 2 + Ident: + - rel + - Col name - String: ) - "###); - Ok(()) + "###) } #[test] - fn test_parse_s_string_braces() -> Result<()> { - assert_yaml_snapshot!(expr_of_string(r#"s"{{?crystal_var}}""#, Rule::expr_call)?, @r###" - --- - SString: - - String: "{" - - String: "?crystal_var" - - String: "}" - "###); - assert_yaml_snapshot!(expr_of_string(r#"s"foo{{bar""#, Rule::expr_call)?, @r###" + fn test_s_string_braces() { + assert_yaml_snapshot!(parse_expr(r#"s"{{?crystal_var}}""#).unwrap(), @r###" --- SString: - - String: foo - - String: "{" - - String: bar + - String: "{?crystal_var}" "###); - - Ok(()) + parse_expr(r#"s"foo{{bar""#).unwrap_err(); } #[test] - fn test_parse_jinja() { - stmts_of_string( + #[ignore] + fn test_jinja() { + parse( r#" from {{ ref('stg_orders') }} aggregate (sum order_id) @@ -857,8 +657,8 @@ Canada } #[test] - fn test_parse_list() { - assert_yaml_snapshot!(expr_of_string(r#"[1 + 1, 2]"#, Rule::list).unwrap(), @r###" + fn test_list() { + assert_yaml_snapshot!(parse_expr(r#"[1 + 1, 2]"#).unwrap(), @r###" --- List: - Binary: @@ -872,7 +672,7 @@ Canada - Literal: Integer: 2 "###); - assert_yaml_snapshot!(expr_of_string(r#"[1 + (f 1), 2]"#, Rule::list).unwrap(), @r###" + assert_yaml_snapshot!(parse_expr(r#"[1 + (f 1), 2]"#).unwrap(), @r###" --- List: - Binary: @@ -888,16 +688,15 @@ Canada args: - Literal: Integer: 1 - named_args: {} - Literal: Integer: 2 "###); // Line breaks - assert_yaml_snapshot!(expr_of_string( + assert_yaml_snapshot!(parse_expr( r#"[1, - 2]"#, - Rule::list).unwrap(), @r###" + 2]"# + ).unwrap(), @r###" --- List: - Literal: @@ -906,8 +705,8 @@ Canada Integer: 2 "###); // Function call in a list - let ab = expr_of_string(r#"[a b]"#, Rule::list).unwrap(); - let a_comma_b = expr_of_string(r#"[a, b]"#, Rule::list).unwrap(); + let ab = parse_expr(r#"[a b]"#).unwrap(); + let a_comma_b = parse_expr(r#"[a, b]"#).unwrap(); assert_yaml_snapshot!(ab, @r###" --- List: @@ -918,7 +717,6 @@ Canada args: - Ident: - b - named_args: {} "###); assert_yaml_snapshot!(a_comma_b, @r###" --- @@ -930,13 +728,16 @@ Canada "###); assert_ne!(ab, a_comma_b); - assert_yaml_snapshot!(expr_of_string(r#"[amount, +amount, -amount]"#, Rule::list).unwrap(), @r###" + assert_yaml_snapshot!(parse_expr(r#"[amount, +amount, -amount]"#).unwrap(), @r###" --- List: - Ident: - amount - - Ident: - - amount + - Unary: + op: Add + expr: + Ident: + - amount - Unary: op: Neg expr: @@ -944,13 +745,16 @@ Canada - amount "###); // Operators in list items - assert_yaml_snapshot!(expr_of_string(r#"[amount, +amount, -amount]"#, Rule::list).unwrap(), @r###" + assert_yaml_snapshot!(parse_expr(r#"[amount, +amount, -amount]"#).unwrap(), @r###" --- List: - - Ident: - - amount - Ident: - amount + - Unary: + op: Add + expr: + Ident: + - amount - Unary: op: Neg expr: @@ -960,28 +764,28 @@ Canada } #[test] - fn test_parse_number() -> Result<()> { - assert_yaml_snapshot!(expr_of_string(r#"23"#, Rule::number)?, @r###" + fn test_number() { + assert_yaml_snapshot!(parse_expr(r#"23"#).unwrap(), @r###" --- Literal: Integer: 23 "###); - assert_yaml_snapshot!(expr_of_string(r#"2_3_4.5_6"#, Rule::number)?, @r###" + assert_yaml_snapshot!(parse_expr(r#"2_3_4.5_6"#).unwrap(), @r###" --- Literal: Float: 234.56 "###); - assert_yaml_snapshot!(expr_of_string(r#"23.6"#, Rule::number)?, @r###" + assert_yaml_snapshot!(parse_expr(r#"23.6"#).unwrap(), @r###" --- Literal: Float: 23.6 "###); - assert_yaml_snapshot!(expr_of_string(r#"23.0"#, Rule::number)?, @r###" + assert_yaml_snapshot!(parse_expr(r#"23.0"#).unwrap(), @r###" --- Literal: Float: 23 "###); - assert_yaml_snapshot!(expr_of_string(r#"2 + 2"#, Rule::expr_add)?, @r###" + assert_yaml_snapshot!(parse_expr(r#"2 + 2"#).unwrap(), @r###" --- Binary: left: @@ -993,23 +797,22 @@ Canada Integer: 2 "###); - // Underscores can't go at the beginning or end of numbers - assert!(expr_of_string("_2", Rule::number).is_err()); - assert!(expr_of_string("_", Rule::number).is_err()); - assert!(expr_of_string("_2.3", Rule::number).is_err()); - // We need to test these with `stmts_of_string` because they start with - // a valid number (and pest will return as much as possible and then return) - let bad_numbers = vec!["2_", "2.3_"]; - for bad_number in bad_numbers { - assert!(stmts_of_string(bad_number).is_err()); - } - Ok(()) + // Underscores at the beginning are parsed as ident + parse_expr("_2").unwrap().kind.into_ident().unwrap(); + parse_expr("_").unwrap().kind.into_ident().unwrap(); + + // We don't allow empty fractions. + parse_expr(r#"add 1. 2"#).unwrap_err(); + + parse_expr("_2.3").unwrap_err(); + // expr_of_string("2_").unwrap_err(); // TODO + // expr_of_string("2.3_").unwrap_err(); // TODO } #[test] - fn test_parse_filter() { + fn test_filter() { assert_yaml_snapshot!( - stmts_of_string(r#"filter country == "USA""#).unwrap(), @r###" + parse(r#"filter country == "USA""#).unwrap(), @r###" --- - Main: FuncCall: @@ -1025,11 +828,10 @@ Canada right: Literal: String: USA - named_args: {} "###); assert_yaml_snapshot!( - stmts_of_string(r#"filter (upper country) == "USA""#).unwrap(), @r###" + parse(r#"filter (upper country) == "USA""#).unwrap(), @r###" --- - Main: FuncCall: @@ -1046,19 +848,17 @@ Canada args: - Ident: - country - named_args: {} op: Eq right: Literal: String: USA - named_args: {} "### ); } #[test] - fn test_parse_aggregate() { - let aggregate = stmts_of_string( + fn test_aggregate() { + let aggregate = parse( r"group [title] ( aggregate [sum salary, count] )", @@ -1089,13 +889,10 @@ Canada args: - Ident: - salary - named_args: {} - Ident: - count - named_args: {} - named_args: {} "###); - let aggregate = stmts_of_string( + let aggregate = parse( r"group [title] ( aggregate [sum salary] )", @@ -1126,16 +923,13 @@ Canada args: - Ident: - salary - named_args: {} - named_args: {} - named_args: {} "###); } #[test] - fn test_parse_derive() -> Result<()> { + fn test_derive() { assert_yaml_snapshot!( - expr_of_string(r#"derive [x = 5, y = (-x)]"#, Rule::func_call)? + parse_expr(r#"derive [x = 5, y = (-x)]"#).unwrap() , @r###" --- FuncCall: @@ -1153,16 +947,13 @@ Canada Ident: - x alias: y - named_args: {} "###); - - Ok(()) } #[test] - fn test_parse_select() -> Result<()> { + fn test_select() { assert_yaml_snapshot!( - expr_of_string(r#"select x"#, Rule::func_call)? + parse_expr(r#"select x"#).unwrap() , @r###" --- FuncCall: @@ -1172,11 +963,10 @@ Canada args: - Ident: - x - named_args: {} "###); assert_yaml_snapshot!( - expr_of_string(r#"select ![x]"#, Rule::func_call)? + parse_expr(r#"select ![x]"#).unwrap() , @r###" --- FuncCall: @@ -1190,11 +980,10 @@ Canada List: - Ident: - x - named_args: {} "###); assert_yaml_snapshot!( - expr_of_string(r#"select [x, y]"#, Rule::func_call)? + parse_expr(r#"select [x, y]"#).unwrap() , @r###" --- FuncCall: @@ -1207,16 +996,13 @@ Canada - x - Ident: - y - named_args: {} "###); - - Ok(()) } #[test] - fn test_parse_expr() -> Result<()> { + fn test_expr() { assert_yaml_snapshot!( - expr_of_string(r#"country == "USA""#, Rule::expr)? + parse_expr(r#"country == "USA""#).unwrap() , @r###" --- Binary: @@ -1228,12 +1014,11 @@ Canada Literal: String: USA "###); - assert_yaml_snapshot!(expr_of_string( + assert_yaml_snapshot!(parse_expr( r#"[ gross_salary = salary + payroll_tax, gross_cost = gross_salary + benefits_cost, -]"#, - Rule::list)?, @r###" +]"#).unwrap(), @r###" --- List: - Binary: @@ -1256,10 +1041,9 @@ Canada alias: gross_cost "###); assert_yaml_snapshot!( - expr_of_string( - "gross_salary = (salary + payroll_tax) * (1 + tax_rate)", - Rule::alias, - )?, + parse_expr( + "(salary + payroll_tax) * (1 + tax_rate)" + ).unwrap(), @r###" --- Binary: @@ -1282,14 +1066,12 @@ Canada right: Ident: - tax_rate - alias: gross_salary - "###); - Ok(()) + "###) } #[test] - fn test_parse_function() -> Result<()> { - assert_yaml_snapshot!(stmts_of_string("func plus_one x -> x + 1")?, @r###" + fn test_function() { + assert_yaml_snapshot!(parse("func plus_one x -> x + 1\n").unwrap(), @r###" --- - FuncDef: name: plus_one @@ -1308,7 +1090,7 @@ Canada Integer: 1 return_ty: ~ "###); - assert_yaml_snapshot!(stmts_of_string("func identity x -> x")? + assert_yaml_snapshot!(parse("func identity x -> x\n").unwrap() , @r###" --- - FuncDef: @@ -1322,7 +1104,7 @@ Canada - x return_ty: ~ "###); - assert_yaml_snapshot!(stmts_of_string("func plus_one x -> (x + 1)")? + assert_yaml_snapshot!(parse("func plus_one x -> (x + 1)\n").unwrap() , @r###" --- - FuncDef: @@ -1342,7 +1124,7 @@ Canada Integer: 1 return_ty: ~ "###); - assert_yaml_snapshot!(stmts_of_string("func plus_one x -> x + 1")? + assert_yaml_snapshot!(parse("func plus_one x -> x + 1\n").unwrap() , @r###" --- - FuncDef: @@ -1362,7 +1144,8 @@ Canada Integer: 1 return_ty: ~ "###); - assert_yaml_snapshot!(stmts_of_string("func foo x -> some_func (foo bar + 1) (plax) - baz")? + + assert_yaml_snapshot!(parse("func foo x -> some_func (foo bar + 1) (plax) - baz\n").unwrap() , @r###" --- - FuncDef: @@ -1390,7 +1173,6 @@ Canada right: Literal: Integer: 1 - named_args: {} - Binary: left: Ident: @@ -1399,11 +1181,10 @@ Canada right: Ident: - baz - named_args: {} return_ty: ~ "###); - assert_yaml_snapshot!(stmts_of_string("func return_constant -> 42")?, @r###" + assert_yaml_snapshot!(parse("func return_constant -> 42\n").unwrap(), @r###" --- - FuncDef: name: return_constant @@ -1414,7 +1195,9 @@ Canada Integer: 42 return_ty: ~ "###); - assert_yaml_snapshot!(stmts_of_string(r#"func count X -> s"SUM({X})""#)?, @r###" + + assert_yaml_snapshot!(parse(r#"func count X -> s"SUM({X})" + "#).unwrap(), @r###" --- - FuncDef: name: count @@ -1432,24 +1215,59 @@ Canada return_ty: ~ "###); - /* TODO: Does not yet parse because `window` not yet implemented. - assert_debug_snapshot!(ast_of_parse_tree( - parse_tree_of_str( - r#" - func lag_day x -> ( - window x - by sec_id - sort date - lag 1 + assert_yaml_snapshot!(parse( + r#" + func lag_day x -> ( + window x + by sec_id + sort date + lag 1 + ) + "# ) - "#, - Rule::func_def - ) - .unwrap() - )); - */ + .unwrap(), @r###" + --- + - FuncDef: + name: lag_day + positional_params: + - name: x + default_value: ~ + named_params: [] + body: + Pipeline: + exprs: + - FuncCall: + name: + Ident: + - window + args: + - Ident: + - x + - FuncCall: + name: + Ident: + - by + args: + - Ident: + - sec_id + - FuncCall: + name: + Ident: + - sort + args: + - Ident: + - date + - FuncCall: + name: + Ident: + - lag + args: + - Literal: + Integer: 1 + return_ty: ~ + "###); - assert_yaml_snapshot!(stmts_of_string(r#"func add x to:a -> x + to"#)?, @r###" + assert_yaml_snapshot!(parse("func add x to:a -> x + to\n").unwrap(), @r###" --- - FuncDef: name: add @@ -1472,14 +1290,12 @@ Canada - to return_ty: ~ "###); - - Ok(()) } #[test] - fn test_parse_func_call() { + fn test_func_call() { // Function without argument - let ast = expr_of_string(r#"count"#, Rule::expr).unwrap(); + let ast = parse_expr(r#"count"#).unwrap(); let ident = ast.kind.into_ident().unwrap(); assert_yaml_snapshot!( ident, @r###" @@ -1487,8 +1303,21 @@ Canada - count "###); + let ast = parse_expr(r#"s 'foo'"#).unwrap(); + assert_yaml_snapshot!( + ast, @r###" + --- + FuncCall: + name: + Ident: + - s + args: + - Literal: + String: foo + "###); + // A non-friendly option for #154 - let ast = expr_of_string(r#"count s'*'"#, Rule::expr_call).unwrap(); + let ast = parse_expr(r#"count s'*'"#).unwrap(); let func_call: FuncCall = ast.kind.into_func_call().unwrap(); assert_yaml_snapshot!( func_call, @r###" @@ -1499,64 +1328,11 @@ Canada args: - SString: - String: "*" - named_args: {} "###); - assert_yaml_snapshot!(parse(r#"from mytable | select [a and b + c or (d e) and f]"#).unwrap(), @r###" - --- - - Main: - Pipeline: - exprs: - - FuncCall: - name: - Ident: - - from - args: - - Ident: - - mytable - named_args: {} - - FuncCall: - name: - Ident: - - select - args: - - List: - - Binary: - left: - Ident: - - a - op: And - right: - Binary: - left: - Binary: - left: - Ident: - - b - op: Add - right: - Ident: - - c - op: Or - right: - Binary: - left: - FuncCall: - name: - Ident: - - d - args: - - Ident: - - e - named_args: {} - op: And - right: - Ident: - - f - named_args: {} - "###); + parse_expr("plus_one x:0 x:0 ").unwrap_err(); - let ast = expr_of_string(r#"add bar to=3"#, Rule::expr_call).unwrap(); + let ast = parse_expr(r#"add bar to=3"#).unwrap(); assert_yaml_snapshot!( ast, @r###" --- @@ -1570,15 +1346,130 @@ Canada - Literal: Integer: 3 alias: to - named_args: {} "###); } #[test] - fn test_parse_table() -> Result<()> { - assert_yaml_snapshot!(stmts_of_string( + fn test_op_precedence() { + assert_yaml_snapshot!(parse_expr(r#"1 + 2 - 3 - 4"#).unwrap(), @r###" + --- + Binary: + left: + Binary: + left: + Binary: + left: + Literal: + Integer: 1 + op: Add + right: + Literal: + Integer: 2 + op: Sub + right: + Literal: + Integer: 3 + op: Sub + right: + Literal: + Integer: 4 + "###); + + assert_yaml_snapshot!(parse_expr(r#"1 / 2 - 3 * 4 + 1"#).unwrap(), @r###" + --- + Binary: + left: + Binary: + left: + Binary: + left: + Literal: + Integer: 1 + op: Div + right: + Literal: + Integer: 2 + op: Sub + right: + Binary: + left: + Literal: + Integer: 3 + op: Mul + right: + Literal: + Integer: 4 + op: Add + right: + Literal: + Integer: 1 + "###); + + assert_yaml_snapshot!(parse_expr(r#"a and b or c and d"#).unwrap(), @r###" + --- + Binary: + left: + Binary: + left: + Ident: + - a + op: And + right: + Ident: + - b + op: Or + right: + Binary: + left: + Ident: + - c + op: And + right: + Ident: + - d + "###); + + assert_yaml_snapshot!(parse_expr(r#"a and b + c or (d e) and f"#).unwrap(), @r###" + --- + Binary: + left: + Binary: + left: + Ident: + - a + op: And + right: + Binary: + left: + Ident: + - b + op: Add + right: + Ident: + - c + op: Or + right: + Binary: + left: + FuncCall: + name: + Ident: + - d + args: + - Ident: + - e + op: And + right: + Ident: + - f + "###); + } + + #[test] + fn test_var_def() { + assert_yaml_snapshot!(parse( "let newest_employees = (from employees)" - )?, @r###" + ).unwrap(), @r###" --- - VarDef: name: newest_employees @@ -1590,10 +1481,9 @@ Canada args: - Ident: - employees - named_args: {} "###); - assert_yaml_snapshot!(stmts_of_string( + assert_yaml_snapshot!(parse( r#" let newest_employees = ( from employees @@ -1604,7 +1494,7 @@ Canada ) sort tenure take 50 - )"#.trim())?, + )"#.trim()).unwrap(), @r###" --- - VarDef: @@ -1619,7 +1509,6 @@ Canada args: - Ident: - employees - named_args: {} - FuncCall: name: Ident: @@ -1640,10 +1529,7 @@ Canada args: - Ident: - salary - named_args: {} alias: average_country_salary - named_args: {} - named_args: {} - FuncCall: name: Ident: @@ -1651,7 +1537,6 @@ Canada args: - Ident: - tenure - named_args: {} - FuncCall: name: Ident: @@ -1659,12 +1544,11 @@ Canada args: - Literal: Integer: 50 - named_args: {} "###); - assert_yaml_snapshot!(stmts_of_string(r#" + assert_yaml_snapshot!(parse(r#" let e = s"SELECT * FROM employees" - "#)?, @r###" + "#).unwrap(), @r###" --- - VarDef: name: e @@ -1673,7 +1557,7 @@ Canada - String: SELECT * FROM employees "###); - assert_yaml_snapshot!(stmts_of_string( + assert_yaml_snapshot!(parse( "let x = ( from x_table @@ -1683,7 +1567,7 @@ Canada ) from x" - )?, @r###" + ).unwrap(), @r###" --- - VarDef: name: x @@ -1697,7 +1581,6 @@ Canada args: - Ident: - x_table - named_args: {} - FuncCall: name: Ident: @@ -1706,7 +1589,6 @@ Canada - Ident: - foo alias: only_in_x - named_args: {} - Main: FuncCall: name: @@ -1715,15 +1597,12 @@ Canada args: - Ident: - x - named_args: {} "###); - - Ok(()) } #[test] fn test_inline_pipeline() { - assert_yaml_snapshot!(expr_of_string("(salary | percentile 50)", Rule::nested_pipeline).unwrap(), @r###" + assert_yaml_snapshot!(parse_expr("(salary | percentile 50)").unwrap(), @r###" --- Pipeline: exprs: @@ -1736,9 +1615,8 @@ Canada args: - Literal: Integer: 50 - named_args: {} "###); - assert_yaml_snapshot!(stmts_of_string("func median x -> (x | percentile 50)").unwrap(), @r###" + assert_yaml_snapshot!(parse("func median x -> (x | percentile 50)\n").unwrap(), @r###" --- - FuncDef: name: median @@ -1758,20 +1636,19 @@ Canada args: - Literal: Integer: 50 - named_args: {} return_ty: ~ "###); } #[test] - fn test_parse_sql_parameters() -> Result<()> { + fn test_sql_parameters() { assert_yaml_snapshot!(parse(r#" from mytable filter [ first_name == $1, last_name == $2.name ] - "#)?, @r###" + "#).unwrap(), @r###" --- - Main: Pipeline: @@ -1783,7 +1660,6 @@ Canada args: - Ident: - mytable - named_args: {} - FuncCall: name: Ident: @@ -1807,28 +1683,25 @@ Canada Ident: - $2 - name - named_args: {} "###); - Ok(()) } #[test] - fn test_tab_characters() -> Result<()> { + fn test_tab_characters() { // #284 - - let prql = "from c_invoice + parse( + "from c_invoice join doc:c_doctype [==c_invoice_id] select [ \tinvoice_no, \tdocstatus -]"; - parse(prql)?; - - Ok(()) +]", + ) + .unwrap(); } #[test] - fn test_parse_backticks() -> Result<()> { + fn test_backticks() { let prql = " from `a/*.parquet` aggregate [max c] @@ -1837,7 +1710,7 @@ join `my-proj.dataset.table` join `my-proj`.`dataset`.`table` "; - assert_yaml_snapshot!(parse(prql)?, @r###" + assert_yaml_snapshot!(parse(prql).unwrap(), @r###" --- - Main: Pipeline: @@ -1849,7 +1722,6 @@ join `my-proj`.`dataset`.`table` args: - Ident: - a/*.parquet - named_args: {} - FuncCall: name: Ident: @@ -1863,8 +1735,6 @@ join `my-proj`.`dataset`.`table` args: - Ident: - c - named_args: {} - named_args: {} - FuncCall: name: Ident: @@ -1878,7 +1748,6 @@ join `my-proj`.`dataset`.`table` expr: Ident: - id - named_args: {} - FuncCall: name: Ident: @@ -1886,7 +1755,6 @@ join `my-proj`.`dataset`.`table` args: - Ident: - my-proj.dataset.table - named_args: {} - FuncCall: name: Ident: @@ -1896,14 +1764,11 @@ join `my-proj`.`dataset`.`table` - my-proj - dataset - table - named_args: {} "###); - - Ok(()) } #[test] - fn test_parse_sort() -> Result<()> { + fn test_sort() { assert_yaml_snapshot!(parse(" from invoices sort issued_at @@ -1923,7 +1788,6 @@ join `my-proj`.`dataset`.`table` args: - Ident: - invoices - named_args: {} - FuncCall: name: Ident: @@ -1931,7 +1795,6 @@ join `my-proj`.`dataset`.`table` args: - Ident: - issued_at - named_args: {} - FuncCall: name: Ident: @@ -1942,7 +1805,6 @@ join `my-proj`.`dataset`.`table` expr: Ident: - issued_at - named_args: {} - FuncCall: name: Ident: @@ -1951,7 +1813,6 @@ join `my-proj`.`dataset`.`table` - List: - Ident: - issued_at - named_args: {} - FuncCall: name: Ident: @@ -1963,7 +1824,6 @@ join `my-proj`.`dataset`.`table` expr: Ident: - issued_at - named_args: {} - FuncCall: name: Ident: @@ -1977,137 +1837,16 @@ join `my-proj`.`dataset`.`table` expr: Ident: - amount - - Ident: - - num_of_articles - named_args: {} - "###); - - Ok(()) - } - - #[test] - fn test_range() { - assert_yaml_snapshot!(parse(" - from employees - filter (distance | in 0..40) - filter (distance | in (0)..40) - derive [ - greater_than_ten = 11.., - less_than_ten = ..9, - negative = (-5..), - more_negative = -10.., - dates_open = @2020-01-01.., - dates = @2020-01-01..@2021-01-01, - ] - ").unwrap(), @r###" - --- - - Main: - Pipeline: - exprs: - - FuncCall: - name: - Ident: - - from - args: - - Ident: - - employees - named_args: {} - - FuncCall: - name: - Ident: - - filter - args: - - Pipeline: - exprs: - - Ident: - - distance - - FuncCall: - name: - Ident: - - in - args: - - Range: - start: - Literal: - Integer: 0 - end: - Literal: - Integer: 40 - named_args: {} - named_args: {} - - FuncCall: - name: - Ident: - - filter - args: - - Pipeline: - exprs: - - Ident: - - distance - - FuncCall: - name: - Ident: - - in - args: - - Range: - start: - Literal: - Integer: 0 - end: - Literal: - Integer: 40 - named_args: {} - named_args: {} - - FuncCall: - name: - Ident: - - derive - args: - - List: - - Range: - start: - Literal: - Integer: 11 - end: ~ - alias: greater_than_ten - - Range: - start: ~ - end: - Literal: - Integer: 9 - alias: less_than_ten - - Range: - start: - Literal: - Integer: -5 - end: ~ - alias: negative - - Range: - start: - Literal: - Integer: -10 - end: ~ - alias: more_negative - - Range: - start: - Literal: - Date: 2020-01-01 - end: ~ - alias: dates_open - - Range: - start: - Literal: - Date: 2020-01-01 - end: - Literal: - Date: 2021-01-01 - alias: dates - named_args: {} + - Unary: + op: Add + expr: + Ident: + - num_of_articles "###); } #[test] - fn test_dates() -> Result<()> { + fn test_dates() { assert_yaml_snapshot!(parse(" from employees derive [age_plus_two_years = (age + 2years)] @@ -2123,7 +1862,6 @@ join `my-proj`.`dataset`.`table` args: - Ident: - employees - named_args: {} - FuncCall: name: Ident: @@ -2141,40 +1879,30 @@ join `my-proj`.`dataset`.`table` n: 2 unit: years alias: age_plus_two_years - named_args: {} "###); - assert_yaml_snapshot!(parse(" - derive [ - date = @2011-02-01, - timestamp = @2011-02-01T10:00, - time = @14:00, - # datetime = @2011-02-01T10:00, - ] - ").unwrap(), @r###" + assert_yaml_snapshot!(parse_expr("@2011-02-01").unwrap(), @r###" --- - - Main: - FuncCall: - name: - Ident: - - derive - args: - - List: - - Literal: - Date: 2011-02-01 - alias: date - - Literal: - Timestamp: "2011-02-01T10:00" - alias: timestamp - - Literal: - Time: "14:00" - alias: time - named_args: {} + Literal: + Date: 2011-02-01 "###); + assert_yaml_snapshot!(parse_expr("@2011-02-01T10:00").unwrap(), @r###" + --- + Literal: + Timestamp: "2011-02-01T10:00" + "###); + assert_yaml_snapshot!(parse_expr("@14:00").unwrap(), @r###" + --- + Literal: + Time: "14:00" + "###); + // assert_yaml_snapshot!(parse_expr("@2011-02-01T10:00").unwrap(), @""); + + parse_expr("@2020-01-0").unwrap_err(); - assert!(parse("derive x = @2020-01-0").is_err()); + parse_expr("@2020-01-011").unwrap_err(); - Ok(()) + parse_expr("@2020-01-01T111").unwrap_err(); } #[test] @@ -2192,12 +1920,11 @@ join `my-proj`.`dataset`.`table` - Ident: - r alias: x - named_args: {} "### ) } #[test] - fn test_parse_coalesce() { + fn test_coalesce() { assert_yaml_snapshot!(parse(r###" from employees derive amount = amount ?? 0 @@ -2213,7 +1940,6 @@ join `my-proj`.`dataset`.`table` args: - Ident: - employees - named_args: {} - FuncCall: name: Ident: @@ -2228,12 +1954,11 @@ join `my-proj`.`dataset`.`table` Literal: Integer: 0 alias: amount - named_args: {} "### ) } #[test] - fn test_parse_literal() { + fn test_literal() { assert_yaml_snapshot!(parse(r###" derive x = true "###).unwrap(), @r###" @@ -2247,12 +1972,11 @@ join `my-proj`.`dataset`.`table` - Literal: Boolean: true alias: x - named_args: {} "###) } #[test] - fn test_parse_allowed_idents() { + fn test_allowed_idents() { assert_yaml_snapshot!(parse(r###" from employees join _salary [==employee_id] # table with leading underscore @@ -2270,7 +1994,6 @@ join `my-proj`.`dataset`.`table` args: - Ident: - employees - named_args: {} - FuncCall: name: Ident: @@ -2284,7 +2007,6 @@ join `my-proj`.`dataset`.`table` expr: Ident: - employee_id - named_args: {} - FuncCall: name: Ident: @@ -2298,7 +2020,6 @@ join `my-proj`.`dataset`.`table` right: Ident: - $1 - named_args: {} - FuncCall: name: Ident: @@ -2308,12 +2029,11 @@ join `my-proj`.`dataset`.`table` - Ident: - _employees - _underscored_column - named_args: {} "###) } #[test] - fn test_parse_gt_lt_gte_lte() { + fn test_gt_lt_gte_lte() { assert_yaml_snapshot!(parse(r###" from people filter age >= 100 @@ -2332,7 +2052,6 @@ join `my-proj`.`dataset`.`table` args: - Ident: - people - named_args: {} - FuncCall: name: Ident: @@ -2346,7 +2065,6 @@ join `my-proj`.`dataset`.`table` right: Literal: Integer: 100 - named_args: {} - FuncCall: name: Ident: @@ -2360,7 +2078,6 @@ join `my-proj`.`dataset`.`table` right: Literal: Integer: 10 - named_args: {} - FuncCall: name: Ident: @@ -2374,7 +2091,6 @@ join `my-proj`.`dataset`.`table` right: Literal: Integer: 0 - named_args: {} - FuncCall: name: Ident: @@ -2388,7 +2104,6 @@ join `my-proj`.`dataset`.`table` right: Literal: Integer: 2 - named_args: {} "###) } @@ -2409,7 +2124,6 @@ join s=salaries [==id] args: - Ident: - employees - named_args: {} - FuncCall: name: Ident: @@ -2424,7 +2138,63 @@ join s=salaries [==id] expr: Ident: - id - named_args: {} + "###); + } + + #[test] + fn test_ident_with_keywords() { + assert_yaml_snapshot!(parse_expr(r"select [andrew, orion, lettuce, falsehood, null0]").unwrap(), @r###" + --- + FuncCall: + name: + Ident: + - select + args: + - List: + - Ident: + - andrew + - Ident: + - orion + - Ident: + - lettuce + - Ident: + - falsehood + - Ident: + - null0 + "###); + + assert_yaml_snapshot!(parse_expr(r"[false]").unwrap(), @r###" + --- + List: + - Literal: + Boolean: false + "###); + } + + #[test] + fn test_switch() { + assert_yaml_snapshot!(parse_expr(r#"switch [ + nickname != null -> nickname, + true -> null + ]"#).unwrap(), @r###" + --- + Switch: + - condition: + Binary: + left: + Ident: + - nickname + op: Ne + right: + Literal: "Null" + value: + Ident: + - nickname + - condition: + Literal: + Boolean: true + value: + Literal: "Null" "###); } } diff --git a/prql-compiler/src/parser/prql.pest b/prql-compiler/src/parser/prql.pest deleted file mode 100644 index b30651838c25..000000000000 --- a/prql-compiler/src/parser/prql.pest +++ /dev/null @@ -1,150 +0,0 @@ -WHITESPACE = _{ " " | "\t" } - -// TODO: maybe pass comments to AST (and potentially put them into SQL comments) -COMMENT = _{ "#" ~ (!NEWLINE ~ ANY) * } - -statements = _{ SOI ~ NEWLINE* ~ query_def ? ~ (func_def | var_def)* ~ pipeline_stmt? ~ EOI } - -query_def = { "prql" ~ named_arg* ~ NEWLINE+ } - -func_def = { "func" ~ func_def_name ~ func_def_params ~ "->" ~ expr_call ~ ( NEWLINE+ | &EOI ) } - -func_def_name = { ident_part ~ type_def? } -func_def_params = { func_def_param* } -func_def_param = { ident_part ~ type_def? ~ (":" ~ expr)? } -type_def = { "<" ~ type_term ~ ( "|" ~ type_term)* ~ ">" } -type_term = { ident_part ~ type_def? } - -var_def = { "let" ~ ident_part ~ "=" ~ expr_call ~ ( NEWLINE+ | &EOI ) } - -pipeline_stmt = { pipeline ~ ( NEWLINE+ | &EOI ) } - -// An ident is a sequence of word-like terms, separated by `.`. Where surrounded -// by backticks, the term is taken as-is, including any periods it contains. -// We allow `e.*`, but not just `*`, since it would conflict with multiply in some cases. -ident = ${ - !operator - ~ (ident_plain | ident_backticks) - ~ ("." ~ (ident_plain | ident_backticks | ident_star))* -} -ident_part = ${ ident_plain | ident_backticks } -// Either a normal ident (starting with a letter, `$` or `_`), or any string surrounded -// by backticks. -ident_plain = { ((ASCII_ALPHA | "$" | "_") ~ (ASCII_ALPHANUMERIC | "_" )* ) } -ident_backticks = _{ PUSH("`") ~ (!NEWLINE ~ string_inner)* ~ POP } -// This is split out so we can make `ident_part_next` silent, but still capture it. -ident_star = { "*" } - -pipe = _{ NEWLINE+ | "|" } -pipeline = { WHITESPACE* ~ expr_call ~ (pipe ~ expr_call)* } - -// Whitespace is required to prevent matching s"string". Forbid `operator_binary` so `a -// - b` can't parse as `a` & `-b` (but allow `select ![a]`) -func_call = ${ ident ~ WHITESPACE+ ~ (!operator_binary ~ (named_arg | alias | expr) ~ WHITESPACE*)+ } - -named_arg = !{ ident_part ~ ":" ~ !":" ~ expr } -// alias needs to be distinct from assign, so that in `join s=salaries [==id]`, -// `s=salaries` is parsed separately from `[==id]`, since aliases allow for an -// expr as an rvalue, but not a function call. -alias = !{ ident_part ~ "=" ~ !"=" ~ expr } -assign = !{ ident_part ~ "=" ~ !"=" ~ expr_call } - -expr_call = _{ (func_call | expr) } - -expr = !{ expr_coalesce ~ (operator_logical ~ expr)? } -expr_coalesce = { expr_compare ~ (operator_coalesce ~ expr_coalesce)? } -expr_compare = { expr_add ~ (operator_compare ~ expr_add)? } -expr_add = { expr_mul ~ (operator_add ~ expr_add)? } -expr_mul = { term ~ (operator_mul ~ expr_mul)? } - -term = _{ ( switch | s_string | f_string | range | literal | ident | nested_pipeline | expr_unary | list ) } -expr_unary = { ( operator_unary ~ ( nested_pipeline | ident | list )) } -literal = _{ value_and_unit | number | boolean | null | string | timestamp | date | time | "(" ~ literal ~ ")" } -// `assign | pipeline` based on discussion in #648 -list = { "[" ~ (NEWLINE* ~ (assign | pipeline) ~ ("," ~ NEWLINE* ~ (assign | pipeline) )* ~ ","?)? ~ NEWLINE* ~ "]" } -nested_pipeline = { "(" ~ (WHITESPACE | NEWLINE)* ~ pipeline? ~ (WHITESPACE | NEWLINE)* ~ ")" } - -// We haven't implemented escapes — I think we can mostly pass those through to -// SQL, but there may be things we're missing. -// https://pest.rs/book/examples/rust/literals.html - -// We need to have a non-silent rule which contains the quotes -// — `string` in this case — because of -// https://github.com/pest-parser/pest/issues/583. Then when converting to AST, -// we only keep the `string_inner` and discard the `string` given it contains -// the quotes. -// -// TODO: I'm still a bit unclear how preceding and trailing spaces are working -// -- it seems that inner spaces are included without an atomic operator (or -// with `ANY`), but prceeding & trailing spaces require both `ANY` _and_ an -// atomic operator. We have some rudimentary tests for these. - -single_quote = _{ "\"" | "'" } -multi_quote = _{ "\""{3,} | "'"{3,} } -opening_quote = _{ PUSH(multi_quote) | PUSH(single_quote) } -// PEEK refers to the opening quote; `"` or `'` or multiple quotes. -string_inner = { ( !( PEEK ) ~ ANY )+ } -// Either > 3 quotes, or just one. Currently both of those can be multiline. -string = ${ opening_quote ~ string_inner? ~ POP } - -// We can use underscores within numbers -number_char = _{ ASCII_DIGIT | "_" } -// Numbers need to start and end with a digit. We implement the end by matching -// either a number_char that's not the final char, or a final char that's a digit. -number_part = _{ ( ASCII_DIGIT ) ~ (( number_char ~ &number_char )* ~ ( ASCII_DIGIT ~ !number_char ))? } -number = ${ operator_add? ~ number_part ~ ("." ~ number_part)? } - -boolean = ${ "true" | "false" } - -null = ${ "null" } - -range = ${ range_edge ~ ".." ~ range_edge } -range_edge = ${ literal? } - -operator = _{ operator_unary | operator_binary } -operator_binary = _{ operator_mul | operator_add | operator_compare | operator_logical | operator_coalesce } -operator_unary = ${ "-" | "+" | "!" | "==" } -operator_mul = ${ "*" | "/" | "%" } -operator_add = ${ "+" | "-" } -operator_compare = ${ "==" | "!=" | ">=" | "<=" | ">" | "<" } -operator_logical = ${ ("and" | "or") ~ &WHITESPACE } -operator_coalesce = ${ "??" } - -// If we have lots more string prefixes then we could just have a type -// `prefixed` string and parse in the parser, but manageable for now. -s_string = ${ "s" ~ opening_quote ~ interpolate_string_inner ~ POP } -f_string = ${ "f" ~ opening_quote ~ interpolate_string_inner ~ POP } -interpolate_string_inner = _{ - ( - interpolate_string_inner_literal | - double_open_bracket | - double_close_bracket | - ( "{" ~ pipeline ~ "}" ) - )* -} -double_open_bracket = { "{{" } -double_close_bracket = { "}}" } -// Anything apart from the quote (PEEK), the beginning of an expr (`{`), or a `}}` -interpolate_string_inner_literal = { ( !( PEEK | "{" | double_close_bracket ) ~ ANY )+ } - -unit = { "microseconds" | "milliseconds" | "seconds" | "minutes" | "hours" | "days" | "weeks" | "months" | "years" } -value_and_unit = ${ number ~ unit } - -date = ${ "@" ~ date_inner ~ &end_expr } -time = ${ "@" ~ time_inner ~ &end_expr } -timestamp = ${ "@" ~ timestamp_inner ~ &end_expr } -// We use the `inner` types as containing the data that we want to retain in the AST. -date_inner = ${ ASCII_DIGIT{4} ~ "-" ~ ASCII_DIGIT{2} ~ "-" ~ ASCII_DIGIT{2} } -// Times are liberally defined atm, we could make this more robust. -time_inner = ${ ASCII_DIGIT{2} ~ (( ":" | "." ) ~ ASCII_DIGIT* )* ~ ((( "+" | "-" ) ~ (ASCII_DIGIT | ":" )*) | "Z")? } -timestamp_inner = ${ date_inner ~ "T" ~ time_inner } - -// We can use this when want to ensure something is ending, like a date, so `@20-01-0` -// isn't treated like a time `@20-01` `-` (minus) `0`. -// (Not sure whether `..` should be here or in the items that allow it; feel -// free to demote it to those items if `end_expr` is used somewhere where it's -// not supported) -end_expr = _{ WHITESPACE | "," | ")" | "]" | EOI | NEWLINE | ".." } - -switch = { "switch" ~ "[" ~ (NEWLINE* ~ switch_case ~ ("," ~ NEWLINE* ~ switch_case )* ~ ","?)? ~ NEWLINE* ~ "]" } -switch_case = { expr_call ~ "->" ~ expr_call } diff --git a/prql-compiler/src/parser/snapshots/prql_compiler__parser__test__parse_pipeline_parse_tree.snap b/prql-compiler/src/parser/snapshots/prql_compiler__parser__test__pipeline_parse_tree.snap similarity index 85% rename from prql-compiler/src/parser/snapshots/prql_compiler__parser__test__parse_pipeline_parse_tree.snap rename to prql-compiler/src/parser/snapshots/prql_compiler__parser__test__pipeline_parse_tree.snap index 66faeab9a4cb..d973041eff4d 100644 --- a/prql-compiler/src/parser/snapshots/prql_compiler__parser__test__parse_pipeline_parse_tree.snap +++ b/prql-compiler/src/parser/snapshots/prql_compiler__parser__test__pipeline_parse_tree.snap @@ -1,6 +1,6 @@ --- source: prql-compiler/src/parser/mod.rs -expression: "stmts_of_parse_pairs(parse_tree_of_str(&include_str!(\"../../../book/tests/prql/examples/variables-0.prql\").trim().replace(\"\\r\\n\",\n \"\\n\"), Rule::statements).unwrap()).unwrap()" +expression: "parse(&include_str!(\"../../../book/tests/prql/examples/variables-0.prql\")).unwrap()" --- - Main: Pipeline: @@ -12,7 +12,6 @@ expression: "stmts_of_parse_pairs(parse_tree_of_str(&include_str!(\"../../../boo args: - Ident: - employees - named_args: {} - FuncCall: name: Ident: @@ -26,7 +25,6 @@ expression: "stmts_of_parse_pairs(parse_tree_of_str(&include_str!(\"../../../boo right: Literal: String: USA - named_args: {} - FuncCall: name: Ident: @@ -51,7 +49,6 @@ expression: "stmts_of_parse_pairs(parse_tree_of_str(&include_str!(\"../../../boo Ident: - benefits_cost alias: gross_cost - named_args: {} - FuncCall: name: Ident: @@ -65,7 +62,6 @@ expression: "stmts_of_parse_pairs(parse_tree_of_str(&include_str!(\"../../../boo right: Literal: Integer: 0 - named_args: {} - FuncCall: name: Ident: @@ -89,7 +85,6 @@ expression: "stmts_of_parse_pairs(parse_tree_of_str(&include_str!(\"../../../boo args: - Ident: - salary - named_args: {} - FuncCall: name: Ident: @@ -97,7 +92,6 @@ expression: "stmts_of_parse_pairs(parse_tree_of_str(&include_str!(\"../../../boo args: - Ident: - gross_salary - named_args: {} - FuncCall: name: Ident: @@ -105,7 +99,6 @@ expression: "stmts_of_parse_pairs(parse_tree_of_str(&include_str!(\"../../../boo args: - Ident: - salary - named_args: {} - FuncCall: name: Ident: @@ -113,7 +106,6 @@ expression: "stmts_of_parse_pairs(parse_tree_of_str(&include_str!(\"../../../boo args: - Ident: - gross_salary - named_args: {} - FuncCall: name: Ident: @@ -121,7 +113,6 @@ expression: "stmts_of_parse_pairs(parse_tree_of_str(&include_str!(\"../../../boo args: - Ident: - gross_cost - named_args: {} - FuncCall: name: Ident: @@ -129,13 +120,10 @@ expression: "stmts_of_parse_pairs(parse_tree_of_str(&include_str!(\"../../../boo args: - Ident: - gross_cost - named_args: {} alias: sum_gross_cost - Ident: - count alias: ct - named_args: {} - named_args: {} - FuncCall: name: Ident: @@ -143,7 +131,6 @@ expression: "stmts_of_parse_pairs(parse_tree_of_str(&include_str!(\"../../../boo args: - Ident: - sum_gross_cost - named_args: {} - FuncCall: name: Ident: @@ -157,7 +144,6 @@ expression: "stmts_of_parse_pairs(parse_tree_of_str(&include_str!(\"../../../boo right: Literal: Integer: 200 - named_args: {} - FuncCall: name: Ident: @@ -165,5 +151,4 @@ expression: "stmts_of_parse_pairs(parse_tree_of_str(&include_str!(\"../../../boo args: - Literal: Integer: 20 - named_args: {} diff --git a/prql-compiler/src/parser/stmt.rs b/prql-compiler/src/parser/stmt.rs new file mode 100644 index 000000000000..3006cfbe0c1f --- /dev/null +++ b/prql-compiler/src/parser/stmt.rs @@ -0,0 +1,154 @@ +use std::{collections::HashMap, str::FromStr}; + +use chumsky::prelude::*; +use semver::VersionReq; + +use crate::ast::pl::*; + +use super::common::*; +use super::expr::*; +use super::lexer::Token; + +pub fn source() -> impl Parser, Error = Simple> { + query_def() + .or_not() + .chain::( + var_def() + .or(function_def()) + .separated_by(new_line().repeated()) + .allow_leading() + .allow_trailing(), + ) + .chain(main_pipeline().or_not()) + .then_ignore(end()) + .labelled("source file") +} + +fn main_pipeline() -> impl Parser> { + pipeline(expr_call()) + .map_with_span(into_expr) + .map(Box::new) + .map(StmtKind::Main) + .map_with_span(into_stmt) + .labelled("main pipeline") +} + +fn query_def() -> impl Parser> { + new_line() + .repeated() + .ignore_then(keyword("prql")) + .ignore_then( + // named arg + ident_part().then_ignore(ctrl(':')).then(expr()).repeated(), + ) + .then_ignore(new_line()) + .try_map(|args, span| { + let mut args: HashMap<_, _> = args.into_iter().collect(); + + let version = args + .remove("version") + .map(|v| match v.kind { + ExprKind::Literal(Literal::String(v)) => { + VersionReq::parse(&v).map_err(|e| e.to_string()) + } + _ => Err("version must be a sting literal".to_string()), + }) + .transpose() + .map_err(|msg| Simple::custom(span, msg))?; + + let other = args + .into_iter() + .flat_map(|(key, value)| match value.kind { + ExprKind::Ident(value) => Some((key, value.to_string())), + _ => None, + }) + .collect(); + + Ok(StmtKind::QueryDef(QueryDef { version, other })) + }) + .map_with_span(into_stmt) + .labelled("query header") +} + +fn var_def() -> impl Parser> { + keyword("let") + .ignore_then(ident_part()) + .then_ignore(ctrl('=')) + .then(expr_call().map(Box::new)) + .map(|(name, value)| VarDef { name, value }) + .map(StmtKind::VarDef) + .map_with_span(into_stmt) + .labelled("variable definition") +} + +fn function_def() -> impl Parser> { + keyword("func") + .ignore_then( + // func name + ident_part().then(type_expr().or_not()), + ) + .then( + // params + ident_part() + .then(type_expr().or_not()) + .then(ctrl(':').ignore_then(expr()).or_not()) + .repeated(), + ) + .then_ignore(just(Token::Arrow)) + .then(expr_call().map(Box::new)) + .then_ignore(new_line()) + .map(|(((name, return_ty), params), body)| { + let (pos, nam) = params + .into_iter() + .map(|((name, ty), default_value)| FuncParam { + name, + ty, + default_value, + }) + .partition(|p| p.default_value.is_none()); + + FuncDef { + name, + positional_params: pos, + named_params: nam, + body, + return_ty, + } + }) + .map(StmtKind::FuncDef) + .map_with_span(into_stmt) + .labelled("function definition") +} + +pub fn type_expr() -> impl Parser> { + recursive(|type_expr| { + let type_term = ident_part().then(type_expr.or_not()).map(|(name, param)| { + let ty = match TyLit::from_str(&name) { + Ok(t) => Ty::from(t), + Err(_) if name == "table" => Ty::Table(Frame::default()), + Err(_) => { + eprintln!("named type: {}", name); + Ty::Named(name.to_string()) + } + }; + + if let Some(param) = param { + Ty::Parameterized(Box::new(ty), Box::new(param)) + } else { + ty + } + }); + + type_term + .separated_by(ctrl('|')) + .delimited_by(ctrl('<'), ctrl('>')) + .map(|mut terms| { + if terms.len() == 1 { + terms.remove(0) + } else { + Ty::AnyOf(terms) + } + }) + }) + .labelled("type expression") +} diff --git a/prql-compiler/src/semantic/resolver.rs b/prql-compiler/src/semantic/resolver.rs index b0cd8af29b40..d4c4bcc0e948 100644 --- a/prql-compiler/src/semantic/resolver.rs +++ b/prql-compiler/src/semantic/resolver.rs @@ -227,6 +227,11 @@ impl AstFold for Resolver { Expr { kind, ..node } } + ExprKind::Unary { + op: UnOp::Add, + expr, + } => self.fold_expr(*expr)?, + ExprKind::Unary { op: UnOp::Not, expr, diff --git a/prql-compiler/src/semantic/snapshots/prql_compiler__semantic__resolver__test__functions_nested.snap b/prql-compiler/src/semantic/snapshots/prql_compiler__semantic__resolver__test__functions_nested.snap index 7901f4f36660..7f629f209879 100644 --- a/prql-compiler/src/semantic/snapshots/prql_compiler__semantic__resolver__test__functions_nested.snap +++ b/prql-compiler/src/semantic/snapshots/prql_compiler__semantic__resolver__test__functions_nested.snap @@ -8,48 +8,48 @@ expression: "resolve_derive(r#\"\n func lag_day x -> s\"lag_day_todo( id: 15 Binary: left: - id: 12 - Ident: - - _frame - - a - - b - target_id: 6 + id: 16 + Binary: + left: + id: 12 + Ident: + - _frame + - a + - b + target_id: 6 + ty: Infer + op: Div + right: + id: 21 + SString: + - String: lag_day_todo( + - Expr: + id: 12 + Ident: + - _frame + - a + - b + target_id: 6 + ty: Infer + - String: ) + ty: Infer ty: Infer - op: Div + op: Sub right: - id: 20 - SString: - - String: lag_day_todo( - - Expr: - id: 12 - Ident: - - _frame - - a - - b - target_id: 6 - ty: Infer - - String: ) - ty: Infer - ty: Infer - op: Sub - right: - id: 22 - Binary: - left: id: 23 Literal: Integer: 1 ty: Literal: Integer - op: Add - right: - id: 13 - Ident: - - _frame - - a - - c - target_id: 6 - ty: Infer + ty: Infer + op: Add + right: + id: 13 + Ident: + - _frame + - a + - c + target_id: 6 ty: Infer ty: Literal: Column diff --git a/prql-compiler/src/test.rs b/prql-compiler/src/test.rs index 4b3f16018b5f..0afc74a533bc 100644 --- a/prql-compiler/src/test.rs +++ b/prql-compiler/src/test.rs @@ -2417,11 +2417,11 @@ fn test_unused_alias() { select n = [account.name] "###).unwrap_err(), @r###" Error: - ╭─[:3:12] + ╭─[:3:16] │ 3 │ select n = [account.name] - · ─────────┬──────── - · ╰────────── unexpected assign to `n` + · ───────┬────── + · ╰──────── unexpected assign to `n` · · Help: move assign into the list: `[n = ...]` ───╯ @@ -2569,11 +2569,11 @@ fn test_direct_table_references() { ) .unwrap_err(), @r###" Error: - ╭─[:3:15] + ╭─[:3:14] │ 3 │ select s"{x}.field" - · ┬ - · ╰── table instance cannot be referenced directly + · ─┬─ + · ╰─── table instance cannot be referenced directly · · Help: did you forget to specify the column name? ───╯ @@ -2890,11 +2890,11 @@ fn test_errors() { "###).unwrap_err(), @r###" Error: - ╭─[:5:12] + ╭─[:5:16] │ 5 │ derive y = (addadd 4 5 6) - · ─────────┬──────── - · ╰────────── Too many arguments to function `addadd` + · ───────┬────── + · ╰──────── Too many arguments to function `addadd` ───╯ "###); @@ -2906,8 +2906,8 @@ fn test_errors() { ╭─[:2:5] │ 2 │ from a select b - · ───────┬─────── - · ╰───────── Too many arguments to function `from` + · ────────┬─────── + · ╰───────── Too many arguments to function `from` ───╯ "###); From e40a6201617baff35751f5e1e4be3792cc4552cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alja=C5=BE=20Mur=20Er=C5=BEen?= Date: Mon, 27 Feb 2023 21:50:47 +0100 Subject: [PATCH 058/106] feat: parse and compile params (#1957) --- CHANGELOG.md | 1 + prql-compiler/src/ast/pl/expr.rs | 8 +++++- prql-compiler/src/ast/pl/fold.rs | 1 + prql-compiler/src/ast/rq/expr.rs | 3 ++ prql-compiler/src/ast/rq/fold.rs | 1 + prql-compiler/src/parser/expr.rs | 16 +++++++++-- prql-compiler/src/parser/lexer.rs | 11 +++++++- prql-compiler/src/parser/mod.rs | 23 ++++++++++----- prql-compiler/src/semantic/context.rs | 2 +- prql-compiler/src/semantic/lowering.rs | 4 +-- prql-compiler/src/semantic/std.prql | 1 - prql-compiler/src/semantic/transforms.rs | 36 +----------------------- prql-compiler/src/sql/anchor.rs | 1 + prql-compiler/src/sql/gen_expr.rs | 1 + prql-compiler/src/test.rs | 27 ++++++++++++++++++ 15 files changed, 85 insertions(+), 51 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c60fe61f27a1..953ea069121f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ - Float literals without fraction part are not allowed anymore (`1.`). - Add a `--format` option to `prqlc parse` which can return the AST in YAML (@max-sixty, #1962) +- Support for SQL parameters with similar syntax (#1957, @aljazerzen) **Fixes**: diff --git a/prql-compiler/src/ast/pl/expr.rs b/prql-compiler/src/ast/pl/expr.rs index cfba08fc4934..d23926e458f6 100644 --- a/prql-compiler/src/ast/pl/expr.rs +++ b/prql-compiler/src/ast/pl/expr.rs @@ -77,6 +77,9 @@ pub enum ExprKind { name: String, args: Vec, }, + + /// a placeholder for values provided after query is compiled + Param(String), } impl ExprKind { @@ -338,7 +341,7 @@ pub enum TableExternRef { /// Placeholder for a relation that will be provided later. /// This is very similar to relational s-strings and may not even be needed for now, so /// it's not documented anywhere. But it will be used in the future. - Anchor(String), + Param(String), // TODO: add other sources such as files, URLs } @@ -580,6 +583,9 @@ impl Display for Expr { ExprKind::BuiltInFunction { .. } => { f.write_str("")?; } + ExprKind::Param(id) => { + writeln!(f, "${id}")?; + } } Ok(()) diff --git a/prql-compiler/src/ast/pl/fold.rs b/prql-compiler/src/ast/pl/fold.rs index b82f9178a296..9d7664f80fe6 100644 --- a/prql-compiler/src/ast/pl/fold.rs +++ b/prql-compiler/src/ast/pl/fold.rs @@ -110,6 +110,7 @@ pub fn fold_expr_kind(fold: &mut T, expr_kind: ExprKind) -> name, args: fold.fold_exprs(args)?, }, + Param(id) => Param(id), // None of these capture variables, so we don't need to fold them. Literal(_) => expr_kind, diff --git a/prql-compiler/src/ast/rq/expr.rs b/prql-compiler/src/ast/rq/expr.rs index bf70f4745ffd..ba9f07a8bc40 100644 --- a/prql-compiler/src/ast/rq/expr.rs +++ b/prql-compiler/src/ast/rq/expr.rs @@ -40,6 +40,9 @@ pub enum ExprKind { name: String, args: Vec, }, + + /// Placeholder for + Param(String), } #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] diff --git a/prql-compiler/src/ast/rq/fold.rs b/prql-compiler/src/ast/rq/fold.rs index 1c799e35dfe0..ca0920244f41 100644 --- a/prql-compiler/src/ast/rq/fold.rs +++ b/prql-compiler/src/ast/rq/fold.rs @@ -233,6 +233,7 @@ pub fn fold_expr_kind(fold: &mut F, kind: ExprKind) -> Resul name, args: args.into_iter().map(|a| fold.fold_expr(a)).try_collect()?, }, + ExprKind::Param(id) => ExprKind::Param(id), ExprKind::Literal(_) => kind, }) diff --git a/prql-compiler/src/parser/expr.rs b/prql-compiler/src/parser/expr.rs index ea9c2d32cbc7..6a24915f7a44 100644 --- a/prql-compiler/src/parser/expr.rs +++ b/prql-compiler/src/parser/expr.rs @@ -86,9 +86,19 @@ pub fn expr() -> impl Parser> + Clone { ) .map(ExprKind::Switch); - let term = choice((literal, list, pipeline, interpolation, ident_kind, switch)) - .map_with_span(into_expr) - .boxed(); + let param = select! { Token::Param(id) => ExprKind::Param(id) }; + + let term = choice(( + literal, + list, + pipeline, + interpolation, + ident_kind, + switch, + param, + )) + .map_with_span(into_expr) + .boxed(); // Unary operators let term = term diff --git a/prql-compiler/src/parser/lexer.rs b/prql-compiler/src/parser/lexer.rs index 11d63f491300..2fb468c716ad 100644 --- a/prql-compiler/src/parser/lexer.rs +++ b/prql-compiler/src/parser/lexer.rs @@ -9,6 +9,7 @@ pub enum Token { Ident(String), Keyword(String), Literal(Literal), + Param(String), Range { bind_left: bool, @@ -57,6 +58,11 @@ pub fn lexer() -> impl Parser)>, Error let literal = literal().map(Token::Literal); + let param = just('$') + .ignore_then(filter(|c: &char| c.is_alphanumeric() || *c == '_' || *c == '.').repeated()) + .collect::() + .map(Token::Param); + // s-string and f-strings let interpolation = one_of("sf") .then(quoted_string(true)) @@ -66,6 +72,7 @@ pub fn lexer() -> impl Parser)>, Error new_line.clone(), control_multi, interpolation, + param, control, literal, keyword, @@ -106,7 +113,7 @@ pub fn lexer() -> impl Parser)>, Error } pub fn ident_part() -> impl Parser> { - let plain = filter(|c: &char| c.is_ascii_alphabetic() || *c == '_' || *c == '$') + let plain = filter(|c: &char| c.is_ascii_alphabetic() || *c == '_') .map(Some) .chain::, _>( filter(|c: &char| c.is_ascii_alphanumeric() || *c == '_').repeated(), @@ -382,6 +389,8 @@ impl std::fmt::Display for Token { Self::Or => f.write_str("or"), Self::Coalesce => f.write_str("??"), + Self::Param(id) => write!(f, "${id}"), + Self::Range { bind_left, bind_right, diff --git a/prql-compiler/src/parser/mod.rs b/prql-compiler/src/parser/mod.rs index 461cc0eb5d5f..466850b1cc26 100644 --- a/prql-compiler/src/parser/mod.rs +++ b/prql-compiler/src/parser/mod.rs @@ -1672,17 +1672,14 @@ Canada - first_name op: Eq right: - Ident: - - $1 + Param: "1" - Binary: left: Ident: - last_name op: Eq right: - Ident: - - $2 - - name + Param: 2.name "###); } @@ -2018,8 +2015,7 @@ join `my-proj`.`dataset`.`table` - first_name op: Eq right: - Ident: - - $1 + Param: "1" - FuncCall: name: Ident: @@ -2197,4 +2193,17 @@ join s=salaries [==id] Literal: "Null" "###); } + + #[test] + fn test_params() { + assert_yaml_snapshot!(parse_expr(r#"$2"#).unwrap(), @r###" + --- + Param: "2" + "###); + + assert_yaml_snapshot!(parse_expr(r#"$2_any_text"#).unwrap(), @r###" + --- + Param: 2_any_text + "###); + } } diff --git a/prql-compiler/src/semantic/context.rs b/prql-compiler/src/semantic/context.rs index e61af872ad52..a49fa788fbf3 100644 --- a/prql-compiler/src/semantic/context.rs +++ b/prql-compiler/src/semantic/context.rs @@ -75,7 +75,7 @@ pub enum TableExpr { LocalTable, /// A placeholder for a relation that will be provided later. - Anchor(String), + Param(String), } #[derive(Clone, Eq, Debug, PartialEq, Serialize, Deserialize)] diff --git a/prql-compiler/src/semantic/lowering.rs b/prql-compiler/src/semantic/lowering.rs index 25383b9dd744..32d1ab558d05 100644 --- a/prql-compiler/src/semantic/lowering.rs +++ b/prql-compiler/src/semantic/lowering.rs @@ -653,7 +653,7 @@ impl Lowerer { rq::ExprKind::BuiltInFunction { name, args } } - + pl::ExprKind::Param(id) => rq::ExprKind::Param(id), pl::ExprKind::FuncCall(_) | pl::ExprKind::Range(_) | pl::ExprKind::List(_) @@ -820,7 +820,7 @@ fn lower_table(lowerer: &mut Lowerer, table: context::TableDecl, fq_ident: Ident TableExpr::LocalTable => { extern_ref_to_relation(columns, TableExternRef::LocalTable(fq_ident.name)) } - TableExpr::Anchor(id) => extern_ref_to_relation(columns, TableExternRef::Anchor(id)), + TableExpr::Param(id) => extern_ref_to_relation(columns, TableExternRef::Param(id)), }; log::debug!("lowering table {name:?}, columns = {:?}", relation.columns); diff --git a/prql-compiler/src/semantic/std.prql b/prql-compiler/src/semantic/std.prql index 586a9dcaf94f..201bf929ad4a 100644 --- a/prql-compiler/src/semantic/std.prql +++ b/prql-compiler/src/semantic/std.prql @@ -59,4 +59,3 @@ func _is_null a -> _param.a == null # Misc func from_text
text `noresolve.format`:csv -> null -func anchor
id -> null diff --git a/prql-compiler/src/semantic/transforms.rs b/prql-compiler/src/semantic/transforms.rs index 15c73cbbe44f..661ddc1de351 100644 --- a/prql-compiler/src/semantic/transforms.rs +++ b/prql-compiler/src/semantic/transforms.rs @@ -10,7 +10,7 @@ use crate::ast::pl::*; use crate::ast::rq::RelationColumn; use crate::error::{Error, Reason, WithErrorInfo}; -use super::context::{Decl, DeclKind, TableDecl, TableExpr}; +use super::context::{Decl, DeclKind}; use super::module::{Module, NS_FRAME, NS_PARAM}; use super::resolver::Resolver; use super::{Context, Frame}; @@ -375,40 +375,6 @@ pub fn cast_transform(resolver: &mut Resolver, closure: Closure) -> Result { - // yes, this is not a transform, but this is the most appropriate place for it - - let [id_expr] = unpack::<1>(closure); - - let id = match id_expr.kind { - ExprKind::Literal(Literal::String(text)) => text, - _ => { - return Err(Error::new(Reason::Expected { - who: Some("std.anchor".to_string()), - expected: "a string literal".to_string(), - found: format!("`{id_expr}`"), - }) - .with_span(id_expr.span) - .into()); - } - }; - - let ident = Ident::from_path(vec!["_anchor".to_string(), id.clone()]); - let entry = Decl { - declared_at: id_expr.id, - kind: DeclKind::TableDecl(TableDecl { - columns: vec![RelationColumn::Wildcard], - expr: TableExpr::Anchor(id), - }), - order: 0, - }; - resolver.context.root_mod.insert(ident.clone(), entry)?; - - let mut res = Expr::from(ExprKind::Ident(ident)); - res.alias = Some("anchor".to_string()); - return Ok(Ok(res)); - } - _ => return Ok(Err(closure)), }; diff --git a/prql-compiler/src/sql/anchor.rs b/prql-compiler/src/sql/anchor.rs index 4c0e0ece9b76..a81bcc37d63c 100644 --- a/prql-compiler/src/sql/anchor.rs +++ b/prql-compiler/src/sql/anchor.rs @@ -476,6 +476,7 @@ pub fn infer_complexity_expr(expr: &Expr) -> Complexity { rq::ExprKind::ColumnRef(_) | rq::ExprKind::Literal(_) | rq::ExprKind::SString(_) + | rq::ExprKind::Param(_) | rq::ExprKind::FString(_) => Complexity::Plain, } } diff --git a/prql-compiler/src/sql/gen_expr.rs b/prql-compiler/src/sql/gen_expr.rs index 271b4a6a1833..f062989289e2 100644 --- a/prql-compiler/src/sql/gen_expr.rs +++ b/prql-compiler/src/sql/gen_expr.rs @@ -91,6 +91,7 @@ pub(super) fn translate_expr_kind(item: ExprKind, ctx: &mut Context) -> Result sql_ast::Expr::Identifier(sql_ast::Ident::new(format!("${id}"))), ExprKind::FString(f_string_items) => translate_fstring(f_string_items, ctx)?, ExprKind::Literal(l) => translate_literal(l, ctx)?, ExprKind::Switch(mut cases) => { diff --git a/prql-compiler/src/test.rs b/prql-compiler/src/test.rs index 0afc74a533bc..7fe43edc3c11 100644 --- a/prql-compiler/src/test.rs +++ b/prql-compiler/src/test.rs @@ -3293,3 +3293,30 @@ fn test_loop() { "### ); } + +#[test] +fn test_params() { + assert_display_snapshot!(compile(r#" + from i = invoices + filter $1 <= i.date or i.date <= $2 + select [ + i.id, + i.total, + ] + filter i.total > $3 + "#).unwrap(), + @r###" + SELECT + id, + total + FROM + invoices AS i + WHERE + ( + $1 <= date + OR date <= $2 + ) + AND total > $3 + "### + ); +} From 8fe72ecd1902f69adbaf377fdf02c9978888cb52 Mon Sep 17 00:00:00 2001 From: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Date: Mon, 27 Feb 2023 13:16:47 -0800 Subject: [PATCH 059/106] chore: Remove reference to pest grammar (#1977) This was causing a build failure on main --- book/src/internals/syntax-highlighting.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/book/src/internals/syntax-highlighting.md b/book/src/internals/syntax-highlighting.md index 2a2c3d8b0ca7..506d15e3a4f3 100644 --- a/book/src/internals/syntax-highlighting.md +++ b/book/src/internals/syntax-highlighting.md @@ -30,8 +30,3 @@ an index. and helix. The grammar can be found at [https://github.com/matthias-Q/tree-sitter-prql](https://github.com/matthias-Q/tree-sitter-prql). This is in a very early stage. - -While the [pest](https://pest.rs/) grammar at -[`prql-compiler/src/parser/prql.pest`](https://github.com/PRQL/prql/blob/main/prql-compiler/src/parser/prql.pest) -isn't used for syntax highlighting, it's the arbiter of truth given it currently -powers the PRQL compiler. From 410068ed2c712c9e30a636ce09d4c741b944671e Mon Sep 17 00:00:00 2001 From: Matthias Q <35303817+matthias-Q@users.noreply.github.com> Date: Mon, 27 Feb 2023 22:32:00 +0100 Subject: [PATCH 060/106] docs: update tree-sitter information (#1976) Co-authored-by: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> --- book/src/internals/syntax-highlighting.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/book/src/internals/syntax-highlighting.md b/book/src/internals/syntax-highlighting.md index 506d15e3a4f3..7249f249f37f 100644 --- a/book/src/internals/syntax-highlighting.md +++ b/book/src/internals/syntax-highlighting.md @@ -28,5 +28,4 @@ an index. - [Tree-Sitter](https://tree-sitter.github.io/tree-sitter) — used by the neovim and helix. The grammar can be found at - [https://github.com/matthias-Q/tree-sitter-prql](https://github.com/matthias-Q/tree-sitter-prql). - This is in a very early stage. + [https://github.com/PRQL/tree-sitter-prql](https://github.com/PRQL/tree-sitter-prql). From 340455f04ff1d94e02ea0ca46c0a56f93672a6d6 Mon Sep 17 00:00:00 2001 From: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Date: Mon, 27 Feb 2023 15:49:46 -0800 Subject: [PATCH 061/106] ci: Move to `baptiste0928/cargo-install` for CI (#1979) We were getting 404s on the existing action, and this is also faster once it's cached --- .github/actions/build-prql-js/action.yaml | 5 ++--- .github/workflows/test-rust.yaml | 4 +++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/actions/build-prql-js/action.yaml b/.github/actions/build-prql-js/action.yaml index 8843384d437c..804ed072502e 100644 --- a/.github/actions/build-prql-js/action.yaml +++ b/.github/actions/build-prql-js/action.yaml @@ -6,10 +6,9 @@ description: "" runs: using: composite steps: - - name: Install wasm-pack - uses: jetli/wasm-pack-action@v0.4.0 + - uses: baptiste0928/cargo-install@next with: - version: "latest" + crate: wasm-pack - name: Setup Node uses: actions/setup-node@v3 diff --git a/.github/workflows/test-rust.yaml b/.github/workflows/test-rust.yaml index c983bc6dab46..2c8d0f3b9625 100644 --- a/.github/workflows/test-rust.yaml +++ b/.github/workflows/test-rust.yaml @@ -20,7 +20,9 @@ jobs: with: key: ${{ inputs.target_option }} save-if: ${{ github.ref == 'refs/heads/main' }} - - uses: jetli/wasm-bindgen-action@v0.2.0 + - uses: baptiste0928/cargo-install@next + with: + crate: wasm-bindgen-cli if: inputs.target_option == '--target=wasm32-unknown-unknown' - name: 📎 Clippy uses: richb-hanover/cargo@v1.1.0 From e934ce8138d65660b2c00541e8aa8990e71230f5 Mon Sep 17 00:00:00 2001 From: hbc Date: Tue, 28 Feb 2023 08:44:02 +0800 Subject: [PATCH 062/106] test: repro timestamp parsing issue (#1980) * test: repro timestamp parsing issue * Update prql-compiler/src/test.rs Co-authored-by: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> * Update prql-compiler/src/test.rs Co-authored-by: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> --------- Co-authored-by: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> --- prql-compiler/src/test.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/prql-compiler/src/test.rs b/prql-compiler/src/test.rs index 7fe43edc3c11..b47bedd5c3ad 100644 --- a/prql-compiler/src/test.rs +++ b/prql-compiler/src/test.rs @@ -3320,3 +3320,22 @@ fn test_params() { "### ); } + +// TODO: fix this based on https://github.com/PRQL/prql/pull/1818 +#[test] +#[should_panic] +fn test_datetime_parsing() { + assert_display_snapshot!(compile(r#" + from test_tables + select [date = @2022-12-31, time = @08:30, timestamp = @2020-01-01T13:19:55-0800] + "#).unwrap(), + @r###" + SELECT + DATE '2022-12-31' AS date, + TIME '08:30' AS time, + TIMESTAMP '2020-01-01T13:19:55-0800' AS timestamp + FROM + test_table + "### + ); +} From 5d620566f0cd7b12be7a8b8eeb1ed8c88c978a1a Mon Sep 17 00:00:00 2001 From: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Date: Mon, 27 Feb 2023 16:59:52 -0800 Subject: [PATCH 063/106] chore: Fix typo (#1981) --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 5507308038bd..9232d5453e70 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ rust-version = "1.65.0" version = "0.5.2" [profile.release.package.prql-js] -# Tell `rustc` to optimize for small code size. +# Tell `rust-js` to optimize for small code size. opt-level = "s" [workspace.metadata.release] From 9e6306c9b37eeb2ccc1ed3ef50a9a3d3401dc180 Mon Sep 17 00:00:00 2001 From: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Date: Mon, 27 Feb 2023 18:17:37 -0800 Subject: [PATCH 064/106] chore: Remove extraneous file (#1984) I must have committed this by mistake --- prql-compiler/prqlc/x.prql | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 prql-compiler/prqlc/x.prql diff --git a/prql-compiler/prqlc/x.prql b/prql-compiler/prqlc/x.prql deleted file mode 100644 index ed56de0b1bc9..000000000000 --- a/prql-compiler/prqlc/x.prql +++ /dev/null @@ -1,3 +0,0 @@ -let x = 2 + 2 - -from x From 3da40beea2b216862f72ccff456ab924c8232493 Mon Sep 17 00:00:00 2001 From: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Date: Mon, 27 Feb 2023 19:09:51 -0800 Subject: [PATCH 065/106] fix: Attempt to fix the chumsky break on MacOS (#1978) * fix: Attempt to fix the chumsky break on MacOS * Re-enable workflows * Excluding features from macos vs. wasm --- .github/workflows/test-all.yaml | 4 ---- .github/workflows/test-js.yaml | 3 --- Cargo.toml | 1 + prql-compiler/Cargo.toml | 9 +++++++-- prql-js/tests/test_all.js | 2 +- 5 files changed, 9 insertions(+), 10 deletions(-) diff --git a/.github/workflows/test-all.yaml b/.github/workflows/test-all.yaml index 0582d00a4983..653edc9acdbb 100644 --- a/.github/workflows/test-all.yaml +++ b/.github/workflows/test-all.yaml @@ -28,10 +28,6 @@ jobs: os: [ubuntu-latest, windows-latest, macos-latest] target_option: ["", --target=wasm32-unknown-unknown] - # Combination of macos and wasm32 has a problem with crate psm, a dependency of chumsky - exclude: - - os: macos-latest - target_option: --target=wasm32-unknown-unknown uses: ./.github/workflows/test-rust.yaml with: os: ${{ matrix.os }} diff --git a/.github/workflows/test-js.yaml b/.github/workflows/test-js.yaml index baa88eeda2b2..b018d0e9414b 100644 --- a/.github/workflows/test-js.yaml +++ b/.github/workflows/test-js.yaml @@ -18,9 +18,6 @@ jobs: matrix: os: [ubuntu-latest, macos-latest, windows-latest] - # Combination of macos and wasm32 has a problem with crate psm, a dependency of chumsky - exclude: - - os: macos-latest steps: - name: 📂 Checkout code uses: actions/checkout@v3 diff --git a/Cargo.toml b/Cargo.toml index 9232d5453e70..04b449a500f7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,7 @@ members = [ # Note we don't have a `default-members = ["prql-compiler"]`, since that causes # commands like `cargo test` to only run tests from the default package. And # `cargo insta test` doesn't have a `--workspace` flag. +resolver = "2" [workspace.package] edition = "2021" diff --git a/prql-compiler/Cargo.toml b/prql-compiler/Cargo.toml index 3faa6d29a725..d2df7ea01bf7 100644 --- a/prql-compiler/Cargo.toml +++ b/prql-compiler/Cargo.toml @@ -15,7 +15,6 @@ metadata.msrv = "1.65.0" [dependencies] anyhow = {version = "1.0.57", features = ["backtrace"]} ariadne = "0.1.5" -chumsky = "0.9.0" csv = "1.2.0" enum-as-inner = "0.5.0" itertools = "0.10.3" @@ -31,13 +30,19 @@ sqlparser = {version = "0.30.0", features = ["serde"]} strum = {version = "0.24.0", features = ["std", "derive"]}# for converting enum variants to string strum_macros = "0.24.0" +# Chumsky issues in wasm (though we only see it when compiling on MacOS) +[target.'cfg(not(target_family="wasm"))'.dependencies] +chumsky = "0.9.0" +[target.'cfg(target_family="wasm")'.dependencies] +chumsky = {version = "0.9.0", features = ["ahash", "std"], default-features = false} + [dev-dependencies] cfg-if = "1.0" insta = {version = "1.28", features = ["colors", "glob", "yaml"]} # For integration tests [target.'cfg(not(target_family="wasm"))'.dev-dependencies] -chrono = {version = "0.4", features = [], default-features = false } +chrono = {version = "0.4", features = [], default-features = false} criterion = "0.4.0" postgres = "0.19.3" pretty_assertions = "1.3.0" diff --git a/prql-js/tests/test_all.js b/prql-js/tests/test_all.js index 624ab4040efb..7732e2c1e090 100644 --- a/prql-js/tests/test_all.js +++ b/prql-js/tests/test_all.js @@ -35,7 +35,7 @@ describe("prql-js", () => { it("should throw an error on invalid prql", () => { expect(() => - prql.compile("Mississippi has four S’s and four I’s.") + prql.compile("Mississippi has four Ss and four Is.") ).to.throw("Error"); }); From ea4c70895629ea73cee156c90ea6ab2e188a38c4 Mon Sep 17 00:00:00 2001 From: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Date: Mon, 27 Feb 2023 22:01:06 -0800 Subject: [PATCH 066/106] ci: Reset cache (#1986) --- .github/workflows/test-rust.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/test-rust.yaml b/.github/workflows/test-rust.yaml index 2c8d0f3b9625..0ac9ed479b11 100644 --- a/.github/workflows/test-rust.yaml +++ b/.github/workflows/test-rust.yaml @@ -18,6 +18,11 @@ jobs: - name: 💰 Cache uses: Swatinem/rust-cache@v2 with: + # Based on https://github.com/PRQL/prql/issues/1985, attempting to + # reset the cache. If necessary, we could do this on each release and + # have this update automatically (there's no variable that contains + # the current version unfortunately, though). + prefix-key: "0.5.2" key: ${{ inputs.target_option }} save-if: ${{ github.ref == 'refs/heads/main' }} - uses: baptiste0928/cargo-install@next From 800c7a7926fa0317dbfb496c134512960903a36d Mon Sep 17 00:00:00 2001 From: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Date: Tue, 28 Feb 2023 01:02:26 -0800 Subject: [PATCH 067/106] test: Add test for query which blocks on chumsky (#1982) * test: Add test for query which blocks on chumsky Based on #1978. It will block tests, probably until timeout * Add a very minimal test --- prql-compiler/src/parser/lexer.rs | 6 +++-- prql-compiler/src/parser/mod.rs | 39 +++++++++++++++++++++++++++++-- prql-compiler/src/test.rs | 10 ++++++++ 3 files changed, 51 insertions(+), 4 deletions(-) diff --git a/prql-compiler/src/parser/lexer.rs b/prql-compiler/src/parser/lexer.rs index 2fb468c716ad..63ffae47357c 100644 --- a/prql-compiler/src/parser/lexer.rs +++ b/prql-compiler/src/parser/lexer.rs @@ -77,8 +77,10 @@ pub fn lexer() -> impl Parser)>, Error literal, keyword, ident, - )) - .recover_with(skip_then_retry_until([]).skip_start()); + )); + // TODO: Add this back when https://github.com/zesterer/chumsky/issues/301 + // is fixed. + // .recover_with(skip_then_retry_until([]).skip_start()); let comment = just('#').then(none_of('\n').repeated()); let comments = comment diff --git a/prql-compiler/src/parser/mod.rs b/prql-compiler/src/parser/mod.rs index 466850b1cc26..ab2e6320c209 100644 --- a/prql-compiler/src/parser/mod.rs +++ b/prql-compiler/src/parser/mod.rs @@ -54,7 +54,13 @@ pub fn parse(source: &str) -> Result> { } fn convert_lexer_error(source: &str, e: Cheap) -> Error { - let found = source[e.span()].to_string(); + // TODO: is there a neater way of taking a span? We want to take it based on + // the chars, not the bytes, so can't just index into the str. + let found = source + .chars() + .skip(e.span().start) + .take(e.span().end() - e.span().start) + .collect(); let span = common::into_span(e.span()); Error::new(Reason::Unexpected { found }).with_span(span) @@ -164,7 +170,7 @@ mod test { use super::*; use anyhow::anyhow; - use insta::assert_yaml_snapshot; + use insta::{assert_debug_snapshot, assert_yaml_snapshot}; fn parse_expr(source: &str) -> Result> { let tokens = Parser::parse(&lexer::lexer(), source).map_err(|errs| { @@ -2206,4 +2212,33 @@ join s=salaries [==id] Param: 2_any_text "###); } + + #[test] + fn test_error_unicode_string() { + // Test various unicode strings successfully parse errors. We were + // getting loops in the lexer before. + parse("s’ ").unwrap_err(); + parse("s’").unwrap_err(); + parse(" s’").unwrap_err(); + parse(" ’ s").unwrap_err(); + parse("’s").unwrap_err(); + parse("👍 s’").unwrap_err(); + + let source = "Mississippi has four S’s and four I’s."; + assert_debug_snapshot!(parse(source).unwrap_err(), @r###" + Errors( + [ + Error { + span: Some( + span-chars-22-23, + ), + reason: Unexpected { + found: "’", + }, + help: None, + }, + ], + ) + "###); + } } diff --git a/prql-compiler/src/test.rs b/prql-compiler/src/test.rs index b47bedd5c3ad..be139b81725b 100644 --- a/prql-compiler/src/test.rs +++ b/prql-compiler/src/test.rs @@ -2939,6 +2939,16 @@ fn test_errors() { · ╰─── `take` expected int or range, but found 1.8 ───╯ "###); + + assert_display_snapshot!(compile("Mississippi has four S’s and four I’s.").unwrap_err(), @r###" + Error: + ╭─[:1:23] + │ + 1 │ Mississippi has four S’s and four I’s. + · ┬ + · ╰── unexpected ’ + ───╯ + "###); } #[test] From 7fce2b3607110ad19809c776a3a5ffca596a200b Mon Sep 17 00:00:00 2001 From: eitsupi <50911393+eitsupi@users.noreply.github.com> Date: Wed, 1 Mar 2023 01:15:30 +0900 Subject: [PATCH 068/106] chore: fix typo (#1988) --- .github/workflows/test-all.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-all.yaml b/.github/workflows/test-all.yaml index 653edc9acdbb..69658da969e6 100644 --- a/.github/workflows/test-all.yaml +++ b/.github/workflows/test-all.yaml @@ -115,7 +115,7 @@ jobs: - uses: baptiste0928/cargo-install@next with: crate: cargo-msrv - # Note this currently uses a manually mantained key in + # Note this currently uses a manually maintained key in # `prql-compiler/Cargo.toml`, because of # https://github.com/foresterre/cargo-msrv/issues/590 - name: Verify minimum rust version From 63b01fa4e343cd1e4e347bfaf81fd1cdc5676070 Mon Sep 17 00:00:00 2001 From: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Date: Tue, 28 Feb 2023 11:11:53 -0800 Subject: [PATCH 069/106] refactor: Attempt to replace our `IntoOnly` with `ExactlyOne` (#1915) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: Attempt to replace our `IntoOnly` with `ExactlyOne` Since I originally wrote this (and others have iterated on it), Itertools released `ExactlyOne`, which has better errors and reduces our custom code. Unfortunately, I couldn't fix a rust type error, and spent too long on it already. So pushing what I have in case anyone wants to take a look. There's also a decent chance that we replace the `parser.rs` code, in which case this type error becomes moot, and we can merge this anyway. * remove IntoOnly completely - even from public API * Allow multiple ErrorMessages in prql-python --------- Co-authored-by: Aljaž Mur Eržen --- prql-compiler/src/error.rs | 10 ----- prql-compiler/src/lib.rs | 1 - prql-compiler/src/semantic/resolver.rs | 4 +- prql-compiler/src/sql/gen_query.rs | 6 ++- prql-compiler/src/utils/mod.rs | 2 +- prql-compiler/src/utils/only.rs | 59 +++----------------------- prql-python/src/lib.rs | 4 +- 7 files changed, 14 insertions(+), 72 deletions(-) diff --git a/prql-compiler/src/error.rs b/prql-compiler/src/error.rs index 92f3f3492210..7861baeab3fd 100644 --- a/prql-compiler/src/error.rs +++ b/prql-compiler/src/error.rs @@ -6,8 +6,6 @@ use std::error::Error as StdError; use std::fmt::{self, Debug, Display, Formatter}; use std::ops::{Add, Range}; -use crate::utils::IntoOnly; - #[derive(Clone, PartialEq, Eq, Copy, Serialize, Deserialize)] pub struct Span { pub start: usize, @@ -218,14 +216,6 @@ impl ErrorMessages { } } -impl IntoOnly for ErrorMessages { - type Item = ErrorMessage; - - fn into_only(self) -> Result { - self.inner.into_only() - } -} - impl ErrorMessage { fn compose_display<'a, C>(&self, source_id: &'a str, cache: C, color: bool) -> Option where diff --git a/prql-compiler/src/lib.rs b/prql-compiler/src/lib.rs index 18894b6b5348..7107f45baaa6 100644 --- a/prql-compiler/src/lib.rs +++ b/prql-compiler/src/lib.rs @@ -87,7 +87,6 @@ mod test; mod utils; pub use error::{downcast, Error, ErrorMessage, ErrorMessages, Reason, SourceLocation, Span}; -pub use utils::IntoOnly; use once_cell::sync::Lazy; use semver::Version; diff --git a/prql-compiler/src/semantic/resolver.rs b/prql-compiler/src/semantic/resolver.rs index d4c4bcc0e948..f15003f4e3c5 100644 --- a/prql-compiler/src/semantic/resolver.rs +++ b/prql-compiler/src/semantic/resolver.rs @@ -760,15 +760,15 @@ fn env_of_closure(closure: Closure) -> (Module, Expr) { mod test { use anyhow::Result; use insta::assert_yaml_snapshot; + use itertools::Itertools; use crate::ast::pl::{Expr, Ty}; use crate::semantic::resolve_only; - use crate::utils::IntoOnly; fn parse_and_resolve(query: &str) -> Result { let (stmts, _) = resolve_only(crate::parser::parse(query)?, None)?; - Ok(*stmts.into_only()?.kind.into_main()?) + Ok(*stmts.into_iter().exactly_one()?.kind.into_main()?) } fn resolve_type(query: &str) -> Result { diff --git a/prql-compiler/src/sql/gen_query.rs b/prql-compiler/src/sql/gen_query.rs index fba04d0be692..421ce63d3170 100644 --- a/prql-compiler/src/sql/gen_query.rs +++ b/prql-compiler/src/sql/gen_query.rs @@ -16,7 +16,8 @@ use crate::ast::pl::{BinOp, JoinSide, Literal, RelationLiteral}; use crate::ast::rq::{CId, Expr, ExprKind, Query, RelationKind, TableRef, Transform}; use crate::sql::anchor::anchor_split; use crate::sql::preprocess::SqlRelationKind; -use crate::utils::{BreakUp, IntoOnly, Pluck}; +use crate::utils::{BreakUp, Pluck}; + use crate::Target; use super::context::AnchorContext; @@ -249,7 +250,8 @@ fn sql_select_query_of_pipeline( let projection = pipeline .pluck(|t| t.into_super_and(|t| t.into_select())) - .into_only() + .into_iter() + .exactly_one() .unwrap(); let projection = translate_wildcards(&ctx.anchor, projection); let projection = translate_select_items(projection.0, projection.1, ctx)?; diff --git a/prql-compiler/src/utils/mod.rs b/prql-compiler/src/utils/mod.rs index 0ff61841b1b1..792d55fbdf64 100644 --- a/prql-compiler/src/utils/mod.rs +++ b/prql-compiler/src/utils/mod.rs @@ -3,11 +3,11 @@ mod only; mod toposort; pub use id_gen::{IdGenerator, NameGenerator}; -use itertools::Itertools; pub use only::*; pub use toposort::toposort; use anyhow::Result; +use itertools::Itertools; pub trait OrMap { /// Merges two options into one using `f`. diff --git a/prql-compiler/src/utils/only.rs b/prql-compiler/src/utils/only.rs index 1a52e97027ee..0eef8df16664 100644 --- a/prql-compiler/src/utils/only.rs +++ b/prql-compiler/src/utils/only.rs @@ -1,46 +1,14 @@ -use anyhow::{anyhow, Result}; -use itertools::{Itertools, Position}; +use anyhow::Result; use crate::ast::pl::Expr; use crate::error::{Error, Reason}; -// Inspired by version in sqlparser-rs; I'm surprised there isn't a version in -// the stdlib / Itertools. -/// Returns the only element of an Iterator, or an error if it has more than one element. -pub trait IntoOnly { - type Item; - - fn into_only(self) -> Result; -} - -impl IntoOnly for I -where - I: IntoIterator, - // See below re using Debug. - // I: std::fmt::Debug, - // ::IntoIter: std::fmt::Debug, -{ - type Item = T; - - fn into_only(self) -> Result { - match self.into_iter().with_position().next() { - Some(Position::Only(item)) => Ok(item), - // Can't get the debug of the iterator because it's already - // consumed; is there a way around this? I guess we could show - // the items after the second, which is kinda weird. - Some(Position::First(_)) => Err(anyhow!("Expected only one element, but found more.",)), - None => Err(anyhow!("Expected one element, but found none.",)), - _ => unreachable!(), - } - } -} - -pub trait IntoOnlyNode { - fn into_only_node(self, who: &str, occupation: &str) -> Result; +pub trait ExactlyOneNode { + fn exactly_one_node(self, who: &str, occupation: &str) -> Result; } -impl IntoOnlyNode for Vec { - fn into_only_node(mut self, who: &str, occupation: &str) -> Result { +impl ExactlyOneNode for Vec { + fn exactly_one_node(mut self, who: &str, occupation: &str) -> Result { match self.len() { 1 => Ok(self.remove(0)), 0 => Err(Error { @@ -64,20 +32,3 @@ impl IntoOnlyNode for Vec { } } } - -pub trait Only { - fn only(&self) -> Result<&T>; -} - -impl Only for [T] -where - T: std::fmt::Debug, -{ - fn only(&self) -> Result<&T> { - if self.len() == 1 { - Ok(self.first().unwrap()) - } else { - Err(anyhow!("Expected 1 item, got {}; {:?}", self.len(), self)) - } - } -} diff --git a/prql-python/src/lib.rs b/prql-python/src/lib.rs index 1202df209d82..6beebe154a69 100644 --- a/prql-python/src/lib.rs +++ b/prql-python/src/lib.rs @@ -1,7 +1,7 @@ #![cfg(not(target_family = "wasm"))] use std::str::FromStr; -use prql_compiler::{self, IntoOnly, Target}; +use prql_compiler::{self, Target}; use pyo3::{exceptions, prelude::*}; #[pyfunction] @@ -11,7 +11,7 @@ pub fn compile(prql_query: &str, options: Option) -> PyResult(e.into_only().unwrap().reason))) + .map_err(|e| (PyErr::new::(e.to_string()))) } #[pyfunction] From 2a4b9e887d692f5079b8c57f4188c98ca9cce11a Mon Sep 17 00:00:00 2001 From: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Date: Tue, 28 Feb 2023 11:47:53 -0800 Subject: [PATCH 070/106] devops: Add `bacon` config file (#1989) * devops: Add `bacon` config file I recently discovered `bacon`, which is great (thanks to @snth for the link), and replaces some of the `watchexec` and `task` watch tasks. This is an initial config file; it'll get some updates as folks use it more. I'll also update `development.md` once I've used it more (unless anyone gets there first...). * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- Taskfile.yml | 2 +- bacon.toml | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 bacon.toml diff --git a/Taskfile.yml b/Taskfile.yml index 15995412728a..0407891f50f6 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -58,7 +58,7 @@ tasks: cmds: # `--locked` installs from the underlying lock files (which is not the # default?!) - - cargo install --locked cargo-audit cargo-insta cargo-release + - cargo install --locked bacon cargo-audit cargo-insta cargo-release default-target mdbook mdbook-admonish mdbook-toc wasm-bindgen-cli wasm-pack # Can't install atm with `--locked` diff --git a/bacon.toml b/bacon.toml new file mode 100644 index 000000000000..765e2d35ba32 --- /dev/null +++ b/bacon.toml @@ -0,0 +1,64 @@ +# Initial bacon config file; edits and contributions welcome. + +default_job = "check" + +# PRQL additions +[jobs.test-rust-fast] +command = ['cargo', 'insta', 'test', '--accept', "--color=always", "-p=prql-compiler", "--lib"] +[jobs.test-rust] +command = ['cargo', 'insta', 'test', '--accept', "--color=always"] + +# Standard tasks + +[jobs.check] +command = ["cargo", "check", "--color", "always"] +need_stdout = false + +[jobs.check-all] +command = ["cargo", "check", "--all-targets", "--color", "always"] +need_stdout = false +watch = ["tests", "benches", "examples"] + +[jobs.clippy] +command = ["cargo", "clippy", "--all-targets", "--color", "always"] +need_stdout = false +watch = ["tests", "benches", "examples"] + +[jobs.test] +command = ["cargo", "test", "--color", "always"] +need_stdout = true +watch = ["tests"] + +[jobs.doc] +command = ["cargo", "doc", "--color", "always", "--no-deps"] +need_stdout = false + +# If the doc compiles, then it opens in your browser and bacon switches +# to the previous job +[jobs.doc-open] +command = ["cargo", "doc", "--color", "always", "--no-deps", "--open"] +need_stdout = false +on_success = "back" # so that we don't open the browser at each change + +# You can run your application and have the result displayed in bacon, +# *if* it makes sense for this crate. You can run an example the same +# way. Don't forget the `--color always` part or the errors won't be +# properly parsed. +# If you want to pass options to your program, a `--` separator +# will be needed. +[jobs.run] +allow_warnings = true +command = ["cargo", "run", "--color", "always"] +need_stdout = true + +# You may define here keybindings that would be specific to +# a project, for example a shortcut to launch a specific job. +# Shortcuts to internal functions (scrolling, toggling, etc.) +# should go in your personal prefs.toml file instead. +[keybindings] +a = "job:check-all" +c = "job:clippy" +d = "job:doc-open" +i = "job:initial" +r = "job:run" +t = "job:test" From 9cd58a4bdbe43e112711e5624a895f13abee5315 Mon Sep 17 00:00:00 2001 From: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Date: Tue, 28 Feb 2023 16:28:33 -0800 Subject: [PATCH 071/106] fix: Allow no `:` in timezones (#1991) feat: Allow no `:` in timezones Fixes issue in #1818 --- CHANGELOG.md | 2 ++ book/src/language-features/dates-and-times.md | 12 ++++++------ prql-compiler/src/parser/lexer.rs | 12 +++++++++--- prql-compiler/src/test.rs | 14 ++++++-------- 4 files changed, 23 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 953ea069121f..466005ed691d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,8 @@ - Add a `--format` option to `prqlc parse` which can return the AST in YAML (@max-sixty, #1962) - Support for SQL parameters with similar syntax (#1957, @aljazerzen) +- Allow `:` to be elided in timezones, such as `0800` in + `@2020-01-01T13:19:55-0800` (@max-sixty, #1991). **Fixes**: diff --git a/book/src/language-features/dates-and-times.md b/book/src/language-features/dates-and-times.md index 529eda6a6521..e788ffc33165 100644 --- a/book/src/language-features/dates-and-times.md +++ b/book/src/language-features/dates-and-times.md @@ -36,8 +36,8 @@ derive should_have_shipped_today = (order_time < @08:30) Timestamps are represented by `@{yyyy-mm-ddTHH:mm:ss.SSS±Z}` / `@{date}T{time}`, with any time parts not supplied being rounded to zero, including the timezone, -which is represented by `+HH:mm`, `-HH:mm` or `Z`. This is `@` followed by the -ISO8601 datetime format, which uses `T` to separate date & time. +which is represented by `+HH:mm`, `-HH:mm` or `Z` (`:` is optional). This is `@` +followed by the ISO8601 datetime format, which uses `T` to separate date & time. ```prql from commits @@ -66,9 +66,9 @@ derive first_check_in = start + 10days Here's a fuller list of examples: -- `@20221231` is forbidden — it must contain full punctuation (`-` and `:`), +- `@20221231` is invalid — it must contain full punctuation (`-` and `:`), - `@2022-12-31` is a date -- `@2022-12` or `@2022` are forbidden — SQL can't express a month, only a date +- `@2022-12` or `@2022` are invalid — SQL can't express a month, only a date - `@16:54:32.123456` is a time - `@16:54:32`, `@16:54`, `@16` are all allowed, expressing `@16:54:32.000000`, `@16:54:00.000000`, `@16:00:00.000000` respectively @@ -76,8 +76,8 @@ Here's a fuller list of examples: - `@2022-12-31T16:54:32.123456Z` is a timestamp in UTC - `@2022-12-31T16:54+02` is timestamp in UTC+2 - `@2022-12-31T16:54+02:00` and `@2022-12-31T16:54+02` are datetimes in UTC+2 -- `@16:54+02` is forbidden — time is always local, so it cannot have a timezone -- `@2022-12-31+02` is forbidden — date is always local, so it cannot have a +- `@16:54+02` is invalid — time is always local, so it cannot have a timezone +- `@2022-12-31+02` is invalid — date is always local, so it cannot have a timezone ## Roadmap diff --git a/prql-compiler/src/parser/lexer.rs b/prql-compiler/src/parser/lexer.rs index 63ffae47357c..7874aced3c19 100644 --- a/prql-compiler/src/parser/lexer.rs +++ b/prql-compiler/src/parser/lexer.rs @@ -230,9 +230,15 @@ fn literal() -> impl Parser> { .chain::( one_of("-+") .chain( - digits(2) - .chain(just(':')) - .chain(digits(2)) + // TODO: This is repeated without the `:`~ with an `or` + // because using `.or_not` triggers a request for + // type hints, which seems difficult to provide... Is there + // an easier way? + // + // (digits(2).chain(just(':').or_not()).chain(digits(2))) + // + (digits(2).chain(just(':')).chain(digits(2))) + .or(digits(2).chain(digits(2))) .or(just('Z').map(|x| vec![x])), ) .or_not() diff --git a/prql-compiler/src/test.rs b/prql-compiler/src/test.rs index be139b81725b..994347860a24 100644 --- a/prql-compiler/src/test.rs +++ b/prql-compiler/src/test.rs @@ -3331,21 +3331,19 @@ fn test_params() { ); } -// TODO: fix this based on https://github.com/PRQL/prql/pull/1818 #[test] -#[should_panic] fn test_datetime_parsing() { assert_display_snapshot!(compile(r#" from test_tables select [date = @2022-12-31, time = @08:30, timestamp = @2020-01-01T13:19:55-0800] "#).unwrap(), @r###" - SELECT - DATE '2022-12-31' AS date, - TIME '08:30' AS time, - TIMESTAMP '2020-01-01T13:19:55-0800' AS timestamp - FROM - test_table + SELECT + DATE '2022-12-31' AS date, + TIME '08:30' AS time, + TIMESTAMP '2020-01-01T13:19:55-0800' AS timestamp + FROM + test_tables "### ); } From b666fb60b533cb25d29c141b5836b9acfb61eb8f Mon Sep 17 00:00:00 2001 From: hbc Date: Wed, 1 Mar 2023 08:36:30 +0800 Subject: [PATCH 072/106] fix: Fix sqlite datetime output (#1970) * test: add test case for sqlite datetime * feat: implement `is` helper for DialectHandler * fix: use datetime functions for sqlite dialect * style: fix lint issues * Update prql-compiler/src/sql/gen_expr.rs Co-authored-by: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> * Update prql-compiler/src/sql/gen_expr.rs Co-authored-by: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> * Update prql-compiler/src/sql/gen_expr.rs Co-authored-by: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> * test: move tests to test.rs * style: lint fix --------- Co-authored-by: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> --- prql-compiler/src/sql/dialect.rs | 10 +- prql-compiler/src/sql/gen_expr.rs | 212 ++++++++++++++++++++++++++++-- prql-compiler/src/test.rs | 44 +++++++ 3 files changed, 255 insertions(+), 11 deletions(-) diff --git a/prql-compiler/src/sql/dialect.rs b/prql-compiler/src/sql/dialect.rs index 6bc52b2859c7..18a74ef5e729 100644 --- a/prql-compiler/src/sql/dialect.rs +++ b/prql-compiler/src/sql/dialect.rs @@ -14,6 +14,7 @@ use core::fmt::Debug; use serde::{Deserialize, Serialize}; +use std::any::{Any, TypeId}; use strum::{EnumMessage, IntoEnumIterator}; /// SQL dialect. @@ -109,7 +110,7 @@ pub(super) enum ColumnExclude { Except, } -pub(super) trait DialectHandler { +pub(super) trait DialectHandler: Any { fn use_top(&self) -> bool { false } @@ -155,6 +156,13 @@ pub(super) trait DialectHandler { } } +impl dyn DialectHandler { + #[inline] + pub fn is(&self) -> bool { + TypeId::of::() == self.type_id() + } +} + impl DialectHandler for GenericDialect {} impl DialectHandler for PostgresDialect { diff --git a/prql-compiler/src/sql/gen_expr.rs b/prql-compiler/src/sql/gen_expr.rs index f062989289e2..2a6ed8aed55a 100644 --- a/prql-compiler/src/sql/gen_expr.rs +++ b/prql-compiler/src/sql/gen_expr.rs @@ -144,18 +144,17 @@ pub(super) fn translate_literal(l: Literal, ctx: &Context) -> Result sql_ast::Expr::Value(Value::Boolean(b)), Literal::Float(f) => sql_ast::Expr::Value(Value::Number(format!("{f:?}"), false)), Literal::Integer(i) => sql_ast::Expr::Value(Value::Number(format!("{i}"), false)), - Literal::Date(value) => sql_ast::Expr::TypedString { - data_type: sql_ast::DataType::Date, + Literal::Date(value) => translate_datetime_literal(sql_ast::DataType::Date, value, ctx), + Literal::Time(value) => translate_datetime_literal( + sql_ast::DataType::Time(None, sql_ast::TimezoneInfo::None), value, - }, - Literal::Time(value) => sql_ast::Expr::TypedString { - data_type: sql_ast::DataType::Time(None, sql_ast::TimezoneInfo::None), - value, - }, - Literal::Timestamp(value) => sql_ast::Expr::TypedString { - data_type: sql_ast::DataType::Timestamp(None, sql_ast::TimezoneInfo::None), + ctx, + ), + Literal::Timestamp(value) => translate_datetime_literal( + sql_ast::DataType::Timestamp(None, sql_ast::TimezoneInfo::None), value, - }, + ctx, + ), Literal::ValueAndUnit(vau) => { let sql_parser_datetime = match vau.unit.as_str() { "years" => DateTimeField::Year, @@ -185,6 +184,62 @@ pub(super) fn translate_literal(l: Literal, ctx: &Context) -> Result sql_ast::Expr { + if ctx.dialect.is::() { + translate_datetime_literal_with_sqlite_function(data_type, value) + } else { + translate_datetime_literal_with_typed_string(data_type, value) + } +} + +fn translate_datetime_literal_with_typed_string( + data_type: sql_ast::DataType, + value: String, +) -> sql_ast::Expr { + sql_ast::Expr::TypedString { data_type, value } +} + +fn translate_datetime_literal_with_sqlite_function( + data_type: sql_ast::DataType, + value: String, +) -> sql_ast::Expr { + // TODO: promote parsing timezone handling to the parser; we should be storing + // structured data rather than strings in the AST + let timezone_indicator_regex = Regex::new(r"([+-]\d{2}):?(\d{2})$").unwrap(); + let time_value = if let Some(groups) = timezone_indicator_regex.captures(value.as_str()) { + // formalize the timezone indicator to be [+-]HH:MM + // ref: https://www.sqlite.org/lang_datefunc.html + timezone_indicator_regex + .replace(&value, format!("{}:{}", &groups[1], &groups[2]).as_str()) + .to_string() + } else { + value + }; + + let arg = FunctionArg::Unnamed(FunctionArgExpr::Expr(sql_ast::Expr::Value( + Value::SingleQuotedString(time_value), + ))); + + let func_name = match data_type { + sql_ast::DataType::Date => data_type.to_string(), + sql_ast::DataType::Time(..) => data_type.to_string(), + sql_ast::DataType::Timestamp(..) => "DATETIME".to_string(), + _ => unreachable!(), + }; + + sql_ast::Expr::Function(Function { + name: ObjectName(vec![sql_ast::Ident::new(func_name)]), + args: vec![arg], + over: None, + distinct: false, + special: false, + }) +} + pub(super) fn translate_cid(cid: CId, ctx: &mut Context) -> Result { if ctx.query.pre_projection { log::debug!("translating {cid:?} pre projection"); @@ -931,4 +986,141 @@ mod test { Ok(()) } + + #[test] + fn test_translate_datetime_literal_with_sqlite_function() -> Result<()> { + assert_yaml_snapshot!( + translate_datetime_literal_with_sqlite_function( + sql_ast::DataType::Date, + "2020-01-01".to_string(), + ), + @r###" +--- +Function: + name: + - value: DATE + quote_style: ~ + args: + - Unnamed: + Expr: + Value: + SingleQuotedString: 2020-01-01 + over: ~ + distinct: false + special: false +"### + ); + + assert_yaml_snapshot!( + translate_datetime_literal_with_sqlite_function( + sql_ast::DataType::Time(None, sql_ast::TimezoneInfo::None), + "03:05".to_string(), + ), + @r###" +--- +Function: + name: + - value: TIME + quote_style: ~ + args: + - Unnamed: + Expr: + Value: + SingleQuotedString: "03:05" + over: ~ + distinct: false + special: false +"### + ); + + assert_yaml_snapshot!( + translate_datetime_literal_with_sqlite_function( + sql_ast::DataType::Time(None, sql_ast::TimezoneInfo::None), + "03:05+08:00".to_string(), + ), + @r###" +--- +Function: + name: + - value: TIME + quote_style: ~ + args: + - Unnamed: + Expr: + Value: + SingleQuotedString: "03:05+08:00" + over: ~ + distinct: false + special: false +"### + ); + + assert_yaml_snapshot!( + translate_datetime_literal_with_sqlite_function( + sql_ast::DataType::Time(None, sql_ast::TimezoneInfo::None), + "03:05+0800".to_string(), + ), + @r###" +--- +Function: + name: + - value: TIME + quote_style: ~ + args: + - Unnamed: + Expr: + Value: + SingleQuotedString: "03:05+08:00" + over: ~ + distinct: false + special: false +"### + ); + + assert_yaml_snapshot!( + translate_datetime_literal_with_sqlite_function( + sql_ast::DataType::Timestamp(None, sql_ast::TimezoneInfo::None), + "2021-03-14T03:05+0800".to_string(), + ), + @r###" +--- +Function: + name: + - value: DATETIME + quote_style: ~ + args: + - Unnamed: + Expr: + Value: + SingleQuotedString: "2021-03-14T03:05+08:00" + over: ~ + distinct: false + special: false +"### + ); + + assert_yaml_snapshot!( + translate_datetime_literal_with_sqlite_function( + sql_ast::DataType::Timestamp(None, sql_ast::TimezoneInfo::None), + "2021-03-14T03:05+08:00".to_string(), + ), + @r###" +--- +Function: + name: + - value: DATETIME + quote_style: ~ + args: + - Unnamed: + Expr: + Value: + SingleQuotedString: "2021-03-14T03:05+08:00" + over: ~ + distinct: false + special: false +"### + ); + + Ok(()) + } } diff --git a/prql-compiler/src/test.rs b/prql-compiler/src/test.rs index 994347860a24..a99e58ce425f 100644 --- a/prql-compiler/src/test.rs +++ b/prql-compiler/src/test.rs @@ -3328,6 +3328,50 @@ fn test_params() { ) AND total > $3 "### + ) +} + +// for #1969 +#[test] +fn test_datetime() { + let query = &r#" + from test_table + select [date = @2022-12-31, time = @08:30, timestamp = @2020-01-01T13:19:55-0800] + "#; + + assert_snapshot!( + compile(query).unwrap(), + @r###"SELECT + DATE '2022-12-31' AS date, + TIME '08:30' AS time, + TIMESTAMP '2020-01-01T13:19:55-0800' AS timestamp +FROM + test_table +"### + ) +} + +// for #1969 +#[test] +fn test_datetime_sqlite() { + let query = &r#" + from test_table + select [date = @2022-12-31, time = @08:30, timestamp = @2020-01-01T13:19:55-0800] + "#; + + let opts = Options::default() + .no_signature() + .with_target(Target::Sql(Some(sql::Dialect::SQLite))); + + assert_snapshot!( + crate::compile(query, &opts).unwrap(), + @r###"SELECT + DATE('2022-12-31') AS date, + TIME('08:30') AS time, + DATETIME('2020-01-01T13:19:55-08:00') AS timestamp +FROM + test_table +"### ); } From 4b4a8107670260645f0592a6bf4e13582b14cc15 Mon Sep 17 00:00:00 2001 From: Libing Chen Date: Wed, 1 Mar 2023 13:17:22 +0800 Subject: [PATCH 073/106] feat: adjust panic to Java Exception (#1971) * build: update to version 0.5.2 * feat: add Exception for method signature * chore: add Exception for test method * feat: adjust panic to Java Exception and add format method * chore: use implicit return * test: add compileWithError() to test compile with error * feat: add dialect, format and signature parameters for toSql method * chore: update toSql method signature * lint: code polishing reported by clippy * chore: code format * docs: adjust signature for toSQL() * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * docs: format * chore: introduce target dialect from https://github.com/PRQL/prql/blob/main/book/src/language-features/target.md * chore: rename dialect to target * Use target rather than dialect * lint * docs: add javadoc for toSql() --------- Co-authored-by: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Maximilian Roos --- prql-java/DEVELOPMENT.md | 4 +- prql-java/java/pom.xml | 2 +- .../java/org/prql/prql4j/PrqlCompiler.java | 15 ++++- .../org/prql/prql4j/PrqlCompilerTest.java | 9 ++- prql-java/src/lib.rs | 61 +++++++++++++++---- 5 files changed, 72 insertions(+), 19 deletions(-) diff --git a/prql-java/DEVELOPMENT.md b/prql-java/DEVELOPMENT.md index a8dc766aa1eb..5d2933a86a32 100644 --- a/prql-java/DEVELOPMENT.md +++ b/prql-java/DEVELOPMENT.md @@ -8,8 +8,8 @@ We implement Rust bindings to Java with [JNI](https://docs.oracle.com/javase/8/docs/technotes/guides/jni/). First, define a native method -- -`public static native String toSql(String query)` for PrqlCompiler, `toJson` is -same. +`public static native String toSql(String query, String target, boolean format, boolean signature)` +for PrqlCompiler, `toJson` is same. And then implement it in Rust with this [crate](https://docs.rs/jni/latest/jni/). diff --git a/prql-java/java/pom.xml b/prql-java/java/pom.xml index 84d8bddd2339..d7276e6edff1 100644 --- a/prql-java/java/pom.xml +++ b/prql-java/java/pom.xml @@ -6,7 +6,7 @@ org.prqllang prql-java - 0.2.1 + 0.5.2 ${project.groupId}:${project.artifactId} prql-compiler api for java diff --git a/prql-java/java/src/main/java/org/prql/prql4j/PrqlCompiler.java b/prql-java/java/src/main/java/org/prql/prql4j/PrqlCompiler.java index 49f47d19728d..bf0efbf46f23 100644 --- a/prql-java/java/src/main/java/org/prql/prql4j/PrqlCompiler.java +++ b/prql-java/java/src/main/java/org/prql/prql4j/PrqlCompiler.java @@ -3,8 +3,19 @@ import java.io.IOException; public class PrqlCompiler { - public static native String toSql(String query); - public static native String toJson(String query); + + /** + * compile PRQL to SQL + * @param query PRQL query + * @param target target dialect, such as sql.mysql etc. Please refer PRQL Target and Version + * @param format format SQL or not + * @param signature comment signature or not + * @return SQL + * @throws Exception PRQL compile exception + */ + public static native String toSql(String query, String target, boolean format, boolean signature) throws Exception; + public static native String toJson(String query) throws Exception; + public static native String format(String query) throws Exception; static { try { diff --git a/prql-java/java/src/test/java/org/prql/prql4j/PrqlCompilerTest.java b/prql-java/java/src/test/java/org/prql/prql4j/PrqlCompilerTest.java index 4ca948b87959..5a8627d62c57 100644 --- a/prql-java/java/src/test/java/org/prql/prql4j/PrqlCompilerTest.java +++ b/prql-java/java/src/test/java/org/prql/prql4j/PrqlCompilerTest.java @@ -4,8 +4,8 @@ public class PrqlCompilerTest { @Test - public void compile() { - String found = PrqlCompiler.toSql("from table"); + public void compile() throws Exception { + String found = PrqlCompiler.toSql("from table", "sql.mysql", true, true); // remove signature found = found.substring(0, found.indexOf("\n\n--")); @@ -16,4 +16,9 @@ public void compile() { " table"; assert expected.equalsIgnoreCase(found); } + + @Test(expected = Exception.class) + public void compileWithError() throws Exception { + PrqlCompiler.toSql("from table | filter id >> 1", "sql.mysql", true, true); + } } diff --git a/prql-java/src/lib.rs b/prql-java/src/lib.rs index 6c59dfa9fb24..93e7052dc160 100644 --- a/prql-java/src/lib.rs +++ b/prql-java/src/lib.rs @@ -1,7 +1,8 @@ use jni::objects::{JClass, JString}; -use jni::sys::jstring; +use jni::sys::{jboolean, jstring}; use jni::JNIEnv; -use prql_compiler::{json, prql_to_pl, Options}; +use prql_compiler::{json, pl_to_prql, prql_to_pl, ErrorMessages, Options, Target}; +use std::str::FromStr; #[no_mangle] #[allow(non_snake_case)] @@ -9,16 +10,41 @@ pub extern "system" fn Java_org_prql_prql4j_PrqlCompiler_toSql( env: JNIEnv, _class: JClass, query: JString, + target: JString, + format: jboolean, + signature: jboolean, ) -> jstring { let prql_query: String = env .get_string(query) .expect("Couldn't get java string!") .into(); - let rs_sql_str: String = prql_compiler::compile(&prql_query, &Options::default()) - .expect("Couldn't compile query to prql!"); - env.new_string(rs_sql_str) - .expect("Couldn't create java string!") - .into_raw() + let target_str: String = env + .get_string(target) + .expect("Couldn't get java string") + .into(); + let prql_dialect: Target = Target::from_str(&target_str).unwrap_or(Target::Sql(None)); + let opt = Options { + format: format != 0, + target: prql_dialect, + signature_comment: signature != 0, + }; + let result = prql_compiler::compile(&prql_query, &opt); + java_string_with_exception(result, &env) +} + +#[no_mangle] +#[allow(non_snake_case)] +pub extern "system" fn Java_org_prql_prql4j_PrqlCompiler_format( + env: JNIEnv, + _class: JClass, + query: JString, +) -> jstring { + let prql_query: String = env + .get_string(query) + .expect("Couldn't get java string!") + .into(); + let result = prql_to_pl(&prql_query).and_then(pl_to_prql); + java_string_with_exception(result, &env) } #[no_mangle] @@ -32,9 +58,20 @@ pub extern "system" fn Java_org_prql_prql4j_PrqlCompiler_toJson( .get_string(query) .expect("Couldn't get java string!") .into(); - let rs_json_str: String = { prql_to_pl(&prql_query).and_then(json::from_pl) } - .expect("Couldn't get json from prql query!"); - env.new_string(rs_json_str) - .expect("Couldn't create java string!") - .into_raw() + let result = prql_to_pl(&prql_query).and_then(json::from_pl); + java_string_with_exception(result, &env) +} + +fn java_string_with_exception(result: Result, env: &JNIEnv) -> jstring { + if let Ok(text) = result { + env.new_string(text) + .expect("Couldn't create java string!") + .into_raw() + } else { + let exception = env.find_class("java/lang/Exception").unwrap(); + if let Err(e) = env.throw_new(exception, result.err().unwrap().to_string()) { + println!("Error throwing exception: {:?}", e); + } + std::ptr::null_mut() as jstring + } } From c75c7852756470c7359dddc5a603a2a94913dc8b Mon Sep 17 00:00:00 2001 From: eitsupi <50911393+eitsupi@users.noreply.github.com> Date: Wed, 1 Mar 2023 18:46:19 +0900 Subject: [PATCH 074/106] build: add very experimental MegaLinter config files (#1974) * build: add MegaLinter config files * build: disable errors of some linters * chore: temporarily enable linting for all codes * build: disable stylelint because of looong time required in CI * chore: auto formatting * build: disable all Linter errors that are currently causing errors * build: disable markdown-link-chack's error * build: disable megalinter's GitHub comment reporter * chore: add comments in megalinter config files * docs: add note about MegaLinter * Revert "chore: temporarily enable linting for all codes" This reverts commit a665b2dd19bf6b16ba437d76b106a4e2e1582a43. * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * build: fix workflow trigger not to run twice in PR from other branch --------- Co-authored-by: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .github/workflows/mega-linter.yaml | 105 +++++++++++++++++++++++++++ .mega-linter.yaml | 34 +++++++++ book/src/contributing/development.md | 3 + 3 files changed, 142 insertions(+) create mode 100644 .github/workflows/mega-linter.yaml create mode 100644 .mega-linter.yaml diff --git a/.github/workflows/mega-linter.yaml b/.github/workflows/mega-linter.yaml new file mode 100644 index 000000000000..542bcb365b59 --- /dev/null +++ b/.github/workflows/mega-linter.yaml @@ -0,0 +1,105 @@ +# This MegaLinter workflow is very experimental stage. Open to changes and updates. +# https://github.com/PRQL/prql/pull/1974 + +# MegaLinter GitHub Action configuration file +# More info at https://megalinter.io +name: MegaLinter + +on: + push: + branches: + - main + pull_request: + branches: + - main + +env: # Comment env block if you do not want to apply fixes + # Apply linter fixes configuration + # APPLY_FIXES: all # When active, APPLY_FIXES must also be defined as environment variable (in github/workflows/mega-linter.yml or other CI tool) + APPLY_FIXES_EVENT: pull_request # Decide which event triggers application of fixes in a commit or a PR (pull_request, push, all) + APPLY_FIXES_MODE: commit # If APPLY_FIXES is used, defines if the fixes are directly committed (commit) or posted in a PR (pull_request) + +concurrency: + group: ${{ github.ref }}-${{ github.workflow }} + cancel-in-progress: true + +jobs: + build: + name: MegaLinter + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 # If you use VALIDATE_ALL_CODEBASE = true, you can remove this line to improve performances + + # MegaLinter + - name: MegaLinter + id: ml + # You can override MegaLinter flavor used to have faster performances + # More info at https://megalinter.io/flavors/ + uses: oxsecurity/megalinter@v6 + env: + # All available variables are described in documentation + # https://megalinter.io/configuration/ + VALIDATE_ALL_CODEBASE: ${{ github.event_name == 'push' && github.ref + == 'refs/heads/main' }} # Validates all source when push on main, else just the git diff with main. Override with true if you always want to lint all sources + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + # ADD YOUR CUSTOM ENV VARIABLES HERE OR DEFINE THEM IN A FILE .mega-linter.yml AT THE ROOT OF YOUR REPOSITORY + # DISABLE: COPYPASTE,SPELL # Uncomment to disable copy-paste and spell checks + + # Upload MegaLinter artifacts + - name: Archive production artifacts + if: ${{ success() }} || ${{ failure() }} + uses: actions/upload-artifact@v3 + with: + name: MegaLinter reports + path: | + megalinter-reports + mega-linter.log + + # Create pull request if applicable (for now works only on PR from same repository, not from forks) + - name: Create Pull Request with applied fixes + id: cpr + if: + steps.ml.outputs.has_updated_sources == 1 && (env.APPLY_FIXES_EVENT == + 'all' || env.APPLY_FIXES_EVENT == github.event_name) && + env.APPLY_FIXES_MODE == 'pull_request' && (github.event_name == 'push' + || github.event.pull_request.head.repo.full_name == github.repository) + uses: peter-evans/create-pull-request@v4 + with: + token: ${{ secrets.PAT || secrets.GITHUB_TOKEN }} + commit-message: "[MegaLinter] Apply linters automatic fixes" + title: "[MegaLinter] Apply linters automatic fixes" + labels: bot + - name: Create PR output + if: + steps.ml.outputs.has_updated_sources == 1 && (env.APPLY_FIXES_EVENT == + 'all' || env.APPLY_FIXES_EVENT == github.event_name) && + env.APPLY_FIXES_MODE == 'pull_request' && (github.event_name == 'push' + || github.event.pull_request.head.repo.full_name == github.repository) + run: | + echo "Pull Request Number - ${{ steps.cpr.outputs.pull-request-number }}" + echo "Pull Request URL - ${{ steps.cpr.outputs.pull-request-url }}" + + # Push new commit if applicable (for now works only on PR from same repository, not from forks) + - name: Prepare commit + if: + steps.ml.outputs.has_updated_sources == 1 && (env.APPLY_FIXES_EVENT == + 'all' || env.APPLY_FIXES_EVENT == github.event_name) && + env.APPLY_FIXES_MODE == 'commit' && github.ref != 'refs/heads/main' && + (github.event_name == 'push' || + github.event.pull_request.head.repo.full_name == github.repository) + run: sudo chown -Rc $UID .git/ + - name: Commit and push applied linter fixes + if: + steps.ml.outputs.has_updated_sources == 1 && (env.APPLY_FIXES_EVENT == + 'all' || env.APPLY_FIXES_EVENT == github.event_name) && + env.APPLY_FIXES_MODE == 'commit' && github.ref != 'refs/heads/main' && + (github.event_name == 'push' || + github.event.pull_request.head.repo.full_name == github.repository) + uses: stefanzweifel/git-auto-commit-action@v4 + with: + branch: + ${{ github.event.pull_request.head.ref || github.head_ref || + github.ref }} + commit_message: "[MegaLinter] Apply linters fixes" diff --git a/.mega-linter.yaml b/.mega-linter.yaml new file mode 100644 index 000000000000..680a2e9edbe4 --- /dev/null +++ b/.mega-linter.yaml @@ -0,0 +1,34 @@ +# This MegaLinter config is very experimental stage. Open to changes and updates. +# https://github.com/PRQL/prql/pull/1974 + +GITHUB_COMMENT_REPORTER: false +DISABLE: + - RUST + - JAVASCRIPT + - PYTHON +DISABLE_LINTERS: + - SPELL_CSPELL + - CSS_STYLELINT +DISABLE_ERRORS_LINTERS: + - COPYPASTE_JSCPD + - REPOSITORY_TRIVY + - REPOSITORY_CHECKOV + - REPOSITORY_DEVSKIM + - ACTION_ACTIONLINT + - BASH_SHELLCHECK + - C_CPPLINT + - CPP_CPPLINT + - DOCKERFILE_HADOLINT + - HTML_DJLINT + - HTML_HTMLHINT + - JAVA_CHECKSTYLE + - JAVA_PMD + - JSON_JSONLINT + - MAKEFILE_CHECKMAKE + - MARKDOWN_MARKDOWN_LINK_CHECK + - PHP_PHPCS + - PHP_PHPSTAN + - PHP_PSALM + - SPELL_MISSPELL + - SQL_TSQLLINT + - YAML_V8R diff --git a/book/src/contributing/development.md b/book/src/contributing/development.md index 2f482a58f65d..1d8e6666c362 100644 --- a/book/src/contributing/development.md +++ b/book/src/contributing/development.md @@ -253,6 +253,9 @@ Our tests, from the bottom of the pyramid to the top: on GitHub on every commit; any changes they make are added onto the branch automatically in an additional commit. + - Checking by [MegaLinter](https://megalinter.io/latest/), which includes more + Linters, is also done automatically on GitHub. (experimental) + - **Unit tests & inline insta snapshots** — we rely on unit tests to rapidly check that our code basically works. We extensively use [Insta](https://insta.rs/), a snapshot testing tool which writes out the From 42112a5a760e839d93a5fc2c605c221b9b898d74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alja=C5=BE=20Mur=20Er=C5=BEen?= Date: Wed, 1 Mar 2023 14:16:59 +0100 Subject: [PATCH 075/106] feat: error code (#1993) --- prql-compiler/src/error.rs | 23 ++++++++++++++++++-- prql-compiler/src/lib.rs | 2 ++ prql-compiler/src/parser/mod.rs | 1 + prql-compiler/src/semantic/lowering.rs | 3 ++- prql-compiler/src/test.rs | 28 ++++++++++++++++++++----- prql-compiler/src/utils/only.rs | 29 ++++++++++---------------- prql-js/package.json | 2 +- prql-js/tests/test_all.js | 24 +++++++++++++++++++++ 8 files changed, 85 insertions(+), 27 deletions(-) diff --git a/prql-compiler/src/error.rs b/prql-compiler/src/error.rs index 7861baeab3fd..e823777afa4d 100644 --- a/prql-compiler/src/error.rs +++ b/prql-compiler/src/error.rs @@ -17,6 +17,7 @@ pub struct Error { pub span: Option, pub reason: Reason, pub help: Option, + pub code: Option<&'static str>, } #[derive(Debug, Clone)] @@ -56,6 +57,7 @@ impl Error { span: None, reason, help: None, + code: None, } } @@ -72,10 +74,17 @@ impl Error { self.span = span; self } + + pub fn with_code(mut self, code: &'static str) -> Self { + self.code = Some(code); + self + } } #[derive(Debug, Clone, Serialize)] pub struct ErrorMessage { + /// Plain text of the error + pub code: Option, /// Plain text of the error pub reason: String, /// A list of suggestions of how to fix the error @@ -100,7 +109,11 @@ impl Display for ErrorMessage { .join("\n"); f.write_str(&message_without_trailing_spaces)?; } else { - f.write_str(&self.reason)?; + let code = (self.code.as_ref()) + .map(|c| format!("[{c}] ")) + .unwrap_or_default(); + + writeln!(f, "{}Error: {}", code, &self.reason)?; } Ok(()) } @@ -148,6 +161,7 @@ impl Display for ErrorMessages { } pub fn downcast(error: anyhow::Error) -> ErrorMessages { + let mut code = None; let mut span = None; let mut hint = None; @@ -171,6 +185,7 @@ pub fn downcast(error: anyhow::Error) -> ErrorMessages { let reason = match error.downcast::() { Ok(error) => { + code = error.code.map(|x| x.to_string()); span = error.span; hint = error.help; @@ -183,6 +198,7 @@ pub fn downcast(error: anyhow::Error) -> ErrorMessages { }; ErrorMessage { + code, reason, hint, span, @@ -227,9 +243,12 @@ impl ErrorMessage { let mut report = Report::build(ReportKind::Error, source_id, span.start) .with_config(config) - .with_message("") .with_label(Label::new((source_id, span)).with_message(&self.reason)); + if let Some(code) = &self.code { + report = report.with_code(code); + } + if let Some(hint) = &self.hint { report.set_help(hint); } diff --git a/prql-compiler/src/lib.rs b/prql-compiler/src/lib.rs index 7107f45baaa6..4e5c2557db7f 100644 --- a/prql-compiler/src/lib.rs +++ b/prql-compiler/src/lib.rs @@ -297,6 +297,7 @@ mod tests { namespace: "target", }, help: None, + code: None, }, ) "###); @@ -310,6 +311,7 @@ mod tests { namespace: "target", }, help: None, + code: None, }, ) "###); diff --git a/prql-compiler/src/parser/mod.rs b/prql-compiler/src/parser/mod.rs index ab2e6320c209..60de65d6c7b3 100644 --- a/prql-compiler/src/parser/mod.rs +++ b/prql-compiler/src/parser/mod.rs @@ -2236,6 +2236,7 @@ join s=salaries [==id] found: "’", }, help: None, + code: None, }, ], ) diff --git a/prql-compiler/src/semantic/lowering.rs b/prql-compiler/src/semantic/lowering.rs index 32d1ab558d05..92f36d1c4428 100644 --- a/prql-compiler/src/semantic/lowering.rs +++ b/prql-compiler/src/semantic/lowering.rs @@ -45,7 +45,8 @@ pub fn lower_ast_to_ir(statements: Vec, context: Context) -> Result { fn exactly_one_node(mut self, who: &str, occupation: &str) -> Result { match self.len() { 1 => Ok(self.remove(0)), - 0 => Err(Error { - reason: Reason::Expected { - who: Some(who.to_string()), - expected: format!("only one {occupation}"), - found: "none".to_string(), - }, - span: None, - help: None, - }), - _ => Err(Error { - reason: Reason::Expected { - who: Some(who.to_string()), - expected: format!("only one {occupation}"), - found: "more".to_string(), - }, - span: self[1].span, - help: None, - }), + 0 => Err(Error::new(Reason::Expected { + who: Some(who.to_string()), + expected: format!("only one {occupation}"), + found: "none".to_string(), + })), + _ => Err(Error::new(Reason::Expected { + who: Some(who.to_string()), + expected: format!("only one {occupation}"), + found: "more".to_string(), + }) + .with_span(self[1].span)), } } } diff --git a/prql-js/package.json b/prql-js/package.json index 06e58721e5ed..9e25e8fed74f 100644 --- a/prql-js/package.json +++ b/prql-js/package.json @@ -21,7 +21,7 @@ "build:bundler": "wasm-pack build --target bundler --release --out-dir dist/bundler && rm dist/bundler/.gitignore", "build:node": "wasm-pack build --target nodejs --release --out-dir dist/node && rm dist/node/.gitignore", "build:web": "wasm-pack build --target no-modules --release --out-dir dist/web && rm dist/web/.gitignore", - "test": "wasm-pack test --firefox && mocha tests" + "test": "mocha tests" }, "types": "dist/node/prql_js.d.ts", "version": "0.5.2" diff --git a/prql-js/tests/test_all.js b/prql-js/tests/test_all.js index 7732e2c1e090..57cc9d5a781c 100644 --- a/prql-js/tests/test_all.js +++ b/prql-js/tests/test_all.js @@ -100,4 +100,28 @@ describe("prql-js", () => { assert(targets.includes("sql.sqlite")); }); }); + + describe("compile error", () => { + it("should contain json", () => { + try { + prql.compile("from x | select a | select b"); + } catch (error) { + const errorMessages = JSON.parse(error.message).inner; + + assert(errorMessages.length > 0); + assert(errorMessages[0].display.includes("\n")); + assert(!errorMessages[0].reason.includes("\n")); + } + }); + + it("should contain error code", () => { + try { + prql.compile("let a = (from x)"); + } catch (error) { + const errorMessages = JSON.parse(error.message).inner; + + assert(errorMessages[0].code == "E0001"); + } + }); + }); }); From e835c28748f7633e774ee5a1060ab87fe67bb1b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alja=C5=BE=20Mur=20Er=C5=BEen?= Date: Wed, 1 Mar 2023 16:17:17 +0100 Subject: [PATCH 076/106] feat: validate Options.target and allow sql.any (#1995) --- prql-compiler/src/lib.rs | 38 +++++++++++---------- prql-compiler/src/test.rs | 9 ++++- prql-js/src/lib.rs | 7 ++-- prql-js/tests/test_all.js | 2 +- prql-lib/libprql_lib.h | 3 ++ prql-lib/src/lib.rs | 45 ++++++++++++++++--------- prql-python/python/tests/test_all.py | 22 ++++++++----- prql-python/src/lib.rs | 49 ++++++++++++++-------------- 8 files changed, 102 insertions(+), 73 deletions(-) diff --git a/prql-compiler/src/lib.rs b/prql-compiler/src/lib.rs index 4e5c2557db7f..f88d4f133281 100644 --- a/prql-compiler/src/lib.rs +++ b/prql-compiler/src/lib.rs @@ -142,10 +142,12 @@ impl Default for Target { impl Target { pub fn names() -> Vec { - sql::Dialect::names() - .into_iter() - .map(|d| format!("sql.{d}")) - .collect() + let mut names = vec!["sql.any".to_string()]; + + let dialects = sql::Dialect::names(); + names.extend(dialects.into_iter().map(|d| format!("sql.{d}"))); + + names } } @@ -153,20 +155,20 @@ impl FromStr for Target { type Err = Error; fn from_str(s: &str) -> Result { - // We have a closure here because we can't create the error in the - // pipeline, since it needs to be in two places, and we'd need to clone. - // (Though possibly it's too optimize-y.) - let not_found_error = |s| { - Error::new(Reason::NotFound { - name: format!("{s:?}"), - namespace: "target".to_string(), - }) - }; - s.strip_prefix("sql.") - .ok_or_else(|| not_found_error(s)) - .map(sql::Dialect::from_str)? - .map(|x| Target::Sql(Some(x))) - .map_err(|_| not_found_error(s)) + if let Some(dialect) = s.strip_prefix("sql.") { + if dialect == "any" { + return Ok(Target::Sql(None)); + } + + if let Ok(dialect) = sql::Dialect::from_str(dialect) { + return Ok(Target::Sql(Some(dialect))); + } + } + + Err(Error::new(Reason::NotFound { + name: format!("{s:?}"), + namespace: "target".to_string(), + })) } } diff --git a/prql-compiler/src/test.rs b/prql-compiler/src/test.rs index 8312ff4c775b..b8133c689024 100644 --- a/prql-compiler/src/test.rs +++ b/prql-compiler/src/test.rs @@ -3267,7 +3267,14 @@ fn test_header_target_error() { from a "#).unwrap_err(),@r###" Error: target `"sql.foo"` not found - "###) + "###); + + assert_display_snapshot!(compile(r#" + prql target:foo.bar + from a + "#).unwrap_err(),@r###" + Error: target `"foo.bar"` not found + "###); } #[test] diff --git a/prql-js/src/lib.rs b/prql-js/src/lib.rs index 2e17e7e48703..6a7a7add9571 100644 --- a/prql-js/src/lib.rs +++ b/prql-js/src/lib.rs @@ -53,9 +53,6 @@ pub struct CompileOptions { /// Defaults to true. pub format: bool, - /// Target to compile to (e.g. sql.postgres) - /// - /// If `None` is used, the `target` argument from the query header is used. #[wasm_bindgen(skip)] pub target: String, @@ -90,6 +87,10 @@ impl CompileOptions { Self::default() } + /// Target to compile to (e.g. sql.postgres) + /// + /// Defaults to `sql.any`, which uses `target` argument from the query header to determine + /// the SQL dialect. #[wasm_bindgen(getter)] pub fn target(&self) -> String { self.target.clone() diff --git a/prql-js/tests/test_all.js b/prql-js/tests/test_all.js index 57cc9d5a781c..5fb0b8a5256f 100644 --- a/prql-js/tests/test_all.js +++ b/prql-js/tests/test_all.js @@ -86,7 +86,7 @@ describe("prql-js", () => { it("should fallback to the target in header", () => { const opts = new prql.CompileOptions(); - opts.target = "sql.not_existing"; + opts.target = "sql.any"; const res = prql.compile("prql target:sql.mssql\nfrom a | take 1", opts); assert(res.includes("TOP (1)")); diff --git a/prql-lib/libprql_lib.h b/prql-lib/libprql_lib.h index e605d46b9987..7e9ca050049c 100644 --- a/prql-lib/libprql_lib.h +++ b/prql-lib/libprql_lib.h @@ -16,6 +16,9 @@ typedef struct Options { bool format; /** * Target and dialect to compile to. + * + * Defaults to `sql.any`, which uses `target` argument from the query header to determine + * the SQL dialect. */ char *target; /** diff --git a/prql-lib/src/lib.rs b/prql-lib/src/lib.rs index ef00c96d5ccd..7c7e39f5eef8 100644 --- a/prql-lib/src/lib.rs +++ b/prql-lib/src/lib.rs @@ -27,11 +27,14 @@ pub unsafe extern "C" fn compile( ) -> c_int { let prql_query: String = c_str_to_string(prql_query); - let result = Ok(prql_query.as_str()) - .and_then(prql_compiler::prql_to_pl) - .and_then(prql_compiler::pl_to_rq) - .and_then(|rq| { - prql_compiler::rq_to_sql(rq, &options.as_ref().map(|o| o.into()).unwrap_or_default()) + let options = options.as_ref().map(convert_options).transpose(); + + let result = options + .and_then(|opts| { + Ok(prql_query.as_str()) + .and_then(prql_compiler::prql_to_pl) + .and_then(prql_compiler::pl_to_rq) + .and_then(|rq| prql_compiler::rq_to_sql(rq, &opts.unwrap_or_default())) }) .map_err(|e| e.composed("", &prql_query, false)); @@ -110,6 +113,9 @@ pub struct Options { pub format: bool, /// Target and dialect to compile to. + /// + /// Defaults to `sql.any`, which uses `target` argument from the query header to determine + /// the SQL dialect. pub target: *mut c_char, /// Emits the compiler signature as a comment after generated SQL @@ -142,15 +148,22 @@ unsafe fn c_str_to_string(c_str: *const c_char) -> String { CStr::from_ptr(c_str).to_string_lossy().into_owned() } -impl From<&Options> for prql_compiler::Options { - fn from(o: &Options) -> Self { - let target = unsafe { c_str_to_string(o.target) }; - let target = Target::from_str(&target).unwrap_or_default(); - - prql_compiler::Options { - format: o.format, - target, - signature_comment: o.signature_comment, - } - } +fn convert_options(o: &Options) -> Result { + let target = if o.target.is_null() { + Some(unsafe { c_str_to_string(o.target) }) + } else { + None + }; + let target = target + .as_deref() + .filter(|x| !x.is_empty()) + .unwrap_or("sql.any"); + + let target = Target::from_str(target).map_err(|e| prql_compiler::downcast(e.into()))?; + + Ok(prql_compiler::Options { + format: o.format, + target, + signature_comment: o.signature_comment, + }) } diff --git a/prql-python/python/tests/test_all.py b/prql-python/python/tests/test_all.py index a1a364f0a840..481f9055cae2 100644 --- a/prql-python/python/tests/test_all.py +++ b/prql-python/python/tests/test_all.py @@ -49,24 +49,28 @@ def test_compile_options(): """ query_mssql = "prql target:sql.mssql\nfrom a | take 3" + assert prql.compile(query_mssql).startswith("SELECT\n TOP (3) *\nFROM\n a") + options_with_known_target = prql.CompileOptions( format=False, signature_comment=False, target="sql.sqlite" ) - options_without_target = prql.CompileOptions(format=False, signature_comment=False) - options_with_unknown_target = prql.CompileOptions( - format=False, signature_comment=False, target="foo" - ) - - assert prql.compile(query_mssql).startswith("SELECT\n TOP (3) *\nFROM\n a") assert ( prql.compile(query_mssql, options_with_known_target) == "SELECT * FROM a LIMIT 3" ) + + options_without_target = prql.CompileOptions(format=False, signature_comment=False) assert ( prql.compile(query_mssql, options_without_target) == "SELECT TOP (3) * FROM a" ) - # TODO: This should be unknown target error? + + options_with_any_target = prql.CompileOptions( + format=False, signature_comment=False, target="sql.any" + ) assert ( - prql.compile(query_mssql, options_with_unknown_target) - == "SELECT TOP (3) * FROM a" + prql.compile(query_mssql, options_with_any_target) == "SELECT TOP (3) * FROM a" ) + + options_default = prql.CompileOptions() + res = prql.compile(query_mssql, options_default) + assert res.startswith("SELECT\n TOP (3)") diff --git a/prql-python/src/lib.rs b/prql-python/src/lib.rs index 6beebe154a69..332afdcd6df4 100644 --- a/prql-python/src/lib.rs +++ b/prql-python/src/lib.rs @@ -6,10 +6,15 @@ use pyo3::{exceptions, prelude::*}; #[pyfunction] pub fn compile(prql_query: &str, options: Option) -> PyResult { - Ok(prql_query) - .and_then(prql_compiler::prql_to_pl) - .and_then(prql_compiler::pl_to_rq) - .and_then(|rq| prql_compiler::rq_to_sql(rq, &options.map(|o| o.into()).unwrap_or_default())) + let options = options.map(convert_options).transpose(); + + options + .and_then(|opts| { + Ok(prql_query) + .and_then(prql_compiler::prql_to_pl) + .and_then(prql_compiler::pl_to_rq) + .and_then(|rq| prql_compiler::rq_to_sql(rq, &opts.unwrap_or_default())) + }) .map_err(|e| e.composed("", prql_query, false)) .map_err(|e| (PyErr::new::(e.to_string()))) } @@ -63,16 +68,10 @@ pub struct CompileOptions { /// Defaults to true. pub format: bool, - /// Target dialect to compile to. - /// - /// This is only changes the output for a relatively small subset of - /// features. + /// Target to compile to. /// - /// If something does not work in a specific dialect, please raise in a - /// GitHub issue. - /// - /// If `None` is used, the `target` argument from the query header is used. - /// If it does not exist, [Dialect::Generic] is used. + /// Defaults to "sql.any", which uses the `target` argument from the query + /// header to determine The SQL dialect. pub target: String, /// Emits the compiler signature as a comment after generated SQL @@ -84,8 +83,8 @@ pub struct CompileOptions { #[pymethods] impl CompileOptions { #[new] - pub fn new(format: bool, signature_comment: bool, target: Option) -> Self { - let target = target.unwrap_or_default(); + #[pyo3(signature = (*, format=true, signature_comment=true, target="sql.any".to_string()))] + pub fn new(format: bool, signature_comment: bool, target: String) -> Self { CompileOptions { format, target, @@ -94,16 +93,16 @@ impl CompileOptions { } } -impl From for prql_compiler::Options { - fn from(o: CompileOptions) -> Self { - let target = Target::from_str(&o.target).unwrap_or_default(); +fn convert_options( + o: CompileOptions, +) -> Result { + let target = Target::from_str(&o.target).map_err(|e| prql_compiler::downcast(e.into()))?; - prql_compiler::Options { - format: o.format, - target, - signature_comment: o.signature_comment, - } - } + Ok(prql_compiler::Options { + format: o.format, + target, + signature_comment: o.signature_comment, + }) } #[pyfunction] @@ -121,7 +120,7 @@ mod test { fn parse_for_python() { let opts = Some(CompileOptions { format: true, - target: String::new(), + target: "sql.any".to_string(), signature_comment: false, }); From 3fdb0c10e3aa2e824ef67b1b0c1b2b8ae330762f Mon Sep 17 00:00:00 2001 From: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Date: Wed, 1 Mar 2023 22:56:16 -0800 Subject: [PATCH 077/106] test: Fix Elixir test from #1995 (#1999) --- prql-elixir/test/prql_test.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prql-elixir/test/prql_test.exs b/prql-elixir/test/prql_test.exs index 9053244598ce..bb7648b371a1 100644 --- a/prql-elixir/test/prql_test.exs +++ b/prql-elixir/test/prql_test.exs @@ -16,7 +16,7 @@ defmodule PRQLTest do test "return errors on invalid query" do excepted_result = - "{\"inner\":[{\"reason\":\"Unknown name invalid\",\"hint\":null,\"span\":{\"start\":0,\"end\":7},\"display\":\"Error: \\n ╭─[:1:1]\\n │\\n 1 │ invalid\\n · ───┬─── \\n · ╰───── Unknown name invalid\\n───╯\\n\",\"location\":{\"start\":[0,0],\"end\":[0,7]}}]}" + "{\"inner\":[{\"code\":null,\"reason\":\"Unknown name invalid\",\"hint\":null,\"span\":{\"start\":0,\"end\":7},\"display\":\"Error: \\n ╭─[:1:1]\\n │\\n 1 │ invalid\\n · ───┬─── \\n · ╰───── Unknown name invalid\\n───╯\\n\",\"location\":{\"start\":[0,0],\"end\":[0,7]}}]}" assert PRQL.compile("invalid", @compile_opts) == {:error, excepted_result} end From 7e8094f5b6d28e65aac4d7ee1ae73f191a141c39 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 2 Mar 2023 10:07:51 -0800 Subject: [PATCH 078/106] chore: bump @duckdb/duckdb-wasm from 1.21.0 to 1.24.0 in /playground (#2000) Bumps [@duckdb/duckdb-wasm](https://github.com/duckdb/duckdb-wasm) from 1.21.0 to 1.24.0. - [Release notes](https://github.com/duckdb/duckdb-wasm/releases) - [Commits](https://github.com/duckdb/duckdb-wasm/compare/v1.21.0...v1.24.0) --- updated-dependencies: - dependency-name: "@duckdb/duckdb-wasm" dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- playground/package-lock.json | 46 ++++++++++++++++++------------------ playground/package.json | 2 +- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/playground/package-lock.json b/playground/package-lock.json index 3e8d7dd2ad9b..3cae1d7b48db 100644 --- a/playground/package-lock.json +++ b/playground/package-lock.json @@ -9,7 +9,7 @@ "version": "0.1.0", "hasInstallScript": true, "dependencies": { - "@duckdb/duckdb-wasm": "^1.21.0", + "@duckdb/duckdb-wasm": "^1.24.0", "@monaco-editor/react": "^4.4.6", "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^14.0.0", @@ -2281,11 +2281,11 @@ } }, "node_modules/@duckdb/duckdb-wasm": { - "version": "1.21.0", - "resolved": "https://registry.npmjs.org/@duckdb/duckdb-wasm/-/duckdb-wasm-1.21.0.tgz", - "integrity": "sha512-3HBqwAhkjGWUGY2zSk2YG9i6bjNeTO5tyhBTJC9asv4ChTjx4mY6j4PFpAgUNomLm+QEFx1XXZN/BjRfENLdZQ==", + "version": "1.24.0", + "resolved": "https://registry.npmjs.org/@duckdb/duckdb-wasm/-/duckdb-wasm-1.24.0.tgz", + "integrity": "sha512-ow3y5kNV5saNd9dK1PkoKq7I0yqOJsnuRA15p92/gIl37wsNq/hI1R5m1HBe02CAEBQPi14w7+EV9xzvduSfZA==", "dependencies": { - "apache-arrow": "^9.0.0" + "apache-arrow": "^11.0.0" } }, "node_modules/@eslint/eslintrc": { @@ -5056,14 +5056,14 @@ } }, "node_modules/apache-arrow": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/apache-arrow/-/apache-arrow-9.0.0.tgz", - "integrity": "sha512-Myt0vtm7eRtg4dYQp1hb2A77jbPhCYZcPeNp1F0u7te3rWQtcDI3EOSLxToFywdLQ1hfPzhzdLfDL0tPQObJjw==", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/apache-arrow/-/apache-arrow-11.0.0.tgz", + "integrity": "sha512-M8J4y+DimIyS44w2KOmVfzNHbTroR1oDpBKK6BYnlu8xVB41lxTz0yLmapo8/WJVAt5XcinAxMm14M771dm/rA==", "dependencies": { "@types/command-line-args": "5.2.0", "@types/command-line-usage": "5.0.2", "@types/flatbuffers": "*", - "@types/node": "^17.0.36", + "@types/node": "18.7.23", "@types/pad-left": "2.1.1", "command-line-args": "5.2.1", "command-line-usage": "6.1.3", @@ -5077,9 +5077,9 @@ } }, "node_modules/apache-arrow/node_modules/@types/node": { - "version": "17.0.45", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz", - "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==" + "version": "18.7.23", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.23.tgz", + "integrity": "sha512-DWNcCHolDq0ZKGizjx2DZjR/PqsYwAcYUJmfMWqtVU2MBMG5Mo+xFZrhGId5r/O5HOuMPyQEcM6KUBp5lBZZBg==" }, "node_modules/arg": { "version": "5.0.2", @@ -19376,11 +19376,11 @@ "requires": {} }, "@duckdb/duckdb-wasm": { - "version": "1.21.0", - "resolved": "https://registry.npmjs.org/@duckdb/duckdb-wasm/-/duckdb-wasm-1.21.0.tgz", - "integrity": "sha512-3HBqwAhkjGWUGY2zSk2YG9i6bjNeTO5tyhBTJC9asv4ChTjx4mY6j4PFpAgUNomLm+QEFx1XXZN/BjRfENLdZQ==", + "version": "1.24.0", + "resolved": "https://registry.npmjs.org/@duckdb/duckdb-wasm/-/duckdb-wasm-1.24.0.tgz", + "integrity": "sha512-ow3y5kNV5saNd9dK1PkoKq7I0yqOJsnuRA15p92/gIl37wsNq/hI1R5m1HBe02CAEBQPi14w7+EV9xzvduSfZA==", "requires": { - "apache-arrow": "^9.0.0" + "apache-arrow": "^11.0.0" } }, "@eslint/eslintrc": { @@ -21525,14 +21525,14 @@ } }, "apache-arrow": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/apache-arrow/-/apache-arrow-9.0.0.tgz", - "integrity": "sha512-Myt0vtm7eRtg4dYQp1hb2A77jbPhCYZcPeNp1F0u7te3rWQtcDI3EOSLxToFywdLQ1hfPzhzdLfDL0tPQObJjw==", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/apache-arrow/-/apache-arrow-11.0.0.tgz", + "integrity": "sha512-M8J4y+DimIyS44w2KOmVfzNHbTroR1oDpBKK6BYnlu8xVB41lxTz0yLmapo8/WJVAt5XcinAxMm14M771dm/rA==", "requires": { "@types/command-line-args": "5.2.0", "@types/command-line-usage": "5.0.2", "@types/flatbuffers": "*", - "@types/node": "^17.0.36", + "@types/node": "18.7.23", "@types/pad-left": "2.1.1", "command-line-args": "5.2.1", "command-line-usage": "6.1.3", @@ -21543,9 +21543,9 @@ }, "dependencies": { "@types/node": { - "version": "17.0.45", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz", - "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==" + "version": "18.7.23", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.23.tgz", + "integrity": "sha512-DWNcCHolDq0ZKGizjx2DZjR/PqsYwAcYUJmfMWqtVU2MBMG5Mo+xFZrhGId5r/O5HOuMPyQEcM6KUBp5lBZZBg==" } } }, diff --git a/playground/package.json b/playground/package.json index 1de1b6c79627..379af98d2616 100644 --- a/playground/package.json +++ b/playground/package.json @@ -12,7 +12,7 @@ ] }, "dependencies": { - "@duckdb/duckdb-wasm": "^1.21.0", + "@duckdb/duckdb-wasm": "^1.24.0", "@monaco-editor/react": "^4.4.6", "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^14.0.0", From db7b517972e68b673d9a3eea9b9b4c75180656d9 Mon Sep 17 00:00:00 2001 From: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Date: Thu, 2 Mar 2023 20:25:33 -0800 Subject: [PATCH 079/106] fix: Allow unicode in identifiers (#2005) * fix: Allow unicode in identifiers Closes #2003. Thanks to @vanillajonathan for the report. --- CHANGELOG.md | 1 + prql-compiler/src/parser/lexer.rs | 6 ++---- prql-compiler/src/parser/mod.rs | 16 ++++++++++++++++ 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 466005ed691d..5672e83a7623 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ - `prqlc compile` returns a non-zero exit code for invalid queries. (@max-sixty, #1924) +- Identifiers can contain any alphabetic unicode characters (@max-sixty, #2003) **Documentation**: diff --git a/prql-compiler/src/parser/lexer.rs b/prql-compiler/src/parser/lexer.rs index 7874aced3c19..3b5e684dff12 100644 --- a/prql-compiler/src/parser/lexer.rs +++ b/prql-compiler/src/parser/lexer.rs @@ -115,11 +115,9 @@ pub fn lexer() -> impl Parser)>, Error } pub fn ident_part() -> impl Parser> { - let plain = filter(|c: &char| c.is_ascii_alphabetic() || *c == '_') + let plain = filter(|c: &char| c.is_alphabetic() || *c == '_') .map(Some) - .chain::, _>( - filter(|c: &char| c.is_ascii_alphanumeric() || *c == '_').repeated(), - ) + .chain::, _>(filter(|c: &char| c.is_alphanumeric() || *c == '_').repeated()) .collect(); let backticks = just('`') diff --git a/prql-compiler/src/parser/mod.rs b/prql-compiler/src/parser/mod.rs index 60de65d6c7b3..12c6227a8368 100644 --- a/prql-compiler/src/parser/mod.rs +++ b/prql-compiler/src/parser/mod.rs @@ -2213,6 +2213,22 @@ join s=salaries [==id] "###); } + #[test] + fn test_unicode() { + let source = "from tète"; + assert_yaml_snapshot!(parse(source).unwrap(), @r###" + --- + - Main: + FuncCall: + name: + Ident: + - from + args: + - Ident: + - tète + "###); + } + #[test] fn test_error_unicode_string() { // Test various unicode strings successfully parse errors. We were From 5aa13a52468a28ecaf8faef71b430dbfcd9c1416 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alja=C5=BE=20Mur=20Er=C5=BEen?= Date: Fri, 3 Mar 2023 14:51:23 +0100 Subject: [PATCH 080/106] test: convert a few unit tests to integration (#2006) --- prql-compiler/src/error.rs | 8 +- prql-compiler/src/sql/dialect.rs | 9 ++ prql-compiler/src/sql/gen_expr.rs | 18 ++- prql-compiler/src/sql/gen_projection.rs | 52 ++++----- prql-compiler/src/sql/gen_query.rs | 2 + prql-compiler/src/sql/mod.rs | 3 + prql-compiler/src/test.rs | 54 ++------- prql-compiler/tests/integration/main.rs | 15 ++- .../tests/integration/queries/distinct.prql | 4 + .../tests/integration/queries/group_all.prql | 5 + .../tests/integration/queries/pipelines.prql | 4 + .../tests/integration/queries/switch.prql | 8 ++ ...ntegration__tests__test@distinct.prql.snap | 106 ++++++++++++++++++ ...tegration__tests__test@group_all.prql.snap | 16 +++ ...tegration__tests__test@pipelines.prql.snap | 12 ++ .../integration__tests__test@switch.prql.snap | 16 +++ 16 files changed, 256 insertions(+), 76 deletions(-) create mode 100644 prql-compiler/tests/integration/queries/distinct.prql create mode 100644 prql-compiler/tests/integration/queries/group_all.prql create mode 100644 prql-compiler/tests/integration/queries/pipelines.prql create mode 100644 prql-compiler/tests/integration/queries/switch.prql create mode 100644 prql-compiler/tests/integration/snapshots/integration__tests__test@distinct.prql.snap create mode 100644 prql-compiler/tests/integration/snapshots/integration__tests__test@group_all.prql.snap create mode 100644 prql-compiler/tests/integration/snapshots/integration__tests__test@pipelines.prql.snap create mode 100644 prql-compiler/tests/integration/snapshots/integration__tests__test@switch.prql.snap diff --git a/prql-compiler/src/error.rs b/prql-compiler/src/error.rs index e823777afa4d..5ba0ece52685 100644 --- a/prql-compiler/src/error.rs +++ b/prql-compiler/src/error.rs @@ -81,7 +81,7 @@ impl Error { } } -#[derive(Debug, Clone, Serialize)] +#[derive(Clone, Serialize)] pub struct ErrorMessage { /// Plain text of the error pub code: Option, @@ -119,6 +119,12 @@ impl Display for ErrorMessage { } } +impl Debug for ErrorMessage { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + Display::fmt(&self, f) + } +} + // Needed for anyhow impl StdError for Error {} diff --git a/prql-compiler/src/sql/dialect.rs b/prql-compiler/src/sql/dialect.rs index 18a74ef5e729..64bbeb08e766 100644 --- a/prql-compiler/src/sql/dialect.rs +++ b/prql-compiler/src/sql/dialect.rs @@ -154,6 +154,11 @@ pub(super) trait DialectHandler: Any { fn requires_quotes_intervals(&self) -> bool { false } + + /// Support for GROUP BY * + fn stars_in_group(&self) -> bool { + true + } } impl dyn DialectHandler { @@ -183,6 +188,10 @@ impl DialectHandler for SQLiteDialect { fn has_concat_function(&self) -> bool { false } + + fn stars_in_group(&self) -> bool { + false + } } impl DialectHandler for MsSqlDialect { diff --git a/prql-compiler/src/sql/gen_expr.rs b/prql-compiler/src/sql/gen_expr.rs index 2a6ed8aed55a..a1e90216c005 100644 --- a/prql-compiler/src/sql/gen_expr.rs +++ b/prql-compiler/src/sql/gen_expr.rs @@ -260,7 +260,7 @@ pub(super) fn translate_cid(cid: CId, ctx: &mut Context) -> Result { let column = match col.clone() { - RelationColumn::Wildcard => "*".to_string(), + RelationColumn::Wildcard => translate_star(ctx, None)?, RelationColumn::Single(name) => name.unwrap(), }; let t = &ctx.anchor.table_instances[tiid]; @@ -281,7 +281,9 @@ pub(super) fn translate_cid(cid: CId, ctx: &mut Context) -> Result "*".to_string(), + ColumnDecl::RelationColumn(_, _, RelationColumn::Wildcard) => { + translate_star(ctx, None)? + } _ => { let name = ctx.anchor.column_names.get(&cid).cloned(); @@ -298,6 +300,18 @@ pub(super) fn translate_cid(cid: CId, ctx: &mut Context) -> Result) -> Result { + if ctx.query.forbid_stars { + Err( + Error::new_simple("Target dialect does not support * in this position.") + .with_span(span) + .into(), + ) + } else { + Ok("*".to_string()) + } +} + pub(super) fn translate_sstring( items: Vec>, ctx: &mut Context, diff --git a/prql-compiler/src/sql/gen_projection.rs b/prql-compiler/src/sql/gen_projection.rs index 5d2504fb33da..8b7bb862dfca 100644 --- a/prql-compiler/src/sql/gen_projection.rs +++ b/prql-compiler/src/sql/gen_projection.rs @@ -23,33 +23,35 @@ pub(super) fn try_into_exprs( ) -> Result> { let (cids, excluded) = translate_wildcards(&ctx.anchor, cids); - cids.into_iter() - .map(|cid| { - let decl = ctx.anchor.column_decls.get(&cid).unwrap(); - - let ColumnDecl::RelationColumn(tiid, _, RelationColumn::Wildcard) = decl else { - // base case - return translate_cid(cid, ctx) - }; - - // wildcard - let t = &ctx.anchor.table_instances[tiid]; - let table_name = t.name.clone(); - - let ident = translate_ident(table_name, Some("*".to_string()), ctx); - if let Some(excluded) = excluded.get(&cid) { - if !excluded.is_empty() { - return Err(Error::new_simple( - "Excluding columns not supported as this position", - ) - .with_span(span) - .into()); - } + let mut res = Vec::new(); + for cid in cids { + let decl = ctx.anchor.column_decls.get(&cid).unwrap(); + + let ColumnDecl::RelationColumn(tiid, _, RelationColumn::Wildcard) = decl else { + // base case + res.push(translate_cid(cid, ctx)?); + continue; + }; + + // star + let t = &ctx.anchor.table_instances[tiid]; + let table_name = t.name.clone(); + + let ident = translate_star(ctx, span)?; + if let Some(excluded) = excluded.get(&cid) { + if !excluded.is_empty() { + return Err( + Error::new_simple("Excluding columns not supported as this position") + .with_span(span) + .into(), + ); } + } + let ident = translate_ident(table_name, Some(ident), ctx); - Ok(sql_ast::Expr::CompoundIdentifier(ident)) - }) - .try_collect() + res.push(sql_ast::Expr::CompoundIdentifier(ident)); + } + Ok(res) } type Excluded = HashMap>; diff --git a/prql-compiler/src/sql/gen_query.rs b/prql-compiler/src/sql/gen_query.rs index 421ce63d3170..6a8ba10805e5 100644 --- a/prql-compiler/src/sql/gen_query.rs +++ b/prql-compiler/src/sql/gen_query.rs @@ -284,7 +284,9 @@ fn sql_select_query_of_pipeline( .into_iter() .next(); let group_by: Vec = aggregate.map(|(part, _)| part).unwrap_or_default(); + ctx.query.forbid_stars = !ctx.dialect.stars_in_group(); let group_by = try_into_exprs(group_by, ctx, None)?; + ctx.query.forbid_stars = false; ctx.query.pre_projection = false; diff --git a/prql-compiler/src/sql/mod.rs b/prql-compiler/src/sql/mod.rs index 8e3c3da14c36..350d2d1defc1 100644 --- a/prql-compiler/src/sql/mod.rs +++ b/prql-compiler/src/sql/mod.rs @@ -82,6 +82,9 @@ struct QueryOpts { /// When true, queries will contain nested sub-queries instead of WITH CTEs. pub forbid_ctes: bool, + + /// When true, * are not allowed. + pub forbid_stars: bool, } impl Context { diff --git a/prql-compiler/src/test.rs b/prql-compiler/src/test.rs index b8133c689024..e57cc80fe3d5 100644 --- a/prql-compiler/src/test.rs +++ b/prql-compiler/src/test.rs @@ -154,29 +154,6 @@ fn test_precedence() { ); } -#[test] -fn test_pipelines() { - assert_display_snapshot!((compile(r###" - from employees - group dept (take 1) - "###).unwrap()), @r###" - SELECT - DISTINCT * - FROM - employees - "###); - - assert_display_snapshot!((compile(r###" - from employees - select [age | in 5..10] - "###).unwrap()), @r###" - SELECT - age BETWEEN 5 AND 10 - FROM - employees - "###); -} - #[test] fn test_append() { assert_display_snapshot!(compile(r###" @@ -2643,30 +2620,13 @@ fn test_name_shadowing() { fn test_group_all() { assert_display_snapshot!(compile( r###" - from e=employees - take 10 - join salaries [==emp_no] - group [e.*] (aggregate sal = (sum salaries.salary)) - "###).unwrap(), - @r###" - WITH table_1 AS ( - SELECT - * - FROM - employees AS e - LIMIT - 10 - ) - SELECT - table_0.*, - SUM(salaries.salary) AS sal - FROM - table_1 AS table_0 - JOIN salaries ON table_0.emp_no = salaries.emp_no - GROUP BY - table_0.* - "### - ); + prql target:sql.sqlite + + from a=albums + group a.* (aggregate count) + "###).unwrap_err(), @r###" + Error: Target dialect does not support * in this position. + "###); assert_display_snapshot!(compile( r###" diff --git a/prql-compiler/tests/integration/main.rs b/prql-compiler/tests/integration/main.rs index 484e05bc124d..6ead5ffe1ded 100644 --- a/prql-compiler/tests/integration/main.rs +++ b/prql-compiler/tests/integration/main.rs @@ -86,7 +86,13 @@ mod tests { } pub fn query_csv(conn: &Connection, sql: &str) -> String { - let mut statement = conn.prepare(sql).unwrap(); + let mut statement = conn + .prepare(sql) + .map_err(|e| { + println!("{e}"); + e + }) + .unwrap(); let csv_header = statement.column_names().join(","); let column_count = statement.column_count(); @@ -173,6 +179,13 @@ mod tests { let dt = DateTime::::column_result(value).unwrap(); dt.format("%Y-%m-%d %H:%M:%S").to_string() } + ValueRef::Boolean(b) => { + if b { + "1".to_string() + } else { + "0".to_string() + } + } t => unimplemented!("{t:?}"), } }) diff --git a/prql-compiler/tests/integration/queries/distinct.prql b/prql-compiler/tests/integration/queries/distinct.prql new file mode 100644 index 000000000000..593d4fdea3de --- /dev/null +++ b/prql-compiler/tests/integration/queries/distinct.prql @@ -0,0 +1,4 @@ +from tracks +select [album_id, genre_id] +group tracks.* (take 1) +sort tracks.* diff --git a/prql-compiler/tests/integration/queries/group_all.prql b/prql-compiler/tests/integration/queries/group_all.prql new file mode 100644 index 000000000000..a5a73e1c98ae --- /dev/null +++ b/prql-compiler/tests/integration/queries/group_all.prql @@ -0,0 +1,5 @@ +from a=albums +sort album_id +take 10 +join tracks [==album_id] +group [a.album_id, a.title] (aggregate price = (sum tracks.unit_price)) diff --git a/prql-compiler/tests/integration/queries/pipelines.prql b/prql-compiler/tests/integration/queries/pipelines.prql new file mode 100644 index 000000000000..2b3c6c6cf64a --- /dev/null +++ b/prql-compiler/tests/integration/queries/pipelines.prql @@ -0,0 +1,4 @@ +from tracks +sort track_id +take 20..25 +select [is_in_range = album_id | in 5..10] diff --git a/prql-compiler/tests/integration/queries/switch.prql b/prql-compiler/tests/integration/queries/switch.prql new file mode 100644 index 000000000000..19497776665a --- /dev/null +++ b/prql-compiler/tests/integration/queries/switch.prql @@ -0,0 +1,8 @@ +from tracks +sort milliseconds +select display = switch [ + composer != null -> composer, + genre_id < 17 -> 'no composer', + true -> f'unknown composer' +] +take 10 diff --git a/prql-compiler/tests/integration/snapshots/integration__tests__test@distinct.prql.snap b/prql-compiler/tests/integration/snapshots/integration__tests__test@distinct.prql.snap new file mode 100644 index 000000000000..765cba4ceca1 --- /dev/null +++ b/prql-compiler/tests/integration/snapshots/integration__tests__test@distinct.prql.snap @@ -0,0 +1,106 @@ +--- +source: prql-compiler/tests/integration/main.rs +expression: sqlite_out +input_file: prql-compiler/tests/integration/queries/distinct.prql +--- +album_id,genre_id +1,1 +2,1 +3,1 +4,1 +5,1 +6,1 +7,1 +8,2 +9,3 +10,1 +11,4 +12,5 +13,2 +14,3 +15,3 +16,3 +17,3 +18,4 +19,3 +20,6 +21,7 +22,7 +23,7 +24,7 +25,7 +26,8 +27,8 +28,7 +29,9 +30,1 +31,1 +32,10 +33,7 +34,7 +35,3 +36,1 +37,1 +38,2 +39,4 +40,1 +41,7 +42,4 +43,1 +44,1 +45,7 +46,1 +47,7 +48,2 +49,2 +50,1 +51,2 +52,11 +53,7 +54,1 +55,1 +56,7 +57,7 +58,1 +59,1 +60,1 +61,1 +62,1 +63,1 +64,1 +65,1 +66,1 +67,1 +68,2 +69,7 +70,7 +71,7 +72,6 +73,6 +73,7 +74,4 +75,4 +76,1 +77,4 +78,7 +79,1 +80,1 +81,4 +82,1 +83,12 +84,7 +85,10 +86,7 +87,2 +88,3 +89,4 +90,1 +91,1 +92,3 +93,2 +94,1 +95,3 +96,3 +97,1 +98,13 +99,1 diff --git a/prql-compiler/tests/integration/snapshots/integration__tests__test@group_all.prql.snap b/prql-compiler/tests/integration/snapshots/integration__tests__test@group_all.prql.snap new file mode 100644 index 000000000000..1b5c0359f1bb --- /dev/null +++ b/prql-compiler/tests/integration/snapshots/integration__tests__test@group_all.prql.snap @@ -0,0 +1,16 @@ +--- +source: prql-compiler/tests/integration/main.rs +expression: sqlite_out +input_file: prql-compiler/tests/integration/queries/group_all.prql +--- +album_id,title,price +1,For Those About To Rock We Salute You,9.9 +2,Balls to the Wall,0.99 +3,Restless and Wild,2.9699999999999998 +4,Let There Be Rock,7.920000000000001 +5,Big Ones,14.850000000000001 +6,Jagged Little Pill,12.870000000000001 +7,Facelift,11.88 +8,Warner 25 Anos,13.860000000000001 +9,Plays Metallica By Four Cellos,7.920000000000001 +10,Audioslave,13.860000000000001 diff --git a/prql-compiler/tests/integration/snapshots/integration__tests__test@pipelines.prql.snap b/prql-compiler/tests/integration/snapshots/integration__tests__test@pipelines.prql.snap new file mode 100644 index 000000000000..f039b00e19b4 --- /dev/null +++ b/prql-compiler/tests/integration/snapshots/integration__tests__test@pipelines.prql.snap @@ -0,0 +1,12 @@ +--- +source: prql-compiler/tests/integration/main.rs +expression: sqlite_out +input_file: prql-compiler/tests/integration/queries/pipelines.prql +--- +is_in_range,track_id +0,20 +0,21 +0,22 +1,23 +1,24 +1,25 diff --git a/prql-compiler/tests/integration/snapshots/integration__tests__test@switch.prql.snap b/prql-compiler/tests/integration/snapshots/integration__tests__test@switch.prql.snap new file mode 100644 index 000000000000..b53c9cc01eb9 --- /dev/null +++ b/prql-compiler/tests/integration/snapshots/integration__tests__test@switch.prql.snap @@ -0,0 +1,16 @@ +--- +source: prql-compiler/tests/integration/main.rs +expression: sqlite_out +input_file: prql-compiler/tests/integration/queries/switch.prql +--- +display,milliseconds +Samuel Rosa,1071 +no composer,4884 +no composer,6373 +no composer,6635 +L. Muggerud,7941 +no composer,11650 +L. Muggerud,21211 +unknown composer,29048 +Gilberto Gil,32287 +Chico Science,33149 From 0a1e6944cf7a9d458e8bb7670898acfff0bb02ff Mon Sep 17 00:00:00 2001 From: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Date: Fri, 3 Mar 2023 10:43:30 -0800 Subject: [PATCH 081/106] feat: Improve lexer error recovery (#2002) * feat: Improve lexer error recovery Upgrade to Chumsky 0.9.2 and add back recovery --- Cargo.lock | 4 ++-- prql-compiler/src/parser/lexer.rs | 6 ++---- prql-compiler/src/parser/mod.rs | 25 +++++++++++++++++++++++++ prql-compiler/src/test.rs | 14 ++++++++++++++ 4 files changed, 43 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e23cb065dab2..277baa6309a4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -446,9 +446,9 @@ dependencies = [ [[package]] name = "chumsky" -version = "0.9.0" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4d619fba796986dd538d82660b76e0b9756c6e19b2e4d4559ba5a57f9f00810" +checksum = "23170228b96236b5a7299057ac284a321457700bc8c41a4476052f0f4ba5349d" dependencies = [ "hashbrown 0.12.3", "stacker", diff --git a/prql-compiler/src/parser/lexer.rs b/prql-compiler/src/parser/lexer.rs index 3b5e684dff12..2043ea8d9847 100644 --- a/prql-compiler/src/parser/lexer.rs +++ b/prql-compiler/src/parser/lexer.rs @@ -77,10 +77,8 @@ pub fn lexer() -> impl Parser)>, Error literal, keyword, ident, - )); - // TODO: Add this back when https://github.com/zesterer/chumsky/issues/301 - // is fixed. - // .recover_with(skip_then_retry_until([]).skip_start()); + )) + .recover_with(skip_then_retry_until([]).skip_start()); let comment = just('#').then(none_of('\n').repeated()); let comments = comment diff --git a/prql-compiler/src/parser/mod.rs b/prql-compiler/src/parser/mod.rs index 12c6227a8368..f0680198ae66 100644 --- a/prql-compiler/src/parser/mod.rs +++ b/prql-compiler/src/parser/mod.rs @@ -97,6 +97,7 @@ fn convert_parser_error(e: Simple) -> Error { Error::new(Reason::Unexpected { found }) } else { let mut expected = expected; + expected.sort(); let expected = match expected.len() { 1 => expected.remove(0), 2 => expected.join(" or "), @@ -2254,6 +2255,30 @@ join s=salaries [==id] help: None, code: None, }, + Error { + span: Some( + span-chars-35-36, + ), + reason: Unexpected { + found: "’", + }, + help: None, + code: None, + }, + Error { + span: Some( + span-chars-38-39, + ), + reason: Expected { + who: Some( + "identifier", + ), + expected: "* or an identifier", + found: "", + }, + help: None, + code: None, + }, ], ) "###); diff --git a/prql-compiler/src/test.rs b/prql-compiler/src/test.rs index e57cc80fe3d5..093bee57f2f0 100644 --- a/prql-compiler/src/test.rs +++ b/prql-compiler/src/test.rs @@ -2914,6 +2914,20 @@ fn test_errors() { · ┬ · ╰── unexpected ’ ───╯ + Error: + ╭─[:1:36] + │ + 1 │ Mississippi has four S’s and four I’s. + · ┬ + · ╰── unexpected ’ + ───╯ + Error: + ╭─[:1:39] + │ + 1 │ Mississippi has four S’s and four I’s. + · ┬ + · ╰── identifier expected * or an identifier, but found + ───╯ "###); let err = compile( From 9afbd78ce7e48078845d8c5b551102272e4072bc Mon Sep 17 00:00:00 2001 From: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Date: Sat, 4 Mar 2023 10:50:43 -0800 Subject: [PATCH 082/106] feat: Improve error messages on EOI (#2008) * feat: Improve lexer error recovery Upgrade to Chumsky 0.9.2 and add back recovery * feat: Improve error messages on EOI Based on https://github.com/PRQL/prql/pull/2002#discussion_r1124184718 Also simplifies a code block * . --- prql-compiler/src/parser/mod.rs | 24 ++++++++++++------------ prql-compiler/src/test.rs | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/prql-compiler/src/parser/mod.rs b/prql-compiler/src/parser/mod.rs index f0680198ae66..6c2fa9cf09e3 100644 --- a/prql-compiler/src/parser/mod.rs +++ b/prql-compiler/src/parser/mod.rs @@ -72,20 +72,20 @@ fn convert_parser_error(e: Simple) -> Error { .all(|t| matches!(t, None | Some(Token::NewLine))); let expected = e .expected() - .filter(|t| { - if just_whitespace { - true - } else { - !matches!(t, None | Some(Token::NewLine)) - } - }) - .map(|t| match t { - Some(t) => t.to_string(), - None => "end of input".to_string(), + // TODO: could we collapse this into a `filter_map`? (though semantically + // identical) + .filter(|t| just_whitespace || !matches!(t, None | Some(Token::NewLine))) + .map(|t| { + t.clone() + .map(|t| t.to_string()) + .unwrap_or_else(|| "end of input".to_string()) }) .collect_vec(); - let found = e.found().map(|c| c.to_string()).unwrap_or_default(); + let found = e + .found() + .map(|c| c.to_string()) + .unwrap_or_else(|| "end of input".to_owned()); let span = common::into_span(e.span()); @@ -2274,7 +2274,7 @@ join s=salaries [==id] "identifier", ), expected: "* or an identifier", - found: "", + found: "end of input", }, help: None, code: None, diff --git a/prql-compiler/src/test.rs b/prql-compiler/src/test.rs index 093bee57f2f0..350b0b53f30b 100644 --- a/prql-compiler/src/test.rs +++ b/prql-compiler/src/test.rs @@ -2926,7 +2926,7 @@ fn test_errors() { │ 1 │ Mississippi has four S’s and four I’s. · ┬ - · ╰── identifier expected * or an identifier, but found + · ╰── identifier expected * or an identifier, but found end of input ───╯ "###); From 52aa29a5b46e514d4d1fc57c0afd5221fe656783 Mon Sep 17 00:00:00 2001 From: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Date: Sat, 4 Mar 2023 13:55:37 -0800 Subject: [PATCH 083/106] devops: Adjust gitignore so `bacon` works with `insta` (#2011) --- .gitignore | 7 +++++-- bacon.toml | 3 ++- prql-dotnet/.gitignore | 2 ++ 3 files changed, 9 insertions(+), 3 deletions(-) create mode 100644 prql-dotnet/.gitignore diff --git a/.gitignore b/.gitignore index 51c4f04938a9..711ac9dd9583 100644 --- a/.gitignore +++ b/.gitignore @@ -21,5 +21,8 @@ _*.prql .task -prql-dotnet/**/bin -prql-dotnet/**/obj +# These shouldn't be committed, and cause watchers to re-run when they're +# created, which we don't want. That said, if ignoring them causes confusion +# (e.g. folks look at their git status to assess whether there are pending +# snapshots), we can adjust. +**/*.pending-snap diff --git a/bacon.toml b/bacon.toml index 765e2d35ba32..9e9e82362080 100644 --- a/bacon.toml +++ b/bacon.toml @@ -59,6 +59,7 @@ need_stdout = true a = "job:check-all" c = "job:clippy" d = "job:doc-open" -i = "job:initial" +# i for `insta` +i = "job:test-rust-fast" r = "job:run" t = "job:test" diff --git a/prql-dotnet/.gitignore b/prql-dotnet/.gitignore new file mode 100644 index 000000000000..1746e3269ed0 --- /dev/null +++ b/prql-dotnet/.gitignore @@ -0,0 +1,2 @@ +bin +obj From f2a1b884e2e5fbc48cbdbf55bd7327f6858bedba Mon Sep 17 00:00:00 2001 From: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Date: Sat, 4 Mar 2023 14:44:18 -0800 Subject: [PATCH 084/106] feat: Improve error messages for EOI more (#2012) Follow-up to #2008 --- prql-compiler/src/parser/mod.rs | 76 ++++++++++++++++++--------------- prql-compiler/src/test.rs | 2 +- 2 files changed, 43 insertions(+), 35 deletions(-) diff --git a/prql-compiler/src/parser/mod.rs b/prql-compiler/src/parser/mod.rs index 6c2fa9cf09e3..aacc2a30a86b 100644 --- a/prql-compiler/src/parser/mod.rs +++ b/prql-compiler/src/parser/mod.rs @@ -67,14 +67,22 @@ fn convert_lexer_error(source: &str, e: Cheap) -> Error { } fn convert_parser_error(e: Simple) -> Error { - let just_whitespace = e + let span = common::into_span(e.span()); + + if let SimpleReason::Custom(message) = e.reason() { + return Error::new_simple(message).with_span(span); + } + + let is_all_whitespace = e .expected() .all(|t| matches!(t, None | Some(Token::NewLine))); - let expected = e + let expecteds = e .expected() // TODO: could we collapse this into a `filter_map`? (though semantically // identical) - .filter(|t| just_whitespace || !matches!(t, None | Some(Token::NewLine))) + // + // Only include whitespace if we're _only_ expecting whitespace + .filter(|t| is_all_whitespace || !matches!(t, None | Some(Token::NewLine))) .map(|t| { t.clone() .map(|t| t.to_string()) @@ -82,36 +90,40 @@ fn convert_parser_error(e: Simple) -> Error { }) .collect_vec(); - let found = e - .found() - .map(|c| c.to_string()) - .unwrap_or_else(|| "end of input".to_owned()); - - let span = common::into_span(e.span()); - - if let SimpleReason::Custom(message) = e.reason() { - return Error::new_simple(message).with_span(span); - } - - if expected.is_empty() || expected.len() > 10 { - Error::new(Reason::Unexpected { found }) + let expected = if expecteds.is_empty() || expecteds.len() > 10 { + return Error::new(Reason::Unexpected { + found: e + .found() + .map(|c| c.to_string()) + // I think a rare case where we have both no `expected` and no `found`. + // Would be good to know how often this happens; can improve if we are + // hitting it. + .unwrap_or_else(|| "end of input".to_string()), + }); } else { - let mut expected = expected; - expected.sort(); - let expected = match expected.len() { - 1 => expected.remove(0), - 2 => expected.join(" or "), + let mut expecteds = expecteds; + expecteds.sort(); + + match expecteds.len() { + 1 => expecteds.remove(0), + 2 => expecteds.join(" or "), _ => { - let last = expected.pop().unwrap(); - format!("one of {} or {last}", expected.join(", ")) + let last = expecteds.pop().unwrap(); + format!("one of {} or {last}", expecteds.join(", ")) } - }; + } + }; - Error::new(Reason::Expected { + match e.found() { + Some(found) => Error::new(Reason::Expected { who: e.label().map(|x| x.to_string()), expected, - found, - }) + found: found.to_string(), + }), + // We want a friendlier message than "found end of input"... + None => Error::new(Reason::Simple(format!( + "Expected {expected}, but didn't find anything before the end." + ))), } .with_span(span) } @@ -2269,13 +2281,9 @@ join s=salaries [==id] span: Some( span-chars-38-39, ), - reason: Expected { - who: Some( - "identifier", - ), - expected: "* or an identifier", - found: "end of input", - }, + reason: Simple( + "Expected * or an identifier, but didn't find anything before the end.", + ), help: None, code: None, }, diff --git a/prql-compiler/src/test.rs b/prql-compiler/src/test.rs index 350b0b53f30b..d03dead1b9e2 100644 --- a/prql-compiler/src/test.rs +++ b/prql-compiler/src/test.rs @@ -2926,7 +2926,7 @@ fn test_errors() { │ 1 │ Mississippi has four S’s and four I’s. · ┬ - · ╰── identifier expected * or an identifier, but found end of input + · ╰── Expected * or an identifier, but didn't find anything before the end. ───╯ "###); From a07567231bed35562feb6283b648cc2cb17c04d2 Mon Sep 17 00:00:00 2001 From: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Date: Sat, 4 Mar 2023 19:28:42 -0800 Subject: [PATCH 085/106] fix: Fix regression in @2012 (#2013) Demonstrates we don't have enough tests for error messages! (And that I was not conscientious...) --- prql-compiler/src/parser/mod.rs | 23 ++++++++++++++++++++++- prql-compiler/src/test.rs | 10 ++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/prql-compiler/src/parser/mod.rs b/prql-compiler/src/parser/mod.rs index aacc2a30a86b..247a881dbfd9 100644 --- a/prql-compiler/src/parser/mod.rs +++ b/prql-compiler/src/parser/mod.rs @@ -99,7 +99,8 @@ fn convert_parser_error(e: Simple) -> Error { // Would be good to know how often this happens; can improve if we are // hitting it. .unwrap_or_else(|| "end of input".to_string()), - }); + }) + .with_span(span); } else { let mut expecteds = expecteds; expecteds.sort(); @@ -2291,4 +2292,24 @@ join s=salaries [==id] ) "###); } + + #[test] + fn test_error_unexpected() { + assert_debug_snapshot!(parse("Answer: T-H-A-T!").unwrap_err(), @r###" + Errors( + [ + Error { + span: Some( + span-chars-6-7, + ), + reason: Unexpected { + found: ":", + }, + help: None, + code: None, + }, + ], + ) + "###); + } } diff --git a/prql-compiler/src/test.rs b/prql-compiler/src/test.rs index d03dead1b9e2..413fcae6ee06 100644 --- a/prql-compiler/src/test.rs +++ b/prql-compiler/src/test.rs @@ -2937,6 +2937,16 @@ fn test_errors() { ) .unwrap_err(); assert_eq!(err.inner[0].code.as_ref().unwrap(), "E0001"); + + assert_display_snapshot!(compile("Answer: T-H-A-T!").unwrap_err(), @r###" + Error: + ╭─[:1:7] + │ + 1 │ Answer: T-H-A-T! + · ┬ + · ╰── unexpected : + ───╯ + "###); } #[test] From b78ee5e0ab8ef4d74004461af49ee8970385eccb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 4 Mar 2023 19:48:27 -0800 Subject: [PATCH 086/106] chore: bump sqlparser from 0.30.0 to 0.31.0 (#2001) * chore: bump sqlparser from 0.30.0 to 0.31.0 Bumps [sqlparser](https://github.com/sqlparser-rs/sqlparser-rs) from 0.30.0 to 0.31.0. - [Release notes](https://github.com/sqlparser-rs/sqlparser-rs/releases) - [Changelog](https://github.com/sqlparser-rs/sqlparser-rs/blob/main/CHANGELOG.md) - [Commits](https://github.com/sqlparser-rs/sqlparser-rs/compare/v0.30.0...v0.31.0) --- updated-dependencies: - dependency-name: sqlparser dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * . --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Maximilian Roos Co-authored-by: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> --- Cargo.lock | 4 ++-- prql-compiler/Cargo.toml | 2 +- prql-compiler/src/sql/gen_query.rs | 2 ++ 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 277baa6309a4..b6d5897963b0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2720,9 +2720,9 @@ dependencies = [ [[package]] name = "sqlparser" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db67dc6ef36edb658196c3fef0464a80b53dbbc194a904e81f9bd4190f9ecc5b" +checksum = "f064eb7b163863163c29801910f763c6bfb563b8a8ca4c54193da4c1eea57547" dependencies = [ "log", "serde", diff --git a/prql-compiler/Cargo.toml b/prql-compiler/Cargo.toml index d2df7ea01bf7..c8ba776d9e0b 100644 --- a/prql-compiler/Cargo.toml +++ b/prql-compiler/Cargo.toml @@ -26,7 +26,7 @@ semver = {version = "1.0.14", features = ["serde"]} serde = {version = "1.0.137", features = ["derive"]} serde_json = "1.0.81" sqlformat = "0.2.0" -sqlparser = {version = "0.30.0", features = ["serde"]} +sqlparser = {version = "0.31.0", features = ["serde"]} strum = {version = "0.24.0", features = ["std", "derive"]}# for converting enum variants to string strum_macros = "0.24.0" diff --git a/prql-compiler/src/sql/gen_query.rs b/prql-compiler/src/sql/gen_query.rs index 6a8ba10805e5..4465ba22c879 100644 --- a/prql-compiler/src/sql/gen_query.rs +++ b/prql-compiler/src/sql/gen_query.rs @@ -167,6 +167,7 @@ fn table_factor_of_table_ref(table_ref: TableRef, ctx: &mut Context) -> Result, ctx: &mut Context) -> Result Date: Sat, 4 Mar 2023 22:57:00 -0800 Subject: [PATCH 087/106] docs: Add error messages to the book (#2015) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * docs: Add error messages to the book This allows us to show and test error messages in the book, and adds an initial example. Unfortunately the initial example doesn't have a great error message! So that's something we could work on. It also updates the docs to add late binding — now functions support that! * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * . * . * . * . * . --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- CHANGELOG.md | 4 +- book/highlight-prql.js | 4 + book/src/lib.rs | 93 +++++++++++++++---- book/src/queries/functions.md | 25 ++--- book/src/syntax.md | 12 ++- book/tests/prql/queries/functions-5.prql | 9 ++ book/tests/prql/syntax-10.prql | 2 +- book/tests/prql/syntax-11.prql | 4 +- book/tests/prql/syntax-12.prql | 4 +- book/tests/prql/syntax-13.prql | 4 +- book/tests/prql/syntax-14.prql | 3 +- book/tests/prql/syntax-15.prql | 7 +- book/tests/prql/syntax-16.prql | 8 +- book/tests/prql/syntax-17.prql | 3 + book/tests/prql/syntax-7.prql | 7 +- book/tests/prql/syntax-8.prql | 10 +- book/tests/prql/syntax-9.prql | 6 +- book/tests/snapshot.rs | 27 ++++-- .../snapshot__@queries__functions-4.prql.snap | 1 + .../snapshot__@queries__functions-5.prql.snap | 16 ++++ .../snapshots/snapshot__@syntax-10.prql.snap | 5 +- .../snapshots/snapshot__@syntax-11.prql.snap | 7 +- .../snapshots/snapshot__@syntax-12.prql.snap | 9 +- .../snapshots/snapshot__@syntax-13.prql.snap | 9 +- .../snapshots/snapshot__@syntax-14.prql.snap | 7 +- .../snapshots/snapshot__@syntax-15.prql.snap | 10 +- .../snapshots/snapshot__@syntax-16.prql.snap | 10 +- .../snapshots/snapshot__@syntax-17.prql.snap | 13 +++ .../snapshots/snapshot__@syntax-7.prql.snap | 20 ++-- .../snapshots/snapshot__@syntax-8.prql.snap | 11 ++- .../snapshots/snapshot__@syntax-9.prql.snap | 5 +- ...ests__prql__queries__functions-5.prql.snap | 23 +++++ ...snapshot__tests__prql__syntax-10.prql.snap | 4 +- ...snapshot__tests__prql__syntax-11.prql.snap | 9 +- ...snapshot__tests__prql__syntax-12.prql.snap | 9 +- ...snapshot__tests__prql__syntax-13.prql.snap | 9 +- ...snapshot__tests__prql__syntax-14.prql.snap | 5 +- ...snapshot__tests__prql__syntax-15.prql.snap | 10 +- ...snapshot__tests__prql__syntax-16.prql.snap | 11 +-- ...snapshot__tests__prql__syntax-17.prql.snap | 13 +++ .../snapshot__tests__prql__syntax-7.prql.snap | 12 +-- .../snapshot__tests__prql__syntax-8.prql.snap | 12 ++- .../snapshot__tests__prql__syntax-9.prql.snap | 8 +- 43 files changed, 324 insertions(+), 156 deletions(-) create mode 100644 book/tests/prql/queries/functions-5.prql create mode 100644 book/tests/prql/syntax-17.prql create mode 100644 book/tests/snapshots/snapshot__@queries__functions-5.prql.snap create mode 100644 book/tests/snapshots/snapshot__@syntax-17.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__queries__functions-5.prql.snap create mode 100644 book/tests/snapshots/snapshot__tests__prql__syntax-17.prql.snap diff --git a/CHANGELOG.md b/CHANGELOG.md index 5672e83a7623..0d1d273293ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,7 +15,7 @@ to be more similar to other conventional languages. - `and` now has a higher precedence than `or` (of same reason as the previous point). - - Dates, times and timestamps have a stricter parsing rules. + - Dates, times and timestamps have stricter parsing rules. - `let`, `func`, `prql`, `switch` are now treated as keywords. - Float literals without fraction part are not allowed anymore (`1.`). - Add a `--format` option to `prqlc parse` which can return the AST in YAML @@ -33,6 +33,8 @@ **Documentation**: - Operator precedence (@aljazerzen, #1818) +- Error messages for invalid queries are displayed in the book (@max-sixty, + #2015) **Web**: diff --git a/book/highlight-prql.js b/book/highlight-prql.js index 6955c600b0cc..5f72ddd49f9e 100644 --- a/book/highlight-prql.js +++ b/book/highlight-prql.js @@ -215,6 +215,10 @@ Array.from(document.querySelectorAll("code.language-prql")).forEach( (a) => console.log(a) || hljs.highlightBlock(a) ); +Array.from(document.querySelectorAll("code.language-prql_error")).forEach( + (a) => console.log(a) || hljs.highlightBlock(a) +); + Array.from(document.querySelectorAll("code.language-prql_no_test")).forEach( (a) => console.log(a) || hljs.highlightBlock(a) ); diff --git a/book/src/lib.rs b/book/src/lib.rs index 1d8a8e067edc..74b749a61e80 100644 --- a/book/src/lib.rs +++ b/book/src/lib.rs @@ -13,7 +13,6 @@ use prql_compiler::compile; use pulldown_cmark::{CodeBlockKind, Event, Options, Parser, Tag}; use pulldown_cmark_to_cmark::cmark; use semver::{Version, VersionReq}; -use similar::DiffableStr; use std::{io, process}; /// Checks renderer support and runs the preprocessor. @@ -103,21 +102,50 @@ fn replace_examples(text: &str) -> Result { while let Some(event) = parser.next() { match event.clone() { - Event::Start(Tag::CodeBlock(CodeBlockKind::Fenced(lang))) if lang == "prql".into() => { - if let Some(Event::Text(text)) = parser.next() { - let prql = text.to_string(); - let options = prql_compiler::Options::default().no_signature(); - let html = table_of_comparison( - text.as_str().unwrap(), - &compile(&prql, &options).unwrap(), - ); - cmark_acc.push(Event::Html(html.into())); - - // Skip ending tag - parser.next(); - } else { - bail!("Expected text after PRQL code block"); - } + // Duplicative repetitive logic here and in + // [snapshot.rs/collect_book_examples]; could we unify? + Event::Start(Tag::CodeBlock(CodeBlockKind::Fenced(lang))) + if lang.starts_with("prql") => + { + let Some(Event::Text(text)) = parser.next() + else { + bail!("Expected text after PRQL code block") + }; + let prql = text.to_string(); + let options = prql_compiler::Options::default().no_signature(); + let result = &compile(&prql, &options); + match lang.to_string().as_str() { + "prql" => cmark_acc.push(Event::Html( + table_of_comparison( + &prql, + result + .clone() + .unwrap_or_else(|_| { + panic!("{}", format!("Query raised an error: {prql}")) + }) + .as_str(), + ) + .into(), + )), + "prql_error" => cmark_acc.push(Event::Html( + table_of_error( + &prql, + result + .clone() + .expect_err( + &format!("Query was labeled to raise an error, but succeeded.\n {prql}").to_string(), + ) + .to_string() + .as_str(), + ) + .into(), + )), + "prql_no_test" => {} + _ => bail!("Unknown code block language: {}", lang), + }; + + // Skip ending tag + parser.next(); } _ => cmark_acc.push(event.to_owned()), } @@ -160,6 +188,39 @@ fn table_of_comparison(prql: &str, sql: &str) -> String { .to_string() } +// Exactly the same as `table_of_comparison`, but with a different title for the second column. +fn table_of_error(prql: &str, error: &str) -> String { + format!( + r#" +
+ +
+

PRQL

+ +```prql +{prql} +``` + +
+ +
+

Error

+ +``` +{error} +``` + +
+ +
+"#, + prql = prql.trim(), + error = error, + ) + .trim_start() + .to_string() +} + #[test] fn test_table() -> Result<()> { use insta::assert_display_snapshot; diff --git a/book/src/queries/functions.md b/book/src/queries/functions.md index f49626786b04..14261442527e 100644 --- a/book/src/queries/functions.md +++ b/book/src/queries/functions.md @@ -75,21 +75,22 @@ from kettles derive boiling_proportion = (temp_c | fahrenheit_to_celsius | interp 100) ``` -## Roadmap +## Scope ### Late binding -Currently, functions require a binding to variables in scope; they can't -late-bind to column names; so for example: +Functions can binding to any variables in scope when the function is executed. +For example, here `cost_total` refers to the column that's introduced in the +`from`. -```prql_no_test -func return price -> (price - dividend) / price_yesterday -``` - -...isn't yet a valid function, and instead would needs to be: +```prql +func cost_share cost -> cost / cost_total -```prql_no_test -func return price dividend price_yesterday -> (price - dividend) / (price_yesterday) +from costs +select [materials, labor, overhead, cost_total] +derive [ + materials_share = (cost_share materials), + labor_share = (cost_share labor), + overhead_share = (cost_share overhead), +] ``` - -(which makes functions in this case not useful) diff --git a/book/src/syntax.md b/book/src/syntax.md index 4c7ca169eccc..dbe7dd41820e 100644 --- a/book/src/syntax.md +++ b/book/src/syntax.md @@ -166,9 +166,17 @@ sort (-distance) sort [-distance] ``` +This doesn't work, for example (though it should provide a much better error +message): + +```prql_error +from employees +derive total_distance = sum distance +``` + For a more formal definition, refer to this precedence table. Because function -call has the lowest precedence, nested function calls or arguments that start or -end with an operator require parenthesis. +calls have the lowest precedence, nested function calls or arguments that start +or end with an operator require parenthesis. | Group | Operators | Precedence | Associativity | | -------------- | ----------------- | ---------- | ------------- | diff --git a/book/tests/prql/queries/functions-5.prql b/book/tests/prql/queries/functions-5.prql new file mode 100644 index 000000000000..7875927c0806 --- /dev/null +++ b/book/tests/prql/queries/functions-5.prql @@ -0,0 +1,9 @@ +func cost_share cost -> cost / cost_total + +from costs +select [materials, labor, overhead, cost_total] +derive [ + materials_share = (cost_share materials), + labor_share = (cost_share labor), + overhead_share = (cost_share overhead), +] diff --git a/book/tests/prql/syntax-10.prql b/book/tests/prql/syntax-10.prql index b2ebba1b6488..d768dedf3f09 100644 --- a/book/tests/prql/syntax-10.prql +++ b/book/tests/prql/syntax-10.prql @@ -1,3 +1,3 @@ -prql target:sql.postgres +prql target:sql.mysql from employees select `first name` diff --git a/book/tests/prql/syntax-11.prql b/book/tests/prql/syntax-11.prql index e855d0393136..b2ebba1b6488 100644 --- a/book/tests/prql/syntax-11.prql +++ b/book/tests/prql/syntax-11.prql @@ -1 +1,3 @@ -from `dir/*.parquet` +prql target:sql.postgres +from employees +select `first name` diff --git a/book/tests/prql/syntax-12.prql b/book/tests/prql/syntax-12.prql index a634b9554275..e855d0393136 100644 --- a/book/tests/prql/syntax-12.prql +++ b/book/tests/prql/syntax-12.prql @@ -1,3 +1 @@ -prql target:sql.bigquery -from `project-foo.dataset.table` -join `project-bar.dataset.table` [==col_bax] +from `dir/*.parquet` diff --git a/book/tests/prql/syntax-13.prql b/book/tests/prql/syntax-13.prql index a9ccfe89ed66..a634b9554275 100644 --- a/book/tests/prql/syntax-13.prql +++ b/book/tests/prql/syntax-13.prql @@ -1 +1,3 @@ -from `music.albums` +prql target:sql.bigquery +from `project-foo.dataset.table` +join `project-bar.dataset.table` [==col_bax] diff --git a/book/tests/prql/syntax-14.prql b/book/tests/prql/syntax-14.prql index 15be2cb62f61..a9ccfe89ed66 100644 --- a/book/tests/prql/syntax-14.prql +++ b/book/tests/prql/syntax-14.prql @@ -1,2 +1 @@ -from employees -filter id == $1 +from `music.albums` diff --git a/book/tests/prql/syntax-15.prql b/book/tests/prql/syntax-15.prql index 290e626cf825..15be2cb62f61 100644 --- a/book/tests/prql/syntax-15.prql +++ b/book/tests/prql/syntax-15.prql @@ -1,5 +1,2 @@ -from numbers -select [ - small = 1.000_000_1, - big = 5_000_000, -] +from employees +filter id == $1 diff --git a/book/tests/prql/syntax-16.prql b/book/tests/prql/syntax-16.prql index 029a0ea82464..290e626cf825 100644 --- a/book/tests/prql/syntax-16.prql +++ b/book/tests/prql/syntax-16.prql @@ -1,3 +1,5 @@ -std.from my_table -std.select [from = my_table.a, take = my_table.b] -std.take 3 +from numbers +select [ + small = 1.000_000_1, + big = 5_000_000, +] diff --git a/book/tests/prql/syntax-17.prql b/book/tests/prql/syntax-17.prql new file mode 100644 index 000000000000..029a0ea82464 --- /dev/null +++ b/book/tests/prql/syntax-17.prql @@ -0,0 +1,3 @@ +std.from my_table +std.select [from = my_table.a, take = my_table.b] +std.take 3 diff --git a/book/tests/prql/syntax-7.prql b/book/tests/prql/syntax-7.prql index f655f4637971..afd634e3eb36 100644 --- a/book/tests/prql/syntax-7.prql +++ b/book/tests/prql/syntax-7.prql @@ -1,7 +1,2 @@ from employees -group [title, country] ( - aggregate [ - average salary, - ct = count - ] -) +derive total_distance = sum distance diff --git a/book/tests/prql/syntax-8.prql b/book/tests/prql/syntax-8.prql index 7ee340a4259a..f655f4637971 100644 --- a/book/tests/prql/syntax-8.prql +++ b/book/tests/prql/syntax-8.prql @@ -1,3 +1,7 @@ -from employees # Comment 1 -# Comment 2 -aggregate [average salary] +from employees +group [title, country] ( + aggregate [ + average salary, + ct = count + ] +) diff --git a/book/tests/prql/syntax-9.prql b/book/tests/prql/syntax-9.prql index d768dedf3f09..7ee340a4259a 100644 --- a/book/tests/prql/syntax-9.prql +++ b/book/tests/prql/syntax-9.prql @@ -1,3 +1,3 @@ -prql target:sql.mysql -from employees -select `first name` +from employees # Comment 1 +# Comment 2 +aggregate [average salary] diff --git a/book/tests/snapshot.rs b/book/tests/snapshot.rs index 0d8479b528fc..851d9db9a5c3 100644 --- a/book/tests/snapshot.rs +++ b/book/tests/snapshot.rs @@ -56,22 +56,27 @@ fn collect_book_examples() -> Result> { .filter(|x| glob.is_match(x.path())) .flat_map(|dir_entry| { let text = fs::read_to_string(dir_entry.path())?; + // TODO: Duplicative logic here and in [lib.rs/replace_examples]; + // could we unify? + // + // Could we have a function that takes text and returns a + // Vec, where expected is whether it + // should succeed or fail? let mut parser = Parser::new(&text); let mut prql_blocks = vec![]; while let Some(event) = parser.next() { match event.clone() { // At the start of a PRQL code block, push the _next_ item. // Note that on windows, we only get the next _line_, and so - // we exclude the writing in windows below; + // this is disabled on windows. // https://github.com/PRQL/prql/issues/356 Event::Start(Tag::CodeBlock(CodeBlockKind::Fenced(lang))) - if lang == "prql".into() => + if lang == "prql".into() || lang == "prql_error".into() => { - if let Some(Event::Text(text)) = parser.next() { - prql_blocks.push(text); - } else { - bail!("Expected text after PRQL code block"); - } + let Some(Event::Text(text)) = parser.next() else { + bail!("Expected text after PRQL code block") + }; + prql_blocks.push(text); } _ => {} } @@ -153,7 +158,10 @@ fn write_prql_examples(examples: HashMap) -> Result<()> { }); if is_snapshots_updated { - bail!("Some book snapshots were not consistent with the queries in the book. The snapshots have now been updated. Subsequent runs should pass."); + bail!(r###" +Some book snapshots were not consistent with the queries in the book. +The snapshots have now been updated. Subsequent runs of this test should now pass."### + .trim()); } Ok(()) } @@ -168,7 +176,8 @@ fn test_prql_examples() { return; } - let sql = compile(&prql, &opts).unwrap_or_else(|e| format!("{prql}\n\n{e}")); + // Whether it's a success or a failure, get the string. + let sql = compile(&prql, &opts).unwrap_or_else(|e| e.to_string()); // `glob!` gives us the file path in the test name anyway, so we pass an // empty name. We pass `&prql` so the prql is in the snapshot (albeit in // a single line, and, in the rare case that the SQL doesn't change, the diff --git a/book/tests/snapshots/snapshot__@queries__functions-4.prql.snap b/book/tests/snapshots/snapshot__@queries__functions-4.prql.snap index 86c5ba85d58a..98117ed8ee3a 100644 --- a/book/tests/snapshots/snapshot__@queries__functions-4.prql.snap +++ b/book/tests/snapshots/snapshot__@queries__functions-4.prql.snap @@ -8,3 +8,4 @@ SELECT ((temp_c - 32) / 1.8 - 0) / 100 AS boiling_proportion FROM kettles + diff --git a/book/tests/snapshots/snapshot__@queries__functions-5.prql.snap b/book/tests/snapshots/snapshot__@queries__functions-5.prql.snap new file mode 100644 index 000000000000..043fb613eb3f --- /dev/null +++ b/book/tests/snapshots/snapshot__@queries__functions-5.prql.snap @@ -0,0 +1,16 @@ +--- +source: book/tests/snapshot.rs +expression: "func cost_share cost -> cost / cost_total\n\nfrom costs\nselect [materials, labor, overhead, cost_total]\nderive [\n materials_share = (cost_share materials),\n labor_share = (cost_share labor),\n overhead_share = (cost_share overhead),\n]\n" +input_file: book/tests/prql/queries/functions-5.prql +--- +SELECT + materials, + labor, + overhead, + cost_total, + materials / cost_total AS materials_share, + labor / cost_total AS labor_share, + overhead / cost_total AS overhead_share +FROM + costs + diff --git a/book/tests/snapshots/snapshot__@syntax-10.prql.snap b/book/tests/snapshots/snapshot__@syntax-10.prql.snap index f1b7d23890a6..1b4420bac18f 100644 --- a/book/tests/snapshots/snapshot__@syntax-10.prql.snap +++ b/book/tests/snapshots/snapshot__@syntax-10.prql.snap @@ -1,9 +1,10 @@ --- source: book/tests/snapshot.rs -expression: "prql target:sql.postgres\nfrom employees\nselect `first name`\n" +expression: "prql target:sql.mysql\nfrom employees\nselect `first name`\n" input_file: book/tests/prql/syntax-10.prql --- SELECT - "first name" + `first name` FROM employees + diff --git a/book/tests/snapshots/snapshot__@syntax-11.prql.snap b/book/tests/snapshots/snapshot__@syntax-11.prql.snap index 2ce70ad17f23..3e60cedc7a74 100644 --- a/book/tests/snapshots/snapshot__@syntax-11.prql.snap +++ b/book/tests/snapshots/snapshot__@syntax-11.prql.snap @@ -1,9 +1,10 @@ --- source: book/tests/snapshot.rs -expression: "from `dir/*.parquet`\n" +expression: "prql target:sql.postgres\nfrom employees\nselect `first name`\n" input_file: book/tests/prql/syntax-11.prql --- SELECT - * + "first name" FROM - "dir/*.parquet" + employees + diff --git a/book/tests/snapshots/snapshot__@syntax-12.prql.snap b/book/tests/snapshots/snapshot__@syntax-12.prql.snap index 89258a4e0a89..7372f8f76f8a 100644 --- a/book/tests/snapshots/snapshot__@syntax-12.prql.snap +++ b/book/tests/snapshots/snapshot__@syntax-12.prql.snap @@ -1,11 +1,10 @@ --- source: book/tests/snapshot.rs -expression: "prql target:sql.bigquery\nfrom `project-foo.dataset.table`\njoin `project-bar.dataset.table` [==col_bax]\n" +expression: "from `dir/*.parquet`\n" input_file: book/tests/prql/syntax-12.prql --- SELECT - `project-foo.dataset.table`.*, - `project-bar.dataset.table`.* + * FROM - `project-foo.dataset.table` - JOIN `project-bar.dataset.table` ON `project-foo.dataset.table`.col_bax = `project-bar.dataset.table`.col_bax + "dir/*.parquet" + diff --git a/book/tests/snapshots/snapshot__@syntax-13.prql.snap b/book/tests/snapshots/snapshot__@syntax-13.prql.snap index c1617c87e881..9f4f882ffaca 100644 --- a/book/tests/snapshots/snapshot__@syntax-13.prql.snap +++ b/book/tests/snapshots/snapshot__@syntax-13.prql.snap @@ -1,9 +1,12 @@ --- source: book/tests/snapshot.rs -expression: "from `music.albums`\n" +expression: "prql target:sql.bigquery\nfrom `project-foo.dataset.table`\njoin `project-bar.dataset.table` [==col_bax]\n" input_file: book/tests/prql/syntax-13.prql --- SELECT - * + `project-foo.dataset.table`.*, + `project-bar.dataset.table`.* FROM - music.albums + `project-foo.dataset.table` + JOIN `project-bar.dataset.table` ON `project-foo.dataset.table`.col_bax = `project-bar.dataset.table`.col_bax + diff --git a/book/tests/snapshots/snapshot__@syntax-14.prql.snap b/book/tests/snapshots/snapshot__@syntax-14.prql.snap index 427590aa8b77..cc5fe4f92a62 100644 --- a/book/tests/snapshots/snapshot__@syntax-14.prql.snap +++ b/book/tests/snapshots/snapshot__@syntax-14.prql.snap @@ -1,11 +1,10 @@ --- source: book/tests/snapshot.rs -expression: "from employees\nfilter id == $1\n" +expression: "from `music.albums`\n" input_file: book/tests/prql/syntax-14.prql --- SELECT * FROM - employees -WHERE - id = $1 + music.albums + diff --git a/book/tests/snapshots/snapshot__@syntax-15.prql.snap b/book/tests/snapshots/snapshot__@syntax-15.prql.snap index dddfae4b8812..0ee085bcefeb 100644 --- a/book/tests/snapshots/snapshot__@syntax-15.prql.snap +++ b/book/tests/snapshots/snapshot__@syntax-15.prql.snap @@ -1,10 +1,12 @@ --- source: book/tests/snapshot.rs -expression: "from numbers\nselect [\n small = 1.000_000_1,\n big = 5_000_000,\n]\n" +expression: "from employees\nfilter id == $1\n" input_file: book/tests/prql/syntax-15.prql --- SELECT - 1.0000001 AS small, - 5000000 AS big + * FROM - numbers + employees +WHERE + id = $1 + diff --git a/book/tests/snapshots/snapshot__@syntax-16.prql.snap b/book/tests/snapshots/snapshot__@syntax-16.prql.snap index e62eb76cf856..5bae6263183d 100644 --- a/book/tests/snapshots/snapshot__@syntax-16.prql.snap +++ b/book/tests/snapshots/snapshot__@syntax-16.prql.snap @@ -1,13 +1,11 @@ --- source: book/tests/snapshot.rs -expression: "std.from my_table\nstd.select [from = my_table.a, take = my_table.b]\nstd.take 3\n" +expression: "from numbers\nselect [\n small = 1.000_000_1,\n big = 5_000_000,\n]\n" input_file: book/tests/prql/syntax-16.prql --- SELECT - a AS "from", - b AS take + 1.0000001 AS small, + 5000000 AS big FROM - my_table -LIMIT - 3 + numbers diff --git a/book/tests/snapshots/snapshot__@syntax-17.prql.snap b/book/tests/snapshots/snapshot__@syntax-17.prql.snap new file mode 100644 index 000000000000..a944999d43cd --- /dev/null +++ b/book/tests/snapshots/snapshot__@syntax-17.prql.snap @@ -0,0 +1,13 @@ +--- +source: book/tests/snapshot.rs +expression: "std.from my_table\nstd.select [from = my_table.a, take = my_table.b]\nstd.take 3\n" +input_file: book/tests/prql/syntax-17.prql +--- +SELECT + a AS "from", + b AS take +FROM + my_table +LIMIT + 3 + diff --git a/book/tests/snapshots/snapshot__@syntax-7.prql.snap b/book/tests/snapshots/snapshot__@syntax-7.prql.snap index ef01d0c90ef5..d25417d4c021 100644 --- a/book/tests/snapshots/snapshot__@syntax-7.prql.snap +++ b/book/tests/snapshots/snapshot__@syntax-7.prql.snap @@ -1,15 +1,13 @@ --- source: book/tests/snapshot.rs -expression: "from employees\ngroup [title, country] (\n aggregate [\n average salary,\n ct = count\n ]\n)\n" +expression: "from employees\nderive total_distance = sum distance\n" input_file: book/tests/prql/syntax-7.prql --- -SELECT - title, - country, - AVG(salary), - COUNT(*) AS ct -FROM - employees -GROUP BY - title, - country +Error: + ╭─[:2:29] + │ + 2 │ derive total_distance = sum distance + · ────┬─── + · ╰───── Unknown name distance +───╯ + diff --git a/book/tests/snapshots/snapshot__@syntax-8.prql.snap b/book/tests/snapshots/snapshot__@syntax-8.prql.snap index ea09601c7034..9e7c1486e2a5 100644 --- a/book/tests/snapshots/snapshot__@syntax-8.prql.snap +++ b/book/tests/snapshots/snapshot__@syntax-8.prql.snap @@ -1,9 +1,16 @@ --- source: book/tests/snapshot.rs -expression: "from employees # Comment 1\n# Comment 2\naggregate [average salary]\n" +expression: "from employees\ngroup [title, country] (\n aggregate [\n average salary,\n ct = count\n ]\n)\n" input_file: book/tests/prql/syntax-8.prql --- SELECT - AVG(salary) + title, + country, + AVG(salary), + COUNT(*) AS ct FROM employees +GROUP BY + title, + country + diff --git a/book/tests/snapshots/snapshot__@syntax-9.prql.snap b/book/tests/snapshots/snapshot__@syntax-9.prql.snap index 10db59599207..08fc131cabca 100644 --- a/book/tests/snapshots/snapshot__@syntax-9.prql.snap +++ b/book/tests/snapshots/snapshot__@syntax-9.prql.snap @@ -1,9 +1,10 @@ --- source: book/tests/snapshot.rs -expression: "prql target:sql.mysql\nfrom employees\nselect `first name`\n" +expression: "from employees # Comment 1\n# Comment 2\naggregate [average salary]\n" input_file: book/tests/prql/syntax-9.prql --- SELECT - `first name` + AVG(salary) FROM employees + diff --git a/book/tests/snapshots/snapshot__tests__prql__queries__functions-5.prql.snap b/book/tests/snapshots/snapshot__tests__prql__queries__functions-5.prql.snap new file mode 100644 index 000000000000..4f4e9a5a8d3b --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__queries__functions-5.prql.snap @@ -0,0 +1,23 @@ +--- +source: book/tests/snapshot.rs +expression: "func cost_share cost -> cost / cost_total\n\nfrom costs\nselect [materials, labor, overhead, cost_total]\nderive [\n materials_share = (cost_share materials),\n labor_share = (cost_share labor),\n overhead_share = (cost_share overhead),\n]\n" +--- +func cost_share cost -> cost / cost_total + + + +from costs +select [ + materials, + labor, + overhead, + cost_total, +] +derive [ + materials_share = cost_share materials, + labor_share = cost_share labor, + overhead_share = cost_share overhead, +] + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__syntax-10.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-10.prql.snap index 0ef6f6c5ea4e..19c4de64822f 100644 --- a/book/tests/snapshots/snapshot__tests__prql__syntax-10.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__syntax-10.prql.snap @@ -1,8 +1,8 @@ --- source: book/tests/snapshot.rs -expression: "prql target:sql.postgres\nfrom employees\nselect `first name`\n" +expression: "prql target:sql.mysql\nfrom employees\nselect `first name`\n" --- -prql target:sql.postgres +prql target:sql.mysql diff --git a/book/tests/snapshots/snapshot__tests__prql__syntax-11.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-11.prql.snap index acd1651bdbb9..0ef6f6c5ea4e 100644 --- a/book/tests/snapshots/snapshot__tests__prql__syntax-11.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__syntax-11.prql.snap @@ -1,8 +1,13 @@ --- source: book/tests/snapshot.rs -expression: "from `dir/*.parquet`\n" +expression: "prql target:sql.postgres\nfrom employees\nselect `first name`\n" --- -from `dir/*.parquet` +prql target:sql.postgres + + + +from employees +select `first name` diff --git a/book/tests/snapshots/snapshot__tests__prql__syntax-12.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-12.prql.snap index 6be462d1cb08..acd1651bdbb9 100644 --- a/book/tests/snapshots/snapshot__tests__prql__syntax-12.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__syntax-12.prql.snap @@ -1,13 +1,8 @@ --- source: book/tests/snapshot.rs -expression: "prql target:sql.bigquery\nfrom `project-foo.dataset.table`\njoin `project-bar.dataset.table` [==col_bax]\n" +expression: "from `dir/*.parquet`\n" --- -prql target:sql.bigquery - - - -from `project-foo.dataset.table` -join `project-bar.dataset.table` [==col_bax] +from `dir/*.parquet` diff --git a/book/tests/snapshots/snapshot__tests__prql__syntax-13.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-13.prql.snap index fc9310bcceea..6be462d1cb08 100644 --- a/book/tests/snapshots/snapshot__tests__prql__syntax-13.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__syntax-13.prql.snap @@ -1,8 +1,13 @@ --- source: book/tests/snapshot.rs -expression: "from `music.albums`\n" +expression: "prql target:sql.bigquery\nfrom `project-foo.dataset.table`\njoin `project-bar.dataset.table` [==col_bax]\n" --- -from `music.albums` +prql target:sql.bigquery + + + +from `project-foo.dataset.table` +join `project-bar.dataset.table` [==col_bax] diff --git a/book/tests/snapshots/snapshot__tests__prql__syntax-14.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-14.prql.snap index 429e57d0faf3..fc9310bcceea 100644 --- a/book/tests/snapshots/snapshot__tests__prql__syntax-14.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__syntax-14.prql.snap @@ -1,9 +1,8 @@ --- source: book/tests/snapshot.rs -expression: "from employees\nfilter id == $1\n" +expression: "from `music.albums`\n" --- -from employees -filter id == $1 +from `music.albums` diff --git a/book/tests/snapshots/snapshot__tests__prql__syntax-15.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-15.prql.snap index 7aa2caf4c217..4e250a9bf506 100644 --- a/book/tests/snapshots/snapshot__tests__prql__syntax-15.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__syntax-15.prql.snap @@ -1,12 +1,10 @@ --- source: book/tests/snapshot.rs -expression: "from numbers\nselect [\n small = 1.000_000_1,\n big = 5_000_000,\n]\n" +expression: "from employees\nfilter id == $1\n" --- -from numbers -select [ - small = 1.0000001, - big = 5000000, -] +from employees +filter id == $1 + diff --git a/book/tests/snapshots/snapshot__tests__prql__syntax-16.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-16.prql.snap index ddc2d6ddb49a..7aa2caf4c217 100644 --- a/book/tests/snapshots/snapshot__tests__prql__syntax-16.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__syntax-16.prql.snap @@ -1,13 +1,12 @@ --- source: book/tests/snapshot.rs -expression: "std.from my_table\nstd.select [from = my_table.a, take = my_table.b]\nstd.take 3\n" +expression: "from numbers\nselect [\n small = 1.000_000_1,\n big = 5_000_000,\n]\n" --- -std.from my_table -std.select [ - from = my_table.a, - take = my_table.b, +from numbers +select [ + small = 1.0000001, + big = 5000000, ] -std.take 3 diff --git a/book/tests/snapshots/snapshot__tests__prql__syntax-17.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-17.prql.snap new file mode 100644 index 000000000000..ddc2d6ddb49a --- /dev/null +++ b/book/tests/snapshots/snapshot__tests__prql__syntax-17.prql.snap @@ -0,0 +1,13 @@ +--- +source: book/tests/snapshot.rs +expression: "std.from my_table\nstd.select [from = my_table.a, take = my_table.b]\nstd.take 3\n" +--- +std.from my_table +std.select [ + from = my_table.a, + take = my_table.b, +] +std.take 3 + + + diff --git a/book/tests/snapshots/snapshot__tests__prql__syntax-7.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-7.prql.snap index 81e0a3146955..87ed02336d92 100644 --- a/book/tests/snapshots/snapshot__tests__prql__syntax-7.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__syntax-7.prql.snap @@ -1,17 +1,9 @@ --- source: book/tests/snapshot.rs -expression: "from employees\ngroup [title, country] (\n aggregate [\n average salary,\n ct = count\n ]\n)\n" +expression: "from employees\nderive total_distance = sum distance\n" --- from employees -group [ - title, - country, -] ( - aggregate [ - average salary, - ct = count, -] -) +derive total_distance = sum distance diff --git a/book/tests/snapshots/snapshot__tests__prql__syntax-8.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-8.prql.snap index 4f94033b1f86..81e0a3146955 100644 --- a/book/tests/snapshots/snapshot__tests__prql__syntax-8.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__syntax-8.prql.snap @@ -1,9 +1,17 @@ --- source: book/tests/snapshot.rs -expression: "from employees # Comment 1\n# Comment 2\naggregate [average salary]\n" +expression: "from employees\ngroup [title, country] (\n aggregate [\n average salary,\n ct = count\n ]\n)\n" --- from employees -aggregate [average salary] +group [ + title, + country, +] ( + aggregate [ + average salary, + ct = count, +] +) diff --git a/book/tests/snapshots/snapshot__tests__prql__syntax-9.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-9.prql.snap index 19c4de64822f..4f94033b1f86 100644 --- a/book/tests/snapshots/snapshot__tests__prql__syntax-9.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__syntax-9.prql.snap @@ -1,13 +1,9 @@ --- source: book/tests/snapshot.rs -expression: "prql target:sql.mysql\nfrom employees\nselect `first name`\n" +expression: "from employees # Comment 1\n# Comment 2\naggregate [average salary]\n" --- -prql target:sql.mysql - - - from employees -select `first name` +aggregate [average salary] From 613661a711645fcb58ee236dddb3b0a3c5a0b9a5 Mon Sep 17 00:00:00 2001 From: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Date: Sun, 5 Mar 2023 10:39:04 -0800 Subject: [PATCH 088/106] refactor: Remove double-negatives (#2007) --- prql-compiler/src/sql/gen_expr.rs | 2 +- prql-compiler/src/sql/gen_query.rs | 8 ++++---- prql-compiler/src/sql/mod.rs | 21 ++++++++++++++++----- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/prql-compiler/src/sql/gen_expr.rs b/prql-compiler/src/sql/gen_expr.rs index a1e90216c005..5f57a16670d7 100644 --- a/prql-compiler/src/sql/gen_expr.rs +++ b/prql-compiler/src/sql/gen_expr.rs @@ -301,7 +301,7 @@ pub(super) fn translate_cid(cid: CId, ctx: &mut Context) -> Result) -> Result { - if ctx.query.forbid_stars { + if !ctx.query.allow_stars { Err( Error::new_simple("Target dialect does not support * in this position.") .with_span(span) diff --git a/prql-compiler/src/sql/gen_query.rs b/prql-compiler/src/sql/gen_query.rs index 4465ba22c879..dfbf066f07d5 100644 --- a/prql-compiler/src/sql/gen_query.rs +++ b/prql-compiler/src/sql/gen_query.rs @@ -117,7 +117,7 @@ fn table_factor_of_table_ref(table_ref: TableRef, ctx: &mut Context) -> Result = aggregate.map(|(part, _)| part).unwrap_or_default(); - ctx.query.forbid_stars = !ctx.dialect.stars_in_group(); + ctx.query.allow_stars = ctx.dialect.stars_in_group(); let group_by = try_into_exprs(group_by, ctx, None)?; - ctx.query.forbid_stars = false; + ctx.query.allow_stars = true; ctx.query.pre_projection = false; @@ -429,7 +429,7 @@ fn sql_of_loop(pipeline: Vec, ctx: &mut Context) -> Result, } -#[derive(Default, Clone)] +#[derive(Clone)] struct QueryOpts { /// When true, column references will not include table names prefixes. pub omit_ident_prefix: bool, @@ -80,11 +80,22 @@ struct QueryOpts { /// - ORDER BY needs `pre_projection=false`. pub pre_projection: bool, - /// When true, queries will contain nested sub-queries instead of WITH CTEs. - pub forbid_ctes: bool, + /// When false, queries will contain nested sub-queries instead of WITH CTEs. + pub allow_ctes: bool, - /// When true, * are not allowed. - pub forbid_stars: bool, + /// When false, * are not allowed. + pub allow_stars: bool, +} + +impl Default for QueryOpts { + fn default() -> Self { + QueryOpts { + omit_ident_prefix: false, + pre_projection: false, + allow_ctes: true, + allow_stars: true, + } + } } impl Context { From b02dbd0d167c1abf08e2daf8b9e6fe9411e3c241 Mon Sep 17 00:00:00 2001 From: eitsupi <50911393+eitsupi@users.noreply.github.com> Date: Mon, 6 Mar 2023 04:52:12 +0900 Subject: [PATCH 089/106] docs: update changelog about sql.any (#2017) --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d1d273293ce..53f7ab0fea71 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,9 @@ - Float literals without fraction part are not allowed anymore (`1.`). - Add a `--format` option to `prqlc parse` which can return the AST in YAML (@max-sixty, #1962) +- A new spacial compile target `"sql.any"`. When `"sql.any"` is used as the + target of the compile function's option, the target contained in the query + header will be used. (@aljazerzen, #1995) - Support for SQL parameters with similar syntax (#1957, @aljazerzen) - Allow `:` to be elided in timezones, such as `0800` in `@2020-01-01T13:19:55-0800` (@max-sixty, #1991). From e132c3de9b1099f0fa0d7929c921a301eaccccc4 Mon Sep 17 00:00:00 2001 From: Jelenkee <59470612+Jelenkee@users.noreply.github.com> Date: Sun, 5 Mar 2023 20:54:48 +0100 Subject: [PATCH 090/106] feat: upper and lower function (#2019) --- CHANGELOG.md | 2 ++ book/src/queries/functions.md | 18 +++++------ book/src/syntax.md | 2 +- book/tests/prql/queries/functions-1.prql | 4 +-- book/tests/prql/queries/functions-2.prql | 4 +-- book/tests/prql/queries/functions-4.prql | 2 +- ...ests__prql__queries__functions-1.prql.snap | 6 ++-- ...ests__prql__queries__functions-2.prql.snap | 6 ++-- ...ests__prql__queries__functions-4.prql.snap | 4 +-- prql-compiler/src/semantic/std.prql | 4 +++ prql-compiler/src/sql/std_impl.prql | 4 +++ prql-compiler/src/test.rs | 32 +++++++++++++++++++ 12 files changed, 65 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 53f7ab0fea71..dbb9ffce3285 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,8 @@ - Support for SQL parameters with similar syntax (#1957, @aljazerzen) - Allow `:` to be elided in timezones, such as `0800` in `@2020-01-01T13:19:55-0800` (@max-sixty, #1991). +- Add `std.upper` and `std.lower` functions for changing string casing + (@Jelenkee, #2019). **Fixes**: diff --git a/book/src/queries/functions.md b/book/src/queries/functions.md index 14261442527e..e5fc746056dc 100644 --- a/book/src/queries/functions.md +++ b/book/src/queries/functions.md @@ -23,18 +23,18 @@ from cities derive temp_c = (fahrenheit_to_celsius temp_f) ``` -This function is named `interp`, and has two positional parameters named -`higher` and `x`, and one named parameter named `lower` which takes a default -argument of `0`. It calculates the proportion of the distance that `x` is -between `lower` and `higher`. +This function is named `interp`, and has two positional parameters named `high` +and `x`, and one named parameter named `low` which takes a default argument of +`0`. It calculates the proportion of the distance that `x` is between `low` and +`high`. ```prql -func interp lower:0 higher x -> (x - lower) / (higher - lower) +func interp low:0 high x -> (x - low) / (high - low) from students derive [ sat_proportion_1 = (interp 1600 sat_score), - sat_proportion_2 = (interp lower:0 1600 sat_score), + sat_proportion_2 = (interp low:0 1600 sat_score), ] ``` @@ -47,12 +47,12 @@ positional parameter of the function. Here's the same result as the examples above with an alternative construction: ```prql -func interp lower:0 higher x -> (x - lower) / (higher - lower) +func interp low:0 high x -> (x - low) / (high - low) from students derive [ sat_proportion_1 = (sat_score | interp 1600), - sat_proportion_2 = (sat_score | interp lower:0 1600), + sat_proportion_2 = (sat_score | interp low:0 1600), ] ``` @@ -69,7 +69,7 @@ We can combine a chain of functions, which makes logic more readable: ```prql func fahrenheit_to_celsius temp -> (temp - 32) / 1.8 -func interp lower:0 higher x -> (x - lower) / (higher - lower) +func interp low:0 high x -> (x - low) / (high - low) from kettles derive boiling_proportion = (temp_c | fahrenheit_to_celsius | interp 100) diff --git a/book/src/syntax.md b/book/src/syntax.md index dbe7dd41820e..c2adbe444394 100644 --- a/book/src/syntax.md +++ b/book/src/syntax.md @@ -14,7 +14,7 @@ A summary of PRQL syntax | --------------- | -------------------------------------------------------------------- | ------------------------------------------------------- | | \| | [Pipelines](queries/pipelines.md) | from employees \| select first_name | | `=` | [Assigns](transforms/select.md) & [Aliases](transforms/join.md) | `from e = employees`
`derive total = (sum salary)` | -| `:` | [Named args & Parameters](queries/functions.md) | `interp lower:0 1600 sat_score` | +| `:` | [Named args & Parameters](queries/functions.md) | `interp low:0 1600 sat_score` | | `[]` | [Lists](./syntax.md#lists) | `select [id, amount]` | | `()` | [Precedence & Parentheses](./syntax.md#precedence-and-parentheses) | `derive celsius = (fahrenheit - 32) / 1.8` | | `''` & `""` | [Strings](language-features/strings.md) | `derive name = 'Mary'` | diff --git a/book/tests/prql/queries/functions-1.prql b/book/tests/prql/queries/functions-1.prql index f2da76bdaed6..a03bbcd3ac0d 100644 --- a/book/tests/prql/queries/functions-1.prql +++ b/book/tests/prql/queries/functions-1.prql @@ -1,7 +1,7 @@ -func interp lower:0 higher x -> (x - lower) / (higher - lower) +func interp low:0 high x -> (x - low) / (high - low) from students derive [ sat_proportion_1 = (interp 1600 sat_score), - sat_proportion_2 = (interp lower:0 1600 sat_score), + sat_proportion_2 = (interp low:0 1600 sat_score), ] diff --git a/book/tests/prql/queries/functions-2.prql b/book/tests/prql/queries/functions-2.prql index f7d6afdbd8ac..7fe11cbe86bc 100644 --- a/book/tests/prql/queries/functions-2.prql +++ b/book/tests/prql/queries/functions-2.prql @@ -1,7 +1,7 @@ -func interp lower:0 higher x -> (x - lower) / (higher - lower) +func interp low:0 high x -> (x - low) / (high - low) from students derive [ sat_proportion_1 = (sat_score | interp 1600), - sat_proportion_2 = (sat_score | interp lower:0 1600), + sat_proportion_2 = (sat_score | interp low:0 1600), ] diff --git a/book/tests/prql/queries/functions-4.prql b/book/tests/prql/queries/functions-4.prql index f692e9ffbeb7..fc6ded8dc043 100644 --- a/book/tests/prql/queries/functions-4.prql +++ b/book/tests/prql/queries/functions-4.prql @@ -1,5 +1,5 @@ func fahrenheit_to_celsius temp -> (temp - 32) / 1.8 -func interp lower:0 higher x -> (x - lower) / (higher - lower) +func interp low:0 high x -> (x - low) / (high - low) from kettles derive boiling_proportion = (temp_c | fahrenheit_to_celsius | interp 100) diff --git a/book/tests/snapshots/snapshot__tests__prql__queries__functions-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__queries__functions-1.prql.snap index ef971e8402bc..a8dfd8b7401d 100644 --- a/book/tests/snapshots/snapshot__tests__prql__queries__functions-1.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__queries__functions-1.prql.snap @@ -1,15 +1,15 @@ --- source: book/tests/snapshot.rs -expression: "func interp lower:0 higher x -> (x - lower) / (higher - lower)\n\nfrom students\nderive [\n sat_proportion_1 = (interp 1600 sat_score),\n sat_proportion_2 = (interp lower:0 1600 sat_score),\n]\n" +expression: "func interp low:0 high x -> (x - low) / (high - low)\n\nfrom students\nderive [\n sat_proportion_1 = (interp 1600 sat_score),\n sat_proportion_2 = (interp low:0 1600 sat_score),\n]\n" --- -func interp higher x lower:0 -> x - lower / higher - lower +func interp high x low:0 -> x - low / high - low from students derive [ sat_proportion_1 = interp 1600 sat_score, - sat_proportion_2 = interp lower:0 1600 sat_score, + sat_proportion_2 = interp low:0 1600 sat_score, ] diff --git a/book/tests/snapshots/snapshot__tests__prql__queries__functions-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__queries__functions-2.prql.snap index 2e8f243ea009..62b10ce1ebc0 100644 --- a/book/tests/snapshots/snapshot__tests__prql__queries__functions-2.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__queries__functions-2.prql.snap @@ -1,8 +1,8 @@ --- source: book/tests/snapshot.rs -expression: "func interp lower:0 higher x -> (x - lower) / (higher - lower)\n\nfrom students\nderive [\n sat_proportion_1 = (sat_score | interp 1600),\n sat_proportion_2 = (sat_score | interp lower:0 1600),\n]\n" +expression: "func interp low:0 high x -> (x - low) / (high - low)\n\nfrom students\nderive [\n sat_proportion_1 = (sat_score | interp 1600),\n sat_proportion_2 = (sat_score | interp low:0 1600),\n]\n" --- -func interp higher x lower:0 -> x - lower / higher - lower +func interp high x low:0 -> x - low / high - low @@ -14,7 +14,7 @@ derive [ ), sat_proportion_2 = ( sat_score - interp lower:0 1600 + interp low:0 1600 ), ] diff --git a/book/tests/snapshots/snapshot__tests__prql__queries__functions-4.prql.snap b/book/tests/snapshots/snapshot__tests__prql__queries__functions-4.prql.snap index 3deae6fcab9c..4ad7a7528df5 100644 --- a/book/tests/snapshots/snapshot__tests__prql__queries__functions-4.prql.snap +++ b/book/tests/snapshots/snapshot__tests__prql__queries__functions-4.prql.snap @@ -1,12 +1,12 @@ --- source: book/tests/snapshot.rs -expression: "func fahrenheit_to_celsius temp -> (temp - 32) / 1.8\nfunc interp lower:0 higher x -> (x - lower) / (higher - lower)\n\nfrom kettles\nderive boiling_proportion = (temp_c | fahrenheit_to_celsius | interp 100)\n" +expression: "func fahrenheit_to_celsius temp -> (temp - 32) / 1.8\nfunc interp low:0 high x -> (x - low) / (high - low)\n\nfrom kettles\nderive boiling_proportion = (temp_c | fahrenheit_to_celsius | interp 100)\n" --- func fahrenheit_to_celsius temp -> temp - 32 / 1.8 -func interp higher x lower:0 -> x - lower / higher - lower +func interp high x low:0 -> x - low / high - low diff --git a/prql-compiler/src/semantic/std.prql b/prql-compiler/src/semantic/std.prql index 201bf929ad4a..51027e667c4b 100644 --- a/prql-compiler/src/semantic/std.prql +++ b/prql-compiler/src/semantic/std.prql @@ -59,3 +59,7 @@ func _is_null a -> _param.a == null # Misc func from_text
text `noresolve.format`:csv -> null + +# String functions +func lower column -> null +func upper column -> null diff --git a/prql-compiler/src/sql/std_impl.prql b/prql-compiler/src/sql/std_impl.prql index 91013ab5f9eb..0545e05ebef4 100644 --- a/prql-compiler/src/sql/std_impl.prql +++ b/prql-compiler/src/sql/std_impl.prql @@ -21,3 +21,7 @@ func row_number -> s"ROW_NUMBER()" # Other functions func round n_digits column -> s"ROUND({column}, {n_digits})" func as `noresolve.type` column -> s"CAST({column} AS {type})" + +# String functions +func lower column -> s"LOWER({column})" +func upper column -> s"UPPER({column})" diff --git a/prql-compiler/src/test.rs b/prql-compiler/src/test.rs index 413fcae6ee06..6d4dcb9b071d 100644 --- a/prql-compiler/src/test.rs +++ b/prql-compiler/src/test.rs @@ -3400,3 +3400,35 @@ fn test_datetime_parsing() { "### ); } + +#[test] +fn test_lower() { + assert_display_snapshot!(compile(r#" + from test_tables + derive [lower_name = (name | lower)] + "#).unwrap(), + @r###" + SELECT + *, + LOWER(name) AS lower_name + FROM + test_tables + "### + ); +} + +#[test] +fn test_upper() { + assert_display_snapshot!(compile(r#" + from test_tables + derive [upper_name = upper name] + select [upper_name] + "#).unwrap(), + @r###" + SELECT + UPPER(name) AS upper_name + FROM + test_tables + "### + ); +} From b476fb3c8c73dc6775390a6d4521a216e7c7f4d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alja=C5=BE=20Mur=20Er=C5=BEen?= Date: Sun, 5 Mar 2023 23:08:30 +0100 Subject: [PATCH 091/106] docs: fix website landing page (#2021) --- website/themes/prql-theme/layouts/_default/home.html | 2 +- website/themes/prql-theme/static/style.css | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/website/themes/prql-theme/layouts/_default/home.html b/website/themes/prql-theme/layouts/_default/home.html index 581c747d4558..9875e4dedfe7 100644 --- a/website/themes/prql-theme/layouts/_default/home.html +++ b/website/themes/prql-theme/layouts/_default/home.html @@ -2,7 +2,7 @@ {{ with .Params.hero_section }} {{ if .enable }} -
+
diff --git a/website/themes/prql-theme/static/style.css b/website/themes/prql-theme/static/style.css index df439c136c00..14458343e251 100644 --- a/website/themes/prql-theme/static/style.css +++ b/website/themes/prql-theme/static/style.css @@ -287,7 +287,7 @@ pre ::-webkit-scrollbar-thumb:hover { --------------------------------------------------------------*/ .hero { width: 100%; - min-height: 100vh; + min-height: calc(100vh - 81px); background: #f2f9ff; background: repeating-linear-gradient( 45deg, @@ -297,7 +297,10 @@ pre ::-webkit-scrollbar-thumb:hover { #f2f9ff 300px ), linear-gradient(#daeaff, #f2f9ff); - padding-top: 100px; + display: flex; + flex-direction: column; + justify-content: center; + flex: 1 0 fit-content; } .hero h4 { From 8daadbe7e080ee726e642f627e2f927421b5b3ea Mon Sep 17 00:00:00 2001 From: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Date: Sun, 5 Mar 2023 16:04:51 -0800 Subject: [PATCH 092/106] chore: Fix typo in changelog (#2023) --- CHANGELOG.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dbb9ffce3285..3b54a321c770 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,9 +20,9 @@ - Float literals without fraction part are not allowed anymore (`1.`). - Add a `--format` option to `prqlc parse` which can return the AST in YAML (@max-sixty, #1962) -- A new spacial compile target `"sql.any"`. When `"sql.any"` is used as the - target of the compile function's option, the target contained in the query - header will be used. (@aljazerzen, #1995) +- A new compile target `"sql.any"`. When `"sql.any"` is used as the target of + the compile function's option, the target contained in the query header will + be used. (@aljazerzen, #1995) - Support for SQL parameters with similar syntax (#1957, @aljazerzen) - Allow `:` to be elided in timezones, such as `0800` in `@2020-01-01T13:19:55-0800` (@max-sixty, #1991). From a3a34626a391ef5363ade281ffe1fd6bb8ca365c Mon Sep 17 00:00:00 2001 From: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Date: Sun, 5 Mar 2023 20:29:00 -0800 Subject: [PATCH 093/106] test: Test formatted examples can compile (#2016) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * docs: Add error messages to the book This allows us to show and test error messages in the book, and adds an initial example. Unfortunately the initial example doesn't have a great error message! So that's something we could work on. It also updates the docs to add late binding — now functions support that! * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * . * . * . * . * . * test: Test formatted examples can compile We remove the snapshot output of them all -- even having written these, I was getting confused what all the snapshots were. And we don't use them at all. I added a TODO in the code for a good design if we could make progress on the autoformatter. * Revert "" This reverts commit 193769233653947e5180620ceabe86d014f8a017. * clean up merge diff * . --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- CHANGELOG.md | 3 + book/highlight-prql.js | 2 + book/src/examples/cte.md | 2 +- book/src/examples/employees.md | 2 +- book/src/language-features/s-strings.md | 2 +- book/src/language-features/strings.md | 2 +- book/src/language-features/switch.md | 4 +- book/src/language-features/target.md | 4 +- book/src/lib.rs | 2 +- book/src/queries/functions.md | 2 +- book/src/syntax.md | 2 +- book/src/transforms/select.md | 6 +- book/tests/prql/examples/cte-0.prql | 2 + book/tests/prql/examples/employees-3.prql | 2 + .../prql/language-features/s-strings-4.prql | 2 + .../prql/language-features/strings-5.prql | 2 + .../prql/language-features/switch-0.prql | 2 + .../prql/language-features/switch-1.prql | 2 + .../prql/language-features/target-1.prql | 2 + .../prql/language-features/target-2.prql | 2 + book/tests/prql/queries/functions-0.prql | 2 + book/tests/prql/syntax-6.prql | 2 + book/tests/prql/syntax-7.prql | 2 + book/tests/prql/transforms/select-4.prql | 2 + book/tests/prql/transforms/select-5.prql | 2 + book/tests/prql/transforms/select-6.prql | 2 + book/tests/snapshot.rs | 106 ++++++++++++------ .../snapshots/snapshot__@syntax-7.prql.snap | 6 +- ...ot__tests__prql__examples__cte-0.prql.snap | 33 ------ ...sts__prql__examples__employees-0.prql.snap | 25 ----- ...sts__prql__examples__employees-1.prql.snap | 32 ------ ...sts__prql__examples__employees-2.prql.snap | 35 ------ ...sts__prql__examples__employees-3.prql.snap | 28 ----- ...ql__examples__list-equivalence-0.prql.snap | 9 -- ...ql__examples__list-equivalence-1.prql.snap | 9 -- ...ql__examples__list-equivalence-2.prql.snap | 12 -- ...ql__examples__list-equivalence-3.prql.snap | 10 -- ...t__tests__prql__examples__misc-0.prql.snap | 25 ----- ...t__tests__prql__examples__misc-1.prql.snap | 12 -- ...sts__prql__examples__variables-0.prql.snap | 31 ----- ...sts__prql__examples__variables-1.prql.snap | 18 --- ...ql__internals__functional-lang-0.prql.snap | 10 -- ...ql__internals__functional-lang-1.prql.snap | 10 -- ...ql__internals__functional-lang-2.prql.snap | 11 -- ...ql__internals__functional-lang-3.prql.snap | 12 -- ...rql__internals__name-resolving-0.prql.snap | 9 -- ...rql__internals__name-resolving-1.prql.snap | 17 --- ...hot__tests__prql__introduction-0.prql.snap | 31 ----- ...l__language-features__coalesce-0.prql.snap | 9 -- ...uage-features__dates-and-times-0.prql.snap | 9 -- ...uage-features__dates-and-times-1.prql.snap | 9 -- ...uage-features__dates-and-times-2.prql.snap | 9 -- ...uage-features__dates-and-times-3.prql.snap | 9 -- ...l__language-features__distinct-0.prql.snap | 12 -- ...l__language-features__distinct-1.prql.snap | 12 -- ...l__language-features__distinct-2.prql.snap | 12 -- ...__language-features__f-strings-0.prql.snap | 9 -- ...__language-features__f-strings-1.prql.snap | 9 -- ..._prql__language-features__null-0.prql.snap | 10 -- ...rql__language-features__ranges-0.prql.snap | 20 ---- ...rql__language-features__ranges-1.prql.snap | 13 --- ...__language-features__s-strings-0.prql.snap | 9 -- ...__language-features__s-strings-1.prql.snap | 9 -- ...__language-features__s-strings-2.prql.snap | 14 --- ...__language-features__s-strings-3.prql.snap | 9 -- ...__language-features__s-strings-4.prql.snap | 9 -- ...__language-features__s-strings-5.prql.snap | 12 -- ...__language-features__s-strings-6.prql.snap | 12 -- ...ures__standard-library__README-0.prql.snap | 19 ---- ...s__standard-library__from-text-0.prql.snap | 16 --- ...s__standard-library__from-text-1.prql.snap | 21 ---- ...s__standard-library__from-text-2.prql.snap | 32 ------ ...atures__standard-library__loop-0.prql.snap | 12 -- ...ql__language-features__strings-0.prql.snap | 9 -- ...ql__language-features__strings-1.prql.snap | 9 -- ...ql__language-features__strings-2.prql.snap | 9 -- ...ql__language-features__strings-3.prql.snap | 9 -- ...ql__language-features__strings-4.prql.snap | 9 -- ...ql__language-features__strings-5.prql.snap | 10 -- ...rql__language-features__switch-0.prql.snap | 12 -- ...rql__language-features__switch-1.prql.snap | 13 --- ...rql__language-features__target-0.prql.snap | 14 --- ...rql__language-features__target-1.prql.snap | 14 --- ...rql__language-features__target-2.prql.snap | 12 -- ...ests__prql__queries__functions-0.prql.snap | 15 --- ...ests__prql__queries__functions-1.prql.snap | 16 --- ...ests__prql__queries__functions-2.prql.snap | 22 ---- ...ests__prql__queries__functions-3.prql.snap | 16 --- ...ests__prql__queries__functions-4.prql.snap | 21 ---- ...ests__prql__queries__functions-5.prql.snap | 23 ---- ...ests__prql__queries__pipelines-0.prql.snap | 8 -- ...ests__prql__queries__pipelines-1.prql.snap | 9 -- ...ests__prql__queries__pipelines-2.prql.snap | 17 --- ...ests__prql__queries__variables-0.prql.snap | 17 --- ...ests__prql__queries__variables-1.prql.snap | 18 --- .../snapshot__tests__prql__syntax-0.prql.snap | 13 --- .../snapshot__tests__prql__syntax-1.prql.snap | 13 --- ...snapshot__tests__prql__syntax-10.prql.snap | 13 --- ...snapshot__tests__prql__syntax-11.prql.snap | 13 --- ...snapshot__tests__prql__syntax-12.prql.snap | 8 -- ...snapshot__tests__prql__syntax-13.prql.snap | 13 --- ...snapshot__tests__prql__syntax-14.prql.snap | 8 -- ...snapshot__tests__prql__syntax-15.prql.snap | 10 -- ...snapshot__tests__prql__syntax-16.prql.snap | 12 -- ...snapshot__tests__prql__syntax-17.prql.snap | 13 --- .../snapshot__tests__prql__syntax-2.prql.snap | 20 ---- .../snapshot__tests__prql__syntax-3.prql.snap | 9 -- .../snapshot__tests__prql__syntax-4.prql.snap | 9 -- .../snapshot__tests__prql__syntax-5.prql.snap | 13 --- .../snapshot__tests__prql__syntax-6.prql.snap | 39 ------- .../snapshot__tests__prql__syntax-7.prql.snap | 9 -- .../snapshot__tests__prql__syntax-8.prql.snap | 17 --- .../snapshot__tests__prql__syntax-9.prql.snap | 9 -- ...s__prql__transforms__aggregate-0.prql.snap | 12 -- ...s__prql__transforms__aggregate-1.prql.snap | 17 --- ...s__prql__transforms__aggregate-2.prql.snap | 9 -- ...ests__prql__transforms__append-0.prql.snap | 9 -- ...ests__prql__transforms__append-1.prql.snap | 9 -- ...ests__prql__transforms__append-2.prql.snap | 9 -- ...ests__prql__transforms__derive-0.prql.snap | 9 -- ...ests__prql__transforms__derive-1.prql.snap | 12 -- ...ests__prql__transforms__filter-0.prql.snap | 9 -- ...ests__prql__transforms__filter-1.prql.snap | 9 -- ...ests__prql__transforms__filter-2.prql.snap | 12 -- ..._tests__prql__transforms__from-0.prql.snap | 8 -- ..._tests__prql__transforms__from-1.prql.snap | 9 -- ...tests__prql__transforms__group-0.prql.snap | 17 --- ...tests__prql__transforms__group-1.prql.snap | 10 -- ...tests__prql__transforms__group-2.prql.snap | 12 -- ..._tests__prql__transforms__join-0.prql.snap | 9 -- ..._tests__prql__transforms__join-1.prql.snap | 9 -- ..._tests__prql__transforms__join-2.prql.snap | 9 -- ...ests__prql__transforms__select-0.prql.snap | 9 -- ...ests__prql__transforms__select-1.prql.snap | 12 -- ...ests__prql__transforms__select-2.prql.snap | 9 -- ...ests__prql__transforms__select-3.prql.snap | 12 -- ...ests__prql__transforms__select-4.prql.snap | 16 --- ...ests__prql__transforms__select-5.prql.snap | 18 --- ...ests__prql__transforms__select-6.prql.snap | 10 -- ..._tests__prql__transforms__sort-0.prql.snap | 9 -- ..._tests__prql__transforms__sort-1.prql.snap | 9 -- ..._tests__prql__transforms__sort-2.prql.snap | 13 --- ..._tests__prql__transforms__sort-3.prql.snap | 9 -- ..._tests__prql__transforms__sort-4.prql.snap | 10 -- ..._tests__prql__transforms__sort-5.prql.snap | 10 -- ..._tests__prql__transforms__take-0.prql.snap | 9 -- ..._tests__prql__transforms__take-1.prql.snap | 13 --- ...ests__prql__transforms__window-0.prql.snap | 14 --- ...ests__prql__transforms__window-1.prql.snap | 18 --- ...ests__prql__transforms__window-2.prql.snap | 10 -- ...ests__prql__transforms__window-3.prql.snap | 12 -- ...ests__prql__transforms__window-4.prql.snap | 9 -- 152 files changed, 122 insertions(+), 1719 deletions(-) delete mode 100644 book/tests/snapshots/snapshot__tests__prql__examples__cte-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__examples__employees-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__examples__employees-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__examples__employees-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__examples__employees-3.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__examples__list-equivalence-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__examples__list-equivalence-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__examples__list-equivalence-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__examples__list-equivalence-3.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__examples__misc-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__examples__misc-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__examples__variables-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__examples__variables-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-3.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__internals__name-resolving-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__internals__name-resolving-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__introduction-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__coalesce-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-3.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__distinct-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__distinct-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__distinct-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__f-strings-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__f-strings-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__null-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__ranges-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__ranges-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-3.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-4.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-5.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-6.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__standard-library__README-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__standard-library__from-text-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__standard-library__from-text-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__standard-library__from-text-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__standard-library__loop-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__strings-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__strings-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__strings-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__strings-3.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__strings-4.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__strings-5.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__switch-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__switch-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__target-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__target-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__language-features__target-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__queries__functions-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__queries__functions-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__queries__functions-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__queries__functions-3.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__queries__functions-4.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__queries__functions-5.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__queries__pipelines-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__queries__pipelines-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__queries__pipelines-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__queries__variables-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__queries__variables-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__syntax-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__syntax-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__syntax-10.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__syntax-11.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__syntax-12.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__syntax-13.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__syntax-14.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__syntax-15.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__syntax-16.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__syntax-17.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__syntax-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__syntax-3.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__syntax-4.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__syntax-5.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__syntax-6.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__syntax-7.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__syntax-8.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__syntax-9.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__aggregate-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__aggregate-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__aggregate-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__append-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__append-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__append-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__derive-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__derive-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__filter-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__filter-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__filter-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__from-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__from-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__group-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__group-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__group-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__join-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__join-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__join-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__select-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__select-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__select-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__select-3.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__select-4.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__select-5.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__select-6.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__sort-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__sort-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__sort-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__sort-3.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__sort-4.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__sort-5.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__take-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__take-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__window-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__window-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__window-2.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__window-3.prql.snap delete mode 100644 book/tests/snapshots/snapshot__tests__prql__transforms__window-4.prql.snap diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b54a321c770..d5d7bec3f038 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -55,6 +55,9 @@ **Internal changes**: +- Test that the code our nascent autoformatter generates can be compiled into + SQL. Examples where it can't are now labeled. (@max-sixty, #2016) + **New Contributors**: ## 0.5.2 — 2022-02-18 diff --git a/book/highlight-prql.js b/book/highlight-prql.js index 5f72ddd49f9e..6993b6f799d5 100644 --- a/book/highlight-prql.js +++ b/book/highlight-prql.js @@ -205,6 +205,8 @@ formatting = function (hljs) { hljs.registerLanguage("prql", formatting); hljs.registerLanguage("prql_no_test", formatting); +hljs.registerLanguage("prql_error", formatting); +hljs.registerLanguage("prql_no_fmt", formatting); hljs.registerLanguage("elm", formatting); // These lines should only exists in the book, not the website. diff --git a/book/src/examples/cte.md b/book/src/examples/cte.md index 138b47154575..eab8c1592c7a 100644 --- a/book/src/examples/cte.md +++ b/book/src/examples/cte.md @@ -1,4 +1,4 @@ -```prql +```prql_no_fmt let newest_employees = ( from employees sort tenure diff --git a/book/src/examples/employees.md b/book/src/examples/employees.md index 5090a78155e2..48467dc87ecb 100644 --- a/book/src/examples/employees.md +++ b/book/src/examples/employees.md @@ -99,7 +99,7 @@ select [mng_name, managers.gender, salary_avg, salary_sd] > Find distributions of titles, salaries and genders for each department. -```prql +```prql_no_fmt from de=dept_emp join s=salaries side:left [ (s.emp_no == de.emp_no), diff --git a/book/src/language-features/s-strings.md b/book/src/language-features/s-strings.md index ed70b1923dbe..8cde2da4560d 100644 --- a/book/src/language-features/s-strings.md +++ b/book/src/language-features/s-strings.md @@ -61,7 +61,7 @@ should implement it in PRQL or PRQL's stdlib. To output braces from an s-string, use double braces: -```prql +```prql_no_fmt from employees derive [ has_valid_title = s"regexp_contains(title, '([a-z0-9]*-){{2,}}')" diff --git a/book/src/language-features/strings.md b/book/src/language-features/strings.md index 922c5cac5e76..23acb935ce77 100644 --- a/book/src/language-features/strings.md +++ b/book/src/language-features/strings.md @@ -33,7 +33,7 @@ select x = """""I said """hello world"""!""""" Strings can also contain any escape defined by [JSON standard](https://www.ecma-international.org/publications-and-standards/standards/ecma-404/). -```prql +```prql_no_fmt from my_table select x = "\t\tline ends here\n \\ " ``` diff --git a/book/src/language-features/switch.md b/book/src/language-features/switch.md index 9570570eeb9c..eb9353eee968 100644 --- a/book/src/language-features/switch.md +++ b/book/src/language-features/switch.md @@ -6,7 +6,7 @@ PRQL uses `switch` for both SQL's `CASE` and `IF` statements. Here's an example: -```prql +```prql_no_fmt from employees derive distance = switch [ city == "Calgary" -> 0, @@ -17,7 +17,7 @@ derive distance = switch [ If no condition is met, the value takes a `null` value. To set a default, use a `true` condition: -```prql +```prql_no_fmt from employees derive distance = switch [ city == "Calgary" -> 0, diff --git a/book/src/language-features/target.md b/book/src/language-features/target.md index 558e338292cc..979d9434f4c9 100644 --- a/book/src/language-features/target.md +++ b/book/src/language-features/target.md @@ -15,7 +15,7 @@ sort age take 10 ``` -```prql +```prql_no_fmt prql target:sql.mssql from employees @@ -47,7 +47,7 @@ very welcome. PRQL allows specifying a version of the language in the PRQL header, like: -```prql +```prql_no_fmt prql version:"0.5" from employees diff --git a/book/src/lib.rs b/book/src/lib.rs index 74b749a61e80..dc85ee7aa710 100644 --- a/book/src/lib.rs +++ b/book/src/lib.rs @@ -115,7 +115,7 @@ fn replace_examples(text: &str) -> Result { let options = prql_compiler::Options::default().no_signature(); let result = &compile(&prql, &options); match lang.to_string().as_str() { - "prql" => cmark_acc.push(Event::Html( + "prql" | "prql_no_fmt" => cmark_acc.push(Event::Html( table_of_comparison( &prql, result diff --git a/book/src/queries/functions.md b/book/src/queries/functions.md index e5fc746056dc..5f31e4de8903 100644 --- a/book/src/queries/functions.md +++ b/book/src/queries/functions.md @@ -16,7 +16,7 @@ Functions have two types of parameters: So this function is named `fahrenheit_to_celsius` and has one parameter `temp`: -```prql +```prql_no_fmt func fahrenheit_to_celsius temp -> (temp - 32) / 1.8 from cities diff --git a/book/src/syntax.md b/book/src/syntax.md index c2adbe444394..2382e5be3d44 100644 --- a/book/src/syntax.md +++ b/book/src/syntax.md @@ -137,7 +137,7 @@ function call, like `foo + bar`. Here's a full rundown of times this applier: -```prql +```prql_no_fmt from employees # Requires parentheses, because it's contains a pipe derive is_proximate = (distance | in 0..20) diff --git a/book/src/transforms/select.md b/book/src/transforms/select.md index aa330ac45b8e..b6f9694ef6d9 100644 --- a/book/src/transforms/select.md +++ b/book/src/transforms/select.md @@ -50,19 +50,19 @@ We can use `!` to exclude a list of columns. This can operate in two ways: Some examples: -```prql +```prql_no_fmt prql target:sql.bigquery from tracks select ![milliseconds,bytes] ``` -```prql +```prql_no_fmt from tracks select [track_id, title, composer, bytes] select ![title, composer] ``` -```prql +```prql_no_fmt from artists derive nick = name select ![artists.*] diff --git a/book/tests/prql/examples/cte-0.prql b/book/tests/prql/examples/cte-0.prql index c5d23ce84ec6..e1f990d5a366 100644 --- a/book/tests/prql/examples/cte-0.prql +++ b/book/tests/prql/examples/cte-0.prql @@ -1,3 +1,5 @@ +# Can't yet format & compile + let newest_employees = ( from employees sort tenure diff --git a/book/tests/prql/examples/employees-3.prql b/book/tests/prql/examples/employees-3.prql index 9e9d9e47855f..41950b3019cb 100644 --- a/book/tests/prql/examples/employees-3.prql +++ b/book/tests/prql/examples/employees-3.prql @@ -1,3 +1,5 @@ +# Can't yet format & compile + from de=dept_emp join s=salaries side:left [ (s.emp_no == de.emp_no), diff --git a/book/tests/prql/language-features/s-strings-4.prql b/book/tests/prql/language-features/s-strings-4.prql index 782542d16c58..39a20f5bae9a 100644 --- a/book/tests/prql/language-features/s-strings-4.prql +++ b/book/tests/prql/language-features/s-strings-4.prql @@ -1,3 +1,5 @@ +# Can't yet format & compile + from employees derive [ has_valid_title = s"regexp_contains(title, '([a-z0-9]*-){{2,}}')" diff --git a/book/tests/prql/language-features/strings-5.prql b/book/tests/prql/language-features/strings-5.prql index 491c9f04bdd1..190823141edf 100644 --- a/book/tests/prql/language-features/strings-5.prql +++ b/book/tests/prql/language-features/strings-5.prql @@ -1,2 +1,4 @@ +# Can't yet format & compile + from my_table select x = "\t\tline ends here\n \\ " diff --git a/book/tests/prql/language-features/switch-0.prql b/book/tests/prql/language-features/switch-0.prql index e3284d640b83..c2cd611f974a 100644 --- a/book/tests/prql/language-features/switch-0.prql +++ b/book/tests/prql/language-features/switch-0.prql @@ -1,3 +1,5 @@ +# Can't yet format & compile + from employees derive distance = switch [ city == "Calgary" -> 0, diff --git a/book/tests/prql/language-features/switch-1.prql b/book/tests/prql/language-features/switch-1.prql index f8d840c11cb5..aba9837069df 100644 --- a/book/tests/prql/language-features/switch-1.prql +++ b/book/tests/prql/language-features/switch-1.prql @@ -1,3 +1,5 @@ +# Can't yet format & compile + from employees derive distance = switch [ city == "Calgary" -> 0, diff --git a/book/tests/prql/language-features/target-1.prql b/book/tests/prql/language-features/target-1.prql index 53433b4b16c0..58ed8531c0e5 100644 --- a/book/tests/prql/language-features/target-1.prql +++ b/book/tests/prql/language-features/target-1.prql @@ -1,3 +1,5 @@ +# Can't yet format & compile + prql target:sql.mssql from employees diff --git a/book/tests/prql/language-features/target-2.prql b/book/tests/prql/language-features/target-2.prql index c452ea2a5aad..06bf38542363 100644 --- a/book/tests/prql/language-features/target-2.prql +++ b/book/tests/prql/language-features/target-2.prql @@ -1,3 +1,5 @@ +# Can't yet format & compile + prql version:"0.5" from employees diff --git a/book/tests/prql/queries/functions-0.prql b/book/tests/prql/queries/functions-0.prql index b09007f54290..f859ceaa151e 100644 --- a/book/tests/prql/queries/functions-0.prql +++ b/book/tests/prql/queries/functions-0.prql @@ -1,3 +1,5 @@ +# Can't yet format & compile + func fahrenheit_to_celsius temp -> (temp - 32) / 1.8 from cities diff --git a/book/tests/prql/syntax-6.prql b/book/tests/prql/syntax-6.prql index 9ce71c723b6a..ac2acdcd7a08 100644 --- a/book/tests/prql/syntax-6.prql +++ b/book/tests/prql/syntax-6.prql @@ -1,3 +1,5 @@ +# Can't yet format & compile + from employees # Requires parentheses, because it's contains a pipe derive is_proximate = (distance | in 0..20) diff --git a/book/tests/prql/syntax-7.prql b/book/tests/prql/syntax-7.prql index afd634e3eb36..a7ee0af913aa 100644 --- a/book/tests/prql/syntax-7.prql +++ b/book/tests/prql/syntax-7.prql @@ -1,2 +1,4 @@ +# Error expected + from employees derive total_distance = sum distance diff --git a/book/tests/prql/transforms/select-4.prql b/book/tests/prql/transforms/select-4.prql index a473a7832655..5d89bfe51b61 100644 --- a/book/tests/prql/transforms/select-4.prql +++ b/book/tests/prql/transforms/select-4.prql @@ -1,3 +1,5 @@ +# Can't yet format & compile + prql target:sql.bigquery from tracks select ![milliseconds,bytes] diff --git a/book/tests/prql/transforms/select-5.prql b/book/tests/prql/transforms/select-5.prql index 06d8486c28a7..6296e2abd6e7 100644 --- a/book/tests/prql/transforms/select-5.prql +++ b/book/tests/prql/transforms/select-5.prql @@ -1,3 +1,5 @@ +# Can't yet format & compile + from tracks select [track_id, title, composer, bytes] select ![title, composer] diff --git a/book/tests/prql/transforms/select-6.prql b/book/tests/prql/transforms/select-6.prql index 78a496224d09..0f5a238d4098 100644 --- a/book/tests/prql/transforms/select-6.prql +++ b/book/tests/prql/transforms/select-6.prql @@ -1,3 +1,5 @@ +# Can't yet format & compile + from artists derive nick = name select ![artists.*] diff --git a/book/tests/snapshot.rs b/book/tests/snapshot.rs index 851d9db9a5c3..c742bf3caa4d 100644 --- a/book/tests/snapshot.rs +++ b/book/tests/snapshot.rs @@ -1,15 +1,6 @@ #![cfg(not(target_family = "wasm"))] -/// This test: -/// - Extracts PRQL code blocks into files in the `examples` path, skipping -/// where the matching example is already present. -/// - Compiles them to SQL, comparing to a snapshot. Insta raises an error if -/// there's a diff. -/// -/// Then, when the book is built, the PRQL code block in the book is replaced -/// with a comparison table. -/// -/// We also use this test to run tests on our Display trait output, currently as -/// another set of snapshots (more comments inline). +// +// Thoughts on the overall code: // // Overall, this is overengineered — it's complicated and took a long time to // write. The intention is good — have a version of the SQL that's committed @@ -17,6 +8,10 @@ // custom code for quite a general problem, even if our preferences are slightly // different from the general case. // +// Having an API for being able to read snapshots +// (https://github.com/mitsuhiko/insta/issues/353) would significantly reduce the need for +// custom code; +// // Possibly we should be using something like pandoc / // https://github.com/gpoore/codebraid / which would run the transformation for // us. They introduce a bunch of non-rust dependencies, which is not ideal, but @@ -25,6 +20,7 @@ use anyhow::{bail, Error, Result}; use globset::Glob; use insta::{assert_snapshot, glob}; +use itertools::Itertools; use log::warn; use prql_compiler::*; use std::path::{Path, PathBuf}; @@ -32,8 +28,16 @@ use std::{collections::HashMap, fs}; use walkdir::WalkDir; #[test] +/// This test: +/// - Extracts PRQL code blocks into files in the `examples` path, skipping +/// where the matching example is already present. +/// - Compiles them to SQL, comparing to a snapshot. Insta raises an error if +/// there's a diff. +/// +/// Then, when the book is built, the PRQL code block in the book is replaced +/// with a comparison table. fn test_examples() -> Result<()> { - // Note that on windows, markdown is read differently, and so we don't write + // Note that on Windows, markdown is read differently, and so we don't write // on Windows (we write from the same place we read as a workaround). ref // https://github.com/PRQL/prql/issues/356 @@ -71,12 +75,18 @@ fn collect_book_examples() -> Result> { // this is disabled on windows. // https://github.com/PRQL/prql/issues/356 Event::Start(Tag::CodeBlock(CodeBlockKind::Fenced(lang))) - if lang == "prql".into() || lang == "prql_error".into() => + if lang.starts_with("prql") => { let Some(Event::Text(text)) = parser.next() else { bail!("Expected text after PRQL code block") }; - prql_blocks.push(text); + if lang == "prql".into() { + prql_blocks.push(text.to_string()); + } else if lang == "prql_error".into() { + prql_blocks.push(format!("# Error expected\n\n{text}")); + } else if lang == "prql_no_fmt".into() { + prql_blocks.push(format!("# Can't yet format & compile\n\n{text}")); + } } _ => {} } @@ -107,7 +117,6 @@ fn collect_book_examples() -> Result> { /// Collect examples which we've already written to disk, as a map of . fn collect_snapshot_examples() -> Result> { - use itertools::Itertools; let glob = Glob::new("**/*.prql")?.compile_matcher(); let existing_examples = WalkDir::new(Path::new(ROOT_EXAMPLES_PATH)) .into_iter() @@ -131,7 +140,7 @@ fn collect_book_examples() -> Result> { // requires no dependencies. fn write_prql_examples(examples: HashMap) -> Result<()> { // If we have to modify any files, raise an error at the end, so it fails in CI. - let mut is_snapshots_updated = false; + let mut snapshots_updated = vec![]; let mut existing_snapshots: HashMap<_, _> = collect_snapshot_examples()?; // Write any new snapshots, or update any that have changed @@ -141,7 +150,7 @@ fn write_prql_examples(examples: HashMap) -> Result<()> { .map(|existing| existing != *example) .unwrap_or(true) { - is_snapshots_updated = true; + snapshots_updated.push(prql_path); fs::create_dir_all(Path::new(prql_path).parent().unwrap())?; fs::write(prql_path, example)?; } @@ -149,19 +158,28 @@ fn write_prql_examples(examples: HashMap) -> Result<()> { Ok::<(), anyhow::Error>(()) })?; - // If there are any files left in `existing_snapshots`, we remove them, since - // they don't reference anything. + // If there are any files left in `existing_snapshots`, we remove them, + // since they don't reference anything (like + // `--delete-unreferenced-snapshots` in insta). existing_snapshots.iter().for_each(|(path, _)| { trash::delete(path).unwrap_or_else(|e| { warn!("Failed to delete unreferenced example: {}", e); }) }); - if is_snapshots_updated { - bail!(r###" -Some book snapshots were not consistent with the queries in the book. + if !snapshots_updated.is_empty() { + let snapshots_updated = snapshots_updated + .iter() + .map(|x| format!(" - {}", x.to_str().unwrap())) + .join("\n"); + bail!(format!( + r###" +Some book snapshots were not consistent with the queries in the book: + +{snapshots_updated} + The snapshots have now been updated. Subsequent runs of this test should now pass."### - .trim()); + )); } Ok(()) } @@ -186,22 +204,42 @@ fn test_prql_examples() { }); } -/// Snapshot the display trait output of each example. +/// Test that the formatted result (the `Display` result) of each example can be +/// compiled. +// +// We previously snapshot all the queries. But that was a lot of output, for +// something we weren't yet looking at. // -// TODO: this involves writing out almost the same PRQL again — instead we could -// compare the output of Display to the auto-formatted source. But we need an -// autoformatter for that (unless we want to raise on any non-matching input, -// which seems very strict) +// The ideal would be to auto-format the examples themselves, likely during the +// compilation. For that to provide a good output, we need to implement a proper +// autoformatter. #[test] fn test_display() -> Result<(), ErrorMessages> { collect_book_examples()? .iter() - .try_for_each(|(path, example)| { - assert_snapshot!( - path.to_string_lossy().to_string(), - prql_to_pl(example).and_then(pl_to_prql)?, - example - ); + .try_for_each(|(path, prql)| { + if prql.contains("# Error expected") || prql.contains("# Can't yet format & compile") { + return Ok(()); + } + prql_to_pl(prql) + .and_then(pl_to_prql) + .and_then(|formatted| compile(&formatted, &Options::default())) + .unwrap_or_else(|_| { + panic!( + " +Failed compiling the formatted result of {path:?} +To skip this test for an example, use `prql_no_fmt` as the language label. + +The original PRQL was: + +{prql} + +", + path = path.canonicalize().unwrap(), + prql = prql + ) + }); + Ok::<(), ErrorMessages>(()) })?; diff --git a/book/tests/snapshots/snapshot__@syntax-7.prql.snap b/book/tests/snapshots/snapshot__@syntax-7.prql.snap index d25417d4c021..d52ff256c269 100644 --- a/book/tests/snapshots/snapshot__@syntax-7.prql.snap +++ b/book/tests/snapshots/snapshot__@syntax-7.prql.snap @@ -1,12 +1,12 @@ --- source: book/tests/snapshot.rs -expression: "from employees\nderive total_distance = sum distance\n" +expression: "# Error expected\n\nfrom employees\nderive total_distance = sum distance\n" input_file: book/tests/prql/syntax-7.prql --- Error: - ╭─[:2:29] + ╭─[:4:29] │ - 2 │ derive total_distance = sum distance + 4 │ derive total_distance = sum distance · ────┬─── · ╰───── Unknown name distance ───╯ diff --git a/book/tests/snapshots/snapshot__tests__prql__examples__cte-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__examples__cte-0.prql.snap deleted file mode 100644 index 83e9f48a0e9e..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__examples__cte-0.prql.snap +++ /dev/null @@ -1,33 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "let newest_employees = (\n from employees\n sort tenure\n take 50\n)\n\nlet average_salaries = (\n from salaries\n group country (\n aggregate average_country_salary = (average salary)\n )\n)\n\nfrom newest_employees\njoin average_salaries [==country]\nselect [name, salary, average_country_salary]\n" ---- -let newest_employees = ( - from employees - sort tenure - take 50 -) - - - -let average_salaries = ( - from salaries - group country ( - aggregate ( - average_country_salary = average salary -) -) -) - - - -from newest_employees -join average_salaries [==country] -select [ - name, - salary, - average_country_salary, -] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__examples__employees-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__examples__employees-0.prql.snap deleted file mode 100644 index ac80804d08a1..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__examples__employees-0.prql.snap +++ /dev/null @@ -1,25 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from salaries\ngroup [emp_no] (\n aggregate [emp_salary = average salary]\n)\njoin t=titles [==emp_no]\njoin dept_emp side:left [==emp_no]\ngroup [dept_emp.dept_no, t.title] (\n aggregate [avg_salary = average emp_salary]\n)\njoin departments [==dept_no]\nselect [dept_name, title, avg_salary]\n" ---- -from salaries -group [emp_no] ( - aggregate [emp_salary = average salary] -) -join t = titles [==emp_no] -join side:left dept_emp [==emp_no] -group [ - dept_emp.dept_no, - t.title, -] ( - aggregate [avg_salary = average emp_salary] -) -join departments [==dept_no] -select [ - dept_name, - title, - avg_salary, -] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__examples__employees-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__examples__employees-1.prql.snap deleted file mode 100644 index c5d5366f6306..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__examples__employees-1.prql.snap +++ /dev/null @@ -1,32 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from e=employees\njoin salaries [==emp_no]\ngroup [e.emp_no, e.gender] (\n aggregate [\n emp_salary = average salaries.salary\n ]\n)\njoin de=dept_emp [==emp_no] side:left\ngroup [de.dept_no, gender] (\n aggregate [\n salary_avg = average emp_salary,\n salary_sd = stddev emp_salary,\n ]\n)\njoin departments [==dept_no]\nselect [dept_name, gender, salary_avg, salary_sd]\n" ---- -from e = employees -join salaries [==emp_no] -group [ - e.emp_no, - e.gender, -] ( - aggregate [emp_salary = average salaries.salary] -) -join side:left de = dept_emp [==emp_no] -group [ - de.dept_no, - gender, -] ( - aggregate [ - salary_avg = average emp_salary, - salary_sd = stddev emp_salary, -] -) -join departments [==dept_no] -select [ - dept_name, - gender, - salary_avg, - salary_sd, -] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__examples__employees-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__examples__employees-2.prql.snap deleted file mode 100644 index d957c280a5c6..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__examples__employees-2.prql.snap +++ /dev/null @@ -1,35 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from e=employees\njoin salaries [==emp_no]\ngroup [e.emp_no, e.gender] (\n aggregate [\n emp_salary = average salaries.salary\n ]\n)\njoin de=dept_emp [==emp_no]\njoin dm=dept_manager [\n (dm.dept_no == de.dept_no) and s\"(de.from_date, de.to_date) OVERLAPS (dm.from_date, dm.to_date)\"\n]\ngroup [dm.emp_no, gender] (\n aggregate [\n salary_avg = average emp_salary,\n salary_sd = stddev emp_salary\n ]\n)\nderive mng_no = emp_no\njoin managers=employees [==emp_no]\nderive mng_name = s\"managers.first_name || ' ' || managers.last_name\"\nselect [mng_name, managers.gender, salary_avg, salary_sd]\n" ---- -from e = employees -join salaries [==emp_no] -group [ - e.emp_no, - e.gender, -] ( - aggregate [emp_salary = average salaries.salary] -) -join de = dept_emp [==emp_no] -join dm = dept_manager [dm.dept_no == de.dept_no and s"(de.from_date, de.to_date) OVERLAPS (dm.from_date, dm.to_date)"] -group [ - dm.emp_no, - gender, -] ( - aggregate [ - salary_avg = average emp_salary, - salary_sd = stddev emp_salary, -] -) -derive mng_no = emp_no -join managers = employees [==emp_no] -derive mng_name = s"managers.first_name || ' ' || managers.last_name" -select [ - mng_name, - managers.gender, - salary_avg, - salary_sd, -] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__examples__employees-3.prql.snap b/book/tests/snapshots/snapshot__tests__prql__examples__employees-3.prql.snap deleted file mode 100644 index 9cc6115f24bd..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__examples__employees-3.prql.snap +++ /dev/null @@ -1,28 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from de=dept_emp\njoin s=salaries side:left [\n (s.emp_no == de.emp_no),\n s\"({s.from_date}, {s.to_date}) OVERLAPS ({de.from_date}, {de.to_date})\"\n]\ngroup [de.emp_no, de.dept_no] (\n aggregate salary = (average s.salary)\n)\njoin employees [==emp_no]\njoin titles [==emp_no]\nselect [dept_no, salary, employees.gender, titles.title]\n" ---- -from de = dept_emp -join side:left s = salaries [ - s.emp_no == de.emp_no, - s"({s.from_date}, {s.to_date}) OVERLAPS ({de.from_date}, {de.to_date})", -] -group [ - de.emp_no, - de.dept_no, -] ( - aggregate ( - salary = average s.salary -) -) -join employees [==emp_no] -join titles [==emp_no] -select [ - dept_no, - salary, - employees.gender, - titles.title, -] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__examples__list-equivalence-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__examples__list-equivalence-0.prql.snap deleted file mode 100644 index 8566dfaeb2b2..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__examples__list-equivalence-0.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nselect salary\n" ---- -from employees -select salary - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__examples__list-equivalence-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__examples__list-equivalence-1.prql.snap deleted file mode 100644 index 055af64b363a..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__examples__list-equivalence-1.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nselect [salary]\n" ---- -from employees -select [salary] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__examples__list-equivalence-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__examples__list-equivalence-2.prql.snap deleted file mode 100644 index 3d298b6f9b55..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__examples__list-equivalence-2.prql.snap +++ /dev/null @@ -1,12 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nderive [\n gross_salary = salary + payroll_tax,\n gross_cost = gross_salary + benefits_cost\n]\n" ---- -from employees -derive [ - gross_salary = salary + payroll_tax, - gross_cost = gross_salary + benefits_cost, -] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__examples__list-equivalence-3.prql.snap b/book/tests/snapshots/snapshot__tests__prql__examples__list-equivalence-3.prql.snap deleted file mode 100644 index 254f07187889..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__examples__list-equivalence-3.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nderive gross_salary = salary + payroll_tax\nderive gross_cost = gross_salary + benefits_cost\n" ---- -from employees -derive gross_salary = salary + payroll_tax -derive gross_cost = gross_salary + benefits_cost - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__examples__misc-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__examples__misc-0.prql.snap deleted file mode 100644 index 63b13a31ec56..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__examples__misc-0.prql.snap +++ /dev/null @@ -1,25 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "# TODO: this table should have a column `part` with values 1..5,\n# but such data declaration is not yet supported, see #286\nlet parts = (\n from seq_1_to_5\n)\n\nfrom pl=prospect_lists_prospects\nfilter prospect_list_id == 'cc675eee-8bd1-237f-be5e-622ba511d65e'\njoin a=accounts [a.id == pl.related_id]\njoin er=email_addr_bean_rel [er.bean_id == a.id and er.primary_address == '1']\njoin ea=email_addresses [ea.id == er.email_address_id]\nselect ea.email_address\nderive prefix = s\"regexp_replace(SUBSTRING_INDEX({email_address}, '@', 1), '[.0-9-_:]+', '.')\"\nderive stub = s\"SUBSTRING_INDEX(SUBSTRING_INDEX({prefix}, '.', part), '.', -1)\"\nselect [email_address, stub]\n" ---- -let parts = ( - from seq_1_to_5 -) - - - -from pl = prospect_lists_prospects -filter prospect_list_id == "cc675eee-8bd1-237f-be5e-622ba511d65e" -join a = accounts [a.id == pl.related_id] -join er = email_addr_bean_rel [er.bean_id == a.id and er.primary_address == "1"] -join ea = email_addresses [ea.id == er.email_address_id] -select ea.email_address -derive prefix = s"regexp_replace(SUBSTRING_INDEX({email_address}, '@', 1), '[.0-9-_:]+', '.')" -derive stub = s"SUBSTRING_INDEX(SUBSTRING_INDEX({prefix}, '.', part), '.', -1)" -select [ - email_address, - stub, -] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__examples__misc-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__examples__misc-1.prql.snap deleted file mode 100644 index 50dcca896ea5..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__examples__misc-1.prql.snap +++ /dev/null @@ -1,12 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from club_ratings\nfilter rating != null\n# TODO: this is real ugly. `average rating` should not require parenthesis\n# TODO: why cannot we put comments in group's pipeline?\ngroup year (\n derive [rating_norm = rating - (average rating) / (stddev rating)]\n)\n" ---- -from club_ratings -filter rating != null -group year ( - derive [rating_norm = rating - ( average rating ) / ( stddev rating )] -) - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__examples__variables-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__examples__variables-0.prql.snap deleted file mode 100644 index 4b1f4fce84c1..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__examples__variables-0.prql.snap +++ /dev/null @@ -1,31 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nfilter country == \"USA\" # Each line transforms the previous result.\nderive [ # This adds columns / variables.\n gross_salary = salary + payroll_tax,\n gross_cost = gross_salary + benefits_cost # Variables can use other variables.\n]\nfilter gross_cost > 0\ngroup [title, country] ( # For each group use a nested pipeline\n aggregate [ # Aggregate each group to a single row\n average salary,\n average gross_salary,\n sum salary,\n sum gross_salary,\n average gross_cost,\n sum_gross_cost = sum gross_cost,\n ct = count,\n ]\n)\nsort sum_gross_cost\nfilter ct > 200\ntake 20\n" ---- -from employees -filter country == "USA" -derive [ - gross_salary = salary + payroll_tax, - gross_cost = gross_salary + benefits_cost, -] -filter gross_cost > 0 -group [ - title, - country, -] ( - aggregate [ - average salary, - average gross_salary, - sum salary, - sum gross_salary, - average gross_cost, - sum_gross_cost = sum gross_cost, - ct = count, -] -) -sort sum_gross_cost -filter ct > 200 -take 20 - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__examples__variables-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__examples__variables-1.prql.snap deleted file mode 100644 index cfb45e96a801..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__examples__variables-1.prql.snap +++ /dev/null @@ -1,18 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\ngroup [emp_no] (\n aggregate [\n emp_salary = average salary # average salary resolves to \"AVG(salary)\" (from stdlib)\n ]\n)\njoin titles [==emp_no]\ngroup [title] (\n aggregate [\n avg_salary = average emp_salary\n ]\n)\nselect salary_k = avg_salary / 1000 # avg_salary should resolve to \"AVG(emp_salary)\"\ntake 10 # induces new SELECT\nderive salary = salary_k * 1000 # salary_k should not resolve to \"avg_salary / 1000\"\n" ---- -from employees -group [emp_no] ( - aggregate [emp_salary = average salary] -) -join titles [==emp_no] -group [title] ( - aggregate [avg_salary = average emp_salary] -) -select salary_k = avg_salary / 1000 -take 10 -derive salary = salary_k * 1000 - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-0.prql.snap deleted file mode 100644 index 1bd2d905e16d..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-0.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nfilter age > 50\nsort name\n" ---- -from employees -filter age > 50 -sort name - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-1.prql.snap deleted file mode 100644 index da4b761a9e4b..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-1.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees | filter age > 50 | sort name\n" ---- -from employees -filter age > 50 -sort name - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-2.prql.snap deleted file mode 100644 index 7da897d0dd14..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-2.prql.snap +++ /dev/null @@ -1,11 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "filter age > 50 (from employees) | sort name\n" ---- -filter age > 50 ( - from employees -) -sort name - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-3.prql.snap b/book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-3.prql.snap deleted file mode 100644 index 045c663815a8..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__internals__functional-lang-3.prql.snap +++ /dev/null @@ -1,12 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "sort name (filter age > 50 (from employees))\n" ---- -sort name ( - filter age > 50 ( - from employees -) -) - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__internals__name-resolving-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__internals__name-resolving-0.prql.snap deleted file mode 100644 index 56e49df27e11..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__internals__name-resolving-0.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nselect first_name\n" ---- -from employees -select first_name - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__internals__name-resolving-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__internals__name-resolving-1.prql.snap deleted file mode 100644 index a9d9e5bada6d..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__internals__name-resolving-1.prql.snap +++ /dev/null @@ -1,17 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nderive [first_name, dept_id]\njoin d=departments [==dept_id]\nselect [first_name, d.title]\n" ---- -from employees -derive [ - first_name, - dept_id, -] -join d = departments [==dept_id] -select [ - first_name, - d.title, -] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__introduction-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__introduction-0.prql.snap deleted file mode 100644 index 96f55b8ab057..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__introduction-0.prql.snap +++ /dev/null @@ -1,31 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nfilter start_date > @2021-01-01 # Clear date syntax\nderive [ # `derive` adds columns / variables\n gross_salary = salary + (tax ?? 0), # Terse coalesce\n gross_cost = gross_salary + benefits_cost, # Variables can use other variables\n]\nfilter gross_cost > 0\ngroup [title, country] ( # `group` runs a pipeline over each group\n aggregate [ # `aggregate` reduces each group to a value\n average gross_salary,\n sum_gross_cost = sum gross_cost, # `=` sets a column name\n ]\n)\nfilter sum_gross_cost > 100_000 # `filter` replaces both of SQL's `WHERE` & `HAVING`\nderive id = f\"{title}_{country}\" # F-strings like Python\nderive country_code = s\"LEFT(country, 2)\" # S-strings allow using SQL as an escape hatch\nsort [sum_gross_cost, -country] # `-country` means descending order\ntake 1..20 # Range expressions (also valid here as `take 20`)\n" ---- -from employees -filter start_date > @2021-01-01 -derive [ - gross_salary = salary + tax ?? 0, - gross_cost = gross_salary + benefits_cost, -] -filter gross_cost > 0 -group [ - title, - country, -] ( - aggregate [ - average gross_salary, - sum_gross_cost = sum gross_cost, -] -) -filter sum_gross_cost > 100000 -derive id = f"{title}_{country}" -derive country_code = s"LEFT(country, 2)" -sort [ - sum_gross_cost, - -country, -] -take 1..20 - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__coalesce-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__coalesce-0.prql.snap deleted file mode 100644 index 24ff749cfbc8..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__coalesce-0.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from orders\nderive amount ?? 0\n" ---- -from orders -derive amount ?? 0 - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-0.prql.snap deleted file mode 100644 index acb71c71fc9a..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-0.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nderive age_at_year_end = (@2022-12-31 - dob)\n" ---- -from employees -derive age_at_year_end = @2022-12-31 - dob - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-1.prql.snap deleted file mode 100644 index fd2fe52b3f6c..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-1.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from orders\nderive should_have_shipped_today = (order_time < @08:30)\n" ---- -from orders -derive should_have_shipped_today = order_time < @08:30 - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-2.prql.snap deleted file mode 100644 index a2f42142ebb6..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-2.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from commits\nderive first_prql_commit = @2020-01-01T13:19:55-08:00\n" ---- -from commits -derive first_prql_commit = @2020-01-01T13:19:55-08:00 - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-3.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-3.prql.snap deleted file mode 100644 index 70ac66f365a2..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__dates-and-times-3.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from projects\nderive first_check_in = start + 10days\n" ---- -from projects -derive first_check_in = start + 10days - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__distinct-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__distinct-0.prql.snap deleted file mode 100644 index 7929401e23b6..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__distinct-0.prql.snap +++ /dev/null @@ -1,12 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nselect department\ngroup department (\n take 1\n)\n" ---- -from employees -select department -group department ( - take 1 -) - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__distinct-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__distinct-1.prql.snap deleted file mode 100644 index 22ba087f087c..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__distinct-1.prql.snap +++ /dev/null @@ -1,12 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nselect department\ngroup department (take 1)\n" ---- -from employees -select department -group department ( - take 1 -) - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__distinct-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__distinct-2.prql.snap deleted file mode 100644 index ceb0035e6601..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__distinct-2.prql.snap +++ /dev/null @@ -1,12 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "# youngest employee from each department\nfrom employees\ngroup department (\n sort age\n take 1\n)\n" ---- -from employees -group department ( - sort age - take 1 -) - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__f-strings-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__f-strings-0.prql.snap deleted file mode 100644 index 5f490aa52f00..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__f-strings-0.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nselect full_name = f\"{first_name} {last_name}\"\n" ---- -from employees -select full_name = f"{first_name} {last_name}" - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__f-strings-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__f-strings-1.prql.snap deleted file mode 100644 index f00e2becbab2..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__f-strings-1.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from web\nselect url = f\"http{tls}://www.{domain}.{tld}/{page}\"\n" ---- -from web -select url = f"http{tls}://www.{domain}.{tld}/{page}" - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__null-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__null-0.prql.snap deleted file mode 100644 index 73594522238f..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__null-0.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nfilter first_name == null\nfilter null != last_name\n" ---- -from employees -filter first_name == null -filter null != last_name - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__ranges-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__ranges-0.prql.snap deleted file mode 100644 index 2d5baa98ae2d..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__ranges-0.prql.snap +++ /dev/null @@ -1,20 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from events\nfilter (date | in @1776-07-04..@1787-09-17)\nfilter (magnitude | in 50..100)\nderive is_northern = (latitude | in 0..)\n" ---- -from events -filter ( - date - in @1776-07-04..@1787-09-17 -) -filter ( - magnitude - in 50..100 -) -derive is_northern = ( - latitude - in 0.. -) - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__ranges-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__ranges-1.prql.snap deleted file mode 100644 index b68c1920a669..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__ranges-1.prql.snap +++ /dev/null @@ -1,13 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from orders\nsort [-value, date]\ntake 101..110\n" ---- -from orders -sort [ - -value, - date, -] -take 101..110 - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-0.prql.snap deleted file mode 100644 index 12abfcc2518c..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-0.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from my_table\nselect db_version = s\"version()\"\n" ---- -from my_table -select db_version = s"version()" - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-1.prql.snap deleted file mode 100644 index c57ed2561d58..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-1.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\naggregate [average salary]\n" ---- -from employees -aggregate [average salary] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-2.prql.snap deleted file mode 100644 index e28b7f46ed0a..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-2.prql.snap +++ /dev/null @@ -1,14 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from de=dept_emp\njoin s=salaries side:left [\n (s.emp_no == de.emp_no),\n s\"\"\"({s.from_date}, {s.to_date})\n OVERLAPS\n ({de.from_date}, {de.to_date})\"\"\"\n]\n" ---- -from de = dept_emp -join side:left s = salaries [ - s.emp_no == de.emp_no, - s"({s.from_date}, {s.to_date}) - OVERLAPS - ({de.from_date}, {de.to_date})", -] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-3.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-3.prql.snap deleted file mode 100644 index 2cb93849dda8..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-3.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from s\"SELECT DISTINCT ON first_name, id, age FROM employees ORDER BY age ASC\"\njoin s = s\"SELECT * FROM salaries\" [==id]\n" ---- -from s"SELECT DISTINCT ON first_name, id, age FROM employees ORDER BY age ASC" -join s = s"SELECT * FROM salaries" [==id] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-4.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-4.prql.snap deleted file mode 100644 index 00c1d5e17349..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-4.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nderive [\n has_valid_title = s\"regexp_contains(title, '([a-z0-9]*-){{2,}}')\"\n]\n" ---- -from employees -derive [has_valid_title = s"regexp_contains(title, '([a-z0-9]*-){2,}')"] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-5.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-5.prql.snap deleted file mode 100644 index 9bd3b0d3fe16..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-5.prql.snap +++ /dev/null @@ -1,12 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nderive [\n gross_salary = salary + benefits,\n daily_rate = s\"{gross_salary} / 365\"\n]\n" ---- -from employees -derive [ - gross_salary = salary + benefits, - daily_rate = s"{gross_salary} / 365", -] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-6.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-6.prql.snap deleted file mode 100644 index 3dc30b6885ae..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__s-strings-6.prql.snap +++ /dev/null @@ -1,12 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nderive [\n gross_salary = salary + benefits,\n daily_rate = s\"({gross_salary}) / 365\"\n]\n" ---- -from employees -derive [ - gross_salary = salary + benefits, - daily_rate = s"({gross_salary}) / 365", -] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__standard-library__README-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__standard-library__README-0.prql.snap deleted file mode 100644 index 011d5f416c47..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__standard-library__README-0.prql.snap +++ /dev/null @@ -1,19 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nderive [\n gross_salary = (salary + payroll_tax | as int),\n gross_salary_rounded = (gross_salary | round 0),\n time = s\"NOW()\", # an s-string, given no `now` function exists in PRQL\n]\n" ---- -from employees -derive [ - gross_salary = ( - salary + payroll_tax - as int -), - gross_salary_rounded = ( - gross_salary - round 0 -), - time = s"NOW()", -] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__standard-library__from-text-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__standard-library__from-text-0.prql.snap deleted file mode 100644 index 6a730d3a1f7e..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__standard-library__from-text-0.prql.snap +++ /dev/null @@ -1,16 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from_text \"\"\"\na,b,c\n1,2,3\n4,5,6\n\"\"\"\nderive [\n d = b + c,\n answer = 20 * 2 + 2,\n]\n" ---- -from_text " -a,b,c -1,2,3 -4,5,6 -" -derive [ - d = b + c, - answer = 20 * 2 + 2, -] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__standard-library__from-text-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__standard-library__from-text-1.prql.snap deleted file mode 100644 index 6f9f848bbd6e..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__standard-library__from-text-1.prql.snap +++ /dev/null @@ -1,21 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "let temp_format_lookup = from_text format:csv \"\"\"\ncountry_code,format\nuk,C\nus,F\nlr,F\nde,C\n\"\"\"\n\nfrom temperatures\njoin temp_format_lookup [==country_code]\n" ---- -let temp_format_lookup = ( - from_text format:csv " -country_code,format -uk,C -us,F -lr,F -de,C -" -) - - - -from temperatures -join temp_format_lookup [==country_code] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__standard-library__from-text-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__standard-library__from-text-2.prql.snap deleted file mode 100644 index da17c3b1fe6f..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__standard-library__from-text-2.prql.snap +++ /dev/null @@ -1,32 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "let x = from_text format:json \"\"\"{\n \"columns\": [\"a\", \"b\", \"c\"],\n \"data\": [\n [1, \"x\", false],\n [4, \"y\", null]\n ]\n}\"\"\"\n\nlet y = from_text format:json \"\"\"\n [\n {\"a\": 1, \"m\": \"5\"},\n {\"a\": 4, \"n\": \"6\"}\n ]\n\"\"\"\n\nfrom x | join y [==a]\n" ---- -let x = ( - from_text format:json '{ - "columns": ["a", "b", "c"], - "data": [ - [1, "x", false], - [4, "y", null] - ] -}' -) - - - -let y = ( - from_text format:json ' - [ - {"a": 1, "m": "5"}, - {"a": 4, "n": "6"} - ] -' -) - - - -from x -join y [==a] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__standard-library__loop-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__standard-library__loop-0.prql.snap deleted file mode 100644 index 0c143248892b..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__standard-library__loop-0.prql.snap +++ /dev/null @@ -1,12 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from_text format:json '[{\"n\": 1 }]'\nloop (\n filter n<4\n select n = n+1\n)\n\n# returns [1, 2, 3, 4]\n" ---- -from_text format:json '[{"n": 1 }]' -loop ( - filter n < 4 - select n = n + 1 -) - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__strings-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__strings-0.prql.snap deleted file mode 100644 index 6a1d79036036..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__strings-0.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from my_table\nselect x = \"hello world\"\n" ---- -from my_table -select x = "hello world" - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__strings-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__strings-1.prql.snap deleted file mode 100644 index 2da7a07937de..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__strings-1.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from my_table\nselect x = 'hello world'\n" ---- -from my_table -select x = "hello world" - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__strings-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__strings-2.prql.snap deleted file mode 100644 index 8d79cd8cedbc..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__strings-2.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from my_table\nselect x = '\"hello world\"'\n" ---- -from my_table -select x = '"hello world"' - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__strings-3.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__strings-3.prql.snap deleted file mode 100644 index a681bc62a036..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__strings-3.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from my_table\nselect x = \"\"\"I said \"hello world\"!\"\"\"\n" ---- -from my_table -select x = 'I said "hello world"!' - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__strings-4.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__strings-4.prql.snap deleted file mode 100644 index 0bae3f836774..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__strings-4.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from my_table\nselect x = \"\"\"\"\"I said \"\"\"hello world\"\"\"!\"\"\"\"\"\n" ---- -from my_table -select x = 'I said """hello world"""!' - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__strings-5.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__strings-5.prql.snap deleted file mode 100644 index 4a0b8ddabd77..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__strings-5.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from my_table\nselect x = \"\\t\\tline ends here\\n \\\\ \"\n" ---- -from my_table -select x = " line ends here - \ " - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__switch-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__switch-0.prql.snap deleted file mode 100644 index 7618b9e71723..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__switch-0.prql.snap +++ /dev/null @@ -1,12 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nderive distance = switch [\n city == \"Calgary\" -> 0,\n city == \"Edmonton\" -> 300,\n]\n" ---- -from employees -derive distance = switch [ - city == "Calgary" => 0 - city == "Edmonton" => 300 -] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__switch-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__switch-1.prql.snap deleted file mode 100644 index f9ee3312b92b..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__switch-1.prql.snap +++ /dev/null @@ -1,13 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nderive distance = switch [\n city == \"Calgary\" -> 0,\n city == \"Edmonton\" -> 300,\n true -> \"Unknown\",\n]\n" ---- -from employees -derive distance = switch [ - city == "Calgary" => 0 - city == "Edmonton" => 300 - true => "Unknown" -] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__target-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__target-0.prql.snap deleted file mode 100644 index b22539422ae4..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__target-0.prql.snap +++ /dev/null @@ -1,14 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "prql target:sql.postgres\n\nfrom employees\nsort age\ntake 10\n" ---- -prql target:sql.postgres - - - -from employees -sort age -take 10 - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__target-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__target-1.prql.snap deleted file mode 100644 index ed7e10fd7388..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__target-1.prql.snap +++ /dev/null @@ -1,14 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "prql target:sql.mssql\n\nfrom employees\nsort age\ntake 10\n" ---- -prql target:sql.mssql - - - -from employees -sort age -take 10 - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__language-features__target-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__language-features__target-2.prql.snap deleted file mode 100644 index b05787ed8bae..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__language-features__target-2.prql.snap +++ /dev/null @@ -1,12 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "prql version:\"0.5\"\n\nfrom employees\n" ---- -prql version:^0.5 - - - -from employees - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__queries__functions-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__queries__functions-0.prql.snap deleted file mode 100644 index e5bb0a64491b..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__queries__functions-0.prql.snap +++ /dev/null @@ -1,15 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "func fahrenheit_to_celsius temp -> (temp - 32) / 1.8\n\nfrom cities\nderive temp_c = (fahrenheit_to_celsius temp_f)\n" ---- -func fahrenheit_to_celsius temp -> temp - 32 / 1.8 - - - -from cities -derive ( - temp_c = fahrenheit_to_celsius temp_f -) - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__queries__functions-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__queries__functions-1.prql.snap deleted file mode 100644 index a8dfd8b7401d..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__queries__functions-1.prql.snap +++ /dev/null @@ -1,16 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "func interp low:0 high x -> (x - low) / (high - low)\n\nfrom students\nderive [\n sat_proportion_1 = (interp 1600 sat_score),\n sat_proportion_2 = (interp low:0 1600 sat_score),\n]\n" ---- -func interp high x low:0 -> x - low / high - low - - - -from students -derive [ - sat_proportion_1 = interp 1600 sat_score, - sat_proportion_2 = interp low:0 1600 sat_score, -] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__queries__functions-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__queries__functions-2.prql.snap deleted file mode 100644 index 62b10ce1ebc0..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__queries__functions-2.prql.snap +++ /dev/null @@ -1,22 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "func interp low:0 high x -> (x - low) / (high - low)\n\nfrom students\nderive [\n sat_proportion_1 = (sat_score | interp 1600),\n sat_proportion_2 = (sat_score | interp low:0 1600),\n]\n" ---- -func interp high x low:0 -> x - low / high - low - - - -from students -derive [ - sat_proportion_1 = ( - sat_score - interp 1600 -), - sat_proportion_2 = ( - sat_score - interp low:0 1600 -), -] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__queries__functions-3.prql.snap b/book/tests/snapshots/snapshot__tests__prql__queries__functions-3.prql.snap deleted file mode 100644 index bc1453813dc9..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__queries__functions-3.prql.snap +++ /dev/null @@ -1,16 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "func fahrenheit_to_celsius temp -> (temp - 32) / 1.8\n\nfrom cities\nderive temp_c = (temp_f | fahrenheit_to_celsius)\n" ---- -func fahrenheit_to_celsius temp -> temp - 32 / 1.8 - - - -from cities -derive temp_c = ( - temp_f - fahrenheit_to_celsius -) - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__queries__functions-4.prql.snap b/book/tests/snapshots/snapshot__tests__prql__queries__functions-4.prql.snap deleted file mode 100644 index 4ad7a7528df5..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__queries__functions-4.prql.snap +++ /dev/null @@ -1,21 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "func fahrenheit_to_celsius temp -> (temp - 32) / 1.8\nfunc interp low:0 high x -> (x - low) / (high - low)\n\nfrom kettles\nderive boiling_proportion = (temp_c | fahrenheit_to_celsius | interp 100)\n" ---- -func fahrenheit_to_celsius temp -> temp - 32 / 1.8 - - - -func interp high x low:0 -> x - low / high - low - - - -from kettles -derive boiling_proportion = ( - temp_c - fahrenheit_to_celsius - interp 100 -) - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__queries__functions-5.prql.snap b/book/tests/snapshots/snapshot__tests__prql__queries__functions-5.prql.snap deleted file mode 100644 index 4f4e9a5a8d3b..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__queries__functions-5.prql.snap +++ /dev/null @@ -1,23 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "func cost_share cost -> cost / cost_total\n\nfrom costs\nselect [materials, labor, overhead, cost_total]\nderive [\n materials_share = (cost_share materials),\n labor_share = (cost_share labor),\n overhead_share = (cost_share overhead),\n]\n" ---- -func cost_share cost -> cost / cost_total - - - -from costs -select [ - materials, - labor, - overhead, - cost_total, -] -derive [ - materials_share = cost_share materials, - labor_share = cost_share labor, - overhead_share = cost_share overhead, -] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__queries__pipelines-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__queries__pipelines-0.prql.snap deleted file mode 100644 index 8ef6dce0bb66..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__queries__pipelines-0.prql.snap +++ /dev/null @@ -1,8 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\n" ---- -from employees - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__queries__pipelines-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__queries__pipelines-1.prql.snap deleted file mode 100644 index b2b18409f03a..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__queries__pipelines-1.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nderive gross_salary = (salary + payroll_tax)\n" ---- -from employees -derive gross_salary = salary + payroll_tax - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__queries__pipelines-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__queries__pipelines-2.prql.snap deleted file mode 100644 index 5c74bd2eeb81..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__queries__pipelines-2.prql.snap +++ /dev/null @@ -1,17 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from e = employees\nderive gross_salary = (salary + payroll_tax)\nsort gross_salary\ntake 10\njoin d = department [==dept_no]\nselect [e.name, gross_salary, d.name]\n" ---- -from e = employees -derive gross_salary = salary + payroll_tax -sort gross_salary -take 10 -join d = department [==dept_no] -select [ - e.name, - gross_salary, - d.name, -] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__queries__variables-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__queries__variables-0.prql.snap deleted file mode 100644 index 3c4edace1010..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__queries__variables-0.prql.snap +++ /dev/null @@ -1,17 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "let top_50 = (\n from employees\n sort salary\n take 50\n aggregate [total_salary = sum salary]\n)\n\nfrom top_50 # Starts a new pipeline\n" ---- -let top_50 = ( - from employees - sort salary - take 50 - aggregate [total_salary = sum salary] -) - - - -from top_50 - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__queries__variables-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__queries__variables-1.prql.snap deleted file mode 100644 index dd72ddc9b4bb..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__queries__variables-1.prql.snap +++ /dev/null @@ -1,18 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "let grouping = s\"\"\"\n SELECT SUM(a)\n FROM tbl\n GROUP BY\n GROUPING SETS\n ((b, c, d), (d), (b, d))\n\"\"\"\n\nfrom grouping\n" ---- -let grouping = s" - SELECT SUM(a) - FROM tbl - GROUP BY - GROUPING SETS - ((b, c, d), (d), (b, d)) -" - - - -from grouping - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__syntax-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-0.prql.snap deleted file mode 100644 index ee78d7a29c00..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__syntax-0.prql.snap +++ /dev/null @@ -1,13 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nfilter department == \"Product\"\nselect [first_name, last_name]\n" ---- -from employees -filter department == "Product" -select [ - first_name, - last_name, -] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__syntax-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-1.prql.snap deleted file mode 100644 index ae9d7fcbb81c..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__syntax-1.prql.snap +++ /dev/null @@ -1,13 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees | filter department == \"Product\" | select [first_name, last_name]\n" ---- -from employees -filter department == "Product" -select [ - first_name, - last_name, -] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__syntax-10.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-10.prql.snap deleted file mode 100644 index 19c4de64822f..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__syntax-10.prql.snap +++ /dev/null @@ -1,13 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "prql target:sql.mysql\nfrom employees\nselect `first name`\n" ---- -prql target:sql.mysql - - - -from employees -select `first name` - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__syntax-11.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-11.prql.snap deleted file mode 100644 index 0ef6f6c5ea4e..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__syntax-11.prql.snap +++ /dev/null @@ -1,13 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "prql target:sql.postgres\nfrom employees\nselect `first name`\n" ---- -prql target:sql.postgres - - - -from employees -select `first name` - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__syntax-12.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-12.prql.snap deleted file mode 100644 index acd1651bdbb9..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__syntax-12.prql.snap +++ /dev/null @@ -1,8 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from `dir/*.parquet`\n" ---- -from `dir/*.parquet` - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__syntax-13.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-13.prql.snap deleted file mode 100644 index 6be462d1cb08..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__syntax-13.prql.snap +++ /dev/null @@ -1,13 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "prql target:sql.bigquery\nfrom `project-foo.dataset.table`\njoin `project-bar.dataset.table` [==col_bax]\n" ---- -prql target:sql.bigquery - - - -from `project-foo.dataset.table` -join `project-bar.dataset.table` [==col_bax] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__syntax-14.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-14.prql.snap deleted file mode 100644 index fc9310bcceea..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__syntax-14.prql.snap +++ /dev/null @@ -1,8 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from `music.albums`\n" ---- -from `music.albums` - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__syntax-15.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-15.prql.snap deleted file mode 100644 index 4e250a9bf506..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__syntax-15.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nfilter id == $1\n" ---- -from employees -filter id == $1 - - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__syntax-16.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-16.prql.snap deleted file mode 100644 index 7aa2caf4c217..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__syntax-16.prql.snap +++ /dev/null @@ -1,12 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from numbers\nselect [\n small = 1.000_000_1,\n big = 5_000_000,\n]\n" ---- -from numbers -select [ - small = 1.0000001, - big = 5000000, -] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__syntax-17.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-17.prql.snap deleted file mode 100644 index ddc2d6ddb49a..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__syntax-17.prql.snap +++ /dev/null @@ -1,13 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "std.from my_table\nstd.select [from = my_table.a, take = my_table.b]\nstd.take 3\n" ---- -std.from my_table -std.select [ - from = my_table.a, - take = my_table.b, -] -std.take 3 - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__syntax-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-2.prql.snap deleted file mode 100644 index a12652162d23..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__syntax-2.prql.snap +++ /dev/null @@ -1,20 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from numbers\nderive [x = 1, y = 2]\nderive [\n a = x,\n b = y\n]\nderive [\n c = a,\n d = b,\n]\n" ---- -from numbers -derive [ - x = 1, - y = 2, -] -derive [ - a = x, - b = y, -] -derive [ - c = a, - d = b, -] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__syntax-3.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-3.prql.snap deleted file mode 100644 index 4077d71aaa9b..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__syntax-3.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nselect [first_name]\n" ---- -from employees -select [first_name] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__syntax-4.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-4.prql.snap deleted file mode 100644 index 56e49df27e11..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__syntax-4.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nselect first_name\n" ---- -from employees -select first_name - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__syntax-5.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-5.prql.snap deleted file mode 100644 index 027e1a5e000f..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__syntax-5.prql.snap +++ /dev/null @@ -1,13 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from foo\nselect [\n circumference = diameter * 3.14159,\n color,\n]\nfilter circumference > 10 and color != \"red\"\n" ---- -from foo -select [ - circumference = diameter * 3.14159, - color, -] -filter circumference > 10 and color != "red" - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__syntax-6.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-6.prql.snap deleted file mode 100644 index b9f326d968cc..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__syntax-6.prql.snap +++ /dev/null @@ -1,39 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\n# Requires parentheses, because it's contains a pipe\nderive is_proximate = (distance | in 0..20)\n# Requires parentheses, because it's a function call\nderive total_distance = (sum distance)\n# `??` doesn't require parentheses, as it's not a function call\nderive min_capped_distance = (min distance ?? 5)\n# No parentheses needed, because no function call\nderive travel_time = distance / 40\n# No inner parentheses needed around `1+1` because no function call\nderive distance_rounded_2_dp = (round 1+1 distance)\nderive [\n # Requires parentheses, because it contains a pipe\n is_far = (distance | in 100..),\n # The left value of the range requires parentheses,\n # because of the minus sign\n is_negative = (distance | in (-100..0)),\n # ...this is equivalent\n is_negative = (distance | in (-100)..0),\n # Doesn't require parentheses, because it's in a list (confusing, see footnote)!\n average_distance = average distance,\n]\n# Requires parentheses because of the minus sign\nsort (-distance)\n# A list is fine too\nsort [-distance]\n" ---- -from employees -derive is_proximate = ( - distance - in 0..20 -) -derive ( - total_distance = sum distance -) -derive ( - min_capped_distance = min distance ?? 5 -) -derive travel_time = distance / 40 -derive ( - distance_rounded_2_dp = round 1 + 1 distance -) -derive [ - is_far = ( - distance - in 100.. -), - is_negative = ( - distance - in -100..0 -), - is_negative = ( - distance - in -100..0 -), - average_distance = average distance, -] -sort -distance -sort [-distance] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__syntax-7.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-7.prql.snap deleted file mode 100644 index 87ed02336d92..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__syntax-7.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nderive total_distance = sum distance\n" ---- -from employees -derive total_distance = sum distance - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__syntax-8.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-8.prql.snap deleted file mode 100644 index 81e0a3146955..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__syntax-8.prql.snap +++ /dev/null @@ -1,17 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\ngroup [title, country] (\n aggregate [\n average salary,\n ct = count\n ]\n)\n" ---- -from employees -group [ - title, - country, -] ( - aggregate [ - average salary, - ct = count, -] -) - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__syntax-9.prql.snap b/book/tests/snapshots/snapshot__tests__prql__syntax-9.prql.snap deleted file mode 100644 index 4f94033b1f86..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__syntax-9.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees # Comment 1\n# Comment 2\naggregate [average salary]\n" ---- -from employees -aggregate [average salary] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__aggregate-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__aggregate-0.prql.snap deleted file mode 100644 index 1c202ec4ba25..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__aggregate-0.prql.snap +++ /dev/null @@ -1,12 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\naggregate [\n average salary,\n ct = count\n]\n" ---- -from employees -aggregate [ - average salary, - ct = count, -] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__aggregate-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__aggregate-1.prql.snap deleted file mode 100644 index 81e0a3146955..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__aggregate-1.prql.snap +++ /dev/null @@ -1,17 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\ngroup [title, country] (\n aggregate [\n average salary,\n ct = count\n ]\n)\n" ---- -from employees -group [ - title, - country, -] ( - aggregate [ - average salary, - ct = count, -] -) - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__aggregate-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__aggregate-2.prql.snap deleted file mode 100644 index 9b49b51df2a5..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__aggregate-2.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nderive [avg_sal = average salary]\n" ---- -from employees -derive [avg_sal = average salary] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__append-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__append-0.prql.snap deleted file mode 100644 index cbbd0478001b..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__append-0.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees_1\nappend employees_2\n" ---- -from employees_1 -append employees_2 - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__append-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__append-1.prql.snap deleted file mode 100644 index e2b9a1338479..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__append-1.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees_1\nremove employees_2\n" ---- -from employees_1 -remove employees_2 - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__append-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__append-2.prql.snap deleted file mode 100644 index 1971d287b890..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__append-2.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees_1\nintersect employees_2\n" ---- -from employees_1 -intersect employees_2 - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__derive-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__derive-0.prql.snap deleted file mode 100644 index 183b59f98112..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__derive-0.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nderive gross_salary = salary + payroll_tax\n" ---- -from employees -derive gross_salary = salary + payroll_tax - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__derive-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__derive-1.prql.snap deleted file mode 100644 index 3d298b6f9b55..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__derive-1.prql.snap +++ /dev/null @@ -1,12 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nderive [\n gross_salary = salary + payroll_tax,\n gross_cost = gross_salary + benefits_cost\n]\n" ---- -from employees -derive [ - gross_salary = salary + payroll_tax, - gross_cost = gross_salary + benefits_cost, -] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__filter-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__filter-0.prql.snap deleted file mode 100644 index bd5e2c425e25..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__filter-0.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nfilter age > 25\n" ---- -from employees -filter age > 25 - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__filter-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__filter-1.prql.snap deleted file mode 100644 index a6cb5b5b569e..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__filter-1.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nfilter (age > 25 or department != \"IT\")\n" ---- -from employees -filter age > 25 or department != "IT" - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__filter-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__filter-2.prql.snap deleted file mode 100644 index d3b04cd4de31..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__filter-2.prql.snap +++ /dev/null @@ -1,12 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nfilter (age | in 25..40)\n" ---- -from employees -filter ( - age - in 25..40 -) - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__from-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__from-0.prql.snap deleted file mode 100644 index 8ef6dce0bb66..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__from-0.prql.snap +++ /dev/null @@ -1,8 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\n" ---- -from employees - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__from-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__from-1.prql.snap deleted file mode 100644 index ef1312a86941..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__from-1.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from e = employees\nselect e.first_name\n" ---- -from e = employees -select e.first_name - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__group-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__group-0.prql.snap deleted file mode 100644 index 81e0a3146955..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__group-0.prql.snap +++ /dev/null @@ -1,17 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\ngroup [title, country] (\n aggregate [\n average salary,\n ct = count\n ]\n)\n" ---- -from employees -group [ - title, - country, -] ( - aggregate [ - average salary, - ct = count, -] -) - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__group-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__group-1.prql.snap deleted file mode 100644 index 2517396a1418..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__group-1.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nsort join_date\ntake 1\n" ---- -from employees -sort join_date -take 1 - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__group-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__group-2.prql.snap deleted file mode 100644 index 11467687bbbb..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__group-2.prql.snap +++ /dev/null @@ -1,12 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\ngroup role (\n sort join_date # taken from above\n take 1\n)\n" ---- -from employees -group role ( - sort join_date - take 1 -) - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__join-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__join-0.prql.snap deleted file mode 100644 index 4d113382409a..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__join-0.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\njoin side:left positions [employees.id==positions.employee_id]\n" ---- -from employees -join side:left positions [employees.id == positions.employee_id] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__join-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__join-1.prql.snap deleted file mode 100644 index b3e13a1d23f8..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__join-1.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\njoin side:left p=positions [employees.id==p.employee_id]\n" ---- -from employees -join side:left p = positions [employees.id == p.employee_id] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__join-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__join-2.prql.snap deleted file mode 100644 index ba833fa01b02..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__join-2.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\njoin positions [==emp_no]\n" ---- -from employees -join positions [==emp_no] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__select-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__select-0.prql.snap deleted file mode 100644 index ef3e65965333..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__select-0.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nselect name = f\"{first_name} {last_name}\"\n" ---- -from employees -select name = f"{first_name} {last_name}" - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__select-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__select-1.prql.snap deleted file mode 100644 index 57c345371217..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__select-1.prql.snap +++ /dev/null @@ -1,12 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nselect [\n name = f\"{first_name} {last_name}\",\n age_eoy = dob - @2022-12-31,\n]\n" ---- -from employees -select [ - name = f"{first_name} {last_name}", - age_eoy = dob - @2022-12-31, -] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__select-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__select-2.prql.snap deleted file mode 100644 index 56e49df27e11..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__select-2.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nselect first_name\n" ---- -from employees -select first_name - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__select-3.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__select-3.prql.snap deleted file mode 100644 index 059b92276754..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__select-3.prql.snap +++ /dev/null @@ -1,12 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from e=employees\nselect [e.first_name, e.last_name]\n" ---- -from e = employees -select [ - e.first_name, - e.last_name, -] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__select-4.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__select-4.prql.snap deleted file mode 100644 index 6445588450d2..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__select-4.prql.snap +++ /dev/null @@ -1,16 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "prql target:sql.bigquery\nfrom tracks\nselect ![milliseconds,bytes]\n" ---- -prql target:sql.bigquery - - - -from tracks -select not [ - milliseconds, - bytes, -] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__select-5.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__select-5.prql.snap deleted file mode 100644 index 568bc821ba4f..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__select-5.prql.snap +++ /dev/null @@ -1,18 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from tracks\nselect [track_id, title, composer, bytes]\nselect ![title, composer]\n" ---- -from tracks -select [ - track_id, - title, - composer, - bytes, -] -select not [ - title, - composer, -] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__select-6.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__select-6.prql.snap deleted file mode 100644 index 19b65db61c48..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__select-6.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from artists\nderive nick = name\nselect ![artists.*]\n" ---- -from artists -derive nick = name -select not [artists.`*`] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__sort-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__sort-0.prql.snap deleted file mode 100644 index cb41ef4b5ddb..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__sort-0.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nsort age\n" ---- -from employees -sort age - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__sort-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__sort-1.prql.snap deleted file mode 100644 index 12203dcc78d3..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__sort-1.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nsort [-age]\n" ---- -from employees -sort [-age] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__sort-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__sort-2.prql.snap deleted file mode 100644 index a7ddb76e2ecc..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__sort-2.prql.snap +++ /dev/null @@ -1,13 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nsort [age, -tenure, +salary]\n" ---- -from employees -sort [ - age, - -tenure, - +salary, -] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__sort-3.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__sort-3.prql.snap deleted file mode 100644 index 01b0d75eb4e3..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__sort-3.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nsort [s\"substr({first_name}, 2, 5)\"]\n" ---- -from employees -sort [s"substr({first_name}, 2, 5)"] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__sort-4.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__sort-4.prql.snap deleted file mode 100644 index 51c71b587af5..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__sort-4.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nsort tenure\nderive name = f\"{first_name} {last_name}\"\n" ---- -from employees -sort tenure -derive name = f"{first_name} {last_name}" - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__sort-5.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__sort-5.prql.snap deleted file mode 100644 index 405c461df7e4..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__sort-5.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nsort tenure\njoin locations [==employee_id]\n" ---- -from employees -sort tenure -join locations [==employee_id] - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__take-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__take-0.prql.snap deleted file mode 100644 index 4c39e0cddcea..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__take-0.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\ntake 10\n" ---- -from employees -take 10 - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__take-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__take-1.prql.snap deleted file mode 100644 index b68c1920a669..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__take-1.prql.snap +++ /dev/null @@ -1,13 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from orders\nsort [-value, date]\ntake 101..110\n" ---- -from orders -sort [ - -value, - date, -] -take 101..110 - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__window-0.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__window-0.prql.snap deleted file mode 100644 index 08d6e23e2468..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__window-0.prql.snap +++ /dev/null @@ -1,14 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\ngroup employee_id (\n sort month\n window rolling:12 (\n derive [trail_12_m_comp = sum paycheck]\n )\n)\n" ---- -from employees -group employee_id ( - sort month - window rolling:12 ( - derive [trail_12_m_comp = sum paycheck] -) -) - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__window-1.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__window-1.prql.snap deleted file mode 100644 index c0663a94bc4a..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__window-1.prql.snap +++ /dev/null @@ -1,18 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from orders\nsort day\nwindow rows:-3..3 (\n derive [centered_weekly_average = average value]\n)\ngroup [order_month] (\n sort day\n window expanding:true (\n derive [monthly_running_total = sum value]\n )\n)\n" ---- -from orders -sort day -window rows:-3..3 ( - derive [centered_weekly_average = average value] -) -group [order_month] ( - sort day - window expanding:true ( - derive [monthly_running_total = sum value] -) -) - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__window-2.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__window-2.prql.snap deleted file mode 100644 index dc3037c993b3..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__window-2.prql.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nsort age\nderive rnk = rank\n" ---- -from employees -sort age -derive rnk = rank - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__window-3.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__window-3.prql.snap deleted file mode 100644 index b71455102a11..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__window-3.prql.snap +++ /dev/null @@ -1,12 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\ngroup department (\n sort age\n derive rnk = rank\n)\n" ---- -from employees -group department ( - sort age - derive rnk = rank -) - - - diff --git a/book/tests/snapshots/snapshot__tests__prql__transforms__window-4.prql.snap b/book/tests/snapshots/snapshot__tests__prql__transforms__window-4.prql.snap deleted file mode 100644 index 9e104fbe34a9..000000000000 --- a/book/tests/snapshots/snapshot__tests__prql__transforms__window-4.prql.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nfilter salary < (average salary)\n" ---- -from employees -filter salary < ( average salary ) - - - From 0d2ff48168344c1e9e4f4cd356c96e214c43ce08 Mon Sep 17 00:00:00 2001 From: eitsupi <50911393+eitsupi@users.noreply.github.com> Date: Mon, 6 Mar 2023 14:31:55 +0900 Subject: [PATCH 094/106] build: add definitions for devcontainer base image (#2025) * build: add definitions for devcontainer base image * build: split install-cargo-tools task to another Taskfile --- .devcontainer/base-image/Dockerfile | 15 +++++++ .github/dependabot.yml | 7 ++++ .github/workflows/devcontainer.yaml | 64 +++++++++++++++++++++++++++++ Taskfile.cargo-tools.yml | 19 +++++++++ Taskfile.yml | 20 ++++----- 5 files changed, 112 insertions(+), 13 deletions(-) create mode 100644 .devcontainer/base-image/Dockerfile create mode 100644 .github/workflows/devcontainer.yaml create mode 100644 Taskfile.cargo-tools.yml diff --git a/.devcontainer/base-image/Dockerfile b/.devcontainer/base-image/Dockerfile new file mode 100644 index 000000000000..00200fe5b006 --- /dev/null +++ b/.devcontainer/base-image/Dockerfile @@ -0,0 +1,15 @@ +FROM mcr.microsoft.com/devcontainers/rust:0.203.7-1 + +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + cmake \ + && rm -rf /var/lib/apt/lists/* \ + && sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d -b /usr/local/bin + +# ========= Install cargo-tools for non-root user (vscode) ========= +COPY Taskfile.cargo-tools.yml /tmp/Taskfile.cargo-tools.yml +WORKDIR /tmp +USER vscode +RUN task -t Taskfile.cargo-tools.yml install + +USER root diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 9037733798b9..cf0f85edf82a 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -29,6 +29,13 @@ updates: commit-message: prefix: "chore: " + - package-ecosystem: docker + directory: .devcontainer/base-image + schedule: + interval: daily + commit-message: + prefix: "chore: " + # For actions (rather than workflows), we need to list each directory, ref # https://github.com/dependabot/dependabot-core/issues/5137, from https://github.com/dependabot/dependabot-core/issues/4178#issuecomment-1118492006 - directory: ".github/actions/build-prql-js" diff --git a/.github/workflows/devcontainer.yaml b/.github/workflows/devcontainer.yaml new file mode 100644 index 000000000000..1b28019a4975 --- /dev/null +++ b/.github/workflows/devcontainer.yaml @@ -0,0 +1,64 @@ +name: devcontainer + +on: + push: + paths: + - .devcontainer/base-image/Dockerfile + - Taskfile.cargo-tools.yml + pull_request: + paths: + - .devcontainer/base-image/Dockerfile + - Taskfile.cargo-tools.yml + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }} + cancel-in-progress: true + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: docker/metadata-action@v4 + id: meta + with: + images: ghcr.io/${{ github.repository_owner }}/prql-devcontainer-base + tags: | + type=raw,latest + + - name: Login to GitHub Container Registry + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + - id: set-platforms + run: | + if [ "${{ github.ref }}" = "refs/heads/main" ]; then + echo "platforms=linux/amd64,linux/arm64" >>$GITHUB_OUTPUT + echo "push=true" >>$GITHUB_OUTPUT + else + echo "platforms=linux/amd64" >>$GITHUB_OUTPUT + echo "push=false" >>$GITHUB_OUTPUT + fi + + - name: Build + uses: docker/build-push-action@v4 + with: + file: "./.devcontainer/base-image/Dockerfile" + tags: ${{ steps.meta.outputs.tags }} + platforms: ${{ steps.set-platforms.outputs.platforms }} + push: ${{ steps.set-platforms.outputs.push }} + cache-from: | + ${{ env.IMAGE_NAME }} + type=gha + cache-to: | + type=inline + type=gha,mode=max diff --git a/Taskfile.cargo-tools.yml b/Taskfile.cargo-tools.yml new file mode 100644 index 000000000000..814e4108fece --- /dev/null +++ b/Taskfile.cargo-tools.yml @@ -0,0 +1,19 @@ +# yaml-language-server: $schema=https://json.schemastore.org/taskfile.json + +version: 3 + +tasks: + install: + # factored this out because it takes a long time to build + desc: Install cargo tools for PRQL development. + cmds: + # `--locked` installs from the underlying lock files (which is not the + # default?!) + - cargo install --locked bacon cargo-audit cargo-insta cargo-release + default-target mdbook mdbook-admonish mdbook-toc wasm-bindgen-cli + wasm-pack + # Can't install atm with `--locked` + - cargo install mdbook-footnote + - cmd: | + [ "$(which cargo-insta)" ] || echo "🔴 Can't find a binary that cargo just installed. Is the cargo bin path (generally at ~/.cargo/bin) on the \$PATH?" + silent: true diff --git a/Taskfile.yml b/Taskfile.yml index 0407891f50f6..6ea88606fff2 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -11,6 +11,9 @@ version: "3" +includes: + cargo-tools: ./Taskfile.cargo-tools.yml + vars: # Keep in sync with .vscode/extensions.json vscode_extensions: | @@ -38,7 +41,7 @@ tasks: desc: Install tools for PRQL development. cmds: - - task: install-cargo-tools + - task: cargo-tools:install - task: install-brew-dependencies - task: install-maturin - task: install-pre-commit @@ -54,18 +57,9 @@ tasks: install-cargo-tools: # factored this out because it takes a long time to build - desc: Install cargo tools for PRQL development. - cmds: - # `--locked` installs from the underlying lock files (which is not the - # default?!) - - cargo install --locked bacon cargo-audit cargo-insta cargo-release - default-target mdbook mdbook-admonish mdbook-toc wasm-bindgen-cli - wasm-pack - # Can't install atm with `--locked` - - cargo install mdbook-footnote - - cmd: | - [ "$(which cargo-insta)" ] || echo "🔴 Can't find a binary that cargo just installed. Is the cargo bin path (generally at ~/.cargo/bin) on the \$PATH?" - silent: true + desc: Alias of `cargo-tools:install` + deps: + - cargo-tools:install install-maturin: desc: Install maturin. From 5d20e7facd1d69ef3de23290270031af77c645af Mon Sep 17 00:00:00 2001 From: eitsupi <50911393+eitsupi@users.noreply.github.com> Date: Mon, 6 Mar 2023 14:43:52 +0900 Subject: [PATCH 095/106] build: fix concurrency of devcontainer.yaml (#2027) --- .github/workflows/devcontainer.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/devcontainer.yaml b/.github/workflows/devcontainer.yaml index 1b28019a4975..840cd9b30f4e 100644 --- a/.github/workflows/devcontainer.yaml +++ b/.github/workflows/devcontainer.yaml @@ -12,7 +12,7 @@ on: workflow_dispatch: concurrency: - group: ${{ github.workflow }} + group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: From dcfcb5f56a44b1a52041cd63a1def093b2691f70 Mon Sep 17 00:00:00 2001 From: eitsupi <50911393+eitsupi@users.noreply.github.com> Date: Mon, 6 Mar 2023 16:17:29 +0900 Subject: [PATCH 096/106] build: fix docker build workflows (#2028) * build: always build amd64 and arm64 * build: fix copying Taskfile * chore: bump base image version and pin to bullseye * build: try only build arm64 * build: build amd64 only for now --- .devcontainer/base-image/Dockerfile | 2 +- .github/workflows/devcontainer.yaml | 9 ++++----- Dockerfile | 4 ++-- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/.devcontainer/base-image/Dockerfile b/.devcontainer/base-image/Dockerfile index 00200fe5b006..6d71dcde78cb 100644 --- a/.devcontainer/base-image/Dockerfile +++ b/.devcontainer/base-image/Dockerfile @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/devcontainers/rust:0.203.7-1 +FROM mcr.microsoft.com/devcontainers/rust:0.203.8-1-bullseye RUN apt-get update \ && apt-get install -y --no-install-recommends \ diff --git a/.github/workflows/devcontainer.yaml b/.github/workflows/devcontainer.yaml index 840cd9b30f4e..86392d342c7c 100644 --- a/.github/workflows/devcontainer.yaml +++ b/.github/workflows/devcontainer.yaml @@ -39,13 +39,11 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 - - id: set-platforms + - id: set-options run: | if [ "${{ github.ref }}" = "refs/heads/main" ]; then - echo "platforms=linux/amd64,linux/arm64" >>$GITHUB_OUTPUT echo "push=true" >>$GITHUB_OUTPUT else - echo "platforms=linux/amd64" >>$GITHUB_OUTPUT echo "push=false" >>$GITHUB_OUTPUT fi @@ -54,8 +52,9 @@ jobs: with: file: "./.devcontainer/base-image/Dockerfile" tags: ${{ steps.meta.outputs.tags }} - platforms: ${{ steps.set-platforms.outputs.platforms }} - push: ${{ steps.set-platforms.outputs.push }} + # TODO: add linux/arm64 + platforms: linux/amd64 + push: ${{ steps.set-options.outputs.push }} cache-from: | ${{ env.IMAGE_NAME }} type=gha diff --git a/Dockerfile b/Dockerfile index 98050395e45e..f97fd15bfcb5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -45,10 +45,10 @@ RUN sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d -b /usr/loc # ========= Set up workdir & copy the taskfile ========= WORKDIR /src -COPY Taskfile.yml . +COPY Taskfile.cargo-tools.yml . # ========= Install cargo-tools ========= -RUN task install-cargo-tools +RUN task -t Taskfile.cargo-tools.yml install # TODO: currently this doesn't support doing things like running the playground, # since we don't install hugo & node. Default `apt` doesn't install up-to-date From b05c626f9b6fb00aa18e7864e6b9b44e1a06a664 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 6 Mar 2023 11:35:10 -0800 Subject: [PATCH 097/106] chore: pre-commit autoupdate (#2032) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/crate-ci/typos: v1.13.12 → v1.13.18](https://github.com/crate-ci/typos/compare/v1.13.12...v1.13.18) - [github.com/pre-commit/mirrors-prettier: v3.0.0-alpha.4 → v3.0.0-alpha.6](https://github.com/pre-commit/mirrors-prettier/compare/v3.0.0-alpha.4...v3.0.0-alpha.6) - [github.com/charliermarsh/ruff-pre-commit: v0.0.252 → v0.0.254](https://github.com/charliermarsh/ruff-pre-commit/compare/v0.0.252...v0.0.254) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 5c1f89d13d77..f7ae30ed711c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -8,20 +8,20 @@ repos: - id: check-yaml - id: mixed-line-ending - repo: https://github.com/crate-ci/typos - rev: v1.13.12 + rev: v1.13.18 hooks: - id: typos # https://github.com/crate-ci/typos/issues/347 pass_filenames: false - repo: https://github.com/pre-commit/mirrors-prettier - rev: v3.0.0-alpha.4 + rev: v3.0.0-alpha.6 hooks: - id: prettier additional_dependencies: - prettier - prettier-plugin-go-template - repo: https://github.com/charliermarsh/ruff-pre-commit - rev: v0.0.252 + rev: v0.0.254 hooks: - id: ruff - repo: https://github.com/psf/black From a6c7455121d64875cdd76a092714c53242bad80d Mon Sep 17 00:00:00 2001 From: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Date: Mon, 6 Mar 2023 21:20:23 -0800 Subject: [PATCH 098/106] devops: Add shortcuts for insta in `bacon` (#2037) * devops: Add shortcuts for insta in `bacon` * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- bacon.toml | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/bacon.toml b/bacon.toml index 9e9e82362080..5e8415c743c6 100644 --- a/bacon.toml +++ b/bacon.toml @@ -3,9 +3,9 @@ default_job = "check" # PRQL additions -[jobs.test-rust-fast] +[jobs.test-fast] command = ['cargo', 'insta', 'test', '--accept', "--color=always", "-p=prql-compiler", "--lib"] -[jobs.test-rust] +[jobs.test] command = ['cargo', 'insta', 'test', '--accept', "--color=always"] # Standard tasks @@ -24,11 +24,6 @@ command = ["cargo", "clippy", "--all-targets", "--color", "always"] need_stdout = false watch = ["tests", "benches", "examples"] -[jobs.test] -command = ["cargo", "test", "--color", "always"] -need_stdout = true -watch = ["tests"] - [jobs.doc] command = ["cargo", "doc", "--color", "always", "--no-deps"] need_stdout = false @@ -59,7 +54,6 @@ need_stdout = true a = "job:check-all" c = "job:clippy" d = "job:doc-open" -# i for `insta` -i = "job:test-rust-fast" +f = "job:test-fast" r = "job:run" t = "job:test" From 47ec070a6588ac012a770830431f0a25171f7ea5 Mon Sep 17 00:00:00 2001 From: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Date: Mon, 6 Mar 2023 22:32:39 -0800 Subject: [PATCH 099/106] devops: Sync bacon command with `test-rust` (#2038) * devops: Sync bacon command with `test-rust` * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- bacon.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bacon.toml b/bacon.toml index 5e8415c743c6..5361e3781741 100644 --- a/bacon.toml +++ b/bacon.toml @@ -6,7 +6,7 @@ default_job = "check" [jobs.test-fast] command = ['cargo', 'insta', 'test', '--accept', "--color=always", "-p=prql-compiler", "--lib"] [jobs.test] -command = ['cargo', 'insta', 'test', '--accept', "--color=always"] +command = ['cargo', 'insta', 'test', '--accept', "--color=always", "--unreferenced=auto"] # Standard tasks From f04baf22a69e02bfa858f23b77926ad702d56ee8 Mon Sep 17 00:00:00 2001 From: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Date: Mon, 6 Mar 2023 22:33:17 -0800 Subject: [PATCH 100/106] feat!: Rename `switch` to `case` (#2036) * feat: Rename `switch` to `case` In case `switch` is confusing, this switches `switch` for `case`. Hopefully the switch won't lead to a case of confusion; or we can case the decision again. --- CHANGELOG.md | 16 +++++++----- book/highlight-prql.js | 2 +- book/src/SUMMARY.md | 2 +- book/src/language-features/README.md | 26 +++++++++---------- .../language-features/{switch.md => case.md} | 10 +++---- book/src/syntax.md | 4 +-- .../{switch-0.prql => case-0.prql} | 2 +- .../{switch-1.prql => case-1.prql} | 2 +- ...shot__@language-features__case-0.prql.snap | 15 +++++++++++ ...shot__@language-features__case-1.prql.snap | 15 +++++++++++ ...ot__@language-features__switch-0.prql.snap | 14 ---------- ...ot__@language-features__switch-1.prql.snap | 14 ---------- book/theme/highlight.js | 2 +- playground/src/workbench/prql-syntax.js | 2 +- prql-compiler/src/ast/pl/expr.rs | 6 ++--- prql-compiler/src/ast/pl/fold.rs | 2 +- prql-compiler/src/ast/rq/expr.rs | 2 +- prql-compiler/src/ast/rq/fold.rs | 2 +- prql-compiler/src/parser/expr.rs | 6 ++--- prql-compiler/src/parser/lexer.rs | 2 +- prql-compiler/src/parser/mod.rs | 6 ++--- prql-compiler/src/semantic/lowering.rs | 2 +- prql-compiler/src/semantic/static_analysis.rs | 4 +-- prql-compiler/src/sql/anchor.rs | 2 +- prql-compiler/src/sql/gen_expr.rs | 2 +- prql-compiler/src/test.rs | 10 +++---- .../tests/integration/data/chinook/tracks.csv | 2 +- .../tests/integration/queries/switch.prql | 2 +- .../integration__tests__test@switch.prql.snap | 2 +- prql-lezer/src/prql.grammar | 2 +- .../posts/2023-02-02-one-year/_index.md | 2 +- .../plugins/bootstrap/bootstrap.bundle.min.js | 2 +- .../static/plugins/highlight/highlight.min.js | 4 +-- .../static/plugins/highlight/prql.js | 2 +- 34 files changed, 97 insertions(+), 93 deletions(-) rename book/src/language-features/{switch.md => case.md} (59%) rename book/tests/prql/language-features/{switch-0.prql => case-0.prql} (79%) rename book/tests/prql/language-features/{switch-1.prql => case-1.prql} (82%) create mode 100644 book/tests/snapshots/snapshot__@language-features__case-0.prql.snap create mode 100644 book/tests/snapshots/snapshot__@language-features__case-1.prql.snap delete mode 100644 book/tests/snapshots/snapshot__@language-features__switch-0.prql.snap delete mode 100644 book/tests/snapshots/snapshot__@language-features__switch-1.prql.snap diff --git a/CHANGELOG.md b/CHANGELOG.md index d5d7bec3f038..fc752c79d360 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,7 +16,7 @@ - `and` now has a higher precedence than `or` (of same reason as the previous point). - Dates, times and timestamps have stricter parsing rules. - - `let`, `func`, `prql`, `switch` are now treated as keywords. + - `let`, `func`, `prql`, `case` are now treated as keywords. - Float literals without fraction part are not allowed anymore (`1.`). - Add a `--format` option to `prqlc parse` which can return the AST in YAML (@max-sixty, #1962) @@ -28,6 +28,8 @@ `@2020-01-01T13:19:55-0800` (@max-sixty, #1991). - Add `std.upper` and `std.lower` functions for changing string casing (@Jelenkee, #2019). +- Rename the experimental `switch` to `case` given it more closely matches the + traditional semantics of `case`. (@max-sixty, #2036) **Fixes**: @@ -214,7 +216,7 @@ This release has 74 commits from 12 contributors. Selected changes: ## 0.4.0 — 2022-01-15 -0.4.0 brings lots of new features including `switch`, `select ![]` and numbers +0.4.0 brings lots of new features including `case`, `select ![]` and numbers with underscores. We have initial (unpublished) bindings to Elixir. And there's the usual improvements to fixes & documentation (only a minority are listed below in this release). @@ -229,12 +231,12 @@ below in this release). [tables docs](https://prql-lang.org/book/queries/variables.html) for details. - _Experimental:_ The - [`switch`](https://prql-lang.org/book/language-features/switch.html) function - sets a variable to a value based on one of several expressions (@aljazerzen, + [`case`](https://prql-lang.org/book/language-features/case.html) function sets + a variable to a value based on one of several expressions (@aljazerzen, #1278). ```prql - derive var = switch [ + derive var = case [ score <= 10 -> "low", score <= 30 -> "medium", score <= 70 -> "high", @@ -258,8 +260,8 @@ below in this release). ``` Check out the - [`switch` docs](https://prql-lang.org/book/language-features/switch.html) for - more details. + [`case` docs](https://prql-lang.org/book/language-features/case.html) for more + details. - _Experimental:_ Columns can be excluded by name with `select` (@aljazerzen, #1329) diff --git a/book/highlight-prql.js b/book/highlight-prql.js index 6993b6f799d5..2f3e7136fdda 100644 --- a/book/highlight-prql.js +++ b/book/highlight-prql.js @@ -35,7 +35,7 @@ formatting = function (hljs) { "union", "window", ]; - const BUILTIN_FUNCTIONS = ["switch", "in", "as"]; + const BUILTIN_FUNCTIONS = ["case", "in", "as"]; const KEYWORDS = ["func", "let", "prql"]; return { name: "PRQL", diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md index cc27566b74a2..d8dea5cd6719 100644 --- a/book/src/SUMMARY.md +++ b/book/src/SUMMARY.md @@ -42,7 +42,7 @@ - [Strings](./language-features/strings.md) - [S-strings](./language-features/s-strings.md) - [F-strings](./language-features/f-strings.md) - - [Switch](./language-features/switch.md) + - [Case](./language-features/case.md) - [Target & Version](./language-features/target.md) - [Bindings](./bindings/README.md) diff --git a/book/src/language-features/README.md b/book/src/language-features/README.md index 45b07178b7d4..a75dfe4e9e88 100644 --- a/book/src/language-features/README.md +++ b/book/src/language-features/README.md @@ -3,16 +3,16 @@ The pages of this section describe how PRQL handles various aspects of the language. -| Feature | Purpose | -| ---------------- | ------------------------------------------------------------------------- | -| Coalesce | [Handle potentially NULL values](./coalesce.md) | -| Dates & times | [Handle dates and times](./dates-and-times.md) | -| Distinct | [Equivalent of SQL `DISTINCT`](./distinct.md) | -| Null handling | [Handle `NULL` values](./null.md) | -| Ranges | [Syntax for all forms of ranges](./ranges.md) | -| Regex | [Handle regular expressions](./regex.md) | -| Strings | [Rules for creating strings](./strings.md) | -| S-strings | [Insert SQL directly into a query with an S-string](./s-strings.md) | -| F-strings | [Combine several column's data with F-strings](./f-strings.md) | -| Switch | [Create a new column based on the contents of other columns](./switch.md) | -| Target & Version | [Specify a target SQL engine and PRQL version](./target.md) | +| Feature | Purpose | +| ---------------- | ----------------------------------------------------------------------- | +| Coalesce | [Handle potentially NULL values](./coalesce.md) | +| Dates & times | [Handle dates and times](./dates-and-times.md) | +| Distinct | [Equivalent of SQL `DISTINCT`](./distinct.md) | +| Null handling | [Handle `NULL` values](./null.md) | +| Ranges | [Syntax for all forms of ranges](./ranges.md) | +| Regex | [Handle regular expressions](./regex.md) | +| Strings | [Rules for creating strings](./strings.md) | +| S-strings | [Insert SQL directly into a query with an S-string](./s-strings.md) | +| F-strings | [Combine several column's data with F-strings](./f-strings.md) | +| Case | [Create a new column based on the contents of other columns](./case.md) | +| Target & Version | [Specify a target SQL engine and PRQL version](./target.md) | diff --git a/book/src/language-features/switch.md b/book/src/language-features/case.md similarity index 59% rename from book/src/language-features/switch.md rename to book/src/language-features/case.md index eb9353eee968..a836e84b1b2b 100644 --- a/book/src/language-features/switch.md +++ b/book/src/language-features/case.md @@ -1,14 +1,14 @@ -# Switch +# Case ```admonish note -`switch` is currently experimental and may change behavior in the near future +`case` is currently experimental and may change behavior in the near future ``` -PRQL uses `switch` for both SQL's `CASE` and `IF` statements. Here's an example: +PRQL uses `case` for both SQL's `CASE` and `IF` statements. Here's an example: ```prql_no_fmt from employees -derive distance = switch [ +derive distance = case [ city == "Calgary" -> 0, city == "Edmonton" -> 300, ] @@ -19,7 +19,7 @@ If no condition is met, the value takes a `null` value. To set a default, use a ```prql_no_fmt from employees -derive distance = switch [ +derive distance = case [ city == "Calgary" -> 0, city == "Edmonton" -> 300, true -> "Unknown", diff --git a/book/src/syntax.md b/book/src/syntax.md index 2382e5be3d44..900f671388c3 100644 --- a/book/src/syntax.md +++ b/book/src/syntax.md @@ -294,9 +294,9 @@ At the moment, PRQL uses only four keywords: - `prql` - `let` - `func` -- `switch` +- `case` -To use these names as columns or relations, use backticks: `` `switch` ``. +To use these names as columns or relations, use backticks: `` `case` ``. It may seem that transforms are also keywords, but they are normal function within std namespace: diff --git a/book/tests/prql/language-features/switch-0.prql b/book/tests/prql/language-features/case-0.prql similarity index 79% rename from book/tests/prql/language-features/switch-0.prql rename to book/tests/prql/language-features/case-0.prql index c2cd611f974a..0845b3bf8fc7 100644 --- a/book/tests/prql/language-features/switch-0.prql +++ b/book/tests/prql/language-features/case-0.prql @@ -1,7 +1,7 @@ # Can't yet format & compile from employees -derive distance = switch [ +derive distance = case [ city == "Calgary" -> 0, city == "Edmonton" -> 300, ] diff --git a/book/tests/prql/language-features/switch-1.prql b/book/tests/prql/language-features/case-1.prql similarity index 82% rename from book/tests/prql/language-features/switch-1.prql rename to book/tests/prql/language-features/case-1.prql index aba9837069df..5a97534e00b1 100644 --- a/book/tests/prql/language-features/switch-1.prql +++ b/book/tests/prql/language-features/case-1.prql @@ -1,7 +1,7 @@ # Can't yet format & compile from employees -derive distance = switch [ +derive distance = case [ city == "Calgary" -> 0, city == "Edmonton" -> 300, true -> "Unknown", diff --git a/book/tests/snapshots/snapshot__@language-features__case-0.prql.snap b/book/tests/snapshots/snapshot__@language-features__case-0.prql.snap new file mode 100644 index 000000000000..c1b47f0b82e5 --- /dev/null +++ b/book/tests/snapshots/snapshot__@language-features__case-0.prql.snap @@ -0,0 +1,15 @@ +--- +source: book/tests/snapshot.rs +expression: "# Can't yet format & compile\n\nfrom employees\nderive distance = case [\n city == \"Calgary\" -> 0,\n city == \"Edmonton\" -> 300,\n]\n" +input_file: book/tests/prql/language-features/case-0.prql +--- +SELECT + *, + CASE + WHEN city = 'Calgary' THEN 0 + WHEN city = 'Edmonton' THEN 300 + ELSE NULL + END AS distance +FROM + employees + diff --git a/book/tests/snapshots/snapshot__@language-features__case-1.prql.snap b/book/tests/snapshots/snapshot__@language-features__case-1.prql.snap new file mode 100644 index 000000000000..816c9244da9b --- /dev/null +++ b/book/tests/snapshots/snapshot__@language-features__case-1.prql.snap @@ -0,0 +1,15 @@ +--- +source: book/tests/snapshot.rs +expression: "# Can't yet format & compile\n\nfrom employees\nderive distance = case [\n city == \"Calgary\" -> 0,\n city == \"Edmonton\" -> 300,\n true -> \"Unknown\",\n]\n" +input_file: book/tests/prql/language-features/case-1.prql +--- +SELECT + *, + CASE + WHEN city = 'Calgary' THEN 0 + WHEN city = 'Edmonton' THEN 300 + ELSE 'Unknown' + END AS distance +FROM + employees + diff --git a/book/tests/snapshots/snapshot__@language-features__switch-0.prql.snap b/book/tests/snapshots/snapshot__@language-features__switch-0.prql.snap deleted file mode 100644 index 3fc3b672a06b..000000000000 --- a/book/tests/snapshots/snapshot__@language-features__switch-0.prql.snap +++ /dev/null @@ -1,14 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nderive distance = switch [\n city == \"Calgary\" -> 0,\n city == \"Edmonton\" -> 300,\n]\n" -input_file: book/tests/prql/language-features/switch-0.prql ---- -SELECT - *, - CASE - WHEN city = 'Calgary' THEN 0 - WHEN city = 'Edmonton' THEN 300 - ELSE NULL - END AS distance -FROM - employees diff --git a/book/tests/snapshots/snapshot__@language-features__switch-1.prql.snap b/book/tests/snapshots/snapshot__@language-features__switch-1.prql.snap deleted file mode 100644 index 3ce88aec5690..000000000000 --- a/book/tests/snapshots/snapshot__@language-features__switch-1.prql.snap +++ /dev/null @@ -1,14 +0,0 @@ ---- -source: book/tests/snapshot.rs -expression: "from employees\nderive distance = switch [\n city == \"Calgary\" -> 0,\n city == \"Edmonton\" -> 300,\n true -> \"Unknown\",\n]\n" -input_file: book/tests/prql/language-features/switch-1.prql ---- -SELECT - *, - CASE - WHEN city = 'Calgary' THEN 0 - WHEN city = 'Edmonton' THEN 300 - ELSE 'Unknown' - END AS distance -FROM - employees diff --git a/book/theme/highlight.js b/book/theme/highlight.js index 070264e2e698..7f5ea2af40b3 100644 --- a/book/theme/highlight.js +++ b/book/theme/highlight.js @@ -1 +1 @@ -var hljs=function(){"use strict";var e={exports:{}};function n(e){return e instanceof Map?e.clear=e.delete=e.set=()=>{throw Error("map is read-only")}:e instanceof Set&&(e.add=e.clear=e.delete=()=>{throw Error("set is read-only")}),Object.freeze(e),Object.getOwnPropertyNames(e).forEach(t=>{var a=e[t];"object"!=typeof a||Object.isFrozen(a)||n(a)}),e}e.exports=n,e.exports.default=n;var t=e.exports;class a{constructor(e){void 0===e.data&&(e.data={}),this.data=e.data,this.isMatchIgnored=!1}ignoreMatch(){this.isMatchIgnored=!0}}function i(e){return e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")}function r(e,...n){const t=Object.create(null);for(const n in e)t[n]=e[n];return n.forEach(e=>{for(const n in e)t[n]=e[n]}),t}const s=e=>!!e.kind;class o{constructor(e,n){this.buffer="",this.classPrefix=n.classPrefix,e.walk(this)}addText(e){this.buffer+=i(e)}openNode(e){if(!s(e))return;let n=e.kind;n=e.sublanguage?"language-"+n:((e,{prefix:n})=>{if(e.includes(".")){const t=e.split(".");return[`${n}${t.shift()}`,...t.map((e,n)=>`${e}${"_".repeat(n+1)}`)].join(" ")}return`${n}${e}`})(n,{prefix:this.classPrefix}),this.span(n)}closeNode(e){s(e)&&(this.buffer+="")}value(){return this.buffer}span(e){this.buffer+=``}}class l{constructor(){this.rootNode={children:[]},this.stack=[this.rootNode]}get top(){return this.stack[this.stack.length-1]}get root(){return this.rootNode}add(e){this.top.children.push(e)}openNode(e){const n={kind:e,children:[]};this.add(n),this.stack.push(n)}closeNode(){if(this.stack.length>1)return this.stack.pop()}closeAllNodes(){for(;this.closeNode(););}toJSON(){return JSON.stringify(this.rootNode,null,4)}walk(e){return this.constructor._walk(e,this.rootNode)}static _walk(e,n){return"string"==typeof n?e.addText(n):n.children&&(e.openNode(n),n.children.forEach(n=>this._walk(e,n)),e.closeNode(n)),e}static _collapse(e){"string"!=typeof e&&e.children&&(e.children.every(e=>"string"==typeof e)?e.children=[e.children.join("")]:e.children.forEach(e=>{l._collapse(e)}))}}class c extends l{constructor(e){super(),this.options=e}addKeyword(e,n){""!==e&&(this.openNode(n),this.addText(e),this.closeNode())}addText(e){""!==e&&this.add(e)}addSublanguage(e,n){const t=e.root;t.kind=n,t.sublanguage=!0,this.add(t)}toHTML(){return new o(this,this.options).value()}finalize(){return!0}}function d(e){return e?"string"==typeof e?e:e.source:null}function g(e){return m("(?=",e,")")}function u(e){return m("(?:",e,")*")}function b(e){return m("(?:",e,")?")}function m(...e){return e.map(e=>d(e)).join("")}function p(...e){const n=(e=>{const n=e[e.length-1];return"object"==typeof n&&n.constructor===Object?(e.splice(e.length-1,1),n):{}})(e);return"("+(n.capture?"":"?:")+e.map(e=>d(e)).join("|")+")"}function _(e){return RegExp(e.toString()+"|").exec("").length-1}const h=/\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./;function f(e,{joinWith:n}){let t=0;return e.map(e=>{t+=1;const n=t;let a=d(e),i="";for(;a.length>0;){const e=h.exec(a);if(!e){i+=a;break}i+=a.substring(0,e.index),a=a.substring(e.index+e[0].length),"\\"===e[0][0]&&e[1]?i+="\\"+(Number(e[1])+n):(i+=e[0],"("===e[0]&&t++)}return i}).map(e=>`(${e})`).join(n)}const E="[a-zA-Z]\\w*",y="[a-zA-Z_]\\w*",w="\\b\\d+(\\.\\d+)?",N="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",v="\\b(0b[01]+)",k={begin:"\\\\[\\s\\S]",relevance:0},O={scope:"string",begin:"'",end:"'",illegal:"\\n",contains:[k]},x={scope:"string",begin:'"',end:'"',illegal:"\\n",contains:[k]},M=(e,n,t={})=>{const a=r({scope:"comment",begin:e,end:n,contains:[]},t);a.contains.push({scope:"doctag",begin:"[ ]*(?=(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):)",end:/(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):/,excludeBegin:!0,relevance:0});const i=p("I","a","is","so","us","to","at","if","in","it","on",/[A-Za-z]+['](d|ve|re|ll|t|s|n)/,/[A-Za-z]+[-][a-z]+/,/[A-Za-z][a-z]{2,}/);return a.contains.push({begin:m(/[ ]+/,"(",i,/[.]?[:]?([.][ ]|[ ])/,"){3}")}),a},S=M("//","$"),A=M("/\\*","\\*/"),C=M("#","$");var T=Object.freeze({__proto__:null,MATCH_NOTHING_RE:/\b\B/,IDENT_RE:E,UNDERSCORE_IDENT_RE:y,NUMBER_RE:w,C_NUMBER_RE:N,BINARY_NUMBER_RE:v,RE_STARTERS_RE:"!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",SHEBANG:(e={})=>{const n=/^#![ ]*\//;return e.binary&&(e.begin=m(n,/.*\b/,e.binary,/\b.*/)),r({scope:"meta",begin:n,end:/$/,relevance:0,"on:begin":(e,n)=>{0!==e.index&&n.ignoreMatch()}},e)},BACKSLASH_ESCAPE:k,APOS_STRING_MODE:O,QUOTE_STRING_MODE:x,PHRASAL_WORDS_MODE:{begin:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/},COMMENT:M,C_LINE_COMMENT_MODE:S,C_BLOCK_COMMENT_MODE:A,HASH_COMMENT_MODE:C,NUMBER_MODE:{scope:"number",begin:w,relevance:0},C_NUMBER_MODE:{scope:"number",begin:N,relevance:0},BINARY_NUMBER_MODE:{scope:"number",begin:v,relevance:0},REGEXP_MODE:{begin:/(?=\/[^/\n]*\/)/,contains:[{scope:"regexp",begin:/\//,end:/\/[gimuy]*/,illegal:/\n/,contains:[k,{begin:/\[/,end:/\]/,relevance:0,contains:[k]}]}]},TITLE_MODE:{scope:"title",begin:E,relevance:0},UNDERSCORE_TITLE_MODE:{scope:"title",begin:y,relevance:0},METHOD_GUARD:{begin:"\\.\\s*[a-zA-Z_]\\w*",relevance:0},END_SAME_AS_BEGIN:e=>Object.assign(e,{"on:begin":(e,n)=>{n.data._beginMatch=e[1]},"on:end":(e,n)=>{n.data._beginMatch!==e[1]&&n.ignoreMatch()}})});function R(e,n){"."===e.input[e.index-1]&&n.ignoreMatch()}function D(e,n){void 0!==e.className&&(e.scope=e.className,delete e.className)}function I(e,n){n&&e.beginKeywords&&(e.begin="\\b("+e.beginKeywords.split(" ").join("|")+")(?!\\.)(?=\\b|\\s)",e.__beforeBegin=R,e.keywords=e.keywords||e.beginKeywords,delete e.beginKeywords,void 0===e.relevance&&(e.relevance=0))}function L(e,n){Array.isArray(e.illegal)&&(e.illegal=p(...e.illegal))}function B(e,n){if(e.match){if(e.begin||e.end)throw Error("begin & end are not supported with match");e.begin=e.match,delete e.match}}function $(e,n){void 0===e.relevance&&(e.relevance=1)}const z=(e,n)=>{if(!e.beforeMatch)return;if(e.starts)throw Error("beforeMatch cannot be used with starts");const t=Object.assign({},e);Object.keys(e).forEach(n=>{delete e[n]}),e.keywords=t.keywords,e.begin=m(t.beforeMatch,g(t.begin)),e.starts={relevance:0,contains:[Object.assign(t,{endsParent:!0})]},e.relevance=0,delete t.beforeMatch},F=["of","and","for","in","not","or","if","then","parent","list","value"];function U(e,n,t="keyword"){const a=Object.create(null);return"string"==typeof e?i(t,e.split(" ")):Array.isArray(e)?i(t,e):Object.keys(e).forEach(t=>{Object.assign(a,U(e[t],n,t))}),a;function i(e,t){n&&(t=t.map(e=>e.toLowerCase())),t.forEach(n=>{const t=n.split("|");a[t[0]]=[e,j(t[0],t[1])]})}}function j(e,n){return n?Number(n):(e=>F.includes(e.toLowerCase()))(e)?0:1}const P={},K=e=>{console.error(e)},H=(e,...n)=>{console.log("WARN: "+e,...n)},q=(e,n)=>{P[`${e}/${n}`]||(console.log(`Deprecated as of ${e}. ${n}`),P[`${e}/${n}`]=!0)},Z=Error();function G(e,n,{key:t}){let a=0;const i=e[t],r={},s={};for(let e=1;e<=n.length;e++)s[e+a]=i[e],r[e+a]=!0,a+=_(n[e-1]);e[t]=s,e[t]._emit=r,e[t]._multi=!0}function W(e){(e=>{e.scope&&"object"==typeof e.scope&&null!==e.scope&&(e.beginScope=e.scope,delete e.scope)})(e),"string"==typeof e.beginScope&&(e.beginScope={_wrap:e.beginScope}),"string"==typeof e.endScope&&(e.endScope={_wrap:e.endScope}),(e=>{if(Array.isArray(e.begin)){if(e.skip||e.excludeBegin||e.returnBegin)throw K("skip, excludeBegin, returnBegin not compatible with beginScope: {}"),Z;if("object"!=typeof e.beginScope||null===e.beginScope)throw K("beginScope must be object"),Z;G(e,e.begin,{key:"beginScope"}),e.begin=f(e.begin,{joinWith:""})}})(e),(e=>{if(Array.isArray(e.end)){if(e.skip||e.excludeEnd||e.returnEnd)throw K("skip, excludeEnd, returnEnd not compatible with endScope: {}"),Z;if("object"!=typeof e.endScope||null===e.endScope)throw K("endScope must be object"),Z;G(e,e.end,{key:"endScope"}),e.end=f(e.end,{joinWith:""})}})(e)}function Q(e){function n(n,t){return RegExp(d(n),"m"+(e.case_insensitive?"i":"")+(e.unicodeRegex?"u":"")+(t?"g":""))}class t{constructor(){this.matchIndexes={},this.regexes=[],this.matchAt=1,this.position=0}addRule(e,n){n.position=this.position++,this.matchIndexes[this.matchAt]=n,this.regexes.push([n,e]),this.matchAt+=_(e)+1}compile(){0===this.regexes.length&&(this.exec=()=>null);const e=this.regexes.map(e=>e[1]);this.matcherRe=n(f(e,{joinWith:"|"}),!0),this.lastIndex=0}exec(e){this.matcherRe.lastIndex=this.lastIndex;const n=this.matcherRe.exec(e);if(!n)return null;const t=n.findIndex((e,n)=>n>0&&void 0!==e),a=this.matchIndexes[t];return n.splice(0,t),Object.assign(n,a)}}class a{constructor(){this.rules=[],this.multiRegexes=[],this.count=0,this.lastIndex=0,this.regexIndex=0}getMatcher(e){if(this.multiRegexes[e])return this.multiRegexes[e];const n=new t;return this.rules.slice(e).forEach(([e,t])=>n.addRule(e,t)),n.compile(),this.multiRegexes[e]=n,n}resumingScanAtSamePosition(){return 0!==this.regexIndex}considerAll(){this.regexIndex=0}addRule(e,n){this.rules.push([e,n]),"begin"===n.type&&this.count++}exec(e){const n=this.getMatcher(this.regexIndex);n.lastIndex=this.lastIndex;let t=n.exec(e);if(this.resumingScanAtSamePosition())if(t&&t.index===this.lastIndex);else{const n=this.getMatcher(0);n.lastIndex=this.lastIndex+1,t=n.exec(e)}return t&&(this.regexIndex+=t.position+1,this.regexIndex===this.count&&this.considerAll()),t}}if(e.compilerExtensions||(e.compilerExtensions=[]),e.contains&&e.contains.includes("self"))throw Error("ERR: contains `self` is not supported at the top-level of a language. See documentation.");return e.classNameAliases=r(e.classNameAliases||{}),function t(i,s){const o=i;if(i.isCompiled)return o;[D,B,W,z].forEach(e=>e(i,s)),e.compilerExtensions.forEach(e=>e(i,s)),i.__beforeBegin=null,[I,L,$].forEach(e=>e(i,s)),i.isCompiled=!0;let l=null;return"object"==typeof i.keywords&&i.keywords.$pattern&&(i.keywords=Object.assign({},i.keywords),l=i.keywords.$pattern,delete i.keywords.$pattern),l=l||/\w+/,i.keywords&&(i.keywords=U(i.keywords,e.case_insensitive)),o.keywordPatternRe=n(l,!0),s&&(i.begin||(i.begin=/\B|\b/),o.beginRe=n(o.begin),i.end||i.endsWithParent||(i.end=/\B|\b/),i.end&&(o.endRe=n(o.end)),o.terminatorEnd=d(o.end)||"",i.endsWithParent&&s.terminatorEnd&&(o.terminatorEnd+=(i.end?"|":"")+s.terminatorEnd)),i.illegal&&(o.illegalRe=n(i.illegal)),i.contains||(i.contains=[]),i.contains=[].concat(...i.contains.map(e=>(e=>(e.variants&&!e.cachedVariants&&(e.cachedVariants=e.variants.map(n=>r(e,{variants:null},n))),e.cachedVariants?e.cachedVariants:X(e)?r(e,{starts:e.starts?r(e.starts):null}):Object.isFrozen(e)?r(e):e))("self"===e?i:e))),i.contains.forEach(e=>{t(e,o)}),i.starts&&t(i.starts,s),o.matcher=(e=>{const n=new a;return e.contains.forEach(e=>n.addRule(e.begin,{rule:e,type:"begin"})),e.terminatorEnd&&n.addRule(e.terminatorEnd,{type:"end"}),e.illegal&&n.addRule(e.illegal,{type:"illegal"}),n})(o),o}(e)}function X(e){return!!e&&(e.endsWithParent||X(e.starts))}class V extends Error{constructor(e,n){super(e),this.name="HTMLInjectionError",this.html=n}}const J=i,Y=r,ee=Symbol("nomatch");var ne=(e=>{const n=Object.create(null),i=Object.create(null),r=[];let s=!0;const o="Could not find the language '{}', did you forget to load/include a language module?",l={disableAutodetect:!0,name:"Plain text",contains:[]};let d={ignoreUnescapedHTML:!1,throwUnescapedHTML:!1,noHighlightRe:/^(no-?highlight)$/i,languageDetectRe:/\blang(?:uage)?-([\w-]+)\b/i,classPrefix:"hljs-",cssSelector:"pre code",languages:null,__emitter:c};function _(e){return d.noHighlightRe.test(e)}function h(e,n,t){let a="",i="";"object"==typeof n?(a=e,t=n.ignoreIllegals,i=n.language):(q("10.7.0","highlight(lang, code, ...args) has been deprecated."),q("10.7.0","Please use highlight(code, options) instead.\nhttps://github.com/highlightjs/highlight.js/issues/2277"),i=e,a=n),void 0===t&&(t=!0);const r={code:a,language:i};x("before:highlight",r);const s=r.result?r.result:f(r.language,r.code,t);return s.code=r.code,x("after:highlight",s),s}function f(e,t,i,r){const l=Object.create(null);function c(){if(!O.keywords)return void M.addText(S);let e=0;O.keywordPatternRe.lastIndex=0;let n=O.keywordPatternRe.exec(S),t="";for(;n;){t+=S.substring(e,n.index);const i=w.case_insensitive?n[0].toLowerCase():n[0],r=(a=i,O.keywords[a]);if(r){const[e,a]=r;if(M.addText(t),t="",l[i]=(l[i]||0)+1,l[i]<=7&&(A+=a),e.startsWith("_"))t+=n[0];else{const t=w.classNameAliases[e]||e;M.addKeyword(n[0],t)}}else t+=n[0];e=O.keywordPatternRe.lastIndex,n=O.keywordPatternRe.exec(S)}var a;t+=S.substr(e),M.addText(t)}function g(){null!=O.subLanguage?(()=>{if(""===S)return;let e=null;if("string"==typeof O.subLanguage){if(!n[O.subLanguage])return void M.addText(S);e=f(O.subLanguage,S,!0,x[O.subLanguage]),x[O.subLanguage]=e._top}else e=E(S,O.subLanguage.length?O.subLanguage:null);O.relevance>0&&(A+=e.relevance),M.addSublanguage(e._emitter,e.language)})():c(),S=""}function u(e,n){let t=1;const a=n.length-1;for(;t<=a;){if(!e._emit[t]){t++;continue}const a=w.classNameAliases[e[t]]||e[t],i=n[t];a?M.addKeyword(i,a):(S=i,c(),S=""),t++}}function b(e,n){return e.scope&&"string"==typeof e.scope&&M.openNode(w.classNameAliases[e.scope]||e.scope),e.beginScope&&(e.beginScope._wrap?(M.addKeyword(S,w.classNameAliases[e.beginScope._wrap]||e.beginScope._wrap),S=""):e.beginScope._multi&&(u(e.beginScope,n),S="")),O=Object.create(e,{parent:{value:O}}),O}function m(e,n,t){let i=((e,n)=>{const t=e&&e.exec(n);return t&&0===t.index})(e.endRe,t);if(i){if(e["on:end"]){const t=new a(e);e["on:end"](n,t),t.isMatchIgnored&&(i=!1)}if(i){for(;e.endsParent&&e.parent;)e=e.parent;return e}}if(e.endsWithParent)return m(e.parent,n,t)}function p(e){return 0===O.matcher.regexIndex?(S+=e[0],1):(R=!0,0)}function _(e){const n=e[0],a=t.substr(e.index),i=m(O,e,a);if(!i)return ee;const r=O;O.endScope&&O.endScope._wrap?(g(),M.addKeyword(n,O.endScope._wrap)):O.endScope&&O.endScope._multi?(g(),u(O.endScope,e)):r.skip?S+=n:(r.returnEnd||r.excludeEnd||(S+=n),g(),r.excludeEnd&&(S=n));do{O.scope&&M.closeNode(),O.skip||O.subLanguage||(A+=O.relevance),O=O.parent}while(O!==i.parent);return i.starts&&b(i.starts,e),r.returnEnd?0:n.length}let h={};function y(n,r){const o=r&&r[0];if(S+=n,null==o)return g(),0;if("begin"===h.type&&"end"===r.type&&h.index===r.index&&""===o){if(S+=t.slice(r.index,r.index+1),!s){const n=Error(`0 width match regex (${e})`);throw n.languageName=e,n.badRule=h.rule,n}return 1}if(h=r,"begin"===r.type)return(e=>{const n=e[0],t=e.rule,i=new a(t),r=[t.__beforeBegin,t["on:begin"]];for(const t of r)if(t&&(t(e,i),i.isMatchIgnored))return p(n);return t.skip?S+=n:(t.excludeBegin&&(S+=n),g(),t.returnBegin||t.excludeBegin||(S=n)),b(t,e),t.returnBegin?0:n.length})(r);if("illegal"===r.type&&!i){const e=Error('Illegal lexeme "'+o+'" for mode "'+(O.scope||"")+'"');throw e.mode=O,e}if("end"===r.type){const e=_(r);if(e!==ee)return e}if("illegal"===r.type&&""===o)return 1;if(T>1e5&&T>3*r.index)throw Error("potential infinite loop, way more iterations than matches");return S+=o,o.length}const w=v(e);if(!w)throw K(o.replace("{}",e)),Error('Unknown language: "'+e+'"');const N=Q(w);let k="",O=r||N;const x={},M=new d.__emitter(d);(()=>{const e=[];for(let n=O;n!==w;n=n.parent)n.scope&&e.unshift(n.scope);e.forEach(e=>M.openNode(e))})();let S="",A=0,C=0,T=0,R=!1;try{for(O.matcher.considerAll();;){T++,R?R=!1:O.matcher.considerAll(),O.matcher.lastIndex=C;const e=O.matcher.exec(t);if(!e)break;const n=y(t.substring(C,e.index),e);C=e.index+n}return y(t.substr(C)),M.closeAllNodes(),M.finalize(),k=M.toHTML(),{language:e,value:k,relevance:A,illegal:!1,_emitter:M,_top:O}}catch(n){if(n.message&&n.message.includes("Illegal"))return{language:e,value:J(t),illegal:!0,relevance:0,_illegalBy:{message:n.message,index:C,context:t.slice(C-100,C+100),mode:n.mode,resultSoFar:k},_emitter:M};if(s)return{language:e,value:J(t),illegal:!1,relevance:0,errorRaised:n,_emitter:M,_top:O};throw n}}function E(e,t){t=t||d.languages||Object.keys(n);const a=(e=>{const n={value:J(e),illegal:!1,relevance:0,_top:l,_emitter:new d.__emitter(d)};return n._emitter.addText(e),n})(e),i=t.filter(v).filter(O).map(n=>f(n,e,!1));i.unshift(a);const r=i.sort((e,n)=>{if(e.relevance!==n.relevance)return n.relevance-e.relevance;if(e.language&&n.language){if(v(e.language).supersetOf===n.language)return 1;if(v(n.language).supersetOf===e.language)return-1}return 0}),[s,o]=r,c=s;return c.secondBest=o,c}function y(e){let n=null;const t=(e=>{let n=e.className+" ";n+=e.parentNode?e.parentNode.className:"";const t=d.languageDetectRe.exec(n);if(t){const n=v(t[1]);return n||(H(o.replace("{}",t[1])),H("Falling back to no-highlight mode for this block.",e)),n?t[1]:"no-highlight"}return n.split(/\s+/).find(e=>_(e)||v(e))})(e);if(_(t))return;if(x("before:highlightElement",{el:e,language:t}),e.children.length>0&&(d.ignoreUnescapedHTML||(console.warn("One of your code blocks includes unescaped HTML. This is a potentially serious security risk."),console.warn("https://github.com/highlightjs/highlight.js/wiki/security"),console.warn("The element with unescaped HTML:"),console.warn(e)),d.throwUnescapedHTML))throw new V("One of your code blocks includes unescaped HTML.",e.innerHTML);n=e;const a=n.textContent,r=t?h(a,{language:t,ignoreIllegals:!0}):E(a);e.innerHTML=r.value,((e,n,t)=>{const a=n&&i[n]||t;e.classList.add("hljs"),e.classList.add("language-"+a)})(e,t,r.language),e.result={language:r.language,re:r.relevance,relevance:r.relevance},r.secondBest&&(e.secondBest={language:r.secondBest.language,relevance:r.secondBest.relevance}),x("after:highlightElement",{el:e,result:r,text:a})}let w=!1;function N(){"loading"!==document.readyState?document.querySelectorAll(d.cssSelector).forEach(y):w=!0}function v(e){return e=(e||"").toLowerCase(),n[e]||n[i[e]]}function k(e,{languageName:n}){"string"==typeof e&&(e=[e]),e.forEach(e=>{i[e.toLowerCase()]=n})}function O(e){const n=v(e);return n&&!n.disableAutodetect}function x(e,n){const t=e;r.forEach(e=>{e[t]&&e[t](n)})}"undefined"!=typeof window&&window.addEventListener&&window.addEventListener("DOMContentLoaded",()=>{w&&N()},!1),Object.assign(e,{highlight:h,highlightAuto:E,highlightAll:N,highlightElement:y,highlightBlock:e=>(q("10.7.0","highlightBlock will be removed entirely in v12.0"),q("10.7.0","Please use highlightElement now."),y(e)),configure:e=>{d=Y(d,e)},initHighlighting:()=>{N(),q("10.6.0","initHighlighting() deprecated. Use highlightAll() now.")},initHighlightingOnLoad:()=>{N(),q("10.6.0","initHighlightingOnLoad() deprecated. Use highlightAll() now.")},registerLanguage:(t,a)=>{let i=null;try{i=a(e)}catch(e){if(K("Language definition for '{}' could not be registered.".replace("{}",t)),!s)throw e;K(e),i=l}i.name||(i.name=t),n[t]=i,i.rawDefinition=a.bind(null,e),i.aliases&&k(i.aliases,{languageName:t})},unregisterLanguage:e=>{delete n[e];for(const n of Object.keys(i))i[n]===e&&delete i[n]},listLanguages:()=>Object.keys(n),getLanguage:v,registerAliases:k,autoDetection:O,inherit:Y,addPlugin:e=>{(e=>{e["before:highlightBlock"]&&!e["before:highlightElement"]&&(e["before:highlightElement"]=n=>{e["before:highlightBlock"](Object.assign({block:n.el},n))}),e["after:highlightBlock"]&&!e["after:highlightElement"]&&(e["after:highlightElement"]=n=>{e["after:highlightBlock"](Object.assign({block:n.el},n))})})(e),r.push(e)}}),e.debugMode=()=>{s=!1},e.safeMode=()=>{s=!0},e.versionString="11.5.0",e.regex={concat:m,lookahead:g,either:p,optional:b,anyNumberOfTimes:u};for(const e in T)"object"==typeof T[e]&&t(T[e]);return Object.assign(e,T),e})({});const te=e=>({IMPORTANT:{scope:"meta",begin:"!important"},BLOCK_COMMENT:e.C_BLOCK_COMMENT_MODE,HEXCOLOR:{scope:"number",begin:/#(([0-9a-fA-F]{3,4})|(([0-9a-fA-F]{2}){3,4}))\b/},FUNCTION_DISPATCH:{className:"built_in",begin:/[\w-]+(?=\()/},ATTRIBUTE_SELECTOR_MODE:{scope:"selector-attr",begin:/\[/,end:/\]/,illegal:"$",contains:[e.APOS_STRING_MODE,e.QUOTE_STRING_MODE]},CSS_NUMBER_MODE:{scope:"number",begin:e.NUMBER_RE+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",relevance:0},CSS_VARIABLE:{className:"attr",begin:/--[A-Za-z][A-Za-z0-9_-]*/}}),ae=["a","abbr","address","article","aside","audio","b","blockquote","body","button","canvas","caption","cite","code","dd","del","details","dfn","div","dl","dt","em","fieldset","figcaption","figure","footer","form","h1","h2","h3","h4","h5","h6","header","hgroup","html","i","iframe","img","input","ins","kbd","label","legend","li","main","mark","menu","nav","object","ol","p","q","quote","samp","section","span","strong","summary","sup","table","tbody","td","textarea","tfoot","th","thead","time","tr","ul","var","video"],ie=["any-hover","any-pointer","aspect-ratio","color","color-gamut","color-index","device-aspect-ratio","device-height","device-width","display-mode","forced-colors","grid","height","hover","inverted-colors","monochrome","orientation","overflow-block","overflow-inline","pointer","prefers-color-scheme","prefers-contrast","prefers-reduced-motion","prefers-reduced-transparency","resolution","scan","scripting","update","width","min-width","max-width","min-height","max-height"],re=["active","any-link","blank","checked","current","default","defined","dir","disabled","drop","empty","enabled","first","first-child","first-of-type","fullscreen","future","focus","focus-visible","focus-within","has","host","host-context","hover","indeterminate","in-range","invalid","is","lang","last-child","last-of-type","left","link","local-link","not","nth-child","nth-col","nth-last-child","nth-last-col","nth-last-of-type","nth-of-type","only-child","only-of-type","optional","out-of-range","past","placeholder-shown","read-only","read-write","required","right","root","scope","target","target-within","user-invalid","valid","visited","where"],se=["after","backdrop","before","cue","cue-region","first-letter","first-line","grammar-error","marker","part","placeholder","selection","slotted","spelling-error"],oe=["align-content","align-items","align-self","all","animation","animation-delay","animation-direction","animation-duration","animation-fill-mode","animation-iteration-count","animation-name","animation-play-state","animation-timing-function","backface-visibility","background","background-attachment","background-blend-mode","background-clip","background-color","background-image","background-origin","background-position","background-repeat","background-size","block-size","border","border-block","border-block-color","border-block-end","border-block-end-color","border-block-end-style","border-block-end-width","border-block-start","border-block-start-color","border-block-start-style","border-block-start-width","border-block-style","border-block-width","border-bottom","border-bottom-color","border-bottom-left-radius","border-bottom-right-radius","border-bottom-style","border-bottom-width","border-collapse","border-color","border-image","border-image-outset","border-image-repeat","border-image-slice","border-image-source","border-image-width","border-inline","border-inline-color","border-inline-end","border-inline-end-color","border-inline-end-style","border-inline-end-width","border-inline-start","border-inline-start-color","border-inline-start-style","border-inline-start-width","border-inline-style","border-inline-width","border-left","border-left-color","border-left-style","border-left-width","border-radius","border-right","border-right-color","border-right-style","border-right-width","border-spacing","border-style","border-top","border-top-color","border-top-left-radius","border-top-right-radius","border-top-style","border-top-width","border-width","bottom","box-decoration-break","box-shadow","box-sizing","break-after","break-before","break-inside","caption-side","caret-color","clear","clip","clip-path","clip-rule","color","column-count","column-fill","column-gap","column-rule","column-rule-color","column-rule-style","column-rule-width","column-span","column-width","columns","contain","content","content-visibility","counter-increment","counter-reset","cue","cue-after","cue-before","cursor","direction","display","empty-cells","filter","flex","flex-basis","flex-direction","flex-flow","flex-grow","flex-shrink","flex-wrap","float","flow","font","font-display","font-family","font-feature-settings","font-kerning","font-language-override","font-size","font-size-adjust","font-smoothing","font-stretch","font-style","font-synthesis","font-variant","font-variant-caps","font-variant-east-asian","font-variant-ligatures","font-variant-numeric","font-variant-position","font-variation-settings","font-weight","gap","glyph-orientation-vertical","grid","grid-area","grid-auto-columns","grid-auto-flow","grid-auto-rows","grid-column","grid-column-end","grid-column-start","grid-gap","grid-row","grid-row-end","grid-row-start","grid-template","grid-template-areas","grid-template-columns","grid-template-rows","hanging-punctuation","height","hyphens","icon","image-orientation","image-rendering","image-resolution","ime-mode","inline-size","isolation","justify-content","left","letter-spacing","line-break","line-height","list-style","list-style-image","list-style-position","list-style-type","margin","margin-block","margin-block-end","margin-block-start","margin-bottom","margin-inline","margin-inline-end","margin-inline-start","margin-left","margin-right","margin-top","marks","mask","mask-border","mask-border-mode","mask-border-outset","mask-border-repeat","mask-border-slice","mask-border-source","mask-border-width","mask-clip","mask-composite","mask-image","mask-mode","mask-origin","mask-position","mask-repeat","mask-size","mask-type","max-block-size","max-height","max-inline-size","max-width","min-block-size","min-height","min-inline-size","min-width","mix-blend-mode","nav-down","nav-index","nav-left","nav-right","nav-up","none","normal","object-fit","object-position","opacity","order","orphans","outline","outline-color","outline-offset","outline-style","outline-width","overflow","overflow-wrap","overflow-x","overflow-y","padding","padding-block","padding-block-end","padding-block-start","padding-bottom","padding-inline","padding-inline-end","padding-inline-start","padding-left","padding-right","padding-top","page-break-after","page-break-before","page-break-inside","pause","pause-after","pause-before","perspective","perspective-origin","pointer-events","position","quotes","resize","rest","rest-after","rest-before","right","row-gap","scroll-margin","scroll-margin-block","scroll-margin-block-end","scroll-margin-block-start","scroll-margin-bottom","scroll-margin-inline","scroll-margin-inline-end","scroll-margin-inline-start","scroll-margin-left","scroll-margin-right","scroll-margin-top","scroll-padding","scroll-padding-block","scroll-padding-block-end","scroll-padding-block-start","scroll-padding-bottom","scroll-padding-inline","scroll-padding-inline-end","scroll-padding-inline-start","scroll-padding-left","scroll-padding-right","scroll-padding-top","scroll-snap-align","scroll-snap-stop","scroll-snap-type","scrollbar-color","scrollbar-gutter","scrollbar-width","shape-image-threshold","shape-margin","shape-outside","speak","speak-as","src","tab-size","table-layout","text-align","text-align-all","text-align-last","text-combine-upright","text-decoration","text-decoration-color","text-decoration-line","text-decoration-style","text-emphasis","text-emphasis-color","text-emphasis-position","text-emphasis-style","text-indent","text-justify","text-orientation","text-overflow","text-rendering","text-shadow","text-transform","text-underline-position","top","transform","transform-box","transform-origin","transform-style","transition","transition-delay","transition-duration","transition-property","transition-timing-function","unicode-bidi","vertical-align","visibility","voice-balance","voice-duration","voice-family","voice-pitch","voice-range","voice-rate","voice-stress","voice-volume","white-space","widows","width","will-change","word-break","word-spacing","word-wrap","writing-mode","z-index"].reverse(),le=re.concat(se);var ce="\\.([0-9](_*[0-9])*)",de="[0-9a-fA-F](_*[0-9a-fA-F])*",ge={className:"number",variants:[{begin:`(\\b([0-9](_*[0-9])*)((${ce})|\\.)?|(${ce}))[eE][+-]?([0-9](_*[0-9])*)[fFdD]?\\b`},{begin:`\\b([0-9](_*[0-9])*)((${ce})[fFdD]?\\b|\\.([fFdD]\\b)?)`},{begin:`(${ce})[fFdD]?\\b`},{begin:"\\b([0-9](_*[0-9])*)[fFdD]\\b"},{begin:`\\b0[xX]((${de})\\.?|(${de})?\\.(${de}))[pP][+-]?([0-9](_*[0-9])*)[fFdD]?\\b`},{begin:"\\b(0|[1-9](_*[0-9])*)[lL]?\\b"},{begin:`\\b0[xX](${de})[lL]?\\b`},{begin:"\\b0(_*[0-7])*[lL]?\\b"},{begin:"\\b0[bB][01](_*[01])*[lL]?\\b"}],relevance:0};function ue(e,n,t){return-1===t?"":e.replace(n,a=>ue(e,n,t-1))}const be="[A-Za-z$_][0-9A-Za-z$_]*",me=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","switch","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends"],pe=["true","false","null","undefined","NaN","Infinity"],_e=["Object","Function","Boolean","Symbol","Math","Date","Number","BigInt","String","RegExp","Array","Float32Array","Float64Array","Int8Array","Uint8Array","Uint8ClampedArray","Int16Array","Int32Array","Uint16Array","Uint32Array","BigInt64Array","BigUint64Array","Set","Map","WeakSet","WeakMap","ArrayBuffer","SharedArrayBuffer","Atomics","DataView","JSON","Promise","Generator","GeneratorFunction","AsyncFunction","Reflect","Proxy","Intl","WebAssembly"],he=["Error","EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"],fe=["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],Ee=["arguments","this","super","console","window","document","localStorage","module","global"],ye=[].concat(fe,_e,he);function we(e){const n=e.regex,t=be,a={begin:/<[A-Za-z0-9\\._:-]+/,end:/\/[A-Za-z0-9\\._:-]+>|\/>/,isTrulyOpeningTag:(e,n)=>{const t=e[0].length+e.index,a=e.input[t];if("<"===a||","===a)return void n.ignoreMatch();let i;">"===a&&(((e,{after:n})=>{const t="",O={match:[/const|var|let/,/\s+/,t,/\s*/,/=\s*/,/(async\s*)?/,n.lookahead(k)],keywords:"async",className:{1:"keyword",3:"title.function"},contains:[_]};return{name:"Javascript",aliases:["js","jsx","mjs","cjs"],keywords:i,exports:{PARAMS_CONTAINS:p,CLASS_REFERENCE:f},illegal:/#(?![$_A-z])/,contains:[e.SHEBANG({label:"shebang",binary:"node",relevance:5}),{label:"use_strict",className:"meta",relevance:10,begin:/^\s*['"]use (strict|asm)['"]/},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,c,d,g,u,o,f,{className:"attr",begin:t+n.lookahead(":"),relevance:0},O,{begin:"("+e.RE_STARTERS_RE+"|\\b(case|return|throw)\\b)\\s*",keywords:"return throw case",relevance:0,contains:[u,e.REGEXP_MODE,{className:"function",begin:k,returnBegin:!0,end:"\\s*=>",contains:[{className:"params",variants:[{begin:e.UNDERSCORE_IDENT_RE,relevance:0},{className:null,begin:/\(\s*\)/,skip:!0},{begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:i,contains:p}]}]},{begin:/,/,relevance:0},{match:/\s+/,relevance:0},{variants:[{begin:"<>",end:""},{match:/<[A-Za-z0-9\\._:-]+\s*\/>/},{begin:a.begin,"on:begin":a.isTrulyOpeningTag,end:a.end}],subLanguage:"xml",contains:[{begin:a.begin,end:a.end,skip:!0,contains:["self"]}]}]},E,{beginKeywords:"while if switch catch for"},{begin:"\\b(?!function)"+e.UNDERSCORE_IDENT_RE+"\\([^()]*(\\([^()]*(\\([^()]*\\)[^()]*)*\\)[^()]*)*\\)\\s*\\{",returnBegin:!0,label:"func.def",contains:[_,e.inherit(e.TITLE_MODE,{begin:t,className:"title.function"})]},{match:/\.\.\./,relevance:0},N,{match:"\\$"+t,relevance:0},{match:[/\bconstructor(?=\s*\()/],className:{1:"title.function"},contains:[_]},y,{relevance:0,match:/\b[A-Z][A-Z_0-9]+\b/,className:"variable.constant"},h,v,{match:/\$[(.]/}]}}const Ne=e=>m(/\b/,e,/\w$/.test(e)?/\b/:/\B/),ve=["Protocol","Type"].map(Ne),ke=["init","self"].map(Ne),Oe=["Any","Self"],xe=["actor","associatedtype","async","await",/as\?/,/as!/,"as","break","case","catch","class","continue","convenience","default","defer","deinit","didSet","do","dynamic","else","enum","extension","fallthrough",/fileprivate\(set\)/,"fileprivate","final","for","func","get","guard","if","import","indirect","infix",/init\?/,/init!/,"inout",/internal\(set\)/,"internal","in","is","isolated","nonisolated","lazy","let","mutating","nonmutating",/open\(set\)/,"open","operator","optional","override","postfix","precedencegroup","prefix",/private\(set\)/,"private","protocol",/public\(set\)/,"public","repeat","required","rethrows","return","set","some","static","struct","subscript","super","switch","throws","throw",/try\?/,/try!/,"try","typealias",/unowned\(safe\)/,/unowned\(unsafe\)/,"unowned","var","weak","where","while","willSet"],Me=["false","nil","true"],Se=["assignment","associativity","higherThan","left","lowerThan","none","right"],Ae=["#colorLiteral","#column","#dsohandle","#else","#elseif","#endif","#error","#file","#fileID","#fileLiteral","#filePath","#function","#if","#imageLiteral","#keyPath","#line","#selector","#sourceLocation","#warn_unqualified_access","#warning"],Ce=["abs","all","any","assert","assertionFailure","debugPrint","dump","fatalError","getVaList","isKnownUniquelyReferenced","max","min","numericCast","pointwiseMax","pointwiseMin","precondition","preconditionFailure","print","readLine","repeatElement","sequence","stride","swap","swift_unboxFromSwiftValueWithType","transcode","type","unsafeBitCast","unsafeDowncast","withExtendedLifetime","withUnsafeMutablePointer","withUnsafePointer","withVaList","withoutActuallyEscaping","zip"],Te=p(/[/=\-+!*%<>&|^~?]/,/[\u00A1-\u00A7]/,/[\u00A9\u00AB]/,/[\u00AC\u00AE]/,/[\u00B0\u00B1]/,/[\u00B6\u00BB\u00BF\u00D7\u00F7]/,/[\u2016-\u2017]/,/[\u2020-\u2027]/,/[\u2030-\u203E]/,/[\u2041-\u2053]/,/[\u2055-\u205E]/,/[\u2190-\u23FF]/,/[\u2500-\u2775]/,/[\u2794-\u2BFF]/,/[\u2E00-\u2E7F]/,/[\u3001-\u3003]/,/[\u3008-\u3020]/,/[\u3030]/),Re=p(Te,/[\u0300-\u036F]/,/[\u1DC0-\u1DFF]/,/[\u20D0-\u20FF]/,/[\uFE00-\uFE0F]/,/[\uFE20-\uFE2F]/),De=m(Te,Re,"*"),Ie=p(/[a-zA-Z_]/,/[\u00A8\u00AA\u00AD\u00AF\u00B2-\u00B5\u00B7-\u00BA]/,/[\u00BC-\u00BE\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF]/,/[\u0100-\u02FF\u0370-\u167F\u1681-\u180D\u180F-\u1DBF]/,/[\u1E00-\u1FFF]/,/[\u200B-\u200D\u202A-\u202E\u203F-\u2040\u2054\u2060-\u206F]/,/[\u2070-\u20CF\u2100-\u218F\u2460-\u24FF\u2776-\u2793]/,/[\u2C00-\u2DFF\u2E80-\u2FFF]/,/[\u3004-\u3007\u3021-\u302F\u3031-\u303F\u3040-\uD7FF]/,/[\uF900-\uFD3D\uFD40-\uFDCF\uFDF0-\uFE1F\uFE30-\uFE44]/,/[\uFE47-\uFEFE\uFF00-\uFFFD]/),Le=p(Ie,/\d/,/[\u0300-\u036F\u1DC0-\u1DFF\u20D0-\u20FF\uFE20-\uFE2F]/),Be=m(Ie,Le,"*"),$e=m(/[A-Z]/,Le,"*"),ze=["autoclosure",m(/convention\(/,p("swift","block","c"),/\)/),"discardableResult","dynamicCallable","dynamicMemberLookup","escaping","frozen","GKInspectable","IBAction","IBDesignable","IBInspectable","IBOutlet","IBSegueAction","inlinable","main","nonobjc","NSApplicationMain","NSCopying","NSManaged",m(/objc\(/,Be,/\)/),"objc","objcMembers","propertyWrapper","requires_stored_property_inits","resultBuilder","testable","UIApplicationMain","unknown","usableFromInline"],Fe=["iOS","iOSApplicationExtension","macOS","macOSApplicationExtension","macCatalyst","macCatalystApplicationExtension","watchOS","watchOSApplicationExtension","tvOS","tvOSApplicationExtension","swift"];var Ue=Object.freeze({__proto__:null,grmr_bash:e=>{const n=e.regex,t={},a={begin:/\$\{/,end:/\}/,contains:["self",{begin:/:-/,contains:[t]}]};Object.assign(t,{className:"variable",variants:[{begin:n.concat(/\$[\w\d#@][\w\d_]*/,"(?![\\w\\d])(?![$])")},a]});const i={className:"subst",begin:/\$\(/,end:/\)/,contains:[e.BACKSLASH_ESCAPE]},r={begin:/<<-?\s*(?=\w+)/,starts:{contains:[e.END_SAME_AS_BEGIN({begin:/(\w+)/,end:/(\w+)/,className:"string"})]}},s={className:"string",begin:/"/,end:/"/,contains:[e.BACKSLASH_ESCAPE,t,i]};i.contains.push(s);const o={begin:/\$\(\(/,end:/\)\)/,contains:[{begin:/\d+#[0-9a-f]+/,className:"number"},e.NUMBER_MODE,t]},l=e.SHEBANG({binary:"(fish|bash|zsh|sh|csh|ksh|tcsh|dash|scsh)",relevance:10}),c={className:"function",begin:/\w[\w\d_]*\s*\(\s*\)\s*\{/,returnBegin:!0,contains:[e.inherit(e.TITLE_MODE,{begin:/\w[\w\d_]*/})],relevance:0};return{name:"Bash",aliases:["sh"],keywords:{$pattern:/\b[a-z][a-z0-9._-]+\b/,keyword:["if","then","else","elif","fi","for","while","in","do","done","case","esac","function"],literal:["true","false"],built_in:["break","cd","continue","eval","exec","exit","export","getopts","hash","pwd","readonly","return","shift","test","times","trap","umask","unset","alias","bind","builtin","caller","command","declare","echo","enable","help","let","local","logout","mapfile","printf","read","readarray","source","type","typeset","ulimit","unalias","set","shopt","autoload","bg","bindkey","bye","cap","chdir","clone","comparguments","compcall","compctl","compdescribe","compfiles","compgroups","compquote","comptags","comptry","compvalues","dirs","disable","disown","echotc","echoti","emulate","fc","fg","float","functions","getcap","getln","history","integer","jobs","kill","limit","log","noglob","popd","print","pushd","pushln","rehash","sched","setcap","setopt","stat","suspend","ttyctl","unfunction","unhash","unlimit","unsetopt","vared","wait","whence","where","which","zcompile","zformat","zftp","zle","zmodload","zparseopts","zprof","zpty","zregexparse","zsocket","zstyle","ztcp","chcon","chgrp","chown","chmod","cp","dd","df","dir","dircolors","ln","ls","mkdir","mkfifo","mknod","mktemp","mv","realpath","rm","rmdir","shred","sync","touch","truncate","vdir","b2sum","base32","base64","cat","cksum","comm","csplit","cut","expand","fmt","fold","head","join","md5sum","nl","numfmt","od","paste","ptx","pr","sha1sum","sha224sum","sha256sum","sha384sum","sha512sum","shuf","sort","split","sum","tac","tail","tr","tsort","unexpand","uniq","wc","arch","basename","chroot","date","dirname","du","echo","env","expr","factor","groups","hostid","id","link","logname","nice","nohup","nproc","pathchk","pinky","printenv","printf","pwd","readlink","runcon","seq","sleep","stat","stdbuf","stty","tee","test","timeout","tty","uname","unlink","uptime","users","who","whoami","yes"]},contains:[l,e.SHEBANG(),c,o,e.HASH_COMMENT_MODE,r,{match:/(\/[a-z._-]+)+/},s,{className:"",begin:/\\"/},{className:"string",begin:/'/,end:/'/},t]}},grmr_c:e=>{const n=e.regex,t=e.COMMENT("//","$",{contains:[{begin:/\\\n/}]}),a="[a-zA-Z_]\\w*::",i="(decltype\\(auto\\)|"+n.optional(a)+"[a-zA-Z_]\\w*"+n.optional("<[^<>]+>")+")",r={className:"type",variants:[{begin:"\\b[a-z\\d_]*_t\\b"},{match:/\batomic_[a-z]{3,6}\b/}]},s={className:"string",variants:[{begin:'(u8?|U|L)?"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE]},{begin:"(u8?|U|L)?'(\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4,8}|[0-7]{3}|\\S)|.)",end:"'",illegal:"."},e.END_SAME_AS_BEGIN({begin:/(?:u8?|U|L)?R"([^()\\ ]{0,16})\(/,end:/\)([^()\\ ]{0,16})"/})]},o={className:"number",variants:[{begin:"\\b(0b[01']+)"},{begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)((ll|LL|l|L)(u|U)?|(u|U)(ll|LL|l|L)?|f|F|b|B)"},{begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)"}],relevance:0},l={className:"meta",begin:/#\s*[a-z]+\b/,end:/$/,keywords:{keyword:"if else elif endif define undef warning error line pragma _Pragma ifdef ifndef include"},contains:[{begin:/\\\n/,relevance:0},e.inherit(s,{className:"string"}),{className:"string",begin:/<.*?>/},t,e.C_BLOCK_COMMENT_MODE]},c={className:"title",begin:n.optional(a)+e.IDENT_RE,relevance:0},d=n.optional(a)+e.IDENT_RE+"\\s*\\(",g={keyword:["asm","auto","break","case","continue","default","do","else","enum","extern","for","fortran","goto","if","inline","register","restrict","return","sizeof","struct","switch","typedef","union","volatile","while","_Alignas","_Alignof","_Atomic","_Generic","_Noreturn","_Static_assert","_Thread_local","alignas","alignof","noreturn","static_assert","thread_local","_Pragma"],type:["float","double","signed","unsigned","int","short","long","char","void","_Bool","_Complex","_Imaginary","_Decimal32","_Decimal64","_Decimal128","const","static","complex","bool","imaginary"],literal:"true false NULL",built_in:"std string wstring cin cout cerr clog stdin stdout stderr stringstream istringstream ostringstream auto_ptr deque list queue stack vector map set pair bitset multiset multimap unordered_set unordered_map unordered_multiset unordered_multimap priority_queue make_pair array shared_ptr abort terminate abs acos asin atan2 atan calloc ceil cosh cos exit exp fabs floor fmod fprintf fputs free frexp fscanf future isalnum isalpha iscntrl isdigit isgraph islower isprint ispunct isspace isupper isxdigit tolower toupper labs ldexp log10 log malloc realloc memchr memcmp memcpy memset modf pow printf putchar puts scanf sinh sin snprintf sprintf sqrt sscanf strcat strchr strcmp strcpy strcspn strlen strncat strncmp strncpy strpbrk strrchr strspn strstr tanh tan vfprintf vprintf vsprintf endl initializer_list unique_ptr"},u=[l,r,t,e.C_BLOCK_COMMENT_MODE,o,s],b={variants:[{begin:/=/,end:/;/},{begin:/\(/,end:/\)/},{beginKeywords:"new throw return else",end:/;/}],keywords:g,contains:u.concat([{begin:/\(/,end:/\)/,keywords:g,contains:u.concat(["self"]),relevance:0}]),relevance:0},m={begin:"("+i+"[\\*&\\s]+)+"+d,returnBegin:!0,end:/[{;=]/,excludeEnd:!0,keywords:g,illegal:/[^\w\s\*&:<>.]/,contains:[{begin:"decltype\\(auto\\)",keywords:g,relevance:0},{begin:d,returnBegin:!0,contains:[e.inherit(c,{className:"title.function"})],relevance:0},{relevance:0,match:/,/},{className:"params",begin:/\(/,end:/\)/,keywords:g,relevance:0,contains:[t,e.C_BLOCK_COMMENT_MODE,s,o,r,{begin:/\(/,end:/\)/,keywords:g,relevance:0,contains:["self",t,e.C_BLOCK_COMMENT_MODE,s,o,r]}]},r,t,e.C_BLOCK_COMMENT_MODE,l]};return{name:"C",aliases:["h"],keywords:g,disableAutodetect:!0,illegal:"=]/,contains:[{beginKeywords:"final class struct"},e.TITLE_MODE]}]),exports:{preprocessor:l,strings:s,keywords:g}}},grmr_cpp:e=>{const n=e.regex,t=e.COMMENT("//","$",{contains:[{begin:/\\\n/}]}),a="[a-zA-Z_]\\w*::",i="(?!struct)(decltype\\(auto\\)|"+n.optional(a)+"[a-zA-Z_]\\w*"+n.optional("<[^<>]+>")+")",r={className:"type",begin:"\\b[a-z\\d_]*_t\\b"},s={className:"string",variants:[{begin:'(u8?|U|L)?"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE]},{begin:"(u8?|U|L)?'(\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4,8}|[0-7]{3}|\\S)|.)",end:"'",illegal:"."},e.END_SAME_AS_BEGIN({begin:/(?:u8?|U|L)?R"([^()\\ ]{0,16})\(/,end:/\)([^()\\ ]{0,16})"/})]},o={className:"number",variants:[{begin:"\\b(0b[01']+)"},{begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)((ll|LL|l|L)(u|U)?|(u|U)(ll|LL|l|L)?|f|F|b|B)"},{begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)"}],relevance:0},l={className:"meta",begin:/#\s*[a-z]+\b/,end:/$/,keywords:{keyword:"if else elif endif define undef warning error line pragma _Pragma ifdef ifndef include"},contains:[{begin:/\\\n/,relevance:0},e.inherit(s,{className:"string"}),{className:"string",begin:/<.*?>/},t,e.C_BLOCK_COMMENT_MODE]},c={className:"title",begin:n.optional(a)+e.IDENT_RE,relevance:0},d=n.optional(a)+e.IDENT_RE+"\\s*\\(",g={type:["bool","char","char16_t","char32_t","char8_t","double","float","int","long","short","void","wchar_t","unsigned","signed","const","static"],keyword:["alignas","alignof","and","and_eq","asm","atomic_cancel","atomic_commit","atomic_noexcept","auto","bitand","bitor","break","case","catch","class","co_await","co_return","co_yield","compl","concept","const_cast|10","consteval","constexpr","constinit","continue","decltype","default","delete","do","dynamic_cast|10","else","enum","explicit","export","extern","false","final","for","friend","goto","if","import","inline","module","mutable","namespace","new","noexcept","not","not_eq","nullptr","operator","or","or_eq","override","private","protected","public","reflexpr","register","reinterpret_cast|10","requires","return","sizeof","static_assert","static_cast|10","struct","switch","synchronized","template","this","thread_local","throw","transaction_safe","transaction_safe_dynamic","true","try","typedef","typeid","typename","union","using","virtual","volatile","while","xor","xor_eq"],literal:["NULL","false","nullopt","nullptr","true"],built_in:["_Pragma"],_type_hints:["any","auto_ptr","barrier","binary_semaphore","bitset","complex","condition_variable","condition_variable_any","counting_semaphore","deque","false_type","future","imaginary","initializer_list","istringstream","jthread","latch","lock_guard","multimap","multiset","mutex","optional","ostringstream","packaged_task","pair","promise","priority_queue","queue","recursive_mutex","recursive_timed_mutex","scoped_lock","set","shared_future","shared_lock","shared_mutex","shared_timed_mutex","shared_ptr","stack","string_view","stringstream","timed_mutex","thread","true_type","tuple","unique_lock","unique_ptr","unordered_map","unordered_multimap","unordered_multiset","unordered_set","variant","vector","weak_ptr","wstring","wstring_view"]},u={className:"function.dispatch",relevance:0,keywords:{_hint:["abort","abs","acos","apply","as_const","asin","atan","atan2","calloc","ceil","cerr","cin","clog","cos","cosh","cout","declval","endl","exchange","exit","exp","fabs","floor","fmod","forward","fprintf","fputs","free","frexp","fscanf","future","invoke","isalnum","isalpha","iscntrl","isdigit","isgraph","islower","isprint","ispunct","isspace","isupper","isxdigit","labs","launder","ldexp","log","log10","make_pair","make_shared","make_shared_for_overwrite","make_tuple","make_unique","malloc","memchr","memcmp","memcpy","memset","modf","move","pow","printf","putchar","puts","realloc","scanf","sin","sinh","snprintf","sprintf","sqrt","sscanf","std","stderr","stdin","stdout","strcat","strchr","strcmp","strcpy","strcspn","strlen","strncat","strncmp","strncpy","strpbrk","strrchr","strspn","strstr","swap","tan","tanh","terminate","to_underlying","tolower","toupper","vfprintf","visit","vprintf","vsprintf"]},begin:n.concat(/\b/,/(?!decltype)/,/(?!if)/,/(?!for)/,/(?!switch)/,/(?!while)/,e.IDENT_RE,n.lookahead(/(<[^<>]+>|)\s*\(/))},b=[u,l,r,t,e.C_BLOCK_COMMENT_MODE,o,s],m={variants:[{begin:/=/,end:/;/},{begin:/\(/,end:/\)/},{beginKeywords:"new throw return else",end:/;/}],keywords:g,contains:b.concat([{begin:/\(/,end:/\)/,keywords:g,contains:b.concat(["self"]),relevance:0}]),relevance:0},p={className:"function",begin:"("+i+"[\\*&\\s]+)+"+d,returnBegin:!0,end:/[{;=]/,excludeEnd:!0,keywords:g,illegal:/[^\w\s\*&:<>.]/,contains:[{begin:"decltype\\(auto\\)",keywords:g,relevance:0},{begin:d,returnBegin:!0,contains:[c],relevance:0},{begin:/::/,relevance:0},{begin:/:/,endsWithParent:!0,contains:[s,o]},{relevance:0,match:/,/},{className:"params",begin:/\(/,end:/\)/,keywords:g,relevance:0,contains:[t,e.C_BLOCK_COMMENT_MODE,s,o,r,{begin:/\(/,end:/\)/,keywords:g,relevance:0,contains:["self",t,e.C_BLOCK_COMMENT_MODE,s,o,r]}]},r,t,e.C_BLOCK_COMMENT_MODE,l]};return{name:"C++",aliases:["cc","c++","h++","hpp","hh","hxx","cxx"],keywords:g,illegal:"",keywords:g,contains:["self",r]},{begin:e.IDENT_RE+"::",keywords:g},{match:[/\b(?:enum(?:\s+(?:class|struct))?|class|struct|union)/,/\s+/,/\w+/],className:{1:"keyword",3:"title.class"}}])}},grmr_csharp:e=>{const n={keyword:["abstract","as","base","break","case","catch","class","const","continue","do","else","event","explicit","extern","finally","fixed","for","foreach","goto","if","implicit","in","interface","internal","is","lock","namespace","new","operator","out","override","params","private","protected","public","readonly","record","ref","return","sealed","sizeof","stackalloc","static","struct","switch","this","throw","try","typeof","unchecked","unsafe","using","virtual","void","volatile","while"].concat(["add","alias","and","ascending","async","await","by","descending","equals","from","get","global","group","init","into","join","let","nameof","not","notnull","on","or","orderby","partial","remove","select","set","unmanaged","value|0","var","when","where","with","yield"]),built_in:["bool","byte","char","decimal","delegate","double","dynamic","enum","float","int","long","nint","nuint","object","sbyte","short","string","ulong","uint","ushort"],literal:["default","false","null","true"]},t=e.inherit(e.TITLE_MODE,{begin:"[a-zA-Z](\\.?\\w)*"}),a={className:"number",variants:[{begin:"\\b(0b[01']+)"},{begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)(u|U|l|L|ul|UL|f|F|b|B)"},{begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)"}],relevance:0},i={className:"string",begin:'@"',end:'"',contains:[{begin:'""'}]},r=e.inherit(i,{illegal:/\n/}),s={className:"subst",begin:/\{/,end:/\}/,keywords:n},o=e.inherit(s,{illegal:/\n/}),l={className:"string",begin:/\$"/,end:'"',illegal:/\n/,contains:[{begin:/\{\{/},{begin:/\}\}/},e.BACKSLASH_ESCAPE,o]},c={className:"string",begin:/\$@"/,end:'"',contains:[{begin:/\{\{/},{begin:/\}\}/},{begin:'""'},s]},d=e.inherit(c,{illegal:/\n/,contains:[{begin:/\{\{/},{begin:/\}\}/},{begin:'""'},o]});s.contains=[c,l,i,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,a,e.C_BLOCK_COMMENT_MODE],o.contains=[d,l,r,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,a,e.inherit(e.C_BLOCK_COMMENT_MODE,{illegal:/\n/})];const g={variants:[c,l,i,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE]},u={begin:"<",end:">",contains:[{beginKeywords:"in out"},t]},b=e.IDENT_RE+"(<"+e.IDENT_RE+"(\\s*,\\s*"+e.IDENT_RE+")*>)?(\\[\\])?",m={begin:"@"+e.IDENT_RE,relevance:0};return{name:"C#",aliases:["cs","c#"],keywords:n,illegal:/::/,contains:[e.COMMENT("///","$",{returnBegin:!0,contains:[{className:"doctag",variants:[{begin:"///",relevance:0},{begin:"\x3c!--|--\x3e"},{begin:""}]}]}),e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{className:"meta",begin:"#",end:"$",keywords:{keyword:"if else elif endif define undef warning error line region endregion pragma checksum"}},g,a,{beginKeywords:"class interface",relevance:0,end:/[{;=]/,illegal:/[^\s:,]/,contains:[{beginKeywords:"where class"},t,u,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{beginKeywords:"namespace",relevance:0,end:/[{;=]/,illegal:/[^\s:]/,contains:[t,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{beginKeywords:"record",relevance:0,end:/[{;=]/,illegal:/[^\s:]/,contains:[t,u,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{className:"meta",begin:"^\\s*\\[(?=[\\w])",excludeBegin:!0,end:"\\]",excludeEnd:!0,contains:[{className:"string",begin:/"/,end:/"/}]},{beginKeywords:"new return throw await else",relevance:0},{className:"function",begin:"("+b+"\\s+)+"+e.IDENT_RE+"\\s*(<[^=]+>\\s*)?\\(",returnBegin:!0,end:/\s*[{;=]/,excludeEnd:!0,keywords:n,contains:[{beginKeywords:"public private protected static internal protected abstract async extern override unsafe virtual new sealed partial",relevance:0},{begin:e.IDENT_RE+"\\s*(<[^=]+>\\s*)?\\(",returnBegin:!0,contains:[e.TITLE_MODE,u],relevance:0},{match:/\(\)/},{className:"params",begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:n,relevance:0,contains:[g,a,e.C_BLOCK_COMMENT_MODE]},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},m]}},grmr_css:e=>{const n=e.regex,t=te(e),a=[e.APOS_STRING_MODE,e.QUOTE_STRING_MODE];return{name:"CSS",case_insensitive:!0,illegal:/[=|'\$]/,keywords:{keyframePosition:"from to"},classNameAliases:{keyframePosition:"selector-tag"},contains:[t.BLOCK_COMMENT,{begin:/-(webkit|moz|ms|o)-(?=[a-z])/},t.CSS_NUMBER_MODE,{className:"selector-id",begin:/#[A-Za-z0-9_-]+/,relevance:0},{className:"selector-class",begin:"\\.[a-zA-Z-][a-zA-Z0-9_-]*",relevance:0},t.ATTRIBUTE_SELECTOR_MODE,{className:"selector-pseudo",variants:[{begin:":("+re.join("|")+")"},{begin:":(:)?("+se.join("|")+")"}]},t.CSS_VARIABLE,{className:"attribute",begin:"\\b("+oe.join("|")+")\\b"},{begin:/:/,end:/[;}{]/,contains:[t.BLOCK_COMMENT,t.HEXCOLOR,t.IMPORTANT,t.CSS_NUMBER_MODE,...a,{begin:/(url|data-uri)\(/,end:/\)/,relevance:0,keywords:{built_in:"url data-uri"},contains:[{className:"string",begin:/[^)]/,endsWithParent:!0,excludeEnd:!0}]},t.FUNCTION_DISPATCH]},{begin:n.lookahead(/@/),end:"[{;]",relevance:0,illegal:/:/,contains:[{className:"keyword",begin:/@-?\w[\w]*(-\w+)*/},{begin:/\s/,endsWithParent:!0,excludeEnd:!0,relevance:0,keywords:{$pattern:/[a-z-]+/,keyword:"and or not only",attribute:ie.join(" ")},contains:[{begin:/[a-z-]+(?=:)/,className:"attribute"},...a,t.CSS_NUMBER_MODE]}]},{className:"selector-tag",begin:"\\b("+ae.join("|")+")\\b"}]}},grmr_diff:e=>{const n=e.regex;return{name:"Diff",aliases:["patch"],contains:[{className:"meta",relevance:10,match:n.either(/^@@ +-\d+,\d+ +\+\d+,\d+ +@@/,/^\*\*\* +\d+,\d+ +\*\*\*\*$/,/^--- +\d+,\d+ +----$/)},{className:"comment",variants:[{begin:n.either(/Index: /,/^index/,/={3,}/,/^-{3}/,/^\*{3} /,/^\+{3}/,/^diff --git/),end:/$/},{match:/^\*{15}$/}]},{className:"addition",begin:/^\+/,end:/$/},{className:"deletion",begin:/^-/,end:/$/},{className:"addition",begin:/^!/,end:/$/}]}},grmr_go:e=>{const n={keyword:["break","case","chan","const","continue","default","defer","else","fallthrough","for","func","go","goto","if","import","interface","map","package","range","return","select","struct","switch","type","var"],type:["bool","byte","complex64","complex128","error","float32","float64","int8","int16","int32","int64","string","uint8","uint16","uint32","uint64","int","uint","uintptr","rune"],literal:["true","false","iota","nil"],built_in:["append","cap","close","complex","copy","imag","len","make","new","panic","print","println","real","recover","delete"]};return{name:"Go",aliases:["golang"],keywords:n,illegal:"{const n=e.regex,t={className:"number",relevance:0,variants:[{begin:/([+-]+)?[\d]+_[\d_]+/},{begin:e.NUMBER_RE}]},a=e.COMMENT();a.variants=[{begin:/;/,end:/$/},{begin:/#/,end:/$/}];const i={className:"variable",variants:[{begin:/\$[\w\d"][\w\d_]*/},{begin:/\$\{(.*?)\}/}]},r={className:"literal",begin:/\bon|off|true|false|yes|no\b/},s={className:"string",contains:[e.BACKSLASH_ESCAPE],variants:[{begin:"'''",end:"'''",relevance:10},{begin:'"""',end:'"""',relevance:10},{begin:'"',end:'"'},{begin:"'",end:"'"}]},o={begin:/\[/,end:/\]/,contains:[a,r,i,s,t,"self"],relevance:0},l=n.either(/[A-Za-z0-9_-]+/,/"(\\"|[^"])*"/,/'[^']*'/);return{name:"TOML, also INI",aliases:["toml"],case_insensitive:!0,illegal:/\S/,contains:[a,{className:"section",begin:/\[+/,end:/\]+/},{begin:n.concat(l,"(\\s*\\.\\s*",l,")*",n.lookahead(/\s*=\s*[^#\s]/)),className:"attr",starts:{end:/$/,contains:[a,o,r,i,s,t]}}]}},grmr_java:e=>{const n=e.regex,t="[À-ʸa-zA-Z_$][À-ʸa-zA-Z_$0-9]*",a=t+ue("(?:<"+t+"~~~(?:\\s*,\\s*"+t+"~~~)*>)?",/~~~/g,2),i={keyword:["synchronized","abstract","private","var","static","if","const ","for","while","strictfp","finally","protected","import","native","final","void","enum","else","break","transient","catch","instanceof","volatile","case","assert","package","default","public","try","switch","continue","throws","protected","public","private","module","requires","exports","do","sealed"],literal:["false","true","null"],type:["char","boolean","long","float","int","byte","short","double"],built_in:["super","this"]},r={className:"meta",begin:"@"+t,contains:[{begin:/\(/,end:/\)/,contains:["self"]}]},s={className:"params",begin:/\(/,end:/\)/,keywords:i,relevance:0,contains:[e.C_BLOCK_COMMENT_MODE],endsParent:!0};return{name:"Java",aliases:["jsp"],keywords:i,illegal:/<\/|#/,contains:[e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{begin:/\w+@/,relevance:0},{className:"doctag",begin:"@[A-Za-z]+"}]}),{begin:/import java\.[a-z]+\./,keywords:"import",relevance:2},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{begin:/"""/,end:/"""/,className:"string",contains:[e.BACKSLASH_ESCAPE]},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,{match:[/\b(?:class|interface|enum|extends|implements|new)/,/\s+/,t],className:{1:"keyword",3:"title.class"}},{match:/non-sealed/,scope:"keyword"},{begin:[n.concat(/(?!else)/,t),/\s+/,t,/\s+/,/=/],className:{1:"type",3:"variable",5:"operator"}},{begin:[/record/,/\s+/,t],className:{1:"keyword",3:"title.class"},contains:[s,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{beginKeywords:"new throw return else",relevance:0},{begin:["(?:"+a+"\\s+)",e.UNDERSCORE_IDENT_RE,/\s*(?=\()/],className:{2:"title.function"},keywords:i,contains:[{className:"params",begin:/\(/,end:/\)/,keywords:i,relevance:0,contains:[r,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,ge,e.C_BLOCK_COMMENT_MODE]},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},ge,r]}},grmr_javascript:we,grmr_json:e=>({name:"JSON",contains:[{className:"attr",begin:/"(\\.|[^\\"\r\n])*"(?=\s*:)/,relevance:1.01},{match:/[{}[\],:]/,className:"punctuation",relevance:0},e.QUOTE_STRING_MODE,{beginKeywords:"true false null"},e.C_NUMBER_MODE,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE],illegal:"\\S"}),grmr_kotlin:e=>{const n={keyword:"abstract as val var vararg get set class object open private protected public noinline crossinline dynamic final enum if else do while for when throw try catch finally import package is in fun override companion reified inline lateinit init interface annotation data sealed internal infix operator out by constructor super tailrec where const inner suspend typealias external expect actual",built_in:"Byte Short Char Int Long Boolean Float Double Void Unit Nothing",literal:"true false null"},t={className:"symbol",begin:e.UNDERSCORE_IDENT_RE+"@"},a={className:"subst",begin:/\$\{/,end:/\}/,contains:[e.C_NUMBER_MODE]},i={className:"variable",begin:"\\$"+e.UNDERSCORE_IDENT_RE},r={className:"string",variants:[{begin:'"""',end:'"""(?=[^"])',contains:[i,a]},{begin:"'",end:"'",illegal:/\n/,contains:[e.BACKSLASH_ESCAPE]},{begin:'"',end:'"',illegal:/\n/,contains:[e.BACKSLASH_ESCAPE,i,a]}]};a.contains.push(r);const s={className:"meta",begin:"@(?:file|property|field|get|set|receiver|param|setparam|delegate)\\s*:(?:\\s*"+e.UNDERSCORE_IDENT_RE+")?"},o={className:"meta",begin:"@"+e.UNDERSCORE_IDENT_RE,contains:[{begin:/\(/,end:/\)/,contains:[e.inherit(r,{className:"string"})]}]},l=ge,c=e.COMMENT("/\\*","\\*/",{contains:[e.C_BLOCK_COMMENT_MODE]}),d={variants:[{className:"type",begin:e.UNDERSCORE_IDENT_RE},{begin:/\(/,end:/\)/,contains:[]}]},g=d;return g.variants[1].contains=[d],d.variants[1].contains=[g],{name:"Kotlin",aliases:["kt","kts"],keywords:n,contains:[e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{className:"doctag",begin:"@[A-Za-z]+"}]}),e.C_LINE_COMMENT_MODE,c,{className:"keyword",begin:/\b(break|continue|return|this)\b/,starts:{contains:[{className:"symbol",begin:/@\w+/}]}},t,s,o,{className:"function",beginKeywords:"fun",end:"[(]|$",returnBegin:!0,excludeEnd:!0,keywords:n,relevance:5,contains:[{begin:e.UNDERSCORE_IDENT_RE+"\\s*\\(",returnBegin:!0,relevance:0,contains:[e.UNDERSCORE_TITLE_MODE]},{className:"type",begin://,keywords:"reified",relevance:0},{className:"params",begin:/\(/,end:/\)/,endsParent:!0,keywords:n,relevance:0,contains:[{begin:/:/,end:/[=,\/]/,endsWithParent:!0,contains:[d,e.C_LINE_COMMENT_MODE,c],relevance:0},e.C_LINE_COMMENT_MODE,c,s,o,r,e.C_NUMBER_MODE]},c]},{className:"class",beginKeywords:"class interface trait",end:/[:\{(]|$/,excludeEnd:!0,illegal:"extends implements",contains:[{beginKeywords:"public protected internal private constructor"},e.UNDERSCORE_TITLE_MODE,{className:"type",begin://,excludeBegin:!0,excludeEnd:!0,relevance:0},{className:"type",begin:/[,:]\s*/,end:/[<\(,]|$/,excludeBegin:!0,returnEnd:!0},s,o]},r,{className:"meta",begin:"^#!/usr/bin/env",end:"$",illegal:"\n"},l]}},grmr_less:e=>{const n=te(e),t=le,a="([\\w-]+|@\\{[\\w-]+\\})",i=[],r=[],s=e=>({className:"string",begin:"~?"+e+".*?"+e}),o=(e,n,t)=>({className:e,begin:n,relevance:t}),l={$pattern:/[a-z-]+/,keyword:"and or not only",attribute:ie.join(" ")},c={begin:"\\(",end:"\\)",contains:r,keywords:l,relevance:0};r.push(e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,s("'"),s('"'),n.CSS_NUMBER_MODE,{begin:"(url|data-uri)\\(",starts:{className:"string",end:"[\\)\\n]",excludeEnd:!0}},n.HEXCOLOR,c,o("variable","@@?[\\w-]+",10),o("variable","@\\{[\\w-]+\\}"),o("built_in","~?`[^`]*?`"),{className:"attribute",begin:"[\\w-]+\\s*:",end:":",returnBegin:!0,excludeEnd:!0},n.IMPORTANT);const d=r.concat({begin:/\{/,end:/\}/,contains:i}),g={beginKeywords:"when",endsWithParent:!0,contains:[{beginKeywords:"and not"}].concat(r)},u={begin:a+"\\s*:",returnBegin:!0,end:/[;}]/,relevance:0,contains:[{begin:/-(webkit|moz|ms|o)-/},n.CSS_VARIABLE,{className:"attribute",begin:"\\b("+oe.join("|")+")\\b",end:/(?=:)/,starts:{endsWithParent:!0,illegal:"[<=$]",relevance:0,contains:r}}]},b={className:"keyword",begin:"@(import|media|charset|font-face|(-[a-z]+-)?keyframes|supports|document|namespace|page|viewport|host)\\b",starts:{end:"[;{}]",keywords:l,returnEnd:!0,contains:r,relevance:0}},m={className:"variable",variants:[{begin:"@[\\w-]+\\s*:",relevance:15},{begin:"@[\\w-]+"}],starts:{end:"[;}]",returnEnd:!0,contains:d}},p={variants:[{begin:"[\\.#:&\\[>]",end:"[;{}]"},{begin:a,end:/\{/}],returnBegin:!0,returnEnd:!0,illegal:"[<='$\"]",relevance:0,contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,g,o("keyword","all\\b"),o("variable","@\\{[\\w-]+\\}"),{begin:"\\b("+ae.join("|")+")\\b",className:"selector-tag"},n.CSS_NUMBER_MODE,o("selector-tag",a,0),o("selector-id","#"+a),o("selector-class","\\."+a,0),o("selector-tag","&",0),n.ATTRIBUTE_SELECTOR_MODE,{className:"selector-pseudo",begin:":("+re.join("|")+")"},{className:"selector-pseudo",begin:":(:)?("+se.join("|")+")"},{begin:/\(/,end:/\)/,relevance:0,contains:d},{begin:"!important"},n.FUNCTION_DISPATCH]},_={begin:`[\\w-]+:(:)?(${t.join("|")})`,returnBegin:!0,contains:[p]};return i.push(e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,b,m,_,u,p),{name:"Less",case_insensitive:!0,illegal:"[=>'/<($\"]",contains:i}},grmr_lua:e=>{const n="\\[=*\\[",t="\\]=*\\]",a={begin:n,end:t,contains:["self"]},i=[e.COMMENT("--(?!\\[=*\\[)","$"),e.COMMENT("--\\[=*\\[",t,{contains:[a],relevance:10})];return{name:"Lua",keywords:{$pattern:e.UNDERSCORE_IDENT_RE,literal:"true false nil",keyword:"and break do else elseif end for goto if in local not or repeat return then until while",built_in:"_G _ENV _VERSION __index __newindex __mode __call __metatable __tostring __len __gc __add __sub __mul __div __mod __pow __concat __unm __eq __lt __le assert collectgarbage dofile error getfenv getmetatable ipairs load loadfile loadstring module next pairs pcall print rawequal rawget rawset require select setfenv setmetatable tonumber tostring type unpack xpcall arg self coroutine resume yield status wrap create running debug getupvalue debug sethook getmetatable gethook setmetatable setlocal traceback setfenv getinfo setupvalue getlocal getregistry getfenv io lines write close flush open output type read stderr stdin input stdout popen tmpfile math log max acos huge ldexp pi cos tanh pow deg tan cosh sinh random randomseed frexp ceil floor rad abs sqrt modf asin min mod fmod log10 atan2 exp sin atan os exit setlocale date getenv difftime remove time clock tmpname rename execute package preload loadlib loaded loaders cpath config path seeall string sub upper len gfind rep find match char dump gmatch reverse byte format gsub lower table setn insert getn foreachi maxn foreach concat sort remove"},contains:i.concat([{className:"function",beginKeywords:"function",end:"\\)",contains:[e.inherit(e.TITLE_MODE,{begin:"([_a-zA-Z]\\w*\\.)*([_a-zA-Z]\\w*:)?[_a-zA-Z]\\w*"}),{className:"params",begin:"\\(",endsWithParent:!0,contains:i}].concat(i)},e.C_NUMBER_MODE,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,{className:"string",begin:n,end:t,contains:[a],relevance:5}])}},grmr_makefile:e=>{const n={className:"variable",variants:[{begin:"\\$\\("+e.UNDERSCORE_IDENT_RE+"\\)",contains:[e.BACKSLASH_ESCAPE]},{begin:/\$[@%{const n=e.regex,t=n.concat(/[A-Z_]/,n.optional(/[A-Z0-9_.-]*:/),/[A-Z0-9_.-]*/),a={className:"symbol",begin:/&[a-z]+;|&#[0-9]+;|&#x[a-f0-9]+;/},i={begin:/\s/,contains:[{className:"keyword",begin:/#?[a-z_][a-z1-9_-]+/,illegal:/\n/}]},r=e.inherit(i,{begin:/\(/,end:/\)/}),s=e.inherit(e.APOS_STRING_MODE,{className:"string"}),o=e.inherit(e.QUOTE_STRING_MODE,{className:"string"}),l={endsWithParent:!0,illegal:/`]+/}]}]}]};return{name:"HTML, XML",aliases:["html","xhtml","rss","atom","xjb","xsd","xsl","plist","wsf","svg"],case_insensitive:!0,contains:[{className:"meta",begin://,relevance:10,contains:[i,o,s,r,{begin:/\[/,end:/\]/,contains:[{className:"meta",begin://,contains:[i,r,o,s]}]}]},e.COMMENT(//,{relevance:10}),{begin://,relevance:10},a,{className:"meta",end:/\?>/,variants:[{begin:/<\?xml/,relevance:10,contains:[o]},{begin:/<\?[a-z][a-z0-9]+/}]},{className:"tag",begin:/)/,end:/>/,keywords:{name:"style"},contains:[l],starts:{end:/<\/style>/,returnEnd:!0,subLanguage:["css","xml"]}},{className:"tag",begin:/)/,end:/>/,keywords:{name:"script"},contains:[l],starts:{end:/<\/script>/,returnEnd:!0,subLanguage:["javascript","handlebars","xml"]}},{className:"tag",begin:/<>|<\/>/},{className:"tag",begin:n.concat(//,/>/,/\s/)))),end:/\/?>/,contains:[{className:"name",begin:t,relevance:0,starts:l}]},{className:"tag",begin:n.concat(/<\//,n.lookahead(n.concat(t,/>/))),contains:[{className:"name",begin:t,relevance:0},{begin:/>/,relevance:0,endsParent:!0}]}]}},grmr_markdown:e=>{const n={begin:/<\/?[A-Za-z_]/,end:">",subLanguage:"xml",relevance:0},t={variants:[{begin:/\[.+?\]\[.*?\]/,relevance:0},{begin:/\[.+?\]\(((data|javascript|mailto):|(?:http|ftp)s?:\/\/).*?\)/,relevance:2},{begin:e.regex.concat(/\[.+?\]\(/,/[A-Za-z][A-Za-z0-9+.-]*/,/:\/\/.*?\)/),relevance:2},{begin:/\[.+?\]\([./?&#].*?\)/,relevance:1},{begin:/\[.*?\]\(.*?\)/,relevance:0}],returnBegin:!0,contains:[{match:/\[(?=\])/},{className:"string",relevance:0,begin:"\\[",end:"\\]",excludeBegin:!0,returnEnd:!0},{className:"link",relevance:0,begin:"\\]\\(",end:"\\)",excludeBegin:!0,excludeEnd:!0},{className:"symbol",relevance:0,begin:"\\]\\[",end:"\\]",excludeBegin:!0,excludeEnd:!0}]},a={className:"strong",contains:[],variants:[{begin:/_{2}/,end:/_{2}/},{begin:/\*{2}/,end:/\*{2}/}]},i={className:"emphasis",contains:[],variants:[{begin:/\*(?!\*)/,end:/\*/},{begin:/_(?!_)/,end:/_/,relevance:0}]},r=e.inherit(a,{contains:[]}),s=e.inherit(i,{contains:[]});a.contains.push(s),i.contains.push(r);let o=[n,t];return[a,i,r,s].forEach(e=>{e.contains=e.contains.concat(o)}),o=o.concat(a,i),{name:"Markdown",aliases:["md","mkdown","mkd"],contains:[{className:"section",variants:[{begin:"^#{1,6}",end:"$",contains:o},{begin:"(?=^.+?\\n[=-]{2,}$)",contains:[{begin:"^[=-]*$"},{begin:"^",end:"\\n",contains:o}]}]},n,{className:"bullet",begin:"^[ \t]*([*+-]|(\\d+\\.))(?=\\s+)",end:"\\s+",excludeEnd:!0},a,i,{className:"quote",begin:"^>\\s+",contains:o,end:"$"},{className:"code",variants:[{begin:"(`{3,})[^`](.|\\n)*?\\1`*[ ]*"},{begin:"(~{3,})[^~](.|\\n)*?\\1~*[ ]*"},{begin:"```",end:"```+[ ]*$"},{begin:"~~~",end:"~~~+[ ]*$"},{begin:"`.+?`"},{begin:"(?=^( {4}|\\t))",contains:[{begin:"^( {4}|\\t)",end:"(\\n)$"}],relevance:0}]},{begin:"^[-\\*]{3,}",end:"$"},t,{begin:/^\[[^\n]+\]:/,returnBegin:!0,contains:[{className:"symbol",begin:/\[/,end:/\]/,excludeBegin:!0,excludeEnd:!0},{className:"link",begin:/:\s*/,end:/$/,excludeBegin:!0}]}]}},grmr_objectivec:e=>{const n=/[a-zA-Z@][a-zA-Z0-9_]*/,t={$pattern:n,keyword:["@interface","@class","@protocol","@implementation"]};return{name:"Objective-C",aliases:["mm","objc","obj-c","obj-c++","objective-c++"],keywords:{"variable.language":["this","super"],$pattern:n,keyword:["while","export","sizeof","typedef","const","struct","for","union","volatile","static","mutable","if","do","return","goto","enum","else","break","extern","asm","case","default","register","explicit","typename","switch","continue","inline","readonly","assign","readwrite","self","@synchronized","id","typeof","nonatomic","IBOutlet","IBAction","strong","weak","copy","in","out","inout","bycopy","byref","oneway","__strong","__weak","__block","__autoreleasing","@private","@protected","@public","@try","@property","@end","@throw","@catch","@finally","@autoreleasepool","@synthesize","@dynamic","@selector","@optional","@required","@encode","@package","@import","@defs","@compatibility_alias","__bridge","__bridge_transfer","__bridge_retained","__bridge_retain","__covariant","__contravariant","__kindof","_Nonnull","_Nullable","_Null_unspecified","__FUNCTION__","__PRETTY_FUNCTION__","__attribute__","getter","setter","retain","unsafe_unretained","nonnull","nullable","null_unspecified","null_resettable","class","instancetype","NS_DESIGNATED_INITIALIZER","NS_UNAVAILABLE","NS_REQUIRES_SUPER","NS_RETURNS_INNER_POINTER","NS_INLINE","NS_AVAILABLE","NS_DEPRECATED","NS_ENUM","NS_OPTIONS","NS_SWIFT_UNAVAILABLE","NS_ASSUME_NONNULL_BEGIN","NS_ASSUME_NONNULL_END","NS_REFINED_FOR_SWIFT","NS_SWIFT_NAME","NS_SWIFT_NOTHROW","NS_DURING","NS_HANDLER","NS_ENDHANDLER","NS_VALUERETURN","NS_VOIDRETURN"],literal:["false","true","FALSE","TRUE","nil","YES","NO","NULL"],built_in:["dispatch_once_t","dispatch_queue_t","dispatch_sync","dispatch_async","dispatch_once"],type:["int","float","char","unsigned","signed","short","long","double","wchar_t","unichar","void","bool","BOOL","id|0","_Bool"]},illegal:"/,end:/$/,illegal:"\\n"},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{className:"class",begin:"("+t.keyword.join("|")+")\\b",end:/(\{|$)/,excludeEnd:!0,keywords:t,contains:[e.UNDERSCORE_TITLE_MODE]},{begin:"\\."+e.UNDERSCORE_IDENT_RE,relevance:0}]}},grmr_perl:e=>{const n=e.regex,t=/[dualxmsipngr]{0,12}/,a={$pattern:/[\w.]+/,keyword:"abs accept alarm and atan2 bind binmode bless break caller chdir chmod chomp chop chown chr chroot close closedir connect continue cos crypt dbmclose dbmopen defined delete die do dump each else elsif endgrent endhostent endnetent endprotoent endpwent endservent eof eval exec exists exit exp fcntl fileno flock for foreach fork format formline getc getgrent getgrgid getgrnam gethostbyaddr gethostbyname gethostent getlogin getnetbyaddr getnetbyname getnetent getpeername getpgrp getpriority getprotobyname getprotobynumber getprotoent getpwent getpwnam getpwuid getservbyname getservbyport getservent getsockname getsockopt given glob gmtime goto grep gt hex if index int ioctl join keys kill last lc lcfirst length link listen local localtime log lstat lt ma map mkdir msgctl msgget msgrcv msgsnd my ne next no not oct open opendir or ord our pack package pipe pop pos print printf prototype push q|0 qq quotemeta qw qx rand read readdir readline readlink readpipe recv redo ref rename require reset return reverse rewinddir rindex rmdir say scalar seek seekdir select semctl semget semop send setgrent sethostent setnetent setpgrp setpriority setprotoent setpwent setservent setsockopt shift shmctl shmget shmread shmwrite shutdown sin sleep socket socketpair sort splice split sprintf sqrt srand stat state study sub substr symlink syscall sysopen sysread sysseek system syswrite tell telldir tie tied time times tr truncate uc ucfirst umask undef unless unlink unpack unshift untie until use utime values vec wait waitpid wantarray warn when while write x|0 xor y|0"},i={className:"subst",begin:"[$@]\\{",end:"\\}",keywords:a},r={begin:/->\{/,end:/\}/},s={variants:[{begin:/\$\d/},{begin:n.concat(/[$%@](\^\w\b|#\w+(::\w+)*|\{\w+\}|\w+(::\w*)*)/,"(?![A-Za-z])(?![@$%])")},{begin:/[$%@][^\s\w{]/,relevance:0}]},o=[e.BACKSLASH_ESCAPE,i,s],l=[/!/,/\//,/\|/,/\?/,/'/,/"/,/#/],c=(e,a,i="\\1")=>{const r="\\1"===i?i:n.concat(i,a);return n.concat(n.concat("(?:",e,")"),a,/(?:\\.|[^\\\/])*?/,r,/(?:\\.|[^\\\/])*?/,i,t)},d=(e,a,i)=>n.concat(n.concat("(?:",e,")"),a,/(?:\\.|[^\\\/])*?/,i,t),g=[s,e.HASH_COMMENT_MODE,e.COMMENT(/^=\w/,/=cut/,{endsWithParent:!0}),r,{className:"string",contains:o,variants:[{begin:"q[qwxr]?\\s*\\(",end:"\\)",relevance:5},{begin:"q[qwxr]?\\s*\\[",end:"\\]",relevance:5},{begin:"q[qwxr]?\\s*\\{",end:"\\}",relevance:5},{begin:"q[qwxr]?\\s*\\|",end:"\\|",relevance:5},{begin:"q[qwxr]?\\s*<",end:">",relevance:5},{begin:"qw\\s+q",end:"q",relevance:5},{begin:"'",end:"'",contains:[e.BACKSLASH_ESCAPE]},{begin:'"',end:'"'},{begin:"`",end:"`",contains:[e.BACKSLASH_ESCAPE]},{begin:/\{\w+\}/,relevance:0},{begin:"-?\\w+\\s*=>",relevance:0}]},{className:"number",begin:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b",relevance:0},{begin:"(\\/\\/|"+e.RE_STARTERS_RE+"|\\b(split|return|print|reverse|grep)\\b)\\s*",keywords:"split return print reverse grep",relevance:0,contains:[e.HASH_COMMENT_MODE,{className:"regexp",variants:[{begin:c("s|tr|y",n.either(...l,{capture:!0}))},{begin:c("s|tr|y","\\(","\\)")},{begin:c("s|tr|y","\\[","\\]")},{begin:c("s|tr|y","\\{","\\}")}],relevance:2},{className:"regexp",variants:[{begin:/(m|qr)\/\//,relevance:0},{begin:d("(?:m|qr)?",/\//,/\//)},{begin:d("m|qr",n.either(...l,{capture:!0}),/\1/)},{begin:d("m|qr",/\(/,/\)/)},{begin:d("m|qr",/\[/,/\]/)},{begin:d("m|qr",/\{/,/\}/)}]}]},{className:"function",beginKeywords:"sub",end:"(\\s*\\(.*?\\))?[;{]",excludeEnd:!0,relevance:5,contains:[e.TITLE_MODE]},{begin:"-\\w\\b",relevance:0},{begin:"^__DATA__$",end:"^__END__$",subLanguage:"mojolicious",contains:[{begin:"^@@.*",end:"$",className:"comment"}]}];return i.contains=g,r.contains=g,{name:"Perl",aliases:["pl","pm"],keywords:a,contains:g}},grmr_php:e=>{const n=e.regex,t=/(?![A-Za-z0-9])(?![$])/,a=n.concat(/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/,t),i=n.concat(/(\\?[A-Z][a-z0-9_\x7f-\xff]+|\\?[A-Z]+(?=[A-Z][a-z0-9_\x7f-\xff])){1,}/,t),r={scope:"variable",match:"\\$+"+a},s={scope:"subst",variants:[{begin:/\$\w+/},{begin:/\{\$/,end:/\}/}]},o=e.inherit(e.APOS_STRING_MODE,{illegal:null}),l="[ \t\n]",c={scope:"string",variants:[e.inherit(e.QUOTE_STRING_MODE,{illegal:null,contains:e.QUOTE_STRING_MODE.contains.concat(s)}),o,e.END_SAME_AS_BEGIN({begin:/<<<[ \t]*(\w+)\n/,end:/[ \t]*(\w+)\b/,contains:e.QUOTE_STRING_MODE.contains.concat(s)})]},d={scope:"number",variants:[{begin:"\\b0[bB][01]+(?:_[01]+)*\\b"},{begin:"\\b0[oO][0-7]+(?:_[0-7]+)*\\b"},{begin:"\\b0[xX][\\da-fA-F]+(?:_[\\da-fA-F]+)*\\b"},{begin:"(?:\\b\\d+(?:_\\d+)*(\\.(?:\\d+(?:_\\d+)*))?|\\B\\.\\d+)(?:[eE][+-]?\\d+)?"}],relevance:0},g=["false","null","true"],u=["__CLASS__","__DIR__","__FILE__","__FUNCTION__","__COMPILER_HALT_OFFSET__","__LINE__","__METHOD__","__NAMESPACE__","__TRAIT__","die","echo","exit","include","include_once","print","require","require_once","array","abstract","and","as","binary","bool","boolean","break","callable","case","catch","class","clone","const","continue","declare","default","do","double","else","elseif","empty","enddeclare","endfor","endforeach","endif","endswitch","endwhile","enum","eval","extends","final","finally","float","for","foreach","from","global","goto","if","implements","instanceof","insteadof","int","integer","interface","isset","iterable","list","match|0","mixed","new","never","object","or","private","protected","public","readonly","real","return","string","switch","throw","trait","try","unset","use","var","void","while","xor","yield"],b=["Error|0","AppendIterator","ArgumentCountError","ArithmeticError","ArrayIterator","ArrayObject","AssertionError","BadFunctionCallException","BadMethodCallException","CachingIterator","CallbackFilterIterator","CompileError","Countable","DirectoryIterator","DivisionByZeroError","DomainException","EmptyIterator","ErrorException","Exception","FilesystemIterator","FilterIterator","GlobIterator","InfiniteIterator","InvalidArgumentException","IteratorIterator","LengthException","LimitIterator","LogicException","MultipleIterator","NoRewindIterator","OutOfBoundsException","OutOfRangeException","OuterIterator","OverflowException","ParentIterator","ParseError","RangeException","RecursiveArrayIterator","RecursiveCachingIterator","RecursiveCallbackFilterIterator","RecursiveDirectoryIterator","RecursiveFilterIterator","RecursiveIterator","RecursiveIteratorIterator","RecursiveRegexIterator","RecursiveTreeIterator","RegexIterator","RuntimeException","SeekableIterator","SplDoublyLinkedList","SplFileInfo","SplFileObject","SplFixedArray","SplHeap","SplMaxHeap","SplMinHeap","SplObjectStorage","SplObserver","SplPriorityQueue","SplQueue","SplStack","SplSubject","SplTempFileObject","TypeError","UnderflowException","UnexpectedValueException","UnhandledMatchError","ArrayAccess","BackedEnum","Closure","Fiber","Generator","Iterator","IteratorAggregate","Serializable","Stringable","Throwable","Traversable","UnitEnum","WeakReference","WeakMap","Directory","__PHP_Incomplete_Class","parent","php_user_filter","self","static","stdClass"],m={keyword:u,literal:(e=>{const n=[];return e.forEach(e=>{n.push(e),e.toLowerCase()===e?n.push(e.toUpperCase()):n.push(e.toLowerCase())}),n})(g),built_in:b},p=e=>e.map(e=>e.replace(/\|\d+$/,"")),_={variants:[{match:[/new/,n.concat(l,"+"),n.concat("(?!",p(b).join("\\b|"),"\\b)"),i],scope:{1:"keyword",4:"title.class"}}]},h=n.concat(a,"\\b(?!\\()"),f={variants:[{match:[n.concat(/::/,n.lookahead(/(?!class\b)/)),h],scope:{2:"variable.constant"}},{match:[/::/,/class/],scope:{2:"variable.language"}},{match:[i,n.concat(/::/,n.lookahead(/(?!class\b)/)),h],scope:{1:"title.class",3:"variable.constant"}},{match:[i,n.concat("::",n.lookahead(/(?!class\b)/))],scope:{1:"title.class"}},{match:[i,/::/,/class/],scope:{1:"title.class",3:"variable.language"}}]},E={scope:"attr",match:n.concat(a,n.lookahead(":"),n.lookahead(/(?!::)/))},y={relevance:0,begin:/\(/,end:/\)/,keywords:m,contains:[E,r,f,e.C_BLOCK_COMMENT_MODE,c,d,_]},w={relevance:0,match:[/\b/,n.concat("(?!fn\\b|function\\b|",p(u).join("\\b|"),"|",p(b).join("\\b|"),"\\b)"),a,n.concat(l,"*"),n.lookahead(/(?=\()/)],scope:{3:"title.function.invoke"},contains:[y]};y.contains.push(w);const N=[E,f,e.C_BLOCK_COMMENT_MODE,c,d,_];return{case_insensitive:!1,keywords:m,contains:[{begin:n.concat(/#\[\s*/,i),beginScope:"meta",end:/]/,endScope:"meta",keywords:{literal:g,keyword:["new","array"]},contains:[{begin:/\[/,end:/]/,keywords:{literal:g,keyword:["new","array"]},contains:["self",...N]},...N,{scope:"meta",match:i}]},e.HASH_COMMENT_MODE,e.COMMENT("//","$"),e.COMMENT("/\\*","\\*/",{contains:[{scope:"doctag",match:"@[A-Za-z]+"}]}),{match:/__halt_compiler\(\);/,keywords:"__halt_compiler",starts:{scope:"comment",end:e.MATCH_NOTHING_RE,contains:[{match:/\?>/,scope:"meta",endsParent:!0}]}},{scope:"meta",variants:[{begin:/<\?php/,relevance:10},{begin:/<\?=/},{begin:/<\?/,relevance:.1},{begin:/\?>/}]},{scope:"variable.language",match:/\$this\b/},r,w,f,{match:[/const/,/\s/,a],scope:{1:"keyword",3:"variable.constant"}},_,{scope:"function",relevance:0,beginKeywords:"fn function",end:/[;{]/,excludeEnd:!0,illegal:"[$%\\[]",contains:[{beginKeywords:"use"},e.UNDERSCORE_TITLE_MODE,{begin:"=>",endsParent:!0},{scope:"params",begin:"\\(",end:"\\)",excludeBegin:!0,excludeEnd:!0,keywords:m,contains:["self",r,f,e.C_BLOCK_COMMENT_MODE,c,d]}]},{scope:"class",variants:[{beginKeywords:"enum",illegal:/[($"]/},{beginKeywords:"class interface trait",illegal:/[:($"]/}],relevance:0,end:/\{/,excludeEnd:!0,contains:[{beginKeywords:"extends implements"},e.UNDERSCORE_TITLE_MODE]},{beginKeywords:"namespace",relevance:0,end:";",illegal:/[.']/,contains:[e.inherit(e.UNDERSCORE_TITLE_MODE,{scope:"title.class"})]},{beginKeywords:"use",relevance:0,end:";",contains:[{match:/\b(as|const|function)\b/,scope:"keyword"},e.UNDERSCORE_TITLE_MODE]},c,d]}},grmr_php_template:e=>({name:"PHP template",subLanguage:"xml",contains:[{begin:/<\?(php|=)?/,end:/\?>/,subLanguage:"php",contains:[{begin:"/\\*",end:"\\*/",skip:!0},{begin:'b"',end:'"',skip:!0},{begin:"b'",end:"'",skip:!0},e.inherit(e.APOS_STRING_MODE,{illegal:null,className:null,contains:null,skip:!0}),e.inherit(e.QUOTE_STRING_MODE,{illegal:null,className:null,contains:null,skip:!0})]}]}),grmr_plaintext:e=>({name:"Plain text",aliases:["text","txt"],disableAutodetect:!0}),grmr_python:e=>{const n=e.regex,t=/[\p{XID_Start}_]\p{XID_Continue}*/u,a=["and","as","assert","async","await","break","class","continue","def","del","elif","else","except","finally","for","from","global","if","import","in","is","lambda","nonlocal|10","not","or","pass","raise","return","try","while","with","yield"],i={$pattern:/[A-Za-z]\w+|__\w+__/,keyword:a,built_in:["__import__","abs","all","any","ascii","bin","bool","breakpoint","bytearray","bytes","callable","chr","classmethod","compile","complex","delattr","dict","dir","divmod","enumerate","eval","exec","filter","float","format","frozenset","getattr","globals","hasattr","hash","help","hex","id","input","int","isinstance","issubclass","iter","len","list","locals","map","max","memoryview","min","next","object","oct","open","ord","pow","print","property","range","repr","reversed","round","set","setattr","slice","sorted","staticmethod","str","sum","super","tuple","type","vars","zip"],literal:["__debug__","Ellipsis","False","None","NotImplemented","True"],type:["Any","Callable","Coroutine","Dict","List","Literal","Generic","Optional","Sequence","Set","Tuple","Type","Union"]},r={className:"meta",begin:/^(>>>|\.\.\.) /},s={className:"subst",begin:/\{/,end:/\}/,keywords:i,illegal:/#/},o={begin:/\{\{/,relevance:0},l={className:"string",contains:[e.BACKSLASH_ESCAPE],variants:[{begin:/([uU]|[bB]|[rR]|[bB][rR]|[rR][bB])?'''/,end:/'''/,contains:[e.BACKSLASH_ESCAPE,r],relevance:10},{begin:/([uU]|[bB]|[rR]|[bB][rR]|[rR][bB])?"""/,end:/"""/,contains:[e.BACKSLASH_ESCAPE,r],relevance:10},{begin:/([fF][rR]|[rR][fF]|[fF])'''/,end:/'''/,contains:[e.BACKSLASH_ESCAPE,r,o,s]},{begin:/([fF][rR]|[rR][fF]|[fF])"""/,end:/"""/,contains:[e.BACKSLASH_ESCAPE,r,o,s]},{begin:/([uU]|[rR])'/,end:/'/,relevance:10},{begin:/([uU]|[rR])"/,end:/"/,relevance:10},{begin:/([bB]|[bB][rR]|[rR][bB])'/,end:/'/},{begin:/([bB]|[bB][rR]|[rR][bB])"/,end:/"/},{begin:/([fF][rR]|[rR][fF]|[fF])'/,end:/'/,contains:[e.BACKSLASH_ESCAPE,o,s]},{begin:/([fF][rR]|[rR][fF]|[fF])"/,end:/"/,contains:[e.BACKSLASH_ESCAPE,o,s]},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE]},c="[0-9](_?[0-9])*",d=`(\\b(${c}))?\\.(${c})|\\b(${c})\\.`,g="\\b|"+a.join("|"),u={className:"number",relevance:0,variants:[{begin:`(\\b(${c})|(${d}))[eE][+-]?(${c})[jJ]?(?=${g})`},{begin:`(${d})[jJ]?`},{begin:`\\b([1-9](_?[0-9])*|0+(_?0)*)[lLjJ]?(?=${g})`},{begin:`\\b0[bB](_?[01])+[lL]?(?=${g})`},{begin:`\\b0[oO](_?[0-7])+[lL]?(?=${g})`},{begin:`\\b0[xX](_?[0-9a-fA-F])+[lL]?(?=${g})`},{begin:`\\b(${c})[jJ](?=${g})`}]},b={className:"comment",begin:n.lookahead(/# type:/),end:/$/,keywords:i,contains:[{begin:/# type:/},{begin:/#/,end:/\b\B/,endsWithParent:!0}]},m={className:"params",variants:[{className:"",begin:/\(\s*\)/,skip:!0},{begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:i,contains:["self",r,u,l,e.HASH_COMMENT_MODE]}]};return s.contains=[l,u,r],{name:"Python",aliases:["py","gyp","ipython"],unicodeRegex:!0,keywords:i,illegal:/(<\/|->|\?)|=>/,contains:[r,u,{begin:/\bself\b/},{beginKeywords:"if",relevance:0},l,b,e.HASH_COMMENT_MODE,{match:[/\bdef/,/\s+/,t],scope:{1:"keyword",3:"title.function"},contains:[m]},{variants:[{match:[/\bclass/,/\s+/,t,/\s*/,/\(\s*/,t,/\s*\)/]},{match:[/\bclass/,/\s+/,t]}],scope:{1:"keyword",3:"title.class",6:"title.class.inherited"}},{className:"meta",begin:/^[\t ]*@/,end:/(?=#)|$/,contains:[u,m,l]}]}},grmr_python_repl:e=>({aliases:["pycon"],contains:[{className:"meta.prompt",starts:{end:/ |$/,starts:{end:"$",subLanguage:"python"}},variants:[{begin:/^>>>(?=[ ]|$)/},{begin:/^\.\.\.(?=[ ]|$)/}]}]}),grmr_r:e=>{const n=e.regex,t=/(?:(?:[a-zA-Z]|\.[._a-zA-Z])[._a-zA-Z0-9]*)|\.(?!\d)/,a=n.either(/0[xX][0-9a-fA-F]+\.[0-9a-fA-F]*[pP][+-]?\d+i?/,/0[xX][0-9a-fA-F]+(?:[pP][+-]?\d+)?[Li]?/,/(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?[Li]?/),i=/[=!<>:]=|\|\||&&|:::?|<-|<<-|->>|->|\|>|[-+*\/?!$&|:<=>@^~]|\*\*/,r=n.either(/[()]/,/[{}]/,/\[\[/,/[[\]]/,/\\/,/,/);return{name:"R",keywords:{$pattern:t,keyword:"function if in break next repeat else for while",literal:"NULL NA TRUE FALSE Inf NaN NA_integer_|10 NA_real_|10 NA_character_|10 NA_complex_|10",built_in:"LETTERS letters month.abb month.name pi T F abs acos acosh all any anyNA Arg as.call as.character as.complex as.double as.environment as.integer as.logical as.null.default as.numeric as.raw asin asinh atan atanh attr attributes baseenv browser c call ceiling class Conj cos cosh cospi cummax cummin cumprod cumsum digamma dim dimnames emptyenv exp expression floor forceAndCall gamma gc.time globalenv Im interactive invisible is.array is.atomic is.call is.character is.complex is.double is.environment is.expression is.finite is.function is.infinite is.integer is.language is.list is.logical is.matrix is.na is.name is.nan is.null is.numeric is.object is.pairlist is.raw is.recursive is.single is.symbol lazyLoadDBfetch length lgamma list log max min missing Mod names nargs nzchar oldClass on.exit pos.to.env proc.time prod quote range Re rep retracemem return round seq_along seq_len seq.int sign signif sin sinh sinpi sqrt standardGeneric substitute sum switch tan tanh tanpi tracemem trigamma trunc unclass untracemem UseMethod xtfrm"},contains:[e.COMMENT(/#'/,/$/,{contains:[{scope:"doctag",match:/@examples/,starts:{end:n.lookahead(n.either(/\n^#'\s*(?=@[a-zA-Z]+)/,/\n^(?!#')/)),endsParent:!0}},{scope:"doctag",begin:"@param",end:/$/,contains:[{scope:"variable",variants:[{match:t},{match:/`(?:\\.|[^`\\])+`/}],endsParent:!0}]},{scope:"doctag",match:/@[a-zA-Z]+/},{scope:"keyword",match:/\\[a-zA-Z]+/}]}),e.HASH_COMMENT_MODE,{scope:"string",contains:[e.BACKSLASH_ESCAPE],variants:[e.END_SAME_AS_BEGIN({begin:/[rR]"(-*)\(/,end:/\)(-*)"/}),e.END_SAME_AS_BEGIN({begin:/[rR]"(-*)\{/,end:/\}(-*)"/}),e.END_SAME_AS_BEGIN({begin:/[rR]"(-*)\[/,end:/\](-*)"/}),e.END_SAME_AS_BEGIN({begin:/[rR]'(-*)\(/,end:/\)(-*)'/}),e.END_SAME_AS_BEGIN({begin:/[rR]'(-*)\{/,end:/\}(-*)'/}),e.END_SAME_AS_BEGIN({begin:/[rR]'(-*)\[/,end:/\](-*)'/}),{begin:'"',end:'"',relevance:0},{begin:"'",end:"'",relevance:0}]},{relevance:0,variants:[{scope:{1:"operator",2:"number"},match:[i,a]},{scope:{1:"operator",2:"number"},match:[/%[^%]*%/,a]},{scope:{1:"punctuation",2:"number"},match:[r,a]},{scope:{2:"number"},match:[/[^a-zA-Z0-9._]|^/,a]}]},{scope:{3:"operator"},match:[t,/\s+/,/<-/,/\s+/]},{scope:"operator",relevance:0,variants:[{match:i},{match:/%[^%]*%/}]},{scope:"punctuation",relevance:0,match:r},{begin:"`",end:"`",contains:[{begin:/\\./}]}]}},grmr_ruby:e=>{const n=e.regex,t="([a-zA-Z_]\\w*[!?=]?|[-+~]@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?)",a=n.either(/\b([A-Z]+[a-z0-9]+)+/,/\b([A-Z]+[a-z0-9]+)+[A-Z]+/),i=n.concat(a,/(::\w+)*/),r={"variable.constant":["__FILE__","__LINE__"],"variable.language":["self","super"],keyword:["alias","and","attr_accessor","attr_reader","attr_writer","begin","BEGIN","break","case","class","defined","do","else","elsif","end","END","ensure","for","if","in","include","module","next","not","or","redo","require","rescue","retry","return","then","undef","unless","until","when","while","yield"],built_in:["proc","lambda"],literal:["true","false","nil"]},s={className:"doctag",begin:"@[A-Za-z]+"},o={begin:"#<",end:">"},l=[e.COMMENT("#","$",{contains:[s]}),e.COMMENT("^=begin","^=end",{contains:[s],relevance:10}),e.COMMENT("^__END__",e.MATCH_NOTHING_RE)],c={className:"subst",begin:/#\{/,end:/\}/,keywords:r},d={className:"string",contains:[e.BACKSLASH_ESCAPE,c],variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/`/,end:/`/},{begin:/%[qQwWx]?\(/,end:/\)/},{begin:/%[qQwWx]?\[/,end:/\]/},{begin:/%[qQwWx]?\{/,end:/\}/},{begin:/%[qQwWx]?/},{begin:/%[qQwWx]?\//,end:/\//},{begin:/%[qQwWx]?%/,end:/%/},{begin:/%[qQwWx]?-/,end:/-/},{begin:/%[qQwWx]?\|/,end:/\|/},{begin:/\B\?(\\\d{1,3})/},{begin:/\B\?(\\x[A-Fa-f0-9]{1,2})/},{begin:/\B\?(\\u\{?[A-Fa-f0-9]{1,6}\}?)/},{begin:/\B\?(\\M-\\C-|\\M-\\c|\\c\\M-|\\M-|\\C-\\M-)[\x20-\x7e]/},{begin:/\B\?\\(c|C-)[\x20-\x7e]/},{begin:/\B\?\\?\S/},{begin:n.concat(/<<[-~]?'?/,n.lookahead(/(\w+)(?=\W)[^\n]*\n(?:[^\n]*\n)*?\s*\1\b/)),contains:[e.END_SAME_AS_BEGIN({begin:/(\w+)/,end:/(\w+)/,contains:[e.BACKSLASH_ESCAPE,c]})]}]},g="[0-9](_?[0-9])*",u={className:"number",relevance:0,variants:[{begin:`\\b([1-9](_?[0-9])*|0)(\\.(${g}))?([eE][+-]?(${g})|r)?i?\\b`},{begin:"\\b0[dD][0-9](_?[0-9])*r?i?\\b"},{begin:"\\b0[bB][0-1](_?[0-1])*r?i?\\b"},{begin:"\\b0[oO][0-7](_?[0-7])*r?i?\\b"},{begin:"\\b0[xX][0-9a-fA-F](_?[0-9a-fA-F])*r?i?\\b"},{begin:"\\b0(_?[0-7])+r?i?\\b"}]},b={variants:[{match:/\(\)/},{className:"params",begin:/\(/,end:/(?=\))/,excludeBegin:!0,endsParent:!0,keywords:r}]},m=[d,{variants:[{match:[/class\s+/,i,/\s+<\s+/,i]},{match:[/class\s+/,i]}],scope:{2:"title.class",4:"title.class.inherited"},keywords:r},{relevance:0,match:[i,/\.new[ (]/],scope:{1:"title.class"}},{relevance:0,match:/\b[A-Z][A-Z_0-9]+\b/,className:"variable.constant"},{match:[/def/,/\s+/,t],scope:{1:"keyword",3:"title.function"},contains:[b]},{begin:e.IDENT_RE+"::"},{className:"symbol",begin:e.UNDERSCORE_IDENT_RE+"(!|\\?)?:",relevance:0},{className:"symbol",begin:":(?!\\s)",contains:[d,{begin:t}],relevance:0},u,{className:"variable",begin:"(\\$\\W)|((\\$|@@?)(\\w+))(?=[^@$?])(?![A-Za-z])(?![@$?'])"},{className:"params",begin:/\|/,end:/\|/,excludeBegin:!0,excludeEnd:!0,relevance:0,keywords:r},{begin:"("+e.RE_STARTERS_RE+"|unless)\\s*",keywords:"unless",contains:[{className:"regexp",contains:[e.BACKSLASH_ESCAPE,c],illegal:/\n/,variants:[{begin:"/",end:"/[a-z]*"},{begin:/%r\{/,end:/\}[a-z]*/},{begin:"%r\\(",end:"\\)[a-z]*"},{begin:"%r!",end:"![a-z]*"},{begin:"%r\\[",end:"\\][a-z]*"}]}].concat(o,l),relevance:0}].concat(o,l);c.contains=m,b.contains=m;const p=[{begin:/^\s*=>/,starts:{end:"$",contains:m}},{className:"meta.prompt",begin:"^([>?]>|[\\w#]+\\(\\w+\\):\\d+:\\d+[>*]|(\\w+-)?\\d+\\.\\d+\\.\\d+(p\\d+)?[^\\d][^>]+>)(?=[ ])",starts:{end:"$",keywords:r,contains:m}}];return l.unshift(o),{name:"Ruby",aliases:["rb","gemspec","podspec","thor","irb"],keywords:r,illegal:/\/\*/,contains:[e.SHEBANG({binary:"ruby"})].concat(p).concat(l).concat(m)}},grmr_rust:e=>{const n=e.regex,t={className:"title.function.invoke",relevance:0,begin:n.concat(/\b/,/(?!let\b)/,e.IDENT_RE,n.lookahead(/\s*\(/))},a="([ui](8|16|32|64|128|size)|f(32|64))?",i=["drop ","Copy","Send","Sized","Sync","Drop","Fn","FnMut","FnOnce","ToOwned","Clone","Debug","PartialEq","PartialOrd","Eq","Ord","AsRef","AsMut","Into","From","Default","Iterator","Extend","IntoIterator","DoubleEndedIterator","ExactSizeIterator","SliceConcatExt","ToString","assert!","assert_eq!","bitflags!","bytes!","cfg!","col!","concat!","concat_idents!","debug_assert!","debug_assert_eq!","env!","panic!","file!","format!","format_args!","include_bin!","include_str!","line!","local_data_key!","module_path!","option_env!","print!","println!","select!","stringify!","try!","unimplemented!","unreachable!","vec!","write!","writeln!","macro_rules!","assert_ne!","debug_assert_ne!"];return{name:"Rust",aliases:["rs"],keywords:{$pattern:e.IDENT_RE+"!?",type:["i8","i16","i32","i64","i128","isize","u8","u16","u32","u64","u128","usize","f32","f64","str","char","bool","Box","Option","Result","String","Vec"],keyword:["abstract","as","async","await","become","box","break","const","continue","crate","do","dyn","else","enum","extern","false","final","fn","for","if","impl","in","let","loop","macro","match","mod","move","mut","override","priv","pub","ref","return","self","Self","static","struct","super","trait","true","try","type","typeof","unsafe","unsized","use","virtual","where","while","yield"],literal:["true","false","Some","None","Ok","Err"],built_in:i},illegal:""},t]}},grmr_scss:e=>{const n=te(e),t=se,a=re,i="@[a-z-]+",r={className:"variable",begin:"(\\$[a-zA-Z-][a-zA-Z0-9_-]*)\\b",relevance:0};return{name:"SCSS",case_insensitive:!0,illegal:"[=/|']",contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,n.CSS_NUMBER_MODE,{className:"selector-id",begin:"#[A-Za-z0-9_-]+",relevance:0},{className:"selector-class",begin:"\\.[A-Za-z0-9_-]+",relevance:0},n.ATTRIBUTE_SELECTOR_MODE,{className:"selector-tag",begin:"\\b("+ae.join("|")+")\\b",relevance:0},{className:"selector-pseudo",begin:":("+a.join("|")+")"},{className:"selector-pseudo",begin:":(:)?("+t.join("|")+")"},r,{begin:/\(/,end:/\)/,contains:[n.CSS_NUMBER_MODE]},n.CSS_VARIABLE,{className:"attribute",begin:"\\b("+oe.join("|")+")\\b"},{begin:"\\b(whitespace|wait|w-resize|visible|vertical-text|vertical-ideographic|uppercase|upper-roman|upper-alpha|underline|transparent|top|thin|thick|text|text-top|text-bottom|tb-rl|table-header-group|table-footer-group|sw-resize|super|strict|static|square|solid|small-caps|separate|se-resize|scroll|s-resize|rtl|row-resize|ridge|right|repeat|repeat-y|repeat-x|relative|progress|pointer|overline|outside|outset|oblique|nowrap|not-allowed|normal|none|nw-resize|no-repeat|no-drop|newspaper|ne-resize|n-resize|move|middle|medium|ltr|lr-tb|lowercase|lower-roman|lower-alpha|loose|list-item|line|line-through|line-edge|lighter|left|keep-all|justify|italic|inter-word|inter-ideograph|inside|inset|inline|inline-block|inherit|inactive|ideograph-space|ideograph-parenthesis|ideograph-numeric|ideograph-alpha|horizontal|hidden|help|hand|groove|fixed|ellipsis|e-resize|double|dotted|distribute|distribute-space|distribute-letter|distribute-all-lines|disc|disabled|default|decimal|dashed|crosshair|collapse|col-resize|circle|char|center|capitalize|break-word|break-all|bottom|both|bolder|bold|block|bidi-override|below|baseline|auto|always|all-scroll|absolute|table|table-cell)\\b"},{begin:/:/,end:/[;}{]/,contains:[n.BLOCK_COMMENT,r,n.HEXCOLOR,n.CSS_NUMBER_MODE,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,n.IMPORTANT]},{begin:"@(page|font-face)",keywords:{$pattern:i,keyword:"@page @font-face"}},{begin:"@",end:"[{;]",returnBegin:!0,keywords:{$pattern:/[a-z-]+/,keyword:"and or not only",attribute:ie.join(" ")},contains:[{begin:i,className:"keyword"},{begin:/[a-z-]+(?=:)/,className:"attribute"},r,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,n.HEXCOLOR,n.CSS_NUMBER_MODE]},n.FUNCTION_DISPATCH]}},grmr_shell:e=>({name:"Shell Session",aliases:["console","shellsession"],contains:[{className:"meta.prompt",begin:/^\s{0,3}[/~\w\d[\]()@-]*[>%$#][ ]?/,starts:{end:/[^\\](?=\s*$)/,subLanguage:"bash"}}]}),grmr_sql:e=>{const n=e.regex,t=e.COMMENT("--","$"),a=["true","false","unknown"],i=["bigint","binary","blob","boolean","char","character","clob","date","dec","decfloat","decimal","float","int","integer","interval","nchar","nclob","national","numeric","real","row","smallint","time","timestamp","varchar","varying","varbinary"],r=["abs","acos","array_agg","asin","atan","avg","cast","ceil","ceiling","coalesce","corr","cos","cosh","count","covar_pop","covar_samp","cume_dist","dense_rank","deref","element","exp","extract","first_value","floor","json_array","json_arrayagg","json_exists","json_object","json_objectagg","json_query","json_table","json_table_primitive","json_value","lag","last_value","lead","listagg","ln","log","log10","lower","max","min","mod","nth_value","ntile","nullif","percent_rank","percentile_cont","percentile_disc","position","position_regex","power","rank","regr_avgx","regr_avgy","regr_count","regr_intercept","regr_r2","regr_slope","regr_sxx","regr_sxy","regr_syy","row_number","sin","sinh","sqrt","stddev_pop","stddev_samp","substring","substring_regex","sum","tan","tanh","translate","translate_regex","treat","trim","trim_array","unnest","upper","value_of","var_pop","var_samp","width_bucket"],s=["create table","insert into","primary key","foreign key","not null","alter table","add constraint","grouping sets","on overflow","character set","respect nulls","ignore nulls","nulls first","nulls last","depth first","breadth first"],o=r,l=["abs","acos","all","allocate","alter","and","any","are","array","array_agg","array_max_cardinality","as","asensitive","asin","asymmetric","at","atan","atomic","authorization","avg","begin","begin_frame","begin_partition","between","bigint","binary","blob","boolean","both","by","call","called","cardinality","cascaded","case","cast","ceil","ceiling","char","char_length","character","character_length","check","classifier","clob","close","coalesce","collate","collect","column","commit","condition","connect","constraint","contains","convert","copy","corr","corresponding","cos","cosh","count","covar_pop","covar_samp","create","cross","cube","cume_dist","current","current_catalog","current_date","current_default_transform_group","current_path","current_role","current_row","current_schema","current_time","current_timestamp","current_path","current_role","current_transform_group_for_type","current_user","cursor","cycle","date","day","deallocate","dec","decimal","decfloat","declare","default","define","delete","dense_rank","deref","describe","deterministic","disconnect","distinct","double","drop","dynamic","each","element","else","empty","end","end_frame","end_partition","end-exec","equals","escape","every","except","exec","execute","exists","exp","external","extract","false","fetch","filter","first_value","float","floor","for","foreign","frame_row","free","from","full","function","fusion","get","global","grant","group","grouping","groups","having","hold","hour","identity","in","indicator","initial","inner","inout","insensitive","insert","int","integer","intersect","intersection","interval","into","is","join","json_array","json_arrayagg","json_exists","json_object","json_objectagg","json_query","json_table","json_table_primitive","json_value","lag","language","large","last_value","lateral","lead","leading","left","like","like_regex","listagg","ln","local","localtime","localtimestamp","log","log10","lower","match","match_number","match_recognize","matches","max","member","merge","method","min","minute","mod","modifies","module","month","multiset","national","natural","nchar","nclob","new","no","none","normalize","not","nth_value","ntile","null","nullif","numeric","octet_length","occurrences_regex","of","offset","old","omit","on","one","only","open","or","order","out","outer","over","overlaps","overlay","parameter","partition","pattern","per","percent","percent_rank","percentile_cont","percentile_disc","period","portion","position","position_regex","power","precedes","precision","prepare","primary","procedure","ptf","range","rank","reads","real","recursive","ref","references","referencing","regr_avgx","regr_avgy","regr_count","regr_intercept","regr_r2","regr_slope","regr_sxx","regr_sxy","regr_syy","release","result","return","returns","revoke","right","rollback","rollup","row","row_number","rows","running","savepoint","scope","scroll","search","second","seek","select","sensitive","session_user","set","show","similar","sin","sinh","skip","smallint","some","specific","specifictype","sql","sqlexception","sqlstate","sqlwarning","sqrt","start","static","stddev_pop","stddev_samp","submultiset","subset","substring","substring_regex","succeeds","sum","symmetric","system","system_time","system_user","table","tablesample","tan","tanh","then","time","timestamp","timezone_hour","timezone_minute","to","trailing","translate","translate_regex","translation","treat","trigger","trim","trim_array","true","truncate","uescape","union","unique","unknown","unnest","update","upper","user","using","value","values","value_of","var_pop","var_samp","varbinary","varchar","varying","versioning","when","whenever","where","width_bucket","window","with","within","without","year","add","asc","collation","desc","final","first","last","view"].filter(e=>!r.includes(e)),c={begin:n.concat(/\b/,n.either(...o),/\s*\(/),relevance:0,keywords:{built_in:o}};return{name:"SQL",case_insensitive:!0,illegal:/[{}]|<\//,keywords:{$pattern:/\b[\w\.]+/,keyword:((e,{exceptions:n,when:t}={})=>{const a=t;return n=n||[],e.map(e=>e.match(/\|\d+$/)||n.includes(e)?e:a(e)?e+"|0":e)})(l,{when:e=>e.length<3}),literal:a,type:i,built_in:["current_catalog","current_date","current_default_transform_group","current_path","current_role","current_schema","current_transform_group_for_type","current_user","session_user","system_time","system_user","current_time","localtime","current_timestamp","localtimestamp"]},contains:[{begin:n.either(...s),relevance:0,keywords:{$pattern:/[\w\.]+/,keyword:l.concat(s),literal:a,type:i}},{className:"type",begin:n.either("double precision","large object","with timezone","without timezone")},c,{className:"variable",begin:/@[a-z0-9]+/},{className:"string",variants:[{begin:/'/,end:/'/,contains:[{begin:/''/}]}]},{begin:/"/,end:/"/,contains:[{begin:/""/}]},e.C_NUMBER_MODE,e.C_BLOCK_COMMENT_MODE,t,{className:"operator",begin:/[-+*/=%^~]|&&?|\|\|?|!=?|<(?:=>?|<|>)?|>[>=]?/,relevance:0}]}},grmr_swift:e=>{const n={match:/\s+/,relevance:0},t=e.COMMENT("/\\*","\\*/",{contains:["self"]}),a=[e.C_LINE_COMMENT_MODE,t],i={match:[/\./,p(...ve,...ke)],className:{2:"keyword"}},r={match:m(/\./,p(...xe)),relevance:0},s=xe.filter(e=>"string"==typeof e).concat(["_|0"]),o={variants:[{className:"keyword",match:p(...xe.filter(e=>"string"!=typeof e).concat(Oe).map(Ne),...ke)}]},l={$pattern:p(/\b\w+/,/#\w+/),keyword:s.concat(Ae),literal:Me},c=[i,r,o],d=[{match:m(/\./,p(...Ce)),relevance:0},{className:"built_in",match:m(/\b/,p(...Ce),/(?=\()/)}],u={match:/->/,relevance:0},b=[u,{className:"operator",relevance:0,variants:[{match:De},{match:`\\.(\\.|${Re})+`}]}],_="([0-9a-fA-F]_*)+",h={className:"number",relevance:0,variants:[{match:"\\b(([0-9]_*)+)(\\.(([0-9]_*)+))?([eE][+-]?(([0-9]_*)+))?\\b"},{match:`\\b0x(${_})(\\.(${_}))?([pP][+-]?(([0-9]_*)+))?\\b`},{match:/\b0o([0-7]_*)+\b/},{match:/\b0b([01]_*)+\b/}]},f=(e="")=>({className:"subst",variants:[{match:m(/\\/,e,/[0\\tnr"']/)},{match:m(/\\/,e,/u\{[0-9a-fA-F]{1,8}\}/)}]}),E=(e="")=>({className:"subst",match:m(/\\/,e,/[\t ]*(?:[\r\n]|\r\n)/)}),y=(e="")=>({className:"subst",label:"interpol",begin:m(/\\/,e,/\(/),end:/\)/}),w=(e="")=>({begin:m(e,/"""/),end:m(/"""/,e),contains:[f(e),E(e),y(e)]}),N=(e="")=>({begin:m(e,/"/),end:m(/"/,e),contains:[f(e),y(e)]}),v={className:"string",variants:[w(),w("#"),w("##"),w("###"),N(),N("#"),N("##"),N("###")]},k={match:m(/`/,Be,/`/)},O=[k,{className:"variable",match:/\$\d+/},{className:"variable",match:`\\$${Le}+`}],x=[{match:/(@|#(un)?)available/,className:"keyword",starts:{contains:[{begin:/\(/,end:/\)/,keywords:Fe,contains:[...b,h,v]}]}},{className:"keyword",match:m(/@/,p(...ze))},{className:"meta",match:m(/@/,Be)}],M={match:g(/\b[A-Z]/),relevance:0,contains:[{className:"type",match:m(/(AV|CA|CF|CG|CI|CL|CM|CN|CT|MK|MP|MTK|MTL|NS|SCN|SK|UI|WK|XC)/,Le,"+")},{className:"type",match:$e,relevance:0},{match:/[?!]+/,relevance:0},{match:/\.\.\./,relevance:0},{match:m(/\s+&\s+/,g($e)),relevance:0}]},S={begin://,keywords:l,contains:[...a,...c,...x,u,M]};M.contains.push(S);const A={begin:/\(/,end:/\)/,relevance:0,keywords:l,contains:["self",{match:m(Be,/\s*:/),keywords:"_|0",relevance:0},...a,...c,...d,...b,h,v,...O,...x,M]},C={begin://,contains:[...a,M]},T={begin:/\(/,end:/\)/,keywords:l,contains:[{begin:p(g(m(Be,/\s*:/)),g(m(Be,/\s+/,Be,/\s*:/))),end:/:/,relevance:0,contains:[{className:"keyword",match:/\b_\b/},{className:"params",match:Be}]},...a,...c,...b,h,v,...x,M,A],endsParent:!0,illegal:/["']/},R={match:[/func/,/\s+/,p(k.match,Be,De)],className:{1:"keyword",3:"title.function"},contains:[C,T,n],illegal:[/\[/,/%/]},D={match:[/\b(?:subscript|init[?!]?)/,/\s*(?=[<(])/],className:{1:"keyword"},contains:[C,T,n],illegal:/\[|%/},I={match:[/operator/,/\s+/,De],className:{1:"keyword",3:"title"}},L={begin:[/precedencegroup/,/\s+/,$e],className:{1:"keyword",3:"title"},contains:[M],keywords:[...Se,...Me],end:/}/};for(const e of v.variants){const n=e.contains.find(e=>"interpol"===e.label);n.keywords=l;const t=[...c,...d,...b,h,v,...O];n.contains=[...t,{begin:/\(/,end:/\)/,contains:["self",...t]}]}return{name:"Swift",keywords:l,contains:[...a,R,D,{beginKeywords:"struct protocol class extension enum actor",end:"\\{",excludeEnd:!0,keywords:l,contains:[e.inherit(e.TITLE_MODE,{className:"title.class",begin:/[A-Za-z$_][\u00C0-\u02B80-9A-Za-z$_]*/}),...c]},I,L,{beginKeywords:"import",end:/$/,contains:[...a],relevance:0},...c,...d,...b,h,v,...O,...x,M,A]}},grmr_typescript:e=>{const n=we(e),t=["any","void","number","boolean","string","object","never","symbol","bigint","unknown"],a={beginKeywords:"namespace",end:/\{/,excludeEnd:!0,contains:[n.exports.CLASS_REFERENCE]},i={beginKeywords:"interface",end:/\{/,excludeEnd:!0,keywords:{keyword:"interface extends",built_in:t},contains:[n.exports.CLASS_REFERENCE]},r={$pattern:be,keyword:me.concat(["type","namespace","interface","public","private","protected","implements","declare","abstract","readonly","enum","override"]),literal:pe,built_in:ye.concat(t),"variable.language":Ee},s={className:"meta",begin:"@[A-Za-z$_][0-9A-Za-z$_]*"},o=(e,n,t)=>{const a=e.contains.findIndex(e=>e.label===n);if(-1===a)throw Error("can not find mode to replace");e.contains.splice(a,1,t)};return Object.assign(n.keywords,r),n.exports.PARAMS_CONTAINS.push(s),n.contains=n.contains.concat([s,a,i]),o(n,"shebang",e.SHEBANG()),o(n,"use_strict",{className:"meta",relevance:10,begin:/^\s*['"]use strict['"]/}),n.contains.find(e=>"func.def"===e.label).relevance=0,Object.assign(n,{name:"TypeScript",aliases:["ts","tsx"]}),n},grmr_vbnet:e=>{const n=e.regex,t=/\d{1,2}\/\d{1,2}\/\d{4}/,a=/\d{4}-\d{1,2}-\d{1,2}/,i=/(\d|1[012])(:\d+){0,2} *(AM|PM)/,r=/\d{1,2}(:\d{1,2}){1,2}/,s={className:"literal",variants:[{begin:n.concat(/# */,n.either(a,t),/ *#/)},{begin:n.concat(/# */,r,/ *#/)},{begin:n.concat(/# */,i,/ *#/)},{begin:n.concat(/# */,n.either(a,t),/ +/,n.either(i,r),/ *#/)}]},o=e.COMMENT(/'''/,/$/,{contains:[{className:"doctag",begin:/<\/?/,end:/>/}]}),l=e.COMMENT(null,/$/,{variants:[{begin:/'/},{begin:/([\t ]|^)REM(?=\s)/}]});return{name:"Visual Basic .NET",aliases:["vb"],case_insensitive:!0,classNameAliases:{label:"symbol"},keywords:{keyword:"addhandler alias aggregate ansi as async assembly auto binary by byref byval call case catch class compare const continue custom declare default delegate dim distinct do each equals else elseif end enum erase error event exit explicit finally for friend from function get global goto group handles if implements imports in inherits interface into iterator join key let lib loop me mid module mustinherit mustoverride mybase myclass namespace narrowing new next notinheritable notoverridable of off on operator option optional order overloads overridable overrides paramarray partial preserve private property protected public raiseevent readonly redim removehandler resume return select set shadows shared skip static step stop structure strict sub synclock take text then throw to try unicode until using when where while widening with withevents writeonly yield",built_in:"addressof and andalso await directcast gettype getxmlnamespace is isfalse isnot istrue like mod nameof new not or orelse trycast typeof xor cbool cbyte cchar cdate cdbl cdec cint clng cobj csbyte cshort csng cstr cuint culng cushort",type:"boolean byte char date decimal double integer long object sbyte short single string uinteger ulong ushort",literal:"true false nothing"},illegal:"//|\\{|\\}|endif|gosub|variant|wend|^\\$ ",contains:[{className:"string",begin:/"(""|[^/n])"C\b/},{className:"string",begin:/"/,end:/"/,illegal:/\n/,contains:[{begin:/""/}]},s,{className:"number",relevance:0,variants:[{begin:/\b\d[\d_]*((\.[\d_]+(E[+-]?[\d_]+)?)|(E[+-]?[\d_]+))[RFD@!#]?/},{begin:/\b\d[\d_]*((U?[SIL])|[%&])?/},{begin:/&H[\dA-F_]+((U?[SIL])|[%&])?/},{begin:/&O[0-7_]+((U?[SIL])|[%&])?/},{begin:/&B[01_]+((U?[SIL])|[%&])?/}]},{className:"label",begin:/^\w+:/},o,l,{className:"meta",begin:/[\t ]*#(const|disable|else|elseif|enable|end|externalsource|if|region)\b/,end:/$/,keywords:{keyword:"const disable else elseif enable end externalsource if region then"},contains:[l]}]}},grmr_yaml:e=>{const n="true false yes no null",t="[\\w#;/?:@&=+$,.~*'()[\\]]+",a={className:"string",relevance:0,variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/\S+/}],contains:[e.BACKSLASH_ESCAPE,{className:"template-variable",variants:[{begin:/\{\{/,end:/\}\}/},{begin:/%\{/,end:/\}/}]}]},i=e.inherit(a,{variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/[^\s,{}[\]]+/}]}),r={end:",",endsWithParent:!0,excludeEnd:!0,keywords:n,relevance:0},s={begin:/\{/,end:/\}/,contains:[r],illegal:"\\n",relevance:0},o={begin:"\\[",end:"\\]",contains:[r],illegal:"\\n",relevance:0},l=[{className:"attr",variants:[{begin:"\\w[\\w :\\/.-]*:(?=[ \t]|$)"},{begin:'"\\w[\\w :\\/.-]*":(?=[ \t]|$)'},{begin:"'\\w[\\w :\\/.-]*':(?=[ \t]|$)"}]},{className:"meta",begin:"^---\\s*$",relevance:10},{className:"string",begin:"[\\|>]([1-9]?[+-])?[ ]*\\n( +)[^ ][^\\n]*\\n(\\2[^\\n]+\\n?)*"},{begin:"<%[%=-]?",end:"[%-]?%>",subLanguage:"ruby",excludeBegin:!0,excludeEnd:!0,relevance:0},{className:"type",begin:"!\\w+!"+t},{className:"type",begin:"!<"+t+">"},{className:"type",begin:"!"+t},{className:"type",begin:"!!"+t},{className:"meta",begin:"&"+e.UNDERSCORE_IDENT_RE+"$"},{className:"meta",begin:"\\*"+e.UNDERSCORE_IDENT_RE+"$"},{className:"bullet",begin:"-(?=[ ]|$)",relevance:0},e.HASH_COMMENT_MODE,{beginKeywords:n,keywords:{literal:n}},{className:"number",begin:"\\b[0-9]{4}(-[0-9][0-9]){0,2}([Tt \\t][0-9][0-9]?(:[0-9][0-9]){2})?(\\.[0-9]*)?([ \\t])*(Z|[-+][0-9][0-9]?(:[0-9][0-9])?)?\\b"},{className:"number",begin:e.C_NUMBER_RE+"\\b",relevance:0},s,o,a],c=[...l];return c.pop(),c.push(i),r.contains=c,{name:"YAML",case_insensitive:!0,aliases:["yml"],contains:l}}});const je=ne;for(const e of Object.keys(Ue)){const n=e.replace("grmr_","").replace("_","-");je.registerLanguage(n,Ue[e])}return je}();"object"==typeof exports&&"undefined"!=typeof module&&(module.exports=hljs); +var hljs=function(){"use strict";var e={exports:{}};function n(e){return e instanceof Map?e.clear=e.delete=e.set=()=>{throw Error("map is read-only")}:e instanceof Set&&(e.add=e.clear=e.delete=()=>{throw Error("set is read-only")}),Object.freeze(e),Object.getOwnPropertyNames(e).forEach(t=>{var a=e[t];"object"!=typeof a||Object.isFrozen(a)||n(a)}),e}e.exports=n,e.exports.default=n;var t=e.exports;class a{constructor(e){void 0===e.data&&(e.data={}),this.data=e.data,this.isMatchIgnored=!1}ignoreMatch(){this.isMatchIgnored=!0}}function i(e){return e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")}function r(e,...n){const t=Object.create(null);for(const n in e)t[n]=e[n];return n.forEach(e=>{for(const n in e)t[n]=e[n]}),t}const s=e=>!!e.kind;class o{constructor(e,n){this.buffer="",this.classPrefix=n.classPrefix,e.walk(this)}addText(e){this.buffer+=i(e)}openNode(e){if(!s(e))return;let n=e.kind;n=e.sublanguage?"language-"+n:((e,{prefix:n})=>{if(e.includes(".")){const t=e.split(".");return[`${n}${t.shift()}`,...t.map((e,n)=>`${e}${"_".repeat(n+1)}`)].join(" ")}return`${n}${e}`})(n,{prefix:this.classPrefix}),this.span(n)}closeNode(e){s(e)&&(this.buffer+="")}value(){return this.buffer}span(e){this.buffer+=``}}class l{constructor(){this.rootNode={children:[]},this.stack=[this.rootNode]}get top(){return this.stack[this.stack.length-1]}get root(){return this.rootNode}add(e){this.top.children.push(e)}openNode(e){const n={kind:e,children:[]};this.add(n),this.stack.push(n)}closeNode(){if(this.stack.length>1)return this.stack.pop()}closeAllNodes(){for(;this.closeNode(););}toJSON(){return JSON.stringify(this.rootNode,null,4)}walk(e){return this.constructor._walk(e,this.rootNode)}static _walk(e,n){return"string"==typeof n?e.addText(n):n.children&&(e.openNode(n),n.children.forEach(n=>this._walk(e,n)),e.closeNode(n)),e}static _collapse(e){"string"!=typeof e&&e.children&&(e.children.every(e=>"string"==typeof e)?e.children=[e.children.join("")]:e.children.forEach(e=>{l._collapse(e)}))}}class c extends l{constructor(e){super(),this.options=e}addKeyword(e,n){""!==e&&(this.openNode(n),this.addText(e),this.closeNode())}addText(e){""!==e&&this.add(e)}addSublanguage(e,n){const t=e.root;t.kind=n,t.sublanguage=!0,this.add(t)}toHTML(){return new o(this,this.options).value()}finalize(){return!0}}function d(e){return e?"string"==typeof e?e:e.source:null}function g(e){return m("(?=",e,")")}function u(e){return m("(?:",e,")*")}function b(e){return m("(?:",e,")?")}function m(...e){return e.map(e=>d(e)).join("")}function p(...e){const n=(e=>{const n=e[e.length-1];return"object"==typeof n&&n.constructor===Object?(e.splice(e.length-1,1),n):{}})(e);return"("+(n.capture?"":"?:")+e.map(e=>d(e)).join("|")+")"}function _(e){return RegExp(e.toString()+"|").exec("").length-1}const h=/\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./;function f(e,{joinWith:n}){let t=0;return e.map(e=>{t+=1;const n=t;let a=d(e),i="";for(;a.length>0;){const e=h.exec(a);if(!e){i+=a;break}i+=a.substring(0,e.index),a=a.substring(e.index+e[0].length),"\\"===e[0][0]&&e[1]?i+="\\"+(Number(e[1])+n):(i+=e[0],"("===e[0]&&t++)}return i}).map(e=>`(${e})`).join(n)}const E="[a-zA-Z]\\w*",y="[a-zA-Z_]\\w*",w="\\b\\d+(\\.\\d+)?",N="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",v="\\b(0b[01]+)",k={begin:"\\\\[\\s\\S]",relevance:0},O={scope:"string",begin:"'",end:"'",illegal:"\\n",contains:[k]},x={scope:"string",begin:'"',end:'"',illegal:"\\n",contains:[k]},M=(e,n,t={})=>{const a=r({scope:"comment",begin:e,end:n,contains:[]},t);a.contains.push({scope:"doctag",begin:"[ ]*(?=(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):)",end:/(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):/,excludeBegin:!0,relevance:0});const i=p("I","a","is","so","us","to","at","if","in","it","on",/[A-Za-z]+['](d|ve|re|ll|t|s|n)/,/[A-Za-z]+[-][a-z]+/,/[A-Za-z][a-z]{2,}/);return a.contains.push({begin:m(/[ ]+/,"(",i,/[.]?[:]?([.][ ]|[ ])/,"){3}")}),a},S=M("//","$"),A=M("/\\*","\\*/"),C=M("#","$");var T=Object.freeze({__proto__:null,MATCH_NOTHING_RE:/\b\B/,IDENT_RE:E,UNDERSCORE_IDENT_RE:y,NUMBER_RE:w,C_NUMBER_RE:N,BINARY_NUMBER_RE:v,RE_STARTERS_RE:"!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",SHEBANG:(e={})=>{const n=/^#![ ]*\//;return e.binary&&(e.begin=m(n,/.*\b/,e.binary,/\b.*/)),r({scope:"meta",begin:n,end:/$/,relevance:0,"on:begin":(e,n)=>{0!==e.index&&n.ignoreMatch()}},e)},BACKSLASH_ESCAPE:k,APOS_STRING_MODE:O,QUOTE_STRING_MODE:x,PHRASAL_WORDS_MODE:{begin:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/},COMMENT:M,C_LINE_COMMENT_MODE:S,C_BLOCK_COMMENT_MODE:A,HASH_COMMENT_MODE:C,NUMBER_MODE:{scope:"number",begin:w,relevance:0},C_NUMBER_MODE:{scope:"number",begin:N,relevance:0},BINARY_NUMBER_MODE:{scope:"number",begin:v,relevance:0},REGEXP_MODE:{begin:/(?=\/[^/\n]*\/)/,contains:[{scope:"regexp",begin:/\//,end:/\/[gimuy]*/,illegal:/\n/,contains:[k,{begin:/\[/,end:/\]/,relevance:0,contains:[k]}]}]},TITLE_MODE:{scope:"title",begin:E,relevance:0},UNDERSCORE_TITLE_MODE:{scope:"title",begin:y,relevance:0},METHOD_GUARD:{begin:"\\.\\s*[a-zA-Z_]\\w*",relevance:0},END_SAME_AS_BEGIN:e=>Object.assign(e,{"on:begin":(e,n)=>{n.data._beginMatch=e[1]},"on:end":(e,n)=>{n.data._beginMatch!==e[1]&&n.ignoreMatch()}})});function R(e,n){"."===e.input[e.index-1]&&n.ignoreMatch()}function D(e,n){void 0!==e.className&&(e.scope=e.className,delete e.className)}function I(e,n){n&&e.beginKeywords&&(e.begin="\\b("+e.beginKeywords.split(" ").join("|")+")(?!\\.)(?=\\b|\\s)",e.__beforeBegin=R,e.keywords=e.keywords||e.beginKeywords,delete e.beginKeywords,void 0===e.relevance&&(e.relevance=0))}function L(e,n){Array.isArray(e.illegal)&&(e.illegal=p(...e.illegal))}function B(e,n){if(e.match){if(e.begin||e.end)throw Error("begin & end are not supported with match");e.begin=e.match,delete e.match}}function $(e,n){void 0===e.relevance&&(e.relevance=1)}const z=(e,n)=>{if(!e.beforeMatch)return;if(e.starts)throw Error("beforeMatch cannot be used with starts");const t=Object.assign({},e);Object.keys(e).forEach(n=>{delete e[n]}),e.keywords=t.keywords,e.begin=m(t.beforeMatch,g(t.begin)),e.starts={relevance:0,contains:[Object.assign(t,{endsParent:!0})]},e.relevance=0,delete t.beforeMatch},F=["of","and","for","in","not","or","if","then","parent","list","value"];function U(e,n,t="keyword"){const a=Object.create(null);return"string"==typeof e?i(t,e.split(" ")):Array.isArray(e)?i(t,e):Object.keys(e).forEach(t=>{Object.assign(a,U(e[t],n,t))}),a;function i(e,t){n&&(t=t.map(e=>e.toLowerCase())),t.forEach(n=>{const t=n.split("|");a[t[0]]=[e,j(t[0],t[1])]})}}function j(e,n){return n?Number(n):(e=>F.includes(e.toLowerCase()))(e)?0:1}const P={},K=e=>{console.error(e)},H=(e,...n)=>{console.log("WARN: "+e,...n)},q=(e,n)=>{P[`${e}/${n}`]||(console.log(`Deprecated as of ${e}. ${n}`),P[`${e}/${n}`]=!0)},Z=Error();function G(e,n,{key:t}){let a=0;const i=e[t],r={},s={};for(let e=1;e<=n.length;e++)s[e+a]=i[e],r[e+a]=!0,a+=_(n[e-1]);e[t]=s,e[t]._emit=r,e[t]._multi=!0}function W(e){(e=>{e.scope&&"object"==typeof e.scope&&null!==e.scope&&(e.beginScope=e.scope,delete e.scope)})(e),"string"==typeof e.beginScope&&(e.beginScope={_wrap:e.beginScope}),"string"==typeof e.endScope&&(e.endScope={_wrap:e.endScope}),(e=>{if(Array.isArray(e.begin)){if(e.skip||e.excludeBegin||e.returnBegin)throw K("skip, excludeBegin, returnBegin not compatible with beginScope: {}"),Z;if("object"!=typeof e.beginScope||null===e.beginScope)throw K("beginScope must be object"),Z;G(e,e.begin,{key:"beginScope"}),e.begin=f(e.begin,{joinWith:""})}})(e),(e=>{if(Array.isArray(e.end)){if(e.skip||e.excludeEnd||e.returnEnd)throw K("skip, excludeEnd, returnEnd not compatible with endScope: {}"),Z;if("object"!=typeof e.endScope||null===e.endScope)throw K("endScope must be object"),Z;G(e,e.end,{key:"endScope"}),e.end=f(e.end,{joinWith:""})}})(e)}function Q(e){function n(n,t){return RegExp(d(n),"m"+(e.case_insensitive?"i":"")+(e.unicodeRegex?"u":"")+(t?"g":""))}class t{constructor(){this.matchIndexes={},this.regexes=[],this.matchAt=1,this.position=0}addRule(e,n){n.position=this.position++,this.matchIndexes[this.matchAt]=n,this.regexes.push([n,e]),this.matchAt+=_(e)+1}compile(){0===this.regexes.length&&(this.exec=()=>null);const e=this.regexes.map(e=>e[1]);this.matcherRe=n(f(e,{joinWith:"|"}),!0),this.lastIndex=0}exec(e){this.matcherRe.lastIndex=this.lastIndex;const n=this.matcherRe.exec(e);if(!n)return null;const t=n.findIndex((e,n)=>n>0&&void 0!==e),a=this.matchIndexes[t];return n.splice(0,t),Object.assign(n,a)}}class a{constructor(){this.rules=[],this.multiRegexes=[],this.count=0,this.lastIndex=0,this.regexIndex=0}getMatcher(e){if(this.multiRegexes[e])return this.multiRegexes[e];const n=new t;return this.rules.slice(e).forEach(([e,t])=>n.addRule(e,t)),n.compile(),this.multiRegexes[e]=n,n}resumingScanAtSamePosition(){return 0!==this.regexIndex}considerAll(){this.regexIndex=0}addRule(e,n){this.rules.push([e,n]),"begin"===n.type&&this.count++}exec(e){const n=this.getMatcher(this.regexIndex);n.lastIndex=this.lastIndex;let t=n.exec(e);if(this.resumingScanAtSamePosition())if(t&&t.index===this.lastIndex);else{const n=this.getMatcher(0);n.lastIndex=this.lastIndex+1,t=n.exec(e)}return t&&(this.regexIndex+=t.position+1,this.regexIndex===this.count&&this.considerAll()),t}}if(e.compilerExtensions||(e.compilerExtensions=[]),e.contains&&e.contains.includes("self"))throw Error("ERR: contains `self` is not supported at the top-level of a language. See documentation.");return e.classNameAliases=r(e.classNameAliases||{}),function t(i,s){const o=i;if(i.isCompiled)return o;[D,B,W,z].forEach(e=>e(i,s)),e.compilerExtensions.forEach(e=>e(i,s)),i.__beforeBegin=null,[I,L,$].forEach(e=>e(i,s)),i.isCompiled=!0;let l=null;return"object"==typeof i.keywords&&i.keywords.$pattern&&(i.keywords=Object.assign({},i.keywords),l=i.keywords.$pattern,delete i.keywords.$pattern),l=l||/\w+/,i.keywords&&(i.keywords=U(i.keywords,e.case_insensitive)),o.keywordPatternRe=n(l,!0),s&&(i.begin||(i.begin=/\B|\b/),o.beginRe=n(o.begin),i.end||i.endsWithParent||(i.end=/\B|\b/),i.end&&(o.endRe=n(o.end)),o.terminatorEnd=d(o.end)||"",i.endsWithParent&&s.terminatorEnd&&(o.terminatorEnd+=(i.end?"|":"")+s.terminatorEnd)),i.illegal&&(o.illegalRe=n(i.illegal)),i.contains||(i.contains=[]),i.contains=[].concat(...i.contains.map(e=>(e=>(e.variants&&!e.cachedVariants&&(e.cachedVariants=e.variants.map(n=>r(e,{variants:null},n))),e.cachedVariants?e.cachedVariants:X(e)?r(e,{starts:e.starts?r(e.starts):null}):Object.isFrozen(e)?r(e):e))("self"===e?i:e))),i.contains.forEach(e=>{t(e,o)}),i.starts&&t(i.starts,s),o.matcher=(e=>{const n=new a;return e.contains.forEach(e=>n.addRule(e.begin,{rule:e,type:"begin"})),e.terminatorEnd&&n.addRule(e.terminatorEnd,{type:"end"}),e.illegal&&n.addRule(e.illegal,{type:"illegal"}),n})(o),o}(e)}function X(e){return!!e&&(e.endsWithParent||X(e.starts))}class V extends Error{constructor(e,n){super(e),this.name="HTMLInjectionError",this.html=n}}const J=i,Y=r,ee=Symbol("nomatch");var ne=(e=>{const n=Object.create(null),i=Object.create(null),r=[];let s=!0;const o="Could not find the language '{}', did you forget to load/include a language module?",l={disableAutodetect:!0,name:"Plain text",contains:[]};let d={ignoreUnescapedHTML:!1,throwUnescapedHTML:!1,noHighlightRe:/^(no-?highlight)$/i,languageDetectRe:/\blang(?:uage)?-([\w-]+)\b/i,classPrefix:"hljs-",cssSelector:"pre code",languages:null,__emitter:c};function _(e){return d.noHighlightRe.test(e)}function h(e,n,t){let a="",i="";"object"==typeof n?(a=e,t=n.ignoreIllegals,i=n.language):(q("10.7.0","highlight(lang, code, ...args) has been deprecated."),q("10.7.0","Please use highlight(code, options) instead.\nhttps://github.com/highlightjs/highlight.js/issues/2277"),i=e,a=n),void 0===t&&(t=!0);const r={code:a,language:i};x("before:highlight",r);const s=r.result?r.result:f(r.language,r.code,t);return s.code=r.code,x("after:highlight",s),s}function f(e,t,i,r){const l=Object.create(null);function c(){if(!O.keywords)return void M.addText(S);let e=0;O.keywordPatternRe.lastIndex=0;let n=O.keywordPatternRe.exec(S),t="";for(;n;){t+=S.substring(e,n.index);const i=w.case_insensitive?n[0].toLowerCase():n[0],r=(a=i,O.keywords[a]);if(r){const[e,a]=r;if(M.addText(t),t="",l[i]=(l[i]||0)+1,l[i]<=7&&(A+=a),e.startsWith("_"))t+=n[0];else{const t=w.classNameAliases[e]||e;M.addKeyword(n[0],t)}}else t+=n[0];e=O.keywordPatternRe.lastIndex,n=O.keywordPatternRe.exec(S)}var a;t+=S.substr(e),M.addText(t)}function g(){null!=O.subLanguage?(()=>{if(""===S)return;let e=null;if("string"==typeof O.subLanguage){if(!n[O.subLanguage])return void M.addText(S);e=f(O.subLanguage,S,!0,x[O.subLanguage]),x[O.subLanguage]=e._top}else e=E(S,O.subLanguage.length?O.subLanguage:null);O.relevance>0&&(A+=e.relevance),M.addSublanguage(e._emitter,e.language)})():c(),S=""}function u(e,n){let t=1;const a=n.length-1;for(;t<=a;){if(!e._emit[t]){t++;continue}const a=w.classNameAliases[e[t]]||e[t],i=n[t];a?M.addKeyword(i,a):(S=i,c(),S=""),t++}}function b(e,n){return e.scope&&"string"==typeof e.scope&&M.openNode(w.classNameAliases[e.scope]||e.scope),e.beginScope&&(e.beginScope._wrap?(M.addKeyword(S,w.classNameAliases[e.beginScope._wrap]||e.beginScope._wrap),S=""):e.beginScope._multi&&(u(e.beginScope,n),S="")),O=Object.create(e,{parent:{value:O}}),O}function m(e,n,t){let i=((e,n)=>{const t=e&&e.exec(n);return t&&0===t.index})(e.endRe,t);if(i){if(e["on:end"]){const t=new a(e);e["on:end"](n,t),t.isMatchIgnored&&(i=!1)}if(i){for(;e.endsParent&&e.parent;)e=e.parent;return e}}if(e.endsWithParent)return m(e.parent,n,t)}function p(e){return 0===O.matcher.regexIndex?(S+=e[0],1):(R=!0,0)}function _(e){const n=e[0],a=t.substr(e.index),i=m(O,e,a);if(!i)return ee;const r=O;O.endScope&&O.endScope._wrap?(g(),M.addKeyword(n,O.endScope._wrap)):O.endScope&&O.endScope._multi?(g(),u(O.endScope,e)):r.skip?S+=n:(r.returnEnd||r.excludeEnd||(S+=n),g(),r.excludeEnd&&(S=n));do{O.scope&&M.closeNode(),O.skip||O.subLanguage||(A+=O.relevance),O=O.parent}while(O!==i.parent);return i.starts&&b(i.starts,e),r.returnEnd?0:n.length}let h={};function y(n,r){const o=r&&r[0];if(S+=n,null==o)return g(),0;if("begin"===h.type&&"end"===r.type&&h.index===r.index&&""===o){if(S+=t.slice(r.index,r.index+1),!s){const n=Error(`0 width match regex (${e})`);throw n.languageName=e,n.badRule=h.rule,n}return 1}if(h=r,"begin"===r.type)return(e=>{const n=e[0],t=e.rule,i=new a(t),r=[t.__beforeBegin,t["on:begin"]];for(const t of r)if(t&&(t(e,i),i.isMatchIgnored))return p(n);return t.skip?S+=n:(t.excludeBegin&&(S+=n),g(),t.returnBegin||t.excludeBegin||(S=n)),b(t,e),t.returnBegin?0:n.length})(r);if("illegal"===r.type&&!i){const e=Error('Illegal lexeme "'+o+'" for mode "'+(O.scope||"")+'"');throw e.mode=O,e}if("end"===r.type){const e=_(r);if(e!==ee)return e}if("illegal"===r.type&&""===o)return 1;if(T>1e5&&T>3*r.index)throw Error("potential infinite loop, way more iterations than matches");return S+=o,o.length}const w=v(e);if(!w)throw K(o.replace("{}",e)),Error('Unknown language: "'+e+'"');const N=Q(w);let k="",O=r||N;const x={},M=new d.__emitter(d);(()=>{const e=[];for(let n=O;n!==w;n=n.parent)n.scope&&e.unshift(n.scope);e.forEach(e=>M.openNode(e))})();let S="",A=0,C=0,T=0,R=!1;try{for(O.matcher.considerAll();;){T++,R?R=!1:O.matcher.considerAll(),O.matcher.lastIndex=C;const e=O.matcher.exec(t);if(!e)break;const n=y(t.substring(C,e.index),e);C=e.index+n}return y(t.substr(C)),M.closeAllNodes(),M.finalize(),k=M.toHTML(),{language:e,value:k,relevance:A,illegal:!1,_emitter:M,_top:O}}catch(n){if(n.message&&n.message.includes("Illegal"))return{language:e,value:J(t),illegal:!0,relevance:0,_illegalBy:{message:n.message,index:C,context:t.slice(C-100,C+100),mode:n.mode,resultSoFar:k},_emitter:M};if(s)return{language:e,value:J(t),illegal:!1,relevance:0,errorRaised:n,_emitter:M,_top:O};throw n}}function E(e,t){t=t||d.languages||Object.keys(n);const a=(e=>{const n={value:J(e),illegal:!1,relevance:0,_top:l,_emitter:new d.__emitter(d)};return n._emitter.addText(e),n})(e),i=t.filter(v).filter(O).map(n=>f(n,e,!1));i.unshift(a);const r=i.sort((e,n)=>{if(e.relevance!==n.relevance)return n.relevance-e.relevance;if(e.language&&n.language){if(v(e.language).supersetOf===n.language)return 1;if(v(n.language).supersetOf===e.language)return-1}return 0}),[s,o]=r,c=s;return c.secondBest=o,c}function y(e){let n=null;const t=(e=>{let n=e.className+" ";n+=e.parentNode?e.parentNode.className:"";const t=d.languageDetectRe.exec(n);if(t){const n=v(t[1]);return n||(H(o.replace("{}",t[1])),H("Falling back to no-highlight mode for this block.",e)),n?t[1]:"no-highlight"}return n.split(/\s+/).find(e=>_(e)||v(e))})(e);if(_(t))return;if(x("before:highlightElement",{el:e,language:t}),e.children.length>0&&(d.ignoreUnescapedHTML||(console.warn("One of your code blocks includes unescaped HTML. This is a potentially serious security risk."),console.warn("https://github.com/highlightjs/highlight.js/wiki/security"),console.warn("The element with unescaped HTML:"),console.warn(e)),d.throwUnescapedHTML))throw new V("One of your code blocks includes unescaped HTML.",e.innerHTML);n=e;const a=n.textContent,r=t?h(a,{language:t,ignoreIllegals:!0}):E(a);e.innerHTML=r.value,((e,n,t)=>{const a=n&&i[n]||t;e.classList.add("hljs"),e.classList.add("language-"+a)})(e,t,r.language),e.result={language:r.language,re:r.relevance,relevance:r.relevance},r.secondBest&&(e.secondBest={language:r.secondBest.language,relevance:r.secondBest.relevance}),x("after:highlightElement",{el:e,result:r,text:a})}let w=!1;function N(){"loading"!==document.readyState?document.querySelectorAll(d.cssSelector).forEach(y):w=!0}function v(e){return e=(e||"").toLowerCase(),n[e]||n[i[e]]}function k(e,{languageName:n}){"string"==typeof e&&(e=[e]),e.forEach(e=>{i[e.toLowerCase()]=n})}function O(e){const n=v(e);return n&&!n.disableAutodetect}function x(e,n){const t=e;r.forEach(e=>{e[t]&&e[t](n)})}"undefined"!=typeof window&&window.addEventListener&&window.addEventListener("DOMContentLoaded",()=>{w&&N()},!1),Object.assign(e,{highlight:h,highlightAuto:E,highlightAll:N,highlightElement:y,highlightBlock:e=>(q("10.7.0","highlightBlock will be removed entirely in v12.0"),q("10.7.0","Please use highlightElement now."),y(e)),configure:e=>{d=Y(d,e)},initHighlighting:()=>{N(),q("10.6.0","initHighlighting() deprecated. Use highlightAll() now.")},initHighlightingOnLoad:()=>{N(),q("10.6.0","initHighlightingOnLoad() deprecated. Use highlightAll() now.")},registerLanguage:(t,a)=>{let i=null;try{i=a(e)}catch(e){if(K("Language definition for '{}' could not be registered.".replace("{}",t)),!s)throw e;K(e),i=l}i.name||(i.name=t),n[t]=i,i.rawDefinition=a.bind(null,e),i.aliases&&k(i.aliases,{languageName:t})},unregisterLanguage:e=>{delete n[e];for(const n of Object.keys(i))i[n]===e&&delete i[n]},listLanguages:()=>Object.keys(n),getLanguage:v,registerAliases:k,autoDetection:O,inherit:Y,addPlugin:e=>{(e=>{e["before:highlightBlock"]&&!e["before:highlightElement"]&&(e["before:highlightElement"]=n=>{e["before:highlightBlock"](Object.assign({block:n.el},n))}),e["after:highlightBlock"]&&!e["after:highlightElement"]&&(e["after:highlightElement"]=n=>{e["after:highlightBlock"](Object.assign({block:n.el},n))})})(e),r.push(e)}}),e.debugMode=()=>{s=!1},e.safeMode=()=>{s=!0},e.versionString="11.5.0",e.regex={concat:m,lookahead:g,either:p,optional:b,anyNumberOfTimes:u};for(const e in T)"object"==typeof T[e]&&t(T[e]);return Object.assign(e,T),e})({});const te=e=>({IMPORTANT:{scope:"meta",begin:"!important"},BLOCK_COMMENT:e.C_BLOCK_COMMENT_MODE,HEXCOLOR:{scope:"number",begin:/#(([0-9a-fA-F]{3,4})|(([0-9a-fA-F]{2}){3,4}))\b/},FUNCTION_DISPATCH:{className:"built_in",begin:/[\w-]+(?=\()/},ATTRIBUTE_SELECTOR_MODE:{scope:"selector-attr",begin:/\[/,end:/\]/,illegal:"$",contains:[e.APOS_STRING_MODE,e.QUOTE_STRING_MODE]},CSS_NUMBER_MODE:{scope:"number",begin:e.NUMBER_RE+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",relevance:0},CSS_VARIABLE:{className:"attr",begin:/--[A-Za-z][A-Za-z0-9_-]*/}}),ae=["a","abbr","address","article","aside","audio","b","blockquote","body","button","canvas","caption","cite","code","dd","del","details","dfn","div","dl","dt","em","fieldset","figcaption","figure","footer","form","h1","h2","h3","h4","h5","h6","header","hgroup","html","i","iframe","img","input","ins","kbd","label","legend","li","main","mark","menu","nav","object","ol","p","q","quote","samp","section","span","strong","summary","sup","table","tbody","td","textarea","tfoot","th","thead","time","tr","ul","var","video"],ie=["any-hover","any-pointer","aspect-ratio","color","color-gamut","color-index","device-aspect-ratio","device-height","device-width","display-mode","forced-colors","grid","height","hover","inverted-colors","monochrome","orientation","overflow-block","overflow-inline","pointer","prefers-color-scheme","prefers-contrast","prefers-reduced-motion","prefers-reduced-transparency","resolution","scan","scripting","update","width","min-width","max-width","min-height","max-height"],re=["active","any-link","blank","checked","current","default","defined","dir","disabled","drop","empty","enabled","first","first-child","first-of-type","fullscreen","future","focus","focus-visible","focus-within","has","host","host-context","hover","indeterminate","in-range","invalid","is","lang","last-child","last-of-type","left","link","local-link","not","nth-child","nth-col","nth-last-child","nth-last-col","nth-last-of-type","nth-of-type","only-child","only-of-type","optional","out-of-range","past","placeholder-shown","read-only","read-write","required","right","root","scope","target","target-within","user-invalid","valid","visited","where"],se=["after","backdrop","before","cue","cue-region","first-letter","first-line","grammar-error","marker","part","placeholder","selection","slotted","spelling-error"],oe=["align-content","align-items","align-self","all","animation","animation-delay","animation-direction","animation-duration","animation-fill-mode","animation-iteration-count","animation-name","animation-play-state","animation-timing-function","backface-visibility","background","background-attachment","background-blend-mode","background-clip","background-color","background-image","background-origin","background-position","background-repeat","background-size","block-size","border","border-block","border-block-color","border-block-end","border-block-end-color","border-block-end-style","border-block-end-width","border-block-start","border-block-start-color","border-block-start-style","border-block-start-width","border-block-style","border-block-width","border-bottom","border-bottom-color","border-bottom-left-radius","border-bottom-right-radius","border-bottom-style","border-bottom-width","border-collapse","border-color","border-image","border-image-outset","border-image-repeat","border-image-slice","border-image-source","border-image-width","border-inline","border-inline-color","border-inline-end","border-inline-end-color","border-inline-end-style","border-inline-end-width","border-inline-start","border-inline-start-color","border-inline-start-style","border-inline-start-width","border-inline-style","border-inline-width","border-left","border-left-color","border-left-style","border-left-width","border-radius","border-right","border-right-color","border-right-style","border-right-width","border-spacing","border-style","border-top","border-top-color","border-top-left-radius","border-top-right-radius","border-top-style","border-top-width","border-width","bottom","box-decoration-break","box-shadow","box-sizing","break-after","break-before","break-inside","caption-side","caret-color","clear","clip","clip-path","clip-rule","color","column-count","column-fill","column-gap","column-rule","column-rule-color","column-rule-style","column-rule-width","column-span","column-width","columns","contain","content","content-visibility","counter-increment","counter-reset","cue","cue-after","cue-before","cursor","direction","display","empty-cells","filter","flex","flex-basis","flex-direction","flex-flow","flex-grow","flex-shrink","flex-wrap","float","flow","font","font-display","font-family","font-feature-settings","font-kerning","font-language-override","font-size","font-size-adjust","font-smoothing","font-stretch","font-style","font-synthesis","font-variant","font-variant-caps","font-variant-east-asian","font-variant-ligatures","font-variant-numeric","font-variant-position","font-variation-settings","font-weight","gap","glyph-orientation-vertical","grid","grid-area","grid-auto-columns","grid-auto-flow","grid-auto-rows","grid-column","grid-column-end","grid-column-start","grid-gap","grid-row","grid-row-end","grid-row-start","grid-template","grid-template-areas","grid-template-columns","grid-template-rows","hanging-punctuation","height","hyphens","icon","image-orientation","image-rendering","image-resolution","ime-mode","inline-size","isolation","justify-content","left","letter-spacing","line-break","line-height","list-style","list-style-image","list-style-position","list-style-type","margin","margin-block","margin-block-end","margin-block-start","margin-bottom","margin-inline","margin-inline-end","margin-inline-start","margin-left","margin-right","margin-top","marks","mask","mask-border","mask-border-mode","mask-border-outset","mask-border-repeat","mask-border-slice","mask-border-source","mask-border-width","mask-clip","mask-composite","mask-image","mask-mode","mask-origin","mask-position","mask-repeat","mask-size","mask-type","max-block-size","max-height","max-inline-size","max-width","min-block-size","min-height","min-inline-size","min-width","mix-blend-mode","nav-down","nav-index","nav-left","nav-right","nav-up","none","normal","object-fit","object-position","opacity","order","orphans","outline","outline-color","outline-offset","outline-style","outline-width","overflow","overflow-wrap","overflow-x","overflow-y","padding","padding-block","padding-block-end","padding-block-start","padding-bottom","padding-inline","padding-inline-end","padding-inline-start","padding-left","padding-right","padding-top","page-break-after","page-break-before","page-break-inside","pause","pause-after","pause-before","perspective","perspective-origin","pointer-events","position","quotes","resize","rest","rest-after","rest-before","right","row-gap","scroll-margin","scroll-margin-block","scroll-margin-block-end","scroll-margin-block-start","scroll-margin-bottom","scroll-margin-inline","scroll-margin-inline-end","scroll-margin-inline-start","scroll-margin-left","scroll-margin-right","scroll-margin-top","scroll-padding","scroll-padding-block","scroll-padding-block-end","scroll-padding-block-start","scroll-padding-bottom","scroll-padding-inline","scroll-padding-inline-end","scroll-padding-inline-start","scroll-padding-left","scroll-padding-right","scroll-padding-top","scroll-snap-align","scroll-snap-stop","scroll-snap-type","scrollbar-color","scrollbar-gutter","scrollbar-width","shape-image-threshold","shape-margin","shape-outside","speak","speak-as","src","tab-size","table-layout","text-align","text-align-all","text-align-last","text-combine-upright","text-decoration","text-decoration-color","text-decoration-line","text-decoration-style","text-emphasis","text-emphasis-color","text-emphasis-position","text-emphasis-style","text-indent","text-justify","text-orientation","text-overflow","text-rendering","text-shadow","text-transform","text-underline-position","top","transform","transform-box","transform-origin","transform-style","transition","transition-delay","transition-duration","transition-property","transition-timing-function","unicode-bidi","vertical-align","visibility","voice-balance","voice-duration","voice-family","voice-pitch","voice-range","voice-rate","voice-stress","voice-volume","white-space","widows","width","will-change","word-break","word-spacing","word-wrap","writing-mode","z-index"].reverse(),le=re.concat(se);var ce="\\.([0-9](_*[0-9])*)",de="[0-9a-fA-F](_*[0-9a-fA-F])*",ge={className:"number",variants:[{begin:`(\\b([0-9](_*[0-9])*)((${ce})|\\.)?|(${ce}))[eE][+-]?([0-9](_*[0-9])*)[fFdD]?\\b`},{begin:`\\b([0-9](_*[0-9])*)((${ce})[fFdD]?\\b|\\.([fFdD]\\b)?)`},{begin:`(${ce})[fFdD]?\\b`},{begin:"\\b([0-9](_*[0-9])*)[fFdD]\\b"},{begin:`\\b0[xX]((${de})\\.?|(${de})?\\.(${de}))[pP][+-]?([0-9](_*[0-9])*)[fFdD]?\\b`},{begin:"\\b(0|[1-9](_*[0-9])*)[lL]?\\b"},{begin:`\\b0[xX](${de})[lL]?\\b`},{begin:"\\b0(_*[0-7])*[lL]?\\b"},{begin:"\\b0[bB][01](_*[01])*[lL]?\\b"}],relevance:0};function ue(e,n,t){return-1===t?"":e.replace(n,a=>ue(e,n,t-1))}const be="[A-Za-z$_][0-9A-Za-z$_]*",me=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","case","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends"],pe=["true","false","null","undefined","NaN","Infinity"],_e=["Object","Function","Boolean","Symbol","Math","Date","Number","BigInt","String","RegExp","Array","Float32Array","Float64Array","Int8Array","Uint8Array","Uint8ClampedArray","Int16Array","Int32Array","Uint16Array","Uint32Array","BigInt64Array","BigUint64Array","Set","Map","WeakSet","WeakMap","ArrayBuffer","SharedArrayBuffer","Atomics","DataView","JSON","Promise","Generator","GeneratorFunction","AsyncFunction","Reflect","Proxy","Intl","WebAssembly"],he=["Error","EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"],fe=["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],Ee=["arguments","this","super","console","window","document","localStorage","module","global"],ye=[].concat(fe,_e,he);function we(e){const n=e.regex,t=be,a={begin:/<[A-Za-z0-9\\._:-]+/,end:/\/[A-Za-z0-9\\._:-]+>|\/>/,isTrulyOpeningTag:(e,n)=>{const t=e[0].length+e.index,a=e.input[t];if("<"===a||","===a)return void n.ignoreMatch();let i;">"===a&&(((e,{after:n})=>{const t="",O={match:[/const|var|let/,/\s+/,t,/\s*/,/=\s*/,/(async\s*)?/,n.lookahead(k)],keywords:"async",className:{1:"keyword",3:"title.function"},contains:[_]};return{name:"Javascript",aliases:["js","jsx","mjs","cjs"],keywords:i,exports:{PARAMS_CONTAINS:p,CLASS_REFERENCE:f},illegal:/#(?![$_A-z])/,contains:[e.SHEBANG({label:"shebang",binary:"node",relevance:5}),{label:"use_strict",className:"meta",relevance:10,begin:/^\s*['"]use (strict|asm)['"]/},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,c,d,g,u,o,f,{className:"attr",begin:t+n.lookahead(":"),relevance:0},O,{begin:"("+e.RE_STARTERS_RE+"|\\b(case|return|throw)\\b)\\s*",keywords:"return throw case",relevance:0,contains:[u,e.REGEXP_MODE,{className:"function",begin:k,returnBegin:!0,end:"\\s*=>",contains:[{className:"params",variants:[{begin:e.UNDERSCORE_IDENT_RE,relevance:0},{className:null,begin:/\(\s*\)/,skip:!0},{begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:i,contains:p}]}]},{begin:/,/,relevance:0},{match:/\s+/,relevance:0},{variants:[{begin:"<>",end:""},{match:/<[A-Za-z0-9\\._:-]+\s*\/>/},{begin:a.begin,"on:begin":a.isTrulyOpeningTag,end:a.end}],subLanguage:"xml",contains:[{begin:a.begin,end:a.end,skip:!0,contains:["self"]}]}]},E,{beginKeywords:"while if case catch for"},{begin:"\\b(?!function)"+e.UNDERSCORE_IDENT_RE+"\\([^()]*(\\([^()]*(\\([^()]*\\)[^()]*)*\\)[^()]*)*\\)\\s*\\{",returnBegin:!0,label:"func.def",contains:[_,e.inherit(e.TITLE_MODE,{begin:t,className:"title.function"})]},{match:/\.\.\./,relevance:0},N,{match:"\\$"+t,relevance:0},{match:[/\bconstructor(?=\s*\()/],className:{1:"title.function"},contains:[_]},y,{relevance:0,match:/\b[A-Z][A-Z_0-9]+\b/,className:"variable.constant"},h,v,{match:/\$[(.]/}]}}const Ne=e=>m(/\b/,e,/\w$/.test(e)?/\b/:/\B/),ve=["Protocol","Type"].map(Ne),ke=["init","self"].map(Ne),Oe=["Any","Self"],xe=["actor","associatedtype","async","await",/as\?/,/as!/,"as","break","case","catch","class","continue","convenience","default","defer","deinit","didSet","do","dynamic","else","enum","extension","fallthrough",/fileprivate\(set\)/,"fileprivate","final","for","func","get","guard","if","import","indirect","infix",/init\?/,/init!/,"inout",/internal\(set\)/,"internal","in","is","isolated","nonisolated","lazy","let","mutating","nonmutating",/open\(set\)/,"open","operator","optional","override","postfix","precedencegroup","prefix",/private\(set\)/,"private","protocol",/public\(set\)/,"public","repeat","required","rethrows","return","set","some","static","struct","subscript","super","case","throws","throw",/try\?/,/try!/,"try","typealias",/unowned\(safe\)/,/unowned\(unsafe\)/,"unowned","var","weak","where","while","willSet"],Me=["false","nil","true"],Se=["assignment","associativity","higherThan","left","lowerThan","none","right"],Ae=["#colorLiteral","#column","#dsohandle","#else","#elseif","#endif","#error","#file","#fileID","#fileLiteral","#filePath","#function","#if","#imageLiteral","#keyPath","#line","#selector","#sourceLocation","#warn_unqualified_access","#warning"],Ce=["abs","all","any","assert","assertionFailure","debugPrint","dump","fatalError","getVaList","isKnownUniquelyReferenced","max","min","numericCast","pointwiseMax","pointwiseMin","precondition","preconditionFailure","print","readLine","repeatElement","sequence","stride","swap","swift_unboxFromSwiftValueWithType","transcode","type","unsafeBitCast","unsafeDowncast","withExtendedLifetime","withUnsafeMutablePointer","withUnsafePointer","withVaList","withoutActuallyEscaping","zip"],Te=p(/[/=\-+!*%<>&|^~?]/,/[\u00A1-\u00A7]/,/[\u00A9\u00AB]/,/[\u00AC\u00AE]/,/[\u00B0\u00B1]/,/[\u00B6\u00BB\u00BF\u00D7\u00F7]/,/[\u2016-\u2017]/,/[\u2020-\u2027]/,/[\u2030-\u203E]/,/[\u2041-\u2053]/,/[\u2055-\u205E]/,/[\u2190-\u23FF]/,/[\u2500-\u2775]/,/[\u2794-\u2BFF]/,/[\u2E00-\u2E7F]/,/[\u3001-\u3003]/,/[\u3008-\u3020]/,/[\u3030]/),Re=p(Te,/[\u0300-\u036F]/,/[\u1DC0-\u1DFF]/,/[\u20D0-\u20FF]/,/[\uFE00-\uFE0F]/,/[\uFE20-\uFE2F]/),De=m(Te,Re,"*"),Ie=p(/[a-zA-Z_]/,/[\u00A8\u00AA\u00AD\u00AF\u00B2-\u00B5\u00B7-\u00BA]/,/[\u00BC-\u00BE\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF]/,/[\u0100-\u02FF\u0370-\u167F\u1681-\u180D\u180F-\u1DBF]/,/[\u1E00-\u1FFF]/,/[\u200B-\u200D\u202A-\u202E\u203F-\u2040\u2054\u2060-\u206F]/,/[\u2070-\u20CF\u2100-\u218F\u2460-\u24FF\u2776-\u2793]/,/[\u2C00-\u2DFF\u2E80-\u2FFF]/,/[\u3004-\u3007\u3021-\u302F\u3031-\u303F\u3040-\uD7FF]/,/[\uF900-\uFD3D\uFD40-\uFDCF\uFDF0-\uFE1F\uFE30-\uFE44]/,/[\uFE47-\uFEFE\uFF00-\uFFFD]/),Le=p(Ie,/\d/,/[\u0300-\u036F\u1DC0-\u1DFF\u20D0-\u20FF\uFE20-\uFE2F]/),Be=m(Ie,Le,"*"),$e=m(/[A-Z]/,Le,"*"),ze=["autoclosure",m(/convention\(/,p("swift","block","c"),/\)/),"discardableResult","dynamicCallable","dynamicMemberLookup","escaping","frozen","GKInspectable","IBAction","IBDesignable","IBInspectable","IBOutlet","IBSegueAction","inlinable","main","nonobjc","NSApplicationMain","NSCopying","NSManaged",m(/objc\(/,Be,/\)/),"objc","objcMembers","propertyWrapper","requires_stored_property_inits","resultBuilder","testable","UIApplicationMain","unknown","usableFromInline"],Fe=["iOS","iOSApplicationExtension","macOS","macOSApplicationExtension","macCatalyst","macCatalystApplicationExtension","watchOS","watchOSApplicationExtension","tvOS","tvOSApplicationExtension","swift"];var Ue=Object.freeze({__proto__:null,grmr_bash:e=>{const n=e.regex,t={},a={begin:/\$\{/,end:/\}/,contains:["self",{begin:/:-/,contains:[t]}]};Object.assign(t,{className:"variable",variants:[{begin:n.concat(/\$[\w\d#@][\w\d_]*/,"(?![\\w\\d])(?![$])")},a]});const i={className:"subst",begin:/\$\(/,end:/\)/,contains:[e.BACKSLASH_ESCAPE]},r={begin:/<<-?\s*(?=\w+)/,starts:{contains:[e.END_SAME_AS_BEGIN({begin:/(\w+)/,end:/(\w+)/,className:"string"})]}},s={className:"string",begin:/"/,end:/"/,contains:[e.BACKSLASH_ESCAPE,t,i]};i.contains.push(s);const o={begin:/\$\(\(/,end:/\)\)/,contains:[{begin:/\d+#[0-9a-f]+/,className:"number"},e.NUMBER_MODE,t]},l=e.SHEBANG({binary:"(fish|bash|zsh|sh|csh|ksh|tcsh|dash|scsh)",relevance:10}),c={className:"function",begin:/\w[\w\d_]*\s*\(\s*\)\s*\{/,returnBegin:!0,contains:[e.inherit(e.TITLE_MODE,{begin:/\w[\w\d_]*/})],relevance:0};return{name:"Bash",aliases:["sh"],keywords:{$pattern:/\b[a-z][a-z0-9._-]+\b/,keyword:["if","then","else","elif","fi","for","while","in","do","done","case","esac","function"],literal:["true","false"],built_in:["break","cd","continue","eval","exec","exit","export","getopts","hash","pwd","readonly","return","shift","test","times","trap","umask","unset","alias","bind","builtin","caller","command","declare","echo","enable","help","let","local","logout","mapfile","printf","read","readarray","source","type","typeset","ulimit","unalias","set","shopt","autoload","bg","bindkey","bye","cap","chdir","clone","comparguments","compcall","compctl","compdescribe","compfiles","compgroups","compquote","comptags","comptry","compvalues","dirs","disable","disown","echotc","echoti","emulate","fc","fg","float","functions","getcap","getln","history","integer","jobs","kill","limit","log","noglob","popd","print","pushd","pushln","rehash","sched","setcap","setopt","stat","suspend","ttyctl","unfunction","unhash","unlimit","unsetopt","vared","wait","whence","where","which","zcompile","zformat","zftp","zle","zmodload","zparseopts","zprof","zpty","zregexparse","zsocket","zstyle","ztcp","chcon","chgrp","chown","chmod","cp","dd","df","dir","dircolors","ln","ls","mkdir","mkfifo","mknod","mktemp","mv","realpath","rm","rmdir","shred","sync","touch","truncate","vdir","b2sum","base32","base64","cat","cksum","comm","csplit","cut","expand","fmt","fold","head","join","md5sum","nl","numfmt","od","paste","ptx","pr","sha1sum","sha224sum","sha256sum","sha384sum","sha512sum","shuf","sort","split","sum","tac","tail","tr","tsort","unexpand","uniq","wc","arch","basename","chroot","date","dirname","du","echo","env","expr","factor","groups","hostid","id","link","logname","nice","nohup","nproc","pathchk","pinky","printenv","printf","pwd","readlink","runcon","seq","sleep","stat","stdbuf","stty","tee","test","timeout","tty","uname","unlink","uptime","users","who","whoami","yes"]},contains:[l,e.SHEBANG(),c,o,e.HASH_COMMENT_MODE,r,{match:/(\/[a-z._-]+)+/},s,{className:"",begin:/\\"/},{className:"string",begin:/'/,end:/'/},t]}},grmr_c:e=>{const n=e.regex,t=e.COMMENT("//","$",{contains:[{begin:/\\\n/}]}),a="[a-zA-Z_]\\w*::",i="(decltype\\(auto\\)|"+n.optional(a)+"[a-zA-Z_]\\w*"+n.optional("<[^<>]+>")+")",r={className:"type",variants:[{begin:"\\b[a-z\\d_]*_t\\b"},{match:/\batomic_[a-z]{3,6}\b/}]},s={className:"string",variants:[{begin:'(u8?|U|L)?"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE]},{begin:"(u8?|U|L)?'(\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4,8}|[0-7]{3}|\\S)|.)",end:"'",illegal:"."},e.END_SAME_AS_BEGIN({begin:/(?:u8?|U|L)?R"([^()\\ ]{0,16})\(/,end:/\)([^()\\ ]{0,16})"/})]},o={className:"number",variants:[{begin:"\\b(0b[01']+)"},{begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)((ll|LL|l|L)(u|U)?|(u|U)(ll|LL|l|L)?|f|F|b|B)"},{begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)"}],relevance:0},l={className:"meta",begin:/#\s*[a-z]+\b/,end:/$/,keywords:{keyword:"if else elif endif define undef warning error line pragma _Pragma ifdef ifndef include"},contains:[{begin:/\\\n/,relevance:0},e.inherit(s,{className:"string"}),{className:"string",begin:/<.*?>/},t,e.C_BLOCK_COMMENT_MODE]},c={className:"title",begin:n.optional(a)+e.IDENT_RE,relevance:0},d=n.optional(a)+e.IDENT_RE+"\\s*\\(",g={keyword:["asm","auto","break","case","continue","default","do","else","enum","extern","for","fortran","goto","if","inline","register","restrict","return","sizeof","struct","case","typedef","union","volatile","while","_Alignas","_Alignof","_Atomic","_Generic","_Noreturn","_Static_assert","_Thread_local","alignas","alignof","noreturn","static_assert","thread_local","_Pragma"],type:["float","double","signed","unsigned","int","short","long","char","void","_Bool","_Complex","_Imaginary","_Decimal32","_Decimal64","_Decimal128","const","static","complex","bool","imaginary"],literal:"true false NULL",built_in:"std string wstring cin cout cerr clog stdin stdout stderr stringstream istringstream ostringstream auto_ptr deque list queue stack vector map set pair bitset multiset multimap unordered_set unordered_map unordered_multiset unordered_multimap priority_queue make_pair array shared_ptr abort terminate abs acos asin atan2 atan calloc ceil cosh cos exit exp fabs floor fmod fprintf fputs free frexp fscanf future isalnum isalpha iscntrl isdigit isgraph islower isprint ispunct isspace isupper isxdigit tolower toupper labs ldexp log10 log malloc realloc memchr memcmp memcpy memset modf pow printf putchar puts scanf sinh sin snprintf sprintf sqrt sscanf strcat strchr strcmp strcpy strcspn strlen strncat strncmp strncpy strpbrk strrchr strspn strstr tanh tan vfprintf vprintf vsprintf endl initializer_list unique_ptr"},u=[l,r,t,e.C_BLOCK_COMMENT_MODE,o,s],b={variants:[{begin:/=/,end:/;/},{begin:/\(/,end:/\)/},{beginKeywords:"new throw return else",end:/;/}],keywords:g,contains:u.concat([{begin:/\(/,end:/\)/,keywords:g,contains:u.concat(["self"]),relevance:0}]),relevance:0},m={begin:"("+i+"[\\*&\\s]+)+"+d,returnBegin:!0,end:/[{;=]/,excludeEnd:!0,keywords:g,illegal:/[^\w\s\*&:<>.]/,contains:[{begin:"decltype\\(auto\\)",keywords:g,relevance:0},{begin:d,returnBegin:!0,contains:[e.inherit(c,{className:"title.function"})],relevance:0},{relevance:0,match:/,/},{className:"params",begin:/\(/,end:/\)/,keywords:g,relevance:0,contains:[t,e.C_BLOCK_COMMENT_MODE,s,o,r,{begin:/\(/,end:/\)/,keywords:g,relevance:0,contains:["self",t,e.C_BLOCK_COMMENT_MODE,s,o,r]}]},r,t,e.C_BLOCK_COMMENT_MODE,l]};return{name:"C",aliases:["h"],keywords:g,disableAutodetect:!0,illegal:"=]/,contains:[{beginKeywords:"final class struct"},e.TITLE_MODE]}]),exports:{preprocessor:l,strings:s,keywords:g}}},grmr_cpp:e=>{const n=e.regex,t=e.COMMENT("//","$",{contains:[{begin:/\\\n/}]}),a="[a-zA-Z_]\\w*::",i="(?!struct)(decltype\\(auto\\)|"+n.optional(a)+"[a-zA-Z_]\\w*"+n.optional("<[^<>]+>")+")",r={className:"type",begin:"\\b[a-z\\d_]*_t\\b"},s={className:"string",variants:[{begin:'(u8?|U|L)?"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE]},{begin:"(u8?|U|L)?'(\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4,8}|[0-7]{3}|\\S)|.)",end:"'",illegal:"."},e.END_SAME_AS_BEGIN({begin:/(?:u8?|U|L)?R"([^()\\ ]{0,16})\(/,end:/\)([^()\\ ]{0,16})"/})]},o={className:"number",variants:[{begin:"\\b(0b[01']+)"},{begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)((ll|LL|l|L)(u|U)?|(u|U)(ll|LL|l|L)?|f|F|b|B)"},{begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)"}],relevance:0},l={className:"meta",begin:/#\s*[a-z]+\b/,end:/$/,keywords:{keyword:"if else elif endif define undef warning error line pragma _Pragma ifdef ifndef include"},contains:[{begin:/\\\n/,relevance:0},e.inherit(s,{className:"string"}),{className:"string",begin:/<.*?>/},t,e.C_BLOCK_COMMENT_MODE]},c={className:"title",begin:n.optional(a)+e.IDENT_RE,relevance:0},d=n.optional(a)+e.IDENT_RE+"\\s*\\(",g={type:["bool","char","char16_t","char32_t","char8_t","double","float","int","long","short","void","wchar_t","unsigned","signed","const","static"],keyword:["alignas","alignof","and","and_eq","asm","atomic_cancel","atomic_commit","atomic_noexcept","auto","bitand","bitor","break","case","catch","class","co_await","co_return","co_yield","compl","concept","const_cast|10","consteval","constexpr","constinit","continue","decltype","default","delete","do","dynamic_cast|10","else","enum","explicit","export","extern","false","final","for","friend","goto","if","import","inline","module","mutable","namespace","new","noexcept","not","not_eq","nullptr","operator","or","or_eq","override","private","protected","public","reflexpr","register","reinterpret_cast|10","requires","return","sizeof","static_assert","static_cast|10","struct","case","synchronized","template","this","thread_local","throw","transaction_safe","transaction_safe_dynamic","true","try","typedef","typeid","typename","union","using","virtual","volatile","while","xor","xor_eq"],literal:["NULL","false","nullopt","nullptr","true"],built_in:["_Pragma"],_type_hints:["any","auto_ptr","barrier","binary_semaphore","bitset","complex","condition_variable","condition_variable_any","counting_semaphore","deque","false_type","future","imaginary","initializer_list","istringstream","jthread","latch","lock_guard","multimap","multiset","mutex","optional","ostringstream","packaged_task","pair","promise","priority_queue","queue","recursive_mutex","recursive_timed_mutex","scoped_lock","set","shared_future","shared_lock","shared_mutex","shared_timed_mutex","shared_ptr","stack","string_view","stringstream","timed_mutex","thread","true_type","tuple","unique_lock","unique_ptr","unordered_map","unordered_multimap","unordered_multiset","unordered_set","variant","vector","weak_ptr","wstring","wstring_view"]},u={className:"function.dispatch",relevance:0,keywords:{_hint:["abort","abs","acos","apply","as_const","asin","atan","atan2","calloc","ceil","cerr","cin","clog","cos","cosh","cout","declval","endl","exchange","exit","exp","fabs","floor","fmod","forward","fprintf","fputs","free","frexp","fscanf","future","invoke","isalnum","isalpha","iscntrl","isdigit","isgraph","islower","isprint","ispunct","isspace","isupper","isxdigit","labs","launder","ldexp","log","log10","make_pair","make_shared","make_shared_for_overwrite","make_tuple","make_unique","malloc","memchr","memcmp","memcpy","memset","modf","move","pow","printf","putchar","puts","realloc","scanf","sin","sinh","snprintf","sprintf","sqrt","sscanf","std","stderr","stdin","stdout","strcat","strchr","strcmp","strcpy","strcspn","strlen","strncat","strncmp","strncpy","strpbrk","strrchr","strspn","strstr","swap","tan","tanh","terminate","to_underlying","tolower","toupper","vfprintf","visit","vprintf","vsprintf"]},begin:n.concat(/\b/,/(?!decltype)/,/(?!if)/,/(?!for)/,/(?!case)/,/(?!while)/,e.IDENT_RE,n.lookahead(/(<[^<>]+>|)\s*\(/))},b=[u,l,r,t,e.C_BLOCK_COMMENT_MODE,o,s],m={variants:[{begin:/=/,end:/;/},{begin:/\(/,end:/\)/},{beginKeywords:"new throw return else",end:/;/}],keywords:g,contains:b.concat([{begin:/\(/,end:/\)/,keywords:g,contains:b.concat(["self"]),relevance:0}]),relevance:0},p={className:"function",begin:"("+i+"[\\*&\\s]+)+"+d,returnBegin:!0,end:/[{;=]/,excludeEnd:!0,keywords:g,illegal:/[^\w\s\*&:<>.]/,contains:[{begin:"decltype\\(auto\\)",keywords:g,relevance:0},{begin:d,returnBegin:!0,contains:[c],relevance:0},{begin:/::/,relevance:0},{begin:/:/,endsWithParent:!0,contains:[s,o]},{relevance:0,match:/,/},{className:"params",begin:/\(/,end:/\)/,keywords:g,relevance:0,contains:[t,e.C_BLOCK_COMMENT_MODE,s,o,r,{begin:/\(/,end:/\)/,keywords:g,relevance:0,contains:["self",t,e.C_BLOCK_COMMENT_MODE,s,o,r]}]},r,t,e.C_BLOCK_COMMENT_MODE,l]};return{name:"C++",aliases:["cc","c++","h++","hpp","hh","hxx","cxx"],keywords:g,illegal:"",keywords:g,contains:["self",r]},{begin:e.IDENT_RE+"::",keywords:g},{match:[/\b(?:enum(?:\s+(?:class|struct))?|class|struct|union)/,/\s+/,/\w+/],className:{1:"keyword",3:"title.class"}}])}},grmr_csharp:e=>{const n={keyword:["abstract","as","base","break","case","catch","class","const","continue","do","else","event","explicit","extern","finally","fixed","for","foreach","goto","if","implicit","in","interface","internal","is","lock","namespace","new","operator","out","override","params","private","protected","public","readonly","record","ref","return","sealed","sizeof","stackalloc","static","struct","case","this","throw","try","typeof","unchecked","unsafe","using","virtual","void","volatile","while"].concat(["add","alias","and","ascending","async","await","by","descending","equals","from","get","global","group","init","into","join","let","nameof","not","notnull","on","or","orderby","partial","remove","select","set","unmanaged","value|0","var","when","where","with","yield"]),built_in:["bool","byte","char","decimal","delegate","double","dynamic","enum","float","int","long","nint","nuint","object","sbyte","short","string","ulong","uint","ushort"],literal:["default","false","null","true"]},t=e.inherit(e.TITLE_MODE,{begin:"[a-zA-Z](\\.?\\w)*"}),a={className:"number",variants:[{begin:"\\b(0b[01']+)"},{begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)(u|U|l|L|ul|UL|f|F|b|B)"},{begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)"}],relevance:0},i={className:"string",begin:'@"',end:'"',contains:[{begin:'""'}]},r=e.inherit(i,{illegal:/\n/}),s={className:"subst",begin:/\{/,end:/\}/,keywords:n},o=e.inherit(s,{illegal:/\n/}),l={className:"string",begin:/\$"/,end:'"',illegal:/\n/,contains:[{begin:/\{\{/},{begin:/\}\}/},e.BACKSLASH_ESCAPE,o]},c={className:"string",begin:/\$@"/,end:'"',contains:[{begin:/\{\{/},{begin:/\}\}/},{begin:'""'},s]},d=e.inherit(c,{illegal:/\n/,contains:[{begin:/\{\{/},{begin:/\}\}/},{begin:'""'},o]});s.contains=[c,l,i,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,a,e.C_BLOCK_COMMENT_MODE],o.contains=[d,l,r,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,a,e.inherit(e.C_BLOCK_COMMENT_MODE,{illegal:/\n/})];const g={variants:[c,l,i,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE]},u={begin:"<",end:">",contains:[{beginKeywords:"in out"},t]},b=e.IDENT_RE+"(<"+e.IDENT_RE+"(\\s*,\\s*"+e.IDENT_RE+")*>)?(\\[\\])?",m={begin:"@"+e.IDENT_RE,relevance:0};return{name:"C#",aliases:["cs","c#"],keywords:n,illegal:/::/,contains:[e.COMMENT("///","$",{returnBegin:!0,contains:[{className:"doctag",variants:[{begin:"///",relevance:0},{begin:"\x3c!--|--\x3e"},{begin:""}]}]}),e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{className:"meta",begin:"#",end:"$",keywords:{keyword:"if else elif endif define undef warning error line region endregion pragma checksum"}},g,a,{beginKeywords:"class interface",relevance:0,end:/[{;=]/,illegal:/[^\s:,]/,contains:[{beginKeywords:"where class"},t,u,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{beginKeywords:"namespace",relevance:0,end:/[{;=]/,illegal:/[^\s:]/,contains:[t,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{beginKeywords:"record",relevance:0,end:/[{;=]/,illegal:/[^\s:]/,contains:[t,u,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{className:"meta",begin:"^\\s*\\[(?=[\\w])",excludeBegin:!0,end:"\\]",excludeEnd:!0,contains:[{className:"string",begin:/"/,end:/"/}]},{beginKeywords:"new return throw await else",relevance:0},{className:"function",begin:"("+b+"\\s+)+"+e.IDENT_RE+"\\s*(<[^=]+>\\s*)?\\(",returnBegin:!0,end:/\s*[{;=]/,excludeEnd:!0,keywords:n,contains:[{beginKeywords:"public private protected static internal protected abstract async extern override unsafe virtual new sealed partial",relevance:0},{begin:e.IDENT_RE+"\\s*(<[^=]+>\\s*)?\\(",returnBegin:!0,contains:[e.TITLE_MODE,u],relevance:0},{match:/\(\)/},{className:"params",begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:n,relevance:0,contains:[g,a,e.C_BLOCK_COMMENT_MODE]},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},m]}},grmr_css:e=>{const n=e.regex,t=te(e),a=[e.APOS_STRING_MODE,e.QUOTE_STRING_MODE];return{name:"CSS",case_insensitive:!0,illegal:/[=|'\$]/,keywords:{keyframePosition:"from to"},classNameAliases:{keyframePosition:"selector-tag"},contains:[t.BLOCK_COMMENT,{begin:/-(webkit|moz|ms|o)-(?=[a-z])/},t.CSS_NUMBER_MODE,{className:"selector-id",begin:/#[A-Za-z0-9_-]+/,relevance:0},{className:"selector-class",begin:"\\.[a-zA-Z-][a-zA-Z0-9_-]*",relevance:0},t.ATTRIBUTE_SELECTOR_MODE,{className:"selector-pseudo",variants:[{begin:":("+re.join("|")+")"},{begin:":(:)?("+se.join("|")+")"}]},t.CSS_VARIABLE,{className:"attribute",begin:"\\b("+oe.join("|")+")\\b"},{begin:/:/,end:/[;}{]/,contains:[t.BLOCK_COMMENT,t.HEXCOLOR,t.IMPORTANT,t.CSS_NUMBER_MODE,...a,{begin:/(url|data-uri)\(/,end:/\)/,relevance:0,keywords:{built_in:"url data-uri"},contains:[{className:"string",begin:/[^)]/,endsWithParent:!0,excludeEnd:!0}]},t.FUNCTION_DISPATCH]},{begin:n.lookahead(/@/),end:"[{;]",relevance:0,illegal:/:/,contains:[{className:"keyword",begin:/@-?\w[\w]*(-\w+)*/},{begin:/\s/,endsWithParent:!0,excludeEnd:!0,relevance:0,keywords:{$pattern:/[a-z-]+/,keyword:"and or not only",attribute:ie.join(" ")},contains:[{begin:/[a-z-]+(?=:)/,className:"attribute"},...a,t.CSS_NUMBER_MODE]}]},{className:"selector-tag",begin:"\\b("+ae.join("|")+")\\b"}]}},grmr_diff:e=>{const n=e.regex;return{name:"Diff",aliases:["patch"],contains:[{className:"meta",relevance:10,match:n.either(/^@@ +-\d+,\d+ +\+\d+,\d+ +@@/,/^\*\*\* +\d+,\d+ +\*\*\*\*$/,/^--- +\d+,\d+ +----$/)},{className:"comment",variants:[{begin:n.either(/Index: /,/^index/,/={3,}/,/^-{3}/,/^\*{3} /,/^\+{3}/,/^diff --git/),end:/$/},{match:/^\*{15}$/}]},{className:"addition",begin:/^\+/,end:/$/},{className:"deletion",begin:/^-/,end:/$/},{className:"addition",begin:/^!/,end:/$/}]}},grmr_go:e=>{const n={keyword:["break","case","chan","const","continue","default","defer","else","fallthrough","for","func","go","goto","if","import","interface","map","package","range","return","select","struct","case","type","var"],type:["bool","byte","complex64","complex128","error","float32","float64","int8","int16","int32","int64","string","uint8","uint16","uint32","uint64","int","uint","uintptr","rune"],literal:["true","false","iota","nil"],built_in:["append","cap","close","complex","copy","imag","len","make","new","panic","print","println","real","recover","delete"]};return{name:"Go",aliases:["golang"],keywords:n,illegal:"{const n=e.regex,t={className:"number",relevance:0,variants:[{begin:/([+-]+)?[\d]+_[\d_]+/},{begin:e.NUMBER_RE}]},a=e.COMMENT();a.variants=[{begin:/;/,end:/$/},{begin:/#/,end:/$/}];const i={className:"variable",variants:[{begin:/\$[\w\d"][\w\d_]*/},{begin:/\$\{(.*?)\}/}]},r={className:"literal",begin:/\bon|off|true|false|yes|no\b/},s={className:"string",contains:[e.BACKSLASH_ESCAPE],variants:[{begin:"'''",end:"'''",relevance:10},{begin:'"""',end:'"""',relevance:10},{begin:'"',end:'"'},{begin:"'",end:"'"}]},o={begin:/\[/,end:/\]/,contains:[a,r,i,s,t,"self"],relevance:0},l=n.either(/[A-Za-z0-9_-]+/,/"(\\"|[^"])*"/,/'[^']*'/);return{name:"TOML, also INI",aliases:["toml"],case_insensitive:!0,illegal:/\S/,contains:[a,{className:"section",begin:/\[+/,end:/\]+/},{begin:n.concat(l,"(\\s*\\.\\s*",l,")*",n.lookahead(/\s*=\s*[^#\s]/)),className:"attr",starts:{end:/$/,contains:[a,o,r,i,s,t]}}]}},grmr_java:e=>{const n=e.regex,t="[À-ʸa-zA-Z_$][À-ʸa-zA-Z_$0-9]*",a=t+ue("(?:<"+t+"~~~(?:\\s*,\\s*"+t+"~~~)*>)?",/~~~/g,2),i={keyword:["synchronized","abstract","private","var","static","if","const ","for","while","strictfp","finally","protected","import","native","final","void","enum","else","break","transient","catch","instanceof","volatile","case","assert","package","default","public","try","case","continue","throws","protected","public","private","module","requires","exports","do","sealed"],literal:["false","true","null"],type:["char","boolean","long","float","int","byte","short","double"],built_in:["super","this"]},r={className:"meta",begin:"@"+t,contains:[{begin:/\(/,end:/\)/,contains:["self"]}]},s={className:"params",begin:/\(/,end:/\)/,keywords:i,relevance:0,contains:[e.C_BLOCK_COMMENT_MODE],endsParent:!0};return{name:"Java",aliases:["jsp"],keywords:i,illegal:/<\/|#/,contains:[e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{begin:/\w+@/,relevance:0},{className:"doctag",begin:"@[A-Za-z]+"}]}),{begin:/import java\.[a-z]+\./,keywords:"import",relevance:2},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{begin:/"""/,end:/"""/,className:"string",contains:[e.BACKSLASH_ESCAPE]},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,{match:[/\b(?:class|interface|enum|extends|implements|new)/,/\s+/,t],className:{1:"keyword",3:"title.class"}},{match:/non-sealed/,scope:"keyword"},{begin:[n.concat(/(?!else)/,t),/\s+/,t,/\s+/,/=/],className:{1:"type",3:"variable",5:"operator"}},{begin:[/record/,/\s+/,t],className:{1:"keyword",3:"title.class"},contains:[s,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{beginKeywords:"new throw return else",relevance:0},{begin:["(?:"+a+"\\s+)",e.UNDERSCORE_IDENT_RE,/\s*(?=\()/],className:{2:"title.function"},keywords:i,contains:[{className:"params",begin:/\(/,end:/\)/,keywords:i,relevance:0,contains:[r,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,ge,e.C_BLOCK_COMMENT_MODE]},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},ge,r]}},grmr_javascript:we,grmr_json:e=>({name:"JSON",contains:[{className:"attr",begin:/"(\\.|[^\\"\r\n])*"(?=\s*:)/,relevance:1.01},{match:/[{}[\],:]/,className:"punctuation",relevance:0},e.QUOTE_STRING_MODE,{beginKeywords:"true false null"},e.C_NUMBER_MODE,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE],illegal:"\\S"}),grmr_kotlin:e=>{const n={keyword:"abstract as val var vararg get set class object open private protected public noinline crossinline dynamic final enum if else do while for when throw try catch finally import package is in fun override companion reified inline lateinit init interface annotation data sealed internal infix operator out by constructor super tailrec where const inner suspend typealias external expect actual",built_in:"Byte Short Char Int Long Boolean Float Double Void Unit Nothing",literal:"true false null"},t={className:"symbol",begin:e.UNDERSCORE_IDENT_RE+"@"},a={className:"subst",begin:/\$\{/,end:/\}/,contains:[e.C_NUMBER_MODE]},i={className:"variable",begin:"\\$"+e.UNDERSCORE_IDENT_RE},r={className:"string",variants:[{begin:'"""',end:'"""(?=[^"])',contains:[i,a]},{begin:"'",end:"'",illegal:/\n/,contains:[e.BACKSLASH_ESCAPE]},{begin:'"',end:'"',illegal:/\n/,contains:[e.BACKSLASH_ESCAPE,i,a]}]};a.contains.push(r);const s={className:"meta",begin:"@(?:file|property|field|get|set|receiver|param|setparam|delegate)\\s*:(?:\\s*"+e.UNDERSCORE_IDENT_RE+")?"},o={className:"meta",begin:"@"+e.UNDERSCORE_IDENT_RE,contains:[{begin:/\(/,end:/\)/,contains:[e.inherit(r,{className:"string"})]}]},l=ge,c=e.COMMENT("/\\*","\\*/",{contains:[e.C_BLOCK_COMMENT_MODE]}),d={variants:[{className:"type",begin:e.UNDERSCORE_IDENT_RE},{begin:/\(/,end:/\)/,contains:[]}]},g=d;return g.variants[1].contains=[d],d.variants[1].contains=[g],{name:"Kotlin",aliases:["kt","kts"],keywords:n,contains:[e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{className:"doctag",begin:"@[A-Za-z]+"}]}),e.C_LINE_COMMENT_MODE,c,{className:"keyword",begin:/\b(break|continue|return|this)\b/,starts:{contains:[{className:"symbol",begin:/@\w+/}]}},t,s,o,{className:"function",beginKeywords:"fun",end:"[(]|$",returnBegin:!0,excludeEnd:!0,keywords:n,relevance:5,contains:[{begin:e.UNDERSCORE_IDENT_RE+"\\s*\\(",returnBegin:!0,relevance:0,contains:[e.UNDERSCORE_TITLE_MODE]},{className:"type",begin://,keywords:"reified",relevance:0},{className:"params",begin:/\(/,end:/\)/,endsParent:!0,keywords:n,relevance:0,contains:[{begin:/:/,end:/[=,\/]/,endsWithParent:!0,contains:[d,e.C_LINE_COMMENT_MODE,c],relevance:0},e.C_LINE_COMMENT_MODE,c,s,o,r,e.C_NUMBER_MODE]},c]},{className:"class",beginKeywords:"class interface trait",end:/[:\{(]|$/,excludeEnd:!0,illegal:"extends implements",contains:[{beginKeywords:"public protected internal private constructor"},e.UNDERSCORE_TITLE_MODE,{className:"type",begin://,excludeBegin:!0,excludeEnd:!0,relevance:0},{className:"type",begin:/[,:]\s*/,end:/[<\(,]|$/,excludeBegin:!0,returnEnd:!0},s,o]},r,{className:"meta",begin:"^#!/usr/bin/env",end:"$",illegal:"\n"},l]}},grmr_less:e=>{const n=te(e),t=le,a="([\\w-]+|@\\{[\\w-]+\\})",i=[],r=[],s=e=>({className:"string",begin:"~?"+e+".*?"+e}),o=(e,n,t)=>({className:e,begin:n,relevance:t}),l={$pattern:/[a-z-]+/,keyword:"and or not only",attribute:ie.join(" ")},c={begin:"\\(",end:"\\)",contains:r,keywords:l,relevance:0};r.push(e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,s("'"),s('"'),n.CSS_NUMBER_MODE,{begin:"(url|data-uri)\\(",starts:{className:"string",end:"[\\)\\n]",excludeEnd:!0}},n.HEXCOLOR,c,o("variable","@@?[\\w-]+",10),o("variable","@\\{[\\w-]+\\}"),o("built_in","~?`[^`]*?`"),{className:"attribute",begin:"[\\w-]+\\s*:",end:":",returnBegin:!0,excludeEnd:!0},n.IMPORTANT);const d=r.concat({begin:/\{/,end:/\}/,contains:i}),g={beginKeywords:"when",endsWithParent:!0,contains:[{beginKeywords:"and not"}].concat(r)},u={begin:a+"\\s*:",returnBegin:!0,end:/[;}]/,relevance:0,contains:[{begin:/-(webkit|moz|ms|o)-/},n.CSS_VARIABLE,{className:"attribute",begin:"\\b("+oe.join("|")+")\\b",end:/(?=:)/,starts:{endsWithParent:!0,illegal:"[<=$]",relevance:0,contains:r}}]},b={className:"keyword",begin:"@(import|media|charset|font-face|(-[a-z]+-)?keyframes|supports|document|namespace|page|viewport|host)\\b",starts:{end:"[;{}]",keywords:l,returnEnd:!0,contains:r,relevance:0}},m={className:"variable",variants:[{begin:"@[\\w-]+\\s*:",relevance:15},{begin:"@[\\w-]+"}],starts:{end:"[;}]",returnEnd:!0,contains:d}},p={variants:[{begin:"[\\.#:&\\[>]",end:"[;{}]"},{begin:a,end:/\{/}],returnBegin:!0,returnEnd:!0,illegal:"[<='$\"]",relevance:0,contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,g,o("keyword","all\\b"),o("variable","@\\{[\\w-]+\\}"),{begin:"\\b("+ae.join("|")+")\\b",className:"selector-tag"},n.CSS_NUMBER_MODE,o("selector-tag",a,0),o("selector-id","#"+a),o("selector-class","\\."+a,0),o("selector-tag","&",0),n.ATTRIBUTE_SELECTOR_MODE,{className:"selector-pseudo",begin:":("+re.join("|")+")"},{className:"selector-pseudo",begin:":(:)?("+se.join("|")+")"},{begin:/\(/,end:/\)/,relevance:0,contains:d},{begin:"!important"},n.FUNCTION_DISPATCH]},_={begin:`[\\w-]+:(:)?(${t.join("|")})`,returnBegin:!0,contains:[p]};return i.push(e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,b,m,_,u,p),{name:"Less",case_insensitive:!0,illegal:"[=>'/<($\"]",contains:i}},grmr_lua:e=>{const n="\\[=*\\[",t="\\]=*\\]",a={begin:n,end:t,contains:["self"]},i=[e.COMMENT("--(?!\\[=*\\[)","$"),e.COMMENT("--\\[=*\\[",t,{contains:[a],relevance:10})];return{name:"Lua",keywords:{$pattern:e.UNDERSCORE_IDENT_RE,literal:"true false nil",keyword:"and break do else elseif end for goto if in local not or repeat return then until while",built_in:"_G _ENV _VERSION __index __newindex __mode __call __metatable __tostring __len __gc __add __sub __mul __div __mod __pow __concat __unm __eq __lt __le assert collectgarbage dofile error getfenv getmetatable ipairs load loadfile loadstring module next pairs pcall print rawequal rawget rawset require select setfenv setmetatable tonumber tostring type unpack xpcall arg self coroutine resume yield status wrap create running debug getupvalue debug sethook getmetatable gethook setmetatable setlocal traceback setfenv getinfo setupvalue getlocal getregistry getfenv io lines write close flush open output type read stderr stdin input stdout popen tmpfile math log max acos huge ldexp pi cos tanh pow deg tan cosh sinh random randomseed frexp ceil floor rad abs sqrt modf asin min mod fmod log10 atan2 exp sin atan os exit setlocale date getenv difftime remove time clock tmpname rename execute package preload loadlib loaded loaders cpath config path seeall string sub upper len gfind rep find match char dump gmatch reverse byte format gsub lower table setn insert getn foreachi maxn foreach concat sort remove"},contains:i.concat([{className:"function",beginKeywords:"function",end:"\\)",contains:[e.inherit(e.TITLE_MODE,{begin:"([_a-zA-Z]\\w*\\.)*([_a-zA-Z]\\w*:)?[_a-zA-Z]\\w*"}),{className:"params",begin:"\\(",endsWithParent:!0,contains:i}].concat(i)},e.C_NUMBER_MODE,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,{className:"string",begin:n,end:t,contains:[a],relevance:5}])}},grmr_makefile:e=>{const n={className:"variable",variants:[{begin:"\\$\\("+e.UNDERSCORE_IDENT_RE+"\\)",contains:[e.BACKSLASH_ESCAPE]},{begin:/\$[@%{const n=e.regex,t=n.concat(/[A-Z_]/,n.optional(/[A-Z0-9_.-]*:/),/[A-Z0-9_.-]*/),a={className:"symbol",begin:/&[a-z]+;|&#[0-9]+;|&#x[a-f0-9]+;/},i={begin:/\s/,contains:[{className:"keyword",begin:/#?[a-z_][a-z1-9_-]+/,illegal:/\n/}]},r=e.inherit(i,{begin:/\(/,end:/\)/}),s=e.inherit(e.APOS_STRING_MODE,{className:"string"}),o=e.inherit(e.QUOTE_STRING_MODE,{className:"string"}),l={endsWithParent:!0,illegal:/`]+/}]}]}]};return{name:"HTML, XML",aliases:["html","xhtml","rss","atom","xjb","xsd","xsl","plist","wsf","svg"],case_insensitive:!0,contains:[{className:"meta",begin://,relevance:10,contains:[i,o,s,r,{begin:/\[/,end:/\]/,contains:[{className:"meta",begin://,contains:[i,r,o,s]}]}]},e.COMMENT(//,{relevance:10}),{begin://,relevance:10},a,{className:"meta",end:/\?>/,variants:[{begin:/<\?xml/,relevance:10,contains:[o]},{begin:/<\?[a-z][a-z0-9]+/}]},{className:"tag",begin:/)/,end:/>/,keywords:{name:"style"},contains:[l],starts:{end:/<\/style>/,returnEnd:!0,subLanguage:["css","xml"]}},{className:"tag",begin:/)/,end:/>/,keywords:{name:"script"},contains:[l],starts:{end:/<\/script>/,returnEnd:!0,subLanguage:["javascript","handlebars","xml"]}},{className:"tag",begin:/<>|<\/>/},{className:"tag",begin:n.concat(//,/>/,/\s/)))),end:/\/?>/,contains:[{className:"name",begin:t,relevance:0,starts:l}]},{className:"tag",begin:n.concat(/<\//,n.lookahead(n.concat(t,/>/))),contains:[{className:"name",begin:t,relevance:0},{begin:/>/,relevance:0,endsParent:!0}]}]}},grmr_markdown:e=>{const n={begin:/<\/?[A-Za-z_]/,end:">",subLanguage:"xml",relevance:0},t={variants:[{begin:/\[.+?\]\[.*?\]/,relevance:0},{begin:/\[.+?\]\(((data|javascript|mailto):|(?:http|ftp)s?:\/\/).*?\)/,relevance:2},{begin:e.regex.concat(/\[.+?\]\(/,/[A-Za-z][A-Za-z0-9+.-]*/,/:\/\/.*?\)/),relevance:2},{begin:/\[.+?\]\([./?&#].*?\)/,relevance:1},{begin:/\[.*?\]\(.*?\)/,relevance:0}],returnBegin:!0,contains:[{match:/\[(?=\])/},{className:"string",relevance:0,begin:"\\[",end:"\\]",excludeBegin:!0,returnEnd:!0},{className:"link",relevance:0,begin:"\\]\\(",end:"\\)",excludeBegin:!0,excludeEnd:!0},{className:"symbol",relevance:0,begin:"\\]\\[",end:"\\]",excludeBegin:!0,excludeEnd:!0}]},a={className:"strong",contains:[],variants:[{begin:/_{2}/,end:/_{2}/},{begin:/\*{2}/,end:/\*{2}/}]},i={className:"emphasis",contains:[],variants:[{begin:/\*(?!\*)/,end:/\*/},{begin:/_(?!_)/,end:/_/,relevance:0}]},r=e.inherit(a,{contains:[]}),s=e.inherit(i,{contains:[]});a.contains.push(s),i.contains.push(r);let o=[n,t];return[a,i,r,s].forEach(e=>{e.contains=e.contains.concat(o)}),o=o.concat(a,i),{name:"Markdown",aliases:["md","mkdown","mkd"],contains:[{className:"section",variants:[{begin:"^#{1,6}",end:"$",contains:o},{begin:"(?=^.+?\\n[=-]{2,}$)",contains:[{begin:"^[=-]*$"},{begin:"^",end:"\\n",contains:o}]}]},n,{className:"bullet",begin:"^[ \t]*([*+-]|(\\d+\\.))(?=\\s+)",end:"\\s+",excludeEnd:!0},a,i,{className:"quote",begin:"^>\\s+",contains:o,end:"$"},{className:"code",variants:[{begin:"(`{3,})[^`](.|\\n)*?\\1`*[ ]*"},{begin:"(~{3,})[^~](.|\\n)*?\\1~*[ ]*"},{begin:"```",end:"```+[ ]*$"},{begin:"~~~",end:"~~~+[ ]*$"},{begin:"`.+?`"},{begin:"(?=^( {4}|\\t))",contains:[{begin:"^( {4}|\\t)",end:"(\\n)$"}],relevance:0}]},{begin:"^[-\\*]{3,}",end:"$"},t,{begin:/^\[[^\n]+\]:/,returnBegin:!0,contains:[{className:"symbol",begin:/\[/,end:/\]/,excludeBegin:!0,excludeEnd:!0},{className:"link",begin:/:\s*/,end:/$/,excludeBegin:!0}]}]}},grmr_objectivec:e=>{const n=/[a-zA-Z@][a-zA-Z0-9_]*/,t={$pattern:n,keyword:["@interface","@class","@protocol","@implementation"]};return{name:"Objective-C",aliases:["mm","objc","obj-c","obj-c++","objective-c++"],keywords:{"variable.language":["this","super"],$pattern:n,keyword:["while","export","sizeof","typedef","const","struct","for","union","volatile","static","mutable","if","do","return","goto","enum","else","break","extern","asm","case","default","register","explicit","typename","case","continue","inline","readonly","assign","readwrite","self","@synchronized","id","typeof","nonatomic","IBOutlet","IBAction","strong","weak","copy","in","out","inout","bycopy","byref","oneway","__strong","__weak","__block","__autoreleasing","@private","@protected","@public","@try","@property","@end","@throw","@catch","@finally","@autoreleasepool","@synthesize","@dynamic","@selector","@optional","@required","@encode","@package","@import","@defs","@compatibility_alias","__bridge","__bridge_transfer","__bridge_retained","__bridge_retain","__covariant","__contravariant","__kindof","_Nonnull","_Nullable","_Null_unspecified","__FUNCTION__","__PRETTY_FUNCTION__","__attribute__","getter","setter","retain","unsafe_unretained","nonnull","nullable","null_unspecified","null_resettable","class","instancetype","NS_DESIGNATED_INITIALIZER","NS_UNAVAILABLE","NS_REQUIRES_SUPER","NS_RETURNS_INNER_POINTER","NS_INLINE","NS_AVAILABLE","NS_DEPRECATED","NS_ENUM","NS_OPTIONS","NS_SWIFT_UNAVAILABLE","NS_ASSUME_NONNULL_BEGIN","NS_ASSUME_NONNULL_END","NS_REFINED_FOR_SWIFT","NS_SWIFT_NAME","NS_SWIFT_NOTHROW","NS_DURING","NS_HANDLER","NS_ENDHANDLER","NS_VALUERETURN","NS_VOIDRETURN"],literal:["false","true","FALSE","TRUE","nil","YES","NO","NULL"],built_in:["dispatch_once_t","dispatch_queue_t","dispatch_sync","dispatch_async","dispatch_once"],type:["int","float","char","unsigned","signed","short","long","double","wchar_t","unichar","void","bool","BOOL","id|0","_Bool"]},illegal:"/,end:/$/,illegal:"\\n"},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{className:"class",begin:"("+t.keyword.join("|")+")\\b",end:/(\{|$)/,excludeEnd:!0,keywords:t,contains:[e.UNDERSCORE_TITLE_MODE]},{begin:"\\."+e.UNDERSCORE_IDENT_RE,relevance:0}]}},grmr_perl:e=>{const n=e.regex,t=/[dualxmsipngr]{0,12}/,a={$pattern:/[\w.]+/,keyword:"abs accept alarm and atan2 bind binmode bless break caller chdir chmod chomp chop chown chr chroot close closedir connect continue cos crypt dbmclose dbmopen defined delete die do dump each else elsif endgrent endhostent endnetent endprotoent endpwent endservent eof eval exec exists exit exp fcntl fileno flock for foreach fork format formline getc getgrent getgrgid getgrnam gethostbyaddr gethostbyname gethostent getlogin getnetbyaddr getnetbyname getnetent getpeername getpgrp getpriority getprotobyname getprotobynumber getprotoent getpwent getpwnam getpwuid getservbyname getservbyport getservent getsockname getsockopt given glob gmtime goto grep gt hex if index int ioctl join keys kill last lc lcfirst length link listen local localtime log lstat lt ma map mkdir msgctl msgget msgrcv msgsnd my ne next no not oct open opendir or ord our pack package pipe pop pos print printf prototype push q|0 qq quotemeta qw qx rand read readdir readline readlink readpipe recv redo ref rename require reset return reverse rewinddir rindex rmdir say scalar seek seekdir select semctl semget semop send setgrent sethostent setnetent setpgrp setpriority setprotoent setpwent setservent setsockopt shift shmctl shmget shmread shmwrite shutdown sin sleep socket socketpair sort splice split sprintf sqrt srand stat state study sub substr symlink syscall sysopen sysread sysseek system syswrite tell telldir tie tied time times tr truncate uc ucfirst umask undef unless unlink unpack unshift untie until use utime values vec wait waitpid wantarray warn when while write x|0 xor y|0"},i={className:"subst",begin:"[$@]\\{",end:"\\}",keywords:a},r={begin:/->\{/,end:/\}/},s={variants:[{begin:/\$\d/},{begin:n.concat(/[$%@](\^\w\b|#\w+(::\w+)*|\{\w+\}|\w+(::\w*)*)/,"(?![A-Za-z])(?![@$%])")},{begin:/[$%@][^\s\w{]/,relevance:0}]},o=[e.BACKSLASH_ESCAPE,i,s],l=[/!/,/\//,/\|/,/\?/,/'/,/"/,/#/],c=(e,a,i="\\1")=>{const r="\\1"===i?i:n.concat(i,a);return n.concat(n.concat("(?:",e,")"),a,/(?:\\.|[^\\\/])*?/,r,/(?:\\.|[^\\\/])*?/,i,t)},d=(e,a,i)=>n.concat(n.concat("(?:",e,")"),a,/(?:\\.|[^\\\/])*?/,i,t),g=[s,e.HASH_COMMENT_MODE,e.COMMENT(/^=\w/,/=cut/,{endsWithParent:!0}),r,{className:"string",contains:o,variants:[{begin:"q[qwxr]?\\s*\\(",end:"\\)",relevance:5},{begin:"q[qwxr]?\\s*\\[",end:"\\]",relevance:5},{begin:"q[qwxr]?\\s*\\{",end:"\\}",relevance:5},{begin:"q[qwxr]?\\s*\\|",end:"\\|",relevance:5},{begin:"q[qwxr]?\\s*<",end:">",relevance:5},{begin:"qw\\s+q",end:"q",relevance:5},{begin:"'",end:"'",contains:[e.BACKSLASH_ESCAPE]},{begin:'"',end:'"'},{begin:"`",end:"`",contains:[e.BACKSLASH_ESCAPE]},{begin:/\{\w+\}/,relevance:0},{begin:"-?\\w+\\s*=>",relevance:0}]},{className:"number",begin:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b",relevance:0},{begin:"(\\/\\/|"+e.RE_STARTERS_RE+"|\\b(split|return|print|reverse|grep)\\b)\\s*",keywords:"split return print reverse grep",relevance:0,contains:[e.HASH_COMMENT_MODE,{className:"regexp",variants:[{begin:c("s|tr|y",n.either(...l,{capture:!0}))},{begin:c("s|tr|y","\\(","\\)")},{begin:c("s|tr|y","\\[","\\]")},{begin:c("s|tr|y","\\{","\\}")}],relevance:2},{className:"regexp",variants:[{begin:/(m|qr)\/\//,relevance:0},{begin:d("(?:m|qr)?",/\//,/\//)},{begin:d("m|qr",n.either(...l,{capture:!0}),/\1/)},{begin:d("m|qr",/\(/,/\)/)},{begin:d("m|qr",/\[/,/\]/)},{begin:d("m|qr",/\{/,/\}/)}]}]},{className:"function",beginKeywords:"sub",end:"(\\s*\\(.*?\\))?[;{]",excludeEnd:!0,relevance:5,contains:[e.TITLE_MODE]},{begin:"-\\w\\b",relevance:0},{begin:"^__DATA__$",end:"^__END__$",subLanguage:"mojolicious",contains:[{begin:"^@@.*",end:"$",className:"comment"}]}];return i.contains=g,r.contains=g,{name:"Perl",aliases:["pl","pm"],keywords:a,contains:g}},grmr_php:e=>{const n=e.regex,t=/(?![A-Za-z0-9])(?![$])/,a=n.concat(/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/,t),i=n.concat(/(\\?[A-Z][a-z0-9_\x7f-\xff]+|\\?[A-Z]+(?=[A-Z][a-z0-9_\x7f-\xff])){1,}/,t),r={scope:"variable",match:"\\$+"+a},s={scope:"subst",variants:[{begin:/\$\w+/},{begin:/\{\$/,end:/\}/}]},o=e.inherit(e.APOS_STRING_MODE,{illegal:null}),l="[ \t\n]",c={scope:"string",variants:[e.inherit(e.QUOTE_STRING_MODE,{illegal:null,contains:e.QUOTE_STRING_MODE.contains.concat(s)}),o,e.END_SAME_AS_BEGIN({begin:/<<<[ \t]*(\w+)\n/,end:/[ \t]*(\w+)\b/,contains:e.QUOTE_STRING_MODE.contains.concat(s)})]},d={scope:"number",variants:[{begin:"\\b0[bB][01]+(?:_[01]+)*\\b"},{begin:"\\b0[oO][0-7]+(?:_[0-7]+)*\\b"},{begin:"\\b0[xX][\\da-fA-F]+(?:_[\\da-fA-F]+)*\\b"},{begin:"(?:\\b\\d+(?:_\\d+)*(\\.(?:\\d+(?:_\\d+)*))?|\\B\\.\\d+)(?:[eE][+-]?\\d+)?"}],relevance:0},g=["false","null","true"],u=["__CLASS__","__DIR__","__FILE__","__FUNCTION__","__COMPILER_HALT_OFFSET__","__LINE__","__METHOD__","__NAMESPACE__","__TRAIT__","die","echo","exit","include","include_once","print","require","require_once","array","abstract","and","as","binary","bool","boolean","break","callable","case","catch","class","clone","const","continue","declare","default","do","double","else","elseif","empty","enddeclare","endfor","endforeach","endif","endcase","endwhile","enum","eval","extends","final","finally","float","for","foreach","from","global","goto","if","implements","instanceof","insteadof","int","integer","interface","isset","iterable","list","match|0","mixed","new","never","object","or","private","protected","public","readonly","real","return","string","case","throw","trait","try","unset","use","var","void","while","xor","yield"],b=["Error|0","AppendIterator","ArgumentCountError","ArithmeticError","ArrayIterator","ArrayObject","AssertionError","BadFunctionCallException","BadMethodCallException","CachingIterator","CallbackFilterIterator","CompileError","Countable","DirectoryIterator","DivisionByZeroError","DomainException","EmptyIterator","ErrorException","Exception","FilesystemIterator","FilterIterator","GlobIterator","InfiniteIterator","InvalidArgumentException","IteratorIterator","LengthException","LimitIterator","LogicException","MultipleIterator","NoRewindIterator","OutOfBoundsException","OutOfRangeException","OuterIterator","OverflowException","ParentIterator","ParseError","RangeException","RecursiveArrayIterator","RecursiveCachingIterator","RecursiveCallbackFilterIterator","RecursiveDirectoryIterator","RecursiveFilterIterator","RecursiveIterator","RecursiveIteratorIterator","RecursiveRegexIterator","RecursiveTreeIterator","RegexIterator","RuntimeException","SeekableIterator","SplDoublyLinkedList","SplFileInfo","SplFileObject","SplFixedArray","SplHeap","SplMaxHeap","SplMinHeap","SplObjectStorage","SplObserver","SplPriorityQueue","SplQueue","SplStack","SplSubject","SplTempFileObject","TypeError","UnderflowException","UnexpectedValueException","UnhandledMatchError","ArrayAccess","BackedEnum","Closure","Fiber","Generator","Iterator","IteratorAggregate","Serializable","Stringable","Throwable","Traversable","UnitEnum","WeakReference","WeakMap","Directory","__PHP_Incomplete_Class","parent","php_user_filter","self","static","stdClass"],m={keyword:u,literal:(e=>{const n=[];return e.forEach(e=>{n.push(e),e.toLowerCase()===e?n.push(e.toUpperCase()):n.push(e.toLowerCase())}),n})(g),built_in:b},p=e=>e.map(e=>e.replace(/\|\d+$/,"")),_={variants:[{match:[/new/,n.concat(l,"+"),n.concat("(?!",p(b).join("\\b|"),"\\b)"),i],scope:{1:"keyword",4:"title.class"}}]},h=n.concat(a,"\\b(?!\\()"),f={variants:[{match:[n.concat(/::/,n.lookahead(/(?!class\b)/)),h],scope:{2:"variable.constant"}},{match:[/::/,/class/],scope:{2:"variable.language"}},{match:[i,n.concat(/::/,n.lookahead(/(?!class\b)/)),h],scope:{1:"title.class",3:"variable.constant"}},{match:[i,n.concat("::",n.lookahead(/(?!class\b)/))],scope:{1:"title.class"}},{match:[i,/::/,/class/],scope:{1:"title.class",3:"variable.language"}}]},E={scope:"attr",match:n.concat(a,n.lookahead(":"),n.lookahead(/(?!::)/))},y={relevance:0,begin:/\(/,end:/\)/,keywords:m,contains:[E,r,f,e.C_BLOCK_COMMENT_MODE,c,d,_]},w={relevance:0,match:[/\b/,n.concat("(?!fn\\b|function\\b|",p(u).join("\\b|"),"|",p(b).join("\\b|"),"\\b)"),a,n.concat(l,"*"),n.lookahead(/(?=\()/)],scope:{3:"title.function.invoke"},contains:[y]};y.contains.push(w);const N=[E,f,e.C_BLOCK_COMMENT_MODE,c,d,_];return{case_insensitive:!1,keywords:m,contains:[{begin:n.concat(/#\[\s*/,i),beginScope:"meta",end:/]/,endScope:"meta",keywords:{literal:g,keyword:["new","array"]},contains:[{begin:/\[/,end:/]/,keywords:{literal:g,keyword:["new","array"]},contains:["self",...N]},...N,{scope:"meta",match:i}]},e.HASH_COMMENT_MODE,e.COMMENT("//","$"),e.COMMENT("/\\*","\\*/",{contains:[{scope:"doctag",match:"@[A-Za-z]+"}]}),{match:/__halt_compiler\(\);/,keywords:"__halt_compiler",starts:{scope:"comment",end:e.MATCH_NOTHING_RE,contains:[{match:/\?>/,scope:"meta",endsParent:!0}]}},{scope:"meta",variants:[{begin:/<\?php/,relevance:10},{begin:/<\?=/},{begin:/<\?/,relevance:.1},{begin:/\?>/}]},{scope:"variable.language",match:/\$this\b/},r,w,f,{match:[/const/,/\s/,a],scope:{1:"keyword",3:"variable.constant"}},_,{scope:"function",relevance:0,beginKeywords:"fn function",end:/[;{]/,excludeEnd:!0,illegal:"[$%\\[]",contains:[{beginKeywords:"use"},e.UNDERSCORE_TITLE_MODE,{begin:"=>",endsParent:!0},{scope:"params",begin:"\\(",end:"\\)",excludeBegin:!0,excludeEnd:!0,keywords:m,contains:["self",r,f,e.C_BLOCK_COMMENT_MODE,c,d]}]},{scope:"class",variants:[{beginKeywords:"enum",illegal:/[($"]/},{beginKeywords:"class interface trait",illegal:/[:($"]/}],relevance:0,end:/\{/,excludeEnd:!0,contains:[{beginKeywords:"extends implements"},e.UNDERSCORE_TITLE_MODE]},{beginKeywords:"namespace",relevance:0,end:";",illegal:/[.']/,contains:[e.inherit(e.UNDERSCORE_TITLE_MODE,{scope:"title.class"})]},{beginKeywords:"use",relevance:0,end:";",contains:[{match:/\b(as|const|function)\b/,scope:"keyword"},e.UNDERSCORE_TITLE_MODE]},c,d]}},grmr_php_template:e=>({name:"PHP template",subLanguage:"xml",contains:[{begin:/<\?(php|=)?/,end:/\?>/,subLanguage:"php",contains:[{begin:"/\\*",end:"\\*/",skip:!0},{begin:'b"',end:'"',skip:!0},{begin:"b'",end:"'",skip:!0},e.inherit(e.APOS_STRING_MODE,{illegal:null,className:null,contains:null,skip:!0}),e.inherit(e.QUOTE_STRING_MODE,{illegal:null,className:null,contains:null,skip:!0})]}]}),grmr_plaintext:e=>({name:"Plain text",aliases:["text","txt"],disableAutodetect:!0}),grmr_python:e=>{const n=e.regex,t=/[\p{XID_Start}_]\p{XID_Continue}*/u,a=["and","as","assert","async","await","break","class","continue","def","del","elif","else","except","finally","for","from","global","if","import","in","is","lambda","nonlocal|10","not","or","pass","raise","return","try","while","with","yield"],i={$pattern:/[A-Za-z]\w+|__\w+__/,keyword:a,built_in:["__import__","abs","all","any","ascii","bin","bool","breakpoint","bytearray","bytes","callable","chr","classmethod","compile","complex","delattr","dict","dir","divmod","enumerate","eval","exec","filter","float","format","frozenset","getattr","globals","hasattr","hash","help","hex","id","input","int","isinstance","issubclass","iter","len","list","locals","map","max","memoryview","min","next","object","oct","open","ord","pow","print","property","range","repr","reversed","round","set","setattr","slice","sorted","staticmethod","str","sum","super","tuple","type","vars","zip"],literal:["__debug__","Ellipsis","False","None","NotImplemented","True"],type:["Any","Callable","Coroutine","Dict","List","Literal","Generic","Optional","Sequence","Set","Tuple","Type","Union"]},r={className:"meta",begin:/^(>>>|\.\.\.) /},s={className:"subst",begin:/\{/,end:/\}/,keywords:i,illegal:/#/},o={begin:/\{\{/,relevance:0},l={className:"string",contains:[e.BACKSLASH_ESCAPE],variants:[{begin:/([uU]|[bB]|[rR]|[bB][rR]|[rR][bB])?'''/,end:/'''/,contains:[e.BACKSLASH_ESCAPE,r],relevance:10},{begin:/([uU]|[bB]|[rR]|[bB][rR]|[rR][bB])?"""/,end:/"""/,contains:[e.BACKSLASH_ESCAPE,r],relevance:10},{begin:/([fF][rR]|[rR][fF]|[fF])'''/,end:/'''/,contains:[e.BACKSLASH_ESCAPE,r,o,s]},{begin:/([fF][rR]|[rR][fF]|[fF])"""/,end:/"""/,contains:[e.BACKSLASH_ESCAPE,r,o,s]},{begin:/([uU]|[rR])'/,end:/'/,relevance:10},{begin:/([uU]|[rR])"/,end:/"/,relevance:10},{begin:/([bB]|[bB][rR]|[rR][bB])'/,end:/'/},{begin:/([bB]|[bB][rR]|[rR][bB])"/,end:/"/},{begin:/([fF][rR]|[rR][fF]|[fF])'/,end:/'/,contains:[e.BACKSLASH_ESCAPE,o,s]},{begin:/([fF][rR]|[rR][fF]|[fF])"/,end:/"/,contains:[e.BACKSLASH_ESCAPE,o,s]},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE]},c="[0-9](_?[0-9])*",d=`(\\b(${c}))?\\.(${c})|\\b(${c})\\.`,g="\\b|"+a.join("|"),u={className:"number",relevance:0,variants:[{begin:`(\\b(${c})|(${d}))[eE][+-]?(${c})[jJ]?(?=${g})`},{begin:`(${d})[jJ]?`},{begin:`\\b([1-9](_?[0-9])*|0+(_?0)*)[lLjJ]?(?=${g})`},{begin:`\\b0[bB](_?[01])+[lL]?(?=${g})`},{begin:`\\b0[oO](_?[0-7])+[lL]?(?=${g})`},{begin:`\\b0[xX](_?[0-9a-fA-F])+[lL]?(?=${g})`},{begin:`\\b(${c})[jJ](?=${g})`}]},b={className:"comment",begin:n.lookahead(/# type:/),end:/$/,keywords:i,contains:[{begin:/# type:/},{begin:/#/,end:/\b\B/,endsWithParent:!0}]},m={className:"params",variants:[{className:"",begin:/\(\s*\)/,skip:!0},{begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:i,contains:["self",r,u,l,e.HASH_COMMENT_MODE]}]};return s.contains=[l,u,r],{name:"Python",aliases:["py","gyp","ipython"],unicodeRegex:!0,keywords:i,illegal:/(<\/|->|\?)|=>/,contains:[r,u,{begin:/\bself\b/},{beginKeywords:"if",relevance:0},l,b,e.HASH_COMMENT_MODE,{match:[/\bdef/,/\s+/,t],scope:{1:"keyword",3:"title.function"},contains:[m]},{variants:[{match:[/\bclass/,/\s+/,t,/\s*/,/\(\s*/,t,/\s*\)/]},{match:[/\bclass/,/\s+/,t]}],scope:{1:"keyword",3:"title.class",6:"title.class.inherited"}},{className:"meta",begin:/^[\t ]*@/,end:/(?=#)|$/,contains:[u,m,l]}]}},grmr_python_repl:e=>({aliases:["pycon"],contains:[{className:"meta.prompt",starts:{end:/ |$/,starts:{end:"$",subLanguage:"python"}},variants:[{begin:/^>>>(?=[ ]|$)/},{begin:/^\.\.\.(?=[ ]|$)/}]}]}),grmr_r:e=>{const n=e.regex,t=/(?:(?:[a-zA-Z]|\.[._a-zA-Z])[._a-zA-Z0-9]*)|\.(?!\d)/,a=n.either(/0[xX][0-9a-fA-F]+\.[0-9a-fA-F]*[pP][+-]?\d+i?/,/0[xX][0-9a-fA-F]+(?:[pP][+-]?\d+)?[Li]?/,/(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?[Li]?/),i=/[=!<>:]=|\|\||&&|:::?|<-|<<-|->>|->|\|>|[-+*\/?!$&|:<=>@^~]|\*\*/,r=n.either(/[()]/,/[{}]/,/\[\[/,/[[\]]/,/\\/,/,/);return{name:"R",keywords:{$pattern:t,keyword:"function if in break next repeat else for while",literal:"NULL NA TRUE FALSE Inf NaN NA_integer_|10 NA_real_|10 NA_character_|10 NA_complex_|10",built_in:"LETTERS letters month.abb month.name pi T F abs acos acosh all any anyNA Arg as.call as.character as.complex as.double as.environment as.integer as.logical as.null.default as.numeric as.raw asin asinh atan atanh attr attributes baseenv browser c call ceiling class Conj cos cosh cospi cummax cummin cumprod cumsum digamma dim dimnames emptyenv exp expression floor forceAndCall gamma gc.time globalenv Im interactive invisible is.array is.atomic is.call is.character is.complex is.double is.environment is.expression is.finite is.function is.infinite is.integer is.language is.list is.logical is.matrix is.na is.name is.nan is.null is.numeric is.object is.pairlist is.raw is.recursive is.single is.symbol lazyLoadDBfetch length lgamma list log max min missing Mod names nargs nzchar oldClass on.exit pos.to.env proc.time prod quote range Re rep retracemem return round seq_along seq_len seq.int sign signif sin sinh sinpi sqrt standardGeneric substitute sum case tan tanh tanpi tracemem trigamma trunc unclass untracemem UseMethod xtfrm"},contains:[e.COMMENT(/#'/,/$/,{contains:[{scope:"doctag",match:/@examples/,starts:{end:n.lookahead(n.either(/\n^#'\s*(?=@[a-zA-Z]+)/,/\n^(?!#')/)),endsParent:!0}},{scope:"doctag",begin:"@param",end:/$/,contains:[{scope:"variable",variants:[{match:t},{match:/`(?:\\.|[^`\\])+`/}],endsParent:!0}]},{scope:"doctag",match:/@[a-zA-Z]+/},{scope:"keyword",match:/\\[a-zA-Z]+/}]}),e.HASH_COMMENT_MODE,{scope:"string",contains:[e.BACKSLASH_ESCAPE],variants:[e.END_SAME_AS_BEGIN({begin:/[rR]"(-*)\(/,end:/\)(-*)"/}),e.END_SAME_AS_BEGIN({begin:/[rR]"(-*)\{/,end:/\}(-*)"/}),e.END_SAME_AS_BEGIN({begin:/[rR]"(-*)\[/,end:/\](-*)"/}),e.END_SAME_AS_BEGIN({begin:/[rR]'(-*)\(/,end:/\)(-*)'/}),e.END_SAME_AS_BEGIN({begin:/[rR]'(-*)\{/,end:/\}(-*)'/}),e.END_SAME_AS_BEGIN({begin:/[rR]'(-*)\[/,end:/\](-*)'/}),{begin:'"',end:'"',relevance:0},{begin:"'",end:"'",relevance:0}]},{relevance:0,variants:[{scope:{1:"operator",2:"number"},match:[i,a]},{scope:{1:"operator",2:"number"},match:[/%[^%]*%/,a]},{scope:{1:"punctuation",2:"number"},match:[r,a]},{scope:{2:"number"},match:[/[^a-zA-Z0-9._]|^/,a]}]},{scope:{3:"operator"},match:[t,/\s+/,/<-/,/\s+/]},{scope:"operator",relevance:0,variants:[{match:i},{match:/%[^%]*%/}]},{scope:"punctuation",relevance:0,match:r},{begin:"`",end:"`",contains:[{begin:/\\./}]}]}},grmr_ruby:e=>{const n=e.regex,t="([a-zA-Z_]\\w*[!?=]?|[-+~]@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?)",a=n.either(/\b([A-Z]+[a-z0-9]+)+/,/\b([A-Z]+[a-z0-9]+)+[A-Z]+/),i=n.concat(a,/(::\w+)*/),r={"variable.constant":["__FILE__","__LINE__"],"variable.language":["self","super"],keyword:["alias","and","attr_accessor","attr_reader","attr_writer","begin","BEGIN","break","case","class","defined","do","else","elsif","end","END","ensure","for","if","in","include","module","next","not","or","redo","require","rescue","retry","return","then","undef","unless","until","when","while","yield"],built_in:["proc","lambda"],literal:["true","false","nil"]},s={className:"doctag",begin:"@[A-Za-z]+"},o={begin:"#<",end:">"},l=[e.COMMENT("#","$",{contains:[s]}),e.COMMENT("^=begin","^=end",{contains:[s],relevance:10}),e.COMMENT("^__END__",e.MATCH_NOTHING_RE)],c={className:"subst",begin:/#\{/,end:/\}/,keywords:r},d={className:"string",contains:[e.BACKSLASH_ESCAPE,c],variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/`/,end:/`/},{begin:/%[qQwWx]?\(/,end:/\)/},{begin:/%[qQwWx]?\[/,end:/\]/},{begin:/%[qQwWx]?\{/,end:/\}/},{begin:/%[qQwWx]?/},{begin:/%[qQwWx]?\//,end:/\//},{begin:/%[qQwWx]?%/,end:/%/},{begin:/%[qQwWx]?-/,end:/-/},{begin:/%[qQwWx]?\|/,end:/\|/},{begin:/\B\?(\\\d{1,3})/},{begin:/\B\?(\\x[A-Fa-f0-9]{1,2})/},{begin:/\B\?(\\u\{?[A-Fa-f0-9]{1,6}\}?)/},{begin:/\B\?(\\M-\\C-|\\M-\\c|\\c\\M-|\\M-|\\C-\\M-)[\x20-\x7e]/},{begin:/\B\?\\(c|C-)[\x20-\x7e]/},{begin:/\B\?\\?\S/},{begin:n.concat(/<<[-~]?'?/,n.lookahead(/(\w+)(?=\W)[^\n]*\n(?:[^\n]*\n)*?\s*\1\b/)),contains:[e.END_SAME_AS_BEGIN({begin:/(\w+)/,end:/(\w+)/,contains:[e.BACKSLASH_ESCAPE,c]})]}]},g="[0-9](_?[0-9])*",u={className:"number",relevance:0,variants:[{begin:`\\b([1-9](_?[0-9])*|0)(\\.(${g}))?([eE][+-]?(${g})|r)?i?\\b`},{begin:"\\b0[dD][0-9](_?[0-9])*r?i?\\b"},{begin:"\\b0[bB][0-1](_?[0-1])*r?i?\\b"},{begin:"\\b0[oO][0-7](_?[0-7])*r?i?\\b"},{begin:"\\b0[xX][0-9a-fA-F](_?[0-9a-fA-F])*r?i?\\b"},{begin:"\\b0(_?[0-7])+r?i?\\b"}]},b={variants:[{match:/\(\)/},{className:"params",begin:/\(/,end:/(?=\))/,excludeBegin:!0,endsParent:!0,keywords:r}]},m=[d,{variants:[{match:[/class\s+/,i,/\s+<\s+/,i]},{match:[/class\s+/,i]}],scope:{2:"title.class",4:"title.class.inherited"},keywords:r},{relevance:0,match:[i,/\.new[ (]/],scope:{1:"title.class"}},{relevance:0,match:/\b[A-Z][A-Z_0-9]+\b/,className:"variable.constant"},{match:[/def/,/\s+/,t],scope:{1:"keyword",3:"title.function"},contains:[b]},{begin:e.IDENT_RE+"::"},{className:"symbol",begin:e.UNDERSCORE_IDENT_RE+"(!|\\?)?:",relevance:0},{className:"symbol",begin:":(?!\\s)",contains:[d,{begin:t}],relevance:0},u,{className:"variable",begin:"(\\$\\W)|((\\$|@@?)(\\w+))(?=[^@$?])(?![A-Za-z])(?![@$?'])"},{className:"params",begin:/\|/,end:/\|/,excludeBegin:!0,excludeEnd:!0,relevance:0,keywords:r},{begin:"("+e.RE_STARTERS_RE+"|unless)\\s*",keywords:"unless",contains:[{className:"regexp",contains:[e.BACKSLASH_ESCAPE,c],illegal:/\n/,variants:[{begin:"/",end:"/[a-z]*"},{begin:/%r\{/,end:/\}[a-z]*/},{begin:"%r\\(",end:"\\)[a-z]*"},{begin:"%r!",end:"![a-z]*"},{begin:"%r\\[",end:"\\][a-z]*"}]}].concat(o,l),relevance:0}].concat(o,l);c.contains=m,b.contains=m;const p=[{begin:/^\s*=>/,starts:{end:"$",contains:m}},{className:"meta.prompt",begin:"^([>?]>|[\\w#]+\\(\\w+\\):\\d+:\\d+[>*]|(\\w+-)?\\d+\\.\\d+\\.\\d+(p\\d+)?[^\\d][^>]+>)(?=[ ])",starts:{end:"$",keywords:r,contains:m}}];return l.unshift(o),{name:"Ruby",aliases:["rb","gemspec","podspec","thor","irb"],keywords:r,illegal:/\/\*/,contains:[e.SHEBANG({binary:"ruby"})].concat(p).concat(l).concat(m)}},grmr_rust:e=>{const n=e.regex,t={className:"title.function.invoke",relevance:0,begin:n.concat(/\b/,/(?!let\b)/,e.IDENT_RE,n.lookahead(/\s*\(/))},a="([ui](8|16|32|64|128|size)|f(32|64))?",i=["drop ","Copy","Send","Sized","Sync","Drop","Fn","FnMut","FnOnce","ToOwned","Clone","Debug","PartialEq","PartialOrd","Eq","Ord","AsRef","AsMut","Into","From","Default","Iterator","Extend","IntoIterator","DoubleEndedIterator","ExactSizeIterator","SliceConcatExt","ToString","assert!","assert_eq!","bitflags!","bytes!","cfg!","col!","concat!","concat_idents!","debug_assert!","debug_assert_eq!","env!","panic!","file!","format!","format_args!","include_bin!","include_str!","line!","local_data_key!","module_path!","option_env!","print!","println!","select!","stringify!","try!","unimplemented!","unreachable!","vec!","write!","writeln!","macro_rules!","assert_ne!","debug_assert_ne!"];return{name:"Rust",aliases:["rs"],keywords:{$pattern:e.IDENT_RE+"!?",type:["i8","i16","i32","i64","i128","isize","u8","u16","u32","u64","u128","usize","f32","f64","str","char","bool","Box","Option","Result","String","Vec"],keyword:["abstract","as","async","await","become","box","break","const","continue","crate","do","dyn","else","enum","extern","false","final","fn","for","if","impl","in","let","loop","macro","match","mod","move","mut","override","priv","pub","ref","return","self","Self","static","struct","super","trait","true","try","type","typeof","unsafe","unsized","use","virtual","where","while","yield"],literal:["true","false","Some","None","Ok","Err"],built_in:i},illegal:""},t]}},grmr_scss:e=>{const n=te(e),t=se,a=re,i="@[a-z-]+",r={className:"variable",begin:"(\\$[a-zA-Z-][a-zA-Z0-9_-]*)\\b",relevance:0};return{name:"SCSS",case_insensitive:!0,illegal:"[=/|']",contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,n.CSS_NUMBER_MODE,{className:"selector-id",begin:"#[A-Za-z0-9_-]+",relevance:0},{className:"selector-class",begin:"\\.[A-Za-z0-9_-]+",relevance:0},n.ATTRIBUTE_SELECTOR_MODE,{className:"selector-tag",begin:"\\b("+ae.join("|")+")\\b",relevance:0},{className:"selector-pseudo",begin:":("+a.join("|")+")"},{className:"selector-pseudo",begin:":(:)?("+t.join("|")+")"},r,{begin:/\(/,end:/\)/,contains:[n.CSS_NUMBER_MODE]},n.CSS_VARIABLE,{className:"attribute",begin:"\\b("+oe.join("|")+")\\b"},{begin:"\\b(whitespace|wait|w-resize|visible|vertical-text|vertical-ideographic|uppercase|upper-roman|upper-alpha|underline|transparent|top|thin|thick|text|text-top|text-bottom|tb-rl|table-header-group|table-footer-group|sw-resize|super|strict|static|square|solid|small-caps|separate|se-resize|scroll|s-resize|rtl|row-resize|ridge|right|repeat|repeat-y|repeat-x|relative|progress|pointer|overline|outside|outset|oblique|nowrap|not-allowed|normal|none|nw-resize|no-repeat|no-drop|newspaper|ne-resize|n-resize|move|middle|medium|ltr|lr-tb|lowercase|lower-roman|lower-alpha|loose|list-item|line|line-through|line-edge|lighter|left|keep-all|justify|italic|inter-word|inter-ideograph|inside|inset|inline|inline-block|inherit|inactive|ideograph-space|ideograph-parenthesis|ideograph-numeric|ideograph-alpha|horizontal|hidden|help|hand|groove|fixed|ellipsis|e-resize|double|dotted|distribute|distribute-space|distribute-letter|distribute-all-lines|disc|disabled|default|decimal|dashed|crosshair|collapse|col-resize|circle|char|center|capitalize|break-word|break-all|bottom|both|bolder|bold|block|bidi-override|below|baseline|auto|always|all-scroll|absolute|table|table-cell)\\b"},{begin:/:/,end:/[;}{]/,contains:[n.BLOCK_COMMENT,r,n.HEXCOLOR,n.CSS_NUMBER_MODE,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,n.IMPORTANT]},{begin:"@(page|font-face)",keywords:{$pattern:i,keyword:"@page @font-face"}},{begin:"@",end:"[{;]",returnBegin:!0,keywords:{$pattern:/[a-z-]+/,keyword:"and or not only",attribute:ie.join(" ")},contains:[{begin:i,className:"keyword"},{begin:/[a-z-]+(?=:)/,className:"attribute"},r,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,n.HEXCOLOR,n.CSS_NUMBER_MODE]},n.FUNCTION_DISPATCH]}},grmr_shell:e=>({name:"Shell Session",aliases:["console","shellsession"],contains:[{className:"meta.prompt",begin:/^\s{0,3}[/~\w\d[\]()@-]*[>%$#][ ]?/,starts:{end:/[^\\](?=\s*$)/,subLanguage:"bash"}}]}),grmr_sql:e=>{const n=e.regex,t=e.COMMENT("--","$"),a=["true","false","unknown"],i=["bigint","binary","blob","boolean","char","character","clob","date","dec","decfloat","decimal","float","int","integer","interval","nchar","nclob","national","numeric","real","row","smallint","time","timestamp","varchar","varying","varbinary"],r=["abs","acos","array_agg","asin","atan","avg","cast","ceil","ceiling","coalesce","corr","cos","cosh","count","covar_pop","covar_samp","cume_dist","dense_rank","deref","element","exp","extract","first_value","floor","json_array","json_arrayagg","json_exists","json_object","json_objectagg","json_query","json_table","json_table_primitive","json_value","lag","last_value","lead","listagg","ln","log","log10","lower","max","min","mod","nth_value","ntile","nullif","percent_rank","percentile_cont","percentile_disc","position","position_regex","power","rank","regr_avgx","regr_avgy","regr_count","regr_intercept","regr_r2","regr_slope","regr_sxx","regr_sxy","regr_syy","row_number","sin","sinh","sqrt","stddev_pop","stddev_samp","substring","substring_regex","sum","tan","tanh","translate","translate_regex","treat","trim","trim_array","unnest","upper","value_of","var_pop","var_samp","width_bucket"],s=["create table","insert into","primary key","foreign key","not null","alter table","add constraint","grouping sets","on overflow","character set","respect nulls","ignore nulls","nulls first","nulls last","depth first","breadth first"],o=r,l=["abs","acos","all","allocate","alter","and","any","are","array","array_agg","array_max_cardinality","as","asensitive","asin","asymmetric","at","atan","atomic","authorization","avg","begin","begin_frame","begin_partition","between","bigint","binary","blob","boolean","both","by","call","called","cardinality","cascaded","case","cast","ceil","ceiling","char","char_length","character","character_length","check","classifier","clob","close","coalesce","collate","collect","column","commit","condition","connect","constraint","contains","convert","copy","corr","corresponding","cos","cosh","count","covar_pop","covar_samp","create","cross","cube","cume_dist","current","current_catalog","current_date","current_default_transform_group","current_path","current_role","current_row","current_schema","current_time","current_timestamp","current_path","current_role","current_transform_group_for_type","current_user","cursor","cycle","date","day","deallocate","dec","decimal","decfloat","declare","default","define","delete","dense_rank","deref","describe","deterministic","disconnect","distinct","double","drop","dynamic","each","element","else","empty","end","end_frame","end_partition","end-exec","equals","escape","every","except","exec","execute","exists","exp","external","extract","false","fetch","filter","first_value","float","floor","for","foreign","frame_row","free","from","full","function","fusion","get","global","grant","group","grouping","groups","having","hold","hour","identity","in","indicator","initial","inner","inout","insensitive","insert","int","integer","intersect","intersection","interval","into","is","join","json_array","json_arrayagg","json_exists","json_object","json_objectagg","json_query","json_table","json_table_primitive","json_value","lag","language","large","last_value","lateral","lead","leading","left","like","like_regex","listagg","ln","local","localtime","localtimestamp","log","log10","lower","match","match_number","match_recognize","matches","max","member","merge","method","min","minute","mod","modifies","module","month","multiset","national","natural","nchar","nclob","new","no","none","normalize","not","nth_value","ntile","null","nullif","numeric","octet_length","occurrences_regex","of","offset","old","omit","on","one","only","open","or","order","out","outer","over","overlaps","overlay","parameter","partition","pattern","per","percent","percent_rank","percentile_cont","percentile_disc","period","portion","position","position_regex","power","precedes","precision","prepare","primary","procedure","ptf","range","rank","reads","real","recursive","ref","references","referencing","regr_avgx","regr_avgy","regr_count","regr_intercept","regr_r2","regr_slope","regr_sxx","regr_sxy","regr_syy","release","result","return","returns","revoke","right","rollback","rollup","row","row_number","rows","running","savepoint","scope","scroll","search","second","seek","select","sensitive","session_user","set","show","similar","sin","sinh","skip","smallint","some","specific","specifictype","sql","sqlexception","sqlstate","sqlwarning","sqrt","start","static","stddev_pop","stddev_samp","submultiset","subset","substring","substring_regex","succeeds","sum","symmetric","system","system_time","system_user","table","tablesample","tan","tanh","then","time","timestamp","timezone_hour","timezone_minute","to","trailing","translate","translate_regex","translation","treat","trigger","trim","trim_array","true","truncate","uescape","union","unique","unknown","unnest","update","upper","user","using","value","values","value_of","var_pop","var_samp","varbinary","varchar","varying","versioning","when","whenever","where","width_bucket","window","with","within","without","year","add","asc","collation","desc","final","first","last","view"].filter(e=>!r.includes(e)),c={begin:n.concat(/\b/,n.either(...o),/\s*\(/),relevance:0,keywords:{built_in:o}};return{name:"SQL",case_insensitive:!0,illegal:/[{}]|<\//,keywords:{$pattern:/\b[\w\.]+/,keyword:((e,{exceptions:n,when:t}={})=>{const a=t;return n=n||[],e.map(e=>e.match(/\|\d+$/)||n.includes(e)?e:a(e)?e+"|0":e)})(l,{when:e=>e.length<3}),literal:a,type:i,built_in:["current_catalog","current_date","current_default_transform_group","current_path","current_role","current_schema","current_transform_group_for_type","current_user","session_user","system_time","system_user","current_time","localtime","current_timestamp","localtimestamp"]},contains:[{begin:n.either(...s),relevance:0,keywords:{$pattern:/[\w\.]+/,keyword:l.concat(s),literal:a,type:i}},{className:"type",begin:n.either("double precision","large object","with timezone","without timezone")},c,{className:"variable",begin:/@[a-z0-9]+/},{className:"string",variants:[{begin:/'/,end:/'/,contains:[{begin:/''/}]}]},{begin:/"/,end:/"/,contains:[{begin:/""/}]},e.C_NUMBER_MODE,e.C_BLOCK_COMMENT_MODE,t,{className:"operator",begin:/[-+*/=%^~]|&&?|\|\|?|!=?|<(?:=>?|<|>)?|>[>=]?/,relevance:0}]}},grmr_swift:e=>{const n={match:/\s+/,relevance:0},t=e.COMMENT("/\\*","\\*/",{contains:["self"]}),a=[e.C_LINE_COMMENT_MODE,t],i={match:[/\./,p(...ve,...ke)],className:{2:"keyword"}},r={match:m(/\./,p(...xe)),relevance:0},s=xe.filter(e=>"string"==typeof e).concat(["_|0"]),o={variants:[{className:"keyword",match:p(...xe.filter(e=>"string"!=typeof e).concat(Oe).map(Ne),...ke)}]},l={$pattern:p(/\b\w+/,/#\w+/),keyword:s.concat(Ae),literal:Me},c=[i,r,o],d=[{match:m(/\./,p(...Ce)),relevance:0},{className:"built_in",match:m(/\b/,p(...Ce),/(?=\()/)}],u={match:/->/,relevance:0},b=[u,{className:"operator",relevance:0,variants:[{match:De},{match:`\\.(\\.|${Re})+`}]}],_="([0-9a-fA-F]_*)+",h={className:"number",relevance:0,variants:[{match:"\\b(([0-9]_*)+)(\\.(([0-9]_*)+))?([eE][+-]?(([0-9]_*)+))?\\b"},{match:`\\b0x(${_})(\\.(${_}))?([pP][+-]?(([0-9]_*)+))?\\b`},{match:/\b0o([0-7]_*)+\b/},{match:/\b0b([01]_*)+\b/}]},f=(e="")=>({className:"subst",variants:[{match:m(/\\/,e,/[0\\tnr"']/)},{match:m(/\\/,e,/u\{[0-9a-fA-F]{1,8}\}/)}]}),E=(e="")=>({className:"subst",match:m(/\\/,e,/[\t ]*(?:[\r\n]|\r\n)/)}),y=(e="")=>({className:"subst",label:"interpol",begin:m(/\\/,e,/\(/),end:/\)/}),w=(e="")=>({begin:m(e,/"""/),end:m(/"""/,e),contains:[f(e),E(e),y(e)]}),N=(e="")=>({begin:m(e,/"/),end:m(/"/,e),contains:[f(e),y(e)]}),v={className:"string",variants:[w(),w("#"),w("##"),w("###"),N(),N("#"),N("##"),N("###")]},k={match:m(/`/,Be,/`/)},O=[k,{className:"variable",match:/\$\d+/},{className:"variable",match:`\\$${Le}+`}],x=[{match:/(@|#(un)?)available/,className:"keyword",starts:{contains:[{begin:/\(/,end:/\)/,keywords:Fe,contains:[...b,h,v]}]}},{className:"keyword",match:m(/@/,p(...ze))},{className:"meta",match:m(/@/,Be)}],M={match:g(/\b[A-Z]/),relevance:0,contains:[{className:"type",match:m(/(AV|CA|CF|CG|CI|CL|CM|CN|CT|MK|MP|MTK|MTL|NS|SCN|SK|UI|WK|XC)/,Le,"+")},{className:"type",match:$e,relevance:0},{match:/[?!]+/,relevance:0},{match:/\.\.\./,relevance:0},{match:m(/\s+&\s+/,g($e)),relevance:0}]},S={begin://,keywords:l,contains:[...a,...c,...x,u,M]};M.contains.push(S);const A={begin:/\(/,end:/\)/,relevance:0,keywords:l,contains:["self",{match:m(Be,/\s*:/),keywords:"_|0",relevance:0},...a,...c,...d,...b,h,v,...O,...x,M]},C={begin://,contains:[...a,M]},T={begin:/\(/,end:/\)/,keywords:l,contains:[{begin:p(g(m(Be,/\s*:/)),g(m(Be,/\s+/,Be,/\s*:/))),end:/:/,relevance:0,contains:[{className:"keyword",match:/\b_\b/},{className:"params",match:Be}]},...a,...c,...b,h,v,...x,M,A],endsParent:!0,illegal:/["']/},R={match:[/func/,/\s+/,p(k.match,Be,De)],className:{1:"keyword",3:"title.function"},contains:[C,T,n],illegal:[/\[/,/%/]},D={match:[/\b(?:subscript|init[?!]?)/,/\s*(?=[<(])/],className:{1:"keyword"},contains:[C,T,n],illegal:/\[|%/},I={match:[/operator/,/\s+/,De],className:{1:"keyword",3:"title"}},L={begin:[/precedencegroup/,/\s+/,$e],className:{1:"keyword",3:"title"},contains:[M],keywords:[...Se,...Me],end:/}/};for(const e of v.variants){const n=e.contains.find(e=>"interpol"===e.label);n.keywords=l;const t=[...c,...d,...b,h,v,...O];n.contains=[...t,{begin:/\(/,end:/\)/,contains:["self",...t]}]}return{name:"Swift",keywords:l,contains:[...a,R,D,{beginKeywords:"struct protocol class extension enum actor",end:"\\{",excludeEnd:!0,keywords:l,contains:[e.inherit(e.TITLE_MODE,{className:"title.class",begin:/[A-Za-z$_][\u00C0-\u02B80-9A-Za-z$_]*/}),...c]},I,L,{beginKeywords:"import",end:/$/,contains:[...a],relevance:0},...c,...d,...b,h,v,...O,...x,M,A]}},grmr_typescript:e=>{const n=we(e),t=["any","void","number","boolean","string","object","never","symbol","bigint","unknown"],a={beginKeywords:"namespace",end:/\{/,excludeEnd:!0,contains:[n.exports.CLASS_REFERENCE]},i={beginKeywords:"interface",end:/\{/,excludeEnd:!0,keywords:{keyword:"interface extends",built_in:t},contains:[n.exports.CLASS_REFERENCE]},r={$pattern:be,keyword:me.concat(["type","namespace","interface","public","private","protected","implements","declare","abstract","readonly","enum","override"]),literal:pe,built_in:ye.concat(t),"variable.language":Ee},s={className:"meta",begin:"@[A-Za-z$_][0-9A-Za-z$_]*"},o=(e,n,t)=>{const a=e.contains.findIndex(e=>e.label===n);if(-1===a)throw Error("can not find mode to replace");e.contains.splice(a,1,t)};return Object.assign(n.keywords,r),n.exports.PARAMS_CONTAINS.push(s),n.contains=n.contains.concat([s,a,i]),o(n,"shebang",e.SHEBANG()),o(n,"use_strict",{className:"meta",relevance:10,begin:/^\s*['"]use strict['"]/}),n.contains.find(e=>"func.def"===e.label).relevance=0,Object.assign(n,{name:"TypeScript",aliases:["ts","tsx"]}),n},grmr_vbnet:e=>{const n=e.regex,t=/\d{1,2}\/\d{1,2}\/\d{4}/,a=/\d{4}-\d{1,2}-\d{1,2}/,i=/(\d|1[012])(:\d+){0,2} *(AM|PM)/,r=/\d{1,2}(:\d{1,2}){1,2}/,s={className:"literal",variants:[{begin:n.concat(/# */,n.either(a,t),/ *#/)},{begin:n.concat(/# */,r,/ *#/)},{begin:n.concat(/# */,i,/ *#/)},{begin:n.concat(/# */,n.either(a,t),/ +/,n.either(i,r),/ *#/)}]},o=e.COMMENT(/'''/,/$/,{contains:[{className:"doctag",begin:/<\/?/,end:/>/}]}),l=e.COMMENT(null,/$/,{variants:[{begin:/'/},{begin:/([\t ]|^)REM(?=\s)/}]});return{name:"Visual Basic .NET",aliases:["vb"],case_insensitive:!0,classNameAliases:{label:"symbol"},keywords:{keyword:"addhandler alias aggregate ansi as async assembly auto binary by byref byval call case catch class compare const continue custom declare default delegate dim distinct do each equals else elseif end enum erase error event exit explicit finally for friend from function get global goto group handles if implements imports in inherits interface into iterator join key let lib loop me mid module mustinherit mustoverride mybase myclass namespace narrowing new next notinheritable notoverridable of off on operator option optional order overloads overridable overrides paramarray partial preserve private property protected public raiseevent readonly redim removehandler resume return select set shadows shared skip static step stop structure strict sub synclock take text then throw to try unicode until using when where while widening with withevents writeonly yield",built_in:"addressof and andalso await directcast gettype getxmlnamespace is isfalse isnot istrue like mod nameof new not or orelse trycast typeof xor cbool cbyte cchar cdate cdbl cdec cint clng cobj csbyte cshort csng cstr cuint culng cushort",type:"boolean byte char date decimal double integer long object sbyte short single string uinteger ulong ushort",literal:"true false nothing"},illegal:"//|\\{|\\}|endif|gosub|variant|wend|^\\$ ",contains:[{className:"string",begin:/"(""|[^/n])"C\b/},{className:"string",begin:/"/,end:/"/,illegal:/\n/,contains:[{begin:/""/}]},s,{className:"number",relevance:0,variants:[{begin:/\b\d[\d_]*((\.[\d_]+(E[+-]?[\d_]+)?)|(E[+-]?[\d_]+))[RFD@!#]?/},{begin:/\b\d[\d_]*((U?[SIL])|[%&])?/},{begin:/&H[\dA-F_]+((U?[SIL])|[%&])?/},{begin:/&O[0-7_]+((U?[SIL])|[%&])?/},{begin:/&B[01_]+((U?[SIL])|[%&])?/}]},{className:"label",begin:/^\w+:/},o,l,{className:"meta",begin:/[\t ]*#(const|disable|else|elseif|enable|end|externalsource|if|region)\b/,end:/$/,keywords:{keyword:"const disable else elseif enable end externalsource if region then"},contains:[l]}]}},grmr_yaml:e=>{const n="true false yes no null",t="[\\w#;/?:@&=+$,.~*'()[\\]]+",a={className:"string",relevance:0,variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/\S+/}],contains:[e.BACKSLASH_ESCAPE,{className:"template-variable",variants:[{begin:/\{\{/,end:/\}\}/},{begin:/%\{/,end:/\}/}]}]},i=e.inherit(a,{variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/[^\s,{}[\]]+/}]}),r={end:",",endsWithParent:!0,excludeEnd:!0,keywords:n,relevance:0},s={begin:/\{/,end:/\}/,contains:[r],illegal:"\\n",relevance:0},o={begin:"\\[",end:"\\]",contains:[r],illegal:"\\n",relevance:0},l=[{className:"attr",variants:[{begin:"\\w[\\w :\\/.-]*:(?=[ \t]|$)"},{begin:'"\\w[\\w :\\/.-]*":(?=[ \t]|$)'},{begin:"'\\w[\\w :\\/.-]*':(?=[ \t]|$)"}]},{className:"meta",begin:"^---\\s*$",relevance:10},{className:"string",begin:"[\\|>]([1-9]?[+-])?[ ]*\\n( +)[^ ][^\\n]*\\n(\\2[^\\n]+\\n?)*"},{begin:"<%[%=-]?",end:"[%-]?%>",subLanguage:"ruby",excludeBegin:!0,excludeEnd:!0,relevance:0},{className:"type",begin:"!\\w+!"+t},{className:"type",begin:"!<"+t+">"},{className:"type",begin:"!"+t},{className:"type",begin:"!!"+t},{className:"meta",begin:"&"+e.UNDERSCORE_IDENT_RE+"$"},{className:"meta",begin:"\\*"+e.UNDERSCORE_IDENT_RE+"$"},{className:"bullet",begin:"-(?=[ ]|$)",relevance:0},e.HASH_COMMENT_MODE,{beginKeywords:n,keywords:{literal:n}},{className:"number",begin:"\\b[0-9]{4}(-[0-9][0-9]){0,2}([Tt \\t][0-9][0-9]?(:[0-9][0-9]){2})?(\\.[0-9]*)?([ \\t])*(Z|[-+][0-9][0-9]?(:[0-9][0-9])?)?\\b"},{className:"number",begin:e.C_NUMBER_RE+"\\b",relevance:0},s,o,a],c=[...l];return c.pop(),c.push(i),r.contains=c,{name:"YAML",case_insensitive:!0,aliases:["yml"],contains:l}}});const je=ne;for(const e of Object.keys(Ue)){const n=e.replace("grmr_","").replace("_","-");je.registerLanguage(n,Ue[e])}return je}();"object"==typeof exports&&"undefined"!=typeof module&&(module.exports=hljs); diff --git a/playground/src/workbench/prql-syntax.js b/playground/src/workbench/prql-syntax.js index 6adce08b273c..8a589aed327c 100644 --- a/playground/src/workbench/prql-syntax.js +++ b/playground/src/workbench/prql-syntax.js @@ -13,7 +13,7 @@ const TRANSFORMS = [ "union", "window", ]; -const BUILTIN_FUNCTIONS = ["switch"]; // "in", "as" +const BUILTIN_FUNCTIONS = ["case"]; // "in", "as" const KEYWORDS = ["func", "let", "prql"]; const LITERALS = ["null", "true", "false"]; const OPERATORS = ["and", "or"]; // "not" diff --git a/prql-compiler/src/ast/pl/expr.rs b/prql-compiler/src/ast/pl/expr.rs index d23926e458f6..21f14994e112 100644 --- a/prql-compiler/src/ast/pl/expr.rs +++ b/prql-compiler/src/ast/pl/expr.rs @@ -72,7 +72,7 @@ pub enum ExprKind { TransformCall(TransformCall), SString(Vec), FString(Vec), - Switch(Vec), + Case(Vec), BuiltInFunction { name: String, args: Vec, @@ -573,8 +573,8 @@ impl Display for Expr { ExprKind::Literal(literal) => { write!(f, "{}", literal)?; } - ExprKind::Switch(cases) => { - f.write_str("switch [\n")?; + ExprKind::Case(cases) => { + f.write_str("case [\n")?; for case in cases { writeln!(f, " {} => {}", case.condition, case.value)?; } diff --git a/prql-compiler/src/ast/pl/fold.rs b/prql-compiler/src/ast/pl/fold.rs index 9d7664f80fe6..09fc02d71bd7 100644 --- a/prql-compiler/src/ast/pl/fold.rs +++ b/prql-compiler/src/ast/pl/fold.rs @@ -100,7 +100,7 @@ pub fn fold_expr_kind(fold: &mut T, expr_kind: ExprKind) -> .map(|x| fold.fold_interpolate_item(x)) .try_collect()?, ), - Switch(cases) => Switch(fold_cases(fold, cases)?), + Case(cases) => Case(fold_cases(fold, cases)?), FuncCall(func_call) => FuncCall(fold.fold_func_call(func_call)?), Closure(closure) => Closure(Box::new(fold.fold_closure(*closure)?)), diff --git a/prql-compiler/src/ast/rq/expr.rs b/prql-compiler/src/ast/rq/expr.rs index ba9f07a8bc40..d685459f268c 100644 --- a/prql-compiler/src/ast/rq/expr.rs +++ b/prql-compiler/src/ast/rq/expr.rs @@ -34,7 +34,7 @@ pub enum ExprKind { // TODO: convert this into built-in function FString(Vec>), - Switch(Vec>), + Case(Vec>), BuiltInFunction { name: String, diff --git a/prql-compiler/src/ast/rq/fold.rs b/prql-compiler/src/ast/rq/fold.rs index ca0920244f41..d0a35d89260a 100644 --- a/prql-compiler/src/ast/rq/fold.rs +++ b/prql-compiler/src/ast/rq/fold.rs @@ -223,7 +223,7 @@ pub fn fold_expr_kind(fold: &mut F, kind: ExprKind) -> Resul ExprKind::SString(items) => ExprKind::SString(fold_interpolate_items(fold, items)?), ExprKind::FString(items) => ExprKind::FString(fold_interpolate_items(fold, items)?), - ExprKind::Switch(cases) => ExprKind::Switch( + ExprKind::Case(cases) => ExprKind::Case( cases .into_iter() .map(|c| fold_switch_case(fold, c)) diff --git a/prql-compiler/src/parser/expr.rs b/prql-compiler/src/parser/expr.rs index 6a24915f7a44..07b16439fd59 100644 --- a/prql-compiler/src/parser/expr.rs +++ b/prql-compiler/src/parser/expr.rs @@ -72,7 +72,7 @@ pub fn expr() -> impl Parser> + Clone { } }); - let switch = keyword("switch") + let case = keyword("case") .ignore_then( func_call(expr.clone()) .then_ignore(just(Token::Arrow)) @@ -84,7 +84,7 @@ pub fn expr() -> impl Parser> + Clone { .then_ignore(new_line().repeated()) .delimited_by(ctrl('['), ctrl(']')), ) - .map(ExprKind::Switch); + .map(ExprKind::Case); let param = select! { Token::Param(id) => ExprKind::Param(id) }; @@ -94,7 +94,7 @@ pub fn expr() -> impl Parser> + Clone { pipeline, interpolation, ident_kind, - switch, + case, param, )) .map_with_span(into_expr) diff --git a/prql-compiler/src/parser/lexer.rs b/prql-compiler/src/parser/lexer.rs index 2043ea8d9847..2d0af4523d7a 100644 --- a/prql-compiler/src/parser/lexer.rs +++ b/prql-compiler/src/parser/lexer.rs @@ -51,7 +51,7 @@ pub fn lexer() -> impl Parser)>, Error let ident = ident_part().map(Token::Ident); - let keyword = choice((just("func"), just("let"), just("switch"), just("prql"))) + let keyword = choice((just("func"), just("let"), just("case"), just("prql"))) .then_ignore(end_expr()) .map(|x| x.to_string()) .map(Token::Keyword); diff --git a/prql-compiler/src/parser/mod.rs b/prql-compiler/src/parser/mod.rs index 247a881dbfd9..db7b880e3fb9 100644 --- a/prql-compiler/src/parser/mod.rs +++ b/prql-compiler/src/parser/mod.rs @@ -2188,13 +2188,13 @@ join s=salaries [==id] } #[test] - fn test_switch() { - assert_yaml_snapshot!(parse_expr(r#"switch [ + fn test_case() { + assert_yaml_snapshot!(parse_expr(r#"case [ nickname != null -> nickname, true -> null ]"#).unwrap(), @r###" --- - Switch: + Case: - condition: Binary: left: diff --git a/prql-compiler/src/semantic/lowering.rs b/prql-compiler/src/semantic/lowering.rs index 92f36d1c4428..1c688ac4589a 100644 --- a/prql-compiler/src/semantic/lowering.rs +++ b/prql-compiler/src/semantic/lowering.rs @@ -637,7 +637,7 @@ impl Lowerer { pl::ExprKind::FString(items) => { rq::ExprKind::FString(self.lower_interpolations(items)?) } - pl::ExprKind::Switch(cases) => rq::ExprKind::Switch( + pl::ExprKind::Case(cases) => rq::ExprKind::Case( cases .into_iter() .map(|case| -> Result<_> { diff --git a/prql-compiler/src/semantic/static_analysis.rs b/prql-compiler/src/semantic/static_analysis.rs index 4db3b93fd54d..081fff2b5821 100644 --- a/prql-compiler/src/semantic/static_analysis.rs +++ b/prql-compiler/src/semantic/static_analysis.rs @@ -131,7 +131,7 @@ fn eval(kind: ExprKind) -> ExprKind { } } - ExprKind::Switch(items) => { + ExprKind::Case(items) => { let mut res = Vec::with_capacity(items.len()); for item in items { if let ExprKind::Literal(Literal::Boolean(condition)) = item.condition.kind { @@ -160,7 +160,7 @@ fn eval(kind: ExprKind) -> ExprKind { } } - ExprKind::Switch(res) + ExprKind::Case(res) } k => k, diff --git a/prql-compiler/src/sql/anchor.rs b/prql-compiler/src/sql/anchor.rs index a81bcc37d63c..a96d52300714 100644 --- a/prql-compiler/src/sql/anchor.rs +++ b/prql-compiler/src/sql/anchor.rs @@ -463,7 +463,7 @@ pub fn infer_complexity(compute: &Compute) -> Complexity { pub fn infer_complexity_expr(expr: &Expr) -> Complexity { match &expr.kind { - rq::ExprKind::Switch(_) => Complexity::NonGroup, + rq::ExprKind::Case(_) => Complexity::NonGroup, rq::ExprKind::Binary { left, right, .. } => { Complexity::max(infer_complexity_expr(left), infer_complexity_expr(right)) } diff --git a/prql-compiler/src/sql/gen_expr.rs b/prql-compiler/src/sql/gen_expr.rs index 5f57a16670d7..797879487fe6 100644 --- a/prql-compiler/src/sql/gen_expr.rs +++ b/prql-compiler/src/sql/gen_expr.rs @@ -94,7 +94,7 @@ pub(super) fn translate_expr_kind(item: ExprKind, ctx: &mut Context) -> Result sql_ast::Expr::Identifier(sql_ast::Ident::new(format!("${id}"))), ExprKind::FString(f_string_items) => translate_fstring(f_string_items, ctx)?, ExprKind::Literal(l) => translate_literal(l, ctx)?, - ExprKind::Switch(mut cases) => { + ExprKind::Case(mut cases) => { let default = cases .last() .filter(|last| { diff --git a/prql-compiler/src/test.rs b/prql-compiler/src/test.rs index 6d4dcb9b071d..68df47ae447f 100644 --- a/prql-compiler/src/test.rs +++ b/prql-compiler/src/test.rs @@ -2665,11 +2665,11 @@ fn test_output_column_deduplication() { } #[test] -fn test_switch() { +fn test_case() { assert_display_snapshot!(compile( r###" from employees - derive display_name = switch [ + derive display_name = case [ nickname != null -> nickname, true -> f'{first_name} {last_name}' ] @@ -2689,7 +2689,7 @@ fn test_switch() { assert_display_snapshot!(compile( r###" from employees - derive display_name = switch [ + derive display_name = case [ nickname != null -> nickname, first_name != null -> f'{first_name} {last_name}' ] @@ -2710,7 +2710,7 @@ fn test_switch() { assert_display_snapshot!(compile( r###" from tracks - select category = switch [ + select category = case [ length > avg_length -> 'long' ] group category (aggregate count) @@ -2781,7 +2781,7 @@ fn test_static_analysis() { a3 = null ?? y, - a3 = switch [ + a3 = case [ false == true -> 1, 7 == 3 -> 2, 7 == y -> 3, diff --git a/prql-compiler/tests/integration/data/chinook/tracks.csv b/prql-compiler/tests/integration/data/chinook/tracks.csv index 60f177ca91b3..66246430590c 100644 --- a/prql-compiler/tests/integration/data/chinook/tracks.csv +++ b/prql-compiler/tests/integration/data/chinook/tracks.csv @@ -2677,7 +2677,7 @@ track_id,name,album_id,media_type_id,genre_id,composer,milliseconds,bytes,unit_p 2676,Intro,217,1,1,Jagger/Richards,49737,1618591,0.99 2677,You Got Me Rocking,217,1,1,Jagger/Richards,205766,6734385,0.99 2678,Gimmie Shelters,217,1,1,Jagger/Richards,382119,12528764,0.99 -2679,Flip The Switch,217,1,1,Jagger/Richards,252421,8336591,0.99 +2679,Flip The Case,217,1,1,Jagger/Richards,252421,8336591,0.99 2680,Memory Motel,217,1,1,Jagger/Richards,365844,11982431,0.99 2681,Corinna,217,1,1,Jesse Ed Davis III/Taj Mahal,257488,8449471,0.99 2682,Saint Of Me,217,1,1,Jagger/Richards,325694,10725160,0.99 diff --git a/prql-compiler/tests/integration/queries/switch.prql b/prql-compiler/tests/integration/queries/switch.prql index 19497776665a..284f61d6202b 100644 --- a/prql-compiler/tests/integration/queries/switch.prql +++ b/prql-compiler/tests/integration/queries/switch.prql @@ -1,6 +1,6 @@ from tracks sort milliseconds -select display = switch [ +select display = case [ composer != null -> composer, genre_id < 17 -> 'no composer', true -> f'unknown composer' diff --git a/prql-compiler/tests/integration/snapshots/integration__tests__test@switch.prql.snap b/prql-compiler/tests/integration/snapshots/integration__tests__test@switch.prql.snap index b53c9cc01eb9..2a9e5eec12b4 100644 --- a/prql-compiler/tests/integration/snapshots/integration__tests__test@switch.prql.snap +++ b/prql-compiler/tests/integration/snapshots/integration__tests__test@switch.prql.snap @@ -1,7 +1,7 @@ --- source: prql-compiler/tests/integration/main.rs expression: sqlite_out -input_file: prql-compiler/tests/integration/queries/switch.prql +input_file: prql-compiler/tests/integration/queries/case.prql --- display,milliseconds Samuel Rosa,1071 diff --git a/prql-lezer/src/prql.grammar b/prql-lezer/src/prql.grammar index 803e6e61a6c0..e599e2f47991 100644 --- a/prql-lezer/src/prql.grammar +++ b/prql-lezer/src/prql.grammar @@ -1,5 +1,5 @@ // TODO: -// - `switch` transform +// - `case` transform // - Do we want to highlight built-in transforms like `from` differently to // normal functions? // - A few small TODOs included below diff --git a/website/content/posts/2023-02-02-one-year/_index.md b/website/content/posts/2023-02-02-one-year/_index.md index 8ec6ef20c85e..c591feb5e7b3 100644 --- a/website/content/posts/2023-02-02-one-year/_index.md +++ b/website/content/posts/2023-02-02-one-year/_index.md @@ -31,7 +31,7 @@ Language design & development in the last year have been focused on these areas: - small quality-of-life language features (e.g. syntax for [f-strings, dates, coalesce operator](https://prql-lang.org/book/syntax.html), - [switch](https://github.com/PRQL/prql/issues/504)), + [case](https://github.com/PRQL/prql/issues/504)), PRQL is now in a state where it can greatly improve the developer experience for writing complex analytical queries, but it does require a bit of fiddling to set diff --git a/website/themes/prql-theme/static/plugins/bootstrap/bootstrap.bundle.min.js b/website/themes/prql-theme/static/plugins/bootstrap/bootstrap.bundle.min.js index 6c0869bc3b2d..be8801f6ab34 100644 --- a/website/themes/prql-theme/static/plugins/bootstrap/bootstrap.bundle.min.js +++ b/website/themes/prql-theme/static/plugins/bootstrap/bootstrap.bundle.min.js @@ -3,5 +3,5 @@ * Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) */ -!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).bootstrap=e()}(this,(function(){"use strict";const t="transitionend",e=t=>{let e=t.getAttribute("data-bs-target");if(!e||"#"===e){let i=t.getAttribute("href");if(!i||!i.includes("#")&&!i.startsWith("."))return null;i.includes("#")&&!i.startsWith("#")&&(i=`#${i.split("#")[1]}`),e=i&&"#"!==i?i.trim():null}return e},i=t=>{const i=e(t);return i&&document.querySelector(i)?i:null},n=t=>{const i=e(t);return i?document.querySelector(i):null},s=e=>{e.dispatchEvent(new Event(t))},o=t=>!(!t||"object"!=typeof t)&&(void 0!==t.jquery&&(t=t[0]),void 0!==t.nodeType),r=t=>o(t)?t.jquery?t[0]:t:"string"==typeof t&&t.length>0?document.querySelector(t):null,a=(t,e,i)=>{Object.keys(i).forEach((n=>{const s=i[n],r=e[n],a=r&&o(r)?"element":null==(l=r)?`${l}`:{}.toString.call(l).match(/\s([a-z]+)/i)[1].toLowerCase();var l;if(!new RegExp(s).test(a))throw new TypeError(`${t.toUpperCase()}: Option "${n}" provided type "${a}" but expected type "${s}".`)}))},l=t=>!(!o(t)||0===t.getClientRects().length)&&"visible"===getComputedStyle(t).getPropertyValue("visibility"),c=t=>!t||t.nodeType!==Node.ELEMENT_NODE||!!t.classList.contains("disabled")||(void 0!==t.disabled?t.disabled:t.hasAttribute("disabled")&&"false"!==t.getAttribute("disabled")),h=t=>{if(!document.documentElement.attachShadow)return null;if("function"==typeof t.getRootNode){const e=t.getRootNode();return e instanceof ShadowRoot?e:null}return t instanceof ShadowRoot?t:t.parentNode?h(t.parentNode):null},d=()=>{},u=t=>{t.offsetHeight},f=()=>{const{jQuery:t}=window;return t&&!document.body.hasAttribute("data-bs-no-jquery")?t:null},p=[],m=()=>"rtl"===document.documentElement.dir,g=t=>{var e;e=()=>{const e=f();if(e){const i=t.NAME,n=e.fn[i];e.fn[i]=t.jQueryInterface,e.fn[i].Constructor=t,e.fn[i].noConflict=()=>(e.fn[i]=n,t.jQueryInterface)}},"loading"===document.readyState?(p.length||document.addEventListener("DOMContentLoaded",(()=>{p.forEach((t=>t()))})),p.push(e)):e()},_=t=>{"function"==typeof t&&t()},b=(e,i,n=!0)=>{if(!n)return void _(e);const o=(t=>{if(!t)return 0;let{transitionDuration:e,transitionDelay:i}=window.getComputedStyle(t);const n=Number.parseFloat(e),s=Number.parseFloat(i);return n||s?(e=e.split(",")[0],i=i.split(",")[0],1e3*(Number.parseFloat(e)+Number.parseFloat(i))):0})(i)+5;let r=!1;const a=({target:n})=>{n===i&&(r=!0,i.removeEventListener(t,a),_(e))};i.addEventListener(t,a),setTimeout((()=>{r||s(i)}),o)},v=(t,e,i,n)=>{let s=t.indexOf(e);if(-1===s)return t[!i&&n?t.length-1:0];const o=t.length;return s+=i?1:-1,n&&(s=(s+o)%o),t[Math.max(0,Math.min(s,o-1))]},y=/[^.]*(?=\..*)\.|.*/,w=/\..*/,E=/::\d+$/,A={};let T=1;const O={mouseenter:"mouseover",mouseleave:"mouseout"},C=/^(mouseenter|mouseleave)/i,k=new Set(["click","dblclick","mouseup","mousedown","contextmenu","mousewheel","DOMMouseScroll","mouseover","mouseout","mousemove","selectstart","selectend","keydown","keypress","keyup","orientationchange","touchstart","touchmove","touchend","touchcancel","pointerdown","pointermove","pointerup","pointerleave","pointercancel","gesturestart","gesturechange","gestureend","focus","blur","change","reset","select","submit","focusin","focusout","load","unload","beforeunload","resize","move","DOMContentLoaded","readystatechange","error","abort","scroll"]);function L(t,e){return e&&`${e}::${T++}`||t.uidEvent||T++}function x(t){const e=L(t);return t.uidEvent=e,A[e]=A[e]||{},A[e]}function D(t,e,i=null){const n=Object.keys(t);for(let s=0,o=n.length;sfunction(e){if(!e.relatedTarget||e.relatedTarget!==e.delegateTarget&&!e.delegateTarget.contains(e.relatedTarget))return t.call(this,e)};n?n=t(n):i=t(i)}const[o,r,a]=S(e,i,n),l=x(t),c=l[a]||(l[a]={}),h=D(c,r,o?i:null);if(h)return void(h.oneOff=h.oneOff&&s);const d=L(r,e.replace(y,"")),u=o?function(t,e,i){return function n(s){const o=t.querySelectorAll(e);for(let{target:r}=s;r&&r!==this;r=r.parentNode)for(let a=o.length;a--;)if(o[a]===r)return s.delegateTarget=r,n.oneOff&&j.off(t,s.type,e,i),i.apply(r,[s]);return null}}(t,i,n):function(t,e){return function i(n){return n.delegateTarget=t,i.oneOff&&j.off(t,n.type,e),e.apply(t,[n])}}(t,i);u.delegationSelector=o?i:null,u.originalHandler=r,u.oneOff=s,u.uidEvent=d,c[d]=u,t.addEventListener(a,u,o)}function I(t,e,i,n,s){const o=D(e[i],n,s);o&&(t.removeEventListener(i,o,Boolean(s)),delete e[i][o.uidEvent])}function P(t){return t=t.replace(w,""),O[t]||t}const j={on(t,e,i,n){N(t,e,i,n,!1)},one(t,e,i,n){N(t,e,i,n,!0)},off(t,e,i,n){if("string"!=typeof e||!t)return;const[s,o,r]=S(e,i,n),a=r!==e,l=x(t),c=e.startsWith(".");if(void 0!==o){if(!l||!l[r])return;return void I(t,l,r,o,s?i:null)}c&&Object.keys(l).forEach((i=>{!function(t,e,i,n){const s=e[i]||{};Object.keys(s).forEach((o=>{if(o.includes(n)){const n=s[o];I(t,e,i,n.originalHandler,n.delegationSelector)}}))}(t,l,i,e.slice(1))}));const h=l[r]||{};Object.keys(h).forEach((i=>{const n=i.replace(E,"");if(!a||e.includes(n)){const e=h[i];I(t,l,r,e.originalHandler,e.delegationSelector)}}))},trigger(t,e,i){if("string"!=typeof e||!t)return null;const n=f(),s=P(e),o=e!==s,r=k.has(s);let a,l=!0,c=!0,h=!1,d=null;return o&&n&&(a=n.Event(e,i),n(t).trigger(a),l=!a.isPropagationStopped(),c=!a.isImmediatePropagationStopped(),h=a.isDefaultPrevented()),r?(d=document.createEvent("HTMLEvents"),d.initEvent(s,l,!0)):d=new CustomEvent(e,{bubbles:l,cancelable:!0}),void 0!==i&&Object.keys(i).forEach((t=>{Object.defineProperty(d,t,{get:()=>i[t]})})),h&&d.preventDefault(),c&&t.dispatchEvent(d),d.defaultPrevented&&void 0!==a&&a.preventDefault(),d}},M=new Map,H={set(t,e,i){M.has(t)||M.set(t,new Map);const n=M.get(t);n.has(e)||0===n.size?n.set(e,i):console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(n.keys())[0]}.`)},get:(t,e)=>M.has(t)&&M.get(t).get(e)||null,remove(t,e){if(!M.has(t))return;const i=M.get(t);i.delete(e),0===i.size&&M.delete(t)}};class B{constructor(t){(t=r(t))&&(this._element=t,H.set(this._element,this.constructor.DATA_KEY,this))}dispose(){H.remove(this._element,this.constructor.DATA_KEY),j.off(this._element,this.constructor.EVENT_KEY),Object.getOwnPropertyNames(this).forEach((t=>{this[t]=null}))}_queueCallback(t,e,i=!0){b(t,e,i)}static getInstance(t){return H.get(r(t),this.DATA_KEY)}static getOrCreateInstance(t,e={}){return this.getInstance(t)||new this(t,"object"==typeof e?e:null)}static get VERSION(){return"5.1.3"}static get NAME(){throw new Error('You have to implement the static method "NAME", for each component!')}static get DATA_KEY(){return`bs.${this.NAME}`}static get EVENT_KEY(){return`.${this.DATA_KEY}`}}const R=(t,e="hide")=>{const i=`click.dismiss${t.EVENT_KEY}`,s=t.NAME;j.on(document,i,`[data-bs-dismiss="${s}"]`,(function(i){if(["A","AREA"].includes(this.tagName)&&i.preventDefault(),c(this))return;const o=n(this)||this.closest(`.${s}`);t.getOrCreateInstance(o)[e]()}))};class W extends B{static get NAME(){return"alert"}close(){if(j.trigger(this._element,"close.bs.alert").defaultPrevented)return;this._element.classList.remove("show");const t=this._element.classList.contains("fade");this._queueCallback((()=>this._destroyElement()),this._element,t)}_destroyElement(){this._element.remove(),j.trigger(this._element,"closed.bs.alert"),this.dispose()}static jQueryInterface(t){return this.each((function(){const e=W.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}R(W,"close"),g(W);const $='[data-bs-toggle="button"]';class z extends B{static get NAME(){return"button"}toggle(){this._element.setAttribute("aria-pressed",this._element.classList.toggle("active"))}static jQueryInterface(t){return this.each((function(){const e=z.getOrCreateInstance(this);"toggle"===t&&e[t]()}))}}function q(t){return"true"===t||"false"!==t&&(t===Number(t).toString()?Number(t):""===t||"null"===t?null:t)}function F(t){return t.replace(/[A-Z]/g,(t=>`-${t.toLowerCase()}`))}j.on(document,"click.bs.button.data-api",$,(t=>{t.preventDefault();const e=t.target.closest($);z.getOrCreateInstance(e).toggle()})),g(z);const U={setDataAttribute(t,e,i){t.setAttribute(`data-bs-${F(e)}`,i)},removeDataAttribute(t,e){t.removeAttribute(`data-bs-${F(e)}`)},getDataAttributes(t){if(!t)return{};const e={};return Object.keys(t.dataset).filter((t=>t.startsWith("bs"))).forEach((i=>{let n=i.replace(/^bs/,"");n=n.charAt(0).toLowerCase()+n.slice(1,n.length),e[n]=q(t.dataset[i])})),e},getDataAttribute:(t,e)=>q(t.getAttribute(`data-bs-${F(e)}`)),offset(t){const e=t.getBoundingClientRect();return{top:e.top+window.pageYOffset,left:e.left+window.pageXOffset}},position:t=>({top:t.offsetTop,left:t.offsetLeft})},V={find:(t,e=document.documentElement)=>[].concat(...Element.prototype.querySelectorAll.call(e,t)),findOne:(t,e=document.documentElement)=>Element.prototype.querySelector.call(e,t),children:(t,e)=>[].concat(...t.children).filter((t=>t.matches(e))),parents(t,e){const i=[];let n=t.parentNode;for(;n&&n.nodeType===Node.ELEMENT_NODE&&3!==n.nodeType;)n.matches(e)&&i.push(n),n=n.parentNode;return i},prev(t,e){let i=t.previousElementSibling;for(;i;){if(i.matches(e))return[i];i=i.previousElementSibling}return[]},next(t,e){let i=t.nextElementSibling;for(;i;){if(i.matches(e))return[i];i=i.nextElementSibling}return[]},focusableChildren(t){const e=["a","button","input","textarea","select","details","[tabindex]",'[contenteditable="true"]'].map((t=>`${t}:not([tabindex^="-"])`)).join(", ");return this.find(e,t).filter((t=>!c(t)&&l(t)))}},K="carousel",X={interval:5e3,keyboard:!0,slide:!1,pause:"hover",wrap:!0,touch:!0},Y={interval:"(number|boolean)",keyboard:"boolean",slide:"(boolean|string)",pause:"(string|boolean)",wrap:"boolean",touch:"boolean"},Q="next",G="prev",Z="left",J="right",tt={ArrowLeft:J,ArrowRight:Z},et="slid.bs.carousel",it="active",nt=".active.carousel-item";class st extends B{constructor(t,e){super(t),this._items=null,this._interval=null,this._activeElement=null,this._isPaused=!1,this._isSliding=!1,this.touchTimeout=null,this.touchStartX=0,this.touchDeltaX=0,this._config=this._getConfig(e),this._indicatorsElement=V.findOne(".carousel-indicators",this._element),this._touchSupported="ontouchstart"in document.documentElement||navigator.maxTouchPoints>0,this._pointerEvent=Boolean(window.PointerEvent),this._addEventListeners()}static get Default(){return X}static get NAME(){return K}next(){this._slide(Q)}nextWhenVisible(){!document.hidden&&l(this._element)&&this.next()}prev(){this._slide(G)}pause(t){t||(this._isPaused=!0),V.findOne(".carousel-item-next, .carousel-item-prev",this._element)&&(s(this._element),this.cycle(!0)),clearInterval(this._interval),this._interval=null}cycle(t){t||(this._isPaused=!1),this._interval&&(clearInterval(this._interval),this._interval=null),this._config&&this._config.interval&&!this._isPaused&&(this._updateInterval(),this._interval=setInterval((document.visibilityState?this.nextWhenVisible:this.next).bind(this),this._config.interval))}to(t){this._activeElement=V.findOne(nt,this._element);const e=this._getItemIndex(this._activeElement);if(t>this._items.length-1||t<0)return;if(this._isSliding)return void j.one(this._element,et,(()=>this.to(t)));if(e===t)return this.pause(),void this.cycle();const i=t>e?Q:G;this._slide(i,this._items[t])}_getConfig(t){return t={...X,...U.getDataAttributes(this._element),..."object"==typeof t?t:{}},a(K,t,Y),t}_handleSwipe(){const t=Math.abs(this.touchDeltaX);if(t<=40)return;const e=t/this.touchDeltaX;this.touchDeltaX=0,e&&this._slide(e>0?J:Z)}_addEventListeners(){this._config.keyboard&&j.on(this._element,"keydown.bs.carousel",(t=>this._keydown(t))),"hover"===this._config.pause&&(j.on(this._element,"mouseenter.bs.carousel",(t=>this.pause(t))),j.on(this._element,"mouseleave.bs.carousel",(t=>this.cycle(t)))),this._config.touch&&this._touchSupported&&this._addTouchEventListeners()}_addTouchEventListeners(){const t=t=>this._pointerEvent&&("pen"===t.pointerType||"touch"===t.pointerType),e=e=>{t(e)?this.touchStartX=e.clientX:this._pointerEvent||(this.touchStartX=e.touches[0].clientX)},i=t=>{this.touchDeltaX=t.touches&&t.touches.length>1?0:t.touches[0].clientX-this.touchStartX},n=e=>{t(e)&&(this.touchDeltaX=e.clientX-this.touchStartX),this._handleSwipe(),"hover"===this._config.pause&&(this.pause(),this.touchTimeout&&clearTimeout(this.touchTimeout),this.touchTimeout=setTimeout((t=>this.cycle(t)),500+this._config.interval))};V.find(".carousel-item img",this._element).forEach((t=>{j.on(t,"dragstart.bs.carousel",(t=>t.preventDefault()))})),this._pointerEvent?(j.on(this._element,"pointerdown.bs.carousel",(t=>e(t))),j.on(this._element,"pointerup.bs.carousel",(t=>n(t))),this._element.classList.add("pointer-event")):(j.on(this._element,"touchstart.bs.carousel",(t=>e(t))),j.on(this._element,"touchmove.bs.carousel",(t=>i(t))),j.on(this._element,"touchend.bs.carousel",(t=>n(t))))}_keydown(t){if(/input|textarea/i.test(t.target.tagName))return;const e=tt[t.key];e&&(t.preventDefault(),this._slide(e))}_getItemIndex(t){return this._items=t&&t.parentNode?V.find(".carousel-item",t.parentNode):[],this._items.indexOf(t)}_getItemByOrder(t,e){const i=t===Q;return v(this._items,e,i,this._config.wrap)}_triggerSlideEvent(t,e){const i=this._getItemIndex(t),n=this._getItemIndex(V.findOne(nt,this._element));return j.trigger(this._element,"slide.bs.carousel",{relatedTarget:t,direction:e,from:n,to:i})}_setActiveIndicatorElement(t){if(this._indicatorsElement){const e=V.findOne(".active",this._indicatorsElement);e.classList.remove(it),e.removeAttribute("aria-current");const i=V.find("[data-bs-target]",this._indicatorsElement);for(let e=0;e{j.trigger(this._element,et,{relatedTarget:o,direction:d,from:s,to:r})};if(this._element.classList.contains("slide")){o.classList.add(h),u(o),n.classList.add(c),o.classList.add(c);const t=()=>{o.classList.remove(c,h),o.classList.add(it),n.classList.remove(it,h,c),this._isSliding=!1,setTimeout(f,0)};this._queueCallback(t,n,!0)}else n.classList.remove(it),o.classList.add(it),this._isSliding=!1,f();a&&this.cycle()}_directionToOrder(t){return[J,Z].includes(t)?m()?t===Z?G:Q:t===Z?Q:G:t}_orderToDirection(t){return[Q,G].includes(t)?m()?t===G?Z:J:t===G?J:Z:t}static carouselInterface(t,e){const i=st.getOrCreateInstance(t,e);let{_config:n}=i;"object"==typeof e&&(n={...n,...e});const s="string"==typeof e?e:n.slide;if("number"==typeof e)i.to(e);else if("string"==typeof s){if(void 0===i[s])throw new TypeError(`No method named "${s}"`);i[s]()}else n.interval&&n.ride&&(i.pause(),i.cycle())}static jQueryInterface(t){return this.each((function(){st.carouselInterface(this,t)}))}static dataApiClickHandler(t){const e=n(this);if(!e||!e.classList.contains("carousel"))return;const i={...U.getDataAttributes(e),...U.getDataAttributes(this)},s=this.getAttribute("data-bs-slide-to");s&&(i.interval=!1),st.carouselInterface(e,i),s&&st.getInstance(e).to(s),t.preventDefault()}}j.on(document,"click.bs.carousel.data-api","[data-bs-slide], [data-bs-slide-to]",st.dataApiClickHandler),j.on(window,"load.bs.carousel.data-api",(()=>{const t=V.find('[data-bs-ride="carousel"]');for(let e=0,i=t.length;et===this._element));null!==s&&o.length&&(this._selector=s,this._triggerArray.push(e))}this._initializeChildren(),this._config.parent||this._addAriaAndCollapsedClass(this._triggerArray,this._isShown()),this._config.toggle&&this.toggle()}static get Default(){return rt}static get NAME(){return ot}toggle(){this._isShown()?this.hide():this.show()}show(){if(this._isTransitioning||this._isShown())return;let t,e=[];if(this._config.parent){const t=V.find(ut,this._config.parent);e=V.find(".collapse.show, .collapse.collapsing",this._config.parent).filter((e=>!t.includes(e)))}const i=V.findOne(this._selector);if(e.length){const n=e.find((t=>i!==t));if(t=n?pt.getInstance(n):null,t&&t._isTransitioning)return}if(j.trigger(this._element,"show.bs.collapse").defaultPrevented)return;e.forEach((e=>{i!==e&&pt.getOrCreateInstance(e,{toggle:!1}).hide(),t||H.set(e,"bs.collapse",null)}));const n=this._getDimension();this._element.classList.remove(ct),this._element.classList.add(ht),this._element.style[n]=0,this._addAriaAndCollapsedClass(this._triggerArray,!0),this._isTransitioning=!0;const s=`scroll${n[0].toUpperCase()+n.slice(1)}`;this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(ht),this._element.classList.add(ct,lt),this._element.style[n]="",j.trigger(this._element,"shown.bs.collapse")}),this._element,!0),this._element.style[n]=`${this._element[s]}px`}hide(){if(this._isTransitioning||!this._isShown())return;if(j.trigger(this._element,"hide.bs.collapse").defaultPrevented)return;const t=this._getDimension();this._element.style[t]=`${this._element.getBoundingClientRect()[t]}px`,u(this._element),this._element.classList.add(ht),this._element.classList.remove(ct,lt);const e=this._triggerArray.length;for(let t=0;t{this._isTransitioning=!1,this._element.classList.remove(ht),this._element.classList.add(ct),j.trigger(this._element,"hidden.bs.collapse")}),this._element,!0)}_isShown(t=this._element){return t.classList.contains(lt)}_getConfig(t){return(t={...rt,...U.getDataAttributes(this._element),...t}).toggle=Boolean(t.toggle),t.parent=r(t.parent),a(ot,t,at),t}_getDimension(){return this._element.classList.contains("collapse-horizontal")?"width":"height"}_initializeChildren(){if(!this._config.parent)return;const t=V.find(ut,this._config.parent);V.find(ft,this._config.parent).filter((e=>!t.includes(e))).forEach((t=>{const e=n(t);e&&this._addAriaAndCollapsedClass([t],this._isShown(e))}))}_addAriaAndCollapsedClass(t,e){t.length&&t.forEach((t=>{e?t.classList.remove(dt):t.classList.add(dt),t.setAttribute("aria-expanded",e)}))}static jQueryInterface(t){return this.each((function(){const e={};"string"==typeof t&&/show|hide/.test(t)&&(e.toggle=!1);const i=pt.getOrCreateInstance(this,e);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t]()}}))}}j.on(document,"click.bs.collapse.data-api",ft,(function(t){("A"===t.target.tagName||t.delegateTarget&&"A"===t.delegateTarget.tagName)&&t.preventDefault();const e=i(this);V.find(e).forEach((t=>{pt.getOrCreateInstance(t,{toggle:!1}).toggle()}))})),g(pt);var mt="top",gt="bottom",_t="right",bt="left",vt="auto",yt=[mt,gt,_t,bt],wt="start",Et="end",At="clippingParents",Tt="viewport",Ot="popper",Ct="reference",kt=yt.reduce((function(t,e){return t.concat([e+"-"+wt,e+"-"+Et])}),[]),Lt=[].concat(yt,[vt]).reduce((function(t,e){return t.concat([e,e+"-"+wt,e+"-"+Et])}),[]),xt="beforeRead",Dt="read",St="afterRead",Nt="beforeMain",It="main",Pt="afterMain",jt="beforeWrite",Mt="write",Ht="afterWrite",Bt=[xt,Dt,St,Nt,It,Pt,jt,Mt,Ht];function Rt(t){return t?(t.nodeName||"").toLowerCase():null}function Wt(t){if(null==t)return window;if("[object Window]"!==t.toString()){var e=t.ownerDocument;return e&&e.defaultView||window}return t}function $t(t){return t instanceof Wt(t).Element||t instanceof Element}function zt(t){return t instanceof Wt(t).HTMLElement||t instanceof HTMLElement}function qt(t){return"undefined"!=typeof ShadowRoot&&(t instanceof Wt(t).ShadowRoot||t instanceof ShadowRoot)}const Ft={name:"applyStyles",enabled:!0,phase:"write",fn:function(t){var e=t.state;Object.keys(e.elements).forEach((function(t){var i=e.styles[t]||{},n=e.attributes[t]||{},s=e.elements[t];zt(s)&&Rt(s)&&(Object.assign(s.style,i),Object.keys(n).forEach((function(t){var e=n[t];!1===e?s.removeAttribute(t):s.setAttribute(t,!0===e?"":e)})))}))},effect:function(t){var e=t.state,i={popper:{position:e.options.strategy,left:"0",top:"0",margin:"0"},arrow:{position:"absolute"},reference:{}};return Object.assign(e.elements.popper.style,i.popper),e.styles=i,e.elements.arrow&&Object.assign(e.elements.arrow.style,i.arrow),function(){Object.keys(e.elements).forEach((function(t){var n=e.elements[t],s=e.attributes[t]||{},o=Object.keys(e.styles.hasOwnProperty(t)?e.styles[t]:i[t]).reduce((function(t,e){return t[e]="",t}),{});zt(n)&&Rt(n)&&(Object.assign(n.style,o),Object.keys(s).forEach((function(t){n.removeAttribute(t)})))}))}},requires:["computeStyles"]};function Ut(t){return t.split("-")[0]}function Vt(t,e){var i=t.getBoundingClientRect();return{width:i.width/1,height:i.height/1,top:i.top/1,right:i.right/1,bottom:i.bottom/1,left:i.left/1,x:i.left/1,y:i.top/1}}function Kt(t){var e=Vt(t),i=t.offsetWidth,n=t.offsetHeight;return Math.abs(e.width-i)<=1&&(i=e.width),Math.abs(e.height-n)<=1&&(n=e.height),{x:t.offsetLeft,y:t.offsetTop,width:i,height:n}}function Xt(t,e){var i=e.getRootNode&&e.getRootNode();if(t.contains(e))return!0;if(i&&qt(i)){var n=e;do{if(n&&t.isSameNode(n))return!0;n=n.parentNode||n.host}while(n)}return!1}function Yt(t){return Wt(t).getComputedStyle(t)}function Qt(t){return["table","td","th"].indexOf(Rt(t))>=0}function Gt(t){return(($t(t)?t.ownerDocument:t.document)||window.document).documentElement}function Zt(t){return"html"===Rt(t)?t:t.assignedSlot||t.parentNode||(qt(t)?t.host:null)||Gt(t)}function Jt(t){return zt(t)&&"fixed"!==Yt(t).position?t.offsetParent:null}function te(t){for(var e=Wt(t),i=Jt(t);i&&Qt(i)&&"static"===Yt(i).position;)i=Jt(i);return i&&("html"===Rt(i)||"body"===Rt(i)&&"static"===Yt(i).position)?e:i||function(t){var e=-1!==navigator.userAgent.toLowerCase().indexOf("firefox");if(-1!==navigator.userAgent.indexOf("Trident")&&zt(t)&&"fixed"===Yt(t).position)return null;for(var i=Zt(t);zt(i)&&["html","body"].indexOf(Rt(i))<0;){var n=Yt(i);if("none"!==n.transform||"none"!==n.perspective||"paint"===n.contain||-1!==["transform","perspective"].indexOf(n.willChange)||e&&"filter"===n.willChange||e&&n.filter&&"none"!==n.filter)return i;i=i.parentNode}return null}(t)||e}function ee(t){return["top","bottom"].indexOf(t)>=0?"x":"y"}var ie=Math.max,ne=Math.min,se=Math.round;function oe(t,e,i){return ie(t,ne(e,i))}function re(t){return Object.assign({},{top:0,right:0,bottom:0,left:0},t)}function ae(t,e){return e.reduce((function(e,i){return e[i]=t,e}),{})}const le={name:"arrow",enabled:!0,phase:"main",fn:function(t){var e,i=t.state,n=t.name,s=t.options,o=i.elements.arrow,r=i.modifiersData.popperOffsets,a=Ut(i.placement),l=ee(a),c=[bt,_t].indexOf(a)>=0?"height":"width";if(o&&r){var h=function(t,e){return re("number"!=typeof(t="function"==typeof t?t(Object.assign({},e.rects,{placement:e.placement})):t)?t:ae(t,yt))}(s.padding,i),d=Kt(o),u="y"===l?mt:bt,f="y"===l?gt:_t,p=i.rects.reference[c]+i.rects.reference[l]-r[l]-i.rects.popper[c],m=r[l]-i.rects.reference[l],g=te(o),_=g?"y"===l?g.clientHeight||0:g.clientWidth||0:0,b=p/2-m/2,v=h[u],y=_-d[c]-h[f],w=_/2-d[c]/2+b,E=oe(v,w,y),A=l;i.modifiersData[n]=((e={})[A]=E,e.centerOffset=E-w,e)}},effect:function(t){var e=t.state,i=t.options.element,n=void 0===i?"[data-popper-arrow]":i;null!=n&&("string"!=typeof n||(n=e.elements.popper.querySelector(n)))&&Xt(e.elements.popper,n)&&(e.elements.arrow=n)},requires:["popperOffsets"],requiresIfExists:["preventOverflow"]};function ce(t){return t.split("-")[1]}var he={top:"auto",right:"auto",bottom:"auto",left:"auto"};function de(t){var e,i=t.popper,n=t.popperRect,s=t.placement,o=t.variation,r=t.offsets,a=t.position,l=t.gpuAcceleration,c=t.adaptive,h=t.roundOffsets,d=!0===h?function(t){var e=t.x,i=t.y,n=window.devicePixelRatio||1;return{x:se(se(e*n)/n)||0,y:se(se(i*n)/n)||0}}(r):"function"==typeof h?h(r):r,u=d.x,f=void 0===u?0:u,p=d.y,m=void 0===p?0:p,g=r.hasOwnProperty("x"),_=r.hasOwnProperty("y"),b=bt,v=mt,y=window;if(c){var w=te(i),E="clientHeight",A="clientWidth";w===Wt(i)&&"static"!==Yt(w=Gt(i)).position&&"absolute"===a&&(E="scrollHeight",A="scrollWidth"),w=w,s!==mt&&(s!==bt&&s!==_t||o!==Et)||(v=gt,m-=w[E]-n.height,m*=l?1:-1),s!==bt&&(s!==mt&&s!==gt||o!==Et)||(b=_t,f-=w[A]-n.width,f*=l?1:-1)}var T,O=Object.assign({position:a},c&&he);return l?Object.assign({},O,((T={})[v]=_?"0":"",T[b]=g?"0":"",T.transform=(y.devicePixelRatio||1)<=1?"translate("+f+"px, "+m+"px)":"translate3d("+f+"px, "+m+"px, 0)",T)):Object.assign({},O,((e={})[v]=_?m+"px":"",e[b]=g?f+"px":"",e.transform="",e))}const ue={name:"computeStyles",enabled:!0,phase:"beforeWrite",fn:function(t){var e=t.state,i=t.options,n=i.gpuAcceleration,s=void 0===n||n,o=i.adaptive,r=void 0===o||o,a=i.roundOffsets,l=void 0===a||a,c={placement:Ut(e.placement),variation:ce(e.placement),popper:e.elements.popper,popperRect:e.rects.popper,gpuAcceleration:s};null!=e.modifiersData.popperOffsets&&(e.styles.popper=Object.assign({},e.styles.popper,de(Object.assign({},c,{offsets:e.modifiersData.popperOffsets,position:e.options.strategy,adaptive:r,roundOffsets:l})))),null!=e.modifiersData.arrow&&(e.styles.arrow=Object.assign({},e.styles.arrow,de(Object.assign({},c,{offsets:e.modifiersData.arrow,position:"absolute",adaptive:!1,roundOffsets:l})))),e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-placement":e.placement})},data:{}};var fe={passive:!0};const pe={name:"eventListeners",enabled:!0,phase:"write",fn:function(){},effect:function(t){var e=t.state,i=t.instance,n=t.options,s=n.scroll,o=void 0===s||s,r=n.resize,a=void 0===r||r,l=Wt(e.elements.popper),c=[].concat(e.scrollParents.reference,e.scrollParents.popper);return o&&c.forEach((function(t){t.addEventListener("scroll",i.update,fe)})),a&&l.addEventListener("resize",i.update,fe),function(){o&&c.forEach((function(t){t.removeEventListener("scroll",i.update,fe)})),a&&l.removeEventListener("resize",i.update,fe)}},data:{}};var me={left:"right",right:"left",bottom:"top",top:"bottom"};function ge(t){return t.replace(/left|right|bottom|top/g,(function(t){return me[t]}))}var _e={start:"end",end:"start"};function be(t){return t.replace(/start|end/g,(function(t){return _e[t]}))}function ve(t){var e=Wt(t);return{scrollLeft:e.pageXOffset,scrollTop:e.pageYOffset}}function ye(t){return Vt(Gt(t)).left+ve(t).scrollLeft}function we(t){var e=Yt(t),i=e.overflow,n=e.overflowX,s=e.overflowY;return/auto|scroll|overlay|hidden/.test(i+s+n)}function Ee(t){return["html","body","#document"].indexOf(Rt(t))>=0?t.ownerDocument.body:zt(t)&&we(t)?t:Ee(Zt(t))}function Ae(t,e){var i;void 0===e&&(e=[]);var n=Ee(t),s=n===(null==(i=t.ownerDocument)?void 0:i.body),o=Wt(n),r=s?[o].concat(o.visualViewport||[],we(n)?n:[]):n,a=e.concat(r);return s?a:a.concat(Ae(Zt(r)))}function Te(t){return Object.assign({},t,{left:t.x,top:t.y,right:t.x+t.width,bottom:t.y+t.height})}function Oe(t,e){return e===Tt?Te(function(t){var e=Wt(t),i=Gt(t),n=e.visualViewport,s=i.clientWidth,o=i.clientHeight,r=0,a=0;return n&&(s=n.width,o=n.height,/^((?!chrome|android).)*safari/i.test(navigator.userAgent)||(r=n.offsetLeft,a=n.offsetTop)),{width:s,height:o,x:r+ye(t),y:a}}(t)):zt(e)?function(t){var e=Vt(t);return e.top=e.top+t.clientTop,e.left=e.left+t.clientLeft,e.bottom=e.top+t.clientHeight,e.right=e.left+t.clientWidth,e.width=t.clientWidth,e.height=t.clientHeight,e.x=e.left,e.y=e.top,e}(e):Te(function(t){var e,i=Gt(t),n=ve(t),s=null==(e=t.ownerDocument)?void 0:e.body,o=ie(i.scrollWidth,i.clientWidth,s?s.scrollWidth:0,s?s.clientWidth:0),r=ie(i.scrollHeight,i.clientHeight,s?s.scrollHeight:0,s?s.clientHeight:0),a=-n.scrollLeft+ye(t),l=-n.scrollTop;return"rtl"===Yt(s||i).direction&&(a+=ie(i.clientWidth,s?s.clientWidth:0)-o),{width:o,height:r,x:a,y:l}}(Gt(t)))}function Ce(t){var e,i=t.reference,n=t.element,s=t.placement,o=s?Ut(s):null,r=s?ce(s):null,a=i.x+i.width/2-n.width/2,l=i.y+i.height/2-n.height/2;switch(o){case mt:e={x:a,y:i.y-n.height};break;case gt:e={x:a,y:i.y+i.height};break;case _t:e={x:i.x+i.width,y:l};break;case bt:e={x:i.x-n.width,y:l};break;default:e={x:i.x,y:i.y}}var c=o?ee(o):null;if(null!=c){var h="y"===c?"height":"width";switch(r){case wt:e[c]=e[c]-(i[h]/2-n[h]/2);break;case Et:e[c]=e[c]+(i[h]/2-n[h]/2)}}return e}function ke(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=void 0===n?t.placement:n,o=i.boundary,r=void 0===o?At:o,a=i.rootBoundary,l=void 0===a?Tt:a,c=i.elementContext,h=void 0===c?Ot:c,d=i.altBoundary,u=void 0!==d&&d,f=i.padding,p=void 0===f?0:f,m=re("number"!=typeof p?p:ae(p,yt)),g=h===Ot?Ct:Ot,_=t.rects.popper,b=t.elements[u?g:h],v=function(t,e,i){var n="clippingParents"===e?function(t){var e=Ae(Zt(t)),i=["absolute","fixed"].indexOf(Yt(t).position)>=0&&zt(t)?te(t):t;return $t(i)?e.filter((function(t){return $t(t)&&Xt(t,i)&&"body"!==Rt(t)})):[]}(t):[].concat(e),s=[].concat(n,[i]),o=s[0],r=s.reduce((function(e,i){var n=Oe(t,i);return e.top=ie(n.top,e.top),e.right=ne(n.right,e.right),e.bottom=ne(n.bottom,e.bottom),e.left=ie(n.left,e.left),e}),Oe(t,o));return r.width=r.right-r.left,r.height=r.bottom-r.top,r.x=r.left,r.y=r.top,r}($t(b)?b:b.contextElement||Gt(t.elements.popper),r,l),y=Vt(t.elements.reference),w=Ce({reference:y,element:_,strategy:"absolute",placement:s}),E=Te(Object.assign({},_,w)),A=h===Ot?E:y,T={top:v.top-A.top+m.top,bottom:A.bottom-v.bottom+m.bottom,left:v.left-A.left+m.left,right:A.right-v.right+m.right},O=t.modifiersData.offset;if(h===Ot&&O){var C=O[s];Object.keys(T).forEach((function(t){var e=[_t,gt].indexOf(t)>=0?1:-1,i=[mt,gt].indexOf(t)>=0?"y":"x";T[t]+=C[i]*e}))}return T}function Le(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=i.boundary,o=i.rootBoundary,r=i.padding,a=i.flipVariations,l=i.allowedAutoPlacements,c=void 0===l?Lt:l,h=ce(n),d=h?a?kt:kt.filter((function(t){return ce(t)===h})):yt,u=d.filter((function(t){return c.indexOf(t)>=0}));0===u.length&&(u=d);var f=u.reduce((function(e,i){return e[i]=ke(t,{placement:i,boundary:s,rootBoundary:o,padding:r})[Ut(i)],e}),{});return Object.keys(f).sort((function(t,e){return f[t]-f[e]}))}const xe={name:"flip",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name;if(!e.modifiersData[n]._skip){for(var s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0===r||r,l=i.fallbackPlacements,c=i.padding,h=i.boundary,d=i.rootBoundary,u=i.altBoundary,f=i.flipVariations,p=void 0===f||f,m=i.allowedAutoPlacements,g=e.options.placement,_=Ut(g),b=l||(_!==g&&p?function(t){if(Ut(t)===vt)return[];var e=ge(t);return[be(t),e,be(e)]}(g):[ge(g)]),v=[g].concat(b).reduce((function(t,i){return t.concat(Ut(i)===vt?Le(e,{placement:i,boundary:h,rootBoundary:d,padding:c,flipVariations:p,allowedAutoPlacements:m}):i)}),[]),y=e.rects.reference,w=e.rects.popper,E=new Map,A=!0,T=v[0],O=0;O=0,D=x?"width":"height",S=ke(e,{placement:C,boundary:h,rootBoundary:d,altBoundary:u,padding:c}),N=x?L?_t:bt:L?gt:mt;y[D]>w[D]&&(N=ge(N));var I=ge(N),P=[];if(o&&P.push(S[k]<=0),a&&P.push(S[N]<=0,S[I]<=0),P.every((function(t){return t}))){T=C,A=!1;break}E.set(C,P)}if(A)for(var j=function(t){var e=v.find((function(e){var i=E.get(e);if(i)return i.slice(0,t).every((function(t){return t}))}));if(e)return T=e,"break"},M=p?3:1;M>0&&"break"!==j(M);M--);e.placement!==T&&(e.modifiersData[n]._skip=!0,e.placement=T,e.reset=!0)}},requiresIfExists:["offset"],data:{_skip:!1}};function De(t,e,i){return void 0===i&&(i={x:0,y:0}),{top:t.top-e.height-i.y,right:t.right-e.width+i.x,bottom:t.bottom-e.height+i.y,left:t.left-e.width-i.x}}function Se(t){return[mt,_t,gt,bt].some((function(e){return t[e]>=0}))}const Ne={name:"hide",enabled:!0,phase:"main",requiresIfExists:["preventOverflow"],fn:function(t){var e=t.state,i=t.name,n=e.rects.reference,s=e.rects.popper,o=e.modifiersData.preventOverflow,r=ke(e,{elementContext:"reference"}),a=ke(e,{altBoundary:!0}),l=De(r,n),c=De(a,s,o),h=Se(l),d=Se(c);e.modifiersData[i]={referenceClippingOffsets:l,popperEscapeOffsets:c,isReferenceHidden:h,hasPopperEscaped:d},e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-reference-hidden":h,"data-popper-escaped":d})}},Ie={name:"offset",enabled:!0,phase:"main",requires:["popperOffsets"],fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.offset,o=void 0===s?[0,0]:s,r=Lt.reduce((function(t,i){return t[i]=function(t,e,i){var n=Ut(t),s=[bt,mt].indexOf(n)>=0?-1:1,o="function"==typeof i?i(Object.assign({},e,{placement:t})):i,r=o[0],a=o[1];return r=r||0,a=(a||0)*s,[bt,_t].indexOf(n)>=0?{x:a,y:r}:{x:r,y:a}}(i,e.rects,o),t}),{}),a=r[e.placement],l=a.x,c=a.y;null!=e.modifiersData.popperOffsets&&(e.modifiersData.popperOffsets.x+=l,e.modifiersData.popperOffsets.y+=c),e.modifiersData[n]=r}},Pe={name:"popperOffsets",enabled:!0,phase:"read",fn:function(t){var e=t.state,i=t.name;e.modifiersData[i]=Ce({reference:e.rects.reference,element:e.rects.popper,strategy:"absolute",placement:e.placement})},data:{}},je={name:"preventOverflow",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0!==r&&r,l=i.boundary,c=i.rootBoundary,h=i.altBoundary,d=i.padding,u=i.tether,f=void 0===u||u,p=i.tetherOffset,m=void 0===p?0:p,g=ke(e,{boundary:l,rootBoundary:c,padding:d,altBoundary:h}),_=Ut(e.placement),b=ce(e.placement),v=!b,y=ee(_),w="x"===y?"y":"x",E=e.modifiersData.popperOffsets,A=e.rects.reference,T=e.rects.popper,O="function"==typeof m?m(Object.assign({},e.rects,{placement:e.placement})):m,C={x:0,y:0};if(E){if(o||a){var k="y"===y?mt:bt,L="y"===y?gt:_t,x="y"===y?"height":"width",D=E[y],S=E[y]+g[k],N=E[y]-g[L],I=f?-T[x]/2:0,P=b===wt?A[x]:T[x],j=b===wt?-T[x]:-A[x],M=e.elements.arrow,H=f&&M?Kt(M):{width:0,height:0},B=e.modifiersData["arrow#persistent"]?e.modifiersData["arrow#persistent"].padding:{top:0,right:0,bottom:0,left:0},R=B[k],W=B[L],$=oe(0,A[x],H[x]),z=v?A[x]/2-I-$-R-O:P-$-R-O,q=v?-A[x]/2+I+$+W+O:j+$+W+O,F=e.elements.arrow&&te(e.elements.arrow),U=F?"y"===y?F.clientTop||0:F.clientLeft||0:0,V=e.modifiersData.offset?e.modifiersData.offset[e.placement][y]:0,K=E[y]+z-V-U,X=E[y]+q-V;if(o){var Y=oe(f?ne(S,K):S,D,f?ie(N,X):N);E[y]=Y,C[y]=Y-D}if(a){var Q="x"===y?mt:bt,G="x"===y?gt:_t,Z=E[w],J=Z+g[Q],tt=Z-g[G],et=oe(f?ne(J,K):J,Z,f?ie(tt,X):tt);E[w]=et,C[w]=et-Z}}e.modifiersData[n]=C}},requiresIfExists:["offset"]};function Me(t,e,i){void 0===i&&(i=!1);var n=zt(e);zt(e)&&function(t){var e=t.getBoundingClientRect();e.width,t.offsetWidth,e.height,t.offsetHeight}(e);var s,o,r=Gt(e),a=Vt(t),l={scrollLeft:0,scrollTop:0},c={x:0,y:0};return(n||!n&&!i)&&(("body"!==Rt(e)||we(r))&&(l=(s=e)!==Wt(s)&&zt(s)?{scrollLeft:(o=s).scrollLeft,scrollTop:o.scrollTop}:ve(s)),zt(e)?((c=Vt(e)).x+=e.clientLeft,c.y+=e.clientTop):r&&(c.x=ye(r))),{x:a.left+l.scrollLeft-c.x,y:a.top+l.scrollTop-c.y,width:a.width,height:a.height}}function He(t){var e=new Map,i=new Set,n=[];function s(t){i.add(t.name),[].concat(t.requires||[],t.requiresIfExists||[]).forEach((function(t){if(!i.has(t)){var n=e.get(t);n&&s(n)}})),n.push(t)}return t.forEach((function(t){e.set(t.name,t)})),t.forEach((function(t){i.has(t.name)||s(t)})),n}var Be={placement:"bottom",modifiers:[],strategy:"absolute"};function Re(){for(var t=arguments.length,e=new Array(t),i=0;ij.on(t,"mouseover",d))),this._element.focus(),this._element.setAttribute("aria-expanded",!0),this._menu.classList.add(Je),this._element.classList.add(Je),j.trigger(this._element,"shown.bs.dropdown",t)}hide(){if(c(this._element)||!this._isShown(this._menu))return;const t={relatedTarget:this._element};this._completeHide(t)}dispose(){this._popper&&this._popper.destroy(),super.dispose()}update(){this._inNavbar=this._detectNavbar(),this._popper&&this._popper.update()}_completeHide(t){j.trigger(this._element,"hide.bs.dropdown",t).defaultPrevented||("ontouchstart"in document.documentElement&&[].concat(...document.body.children).forEach((t=>j.off(t,"mouseover",d))),this._popper&&this._popper.destroy(),this._menu.classList.remove(Je),this._element.classList.remove(Je),this._element.setAttribute("aria-expanded","false"),U.removeDataAttribute(this._menu,"popper"),j.trigger(this._element,"hidden.bs.dropdown",t))}_getConfig(t){if(t={...this.constructor.Default,...U.getDataAttributes(this._element),...t},a(Ue,t,this.constructor.DefaultType),"object"==typeof t.reference&&!o(t.reference)&&"function"!=typeof t.reference.getBoundingClientRect)throw new TypeError(`${Ue.toUpperCase()}: Option "reference" provided type "object" without a required "getBoundingClientRect" method.`);return t}_createPopper(t){if(void 0===Fe)throw new TypeError("Bootstrap's dropdowns require Popper (https://popper.js.org)");let e=this._element;"parent"===this._config.reference?e=t:o(this._config.reference)?e=r(this._config.reference):"object"==typeof this._config.reference&&(e=this._config.reference);const i=this._getPopperConfig(),n=i.modifiers.find((t=>"applyStyles"===t.name&&!1===t.enabled));this._popper=qe(e,this._menu,i),n&&U.setDataAttribute(this._menu,"popper","static")}_isShown(t=this._element){return t.classList.contains(Je)}_getMenuElement(){return V.next(this._element,ei)[0]}_getPlacement(){const t=this._element.parentNode;if(t.classList.contains("dropend"))return ri;if(t.classList.contains("dropstart"))return ai;const e="end"===getComputedStyle(this._menu).getPropertyValue("--bs-position").trim();return t.classList.contains("dropup")?e?ni:ii:e?oi:si}_detectNavbar(){return null!==this._element.closest(".navbar")}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map((t=>Number.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_getPopperConfig(){const t={placement:this._getPlacement(),modifiers:[{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"offset",options:{offset:this._getOffset()}}]};return"static"===this._config.display&&(t.modifiers=[{name:"applyStyles",enabled:!1}]),{...t,..."function"==typeof this._config.popperConfig?this._config.popperConfig(t):this._config.popperConfig}}_selectMenuItem({key:t,target:e}){const i=V.find(".dropdown-menu .dropdown-item:not(.disabled):not(:disabled)",this._menu).filter(l);i.length&&v(i,e,t===Ye,!i.includes(e)).focus()}static jQueryInterface(t){return this.each((function(){const e=hi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}static clearMenus(t){if(t&&(2===t.button||"keyup"===t.type&&"Tab"!==t.key))return;const e=V.find(ti);for(let i=0,n=e.length;ie+t)),this._setElementAttributes(di,"paddingRight",(e=>e+t)),this._setElementAttributes(ui,"marginRight",(e=>e-t))}_disableOverFlow(){this._saveInitialAttribute(this._element,"overflow"),this._element.style.overflow="hidden"}_setElementAttributes(t,e,i){const n=this.getWidth();this._applyManipulationCallback(t,(t=>{if(t!==this._element&&window.innerWidth>t.clientWidth+n)return;this._saveInitialAttribute(t,e);const s=window.getComputedStyle(t)[e];t.style[e]=`${i(Number.parseFloat(s))}px`}))}reset(){this._resetElementAttributes(this._element,"overflow"),this._resetElementAttributes(this._element,"paddingRight"),this._resetElementAttributes(di,"paddingRight"),this._resetElementAttributes(ui,"marginRight")}_saveInitialAttribute(t,e){const i=t.style[e];i&&U.setDataAttribute(t,e,i)}_resetElementAttributes(t,e){this._applyManipulationCallback(t,(t=>{const i=U.getDataAttribute(t,e);void 0===i?t.style.removeProperty(e):(U.removeDataAttribute(t,e),t.style[e]=i)}))}_applyManipulationCallback(t,e){o(t)?e(t):V.find(t,this._element).forEach(e)}isOverflowing(){return this.getWidth()>0}}const pi={className:"modal-backdrop",isVisible:!0,isAnimated:!1,rootElement:"body",clickCallback:null},mi={className:"string",isVisible:"boolean",isAnimated:"boolean",rootElement:"(element|string)",clickCallback:"(function|null)"},gi="show",_i="mousedown.bs.backdrop";class bi{constructor(t){this._config=this._getConfig(t),this._isAppended=!1,this._element=null}show(t){this._config.isVisible?(this._append(),this._config.isAnimated&&u(this._getElement()),this._getElement().classList.add(gi),this._emulateAnimation((()=>{_(t)}))):_(t)}hide(t){this._config.isVisible?(this._getElement().classList.remove(gi),this._emulateAnimation((()=>{this.dispose(),_(t)}))):_(t)}_getElement(){if(!this._element){const t=document.createElement("div");t.className=this._config.className,this._config.isAnimated&&t.classList.add("fade"),this._element=t}return this._element}_getConfig(t){return(t={...pi,..."object"==typeof t?t:{}}).rootElement=r(t.rootElement),a("backdrop",t,mi),t}_append(){this._isAppended||(this._config.rootElement.append(this._getElement()),j.on(this._getElement(),_i,(()=>{_(this._config.clickCallback)})),this._isAppended=!0)}dispose(){this._isAppended&&(j.off(this._element,_i),this._element.remove(),this._isAppended=!1)}_emulateAnimation(t){b(t,this._getElement(),this._config.isAnimated)}}const vi={trapElement:null,autofocus:!0},yi={trapElement:"element",autofocus:"boolean"},wi=".bs.focustrap",Ei="backward";class Ai{constructor(t){this._config=this._getConfig(t),this._isActive=!1,this._lastTabNavDirection=null}activate(){const{trapElement:t,autofocus:e}=this._config;this._isActive||(e&&t.focus(),j.off(document,wi),j.on(document,"focusin.bs.focustrap",(t=>this._handleFocusin(t))),j.on(document,"keydown.tab.bs.focustrap",(t=>this._handleKeydown(t))),this._isActive=!0)}deactivate(){this._isActive&&(this._isActive=!1,j.off(document,wi))}_handleFocusin(t){const{target:e}=t,{trapElement:i}=this._config;if(e===document||e===i||i.contains(e))return;const n=V.focusableChildren(i);0===n.length?i.focus():this._lastTabNavDirection===Ei?n[n.length-1].focus():n[0].focus()}_handleKeydown(t){"Tab"===t.key&&(this._lastTabNavDirection=t.shiftKey?Ei:"forward")}_getConfig(t){return t={...vi,..."object"==typeof t?t:{}},a("focustrap",t,yi),t}}const Ti="modal",Oi="Escape",Ci={backdrop:!0,keyboard:!0,focus:!0},ki={backdrop:"(boolean|string)",keyboard:"boolean",focus:"boolean"},Li="hidden.bs.modal",xi="show.bs.modal",Di="resize.bs.modal",Si="click.dismiss.bs.modal",Ni="keydown.dismiss.bs.modal",Ii="mousedown.dismiss.bs.modal",Pi="modal-open",ji="show",Mi="modal-static";class Hi extends B{constructor(t,e){super(t),this._config=this._getConfig(e),this._dialog=V.findOne(".modal-dialog",this._element),this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._isShown=!1,this._ignoreBackdropClick=!1,this._isTransitioning=!1,this._scrollBar=new fi}static get Default(){return Ci}static get NAME(){return Ti}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||this._isTransitioning||j.trigger(this._element,xi,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._isAnimated()&&(this._isTransitioning=!0),this._scrollBar.hide(),document.body.classList.add(Pi),this._adjustDialog(),this._setEscapeEvent(),this._setResizeEvent(),j.on(this._dialog,Ii,(()=>{j.one(this._element,"mouseup.dismiss.bs.modal",(t=>{t.target===this._element&&(this._ignoreBackdropClick=!0)}))})),this._showBackdrop((()=>this._showElement(t))))}hide(){if(!this._isShown||this._isTransitioning)return;if(j.trigger(this._element,"hide.bs.modal").defaultPrevented)return;this._isShown=!1;const t=this._isAnimated();t&&(this._isTransitioning=!0),this._setEscapeEvent(),this._setResizeEvent(),this._focustrap.deactivate(),this._element.classList.remove(ji),j.off(this._element,Si),j.off(this._dialog,Ii),this._queueCallback((()=>this._hideModal()),this._element,t)}dispose(){[window,this._dialog].forEach((t=>j.off(t,".bs.modal"))),this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}handleUpdate(){this._adjustDialog()}_initializeBackDrop(){return new bi({isVisible:Boolean(this._config.backdrop),isAnimated:this._isAnimated()})}_initializeFocusTrap(){return new Ai({trapElement:this._element})}_getConfig(t){return t={...Ci,...U.getDataAttributes(this._element),..."object"==typeof t?t:{}},a(Ti,t,ki),t}_showElement(t){const e=this._isAnimated(),i=V.findOne(".modal-body",this._dialog);this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE||document.body.append(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.scrollTop=0,i&&(i.scrollTop=0),e&&u(this._element),this._element.classList.add(ji),this._queueCallback((()=>{this._config.focus&&this._focustrap.activate(),this._isTransitioning=!1,j.trigger(this._element,"shown.bs.modal",{relatedTarget:t})}),this._dialog,e)}_setEscapeEvent(){this._isShown?j.on(this._element,Ni,(t=>{this._config.keyboard&&t.key===Oi?(t.preventDefault(),this.hide()):this._config.keyboard||t.key!==Oi||this._triggerBackdropTransition()})):j.off(this._element,Ni)}_setResizeEvent(){this._isShown?j.on(window,Di,(()=>this._adjustDialog())):j.off(window,Di)}_hideModal(){this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._isTransitioning=!1,this._backdrop.hide((()=>{document.body.classList.remove(Pi),this._resetAdjustments(),this._scrollBar.reset(),j.trigger(this._element,Li)}))}_showBackdrop(t){j.on(this._element,Si,(t=>{this._ignoreBackdropClick?this._ignoreBackdropClick=!1:t.target===t.currentTarget&&(!0===this._config.backdrop?this.hide():"static"===this._config.backdrop&&this._triggerBackdropTransition())})),this._backdrop.show(t)}_isAnimated(){return this._element.classList.contains("fade")}_triggerBackdropTransition(){if(j.trigger(this._element,"hidePrevented.bs.modal").defaultPrevented)return;const{classList:t,scrollHeight:e,style:i}=this._element,n=e>document.documentElement.clientHeight;!n&&"hidden"===i.overflowY||t.contains(Mi)||(n||(i.overflowY="hidden"),t.add(Mi),this._queueCallback((()=>{t.remove(Mi),n||this._queueCallback((()=>{i.overflowY=""}),this._dialog)}),this._dialog),this._element.focus())}_adjustDialog(){const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._scrollBar.getWidth(),i=e>0;(!i&&t&&!m()||i&&!t&&m())&&(this._element.style.paddingLeft=`${e}px`),(i&&!t&&!m()||!i&&t&&m())&&(this._element.style.paddingRight=`${e}px`)}_resetAdjustments(){this._element.style.paddingLeft="",this._element.style.paddingRight=""}static jQueryInterface(t,e){return this.each((function(){const i=Hi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t](e)}}))}}j.on(document,"click.bs.modal.data-api",'[data-bs-toggle="modal"]',(function(t){const e=n(this);["A","AREA"].includes(this.tagName)&&t.preventDefault(),j.one(e,xi,(t=>{t.defaultPrevented||j.one(e,Li,(()=>{l(this)&&this.focus()}))}));const i=V.findOne(".modal.show");i&&Hi.getInstance(i).hide(),Hi.getOrCreateInstance(e).toggle(this)})),R(Hi),g(Hi);const Bi="offcanvas",Ri={backdrop:!0,keyboard:!0,scroll:!1},Wi={backdrop:"boolean",keyboard:"boolean",scroll:"boolean"},$i="show",zi=".offcanvas.show",qi="hidden.bs.offcanvas";class Fi extends B{constructor(t,e){super(t),this._config=this._getConfig(e),this._isShown=!1,this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._addEventListeners()}static get NAME(){return Bi}static get Default(){return Ri}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||j.trigger(this._element,"show.bs.offcanvas",{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._element.style.visibility="visible",this._backdrop.show(),this._config.scroll||(new fi).hide(),this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.classList.add($i),this._queueCallback((()=>{this._config.scroll||this._focustrap.activate(),j.trigger(this._element,"shown.bs.offcanvas",{relatedTarget:t})}),this._element,!0))}hide(){this._isShown&&(j.trigger(this._element,"hide.bs.offcanvas").defaultPrevented||(this._focustrap.deactivate(),this._element.blur(),this._isShown=!1,this._element.classList.remove($i),this._backdrop.hide(),this._queueCallback((()=>{this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._element.style.visibility="hidden",this._config.scroll||(new fi).reset(),j.trigger(this._element,qi)}),this._element,!0)))}dispose(){this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}_getConfig(t){return t={...Ri,...U.getDataAttributes(this._element),..."object"==typeof t?t:{}},a(Bi,t,Wi),t}_initializeBackDrop(){return new bi({className:"offcanvas-backdrop",isVisible:this._config.backdrop,isAnimated:!0,rootElement:this._element.parentNode,clickCallback:()=>this.hide()})}_initializeFocusTrap(){return new Ai({trapElement:this._element})}_addEventListeners(){j.on(this._element,"keydown.dismiss.bs.offcanvas",(t=>{this._config.keyboard&&"Escape"===t.key&&this.hide()}))}static jQueryInterface(t){return this.each((function(){const e=Fi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}j.on(document,"click.bs.offcanvas.data-api",'[data-bs-toggle="offcanvas"]',(function(t){const e=n(this);if(["A","AREA"].includes(this.tagName)&&t.preventDefault(),c(this))return;j.one(e,qi,(()=>{l(this)&&this.focus()}));const i=V.findOne(zi);i&&i!==e&&Fi.getInstance(i).hide(),Fi.getOrCreateInstance(e).toggle(this)})),j.on(window,"load.bs.offcanvas.data-api",(()=>V.find(zi).forEach((t=>Fi.getOrCreateInstance(t).show())))),R(Fi),g(Fi);const Ui=new Set(["background","cite","href","itemtype","longdesc","poster","src","xlink:href"]),Vi=/^(?:(?:https?|mailto|ftp|tel|file|sms):|[^#&/:?]*(?:[#/?]|$))/i,Ki=/^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[\d+/a-z]+=*$/i,Xi=(t,e)=>{const i=t.nodeName.toLowerCase();if(e.includes(i))return!Ui.has(i)||Boolean(Vi.test(t.nodeValue)||Ki.test(t.nodeValue));const n=e.filter((t=>t instanceof RegExp));for(let t=0,e=n.length;t{Xi(t,r)||i.removeAttribute(t.nodeName)}))}return n.body.innerHTML}const Qi="tooltip",Gi=new Set(["sanitize","allowList","sanitizeFn"]),Zi={animation:"boolean",template:"string",title:"(string|element|function)",trigger:"string",delay:"(number|object)",html:"boolean",selector:"(string|boolean)",placement:"(string|function)",offset:"(array|string|function)",container:"(string|element|boolean)",fallbackPlacements:"array",boundary:"(string|element)",customClass:"(string|function)",sanitize:"boolean",sanitizeFn:"(null|function)",allowList:"object",popperConfig:"(null|object|function)"},Ji={AUTO:"auto",TOP:"top",RIGHT:m()?"left":"right",BOTTOM:"bottom",LEFT:m()?"right":"left"},tn={animation:!0,template:'',trigger:"hover focus",title:"",delay:0,html:!1,selector:!1,placement:"top",offset:[0,0],container:!1,fallbackPlacements:["top","right","bottom","left"],boundary:"clippingParents",customClass:"",sanitize:!0,sanitizeFn:null,allowList:{"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],div:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","srcset","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},popperConfig:null},en={HIDE:"hide.bs.tooltip",HIDDEN:"hidden.bs.tooltip",SHOW:"show.bs.tooltip",SHOWN:"shown.bs.tooltip",INSERTED:"inserted.bs.tooltip",CLICK:"click.bs.tooltip",FOCUSIN:"focusin.bs.tooltip",FOCUSOUT:"focusout.bs.tooltip",MOUSEENTER:"mouseenter.bs.tooltip",MOUSELEAVE:"mouseleave.bs.tooltip"},nn="fade",sn="show",on="show",rn="out",an=".tooltip-inner",ln=".modal",cn="hide.bs.modal",hn="hover",dn="focus";class un extends B{constructor(t,e){if(void 0===Fe)throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org)");super(t),this._isEnabled=!0,this._timeout=0,this._hoverState="",this._activeTrigger={},this._popper=null,this._config=this._getConfig(e),this.tip=null,this._setListeners()}static get Default(){return tn}static get NAME(){return Qi}static get Event(){return en}static get DefaultType(){return Zi}enable(){this._isEnabled=!0}disable(){this._isEnabled=!1}toggleEnabled(){this._isEnabled=!this._isEnabled}toggle(t){if(this._isEnabled)if(t){const e=this._initializeOnDelegatedTarget(t);e._activeTrigger.click=!e._activeTrigger.click,e._isWithActiveTrigger()?e._enter(null,e):e._leave(null,e)}else{if(this.getTipElement().classList.contains(sn))return void this._leave(null,this);this._enter(null,this)}}dispose(){clearTimeout(this._timeout),j.off(this._element.closest(ln),cn,this._hideModalHandler),this.tip&&this.tip.remove(),this._disposePopper(),super.dispose()}show(){if("none"===this._element.style.display)throw new Error("Please use show on visible elements");if(!this.isWithContent()||!this._isEnabled)return;const t=j.trigger(this._element,this.constructor.Event.SHOW),e=h(this._element),i=null===e?this._element.ownerDocument.documentElement.contains(this._element):e.contains(this._element);if(t.defaultPrevented||!i)return;"tooltip"===this.constructor.NAME&&this.tip&&this.getTitle()!==this.tip.querySelector(an).innerHTML&&(this._disposePopper(),this.tip.remove(),this.tip=null);const n=this.getTipElement(),s=(t=>{do{t+=Math.floor(1e6*Math.random())}while(document.getElementById(t));return t})(this.constructor.NAME);n.setAttribute("id",s),this._element.setAttribute("aria-describedby",s),this._config.animation&&n.classList.add(nn);const o="function"==typeof this._config.placement?this._config.placement.call(this,n,this._element):this._config.placement,r=this._getAttachment(o);this._addAttachmentClass(r);const{container:a}=this._config;H.set(n,this.constructor.DATA_KEY,this),this._element.ownerDocument.documentElement.contains(this.tip)||(a.append(n),j.trigger(this._element,this.constructor.Event.INSERTED)),this._popper?this._popper.update():this._popper=qe(this._element,n,this._getPopperConfig(r)),n.classList.add(sn);const l=this._resolvePossibleFunction(this._config.customClass);l&&n.classList.add(...l.split(" ")),"ontouchstart"in document.documentElement&&[].concat(...document.body.children).forEach((t=>{j.on(t,"mouseover",d)}));const c=this.tip.classList.contains(nn);this._queueCallback((()=>{const t=this._hoverState;this._hoverState=null,j.trigger(this._element,this.constructor.Event.SHOWN),t===rn&&this._leave(null,this)}),this.tip,c)}hide(){if(!this._popper)return;const t=this.getTipElement();if(j.trigger(this._element,this.constructor.Event.HIDE).defaultPrevented)return;t.classList.remove(sn),"ontouchstart"in document.documentElement&&[].concat(...document.body.children).forEach((t=>j.off(t,"mouseover",d))),this._activeTrigger.click=!1,this._activeTrigger.focus=!1,this._activeTrigger.hover=!1;const e=this.tip.classList.contains(nn);this._queueCallback((()=>{this._isWithActiveTrigger()||(this._hoverState!==on&&t.remove(),this._cleanTipClass(),this._element.removeAttribute("aria-describedby"),j.trigger(this._element,this.constructor.Event.HIDDEN),this._disposePopper())}),this.tip,e),this._hoverState=""}update(){null!==this._popper&&this._popper.update()}isWithContent(){return Boolean(this.getTitle())}getTipElement(){if(this.tip)return this.tip;const t=document.createElement("div");t.innerHTML=this._config.template;const e=t.children[0];return this.setContent(e),e.classList.remove(nn,sn),this.tip=e,this.tip}setContent(t){this._sanitizeAndSetContent(t,this.getTitle(),an)}_sanitizeAndSetContent(t,e,i){const n=V.findOne(i,t);e||!n?this.setElementContent(n,e):n.remove()}setElementContent(t,e){if(null!==t)return o(e)?(e=r(e),void(this._config.html?e.parentNode!==t&&(t.innerHTML="",t.append(e)):t.textContent=e.textContent)):void(this._config.html?(this._config.sanitize&&(e=Yi(e,this._config.allowList,this._config.sanitizeFn)),t.innerHTML=e):t.textContent=e)}getTitle(){const t=this._element.getAttribute("data-bs-original-title")||this._config.title;return this._resolvePossibleFunction(t)}updateAttachment(t){return"right"===t?"end":"left"===t?"start":t}_initializeOnDelegatedTarget(t,e){return e||this.constructor.getOrCreateInstance(t.delegateTarget,this._getDelegateConfig())}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map((t=>Number.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_resolvePossibleFunction(t){return"function"==typeof t?t.call(this._element):t}_getPopperConfig(t){const e={placement:t,modifiers:[{name:"flip",options:{fallbackPlacements:this._config.fallbackPlacements}},{name:"offset",options:{offset:this._getOffset()}},{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"arrow",options:{element:`.${this.constructor.NAME}-arrow`}},{name:"onChange",enabled:!0,phase:"afterWrite",fn:t=>this._handlePopperPlacementChange(t)}],onFirstUpdate:t=>{t.options.placement!==t.placement&&this._handlePopperPlacementChange(t)}};return{...e,..."function"==typeof this._config.popperConfig?this._config.popperConfig(e):this._config.popperConfig}}_addAttachmentClass(t){this.getTipElement().classList.add(`${this._getBasicClassPrefix()}-${this.updateAttachment(t)}`)}_getAttachment(t){return Ji[t.toUpperCase()]}_setListeners(){this._config.trigger.split(" ").forEach((t=>{if("click"===t)j.on(this._element,this.constructor.Event.CLICK,this._config.selector,(t=>this.toggle(t)));else if("manual"!==t){const e=t===hn?this.constructor.Event.MOUSEENTER:this.constructor.Event.FOCUSIN,i=t===hn?this.constructor.Event.MOUSELEAVE:this.constructor.Event.FOCUSOUT;j.on(this._element,e,this._config.selector,(t=>this._enter(t))),j.on(this._element,i,this._config.selector,(t=>this._leave(t)))}})),this._hideModalHandler=()=>{this._element&&this.hide()},j.on(this._element.closest(ln),cn,this._hideModalHandler),this._config.selector?this._config={...this._config,trigger:"manual",selector:""}:this._fixTitle()}_fixTitle(){const t=this._element.getAttribute("title"),e=typeof this._element.getAttribute("data-bs-original-title");(t||"string"!==e)&&(this._element.setAttribute("data-bs-original-title",t||""),!t||this._element.getAttribute("aria-label")||this._element.textContent||this._element.setAttribute("aria-label",t),this._element.setAttribute("title",""))}_enter(t,e){e=this._initializeOnDelegatedTarget(t,e),t&&(e._activeTrigger["focusin"===t.type?dn:hn]=!0),e.getTipElement().classList.contains(sn)||e._hoverState===on?e._hoverState=on:(clearTimeout(e._timeout),e._hoverState=on,e._config.delay&&e._config.delay.show?e._timeout=setTimeout((()=>{e._hoverState===on&&e.show()}),e._config.delay.show):e.show())}_leave(t,e){e=this._initializeOnDelegatedTarget(t,e),t&&(e._activeTrigger["focusout"===t.type?dn:hn]=e._element.contains(t.relatedTarget)),e._isWithActiveTrigger()||(clearTimeout(e._timeout),e._hoverState=rn,e._config.delay&&e._config.delay.hide?e._timeout=setTimeout((()=>{e._hoverState===rn&&e.hide()}),e._config.delay.hide):e.hide())}_isWithActiveTrigger(){for(const t in this._activeTrigger)if(this._activeTrigger[t])return!0;return!1}_getConfig(t){const e=U.getDataAttributes(this._element);return Object.keys(e).forEach((t=>{Gi.has(t)&&delete e[t]})),(t={...this.constructor.Default,...e,..."object"==typeof t&&t?t:{}}).container=!1===t.container?document.body:r(t.container),"number"==typeof t.delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),a(Qi,t,this.constructor.DefaultType),t.sanitize&&(t.template=Yi(t.template,t.allowList,t.sanitizeFn)),t}_getDelegateConfig(){const t={};for(const e in this._config)this.constructor.Default[e]!==this._config[e]&&(t[e]=this._config[e]);return t}_cleanTipClass(){const t=this.getTipElement(),e=new RegExp(`(^|\\s)${this._getBasicClassPrefix()}\\S+`,"g"),i=t.getAttribute("class").match(e);null!==i&&i.length>0&&i.map((t=>t.trim())).forEach((e=>t.classList.remove(e)))}_getBasicClassPrefix(){return"bs-tooltip"}_handlePopperPlacementChange(t){const{state:e}=t;e&&(this.tip=e.elements.popper,this._cleanTipClass(),this._addAttachmentClass(this._getAttachment(e.placement)))}_disposePopper(){this._popper&&(this._popper.destroy(),this._popper=null)}static jQueryInterface(t){return this.each((function(){const e=un.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}g(un);const fn={...un.Default,placement:"right",offset:[0,8],trigger:"click",content:"",template:''},pn={...un.DefaultType,content:"(string|element|function)"},mn={HIDE:"hide.bs.popover",HIDDEN:"hidden.bs.popover",SHOW:"show.bs.popover",SHOWN:"shown.bs.popover",INSERTED:"inserted.bs.popover",CLICK:"click.bs.popover",FOCUSIN:"focusin.bs.popover",FOCUSOUT:"focusout.bs.popover",MOUSEENTER:"mouseenter.bs.popover",MOUSELEAVE:"mouseleave.bs.popover"};class gn extends un{static get Default(){return fn}static get NAME(){return"popover"}static get Event(){return mn}static get DefaultType(){return pn}isWithContent(){return this.getTitle()||this._getContent()}setContent(t){this._sanitizeAndSetContent(t,this.getTitle(),".popover-header"),this._sanitizeAndSetContent(t,this._getContent(),".popover-body")}_getContent(){return this._resolvePossibleFunction(this._config.content)}_getBasicClassPrefix(){return"bs-popover"}static jQueryInterface(t){return this.each((function(){const e=gn.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}g(gn);const _n="scrollspy",bn={offset:10,method:"auto",target:""},vn={offset:"number",method:"string",target:"(string|element)"},yn="active",wn=".nav-link, .list-group-item, .dropdown-item",En="position";class An extends B{constructor(t,e){super(t),this._scrollElement="BODY"===this._element.tagName?window:this._element,this._config=this._getConfig(e),this._offsets=[],this._targets=[],this._activeTarget=null,this._scrollHeight=0,j.on(this._scrollElement,"scroll.bs.scrollspy",(()=>this._process())),this.refresh(),this._process()}static get Default(){return bn}static get NAME(){return _n}refresh(){const t=this._scrollElement===this._scrollElement.window?"offset":En,e="auto"===this._config.method?t:this._config.method,n=e===En?this._getScrollTop():0;this._offsets=[],this._targets=[],this._scrollHeight=this._getScrollHeight(),V.find(wn,this._config.target).map((t=>{const s=i(t),o=s?V.findOne(s):null;if(o){const t=o.getBoundingClientRect();if(t.width||t.height)return[U[e](o).top+n,s]}return null})).filter((t=>t)).sort(((t,e)=>t[0]-e[0])).forEach((t=>{this._offsets.push(t[0]),this._targets.push(t[1])}))}dispose(){j.off(this._scrollElement,".bs.scrollspy"),super.dispose()}_getConfig(t){return(t={...bn,...U.getDataAttributes(this._element),..."object"==typeof t&&t?t:{}}).target=r(t.target)||document.documentElement,a(_n,t,vn),t}_getScrollTop(){return this._scrollElement===window?this._scrollElement.pageYOffset:this._scrollElement.scrollTop}_getScrollHeight(){return this._scrollElement.scrollHeight||Math.max(document.body.scrollHeight,document.documentElement.scrollHeight)}_getOffsetHeight(){return this._scrollElement===window?window.innerHeight:this._scrollElement.getBoundingClientRect().height}_process(){const t=this._getScrollTop()+this._config.offset,e=this._getScrollHeight(),i=this._config.offset+e-this._getOffsetHeight();if(this._scrollHeight!==e&&this.refresh(),t>=i){const t=this._targets[this._targets.length-1];this._activeTarget!==t&&this._activate(t)}else{if(this._activeTarget&&t0)return this._activeTarget=null,void this._clear();for(let e=this._offsets.length;e--;)this._activeTarget!==this._targets[e]&&t>=this._offsets[e]&&(void 0===this._offsets[e+1]||t`${e}[data-bs-target="${t}"],${e}[href="${t}"]`)),i=V.findOne(e.join(","),this._config.target);i.classList.add(yn),i.classList.contains("dropdown-item")?V.findOne(".dropdown-toggle",i.closest(".dropdown")).classList.add(yn):V.parents(i,".nav, .list-group").forEach((t=>{V.prev(t,".nav-link, .list-group-item").forEach((t=>t.classList.add(yn))),V.prev(t,".nav-item").forEach((t=>{V.children(t,".nav-link").forEach((t=>t.classList.add(yn)))}))})),j.trigger(this._scrollElement,"activate.bs.scrollspy",{relatedTarget:t})}_clear(){V.find(wn,this._config.target).filter((t=>t.classList.contains(yn))).forEach((t=>t.classList.remove(yn)))}static jQueryInterface(t){return this.each((function(){const e=An.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}j.on(window,"load.bs.scrollspy.data-api",(()=>{V.find('[data-bs-spy="scroll"]').forEach((t=>new An(t)))})),g(An);const Tn="active",On="fade",Cn="show",kn=".active",Ln=":scope > li > .active";class xn extends B{static get NAME(){return"tab"}show(){if(this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE&&this._element.classList.contains(Tn))return;let t;const e=n(this._element),i=this._element.closest(".nav, .list-group");if(i){const e="UL"===i.nodeName||"OL"===i.nodeName?Ln:kn;t=V.find(e,i),t=t[t.length-1]}const s=t?j.trigger(t,"hide.bs.tab",{relatedTarget:this._element}):null;if(j.trigger(this._element,"show.bs.tab",{relatedTarget:t}).defaultPrevented||null!==s&&s.defaultPrevented)return;this._activate(this._element,i);const o=()=>{j.trigger(t,"hidden.bs.tab",{relatedTarget:this._element}),j.trigger(this._element,"shown.bs.tab",{relatedTarget:t})};e?this._activate(e,e.parentNode,o):o()}_activate(t,e,i){const n=(!e||"UL"!==e.nodeName&&"OL"!==e.nodeName?V.children(e,kn):V.find(Ln,e))[0],s=i&&n&&n.classList.contains(On),o=()=>this._transitionComplete(t,n,i);n&&s?(n.classList.remove(Cn),this._queueCallback(o,t,!0)):o()}_transitionComplete(t,e,i){if(e){e.classList.remove(Tn);const t=V.findOne(":scope > .dropdown-menu .active",e.parentNode);t&&t.classList.remove(Tn),"tab"===e.getAttribute("role")&&e.setAttribute("aria-selected",!1)}t.classList.add(Tn),"tab"===t.getAttribute("role")&&t.setAttribute("aria-selected",!0),u(t),t.classList.contains(On)&&t.classList.add(Cn);let n=t.parentNode;if(n&&"LI"===n.nodeName&&(n=n.parentNode),n&&n.classList.contains("dropdown-menu")){const e=t.closest(".dropdown");e&&V.find(".dropdown-toggle",e).forEach((t=>t.classList.add(Tn))),t.setAttribute("aria-expanded",!0)}i&&i()}static jQueryInterface(t){return this.each((function(){const e=xn.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}j.on(document,"click.bs.tab.data-api",'[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]',(function(t){["A","AREA"].includes(this.tagName)&&t.preventDefault(),c(this)||xn.getOrCreateInstance(this).show()})),g(xn);const Dn="toast",Sn="hide",Nn="show",In="showing",Pn={animation:"boolean",autohide:"boolean",delay:"number"},jn={animation:!0,autohide:!0,delay:5e3};class Mn extends B{constructor(t,e){super(t),this._config=this._getConfig(e),this._timeout=null,this._hasMouseInteraction=!1,this._hasKeyboardInteraction=!1,this._setListeners()}static get DefaultType(){return Pn}static get Default(){return jn}static get NAME(){return Dn}show(){j.trigger(this._element,"show.bs.toast").defaultPrevented||(this._clearTimeout(),this._config.animation&&this._element.classList.add("fade"),this._element.classList.remove(Sn),u(this._element),this._element.classList.add(Nn),this._element.classList.add(In),this._queueCallback((()=>{this._element.classList.remove(In),j.trigger(this._element,"shown.bs.toast"),this._maybeScheduleHide()}),this._element,this._config.animation))}hide(){this._element.classList.contains(Nn)&&(j.trigger(this._element,"hide.bs.toast").defaultPrevented||(this._element.classList.add(In),this._queueCallback((()=>{this._element.classList.add(Sn),this._element.classList.remove(In),this._element.classList.remove(Nn),j.trigger(this._element,"hidden.bs.toast")}),this._element,this._config.animation)))}dispose(){this._clearTimeout(),this._element.classList.contains(Nn)&&this._element.classList.remove(Nn),super.dispose()}_getConfig(t){return t={...jn,...U.getDataAttributes(this._element),..."object"==typeof t&&t?t:{}},a(Dn,t,this.constructor.DefaultType),t}_maybeScheduleHide(){this._config.autohide&&(this._hasMouseInteraction||this._hasKeyboardInteraction||(this._timeout=setTimeout((()=>{this.hide()}),this._config.delay)))}_onInteraction(t,e){switch(t.type){case"mouseover":case"mouseout":this._hasMouseInteraction=e;break;case"focusin":case"focusout":this._hasKeyboardInteraction=e}if(e)return void this._clearTimeout();const i=t.relatedTarget;this._element===i||this._element.contains(i)||this._maybeScheduleHide()}_setListeners(){j.on(this._element,"mouseover.bs.toast",(t=>this._onInteraction(t,!0))),j.on(this._element,"mouseout.bs.toast",(t=>this._onInteraction(t,!1))),j.on(this._element,"focusin.bs.toast",(t=>this._onInteraction(t,!0))),j.on(this._element,"focusout.bs.toast",(t=>this._onInteraction(t,!1)))}_clearTimeout(){clearTimeout(this._timeout),this._timeout=null}static jQueryInterface(t){return this.each((function(){const e=Mn.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}return R(Mn),g(Mn),{Alert:W,Button:z,Carousel:st,Collapse:pt,Dropdown:hi,Modal:Hi,Offcanvas:Fi,Popover:gn,ScrollSpy:An,Tab:xn,Toast:Mn,Tooltip:un}})); +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).bootstrap=e()}(this,(function(){"use strict";const t="transitionend",e=t=>{let e=t.getAttribute("data-bs-target");if(!e||"#"===e){let i=t.getAttribute("href");if(!i||!i.includes("#")&&!i.startsWith("."))return null;i.includes("#")&&!i.startsWith("#")&&(i=`#${i.split("#")[1]}`),e=i&&"#"!==i?i.trim():null}return e},i=t=>{const i=e(t);return i&&document.querySelector(i)?i:null},n=t=>{const i=e(t);return i?document.querySelector(i):null},s=e=>{e.dispatchEvent(new Event(t))},o=t=>!(!t||"object"!=typeof t)&&(void 0!==t.jquery&&(t=t[0]),void 0!==t.nodeType),r=t=>o(t)?t.jquery?t[0]:t:"string"==typeof t&&t.length>0?document.querySelector(t):null,a=(t,e,i)=>{Object.keys(i).forEach((n=>{const s=i[n],r=e[n],a=r&&o(r)?"element":null==(l=r)?`${l}`:{}.toString.call(l).match(/\s([a-z]+)/i)[1].toLowerCase();var l;if(!new RegExp(s).test(a))throw new TypeError(`${t.toUpperCase()}: Option "${n}" provided type "${a}" but expected type "${s}".`)}))},l=t=>!(!o(t)||0===t.getClientRects().length)&&"visible"===getComputedStyle(t).getPropertyValue("visibility"),c=t=>!t||t.nodeType!==Node.ELEMENT_NODE||!!t.classList.contains("disabled")||(void 0!==t.disabled?t.disabled:t.hasAttribute("disabled")&&"false"!==t.getAttribute("disabled")),h=t=>{if(!document.documentElement.attachShadow)return null;if("function"==typeof t.getRootNode){const e=t.getRootNode();return e instanceof ShadowRoot?e:null}return t instanceof ShadowRoot?t:t.parentNode?h(t.parentNode):null},d=()=>{},u=t=>{t.offsetHeight},f=()=>{const{jQuery:t}=window;return t&&!document.body.hasAttribute("data-bs-no-jquery")?t:null},p=[],m=()=>"rtl"===document.documentElement.dir,g=t=>{var e;e=()=>{const e=f();if(e){const i=t.NAME,n=e.fn[i];e.fn[i]=t.jQueryInterface,e.fn[i].Constructor=t,e.fn[i].noConflict=()=>(e.fn[i]=n,t.jQueryInterface)}},"loading"===document.readyState?(p.length||document.addEventListener("DOMContentLoaded",(()=>{p.forEach((t=>t()))})),p.push(e)):e()},_=t=>{"function"==typeof t&&t()},b=(e,i,n=!0)=>{if(!n)return void _(e);const o=(t=>{if(!t)return 0;let{transitionDuration:e,transitionDelay:i}=window.getComputedStyle(t);const n=Number.parseFloat(e),s=Number.parseFloat(i);return n||s?(e=e.split(",")[0],i=i.split(",")[0],1e3*(Number.parseFloat(e)+Number.parseFloat(i))):0})(i)+5;let r=!1;const a=({target:n})=>{n===i&&(r=!0,i.removeEventListener(t,a),_(e))};i.addEventListener(t,a),setTimeout((()=>{r||s(i)}),o)},v=(t,e,i,n)=>{let s=t.indexOf(e);if(-1===s)return t[!i&&n?t.length-1:0];const o=t.length;return s+=i?1:-1,n&&(s=(s+o)%o),t[Math.max(0,Math.min(s,o-1))]},y=/[^.]*(?=\..*)\.|.*/,w=/\..*/,E=/::\d+$/,A={};let T=1;const O={mouseenter:"mouseover",mouseleave:"mouseout"},C=/^(mouseenter|mouseleave)/i,k=new Set(["click","dblclick","mouseup","mousedown","contextmenu","mousewheel","DOMMouseScroll","mouseover","mouseout","mousemove","selectstart","selectend","keydown","keypress","keyup","orientationchange","touchstart","touchmove","touchend","touchcancel","pointerdown","pointermove","pointerup","pointerleave","pointercancel","gesturestart","gesturechange","gestureend","focus","blur","change","reset","select","submit","focusin","focusout","load","unload","beforeunload","resize","move","DOMContentLoaded","readystatechange","error","abort","scroll"]);function L(t,e){return e&&`${e}::${T++}`||t.uidEvent||T++}function x(t){const e=L(t);return t.uidEvent=e,A[e]=A[e]||{},A[e]}function D(t,e,i=null){const n=Object.keys(t);for(let s=0,o=n.length;sfunction(e){if(!e.relatedTarget||e.relatedTarget!==e.delegateTarget&&!e.delegateTarget.contains(e.relatedTarget))return t.call(this,e)};n?n=t(n):i=t(i)}const[o,r,a]=S(e,i,n),l=x(t),c=l[a]||(l[a]={}),h=D(c,r,o?i:null);if(h)return void(h.oneOff=h.oneOff&&s);const d=L(r,e.replace(y,"")),u=o?function(t,e,i){return function n(s){const o=t.querySelectorAll(e);for(let{target:r}=s;r&&r!==this;r=r.parentNode)for(let a=o.length;a--;)if(o[a]===r)return s.delegateTarget=r,n.oneOff&&j.off(t,s.type,e,i),i.apply(r,[s]);return null}}(t,i,n):function(t,e){return function i(n){return n.delegateTarget=t,i.oneOff&&j.off(t,n.type,e),e.apply(t,[n])}}(t,i);u.delegationSelector=o?i:null,u.originalHandler=r,u.oneOff=s,u.uidEvent=d,c[d]=u,t.addEventListener(a,u,o)}function I(t,e,i,n,s){const o=D(e[i],n,s);o&&(t.removeEventListener(i,o,Boolean(s)),delete e[i][o.uidEvent])}function P(t){return t=t.replace(w,""),O[t]||t}const j={on(t,e,i,n){N(t,e,i,n,!1)},one(t,e,i,n){N(t,e,i,n,!0)},off(t,e,i,n){if("string"!=typeof e||!t)return;const[s,o,r]=S(e,i,n),a=r!==e,l=x(t),c=e.startsWith(".");if(void 0!==o){if(!l||!l[r])return;return void I(t,l,r,o,s?i:null)}c&&Object.keys(l).forEach((i=>{!function(t,e,i,n){const s=e[i]||{};Object.keys(s).forEach((o=>{if(o.includes(n)){const n=s[o];I(t,e,i,n.originalHandler,n.delegationSelector)}}))}(t,l,i,e.slice(1))}));const h=l[r]||{};Object.keys(h).forEach((i=>{const n=i.replace(E,"");if(!a||e.includes(n)){const e=h[i];I(t,l,r,e.originalHandler,e.delegationSelector)}}))},trigger(t,e,i){if("string"!=typeof e||!t)return null;const n=f(),s=P(e),o=e!==s,r=k.has(s);let a,l=!0,c=!0,h=!1,d=null;return o&&n&&(a=n.Event(e,i),n(t).trigger(a),l=!a.isPropagationStopped(),c=!a.isImmediatePropagationStopped(),h=a.isDefaultPrevented()),r?(d=document.createEvent("HTMLEvents"),d.initEvent(s,l,!0)):d=new CustomEvent(e,{bubbles:l,cancelable:!0}),void 0!==i&&Object.keys(i).forEach((t=>{Object.defineProperty(d,t,{get:()=>i[t]})})),h&&d.preventDefault(),c&&t.dispatchEvent(d),d.defaultPrevented&&void 0!==a&&a.preventDefault(),d}},M=new Map,H={set(t,e,i){M.has(t)||M.set(t,new Map);const n=M.get(t);n.has(e)||0===n.size?n.set(e,i):console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(n.keys())[0]}.`)},get:(t,e)=>M.has(t)&&M.get(t).get(e)||null,remove(t,e){if(!M.has(t))return;const i=M.get(t);i.delete(e),0===i.size&&M.delete(t)}};class B{constructor(t){(t=r(t))&&(this._element=t,H.set(this._element,this.constructor.DATA_KEY,this))}dispose(){H.remove(this._element,this.constructor.DATA_KEY),j.off(this._element,this.constructor.EVENT_KEY),Object.getOwnPropertyNames(this).forEach((t=>{this[t]=null}))}_queueCallback(t,e,i=!0){b(t,e,i)}static getInstance(t){return H.get(r(t),this.DATA_KEY)}static getOrCreateInstance(t,e={}){return this.getInstance(t)||new this(t,"object"==typeof e?e:null)}static get VERSION(){return"5.1.3"}static get NAME(){throw new Error('You have to implement the static method "NAME", for each component!')}static get DATA_KEY(){return`bs.${this.NAME}`}static get EVENT_KEY(){return`.${this.DATA_KEY}`}}const R=(t,e="hide")=>{const i=`click.dismiss${t.EVENT_KEY}`,s=t.NAME;j.on(document,i,`[data-bs-dismiss="${s}"]`,(function(i){if(["A","AREA"].includes(this.tagName)&&i.preventDefault(),c(this))return;const o=n(this)||this.closest(`.${s}`);t.getOrCreateInstance(o)[e]()}))};class W extends B{static get NAME(){return"alert"}close(){if(j.trigger(this._element,"close.bs.alert").defaultPrevented)return;this._element.classList.remove("show");const t=this._element.classList.contains("fade");this._queueCallback((()=>this._destroyElement()),this._element,t)}_destroyElement(){this._element.remove(),j.trigger(this._element,"closed.bs.alert"),this.dispose()}static jQueryInterface(t){return this.each((function(){const e=W.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}R(W,"close"),g(W);const $='[data-bs-toggle="button"]';class z extends B{static get NAME(){return"button"}toggle(){this._element.setAttribute("aria-pressed",this._element.classList.toggle("active"))}static jQueryInterface(t){return this.each((function(){const e=z.getOrCreateInstance(this);"toggle"===t&&e[t]()}))}}function q(t){return"true"===t||"false"!==t&&(t===Number(t).toString()?Number(t):""===t||"null"===t?null:t)}function F(t){return t.replace(/[A-Z]/g,(t=>`-${t.toLowerCase()}`))}j.on(document,"click.bs.button.data-api",$,(t=>{t.preventDefault();const e=t.target.closest($);z.getOrCreateInstance(e).toggle()})),g(z);const U={setDataAttribute(t,e,i){t.setAttribute(`data-bs-${F(e)}`,i)},removeDataAttribute(t,e){t.removeAttribute(`data-bs-${F(e)}`)},getDataAttributes(t){if(!t)return{};const e={};return Object.keys(t.dataset).filter((t=>t.startsWith("bs"))).forEach((i=>{let n=i.replace(/^bs/,"");n=n.charAt(0).toLowerCase()+n.slice(1,n.length),e[n]=q(t.dataset[i])})),e},getDataAttribute:(t,e)=>q(t.getAttribute(`data-bs-${F(e)}`)),offset(t){const e=t.getBoundingClientRect();return{top:e.top+window.pageYOffset,left:e.left+window.pageXOffset}},position:t=>({top:t.offsetTop,left:t.offsetLeft})},V={find:(t,e=document.documentElement)=>[].concat(...Element.prototype.querySelectorAll.call(e,t)),findOne:(t,e=document.documentElement)=>Element.prototype.querySelector.call(e,t),children:(t,e)=>[].concat(...t.children).filter((t=>t.matches(e))),parents(t,e){const i=[];let n=t.parentNode;for(;n&&n.nodeType===Node.ELEMENT_NODE&&3!==n.nodeType;)n.matches(e)&&i.push(n),n=n.parentNode;return i},prev(t,e){let i=t.previousElementSibling;for(;i;){if(i.matches(e))return[i];i=i.previousElementSibling}return[]},next(t,e){let i=t.nextElementSibling;for(;i;){if(i.matches(e))return[i];i=i.nextElementSibling}return[]},focusableChildren(t){const e=["a","button","input","textarea","select","details","[tabindex]",'[contenteditable="true"]'].map((t=>`${t}:not([tabindex^="-"])`)).join(", ");return this.find(e,t).filter((t=>!c(t)&&l(t)))}},K="carousel",X={interval:5e3,keyboard:!0,slide:!1,pause:"hover",wrap:!0,touch:!0},Y={interval:"(number|boolean)",keyboard:"boolean",slide:"(boolean|string)",pause:"(string|boolean)",wrap:"boolean",touch:"boolean"},Q="next",G="prev",Z="left",J="right",tt={ArrowLeft:J,ArrowRight:Z},et="slid.bs.carousel",it="active",nt=".active.carousel-item";class st extends B{constructor(t,e){super(t),this._items=null,this._interval=null,this._activeElement=null,this._isPaused=!1,this._isSliding=!1,this.touchTimeout=null,this.touchStartX=0,this.touchDeltaX=0,this._config=this._getConfig(e),this._indicatorsElement=V.findOne(".carousel-indicators",this._element),this._touchSupported="ontouchstart"in document.documentElement||navigator.maxTouchPoints>0,this._pointerEvent=Boolean(window.PointerEvent),this._addEventListeners()}static get Default(){return X}static get NAME(){return K}next(){this._slide(Q)}nextWhenVisible(){!document.hidden&&l(this._element)&&this.next()}prev(){this._slide(G)}pause(t){t||(this._isPaused=!0),V.findOne(".carousel-item-next, .carousel-item-prev",this._element)&&(s(this._element),this.cycle(!0)),clearInterval(this._interval),this._interval=null}cycle(t){t||(this._isPaused=!1),this._interval&&(clearInterval(this._interval),this._interval=null),this._config&&this._config.interval&&!this._isPaused&&(this._updateInterval(),this._interval=setInterval((document.visibilityState?this.nextWhenVisible:this.next).bind(this),this._config.interval))}to(t){this._activeElement=V.findOne(nt,this._element);const e=this._getItemIndex(this._activeElement);if(t>this._items.length-1||t<0)return;if(this._isSliding)return void j.one(this._element,et,(()=>this.to(t)));if(e===t)return this.pause(),void this.cycle();const i=t>e?Q:G;this._slide(i,this._items[t])}_getConfig(t){return t={...X,...U.getDataAttributes(this._element),..."object"==typeof t?t:{}},a(K,t,Y),t}_handleSwipe(){const t=Math.abs(this.touchDeltaX);if(t<=40)return;const e=t/this.touchDeltaX;this.touchDeltaX=0,e&&this._slide(e>0?J:Z)}_addEventListeners(){this._config.keyboard&&j.on(this._element,"keydown.bs.carousel",(t=>this._keydown(t))),"hover"===this._config.pause&&(j.on(this._element,"mouseenter.bs.carousel",(t=>this.pause(t))),j.on(this._element,"mouseleave.bs.carousel",(t=>this.cycle(t)))),this._config.touch&&this._touchSupported&&this._addTouchEventListeners()}_addTouchEventListeners(){const t=t=>this._pointerEvent&&("pen"===t.pointerType||"touch"===t.pointerType),e=e=>{t(e)?this.touchStartX=e.clientX:this._pointerEvent||(this.touchStartX=e.touches[0].clientX)},i=t=>{this.touchDeltaX=t.touches&&t.touches.length>1?0:t.touches[0].clientX-this.touchStartX},n=e=>{t(e)&&(this.touchDeltaX=e.clientX-this.touchStartX),this._handleSwipe(),"hover"===this._config.pause&&(this.pause(),this.touchTimeout&&clearTimeout(this.touchTimeout),this.touchTimeout=setTimeout((t=>this.cycle(t)),500+this._config.interval))};V.find(".carousel-item img",this._element).forEach((t=>{j.on(t,"dragstart.bs.carousel",(t=>t.preventDefault()))})),this._pointerEvent?(j.on(this._element,"pointerdown.bs.carousel",(t=>e(t))),j.on(this._element,"pointerup.bs.carousel",(t=>n(t))),this._element.classList.add("pointer-event")):(j.on(this._element,"touchstart.bs.carousel",(t=>e(t))),j.on(this._element,"touchmove.bs.carousel",(t=>i(t))),j.on(this._element,"touchend.bs.carousel",(t=>n(t))))}_keydown(t){if(/input|textarea/i.test(t.target.tagName))return;const e=tt[t.key];e&&(t.preventDefault(),this._slide(e))}_getItemIndex(t){return this._items=t&&t.parentNode?V.find(".carousel-item",t.parentNode):[],this._items.indexOf(t)}_getItemByOrder(t,e){const i=t===Q;return v(this._items,e,i,this._config.wrap)}_triggerSlideEvent(t,e){const i=this._getItemIndex(t),n=this._getItemIndex(V.findOne(nt,this._element));return j.trigger(this._element,"slide.bs.carousel",{relatedTarget:t,direction:e,from:n,to:i})}_setActiveIndicatorElement(t){if(this._indicatorsElement){const e=V.findOne(".active",this._indicatorsElement);e.classList.remove(it),e.removeAttribute("aria-current");const i=V.find("[data-bs-target]",this._indicatorsElement);for(let e=0;e{j.trigger(this._element,et,{relatedTarget:o,direction:d,from:s,to:r})};if(this._element.classList.contains("slide")){o.classList.add(h),u(o),n.classList.add(c),o.classList.add(c);const t=()=>{o.classList.remove(c,h),o.classList.add(it),n.classList.remove(it,h,c),this._isSliding=!1,setTimeout(f,0)};this._queueCallback(t,n,!0)}else n.classList.remove(it),o.classList.add(it),this._isSliding=!1,f();a&&this.cycle()}_directionToOrder(t){return[J,Z].includes(t)?m()?t===Z?G:Q:t===Z?Q:G:t}_orderToDirection(t){return[Q,G].includes(t)?m()?t===G?Z:J:t===G?J:Z:t}static carouselInterface(t,e){const i=st.getOrCreateInstance(t,e);let{_config:n}=i;"object"==typeof e&&(n={...n,...e});const s="string"==typeof e?e:n.slide;if("number"==typeof e)i.to(e);else if("string"==typeof s){if(void 0===i[s])throw new TypeError(`No method named "${s}"`);i[s]()}else n.interval&&n.ride&&(i.pause(),i.cycle())}static jQueryInterface(t){return this.each((function(){st.carouselInterface(this,t)}))}static dataApiClickHandler(t){const e=n(this);if(!e||!e.classList.contains("carousel"))return;const i={...U.getDataAttributes(e),...U.getDataAttributes(this)},s=this.getAttribute("data-bs-slide-to");s&&(i.interval=!1),st.carouselInterface(e,i),s&&st.getInstance(e).to(s),t.preventDefault()}}j.on(document,"click.bs.carousel.data-api","[data-bs-slide], [data-bs-slide-to]",st.dataApiClickHandler),j.on(window,"load.bs.carousel.data-api",(()=>{const t=V.find('[data-bs-ride="carousel"]');for(let e=0,i=t.length;et===this._element));null!==s&&o.length&&(this._selector=s,this._triggerArray.push(e))}this._initializeChildren(),this._config.parent||this._addAriaAndCollapsedClass(this._triggerArray,this._isShown()),this._config.toggle&&this.toggle()}static get Default(){return rt}static get NAME(){return ot}toggle(){this._isShown()?this.hide():this.show()}show(){if(this._isTransitioning||this._isShown())return;let t,e=[];if(this._config.parent){const t=V.find(ut,this._config.parent);e=V.find(".collapse.show, .collapse.collapsing",this._config.parent).filter((e=>!t.includes(e)))}const i=V.findOne(this._selector);if(e.length){const n=e.find((t=>i!==t));if(t=n?pt.getInstance(n):null,t&&t._isTransitioning)return}if(j.trigger(this._element,"show.bs.collapse").defaultPrevented)return;e.forEach((e=>{i!==e&&pt.getOrCreateInstance(e,{toggle:!1}).hide(),t||H.set(e,"bs.collapse",null)}));const n=this._getDimension();this._element.classList.remove(ct),this._element.classList.add(ht),this._element.style[n]=0,this._addAriaAndCollapsedClass(this._triggerArray,!0),this._isTransitioning=!0;const s=`scroll${n[0].toUpperCase()+n.slice(1)}`;this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(ht),this._element.classList.add(ct,lt),this._element.style[n]="",j.trigger(this._element,"shown.bs.collapse")}),this._element,!0),this._element.style[n]=`${this._element[s]}px`}hide(){if(this._isTransitioning||!this._isShown())return;if(j.trigger(this._element,"hide.bs.collapse").defaultPrevented)return;const t=this._getDimension();this._element.style[t]=`${this._element.getBoundingClientRect()[t]}px`,u(this._element),this._element.classList.add(ht),this._element.classList.remove(ct,lt);const e=this._triggerArray.length;for(let t=0;t{this._isTransitioning=!1,this._element.classList.remove(ht),this._element.classList.add(ct),j.trigger(this._element,"hidden.bs.collapse")}),this._element,!0)}_isShown(t=this._element){return t.classList.contains(lt)}_getConfig(t){return(t={...rt,...U.getDataAttributes(this._element),...t}).toggle=Boolean(t.toggle),t.parent=r(t.parent),a(ot,t,at),t}_getDimension(){return this._element.classList.contains("collapse-horizontal")?"width":"height"}_initializeChildren(){if(!this._config.parent)return;const t=V.find(ut,this._config.parent);V.find(ft,this._config.parent).filter((e=>!t.includes(e))).forEach((t=>{const e=n(t);e&&this._addAriaAndCollapsedClass([t],this._isShown(e))}))}_addAriaAndCollapsedClass(t,e){t.length&&t.forEach((t=>{e?t.classList.remove(dt):t.classList.add(dt),t.setAttribute("aria-expanded",e)}))}static jQueryInterface(t){return this.each((function(){const e={};"string"==typeof t&&/show|hide/.test(t)&&(e.toggle=!1);const i=pt.getOrCreateInstance(this,e);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t]()}}))}}j.on(document,"click.bs.collapse.data-api",ft,(function(t){("A"===t.target.tagName||t.delegateTarget&&"A"===t.delegateTarget.tagName)&&t.preventDefault();const e=i(this);V.find(e).forEach((t=>{pt.getOrCreateInstance(t,{toggle:!1}).toggle()}))})),g(pt);var mt="top",gt="bottom",_t="right",bt="left",vt="auto",yt=[mt,gt,_t,bt],wt="start",Et="end",At="clippingParents",Tt="viewport",Ot="popper",Ct="reference",kt=yt.reduce((function(t,e){return t.concat([e+"-"+wt,e+"-"+Et])}),[]),Lt=[].concat(yt,[vt]).reduce((function(t,e){return t.concat([e,e+"-"+wt,e+"-"+Et])}),[]),xt="beforeRead",Dt="read",St="afterRead",Nt="beforeMain",It="main",Pt="afterMain",jt="beforeWrite",Mt="write",Ht="afterWrite",Bt=[xt,Dt,St,Nt,It,Pt,jt,Mt,Ht];function Rt(t){return t?(t.nodeName||"").toLowerCase():null}function Wt(t){if(null==t)return window;if("[object Window]"!==t.toString()){var e=t.ownerDocument;return e&&e.defaultView||window}return t}function $t(t){return t instanceof Wt(t).Element||t instanceof Element}function zt(t){return t instanceof Wt(t).HTMLElement||t instanceof HTMLElement}function qt(t){return"undefined"!=typeof ShadowRoot&&(t instanceof Wt(t).ShadowRoot||t instanceof ShadowRoot)}const Ft={name:"applyStyles",enabled:!0,phase:"write",fn:function(t){var e=t.state;Object.keys(e.elements).forEach((function(t){var i=e.styles[t]||{},n=e.attributes[t]||{},s=e.elements[t];zt(s)&&Rt(s)&&(Object.assign(s.style,i),Object.keys(n).forEach((function(t){var e=n[t];!1===e?s.removeAttribute(t):s.setAttribute(t,!0===e?"":e)})))}))},effect:function(t){var e=t.state,i={popper:{position:e.options.strategy,left:"0",top:"0",margin:"0"},arrow:{position:"absolute"},reference:{}};return Object.assign(e.elements.popper.style,i.popper),e.styles=i,e.elements.arrow&&Object.assign(e.elements.arrow.style,i.arrow),function(){Object.keys(e.elements).forEach((function(t){var n=e.elements[t],s=e.attributes[t]||{},o=Object.keys(e.styles.hasOwnProperty(t)?e.styles[t]:i[t]).reduce((function(t,e){return t[e]="",t}),{});zt(n)&&Rt(n)&&(Object.assign(n.style,o),Object.keys(s).forEach((function(t){n.removeAttribute(t)})))}))}},requires:["computeStyles"]};function Ut(t){return t.split("-")[0]}function Vt(t,e){var i=t.getBoundingClientRect();return{width:i.width/1,height:i.height/1,top:i.top/1,right:i.right/1,bottom:i.bottom/1,left:i.left/1,x:i.left/1,y:i.top/1}}function Kt(t){var e=Vt(t),i=t.offsetWidth,n=t.offsetHeight;return Math.abs(e.width-i)<=1&&(i=e.width),Math.abs(e.height-n)<=1&&(n=e.height),{x:t.offsetLeft,y:t.offsetTop,width:i,height:n}}function Xt(t,e){var i=e.getRootNode&&e.getRootNode();if(t.contains(e))return!0;if(i&&qt(i)){var n=e;do{if(n&&t.isSameNode(n))return!0;n=n.parentNode||n.host}while(n)}return!1}function Yt(t){return Wt(t).getComputedStyle(t)}function Qt(t){return["table","td","th"].indexOf(Rt(t))>=0}function Gt(t){return(($t(t)?t.ownerDocument:t.document)||window.document).documentElement}function Zt(t){return"html"===Rt(t)?t:t.assignedSlot||t.parentNode||(qt(t)?t.host:null)||Gt(t)}function Jt(t){return zt(t)&&"fixed"!==Yt(t).position?t.offsetParent:null}function te(t){for(var e=Wt(t),i=Jt(t);i&&Qt(i)&&"static"===Yt(i).position;)i=Jt(i);return i&&("html"===Rt(i)||"body"===Rt(i)&&"static"===Yt(i).position)?e:i||function(t){var e=-1!==navigator.userAgent.toLowerCase().indexOf("firefox");if(-1!==navigator.userAgent.indexOf("Trident")&&zt(t)&&"fixed"===Yt(t).position)return null;for(var i=Zt(t);zt(i)&&["html","body"].indexOf(Rt(i))<0;){var n=Yt(i);if("none"!==n.transform||"none"!==n.perspective||"paint"===n.contain||-1!==["transform","perspective"].indexOf(n.willChange)||e&&"filter"===n.willChange||e&&n.filter&&"none"!==n.filter)return i;i=i.parentNode}return null}(t)||e}function ee(t){return["top","bottom"].indexOf(t)>=0?"x":"y"}var ie=Math.max,ne=Math.min,se=Math.round;function oe(t,e,i){return ie(t,ne(e,i))}function re(t){return Object.assign({},{top:0,right:0,bottom:0,left:0},t)}function ae(t,e){return e.reduce((function(e,i){return e[i]=t,e}),{})}const le={name:"arrow",enabled:!0,phase:"main",fn:function(t){var e,i=t.state,n=t.name,s=t.options,o=i.elements.arrow,r=i.modifiersData.popperOffsets,a=Ut(i.placement),l=ee(a),c=[bt,_t].indexOf(a)>=0?"height":"width";if(o&&r){var h=function(t,e){return re("number"!=typeof(t="function"==typeof t?t(Object.assign({},e.rects,{placement:e.placement})):t)?t:ae(t,yt))}(s.padding,i),d=Kt(o),u="y"===l?mt:bt,f="y"===l?gt:_t,p=i.rects.reference[c]+i.rects.reference[l]-r[l]-i.rects.popper[c],m=r[l]-i.rects.reference[l],g=te(o),_=g?"y"===l?g.clientHeight||0:g.clientWidth||0:0,b=p/2-m/2,v=h[u],y=_-d[c]-h[f],w=_/2-d[c]/2+b,E=oe(v,w,y),A=l;i.modifiersData[n]=((e={})[A]=E,e.centerOffset=E-w,e)}},effect:function(t){var e=t.state,i=t.options.element,n=void 0===i?"[data-popper-arrow]":i;null!=n&&("string"!=typeof n||(n=e.elements.popper.querySelector(n)))&&Xt(e.elements.popper,n)&&(e.elements.arrow=n)},requires:["popperOffsets"],requiresIfExists:["preventOverflow"]};function ce(t){return t.split("-")[1]}var he={top:"auto",right:"auto",bottom:"auto",left:"auto"};function de(t){var e,i=t.popper,n=t.popperRect,s=t.placement,o=t.variation,r=t.offsets,a=t.position,l=t.gpuAcceleration,c=t.adaptive,h=t.roundOffsets,d=!0===h?function(t){var e=t.x,i=t.y,n=window.devicePixelRatio||1;return{x:se(se(e*n)/n)||0,y:se(se(i*n)/n)||0}}(r):"function"==typeof h?h(r):r,u=d.x,f=void 0===u?0:u,p=d.y,m=void 0===p?0:p,g=r.hasOwnProperty("x"),_=r.hasOwnProperty("y"),b=bt,v=mt,y=window;if(c){var w=te(i),E="clientHeight",A="clientWidth";w===Wt(i)&&"static"!==Yt(w=Gt(i)).position&&"absolute"===a&&(E="scrollHeight",A="scrollWidth"),w=w,s!==mt&&(s!==bt&&s!==_t||o!==Et)||(v=gt,m-=w[E]-n.height,m*=l?1:-1),s!==bt&&(s!==mt&&s!==gt||o!==Et)||(b=_t,f-=w[A]-n.width,f*=l?1:-1)}var T,O=Object.assign({position:a},c&&he);return l?Object.assign({},O,((T={})[v]=_?"0":"",T[b]=g?"0":"",T.transform=(y.devicePixelRatio||1)<=1?"translate("+f+"px, "+m+"px)":"translate3d("+f+"px, "+m+"px, 0)",T)):Object.assign({},O,((e={})[v]=_?m+"px":"",e[b]=g?f+"px":"",e.transform="",e))}const ue={name:"computeStyles",enabled:!0,phase:"beforeWrite",fn:function(t){var e=t.state,i=t.options,n=i.gpuAcceleration,s=void 0===n||n,o=i.adaptive,r=void 0===o||o,a=i.roundOffsets,l=void 0===a||a,c={placement:Ut(e.placement),variation:ce(e.placement),popper:e.elements.popper,popperRect:e.rects.popper,gpuAcceleration:s};null!=e.modifiersData.popperOffsets&&(e.styles.popper=Object.assign({},e.styles.popper,de(Object.assign({},c,{offsets:e.modifiersData.popperOffsets,position:e.options.strategy,adaptive:r,roundOffsets:l})))),null!=e.modifiersData.arrow&&(e.styles.arrow=Object.assign({},e.styles.arrow,de(Object.assign({},c,{offsets:e.modifiersData.arrow,position:"absolute",adaptive:!1,roundOffsets:l})))),e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-placement":e.placement})},data:{}};var fe={passive:!0};const pe={name:"eventListeners",enabled:!0,phase:"write",fn:function(){},effect:function(t){var e=t.state,i=t.instance,n=t.options,s=n.scroll,o=void 0===s||s,r=n.resize,a=void 0===r||r,l=Wt(e.elements.popper),c=[].concat(e.scrollParents.reference,e.scrollParents.popper);return o&&c.forEach((function(t){t.addEventListener("scroll",i.update,fe)})),a&&l.addEventListener("resize",i.update,fe),function(){o&&c.forEach((function(t){t.removeEventListener("scroll",i.update,fe)})),a&&l.removeEventListener("resize",i.update,fe)}},data:{}};var me={left:"right",right:"left",bottom:"top",top:"bottom"};function ge(t){return t.replace(/left|right|bottom|top/g,(function(t){return me[t]}))}var _e={start:"end",end:"start"};function be(t){return t.replace(/start|end/g,(function(t){return _e[t]}))}function ve(t){var e=Wt(t);return{scrollLeft:e.pageXOffset,scrollTop:e.pageYOffset}}function ye(t){return Vt(Gt(t)).left+ve(t).scrollLeft}function we(t){var e=Yt(t),i=e.overflow,n=e.overflowX,s=e.overflowY;return/auto|scroll|overlay|hidden/.test(i+s+n)}function Ee(t){return["html","body","#document"].indexOf(Rt(t))>=0?t.ownerDocument.body:zt(t)&&we(t)?t:Ee(Zt(t))}function Ae(t,e){var i;void 0===e&&(e=[]);var n=Ee(t),s=n===(null==(i=t.ownerDocument)?void 0:i.body),o=Wt(n),r=s?[o].concat(o.visualViewport||[],we(n)?n:[]):n,a=e.concat(r);return s?a:a.concat(Ae(Zt(r)))}function Te(t){return Object.assign({},t,{left:t.x,top:t.y,right:t.x+t.width,bottom:t.y+t.height})}function Oe(t,e){return e===Tt?Te(function(t){var e=Wt(t),i=Gt(t),n=e.visualViewport,s=i.clientWidth,o=i.clientHeight,r=0,a=0;return n&&(s=n.width,o=n.height,/^((?!chrome|android).)*safari/i.test(navigator.userAgent)||(r=n.offsetLeft,a=n.offsetTop)),{width:s,height:o,x:r+ye(t),y:a}}(t)):zt(e)?function(t){var e=Vt(t);return e.top=e.top+t.clientTop,e.left=e.left+t.clientLeft,e.bottom=e.top+t.clientHeight,e.right=e.left+t.clientWidth,e.width=t.clientWidth,e.height=t.clientHeight,e.x=e.left,e.y=e.top,e}(e):Te(function(t){var e,i=Gt(t),n=ve(t),s=null==(e=t.ownerDocument)?void 0:e.body,o=ie(i.scrollWidth,i.clientWidth,s?s.scrollWidth:0,s?s.clientWidth:0),r=ie(i.scrollHeight,i.clientHeight,s?s.scrollHeight:0,s?s.clientHeight:0),a=-n.scrollLeft+ye(t),l=-n.scrollTop;return"rtl"===Yt(s||i).direction&&(a+=ie(i.clientWidth,s?s.clientWidth:0)-o),{width:o,height:r,x:a,y:l}}(Gt(t)))}function Ce(t){var e,i=t.reference,n=t.element,s=t.placement,o=s?Ut(s):null,r=s?ce(s):null,a=i.x+i.width/2-n.width/2,l=i.y+i.height/2-n.height/2;case(o){case mt:e={x:a,y:i.y-n.height};break;case gt:e={x:a,y:i.y+i.height};break;case _t:e={x:i.x+i.width,y:l};break;case bt:e={x:i.x-n.width,y:l};break;default:e={x:i.x,y:i.y}}var c=o?ee(o):null;if(null!=c){var h="y"===c?"height":"width";case(r){case wt:e[c]=e[c]-(i[h]/2-n[h]/2);break;case Et:e[c]=e[c]+(i[h]/2-n[h]/2)}}return e}function ke(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=void 0===n?t.placement:n,o=i.boundary,r=void 0===o?At:o,a=i.rootBoundary,l=void 0===a?Tt:a,c=i.elementContext,h=void 0===c?Ot:c,d=i.altBoundary,u=void 0!==d&&d,f=i.padding,p=void 0===f?0:f,m=re("number"!=typeof p?p:ae(p,yt)),g=h===Ot?Ct:Ot,_=t.rects.popper,b=t.elements[u?g:h],v=function(t,e,i){var n="clippingParents"===e?function(t){var e=Ae(Zt(t)),i=["absolute","fixed"].indexOf(Yt(t).position)>=0&&zt(t)?te(t):t;return $t(i)?e.filter((function(t){return $t(t)&&Xt(t,i)&&"body"!==Rt(t)})):[]}(t):[].concat(e),s=[].concat(n,[i]),o=s[0],r=s.reduce((function(e,i){var n=Oe(t,i);return e.top=ie(n.top,e.top),e.right=ne(n.right,e.right),e.bottom=ne(n.bottom,e.bottom),e.left=ie(n.left,e.left),e}),Oe(t,o));return r.width=r.right-r.left,r.height=r.bottom-r.top,r.x=r.left,r.y=r.top,r}($t(b)?b:b.contextElement||Gt(t.elements.popper),r,l),y=Vt(t.elements.reference),w=Ce({reference:y,element:_,strategy:"absolute",placement:s}),E=Te(Object.assign({},_,w)),A=h===Ot?E:y,T={top:v.top-A.top+m.top,bottom:A.bottom-v.bottom+m.bottom,left:v.left-A.left+m.left,right:A.right-v.right+m.right},O=t.modifiersData.offset;if(h===Ot&&O){var C=O[s];Object.keys(T).forEach((function(t){var e=[_t,gt].indexOf(t)>=0?1:-1,i=[mt,gt].indexOf(t)>=0?"y":"x";T[t]+=C[i]*e}))}return T}function Le(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=i.boundary,o=i.rootBoundary,r=i.padding,a=i.flipVariations,l=i.allowedAutoPlacements,c=void 0===l?Lt:l,h=ce(n),d=h?a?kt:kt.filter((function(t){return ce(t)===h})):yt,u=d.filter((function(t){return c.indexOf(t)>=0}));0===u.length&&(u=d);var f=u.reduce((function(e,i){return e[i]=ke(t,{placement:i,boundary:s,rootBoundary:o,padding:r})[Ut(i)],e}),{});return Object.keys(f).sort((function(t,e){return f[t]-f[e]}))}const xe={name:"flip",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name;if(!e.modifiersData[n]._skip){for(var s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0===r||r,l=i.fallbackPlacements,c=i.padding,h=i.boundary,d=i.rootBoundary,u=i.altBoundary,f=i.flipVariations,p=void 0===f||f,m=i.allowedAutoPlacements,g=e.options.placement,_=Ut(g),b=l||(_!==g&&p?function(t){if(Ut(t)===vt)return[];var e=ge(t);return[be(t),e,be(e)]}(g):[ge(g)]),v=[g].concat(b).reduce((function(t,i){return t.concat(Ut(i)===vt?Le(e,{placement:i,boundary:h,rootBoundary:d,padding:c,flipVariations:p,allowedAutoPlacements:m}):i)}),[]),y=e.rects.reference,w=e.rects.popper,E=new Map,A=!0,T=v[0],O=0;O=0,D=x?"width":"height",S=ke(e,{placement:C,boundary:h,rootBoundary:d,altBoundary:u,padding:c}),N=x?L?_t:bt:L?gt:mt;y[D]>w[D]&&(N=ge(N));var I=ge(N),P=[];if(o&&P.push(S[k]<=0),a&&P.push(S[N]<=0,S[I]<=0),P.every((function(t){return t}))){T=C,A=!1;break}E.set(C,P)}if(A)for(var j=function(t){var e=v.find((function(e){var i=E.get(e);if(i)return i.slice(0,t).every((function(t){return t}))}));if(e)return T=e,"break"},M=p?3:1;M>0&&"break"!==j(M);M--);e.placement!==T&&(e.modifiersData[n]._skip=!0,e.placement=T,e.reset=!0)}},requiresIfExists:["offset"],data:{_skip:!1}};function De(t,e,i){return void 0===i&&(i={x:0,y:0}),{top:t.top-e.height-i.y,right:t.right-e.width+i.x,bottom:t.bottom-e.height+i.y,left:t.left-e.width-i.x}}function Se(t){return[mt,_t,gt,bt].some((function(e){return t[e]>=0}))}const Ne={name:"hide",enabled:!0,phase:"main",requiresIfExists:["preventOverflow"],fn:function(t){var e=t.state,i=t.name,n=e.rects.reference,s=e.rects.popper,o=e.modifiersData.preventOverflow,r=ke(e,{elementContext:"reference"}),a=ke(e,{altBoundary:!0}),l=De(r,n),c=De(a,s,o),h=Se(l),d=Se(c);e.modifiersData[i]={referenceClippingOffsets:l,popperEscapeOffsets:c,isReferenceHidden:h,hasPopperEscaped:d},e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-reference-hidden":h,"data-popper-escaped":d})}},Ie={name:"offset",enabled:!0,phase:"main",requires:["popperOffsets"],fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.offset,o=void 0===s?[0,0]:s,r=Lt.reduce((function(t,i){return t[i]=function(t,e,i){var n=Ut(t),s=[bt,mt].indexOf(n)>=0?-1:1,o="function"==typeof i?i(Object.assign({},e,{placement:t})):i,r=o[0],a=o[1];return r=r||0,a=(a||0)*s,[bt,_t].indexOf(n)>=0?{x:a,y:r}:{x:r,y:a}}(i,e.rects,o),t}),{}),a=r[e.placement],l=a.x,c=a.y;null!=e.modifiersData.popperOffsets&&(e.modifiersData.popperOffsets.x+=l,e.modifiersData.popperOffsets.y+=c),e.modifiersData[n]=r}},Pe={name:"popperOffsets",enabled:!0,phase:"read",fn:function(t){var e=t.state,i=t.name;e.modifiersData[i]=Ce({reference:e.rects.reference,element:e.rects.popper,strategy:"absolute",placement:e.placement})},data:{}},je={name:"preventOverflow",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0!==r&&r,l=i.boundary,c=i.rootBoundary,h=i.altBoundary,d=i.padding,u=i.tether,f=void 0===u||u,p=i.tetherOffset,m=void 0===p?0:p,g=ke(e,{boundary:l,rootBoundary:c,padding:d,altBoundary:h}),_=Ut(e.placement),b=ce(e.placement),v=!b,y=ee(_),w="x"===y?"y":"x",E=e.modifiersData.popperOffsets,A=e.rects.reference,T=e.rects.popper,O="function"==typeof m?m(Object.assign({},e.rects,{placement:e.placement})):m,C={x:0,y:0};if(E){if(o||a){var k="y"===y?mt:bt,L="y"===y?gt:_t,x="y"===y?"height":"width",D=E[y],S=E[y]+g[k],N=E[y]-g[L],I=f?-T[x]/2:0,P=b===wt?A[x]:T[x],j=b===wt?-T[x]:-A[x],M=e.elements.arrow,H=f&&M?Kt(M):{width:0,height:0},B=e.modifiersData["arrow#persistent"]?e.modifiersData["arrow#persistent"].padding:{top:0,right:0,bottom:0,left:0},R=B[k],W=B[L],$=oe(0,A[x],H[x]),z=v?A[x]/2-I-$-R-O:P-$-R-O,q=v?-A[x]/2+I+$+W+O:j+$+W+O,F=e.elements.arrow&&te(e.elements.arrow),U=F?"y"===y?F.clientTop||0:F.clientLeft||0:0,V=e.modifiersData.offset?e.modifiersData.offset[e.placement][y]:0,K=E[y]+z-V-U,X=E[y]+q-V;if(o){var Y=oe(f?ne(S,K):S,D,f?ie(N,X):N);E[y]=Y,C[y]=Y-D}if(a){var Q="x"===y?mt:bt,G="x"===y?gt:_t,Z=E[w],J=Z+g[Q],tt=Z-g[G],et=oe(f?ne(J,K):J,Z,f?ie(tt,X):tt);E[w]=et,C[w]=et-Z}}e.modifiersData[n]=C}},requiresIfExists:["offset"]};function Me(t,e,i){void 0===i&&(i=!1);var n=zt(e);zt(e)&&function(t){var e=t.getBoundingClientRect();e.width,t.offsetWidth,e.height,t.offsetHeight}(e);var s,o,r=Gt(e),a=Vt(t),l={scrollLeft:0,scrollTop:0},c={x:0,y:0};return(n||!n&&!i)&&(("body"!==Rt(e)||we(r))&&(l=(s=e)!==Wt(s)&&zt(s)?{scrollLeft:(o=s).scrollLeft,scrollTop:o.scrollTop}:ve(s)),zt(e)?((c=Vt(e)).x+=e.clientLeft,c.y+=e.clientTop):r&&(c.x=ye(r))),{x:a.left+l.scrollLeft-c.x,y:a.top+l.scrollTop-c.y,width:a.width,height:a.height}}function He(t){var e=new Map,i=new Set,n=[];function s(t){i.add(t.name),[].concat(t.requires||[],t.requiresIfExists||[]).forEach((function(t){if(!i.has(t)){var n=e.get(t);n&&s(n)}})),n.push(t)}return t.forEach((function(t){e.set(t.name,t)})),t.forEach((function(t){i.has(t.name)||s(t)})),n}var Be={placement:"bottom",modifiers:[],strategy:"absolute"};function Re(){for(var t=arguments.length,e=new Array(t),i=0;ij.on(t,"mouseover",d))),this._element.focus(),this._element.setAttribute("aria-expanded",!0),this._menu.classList.add(Je),this._element.classList.add(Je),j.trigger(this._element,"shown.bs.dropdown",t)}hide(){if(c(this._element)||!this._isShown(this._menu))return;const t={relatedTarget:this._element};this._completeHide(t)}dispose(){this._popper&&this._popper.destroy(),super.dispose()}update(){this._inNavbar=this._detectNavbar(),this._popper&&this._popper.update()}_completeHide(t){j.trigger(this._element,"hide.bs.dropdown",t).defaultPrevented||("ontouchstart"in document.documentElement&&[].concat(...document.body.children).forEach((t=>j.off(t,"mouseover",d))),this._popper&&this._popper.destroy(),this._menu.classList.remove(Je),this._element.classList.remove(Je),this._element.setAttribute("aria-expanded","false"),U.removeDataAttribute(this._menu,"popper"),j.trigger(this._element,"hidden.bs.dropdown",t))}_getConfig(t){if(t={...this.constructor.Default,...U.getDataAttributes(this._element),...t},a(Ue,t,this.constructor.DefaultType),"object"==typeof t.reference&&!o(t.reference)&&"function"!=typeof t.reference.getBoundingClientRect)throw new TypeError(`${Ue.toUpperCase()}: Option "reference" provided type "object" without a required "getBoundingClientRect" method.`);return t}_createPopper(t){if(void 0===Fe)throw new TypeError("Bootstrap's dropdowns require Popper (https://popper.js.org)");let e=this._element;"parent"===this._config.reference?e=t:o(this._config.reference)?e=r(this._config.reference):"object"==typeof this._config.reference&&(e=this._config.reference);const i=this._getPopperConfig(),n=i.modifiers.find((t=>"applyStyles"===t.name&&!1===t.enabled));this._popper=qe(e,this._menu,i),n&&U.setDataAttribute(this._menu,"popper","static")}_isShown(t=this._element){return t.classList.contains(Je)}_getMenuElement(){return V.next(this._element,ei)[0]}_getPlacement(){const t=this._element.parentNode;if(t.classList.contains("dropend"))return ri;if(t.classList.contains("dropstart"))return ai;const e="end"===getComputedStyle(this._menu).getPropertyValue("--bs-position").trim();return t.classList.contains("dropup")?e?ni:ii:e?oi:si}_detectNavbar(){return null!==this._element.closest(".navbar")}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map((t=>Number.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_getPopperConfig(){const t={placement:this._getPlacement(),modifiers:[{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"offset",options:{offset:this._getOffset()}}]};return"static"===this._config.display&&(t.modifiers=[{name:"applyStyles",enabled:!1}]),{...t,..."function"==typeof this._config.popperConfig?this._config.popperConfig(t):this._config.popperConfig}}_selectMenuItem({key:t,target:e}){const i=V.find(".dropdown-menu .dropdown-item:not(.disabled):not(:disabled)",this._menu).filter(l);i.length&&v(i,e,t===Ye,!i.includes(e)).focus()}static jQueryInterface(t){return this.each((function(){const e=hi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}static clearMenus(t){if(t&&(2===t.button||"keyup"===t.type&&"Tab"!==t.key))return;const e=V.find(ti);for(let i=0,n=e.length;ie+t)),this._setElementAttributes(di,"paddingRight",(e=>e+t)),this._setElementAttributes(ui,"marginRight",(e=>e-t))}_disableOverFlow(){this._saveInitialAttribute(this._element,"overflow"),this._element.style.overflow="hidden"}_setElementAttributes(t,e,i){const n=this.getWidth();this._applyManipulationCallback(t,(t=>{if(t!==this._element&&window.innerWidth>t.clientWidth+n)return;this._saveInitialAttribute(t,e);const s=window.getComputedStyle(t)[e];t.style[e]=`${i(Number.parseFloat(s))}px`}))}reset(){this._resetElementAttributes(this._element,"overflow"),this._resetElementAttributes(this._element,"paddingRight"),this._resetElementAttributes(di,"paddingRight"),this._resetElementAttributes(ui,"marginRight")}_saveInitialAttribute(t,e){const i=t.style[e];i&&U.setDataAttribute(t,e,i)}_resetElementAttributes(t,e){this._applyManipulationCallback(t,(t=>{const i=U.getDataAttribute(t,e);void 0===i?t.style.removeProperty(e):(U.removeDataAttribute(t,e),t.style[e]=i)}))}_applyManipulationCallback(t,e){o(t)?e(t):V.find(t,this._element).forEach(e)}isOverflowing(){return this.getWidth()>0}}const pi={className:"modal-backdrop",isVisible:!0,isAnimated:!1,rootElement:"body",clickCallback:null},mi={className:"string",isVisible:"boolean",isAnimated:"boolean",rootElement:"(element|string)",clickCallback:"(function|null)"},gi="show",_i="mousedown.bs.backdrop";class bi{constructor(t){this._config=this._getConfig(t),this._isAppended=!1,this._element=null}show(t){this._config.isVisible?(this._append(),this._config.isAnimated&&u(this._getElement()),this._getElement().classList.add(gi),this._emulateAnimation((()=>{_(t)}))):_(t)}hide(t){this._config.isVisible?(this._getElement().classList.remove(gi),this._emulateAnimation((()=>{this.dispose(),_(t)}))):_(t)}_getElement(){if(!this._element){const t=document.createElement("div");t.className=this._config.className,this._config.isAnimated&&t.classList.add("fade"),this._element=t}return this._element}_getConfig(t){return(t={...pi,..."object"==typeof t?t:{}}).rootElement=r(t.rootElement),a("backdrop",t,mi),t}_append(){this._isAppended||(this._config.rootElement.append(this._getElement()),j.on(this._getElement(),_i,(()=>{_(this._config.clickCallback)})),this._isAppended=!0)}dispose(){this._isAppended&&(j.off(this._element,_i),this._element.remove(),this._isAppended=!1)}_emulateAnimation(t){b(t,this._getElement(),this._config.isAnimated)}}const vi={trapElement:null,autofocus:!0},yi={trapElement:"element",autofocus:"boolean"},wi=".bs.focustrap",Ei="backward";class Ai{constructor(t){this._config=this._getConfig(t),this._isActive=!1,this._lastTabNavDirection=null}activate(){const{trapElement:t,autofocus:e}=this._config;this._isActive||(e&&t.focus(),j.off(document,wi),j.on(document,"focusin.bs.focustrap",(t=>this._handleFocusin(t))),j.on(document,"keydown.tab.bs.focustrap",(t=>this._handleKeydown(t))),this._isActive=!0)}deactivate(){this._isActive&&(this._isActive=!1,j.off(document,wi))}_handleFocusin(t){const{target:e}=t,{trapElement:i}=this._config;if(e===document||e===i||i.contains(e))return;const n=V.focusableChildren(i);0===n.length?i.focus():this._lastTabNavDirection===Ei?n[n.length-1].focus():n[0].focus()}_handleKeydown(t){"Tab"===t.key&&(this._lastTabNavDirection=t.shiftKey?Ei:"forward")}_getConfig(t){return t={...vi,..."object"==typeof t?t:{}},a("focustrap",t,yi),t}}const Ti="modal",Oi="Escape",Ci={backdrop:!0,keyboard:!0,focus:!0},ki={backdrop:"(boolean|string)",keyboard:"boolean",focus:"boolean"},Li="hidden.bs.modal",xi="show.bs.modal",Di="resize.bs.modal",Si="click.dismiss.bs.modal",Ni="keydown.dismiss.bs.modal",Ii="mousedown.dismiss.bs.modal",Pi="modal-open",ji="show",Mi="modal-static";class Hi extends B{constructor(t,e){super(t),this._config=this._getConfig(e),this._dialog=V.findOne(".modal-dialog",this._element),this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._isShown=!1,this._ignoreBackdropClick=!1,this._isTransitioning=!1,this._scrollBar=new fi}static get Default(){return Ci}static get NAME(){return Ti}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||this._isTransitioning||j.trigger(this._element,xi,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._isAnimated()&&(this._isTransitioning=!0),this._scrollBar.hide(),document.body.classList.add(Pi),this._adjustDialog(),this._setEscapeEvent(),this._setResizeEvent(),j.on(this._dialog,Ii,(()=>{j.one(this._element,"mouseup.dismiss.bs.modal",(t=>{t.target===this._element&&(this._ignoreBackdropClick=!0)}))})),this._showBackdrop((()=>this._showElement(t))))}hide(){if(!this._isShown||this._isTransitioning)return;if(j.trigger(this._element,"hide.bs.modal").defaultPrevented)return;this._isShown=!1;const t=this._isAnimated();t&&(this._isTransitioning=!0),this._setEscapeEvent(),this._setResizeEvent(),this._focustrap.deactivate(),this._element.classList.remove(ji),j.off(this._element,Si),j.off(this._dialog,Ii),this._queueCallback((()=>this._hideModal()),this._element,t)}dispose(){[window,this._dialog].forEach((t=>j.off(t,".bs.modal"))),this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}handleUpdate(){this._adjustDialog()}_initializeBackDrop(){return new bi({isVisible:Boolean(this._config.backdrop),isAnimated:this._isAnimated()})}_initializeFocusTrap(){return new Ai({trapElement:this._element})}_getConfig(t){return t={...Ci,...U.getDataAttributes(this._element),..."object"==typeof t?t:{}},a(Ti,t,ki),t}_showElement(t){const e=this._isAnimated(),i=V.findOne(".modal-body",this._dialog);this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE||document.body.append(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.scrollTop=0,i&&(i.scrollTop=0),e&&u(this._element),this._element.classList.add(ji),this._queueCallback((()=>{this._config.focus&&this._focustrap.activate(),this._isTransitioning=!1,j.trigger(this._element,"shown.bs.modal",{relatedTarget:t})}),this._dialog,e)}_setEscapeEvent(){this._isShown?j.on(this._element,Ni,(t=>{this._config.keyboard&&t.key===Oi?(t.preventDefault(),this.hide()):this._config.keyboard||t.key!==Oi||this._triggerBackdropTransition()})):j.off(this._element,Ni)}_setResizeEvent(){this._isShown?j.on(window,Di,(()=>this._adjustDialog())):j.off(window,Di)}_hideModal(){this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._isTransitioning=!1,this._backdrop.hide((()=>{document.body.classList.remove(Pi),this._resetAdjustments(),this._scrollBar.reset(),j.trigger(this._element,Li)}))}_showBackdrop(t){j.on(this._element,Si,(t=>{this._ignoreBackdropClick?this._ignoreBackdropClick=!1:t.target===t.currentTarget&&(!0===this._config.backdrop?this.hide():"static"===this._config.backdrop&&this._triggerBackdropTransition())})),this._backdrop.show(t)}_isAnimated(){return this._element.classList.contains("fade")}_triggerBackdropTransition(){if(j.trigger(this._element,"hidePrevented.bs.modal").defaultPrevented)return;const{classList:t,scrollHeight:e,style:i}=this._element,n=e>document.documentElement.clientHeight;!n&&"hidden"===i.overflowY||t.contains(Mi)||(n||(i.overflowY="hidden"),t.add(Mi),this._queueCallback((()=>{t.remove(Mi),n||this._queueCallback((()=>{i.overflowY=""}),this._dialog)}),this._dialog),this._element.focus())}_adjustDialog(){const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._scrollBar.getWidth(),i=e>0;(!i&&t&&!m()||i&&!t&&m())&&(this._element.style.paddingLeft=`${e}px`),(i&&!t&&!m()||!i&&t&&m())&&(this._element.style.paddingRight=`${e}px`)}_resetAdjustments(){this._element.style.paddingLeft="",this._element.style.paddingRight=""}static jQueryInterface(t,e){return this.each((function(){const i=Hi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t](e)}}))}}j.on(document,"click.bs.modal.data-api",'[data-bs-toggle="modal"]',(function(t){const e=n(this);["A","AREA"].includes(this.tagName)&&t.preventDefault(),j.one(e,xi,(t=>{t.defaultPrevented||j.one(e,Li,(()=>{l(this)&&this.focus()}))}));const i=V.findOne(".modal.show");i&&Hi.getInstance(i).hide(),Hi.getOrCreateInstance(e).toggle(this)})),R(Hi),g(Hi);const Bi="offcanvas",Ri={backdrop:!0,keyboard:!0,scroll:!1},Wi={backdrop:"boolean",keyboard:"boolean",scroll:"boolean"},$i="show",zi=".offcanvas.show",qi="hidden.bs.offcanvas";class Fi extends B{constructor(t,e){super(t),this._config=this._getConfig(e),this._isShown=!1,this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._addEventListeners()}static get NAME(){return Bi}static get Default(){return Ri}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||j.trigger(this._element,"show.bs.offcanvas",{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._element.style.visibility="visible",this._backdrop.show(),this._config.scroll||(new fi).hide(),this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.classList.add($i),this._queueCallback((()=>{this._config.scroll||this._focustrap.activate(),j.trigger(this._element,"shown.bs.offcanvas",{relatedTarget:t})}),this._element,!0))}hide(){this._isShown&&(j.trigger(this._element,"hide.bs.offcanvas").defaultPrevented||(this._focustrap.deactivate(),this._element.blur(),this._isShown=!1,this._element.classList.remove($i),this._backdrop.hide(),this._queueCallback((()=>{this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._element.style.visibility="hidden",this._config.scroll||(new fi).reset(),j.trigger(this._element,qi)}),this._element,!0)))}dispose(){this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}_getConfig(t){return t={...Ri,...U.getDataAttributes(this._element),..."object"==typeof t?t:{}},a(Bi,t,Wi),t}_initializeBackDrop(){return new bi({className:"offcanvas-backdrop",isVisible:this._config.backdrop,isAnimated:!0,rootElement:this._element.parentNode,clickCallback:()=>this.hide()})}_initializeFocusTrap(){return new Ai({trapElement:this._element})}_addEventListeners(){j.on(this._element,"keydown.dismiss.bs.offcanvas",(t=>{this._config.keyboard&&"Escape"===t.key&&this.hide()}))}static jQueryInterface(t){return this.each((function(){const e=Fi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}j.on(document,"click.bs.offcanvas.data-api",'[data-bs-toggle="offcanvas"]',(function(t){const e=n(this);if(["A","AREA"].includes(this.tagName)&&t.preventDefault(),c(this))return;j.one(e,qi,(()=>{l(this)&&this.focus()}));const i=V.findOne(zi);i&&i!==e&&Fi.getInstance(i).hide(),Fi.getOrCreateInstance(e).toggle(this)})),j.on(window,"load.bs.offcanvas.data-api",(()=>V.find(zi).forEach((t=>Fi.getOrCreateInstance(t).show())))),R(Fi),g(Fi);const Ui=new Set(["background","cite","href","itemtype","longdesc","poster","src","xlink:href"]),Vi=/^(?:(?:https?|mailto|ftp|tel|file|sms):|[^#&/:?]*(?:[#/?]|$))/i,Ki=/^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[\d+/a-z]+=*$/i,Xi=(t,e)=>{const i=t.nodeName.toLowerCase();if(e.includes(i))return!Ui.has(i)||Boolean(Vi.test(t.nodeValue)||Ki.test(t.nodeValue));const n=e.filter((t=>t instanceof RegExp));for(let t=0,e=n.length;t{Xi(t,r)||i.removeAttribute(t.nodeName)}))}return n.body.innerHTML}const Qi="tooltip",Gi=new Set(["sanitize","allowList","sanitizeFn"]),Zi={animation:"boolean",template:"string",title:"(string|element|function)",trigger:"string",delay:"(number|object)",html:"boolean",selector:"(string|boolean)",placement:"(string|function)",offset:"(array|string|function)",container:"(string|element|boolean)",fallbackPlacements:"array",boundary:"(string|element)",customClass:"(string|function)",sanitize:"boolean",sanitizeFn:"(null|function)",allowList:"object",popperConfig:"(null|object|function)"},Ji={AUTO:"auto",TOP:"top",RIGHT:m()?"left":"right",BOTTOM:"bottom",LEFT:m()?"right":"left"},tn={animation:!0,template:'',trigger:"hover focus",title:"",delay:0,html:!1,selector:!1,placement:"top",offset:[0,0],container:!1,fallbackPlacements:["top","right","bottom","left"],boundary:"clippingParents",customClass:"",sanitize:!0,sanitizeFn:null,allowList:{"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],div:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","srcset","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},popperConfig:null},en={HIDE:"hide.bs.tooltip",HIDDEN:"hidden.bs.tooltip",SHOW:"show.bs.tooltip",SHOWN:"shown.bs.tooltip",INSERTED:"inserted.bs.tooltip",CLICK:"click.bs.tooltip",FOCUSIN:"focusin.bs.tooltip",FOCUSOUT:"focusout.bs.tooltip",MOUSEENTER:"mouseenter.bs.tooltip",MOUSELEAVE:"mouseleave.bs.tooltip"},nn="fade",sn="show",on="show",rn="out",an=".tooltip-inner",ln=".modal",cn="hide.bs.modal",hn="hover",dn="focus";class un extends B{constructor(t,e){if(void 0===Fe)throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org)");super(t),this._isEnabled=!0,this._timeout=0,this._hoverState="",this._activeTrigger={},this._popper=null,this._config=this._getConfig(e),this.tip=null,this._setListeners()}static get Default(){return tn}static get NAME(){return Qi}static get Event(){return en}static get DefaultType(){return Zi}enable(){this._isEnabled=!0}disable(){this._isEnabled=!1}toggleEnabled(){this._isEnabled=!this._isEnabled}toggle(t){if(this._isEnabled)if(t){const e=this._initializeOnDelegatedTarget(t);e._activeTrigger.click=!e._activeTrigger.click,e._isWithActiveTrigger()?e._enter(null,e):e._leave(null,e)}else{if(this.getTipElement().classList.contains(sn))return void this._leave(null,this);this._enter(null,this)}}dispose(){clearTimeout(this._timeout),j.off(this._element.closest(ln),cn,this._hideModalHandler),this.tip&&this.tip.remove(),this._disposePopper(),super.dispose()}show(){if("none"===this._element.style.display)throw new Error("Please use show on visible elements");if(!this.isWithContent()||!this._isEnabled)return;const t=j.trigger(this._element,this.constructor.Event.SHOW),e=h(this._element),i=null===e?this._element.ownerDocument.documentElement.contains(this._element):e.contains(this._element);if(t.defaultPrevented||!i)return;"tooltip"===this.constructor.NAME&&this.tip&&this.getTitle()!==this.tip.querySelector(an).innerHTML&&(this._disposePopper(),this.tip.remove(),this.tip=null);const n=this.getTipElement(),s=(t=>{do{t+=Math.floor(1e6*Math.random())}while(document.getElementById(t));return t})(this.constructor.NAME);n.setAttribute("id",s),this._element.setAttribute("aria-describedby",s),this._config.animation&&n.classList.add(nn);const o="function"==typeof this._config.placement?this._config.placement.call(this,n,this._element):this._config.placement,r=this._getAttachment(o);this._addAttachmentClass(r);const{container:a}=this._config;H.set(n,this.constructor.DATA_KEY,this),this._element.ownerDocument.documentElement.contains(this.tip)||(a.append(n),j.trigger(this._element,this.constructor.Event.INSERTED)),this._popper?this._popper.update():this._popper=qe(this._element,n,this._getPopperConfig(r)),n.classList.add(sn);const l=this._resolvePossibleFunction(this._config.customClass);l&&n.classList.add(...l.split(" ")),"ontouchstart"in document.documentElement&&[].concat(...document.body.children).forEach((t=>{j.on(t,"mouseover",d)}));const c=this.tip.classList.contains(nn);this._queueCallback((()=>{const t=this._hoverState;this._hoverState=null,j.trigger(this._element,this.constructor.Event.SHOWN),t===rn&&this._leave(null,this)}),this.tip,c)}hide(){if(!this._popper)return;const t=this.getTipElement();if(j.trigger(this._element,this.constructor.Event.HIDE).defaultPrevented)return;t.classList.remove(sn),"ontouchstart"in document.documentElement&&[].concat(...document.body.children).forEach((t=>j.off(t,"mouseover",d))),this._activeTrigger.click=!1,this._activeTrigger.focus=!1,this._activeTrigger.hover=!1;const e=this.tip.classList.contains(nn);this._queueCallback((()=>{this._isWithActiveTrigger()||(this._hoverState!==on&&t.remove(),this._cleanTipClass(),this._element.removeAttribute("aria-describedby"),j.trigger(this._element,this.constructor.Event.HIDDEN),this._disposePopper())}),this.tip,e),this._hoverState=""}update(){null!==this._popper&&this._popper.update()}isWithContent(){return Boolean(this.getTitle())}getTipElement(){if(this.tip)return this.tip;const t=document.createElement("div");t.innerHTML=this._config.template;const e=t.children[0];return this.setContent(e),e.classList.remove(nn,sn),this.tip=e,this.tip}setContent(t){this._sanitizeAndSetContent(t,this.getTitle(),an)}_sanitizeAndSetContent(t,e,i){const n=V.findOne(i,t);e||!n?this.setElementContent(n,e):n.remove()}setElementContent(t,e){if(null!==t)return o(e)?(e=r(e),void(this._config.html?e.parentNode!==t&&(t.innerHTML="",t.append(e)):t.textContent=e.textContent)):void(this._config.html?(this._config.sanitize&&(e=Yi(e,this._config.allowList,this._config.sanitizeFn)),t.innerHTML=e):t.textContent=e)}getTitle(){const t=this._element.getAttribute("data-bs-original-title")||this._config.title;return this._resolvePossibleFunction(t)}updateAttachment(t){return"right"===t?"end":"left"===t?"start":t}_initializeOnDelegatedTarget(t,e){return e||this.constructor.getOrCreateInstance(t.delegateTarget,this._getDelegateConfig())}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map((t=>Number.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_resolvePossibleFunction(t){return"function"==typeof t?t.call(this._element):t}_getPopperConfig(t){const e={placement:t,modifiers:[{name:"flip",options:{fallbackPlacements:this._config.fallbackPlacements}},{name:"offset",options:{offset:this._getOffset()}},{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"arrow",options:{element:`.${this.constructor.NAME}-arrow`}},{name:"onChange",enabled:!0,phase:"afterWrite",fn:t=>this._handlePopperPlacementChange(t)}],onFirstUpdate:t=>{t.options.placement!==t.placement&&this._handlePopperPlacementChange(t)}};return{...e,..."function"==typeof this._config.popperConfig?this._config.popperConfig(e):this._config.popperConfig}}_addAttachmentClass(t){this.getTipElement().classList.add(`${this._getBasicClassPrefix()}-${this.updateAttachment(t)}`)}_getAttachment(t){return Ji[t.toUpperCase()]}_setListeners(){this._config.trigger.split(" ").forEach((t=>{if("click"===t)j.on(this._element,this.constructor.Event.CLICK,this._config.selector,(t=>this.toggle(t)));else if("manual"!==t){const e=t===hn?this.constructor.Event.MOUSEENTER:this.constructor.Event.FOCUSIN,i=t===hn?this.constructor.Event.MOUSELEAVE:this.constructor.Event.FOCUSOUT;j.on(this._element,e,this._config.selector,(t=>this._enter(t))),j.on(this._element,i,this._config.selector,(t=>this._leave(t)))}})),this._hideModalHandler=()=>{this._element&&this.hide()},j.on(this._element.closest(ln),cn,this._hideModalHandler),this._config.selector?this._config={...this._config,trigger:"manual",selector:""}:this._fixTitle()}_fixTitle(){const t=this._element.getAttribute("title"),e=typeof this._element.getAttribute("data-bs-original-title");(t||"string"!==e)&&(this._element.setAttribute("data-bs-original-title",t||""),!t||this._element.getAttribute("aria-label")||this._element.textContent||this._element.setAttribute("aria-label",t),this._element.setAttribute("title",""))}_enter(t,e){e=this._initializeOnDelegatedTarget(t,e),t&&(e._activeTrigger["focusin"===t.type?dn:hn]=!0),e.getTipElement().classList.contains(sn)||e._hoverState===on?e._hoverState=on:(clearTimeout(e._timeout),e._hoverState=on,e._config.delay&&e._config.delay.show?e._timeout=setTimeout((()=>{e._hoverState===on&&e.show()}),e._config.delay.show):e.show())}_leave(t,e){e=this._initializeOnDelegatedTarget(t,e),t&&(e._activeTrigger["focusout"===t.type?dn:hn]=e._element.contains(t.relatedTarget)),e._isWithActiveTrigger()||(clearTimeout(e._timeout),e._hoverState=rn,e._config.delay&&e._config.delay.hide?e._timeout=setTimeout((()=>{e._hoverState===rn&&e.hide()}),e._config.delay.hide):e.hide())}_isWithActiveTrigger(){for(const t in this._activeTrigger)if(this._activeTrigger[t])return!0;return!1}_getConfig(t){const e=U.getDataAttributes(this._element);return Object.keys(e).forEach((t=>{Gi.has(t)&&delete e[t]})),(t={...this.constructor.Default,...e,..."object"==typeof t&&t?t:{}}).container=!1===t.container?document.body:r(t.container),"number"==typeof t.delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),a(Qi,t,this.constructor.DefaultType),t.sanitize&&(t.template=Yi(t.template,t.allowList,t.sanitizeFn)),t}_getDelegateConfig(){const t={};for(const e in this._config)this.constructor.Default[e]!==this._config[e]&&(t[e]=this._config[e]);return t}_cleanTipClass(){const t=this.getTipElement(),e=new RegExp(`(^|\\s)${this._getBasicClassPrefix()}\\S+`,"g"),i=t.getAttribute("class").match(e);null!==i&&i.length>0&&i.map((t=>t.trim())).forEach((e=>t.classList.remove(e)))}_getBasicClassPrefix(){return"bs-tooltip"}_handlePopperPlacementChange(t){const{state:e}=t;e&&(this.tip=e.elements.popper,this._cleanTipClass(),this._addAttachmentClass(this._getAttachment(e.placement)))}_disposePopper(){this._popper&&(this._popper.destroy(),this._popper=null)}static jQueryInterface(t){return this.each((function(){const e=un.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}g(un);const fn={...un.Default,placement:"right",offset:[0,8],trigger:"click",content:"",template:''},pn={...un.DefaultType,content:"(string|element|function)"},mn={HIDE:"hide.bs.popover",HIDDEN:"hidden.bs.popover",SHOW:"show.bs.popover",SHOWN:"shown.bs.popover",INSERTED:"inserted.bs.popover",CLICK:"click.bs.popover",FOCUSIN:"focusin.bs.popover",FOCUSOUT:"focusout.bs.popover",MOUSEENTER:"mouseenter.bs.popover",MOUSELEAVE:"mouseleave.bs.popover"};class gn extends un{static get Default(){return fn}static get NAME(){return"popover"}static get Event(){return mn}static get DefaultType(){return pn}isWithContent(){return this.getTitle()||this._getContent()}setContent(t){this._sanitizeAndSetContent(t,this.getTitle(),".popover-header"),this._sanitizeAndSetContent(t,this._getContent(),".popover-body")}_getContent(){return this._resolvePossibleFunction(this._config.content)}_getBasicClassPrefix(){return"bs-popover"}static jQueryInterface(t){return this.each((function(){const e=gn.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}g(gn);const _n="scrollspy",bn={offset:10,method:"auto",target:""},vn={offset:"number",method:"string",target:"(string|element)"},yn="active",wn=".nav-link, .list-group-item, .dropdown-item",En="position";class An extends B{constructor(t,e){super(t),this._scrollElement="BODY"===this._element.tagName?window:this._element,this._config=this._getConfig(e),this._offsets=[],this._targets=[],this._activeTarget=null,this._scrollHeight=0,j.on(this._scrollElement,"scroll.bs.scrollspy",(()=>this._process())),this.refresh(),this._process()}static get Default(){return bn}static get NAME(){return _n}refresh(){const t=this._scrollElement===this._scrollElement.window?"offset":En,e="auto"===this._config.method?t:this._config.method,n=e===En?this._getScrollTop():0;this._offsets=[],this._targets=[],this._scrollHeight=this._getScrollHeight(),V.find(wn,this._config.target).map((t=>{const s=i(t),o=s?V.findOne(s):null;if(o){const t=o.getBoundingClientRect();if(t.width||t.height)return[U[e](o).top+n,s]}return null})).filter((t=>t)).sort(((t,e)=>t[0]-e[0])).forEach((t=>{this._offsets.push(t[0]),this._targets.push(t[1])}))}dispose(){j.off(this._scrollElement,".bs.scrollspy"),super.dispose()}_getConfig(t){return(t={...bn,...U.getDataAttributes(this._element),..."object"==typeof t&&t?t:{}}).target=r(t.target)||document.documentElement,a(_n,t,vn),t}_getScrollTop(){return this._scrollElement===window?this._scrollElement.pageYOffset:this._scrollElement.scrollTop}_getScrollHeight(){return this._scrollElement.scrollHeight||Math.max(document.body.scrollHeight,document.documentElement.scrollHeight)}_getOffsetHeight(){return this._scrollElement===window?window.innerHeight:this._scrollElement.getBoundingClientRect().height}_process(){const t=this._getScrollTop()+this._config.offset,e=this._getScrollHeight(),i=this._config.offset+e-this._getOffsetHeight();if(this._scrollHeight!==e&&this.refresh(),t>=i){const t=this._targets[this._targets.length-1];this._activeTarget!==t&&this._activate(t)}else{if(this._activeTarget&&t0)return this._activeTarget=null,void this._clear();for(let e=this._offsets.length;e--;)this._activeTarget!==this._targets[e]&&t>=this._offsets[e]&&(void 0===this._offsets[e+1]||t`${e}[data-bs-target="${t}"],${e}[href="${t}"]`)),i=V.findOne(e.join(","),this._config.target);i.classList.add(yn),i.classList.contains("dropdown-item")?V.findOne(".dropdown-toggle",i.closest(".dropdown")).classList.add(yn):V.parents(i,".nav, .list-group").forEach((t=>{V.prev(t,".nav-link, .list-group-item").forEach((t=>t.classList.add(yn))),V.prev(t,".nav-item").forEach((t=>{V.children(t,".nav-link").forEach((t=>t.classList.add(yn)))}))})),j.trigger(this._scrollElement,"activate.bs.scrollspy",{relatedTarget:t})}_clear(){V.find(wn,this._config.target).filter((t=>t.classList.contains(yn))).forEach((t=>t.classList.remove(yn)))}static jQueryInterface(t){return this.each((function(){const e=An.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}j.on(window,"load.bs.scrollspy.data-api",(()=>{V.find('[data-bs-spy="scroll"]').forEach((t=>new An(t)))})),g(An);const Tn="active",On="fade",Cn="show",kn=".active",Ln=":scope > li > .active";class xn extends B{static get NAME(){return"tab"}show(){if(this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE&&this._element.classList.contains(Tn))return;let t;const e=n(this._element),i=this._element.closest(".nav, .list-group");if(i){const e="UL"===i.nodeName||"OL"===i.nodeName?Ln:kn;t=V.find(e,i),t=t[t.length-1]}const s=t?j.trigger(t,"hide.bs.tab",{relatedTarget:this._element}):null;if(j.trigger(this._element,"show.bs.tab",{relatedTarget:t}).defaultPrevented||null!==s&&s.defaultPrevented)return;this._activate(this._element,i);const o=()=>{j.trigger(t,"hidden.bs.tab",{relatedTarget:this._element}),j.trigger(this._element,"shown.bs.tab",{relatedTarget:t})};e?this._activate(e,e.parentNode,o):o()}_activate(t,e,i){const n=(!e||"UL"!==e.nodeName&&"OL"!==e.nodeName?V.children(e,kn):V.find(Ln,e))[0],s=i&&n&&n.classList.contains(On),o=()=>this._transitionComplete(t,n,i);n&&s?(n.classList.remove(Cn),this._queueCallback(o,t,!0)):o()}_transitionComplete(t,e,i){if(e){e.classList.remove(Tn);const t=V.findOne(":scope > .dropdown-menu .active",e.parentNode);t&&t.classList.remove(Tn),"tab"===e.getAttribute("role")&&e.setAttribute("aria-selected",!1)}t.classList.add(Tn),"tab"===t.getAttribute("role")&&t.setAttribute("aria-selected",!0),u(t),t.classList.contains(On)&&t.classList.add(Cn);let n=t.parentNode;if(n&&"LI"===n.nodeName&&(n=n.parentNode),n&&n.classList.contains("dropdown-menu")){const e=t.closest(".dropdown");e&&V.find(".dropdown-toggle",e).forEach((t=>t.classList.add(Tn))),t.setAttribute("aria-expanded",!0)}i&&i()}static jQueryInterface(t){return this.each((function(){const e=xn.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}j.on(document,"click.bs.tab.data-api",'[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]',(function(t){["A","AREA"].includes(this.tagName)&&t.preventDefault(),c(this)||xn.getOrCreateInstance(this).show()})),g(xn);const Dn="toast",Sn="hide",Nn="show",In="showing",Pn={animation:"boolean",autohide:"boolean",delay:"number"},jn={animation:!0,autohide:!0,delay:5e3};class Mn extends B{constructor(t,e){super(t),this._config=this._getConfig(e),this._timeout=null,this._hasMouseInteraction=!1,this._hasKeyboardInteraction=!1,this._setListeners()}static get DefaultType(){return Pn}static get Default(){return jn}static get NAME(){return Dn}show(){j.trigger(this._element,"show.bs.toast").defaultPrevented||(this._clearTimeout(),this._config.animation&&this._element.classList.add("fade"),this._element.classList.remove(Sn),u(this._element),this._element.classList.add(Nn),this._element.classList.add(In),this._queueCallback((()=>{this._element.classList.remove(In),j.trigger(this._element,"shown.bs.toast"),this._maybeScheduleHide()}),this._element,this._config.animation))}hide(){this._element.classList.contains(Nn)&&(j.trigger(this._element,"hide.bs.toast").defaultPrevented||(this._element.classList.add(In),this._queueCallback((()=>{this._element.classList.add(Sn),this._element.classList.remove(In),this._element.classList.remove(Nn),j.trigger(this._element,"hidden.bs.toast")}),this._element,this._config.animation)))}dispose(){this._clearTimeout(),this._element.classList.contains(Nn)&&this._element.classList.remove(Nn),super.dispose()}_getConfig(t){return t={...jn,...U.getDataAttributes(this._element),..."object"==typeof t&&t?t:{}},a(Dn,t,this.constructor.DefaultType),t}_maybeScheduleHide(){this._config.autohide&&(this._hasMouseInteraction||this._hasKeyboardInteraction||(this._timeout=setTimeout((()=>{this.hide()}),this._config.delay)))}_onInteraction(t,e){case(t.type){case"mouseover":case"mouseout":this._hasMouseInteraction=e;break;case"focusin":case"focusout":this._hasKeyboardInteraction=e}if(e)return void this._clearTimeout();const i=t.relatedTarget;this._element===i||this._element.contains(i)||this._maybeScheduleHide()}_setListeners(){j.on(this._element,"mouseover.bs.toast",(t=>this._onInteraction(t,!0))),j.on(this._element,"mouseout.bs.toast",(t=>this._onInteraction(t,!1))),j.on(this._element,"focusin.bs.toast",(t=>this._onInteraction(t,!0))),j.on(this._element,"focusout.bs.toast",(t=>this._onInteraction(t,!1)))}_clearTimeout(){clearTimeout(this._timeout),this._timeout=null}static jQueryInterface(t){return this.each((function(){const e=Mn.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}return R(Mn),g(Mn),{Alert:W,Button:z,Carousel:st,Collapse:pt,Dropdown:hi,Modal:Hi,Offcanvas:Fi,Popover:gn,ScrollSpy:An,Tab:xn,Toast:Mn,Tooltip:un}})); //# sourceMappingURL=bootstrap.bundle.min.js.map diff --git a/website/themes/prql-theme/static/plugins/highlight/highlight.min.js b/website/themes/prql-theme/static/plugins/highlight/highlight.min.js index 4bb7f08157d4..9c9d11726b67 100644 --- a/website/themes/prql-theme/static/plugins/highlight/highlight.min.js +++ b/website/themes/prql-theme/static/plugins/highlight/highlight.min.js @@ -304,7 +304,7 @@ anyNumberOfTimes:u};for(const t in A)"object"==typeof A[t]&&e.exports(A[t]) ;return Object.assign(t,A),t})({});return te}() ;"object"==typeof exports&&"undefined"!=typeof module&&(module.exports=hljs);/*! `javascript` grammar compiled for Highlight.js 11.7.0 */ (()=>{var e=(()=>{"use strict" -;const e="[A-Za-z$_][0-9A-Za-z$_]*",n=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","switch","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends"],a=["true","false","null","undefined","NaN","Infinity"],t=["Object","Function","Boolean","Symbol","Math","Date","Number","BigInt","String","RegExp","Array","Float32Array","Float64Array","Int8Array","Uint8Array","Uint8ClampedArray","Int16Array","Int32Array","Uint16Array","Uint32Array","BigInt64Array","BigUint64Array","Set","Map","WeakSet","WeakMap","ArrayBuffer","SharedArrayBuffer","Atomics","DataView","JSON","Promise","Generator","GeneratorFunction","AsyncFunction","Reflect","Proxy","Intl","WebAssembly"],s=["Error","EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"],r=["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],c=["arguments","this","super","console","window","document","localStorage","module","global"],i=[].concat(r,t,s) +;const e="[A-Za-z$_][0-9A-Za-z$_]*",n=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","case","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends"],a=["true","false","null","undefined","NaN","Infinity"],t=["Object","Function","Boolean","Symbol","Math","Date","Number","BigInt","String","RegExp","Array","Float32Array","Float64Array","Int8Array","Uint8Array","Uint8ClampedArray","Int16Array","Int32Array","Uint16Array","Uint32Array","BigInt64Array","BigUint64Array","Set","Map","WeakSet","WeakMap","ArrayBuffer","SharedArrayBuffer","Atomics","DataView","JSON","Promise","Generator","GeneratorFunction","AsyncFunction","Reflect","Proxy","Intl","WebAssembly"],s=["Error","EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"],r=["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],c=["arguments","this","super","console","window","document","localStorage","module","global"],i=[].concat(r,t,s) ;return o=>{const l=o.regex,b=e,d={begin:/<[A-Za-z0-9\\._:-]+/, end:/\/[A-Za-z0-9\\._:-]+>|\/>/,isTrulyOpeningTag:(e,n)=>{ const a=e[0].length+e.index,t=e.input[a] @@ -372,7 +372,7 @@ relevance:0},{variants:[{begin:"<>",end:""},{ match:/<[A-Za-z0-9\\._:-]+\s*\/>/},{begin:d.begin, "on:begin":d.isTrulyOpeningTag,end:d.end}],subLanguage:"xml",contains:[{ begin:d.begin,end:d.end,skip:!0,contains:["self"]}]}]},O,{ -beginKeywords:"while if switch catch for"},{ +beginKeywords:"while if case catch for"},{ begin:"\\b(?!function)"+o.UNDERSCORE_IDENT_RE+"\\([^()]*(\\([^()]*(\\([^()]*\\)[^()]*)*\\)[^()]*)*\\)\\s*\\{", returnBegin:!0,label:"func.def",contains:[S,o.inherit(o.TITLE_MODE,{begin:b, className:"title.function"})]},{match:/\.\.\./,relevance:0},x,{match:"\\$"+b, diff --git a/website/themes/prql-theme/static/plugins/highlight/prql.js b/website/themes/prql-theme/static/plugins/highlight/prql.js index ed51a6923d3c..c5bb78a9a230 100644 --- a/website/themes/prql-theme/static/plugins/highlight/prql.js +++ b/website/themes/prql-theme/static/plugins/highlight/prql.js @@ -23,7 +23,7 @@ formatting = function (hljs) { "union", "window", ]; - const BUILTIN_FUNCTIONS = ["switch", "in", "as"]; + const BUILTIN_FUNCTIONS = ["case", "in", "as"]; const KEYWORDS = ["func", "let", "prql"]; return { name: "PRQL", From 080b74776f9aeb6870d10e49cd0913ace4193c72 Mon Sep 17 00:00:00 2001 From: eitsupi <50911393+eitsupi@users.noreply.github.com> Date: Wed, 8 Mar 2023 07:09:30 +0900 Subject: [PATCH 101/106] build: add basic devcontainer.json (for Rust, JavaScript, Python) (#1893) * chore: add devcontainer config file * build: add base devcontainer definition and build workflow file * First cut, very low-quality draft for Dev Containers I have written about 98% of what I know. Let's all contribute to strengthen this document. Thanks. * Remove "will" in favor of direct action words. It's almost always better to write documentation saying "thing X _does_ action Y" instead of "thing X will do action Y". * Update using-dev-container.md * Update using-dev-container.md * Final editorial tweak for first-cut description * Update to reflect @eitsupi's comments * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * docs: some updates about VS Code Dev Containers * docs: update title and add note * docs: add a link to containers.dev * docs: formatting lists * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * build: use only Dockerfile for base pre-built image * ci: update workflow to use docker/build-push-action * chore: autoformatting * build: fix workflow trigger * chore: fix path * fix: fix GHA syntax * fix: fix typo * ci: use docker/metadata-action to prepare tags * build: use pre-built image as devcontainer base image * build: remove task for devcontainer setup for now * chore: sync vscode extensions in devcontainer.json * docs: some document update and install zsh completion * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * docs: add the page about devcontainers to the book * build: set postCreateCommand * chore: fix version of go-task Dev Container Feature * docs: remove superfluous comment --------- Co-authored-by: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Co-authored-by: Rich Brown Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .devcontainer/devcontainer.json | 33 +++++++++++++++++++ book/src/SUMMARY.md | 1 + book/src/contributing/dev-container.md | 45 ++++++++++++++++++++++++++ 3 files changed, 79 insertions(+) create mode 100644 .devcontainer/devcontainer.json create mode 100644 book/src/contributing/dev-container.md diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 000000000000..8af2eec50d0e --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,33 @@ +// Dev Container for Rust, website, prql-js and prql-python +{ + "image": "ghcr.io/prql/prql-devcontainer-base:latest", + "features": { + "ghcr.io/devcontainers/features/hugo:1": {}, + "ghcr.io/devcontainers/features/python:1": {}, + "ghcr.io/devcontainers/features/node:1": {}, + "ghcr.io/eitsupi/devcontainer-features/go-task:1": {} + }, + "customizations": { + "vscode": { + "extensions": [ + // Keep in sync with Taskfile.yml + "prql-lang.prql-vscode", + "rust-lang.rust-analyzer", + "mitsuhiko.insta", + "esbenp.prettier-vscode", + "budparr.language-hugo-vscode" + ] + } + }, + "mounts": [ + { + "source": "devcontainer-cargo-cache", + "target": "/usr/local/cargo", + "type": "volume" + } + ], + "postCreateCommand": { + "install-maturin": "task install-maturin", + "install-npm-dependencies": "task install-npm-dependencies" + } +} diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md index d8dea5cd6719..db5d7a8d3e5b 100644 --- a/book/src/SUMMARY.md +++ b/book/src/SUMMARY.md @@ -73,6 +73,7 @@ - [Development](./contributing/development.md) - [Using Docker](./contributing/using-docker.md) + - [Develop in Dev Containers](./contributing/dev-container.md) - [Internals](./internals/README.md) diff --git a/book/src/contributing/dev-container.md b/book/src/contributing/dev-container.md new file mode 100644 index 000000000000..7157a67b5975 --- /dev/null +++ b/book/src/contributing/dev-container.md @@ -0,0 +1,45 @@ +# Develop in Dev Containers + +```admonish note +Currently the Dev Container included in this repository only supports the `amd64` platform. +``` + +[Dev Containers](https://containers.dev/) are a way to package a number of +"developer tools" (compilers, bundlers, package managers, loaders, etc.) into a +single object. This is helpful when many people want to contribute to a project: +each person only has to install the (single) Dev Container on their own machine +to start working. By definition, the Dev Container has a consistent set of tools +that are known to work together. This avoids a fuss with finding the proper +versions of each of the build tools. + +To use a Dev Container on your local computer with VS Code, you must install the +[VS Code Dev Containers extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) +and its system requirements. + +## How you use it + +While there are a variety of tools that support Dev Containers, the focus here +is on developing with VS Code in a container by +[GitHub Codespaces](https://docs.github.com/en/codespaces/overview) or +[VS Code Dev Containers extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers). + +Please refer to the documents for general instructions on how to use these +tools. + +## Using PRQL in a Dev Container + +[Task](https://taskfile.dev/) is installed in the container for quick access to +tasks defined on the `Taskfiles.yml`. + +Here are some useful commands available in the container. + +- `task -l` lists all the available tasks. +- `task run-book` starts an `mdbook` server. As you edit the files of the + Language Book (in the `book` directory), `mdbook` rebuilds those pages. + (Port 3000) +- `task run-website` starts a `hugo` server. As you edit the files (in the + `website` directory), `hugo` rebuilds those pages. (Port 1313) +- `task run-playground` starts a Node server to build the Playground. As you + edit the files (in the `playground` directory), the server rebuilds those + pages. (Port 3000) +- `task WHAT ELSE?` _Provide explanation of other useful commands._ From 1adc4cb6c5f261714c50b763c2400f2f72fef120 Mon Sep 17 00:00:00 2001 From: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Date: Tue, 7 Mar 2023 15:10:27 -0800 Subject: [PATCH 102/106] docs: Wordsmith #1893 (#2045) * docs: Wordsmith #1893 --- book/src/SUMMARY.md | 4 ++-- ...r.md => developing-with-dev-containers.md} | 23 ++++++++----------- ...ng-docker.md => developing-with-docker.md} | 2 +- 3 files changed, 12 insertions(+), 17 deletions(-) rename book/src/contributing/{dev-container.md => developing-with-dev-containers.md} (71%) rename book/src/contributing/{using-docker.md => developing-with-docker.md} (99%) diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md index db5d7a8d3e5b..62c5d04bf13e 100644 --- a/book/src/SUMMARY.md +++ b/book/src/SUMMARY.md @@ -72,8 +72,8 @@ - [Contributing to PRQL](./contributing/README.md) - [Development](./contributing/development.md) - - [Using Docker](./contributing/using-docker.md) - - [Develop in Dev Containers](./contributing/dev-container.md) + - [Developing with Docker](./contributing/developing-with-docker.md) + - [Developing with Dev Containers](./contributing/developing-with-dev-containers.md) - [Internals](./internals/README.md) diff --git a/book/src/contributing/dev-container.md b/book/src/contributing/developing-with-dev-containers.md similarity index 71% rename from book/src/contributing/dev-container.md rename to book/src/contributing/developing-with-dev-containers.md index 7157a67b5975..534dbaa8139c 100644 --- a/book/src/contributing/dev-container.md +++ b/book/src/contributing/developing-with-dev-containers.md @@ -1,30 +1,25 @@ -# Develop in Dev Containers +# Developing with Dev Containers ```admonish note Currently the Dev Container included in this repository only supports the `amd64` platform. ``` [Dev Containers](https://containers.dev/) are a way to package a number of -"developer tools" (compilers, bundlers, package managers, loaders, etc.) into a +developer tools (compilers, bundlers, package managers, loaders, etc.) into a single object. This is helpful when many people want to contribute to a project: -each person only has to install the (single) Dev Container on their own machine -to start working. By definition, the Dev Container has a consistent set of tools -that are known to work together. This avoids a fuss with finding the proper -versions of each of the build tools. - -To use a Dev Container on your local computer with VS Code, you must install the -[VS Code Dev Containers extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) -and its system requirements. - -## How you use it +each person only has to install the Dev Container on their own machine to start +working. By definition, the Dev Container has a consistent set of tools that are +known to work together. This avoids a fuss with finding the proper version of +each of the build tools. While there are a variety of tools that support Dev Containers, the focus here is on developing with VS Code in a container by [GitHub Codespaces](https://docs.github.com/en/codespaces/overview) or [VS Code Dev Containers extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers). -Please refer to the documents for general instructions on how to use these -tools. +To use a Dev Container on a local computer with VS Code, install the +[VS Code Dev Containers extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) +and its system requirements. Then refer to the links above to get started. ## Using PRQL in a Dev Container diff --git a/book/src/contributing/using-docker.md b/book/src/contributing/developing-with-docker.md similarity index 99% rename from book/src/contributing/using-docker.md rename to book/src/contributing/developing-with-docker.md index ee8a1ce789fe..80977a29ceba 100644 --- a/book/src/contributing/using-docker.md +++ b/book/src/contributing/developing-with-docker.md @@ -1,4 +1,4 @@ -# Using the Dockerfile +# Developing with Docker The `Dockerfile` in this repo builds a Docker image that has current versions of our Rust development tools. This can be the lowest-effort way of setting up a From b1c80c530a24f11487e5c25a9aa1e9c2cdd7ccb2 Mon Sep 17 00:00:00 2001 From: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Date: Tue, 7 Mar 2023 15:22:49 -0800 Subject: [PATCH 103/106] docs: Move task docs out of devcontainers (#2046) These are good docs, but there's no reason for them to be here. They'd be good in the Taskfile, or very open to other suggestions While I _really_ appreciate docs that we write (CC @richbhanover), it's important that they're focused, concise, and close to the code that they document -- because they also need to be maintained, and the project takes on that responsibility. I really don't want to lose folks' generosity and ideas, but I'm going to start being a bit firmer on these sorts of things, because we're already starting to see some stale docs (#2044). There are other ways of writing things that have fewer guarantees of continued support -- blog posts, gists, etc. --- .../developing-with-dev-containers.md | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/book/src/contributing/developing-with-dev-containers.md b/book/src/contributing/developing-with-dev-containers.md index 534dbaa8139c..d595961af25d 100644 --- a/book/src/contributing/developing-with-dev-containers.md +++ b/book/src/contributing/developing-with-dev-containers.md @@ -20,21 +20,3 @@ is on developing with VS Code in a container by To use a Dev Container on a local computer with VS Code, install the [VS Code Dev Containers extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) and its system requirements. Then refer to the links above to get started. - -## Using PRQL in a Dev Container - -[Task](https://taskfile.dev/) is installed in the container for quick access to -tasks defined on the `Taskfiles.yml`. - -Here are some useful commands available in the container. - -- `task -l` lists all the available tasks. -- `task run-book` starts an `mdbook` server. As you edit the files of the - Language Book (in the `book` directory), `mdbook` rebuilds those pages. - (Port 3000) -- `task run-website` starts a `hugo` server. As you edit the files (in the - `website` directory), `hugo` rebuilds those pages. (Port 1313) -- `task run-playground` starts a Node server to build the Playground. As you - edit the files (in the `playground` directory), the server rebuilds those - pages. (Port 3000) -- `task WHAT ELSE?` _Provide explanation of other useful commands._ From cba6e12d4842cf1a0b8aa2c84750a24b1d5b0817 Mon Sep 17 00:00:00 2001 From: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Date: Tue, 7 Mar 2023 15:48:29 -0800 Subject: [PATCH 104/106] chore: Fix footnote in a doc (#2047) --- book/src/contributing/development.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/book/src/contributing/development.md b/book/src/contributing/development.md index 1d8e6666c362..b4bf4ed7b1f4 100644 --- a/book/src/contributing/development.md +++ b/book/src/contributing/development.md @@ -427,6 +427,3 @@ Currently we release in a semi-automated way: ``` We may make this more automated in future; e.g. automatic changelog creation. - -[^wrap]: -[^perms]: From a091820db8e5a7ec0d364416d40140d9d2dbcd55 Mon Sep 17 00:00:00 2001 From: Maximilian Roos Date: Tue, 7 Mar 2023 16:36:40 -0800 Subject: [PATCH 105/106] chore: Redirect case.html This will fix the tests in https://github.com/PRQL/prql/pull/2040 --- book/book.toml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/book/book.toml b/book/book.toml index 1ce7a8769425..b7b5142178dd 100644 --- a/book/book.toml +++ b/book/book.toml @@ -9,6 +9,10 @@ additional-css = ["comparison-table.css", "mdbook-admonish.css"] additional-js = ["highlight-prql.js"] git-repository-url = "https://github.com/PRQL/prql" +[output.html.redirect] +# Can remove / reverse this when we push the `case` version. +"/language-features/case.html" = "/language-features/switch.html" + [preprocessor.prql] # This is required because mdbook-prql isn't necessarily installed; maybe # there's a better way. @@ -17,7 +21,7 @@ command = "cargo run --bin mdbook-prql" [preprocessor.admonish] assets_version = "2.0.0" # do not edit: managed by `mdbook-admonish install` -command = "mdbook-admonish" +command = "mdbook-admonish" [preprocessor.footnote] # Seems to be required for footnotes to show properly. From 201bde0f8edfd17f921ed27693f03f846bb24d12 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 8 Mar 2023 00:36:58 +0000 Subject: [PATCH 106/106] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- book/book.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/book/book.toml b/book/book.toml index b7b5142178dd..69aac0b4b1d0 100644 --- a/book/book.toml +++ b/book/book.toml @@ -21,7 +21,7 @@ command = "cargo run --bin mdbook-prql" [preprocessor.admonish] assets_version = "2.0.0" # do not edit: managed by `mdbook-admonish install` -command = "mdbook-admonish" +command = "mdbook-admonish" [preprocessor.footnote] # Seems to be required for footnotes to show properly.