duckdb-kql 0.0.1.dev2__tar.gz → 0.0.1.dev3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/PKG-INFO +18 -3
  2. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/README.md +17 -2
  3. duckdb_kql-0.0.1.dev3/demo/demo.ipynb +503 -0
  4. duckdb_kql-0.0.1.dev3/demo/demo.kql +3 -0
  5. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/docs/api.md +6 -0
  6. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/docs/cli.md +5 -0
  7. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/docs/kql-support.md +2 -2
  8. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/docs/kusto-client.md +39 -10
  9. duckdb_kql-0.0.1.dev3/docs/kusto-server.md +166 -0
  10. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/src/duckdb_kql/__init__.py +22 -0
  11. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/src/duckdb_kql/_version.py +2 -2
  12. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/src/duckdb_kql/cli.py +90 -2
  13. duckdb_kql-0.0.1.dev3/src/duckdb_kql/control.py +387 -0
  14. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/src/duckdb_kql/ir.py +30 -0
  15. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/src/duckdb_kql/kusto/_models.py +5 -52
  16. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/src/duckdb_kql/kusto/client.py +28 -46
  17. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/src/duckdb_kql/lower.py +3 -0
  18. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/src/duckdb_kql/parser.py +13 -0
  19. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/src/duckdb_kql/schema.py +4 -0
  20. duckdb_kql-0.0.1.dev3/src/duckdb_kql/server.py +650 -0
  21. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/src/duckdb_kql/translate/__init__.py +35 -0
  22. duckdb_kql-0.0.1.dev3/src/duckdb_kql/types.py +149 -0
  23. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/tests/test_behavior.py +1 -1
  24. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/tests/test_cli.py +53 -0
  25. duckdb_kql-0.0.1.dev3/tests/test_control_commands.py +405 -0
  26. duckdb_kql-0.0.1.dev3/tests/test_demo_notebook.py +151 -0
  27. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/tests/test_devcontainers.py +3 -2
  28. duckdb_kql-0.0.1.dev3/tests/test_getschema.py +135 -0
  29. duckdb_kql-0.0.1.dev3/tests/test_server.py +529 -0
  30. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/tools/gen_support_matrix.py +1 -1
  31. duckdb_kql-0.0.1.dev2/demo/duckdb-kql-demo.ipynb +0 -1339
  32. duckdb_kql-0.0.1.dev2/tests/test_demo_notebook.py +0 -91
  33. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/.gitignore +0 -0
  34. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/CODE_OF_CONDUCT.md +0 -0
  35. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/CONTRIBUTING.md +0 -0
  36. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/LICENSE +0 -0
  37. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/SECURITY.md +0 -0
  38. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/THIRD-PARTY-NOTICES.md +0 -0
  39. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/docs/TRANSLATION.md +0 -0
  40. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/docs/ai-cost-strategy.md +0 -0
  41. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/docs/azure-monitor-profile.md +0 -0
  42. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/docs/code-review/README.md +0 -0
  43. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/docs/code-review/kusto-client-compat.md +0 -0
  44. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/docs/code-review/public-api-and-typing.md +0 -0
  45. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/docs/code-review/review-2026-08-04.md +0 -0
  46. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/docs/code-review/security-and-injection.md +0 -0
  47. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/docs/code-review/testing-oracle-and-fixtures.md +0 -0
  48. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/docs/code-review/tooling-packaging-ci-docs.md +0 -0
  49. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/docs/code-review/translation-correctness.md +0 -0
  50. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/docs/frequency-scan-results.md +0 -0
  51. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/docs/getting-started.md +0 -0
  52. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/docs/implementation-options.md +0 -0
  53. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/docs/implementation-plan.md +0 -0
  54. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/docs/kql-on-duckdb-landscape.md +0 -0
  55. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/docs/lessons-from-bun-rewrite.md +0 -0
  56. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/docs/licensing.md +0 -0
  57. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/docs/m0-grammar-spike.md +0 -0
  58. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/docs/oracle-harness.md +0 -0
  59. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/docs/test-plan.md +0 -0
  60. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/grammar/Kql.g4 +0 -0
  61. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/grammar/KqlTokens.g4 +0 -0
  62. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/grammar/UPSTREAM.md +0 -0
  63. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/pyproject.toml +0 -0
  64. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/src/duckdb_kql/__main__.py +0 -0
  65. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/src/duckdb_kql/_antlr/Kql.interp +0 -0
  66. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/src/duckdb_kql/_antlr/Kql.tokens +0 -0
  67. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/src/duckdb_kql/_antlr/KqlLexer.interp +0 -0
  68. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/src/duckdb_kql/_antlr/KqlLexer.py +0 -0
  69. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/src/duckdb_kql/_antlr/KqlLexer.tokens +0 -0
  70. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/src/duckdb_kql/_antlr/KqlListener.py +0 -0
  71. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/src/duckdb_kql/_antlr/KqlParser.py +0 -0
  72. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/src/duckdb_kql/_antlr/KqlVisitor.py +0 -0
  73. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/src/duckdb_kql/_antlr/__init__.py +0 -0
  74. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/src/duckdb_kql/comparison.py +0 -0
  75. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/src/duckdb_kql/engine.py +0 -0
  76. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/src/duckdb_kql/errors.py +0 -0
  77. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/src/duckdb_kql/fixtures.py +0 -0
  78. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/src/duckdb_kql/kusto/__init__.py +0 -0
  79. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/src/duckdb_kql/kusto/client_request_properties.py +0 -0
  80. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/src/duckdb_kql/kusto/exceptions.py +0 -0
  81. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/src/duckdb_kql/kusto/helpers.py +0 -0
  82. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/src/duckdb_kql/kusto/response.py +0 -0
  83. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/src/duckdb_kql/oracle.py +0 -0
  84. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/src/duckdb_kql/params.py +0 -0
  85. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/src/duckdb_kql/py.typed +0 -0
  86. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/src/duckdb_kql/translate/functions.py +0 -0
  87. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/tests/conftest.py +0 -0
  88. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/tests/profiles/azure-monitor.json +0 -0
  89. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/tests/test_column_order_and_null_sort.py +0 -0
  90. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/tests/test_comparison.py +0 -0
  91. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/tests/test_corpus.py +0 -0
  92. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/tests/test_datetime_traps.py +0 -0
  93. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/tests/test_docs.py +0 -0
  94. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/tests/test_dynamic.py +0 -0
  95. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/tests/test_fixtures.py +0 -0
  96. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/tests/test_join.py +0 -0
  97. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/tests/test_kusto_client.py +0 -0
  98. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/tests/test_let.py +0 -0
  99. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/tests/test_null_semantics.py +0 -0
  100. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/tests/test_parse.py +0 -0
  101. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/tests/test_profile_azure_monitor.py +0 -0
  102. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/tests/test_query_parameters.py +0 -0
  103. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/tests/test_range_in_render.py +0 -0
  104. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/tests/test_summarize.py +0 -0
  105. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/tests/test_support_matrix.py +0 -0
  106. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/tests/test_typing.py +0 -0
  107. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/tests/test_workflows.py +0 -0
  108. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/tools/check_profile.py +0 -0
  109. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/tools/frequency_scan.py +0 -0
  110. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/tools/harvest_docs.py +0 -0
  111. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/tools/make_fixtures.py +0 -0
  112. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/tools/regen_expectations.py +0 -0
  113. {duckdb_kql-0.0.1.dev2 → duckdb_kql-0.0.1.dev3}/tools/regen_parser.sh +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: duckdb-kql
3
- Version: 0.0.1.dev2
3
+ Version: 0.0.1.dev3
4
4
  Summary: Run Kusto KQL queries on DuckDB, from Python
5
5
  Project-URL: Homepage, https://github.com/mmaitre314/duckdb-kql
6
6
  Project-URL: Documentation, https://github.com/mmaitre314/duckdb-kql/blob/main/docs/getting-started.md
@@ -138,6 +138,20 @@ duckdb-kql queries/ -o build/sql/ --check # fails the build if a .sql is stale
138
138
 
139
139
  See [Build-time translation](https://github.com/mmaitre314/duckdb-kql/blob/main/docs/cli.md).
140
140
 
141
+ ## Query it from the Azure Data Explorer UI
142
+
143
+ `duckdb-kql serve` puts a local Kusto REST endpoint in front of a DuckDB file,
144
+ so Kusto's own tools can query it. Standard library only — no new dependency.
145
+
146
+ ```bash
147
+ duckdb-kql serve analytics.duckdb # http://127.0.0.1:31415
148
+ ```
149
+
150
+ Open <https://dataexplorer.azure.com>, choose **Add connection**, and paste that
151
+ URL. It listens on loopback only and cannot be told otherwise, because it
152
+ answers unauthenticated queries: see
153
+ [A local Kusto endpoint](https://github.com/mmaitre314/duckdb-kql/blob/main/docs/kusto-server.md).
154
+
141
155
  ## Three layers
142
156
 
143
157
  | Layer | Import | Needs | For |
@@ -215,7 +229,7 @@ Measured against the real KQL engine (the Kusto Emulator), not asserted.
215
229
  |---|---|
216
230
  | Doc-corpus cases matching ground truth | **245** of 1036 (0 mismatches) |
217
231
  | [Azure Monitor's published KQL subset](https://github.com/mmaitre314/duckdb-kql/blob/main/docs/azure-monitor-profile.md) | **114 / 119 (96%)** |
218
- | Tabular operators | **15 / 41** |
232
+ | Tabular operators | **16 / 41** |
219
233
  | Scalar functions / aggregates / binary operators | **110 / 19 / 33** |
220
234
 
221
235
  Supported operators: `where`, `project`, `project-away`, `project-rename`,
@@ -248,6 +262,7 @@ approximation.
248
262
  | [Getting started](https://github.com/mmaitre314/duckdb-kql/blob/main/docs/getting-started.md) | Install, first query, the three layers |
249
263
  | [**KQL support matrix**](https://github.com/mmaitre314/duckdb-kql/blob/main/docs/kql-support.md) | Every operator and function, supported or not, each with its gotchas |
250
264
  | [Build-time CLI](https://github.com/mmaitre314/duckdb-kql/blob/main/docs/cli.md) | Translating `.kql` to `.sql` in CI, to avoid a runtime dependency |
265
+ | [Local Kusto endpoint](https://github.com/mmaitre314/duckdb-kql/blob/main/docs/kusto-server.md) | `duckdb-kql serve` — query a DuckDB file from the Azure Data Explorer UI |
251
266
  | [API reference](https://github.com/mmaitre314/duckdb-kql/blob/main/docs/api.md) | Every public function and type |
252
267
  | [Kusto SDK compatibility](https://github.com/mmaitre314/duckdb-kql/blob/main/docs/kusto-client.md) | What Layer 2 implements, no-ops, and refuses |
253
268
  | [Azure Monitor profile](https://github.com/mmaitre314/duckdb-kql/blob/main/docs/azure-monitor-profile.md) | Coverage against a published KQL subset |
@@ -259,7 +274,7 @@ approximation.
259
274
  | [`docs/m0-grammar-spike.md`](https://github.com/mmaitre314/duckdb-kql/blob/main/docs/m0-grammar-spike.md) | Grammar viability result |
260
275
  | [`docs/frequency-scan-results.md`](https://github.com/mmaitre314/duckdb-kql/blob/main/docs/frequency-scan-results.md) | What KQL constructs actually get used |
261
276
  | [`docs/licensing.md`](https://github.com/mmaitre314/duckdb-kql/blob/main/docs/licensing.md) | Third-party licensing review |
262
- | [demo/](https://github.com/mmaitre314/duckdb-kql/blob/main/demo/duckdb-kql-demo.ipynb) | Notebook tour of all three layers, with outputs |
277
+ | [demo/](https://github.com/mmaitre314/duckdb-kql/blob/main/demo/demo.ipynb) | Notebook tour of all three layers, with outputs |
263
278
  | [CONTRIBUTING.md](https://github.com/mmaitre314/duckdb-kql/blob/main/CONTRIBUTING.md) | How to add a mapping, and when not to |
264
279
  | [SECURITY.md](https://github.com/mmaitre314/duckdb-kql/blob/main/SECURITY.md) | Reporting vulnerabilities; what is in scope |
265
280
  | [Releases](https://github.com/mmaitre314/duckdb-kql/releases) | What changed, and when |
@@ -57,6 +57,20 @@ duckdb-kql queries/ -o build/sql/ --check # fails the build if a .sql is stale
57
57
 
58
58
  See [Build-time translation](https://github.com/mmaitre314/duckdb-kql/blob/main/docs/cli.md).
59
59
 
60
+ ## Query it from the Azure Data Explorer UI
61
+
62
+ `duckdb-kql serve` puts a local Kusto REST endpoint in front of a DuckDB file,
63
+ so Kusto's own tools can query it. Standard library only — no new dependency.
64
+
65
+ ```bash
66
+ duckdb-kql serve analytics.duckdb # http://127.0.0.1:31415
67
+ ```
68
+
69
+ Open <https://dataexplorer.azure.com>, choose **Add connection**, and paste that
70
+ URL. It listens on loopback only and cannot be told otherwise, because it
71
+ answers unauthenticated queries: see
72
+ [A local Kusto endpoint](https://github.com/mmaitre314/duckdb-kql/blob/main/docs/kusto-server.md).
73
+
60
74
  ## Three layers
61
75
 
62
76
  | Layer | Import | Needs | For |
@@ -134,7 +148,7 @@ Measured against the real KQL engine (the Kusto Emulator), not asserted.
134
148
  |---|---|
135
149
  | Doc-corpus cases matching ground truth | **245** of 1036 (0 mismatches) |
136
150
  | [Azure Monitor's published KQL subset](https://github.com/mmaitre314/duckdb-kql/blob/main/docs/azure-monitor-profile.md) | **114 / 119 (96%)** |
137
- | Tabular operators | **15 / 41** |
151
+ | Tabular operators | **16 / 41** |
138
152
  | Scalar functions / aggregates / binary operators | **110 / 19 / 33** |
139
153
 
140
154
  Supported operators: `where`, `project`, `project-away`, `project-rename`,
@@ -167,6 +181,7 @@ approximation.
167
181
  | [Getting started](https://github.com/mmaitre314/duckdb-kql/blob/main/docs/getting-started.md) | Install, first query, the three layers |
168
182
  | [**KQL support matrix**](https://github.com/mmaitre314/duckdb-kql/blob/main/docs/kql-support.md) | Every operator and function, supported or not, each with its gotchas |
169
183
  | [Build-time CLI](https://github.com/mmaitre314/duckdb-kql/blob/main/docs/cli.md) | Translating `.kql` to `.sql` in CI, to avoid a runtime dependency |
184
+ | [Local Kusto endpoint](https://github.com/mmaitre314/duckdb-kql/blob/main/docs/kusto-server.md) | `duckdb-kql serve` — query a DuckDB file from the Azure Data Explorer UI |
170
185
  | [API reference](https://github.com/mmaitre314/duckdb-kql/blob/main/docs/api.md) | Every public function and type |
171
186
  | [Kusto SDK compatibility](https://github.com/mmaitre314/duckdb-kql/blob/main/docs/kusto-client.md) | What Layer 2 implements, no-ops, and refuses |
172
187
  | [Azure Monitor profile](https://github.com/mmaitre314/duckdb-kql/blob/main/docs/azure-monitor-profile.md) | Coverage against a published KQL subset |
@@ -178,7 +193,7 @@ approximation.
178
193
  | [`docs/m0-grammar-spike.md`](https://github.com/mmaitre314/duckdb-kql/blob/main/docs/m0-grammar-spike.md) | Grammar viability result |
179
194
  | [`docs/frequency-scan-results.md`](https://github.com/mmaitre314/duckdb-kql/blob/main/docs/frequency-scan-results.md) | What KQL constructs actually get used |
180
195
  | [`docs/licensing.md`](https://github.com/mmaitre314/duckdb-kql/blob/main/docs/licensing.md) | Third-party licensing review |
181
- | [demo/](https://github.com/mmaitre314/duckdb-kql/blob/main/demo/duckdb-kql-demo.ipynb) | Notebook tour of all three layers, with outputs |
196
+ | [demo/](https://github.com/mmaitre314/duckdb-kql/blob/main/demo/demo.ipynb) | Notebook tour of all three layers, with outputs |
182
197
  | [CONTRIBUTING.md](https://github.com/mmaitre314/duckdb-kql/blob/main/CONTRIBUTING.md) | How to add a mapping, and when not to |
183
198
  | [SECURITY.md](https://github.com/mmaitre314/duckdb-kql/blob/main/SECURITY.md) | Reporting vulnerabilities; what is in scope |
184
199
  | [Releases](https://github.com/mmaitre314/duckdb-kql/releases) | What changed, and when |
@@ -0,0 +1,503 @@
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "id": "915bc73e",
6
+ "metadata": {},
7
+ "source": [
8
+ "# duckdb-kql — run KQL queries on DuckDB\n",
9
+ "\n",
10
+ "[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/mmaitre314/duckdb-kql?devcontainer_path=.devcontainer%2Fdemo%2Fdevcontainer.json&quickstart=1)\n",
11
+ "\n",
12
+ "[`duckdb-kql`](https://github.com/mmaitre314/duckdb-kql) translates\n",
13
+ "[Kusto Query Language](https://learn.microsoft.com/azure/data-explorer/kusto/query/) (KQL)\n",
14
+ "into [DuckDB](https://duckdb.org/) SQL, so you can run KQL against local files and in-process data with\n",
15
+ "no cluster and no network.\n",
16
+ "\n",
17
+ "To get started, either open the GitHub Codespace above or install Python followed by `pip install duckdb-kql[all]`."
18
+ ]
19
+ },
20
+ {
21
+ "cell_type": "code",
22
+ "execution_count": 1,
23
+ "id": "0a703ebc",
24
+ "metadata": {
25
+ "execution": {
26
+ "iopub.execute_input": "2026-08-14T00:22:04.749501Z",
27
+ "iopub.status.busy": "2026-08-14T00:22:04.749303Z",
28
+ "iopub.status.idle": "2026-08-14T00:22:04.811776Z",
29
+ "shell.execute_reply": "2026-08-14T00:22:04.810477Z"
30
+ }
31
+ },
32
+ "outputs": [
33
+ {
34
+ "name": "stdout",
35
+ "output_type": "stream",
36
+ "text": [
37
+ "duckdb-kql 0.0.1.dev2\n"
38
+ ]
39
+ }
40
+ ],
41
+ "source": [
42
+ "import duckdb_kql\n",
43
+ "\n",
44
+ "print(\"duckdb-kql\", duckdb_kql.__version__)"
45
+ ]
46
+ },
47
+ {
48
+ "cell_type": "markdown",
49
+ "id": "adbf3927",
50
+ "metadata": {},
51
+ "source": [
52
+ "## Sample data\n",
53
+ "\n",
54
+ "Connect to an in-memory instance of DuckDB and populate a sample table `Requests`."
55
+ ]
56
+ },
57
+ {
58
+ "cell_type": "code",
59
+ "execution_count": 2,
60
+ "id": "9e490c5b",
61
+ "metadata": {
62
+ "execution": {
63
+ "iopub.execute_input": "2026-08-14T00:22:04.813929Z",
64
+ "iopub.status.busy": "2026-08-14T00:22:04.813705Z",
65
+ "iopub.status.idle": "2026-08-14T00:22:06.117089Z",
66
+ "shell.execute_reply": "2026-08-14T00:22:06.115877Z"
67
+ }
68
+ },
69
+ "outputs": [
70
+ {
71
+ "name": "stdout",
72
+ "output_type": "stream",
73
+ "text": [
74
+ "{'Requests': ['Timestamp', 'Service', 'Region', 'Status', 'LatencyMs', 'UserId']}\n"
75
+ ]
76
+ }
77
+ ],
78
+ "source": [
79
+ "import random\n",
80
+ "from datetime import datetime, timedelta\n",
81
+ "\n",
82
+ "con = duckdb_kql.connect()\n",
83
+ "\n",
84
+ "start = datetime(2026, 3, 1)\n",
85
+ "\n",
86
+ "rows = []\n",
87
+ "for i in range(2_000):\n",
88
+ " service = random.choice([\"checkout\", \"search\", \"auth\", \"catalog\"])\n",
89
+ " status = random.choice([200, 200, 200, 500] if service == \"auth\" else [200, 200, 200, 200, 503])\n",
90
+ " rows.append((\n",
91
+ " start + timedelta(seconds=i * 37),\n",
92
+ " service,\n",
93
+ " random.choice([\"us-west-2\", \"us-east-1\", \"eu-west-1\"]),\n",
94
+ " status,\n",
95
+ " round(random.lognormvariate(3.2, 0.6), 1),\n",
96
+ " f\"user-{random.randint(1, 120):03d}\",\n",
97
+ " ))\n",
98
+ "\n",
99
+ "con.execute(\"\"\"\n",
100
+ " CREATE TABLE Requests (\n",
101
+ " Timestamp TIMESTAMP, Service VARCHAR, Region VARCHAR,\n",
102
+ " Status INTEGER, LatencyMs DOUBLE, UserId VARCHAR\n",
103
+ " )\n",
104
+ "\"\"\")\n",
105
+ "con.executemany(\"INSERT INTO Requests VALUES (?, ?, ?, ?, ?, ?)\", rows)\n",
106
+ "\n",
107
+ "print(duckdb_kql.engine.schema(con))"
108
+ ]
109
+ },
110
+ {
111
+ "cell_type": "markdown",
112
+ "id": "f570c3d5",
113
+ "metadata": {},
114
+ "source": [
115
+ "## Basic query"
116
+ ]
117
+ },
118
+ {
119
+ "cell_type": "markdown",
120
+ "id": "3a08280a",
121
+ "metadata": {},
122
+ "source": [
123
+ "Run a simple query."
124
+ ]
125
+ },
126
+ {
127
+ "cell_type": "code",
128
+ "execution_count": 3,
129
+ "id": "885b458a",
130
+ "metadata": {
131
+ "execution": {
132
+ "iopub.execute_input": "2026-08-14T00:22:06.119481Z",
133
+ "iopub.status.busy": "2026-08-14T00:22:06.119136Z",
134
+ "iopub.status.idle": "2026-08-14T00:22:06.588029Z",
135
+ "shell.execute_reply": "2026-08-14T00:22:06.586666Z"
136
+ }
137
+ },
138
+ "outputs": [
139
+ {
140
+ "data": {
141
+ "text/plain": [
142
+ "┌──────────┬───────────┬──────────┬───────┐\n",
143
+ "│ Service │ Region │ Failures │ Users │\n",
144
+ "│ varchar │ varchar │ int64 │ int64 │\n",
145
+ "├──────────┼───────────┼──────────┼───────┤\n",
146
+ "│ auth │ us-east-1 │ 60 │ 47 │\n",
147
+ "│ auth │ us-west-2 │ 41 │ 34 │\n",
148
+ "│ search │ us-west-2 │ 40 │ 34 │\n",
149
+ "│ checkout │ us-west-2 │ 39 │ 36 │\n",
150
+ "│ auth │ eu-west-1 │ 36 │ 31 │\n",
151
+ "└──────────┴───────────┴──────────┴───────┘"
152
+ ]
153
+ },
154
+ "execution_count": 3,
155
+ "metadata": {},
156
+ "output_type": "execute_result"
157
+ }
158
+ ],
159
+ "source": [
160
+ "duckdb_kql.kql(con, \"\"\"\n",
161
+ " Requests\n",
162
+ " | where Status >= 500\n",
163
+ " | summarize Failures = count(), Users = dcount(UserId) by Service, Region\n",
164
+ " | sort by Failures desc\n",
165
+ " | take 5\n",
166
+ "\"\"\")"
167
+ ]
168
+ },
169
+ {
170
+ "cell_type": "markdown",
171
+ "id": "fd37be76",
172
+ "metadata": {},
173
+ "source": [
174
+ "## Query with parameters"
175
+ ]
176
+ },
177
+ {
178
+ "cell_type": "markdown",
179
+ "id": "91860b14",
180
+ "metadata": {},
181
+ "source": [
182
+ "Run a query with parameters (preventing query injection)."
183
+ ]
184
+ },
185
+ {
186
+ "cell_type": "code",
187
+ "execution_count": 5,
188
+ "id": "ec5d5b75",
189
+ "metadata": {
190
+ "execution": {
191
+ "iopub.execute_input": "2026-08-14T00:22:06.590536Z",
192
+ "iopub.status.busy": "2026-08-14T00:22:06.590303Z",
193
+ "iopub.status.idle": "2026-08-14T00:22:06.624113Z",
194
+ "shell.execute_reply": "2026-08-14T00:22:06.622769Z"
195
+ }
196
+ },
197
+ "outputs": [
198
+ {
199
+ "data": {
200
+ "text/plain": [
201
+ "┌───────┐\n",
202
+ "│ Count │\n",
203
+ "│ int64 │\n",
204
+ "├───────┤\n",
205
+ "│ 137 │\n",
206
+ "└───────┘"
207
+ ]
208
+ },
209
+ "execution_count": 5,
210
+ "metadata": {},
211
+ "output_type": "execute_result"
212
+ }
213
+ ],
214
+ "source": [
215
+ "duckdb_kql.kql(con, \"\"\"\n",
216
+ " declare query_parameters(service:string, floor:long);\n",
217
+ " \n",
218
+ " Requests\n",
219
+ " | where Service == service and Status >= floor\n",
220
+ " | count\n",
221
+ "\"\"\",\n",
222
+ " {\"service\": \"auth\", \"floor\": 500})"
223
+ ]
224
+ },
225
+ {
226
+ "cell_type": "markdown",
227
+ "id": "0a9d90b5",
228
+ "metadata": {},
229
+ "source": [
230
+ "## KustoClient-compatible query\n",
231
+ "\n",
232
+ "Run a query using APIs compatible with Kusto client SDK ([azure-kusto-data](https://github.com/Azure/azure-kusto-python)). Useful to unit-test code with KQL queries meant to run against actual Kusto clusters."
233
+ ]
234
+ },
235
+ {
236
+ "cell_type": "code",
237
+ "execution_count": 6,
238
+ "id": "f0323551",
239
+ "metadata": {
240
+ "execution": {
241
+ "iopub.execute_input": "2026-08-14T00:22:06.626383Z",
242
+ "iopub.status.busy": "2026-08-14T00:22:06.626164Z",
243
+ "iopub.status.idle": "2026-08-14T00:22:06.657424Z",
244
+ "shell.execute_reply": "2026-08-14T00:22:06.656176Z"
245
+ }
246
+ },
247
+ "outputs": [
248
+ {
249
+ "name": "stdout",
250
+ "output_type": "stream",
251
+ "text": [
252
+ "columns : [('Service', 'string'), ('Errors', 'long')]\n",
253
+ "raw_rows : [['auth', 137], ['search', 100], ['catalog', 98], ['checkout', 96]]\n",
254
+ "\n"
255
+ ]
256
+ },
257
+ {
258
+ "data": {
259
+ "text/html": [
260
+ "<div>\n",
261
+ "<style scoped>\n",
262
+ " .dataframe tbody tr th:only-of-type {\n",
263
+ " vertical-align: middle;\n",
264
+ " }\n",
265
+ "\n",
266
+ " .dataframe tbody tr th {\n",
267
+ " vertical-align: top;\n",
268
+ " }\n",
269
+ "\n",
270
+ " .dataframe thead th {\n",
271
+ " text-align: right;\n",
272
+ " }\n",
273
+ "</style>\n",
274
+ "<table border=\"1\" class=\"dataframe\">\n",
275
+ " <thead>\n",
276
+ " <tr style=\"text-align: right;\">\n",
277
+ " <th></th>\n",
278
+ " <th>Service</th>\n",
279
+ " <th>Errors</th>\n",
280
+ " </tr>\n",
281
+ " </thead>\n",
282
+ " <tbody>\n",
283
+ " <tr>\n",
284
+ " <th>0</th>\n",
285
+ " <td>auth</td>\n",
286
+ " <td>137</td>\n",
287
+ " </tr>\n",
288
+ " <tr>\n",
289
+ " <th>1</th>\n",
290
+ " <td>search</td>\n",
291
+ " <td>100</td>\n",
292
+ " </tr>\n",
293
+ " <tr>\n",
294
+ " <th>2</th>\n",
295
+ " <td>catalog</td>\n",
296
+ " <td>98</td>\n",
297
+ " </tr>\n",
298
+ " <tr>\n",
299
+ " <th>3</th>\n",
300
+ " <td>checkout</td>\n",
301
+ " <td>96</td>\n",
302
+ " </tr>\n",
303
+ " </tbody>\n",
304
+ "</table>\n",
305
+ "</div>"
306
+ ],
307
+ "text/plain": [
308
+ " Service Errors\n",
309
+ "0 auth 137\n",
310
+ "1 search 100\n",
311
+ "2 catalog 98\n",
312
+ "3 checkout 96"
313
+ ]
314
+ },
315
+ "execution_count": 6,
316
+ "metadata": {},
317
+ "output_type": "execute_result"
318
+ }
319
+ ],
320
+ "source": [
321
+ "from duckdb_kql.kusto import KustoClient\n",
322
+ "from duckdb_kql.kusto.helpers import dataframe_from_result_table\n",
323
+ "\n",
324
+ "client = KustoClient(con)\n",
325
+ "\n",
326
+ "response = client.execute(\"NetDefaultDB\", \"\"\"\n",
327
+ " Requests\n",
328
+ " | where Status >= 500\n",
329
+ " | summarize Errors = count() by Service\n",
330
+ " | sort by Errors desc\n",
331
+ "\"\"\")\n",
332
+ "\n",
333
+ "table = response.primary_results[0]\n",
334
+ "print(\"columns :\", [(c.column_name, c.column_type) for c in table.columns])\n",
335
+ "print(\"raw_rows :\", table.raw_rows)\n",
336
+ "print()\n",
337
+ "dataframe_from_result_table(table)"
338
+ ]
339
+ },
340
+ {
341
+ "cell_type": "markdown",
342
+ "id": "792b4716",
343
+ "metadata": {},
344
+ "source": [
345
+ "## KQL query translation\n",
346
+ "\n",
347
+ "Pre-compute the SQL-equivalent query. This removes the runtime dependency on `duckdb_kql`."
348
+ ]
349
+ },
350
+ {
351
+ "cell_type": "code",
352
+ "execution_count": 7,
353
+ "id": "edad6fb7",
354
+ "metadata": {
355
+ "execution": {
356
+ "iopub.execute_input": "2026-08-14T00:22:06.659549Z",
357
+ "iopub.status.busy": "2026-08-14T00:22:06.659325Z",
358
+ "iopub.status.idle": "2026-08-14T00:22:07.027790Z",
359
+ "shell.execute_reply": "2026-08-14T00:22:07.026542Z"
360
+ }
361
+ },
362
+ "outputs": [
363
+ {
364
+ "name": "stdout",
365
+ "output_type": "stream",
366
+ "text": [
367
+ "WITH _s0 AS (SELECT * FROM \"Requests\"),\n",
368
+ " _s1 AS (SELECT * FROM _s0 WHERE ((\"Status\" >= CAST(500 AS BIGINT)) AND coalesce(regexp_matches(\"Region\", '(?i)\\b' || regexp_escape('west') || '\\b'), FALSE))),\n",
369
+ " _s2 AS (SELECT \"Service\" AS \"Service\", count(*) AS \"Failures\", count(DISTINCT \"UserId\") AS \"Users\" FROM _s1 GROUP BY \"Service\"),\n",
370
+ " _s3 AS (SELECT * FROM _s2 ORDER BY \"Failures\" DESC NULLS LAST),\n",
371
+ " _s4 AS (SELECT * FROM _s3 LIMIT 3)\n",
372
+ "SELECT * FROM _s4\n"
373
+ ]
374
+ }
375
+ ],
376
+ "source": [
377
+ "print(duckdb_kql.to_sql(\"\"\"\n",
378
+ " Requests\n",
379
+ " | where Status >= 500 and Region has \"west\"\n",
380
+ " | summarize Failures = count(), Users = dcount(UserId) by Service\n",
381
+ " | sort by Failures desc\n",
382
+ " | take 3\n",
383
+ "\"\"\"))"
384
+ ]
385
+ },
386
+ {
387
+ "cell_type": "markdown",
388
+ "id": "58785e21",
389
+ "metadata": {},
390
+ "source": [
391
+ "Validate the syntax of queries."
392
+ ]
393
+ },
394
+ {
395
+ "cell_type": "code",
396
+ "execution_count": 7,
397
+ "id": "7754401b",
398
+ "metadata": {
399
+ "execution": {
400
+ "iopub.execute_input": "2026-08-14T00:22:07.030028Z",
401
+ "iopub.status.busy": "2026-08-14T00:22:07.029791Z",
402
+ "iopub.status.idle": "2026-08-14T00:22:07.035687Z",
403
+ "shell.execute_reply": "2026-08-14T00:22:07.033881Z"
404
+ }
405
+ },
406
+ "outputs": [
407
+ {
408
+ "name": "stdout",
409
+ "output_type": "stream",
410
+ "text": [
411
+ "1:9: mismatched input '|' expecting {<EOF>, ';'}\n"
412
+ ]
413
+ }
414
+ ],
415
+ "source": [
416
+ "for diagnostic in duckdb_kql.validate(\"Requests | wehr Status == 500\"):\n",
417
+ " print(diagnostic)"
418
+ ]
419
+ },
420
+ {
421
+ "cell_type": "markdown",
422
+ "id": "2a0aa6d2",
423
+ "metadata": {},
424
+ "source": [
425
+ "Translate KQL queries using the CLI, to run query translation as part of build pipelines for instance."
426
+ ]
427
+ },
428
+ {
429
+ "cell_type": "code",
430
+ "execution_count": 8,
431
+ "id": "ef8136f0",
432
+ "metadata": {
433
+ "execution": {
434
+ "iopub.execute_input": "2026-08-14T00:22:07.038043Z",
435
+ "iopub.status.busy": "2026-08-14T00:22:07.037826Z",
436
+ "iopub.status.idle": "2026-08-14T00:22:07.555577Z",
437
+ "shell.execute_reply": "2026-08-14T00:22:07.554223Z"
438
+ }
439
+ },
440
+ "outputs": [
441
+ {
442
+ "name": "stdout",
443
+ "output_type": "stream",
444
+ "text": [
445
+ "-- Generated by duckdb-kql from demo.kql. Do not edit.\r\n",
446
+ "--\r\n",
447
+ "-- Run with TimeZone set to UTC: SET TimeZone='UTC';\r\n",
448
+ "-- KQL datetimes are UTC, and DuckDB reads the session zone when casting\r\n",
449
+ "-- text without an offset. Without it, datetimes are silently shifted\r\n",
450
+ "-- rather than rejected.\r\n",
451
+ "\r\n",
452
+ "WITH _s0 AS (SELECT * FROM \"Requests\"),\r\n",
453
+ " _s1 AS (SELECT * FROM _s0 WHERE (\"Status\" >= CAST(500 AS BIGINT))),\r\n",
454
+ " _s2 AS (SELECT \"Service\" AS \"Service\", count(*) AS \"Errors\" FROM _s1 GROUP BY \"Service\")\r\n",
455
+ "SELECT * FROM _s2\r\n"
456
+ ]
457
+ }
458
+ ],
459
+ "source": [
460
+ "!duckdb-kql demo.kql"
461
+ ]
462
+ },
463
+ {
464
+ "cell_type": "markdown",
465
+ "id": "fd8ed70c",
466
+ "metadata": {},
467
+ "source": [
468
+ "## Next steps\n",
469
+ "\n",
470
+ "Documentation:\n",
471
+ "- **[Getting started](https://github.com/mmaitre314/duckdb-kql/blob/main/docs/getting-started.md)**\n",
472
+ "- **[API reference](https://github.com/mmaitre314/duckdb-kql/blob/main/docs/api.md)**\n",
473
+ "- **[KQL support matrix](https://github.com/mmaitre314/duckdb-kql/blob/main/docs/kql-support.md)**\n",
474
+ "- **[Kusto SDK compatibility](https://github.com/mmaitre314/duckdb-kql/blob/main/docs/kusto-client.md)**\n",
475
+ "- **[Build-time translation](https://github.com/mmaitre314/duckdb-kql/blob/main/docs/cli.md)**.\n",
476
+ "\n",
477
+ "Found a query that returns something different from Kusto?\n",
478
+ "[Open an issue](https://github.com/mmaitre314/duckdb-kql/issues)."
479
+ ]
480
+ }
481
+ ],
482
+ "metadata": {
483
+ "kernelspec": {
484
+ "display_name": "Python 3",
485
+ "language": "python",
486
+ "name": "python3"
487
+ },
488
+ "language_info": {
489
+ "codemirror_mode": {
490
+ "name": "ipython",
491
+ "version": 3
492
+ },
493
+ "file_extension": ".py",
494
+ "mimetype": "text/x-python",
495
+ "name": "python",
496
+ "nbconvert_exporter": "python",
497
+ "pygments_lexer": "ipython3",
498
+ "version": "3.13.5"
499
+ }
500
+ },
501
+ "nbformat": 4,
502
+ "nbformat_minor": 5
503
+ }
@@ -0,0 +1,3 @@
1
+ Requests
2
+ | where Status >= 500
3
+ | summarize Errors = count() by Service
@@ -122,6 +122,12 @@ installed.
122
122
 
123
123
  Execute and return a relation, so you can keep composing with DuckDB's API.
124
124
 
125
+ Also accepts the control commands `.show version`, `.show databases` and
126
+ `.show tables` — a separate Kusto dialect, with the column shapes Kusto returns
127
+ — and pipelines built on them, such as
128
+ `.show tables | where TableName startswith "Storm"`.
129
+ See [Control commands](kusto-client.md#control-commands).
130
+
125
131
  ### `execute(con, kql, parameters=None) -> DuckDBPyConnection`
126
132
 
127
133
  Mirrors `con.execute` — for the cursor, or the side effect.
@@ -3,6 +3,11 @@
3
3
  Translate `.kql` to `.sql` once, in CI. What ships is plain SQL, and **nothing
4
4
  that runs it needs this package** — not the transpiler, not Python.
5
5
 
6
+ > There is one subcommand, `duckdb-kql serve`, which does something else
7
+ > entirely: it runs a [local Kusto REST endpoint](kusto-server.md) over a DuckDB
8
+ > database. Everything that is not the literal word `serve` is a file to
9
+ > translate, so nothing on this page changes.
10
+
6
11
  ```bash
7
12
  pip install duckdb-kql # antlr4 only; no database
8
13
  duckdb-kql queries/ -o build/sql/ # translate
@@ -33,7 +33,7 @@ returns an approximate answer.
33
33
 
34
34
  ## Tabular operators
35
35
 
36
- 15 of 41 supported.
36
+ 16 of 41 supported.
37
37
 
38
38
  ### Supported
39
39
 
@@ -54,6 +54,7 @@ returns an approximate answer.
54
54
  | `take` | Which rows come back is **not defined** without a preceding `sort` (R10). |
55
55
  | `limit` | Synonym for `take`. |
56
56
  | `render` | Parsed and **ignored**: there is no chart to draw. The rows are unchanged, so a query ending in `render` still returns its data. |
57
+ | `getschema` | Reports `ColumnName`, `ColumnOrdinal` (0-based), `DataType` and `ColumnType`, verified against the emulator including the non-obvious .NET names (`bool` is `System.SByte`, `decimal` is `System.Data.SqlTypes.SqlDecimal`). Types are DuckDB's, named as Kusto names them, so a DuckDB type with no Kusto counterpart reports as `dynamic` (composites) or `string` (everything else) rather than inventing a name. |
57
58
 
58
59
  ### Not supported
59
60
 
@@ -64,7 +65,6 @@ returns an approximate answer.
64
65
  | `parse` | Needs a pattern-to-regex compiler covering the greedy/lazy `*` forms and typed captures. The largest single gap — around 27 corpus cases. `extract()` and `extract_all()` cover the regex cases meanwhile. |
65
66
  | `parse-where` | The same pattern compiler as `parse`, plus dropping non-matching rows. |
66
67
  | `lookup` | A leftouter join with dimension-table semantics. Close to `join kind=leftouter`, which is supported — but the column-collision rules differ, so it is not aliased to it. |
67
- | `getschema` | Needs the input schema *as data*, in KQL type names rather than DuckDB's. The type mapping exists (`duckdb_kql.kusto`); it is not wired to an operator. |
68
68
  | `project-keep` | Wildcard column selection against the input schema. The plumbing `project-away` uses would cover it. |
69
69
  | `project-reorder` | The same schema plumbing as `project-keep`, plus the trailing-column rules. |
70
70
  | `make-series` | Produces array-valued columns over a generated axis, with gap filling. A different result *shape*, not just a different aggregate. |