pytrilogy 0.0.2.21__tar.gz → 0.0.2.23__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.

Potentially problematic release.


This version of pytrilogy might be problematic. Click here for more details.

Files changed (108) hide show
  1. {pytrilogy-0.0.2.21/pytrilogy.egg-info → pytrilogy-0.0.2.23}/PKG-INFO +17 -11
  2. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/README.md +16 -10
  3. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23/pytrilogy.egg-info}/PKG-INFO +17 -11
  4. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/pytrilogy.egg-info/SOURCES.txt +1 -0
  5. pytrilogy-0.0.2.23/tests/test_imports.py +42 -0
  6. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/tests/test_models.py +9 -0
  7. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/tests/test_parsing.py +31 -13
  8. pytrilogy-0.0.2.23/tests/test_show.py +57 -0
  9. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/tests/test_statements.py +21 -0
  10. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/__init__.py +1 -1
  11. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/constants.py +1 -0
  12. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/enums.py +13 -0
  13. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/env_processor.py +4 -2
  14. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/ergonomics.py +11 -4
  15. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/functions.py +2 -0
  16. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/models.py +80 -3
  17. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/processing/concept_strategies_v3.py +0 -1
  18. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/processing/node_generators/node_merge_node.py +19 -6
  19. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/processing/node_generators/rowset_node.py +2 -2
  20. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/processing/utility.py +2 -0
  21. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/query_processor.py +25 -4
  22. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/dialect/base.py +18 -2
  23. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/executor.py +55 -37
  24. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/parsing/common.py +16 -2
  25. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/parsing/parse_engine.py +43 -45
  26. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/parsing/render.py +25 -3
  27. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/parsing/trilogy.lark +46 -21
  28. pytrilogy-0.0.2.21/tests/test_imports.py +0 -23
  29. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/LICENSE.md +0 -0
  30. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/pyproject.toml +0 -0
  31. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/pytrilogy.egg-info/dependency_links.txt +0 -0
  32. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/pytrilogy.egg-info/entry_points.txt +0 -0
  33. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/pytrilogy.egg-info/requires.txt +0 -0
  34. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/pytrilogy.egg-info/top_level.txt +0 -0
  35. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/setup.cfg +0 -0
  36. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/setup.py +0 -0
  37. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/tests/test_datatypes.py +0 -0
  38. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/tests/test_declarations.py +0 -0
  39. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/tests/test_derived_concepts.py +0 -0
  40. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/tests/test_discovery_nodes.py +0 -0
  41. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/tests/test_environment.py +0 -0
  42. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/tests/test_functions.py +0 -0
  43. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/tests/test_metadata.py +0 -0
  44. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/tests/test_multi_join_assignments.py +0 -0
  45. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/tests/test_partial_handling.py +0 -0
  46. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/tests/test_query_processing.py +0 -0
  47. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/tests/test_select.py +0 -0
  48. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/tests/test_undefined_concept.py +0 -0
  49. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/tests/test_where_clause.py +0 -0
  50. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/compiler.py +0 -0
  51. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/__init__.py +0 -0
  52. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/constants.py +0 -0
  53. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/environment_helpers.py +0 -0
  54. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/exceptions.py +0 -0
  55. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/graph_models.py +0 -0
  56. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/internal.py +0 -0
  57. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/optimization.py +0 -0
  58. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/optimizations/__init__.py +0 -0
  59. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/optimizations/base_optimization.py +0 -0
  60. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/optimizations/inline_constant.py +0 -0
  61. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/optimizations/inline_datasource.py +0 -0
  62. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/optimizations/predicate_pushdown.py +0 -0
  63. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/processing/__init__.py +0 -0
  64. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/processing/graph_utils.py +0 -0
  65. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/processing/node_generators/__init__.py +0 -0
  66. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/processing/node_generators/basic_node.py +0 -0
  67. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/processing/node_generators/common.py +0 -0
  68. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/processing/node_generators/filter_node.py +0 -0
  69. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/processing/node_generators/group_node.py +0 -0
  70. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/processing/node_generators/group_to_node.py +0 -0
  71. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/processing/node_generators/multiselect_node.py +0 -0
  72. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/processing/node_generators/select_merge_node.py +0 -0
  73. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/processing/node_generators/select_node.py +0 -0
  74. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/processing/node_generators/unnest_node.py +0 -0
  75. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/processing/node_generators/window_node.py +0 -0
  76. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/processing/nodes/__init__.py +0 -0
  77. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/processing/nodes/base_node.py +0 -0
  78. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/processing/nodes/filter_node.py +0 -0
  79. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/processing/nodes/group_node.py +0 -0
  80. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/processing/nodes/merge_node.py +0 -0
  81. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/processing/nodes/select_node_v2.py +0 -0
  82. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/processing/nodes/unnest_node.py +0 -0
  83. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/processing/nodes/window_node.py +0 -0
  84. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/dialect/__init__.py +0 -0
  85. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/dialect/bigquery.py +0 -0
  86. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/dialect/common.py +0 -0
  87. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/dialect/config.py +0 -0
  88. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/dialect/duckdb.py +0 -0
  89. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/dialect/enums.py +0 -0
  90. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/dialect/postgres.py +0 -0
  91. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/dialect/presto.py +0 -0
  92. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/dialect/snowflake.py +0 -0
  93. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/dialect/sql_server.py +0 -0
  94. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/engine.py +0 -0
  95. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/hooks/__init__.py +0 -0
  96. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/hooks/base_hook.py +0 -0
  97. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/hooks/graph_hook.py +0 -0
  98. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/hooks/query_debugger.py +0 -0
  99. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/metadata/__init__.py +0 -0
  100. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/parser.py +0 -0
  101. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/parsing/__init__.py +0 -0
  102. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/parsing/config.py +0 -0
  103. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/parsing/exceptions.py +0 -0
  104. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/parsing/helpers.py +0 -0
  105. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/py.typed +0 -0
  106. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/scripts/__init__.py +0 -0
  107. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/scripts/trilogy.py +0 -0
  108. {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/utility.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pytrilogy
3
- Version: 0.0.2.21
3
+ Version: 0.0.2.23
4
4
  Summary: Declarative, typed query language that compiles to SQL.
5
5
  Home-page:
6
6
  Author:
@@ -145,7 +145,7 @@ Run the following from the directory the file is in.
145
145
  trilogy run hello.trilogy duckdb
146
146
  ```
147
147
 
148
- ![UI Preview](./hello_world.png)
148
+ ![UI Preview](hello-world.png)
149
149
 
150
150
  ## Backends
151
151
 
@@ -158,9 +158,9 @@ The current Trilogy implementation supports these backends:
158
158
 
159
159
  ## Basic Example - Python
160
160
 
161
- Trilogy can be run directly in python.
161
+ Trilogy can be run directly in python through the core SDK. Trilogy code can be defined and parsed inline or parsed out of files.
162
162
 
163
- A bigquery example, similar to bigquery [the quickstart](https://cloud.google.com/bigquery/docs/quickstarts/query-public-dataset-console)
163
+ A bigquery example, similar to bigquery [the quickstart](https://cloud.google.com/bigquery/docs/quickstarts/query-public-dataset-console).
164
164
 
165
165
  ```python
166
166
 
@@ -224,7 +224,7 @@ and second the dialect to run.
224
224
  To pass arguments to a backend, append additional --<option> flags after specifying the dialect.
225
225
 
226
226
  Example:
227
- `trilogy run key in int; datasource test_source ( i:in) grain(in) address test; select in;" duckdb --path <path/to/duckdb>`
227
+ `trilogy run "key x int; datasource test_source ( i:x) grain(in) address test; select x;" duckdb --path <path/to/database>`
228
228
 
229
229
  ### Bigquery Args
230
230
  N/A, only supports default auth. In python you can pass in a custom client.
@@ -267,7 +267,7 @@ Clone repository and install requirements.txt and requirements-test.txt.
267
267
  Please open an issue first to discuss what you would like to change, and then create a PR against that issue.
268
268
 
269
269
  ## Similar in space
270
- Trilogy combines two aspects; a semantic layer and a query language. We've covered examples of both below:
270
+ Trilogy combines two aspects; a semantic layer and a query language. Examples of both are linked below:
271
271
 
272
272
  Python "semantic layers" are tools for defining data access to a warehouse in a more abstract way.
273
273
 
@@ -284,20 +284,26 @@ but all are worth checking out. Please open PRs/comment for anything missed!
284
284
 
285
285
  #### IMPORT
286
286
 
287
- `import <path> as <alias>;`
287
+ `import [path] as [alias];`
288
288
 
289
289
  #### CONCEPT
290
290
 
291
- Types: `string | int | float | bool | date | datetime | time | numeric(scale, precision) | timestamp | interval`;
291
+ Types: `string | int | float | bool | date | datetime | time | numeric(scale, precision) | timestamp | interval | list<[type]> | map<[type], [type]> | struct<name:[type], name:[type]>`;
292
292
 
293
293
  Key:
294
- `key <name> <type>;`
294
+ `key [name] [type];`
295
295
 
296
296
  Property:
297
- `property <key>.<name> <type>;`
297
+ `property [key>].[name] [type];`
298
+ `property x.y int;`
299
+ or
300
+ `property <[key](,[key])?>.<name> [type];`
301
+ `property <x,y>.z int;`
302
+
298
303
 
299
304
  Transformation:
300
- `auto <name> <- <expression>;`
305
+ `auto [name] <- [expression];`
306
+ `auto x <- y + 1;`
301
307
 
302
308
  #### DATASOURCE
303
309
  ```sql
@@ -116,7 +116,7 @@ Run the following from the directory the file is in.
116
116
  trilogy run hello.trilogy duckdb
117
117
  ```
118
118
 
119
- ![UI Preview](./hello_world.png)
119
+ ![UI Preview](hello-world.png)
120
120
 
121
121
  ## Backends
122
122
 
@@ -129,9 +129,9 @@ The current Trilogy implementation supports these backends:
129
129
 
130
130
  ## Basic Example - Python
131
131
 
132
- Trilogy can be run directly in python.
132
+ Trilogy can be run directly in python through the core SDK. Trilogy code can be defined and parsed inline or parsed out of files.
133
133
 
134
- A bigquery example, similar to bigquery [the quickstart](https://cloud.google.com/bigquery/docs/quickstarts/query-public-dataset-console)
134
+ A bigquery example, similar to bigquery [the quickstart](https://cloud.google.com/bigquery/docs/quickstarts/query-public-dataset-console).
135
135
 
136
136
  ```python
137
137
 
@@ -195,7 +195,7 @@ and second the dialect to run.
195
195
  To pass arguments to a backend, append additional --<option> flags after specifying the dialect.
196
196
 
197
197
  Example:
198
- `trilogy run key in int; datasource test_source ( i:in) grain(in) address test; select in;" duckdb --path <path/to/duckdb>`
198
+ `trilogy run "key x int; datasource test_source ( i:x) grain(in) address test; select x;" duckdb --path <path/to/database>`
199
199
 
200
200
  ### Bigquery Args
201
201
  N/A, only supports default auth. In python you can pass in a custom client.
@@ -238,7 +238,7 @@ Clone repository and install requirements.txt and requirements-test.txt.
238
238
  Please open an issue first to discuss what you would like to change, and then create a PR against that issue.
239
239
 
240
240
  ## Similar in space
241
- Trilogy combines two aspects; a semantic layer and a query language. We've covered examples of both below:
241
+ Trilogy combines two aspects; a semantic layer and a query language. Examples of both are linked below:
242
242
 
243
243
  Python "semantic layers" are tools for defining data access to a warehouse in a more abstract way.
244
244
 
@@ -255,20 +255,26 @@ but all are worth checking out. Please open PRs/comment for anything missed!
255
255
 
256
256
  #### IMPORT
257
257
 
258
- `import <path> as <alias>;`
258
+ `import [path] as [alias];`
259
259
 
260
260
  #### CONCEPT
261
261
 
262
- Types: `string | int | float | bool | date | datetime | time | numeric(scale, precision) | timestamp | interval`;
262
+ Types: `string | int | float | bool | date | datetime | time | numeric(scale, precision) | timestamp | interval | list<[type]> | map<[type], [type]> | struct<name:[type], name:[type]>`;
263
263
 
264
264
  Key:
265
- `key <name> <type>;`
265
+ `key [name] [type];`
266
266
 
267
267
  Property:
268
- `property <key>.<name> <type>;`
268
+ `property [key>].[name] [type];`
269
+ `property x.y int;`
270
+ or
271
+ `property <[key](,[key])?>.<name> [type];`
272
+ `property <x,y>.z int;`
273
+
269
274
 
270
275
  Transformation:
271
- `auto <name> <- <expression>;`
276
+ `auto [name] <- [expression];`
277
+ `auto x <- y + 1;`
272
278
 
273
279
  #### DATASOURCE
274
280
  ```sql
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pytrilogy
3
- Version: 0.0.2.21
3
+ Version: 0.0.2.23
4
4
  Summary: Declarative, typed query language that compiles to SQL.
5
5
  Home-page:
6
6
  Author:
@@ -145,7 +145,7 @@ Run the following from the directory the file is in.
145
145
  trilogy run hello.trilogy duckdb
146
146
  ```
147
147
 
148
- ![UI Preview](./hello_world.png)
148
+ ![UI Preview](hello-world.png)
149
149
 
150
150
  ## Backends
151
151
 
@@ -158,9 +158,9 @@ The current Trilogy implementation supports these backends:
158
158
 
159
159
  ## Basic Example - Python
160
160
 
161
- Trilogy can be run directly in python.
161
+ Trilogy can be run directly in python through the core SDK. Trilogy code can be defined and parsed inline or parsed out of files.
162
162
 
163
- A bigquery example, similar to bigquery [the quickstart](https://cloud.google.com/bigquery/docs/quickstarts/query-public-dataset-console)
163
+ A bigquery example, similar to bigquery [the quickstart](https://cloud.google.com/bigquery/docs/quickstarts/query-public-dataset-console).
164
164
 
165
165
  ```python
166
166
 
@@ -224,7 +224,7 @@ and second the dialect to run.
224
224
  To pass arguments to a backend, append additional --<option> flags after specifying the dialect.
225
225
 
226
226
  Example:
227
- `trilogy run key in int; datasource test_source ( i:in) grain(in) address test; select in;" duckdb --path <path/to/duckdb>`
227
+ `trilogy run "key x int; datasource test_source ( i:x) grain(in) address test; select x;" duckdb --path <path/to/database>`
228
228
 
229
229
  ### Bigquery Args
230
230
  N/A, only supports default auth. In python you can pass in a custom client.
@@ -267,7 +267,7 @@ Clone repository and install requirements.txt and requirements-test.txt.
267
267
  Please open an issue first to discuss what you would like to change, and then create a PR against that issue.
268
268
 
269
269
  ## Similar in space
270
- Trilogy combines two aspects; a semantic layer and a query language. We've covered examples of both below:
270
+ Trilogy combines two aspects; a semantic layer and a query language. Examples of both are linked below:
271
271
 
272
272
  Python "semantic layers" are tools for defining data access to a warehouse in a more abstract way.
273
273
 
@@ -284,20 +284,26 @@ but all are worth checking out. Please open PRs/comment for anything missed!
284
284
 
285
285
  #### IMPORT
286
286
 
287
- `import <path> as <alias>;`
287
+ `import [path] as [alias];`
288
288
 
289
289
  #### CONCEPT
290
290
 
291
- Types: `string | int | float | bool | date | datetime | time | numeric(scale, precision) | timestamp | interval`;
291
+ Types: `string | int | float | bool | date | datetime | time | numeric(scale, precision) | timestamp | interval | list<[type]> | map<[type], [type]> | struct<name:[type], name:[type]>`;
292
292
 
293
293
  Key:
294
- `key <name> <type>;`
294
+ `key [name] [type];`
295
295
 
296
296
  Property:
297
- `property <key>.<name> <type>;`
297
+ `property [key>].[name] [type];`
298
+ `property x.y int;`
299
+ or
300
+ `property <[key](,[key])?>.<name> [type];`
301
+ `property <x,y>.z int;`
302
+
298
303
 
299
304
  Transformation:
300
- `auto <name> <- <expression>;`
305
+ `auto [name] <- [expression];`
306
+ `auto x <- y + 1;`
301
307
 
302
308
  #### DATASOURCE
303
309
  ```sql
@@ -22,6 +22,7 @@ tests/test_parsing.py
22
22
  tests/test_partial_handling.py
23
23
  tests/test_query_processing.py
24
24
  tests/test_select.py
25
+ tests/test_show.py
25
26
  tests/test_statements.py
26
27
  tests/test_undefined_concept.py
27
28
  tests/test_where_clause.py
@@ -0,0 +1,42 @@
1
+ from trilogy import Environment
2
+ from pathlib import Path
3
+
4
+
5
+ def test_multi_environment():
6
+ basic = Environment()
7
+
8
+ basic.parse(
9
+ """
10
+ const pi <- 3.14;
11
+
12
+
13
+ """,
14
+ namespace="math",
15
+ )
16
+
17
+ basic.parse(
18
+ """
19
+
20
+ select math.pi;
21
+ """
22
+ )
23
+
24
+ assert basic.concepts["math.pi"].name == "pi"
25
+
26
+
27
+ def test_test_alias_free_import():
28
+ basic = Environment(working_path=Path(__file__).parent)
29
+
30
+ basic.parse(
31
+ """
32
+ import test_env;
33
+
34
+ key id2 int;
35
+
36
+
37
+ """,
38
+ )
39
+
40
+ assert basic.concepts["id"].name == "id"
41
+ assert basic.concepts["id2"].name == "id2"
42
+ assert basic.concepts["id"].namespace == basic.concepts["id2"].namespace
@@ -15,8 +15,11 @@ from trilogy.core.models import (
15
15
  Concept,
16
16
  AggregateWrapper,
17
17
  RowsetItem,
18
+ TupleWrapper,
19
+ DataType,
18
20
  )
19
21
  from trilogy import parse
22
+ from copy import deepcopy
20
23
 
21
24
 
22
25
  def test_cte_merge(test_environment, test_environment_graph):
@@ -312,3 +315,9 @@ select avg_greater_ten;
312
315
  lineage = env.concepts["avg_greater_ten"].lineage
313
316
  assert isinstance(lineage, AggregateWrapper)
314
317
  assert isinstance(lineage.function.concept_arguments[0].lineage, RowsetItem)
318
+
319
+
320
+ def test_tuple_clone():
321
+ x = TupleWrapper([1, 2, 3], type=DataType.INTEGER)
322
+ y = deepcopy(x)
323
+ assert y == x
@@ -1,12 +1,12 @@
1
1
  from trilogy.core.enums import Purpose, ComparisonOperator
2
2
  from trilogy.core.models import (
3
3
  DataType,
4
- Parenthetical,
5
4
  ProcessedQuery,
6
5
  ShowStatement,
7
6
  SelectStatement,
8
7
  Environment,
9
8
  Comparison,
9
+ TupleWrapper,
10
10
  )
11
11
  from trilogy.core.functions import argument_to_purpose, function_args_to_output_purpose
12
12
  from trilogy.parsing.parse_engine import (
@@ -27,11 +27,11 @@ def test_in():
27
27
  right = query.where_clause.conditional.right
28
28
  assert isinstance(
29
29
  right,
30
- Parenthetical,
30
+ TupleWrapper,
31
31
  ), type(right)
32
- assert right.content[0] == 1
32
+ assert right[0] == 1
33
33
  rendered = BaseDialect().render_expr(right)
34
- assert rendered.strip() == "( 1,2,3 )".strip()
34
+ assert rendered.strip() == "(1,2,3)".strip()
35
35
 
36
36
  _, parsed = parse_text(
37
37
  "const order_id <- 3; SELECT order_id WHERE order_id IN (1,);"
@@ -40,11 +40,11 @@ def test_in():
40
40
  right = query.where_clause.conditional.right
41
41
  assert isinstance(
42
42
  right,
43
- Parenthetical,
43
+ TupleWrapper,
44
44
  ), type(right)
45
- assert right.content[0] == 1
45
+ assert right[0] == 1
46
46
  rendered = BaseDialect().render_expr(right)
47
- assert rendered.strip() == "( 1 )".strip()
47
+ assert rendered.strip() == "(1)".strip()
48
48
 
49
49
 
50
50
  def test_not_in():
@@ -53,13 +53,10 @@ def test_not_in():
53
53
  )
54
54
  query: ProcessedQuery = parsed[-1]
55
55
  right = query.where_clause.conditional.right
56
- assert isinstance(
57
- right,
58
- Parenthetical,
59
- ), type(right)
60
- assert right.content[0] == 1
56
+ assert isinstance(right, TupleWrapper), type(right)
57
+ assert right[0] == 1
61
58
  rendered = BaseDialect().render_expr(right)
62
- assert rendered.strip() == "( 1,2,3 )".strip()
59
+ assert rendered.strip() == "(1,2,3)".strip()
63
60
 
64
61
 
65
62
  def test_is_not_null():
@@ -516,3 +513,24 @@ select filtered_test;
516
513
  results = Dialects.DUCK_DB.default_executor().generate_sql(text)[0]
517
514
 
518
515
  assert "filtered_test" in results, results
516
+
517
+
518
+ def test_unnest_parsing():
519
+ x = """
520
+ key scalar int;
521
+ property scalar.int_array list<int>;
522
+
523
+ key split <- unnest(int_array);
524
+
525
+ datasource avalues (
526
+ int_array: int_array,
527
+ scalar: scalar
528
+ )
529
+ grain (scalar)
530
+ query '''(
531
+ select [1,2,3,4] as int_array, 2 as scalar
532
+ )''';
533
+ """
534
+
535
+ env, parsed = parse_text(x)
536
+ assert env.concepts["split"].datatype == DataType.INTEGER
@@ -0,0 +1,57 @@
1
+ from trilogy.core.models import ShowStatement
2
+ from trilogy import Dialects
3
+ from trilogy.parser import parse
4
+
5
+
6
+ def test_show_bigquery():
7
+ declarations = """
8
+ key user_id int metadata(description="the description");
9
+ property user_id.display_name string metadata(description="The display name ");
10
+ property user_id.about_me string metadata(description="User provided description");
11
+ key post_id int;
12
+
13
+
14
+ datasource posts (
15
+ user_id: user_id,
16
+ id: post_id
17
+ )
18
+ grain (post_id)
19
+ address bigquery-public-data.stackoverflow.post_history
20
+ ;
21
+
22
+
23
+ datasource users (
24
+ id: user_id,
25
+ display_name: display_name,
26
+ about_me: about_me,
27
+ )
28
+ grain (user_id)
29
+ address bigquery-public-data.stackoverflow.users
30
+ ;
31
+
32
+
33
+ """
34
+ env, parsed = parse(declarations)
35
+
36
+ q1 = """
37
+ metric post_count<- count(post_id);
38
+ metric distinct_post_count <- count_distinct(post_id);
39
+
40
+ metric user_count <- count(user_id);
41
+
42
+ show select
43
+ post_count,
44
+ distinct_post_count,
45
+ user_count
46
+ ;"""
47
+ env, parsed = parse(q1, environment=env)
48
+ select: ShowStatement = parsed[-1]
49
+
50
+ query = (
51
+ Dialects.DUCK_DB.default_executor(environment=env)
52
+ .execute_query(select)
53
+ .fetchall()
54
+ )
55
+ assert "FULL JOIN wakeful on 1=1" in query[0]["__preql_internal_query_text"], query[
56
+ 0
57
+ ]["__preql_internal_query_text"]
@@ -1,4 +1,7 @@
1
1
  from trilogy.parser import parse
2
+ from trilogy import Dialects
3
+ from trilogy.core.models import ProcessedCopyStatement
4
+ from pathlib import Path
2
5
 
3
6
  # from trilogy.compiler import compile
4
7
 
@@ -43,6 +46,24 @@ datasource posts (
43
46
  parse(text)
44
47
 
45
48
 
49
+ def test_io_statement():
50
+ target = Path(__file__).parent / "test_io_statement.csv"
51
+ if target.exists():
52
+ target.unlink()
53
+ text = f"""const array <- [1,2,3,4];
54
+
55
+ auto x <- unnest(array);
56
+
57
+ copy into csv '{target}' from select x -> test;
58
+ """
59
+ exec = Dialects.DUCK_DB.default_executor()
60
+ results = exec.parse_text(text)
61
+ assert isinstance(results[-1], ProcessedCopyStatement)
62
+ for z in results:
63
+ exec.execute_query(z)
64
+ assert target.exists(), "csv file was not created"
65
+
66
+
46
67
  def test_datasource_where():
47
68
  text = """key user_id int metadata(description="the description");
48
69
  property user_id.display_name string metadata(description="The display name ");
@@ -4,6 +4,6 @@ from trilogy.executor import Executor
4
4
  from trilogy.parser import parse
5
5
  from trilogy.constants import CONFIG
6
6
 
7
- __version__ = "0.0.2.21"
7
+ __version__ = "0.0.2.23"
8
8
 
9
9
  __all__ = ["parse", "Executor", "Dialects", "Environment", "CONFIG"]
@@ -44,6 +44,7 @@ class Comments:
44
44
  class Config:
45
45
  strict_mode: bool = True
46
46
  human_identifiers: bool = True
47
+ randomize_cte_names: bool = False
47
48
  validate_missing: bool = True
48
49
  comments: Comments = field(default_factory=Comments)
49
50
  optimizations: Optimizations = field(default_factory=Optimizations)
@@ -12,6 +12,7 @@ class UnnestMode(Enum):
12
12
 
13
13
  class ConceptSource(Enum):
14
14
  MANUAL = "manual"
15
+ CTE = "cte"
15
16
  PERSIST_STATEMENT = "persist_statement"
16
17
  AUTO_DERIVED = "auto_derived"
17
18
 
@@ -206,6 +207,8 @@ class FunctionClass(Enum):
206
207
  FunctionType.CURRENT_DATETIME,
207
208
  ]
208
209
 
210
+ ONE_TO_MANY = [FunctionType.UNNEST]
211
+
209
212
 
210
213
  class Boolean(Enum):
211
214
  TRUE = "true"
@@ -289,3 +292,13 @@ class SelectFiltering(Enum):
289
292
  NONE = "none"
290
293
  EXPLICIT = "explicit" # the filtering contains only selected values
291
294
  IMPLICIT = "implicit" # the filtering contains unselected values
295
+
296
+
297
+ class IOType(Enum):
298
+ CSV = "csv"
299
+
300
+ @classmethod
301
+ def _missing_(cls, value):
302
+ if isinstance(value, str) and value.lower() != value:
303
+ return IOType(value.lower())
304
+ return super()._missing_(value)
@@ -10,9 +10,11 @@ def add_concept(concept: Concept, g: ReferenceGraph):
10
10
  g.add_node(concept)
11
11
  # if we have sources, recursively add them
12
12
  node_name = concept_to_node(concept)
13
- if concept.sources:
14
- for source in concept.sources:
13
+ if concept.concept_arguments:
14
+ for source in concept.concept_arguments:
15
15
  generic = source.with_default_grain()
16
+ add_concept(generic, g)
17
+
16
18
  g.add_edge(generic, node_name)
17
19
  for _, pseudonym in concept.pseudonyms.items():
18
20
  pseudonym = pseudonym.with_default_grain()
@@ -1,3 +1,5 @@
1
+ from trilogy.constants import CONFIG
2
+
1
3
  # source: https://github.com/aaronbassett/Pass-phrase
2
4
  CTE_NAMES = """quizzical
3
5
  highfalutin
@@ -103,8 +105,6 @@ mandrill
103
105
  marlin
104
106
  monitor
105
107
  ocelot
106
- osprey
107
- owl
108
108
  petrel
109
109
  python
110
110
  ray
@@ -132,7 +132,6 @@ cuckoo
132
132
  darter
133
133
  dove
134
134
  duck
135
- eagle
136
135
  falcon
137
136
  finch
138
137
  flamingo
@@ -184,4 +183,12 @@ warbler""".split(
184
183
  "\n"
185
184
  )
186
185
 
187
- CTE_NAMES = list(set(CTE_NAMES))
186
+
187
+ def generate_cte_names():
188
+ if CONFIG.randomize_cte_names:
189
+ from random import shuffle
190
+
191
+ new = [*CTE_NAMES]
192
+ shuffle(new)
193
+ return new
194
+ return CTE_NAMES
@@ -104,6 +104,8 @@ def Unnest(args: list[Concept]) -> Function:
104
104
  output = arg_to_datatype(args[0])
105
105
  if isinstance(output, (ListType)):
106
106
  output = output.value_data_type
107
+ else:
108
+ output = DataType.STRING
107
109
  return Function(
108
110
  operator=FunctionType.UNNEST,
109
111
  arguments=args,