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.
- {pytrilogy-0.0.2.21/pytrilogy.egg-info → pytrilogy-0.0.2.23}/PKG-INFO +17 -11
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/README.md +16 -10
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23/pytrilogy.egg-info}/PKG-INFO +17 -11
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/pytrilogy.egg-info/SOURCES.txt +1 -0
- pytrilogy-0.0.2.23/tests/test_imports.py +42 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/tests/test_models.py +9 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/tests/test_parsing.py +31 -13
- pytrilogy-0.0.2.23/tests/test_show.py +57 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/tests/test_statements.py +21 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/__init__.py +1 -1
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/constants.py +1 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/enums.py +13 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/env_processor.py +4 -2
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/ergonomics.py +11 -4
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/functions.py +2 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/models.py +80 -3
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/processing/concept_strategies_v3.py +0 -1
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/processing/node_generators/node_merge_node.py +19 -6
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/processing/node_generators/rowset_node.py +2 -2
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/processing/utility.py +2 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/query_processor.py +25 -4
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/dialect/base.py +18 -2
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/executor.py +55 -37
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/parsing/common.py +16 -2
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/parsing/parse_engine.py +43 -45
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/parsing/render.py +25 -3
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/parsing/trilogy.lark +46 -21
- pytrilogy-0.0.2.21/tests/test_imports.py +0 -23
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/LICENSE.md +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/pyproject.toml +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/pytrilogy.egg-info/dependency_links.txt +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/pytrilogy.egg-info/entry_points.txt +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/pytrilogy.egg-info/requires.txt +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/pytrilogy.egg-info/top_level.txt +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/setup.cfg +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/setup.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/tests/test_datatypes.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/tests/test_declarations.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/tests/test_derived_concepts.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/tests/test_discovery_nodes.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/tests/test_environment.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/tests/test_functions.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/tests/test_metadata.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/tests/test_multi_join_assignments.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/tests/test_partial_handling.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/tests/test_query_processing.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/tests/test_select.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/tests/test_undefined_concept.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/tests/test_where_clause.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/compiler.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/__init__.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/constants.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/environment_helpers.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/exceptions.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/graph_models.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/internal.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/optimization.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/optimizations/__init__.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/optimizations/base_optimization.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/optimizations/inline_constant.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/optimizations/inline_datasource.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/optimizations/predicate_pushdown.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/processing/__init__.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/processing/graph_utils.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/processing/node_generators/__init__.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/processing/node_generators/basic_node.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/processing/node_generators/common.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/processing/node_generators/filter_node.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/processing/node_generators/group_node.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/processing/node_generators/group_to_node.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/processing/node_generators/multiselect_node.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/processing/node_generators/select_merge_node.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/processing/node_generators/select_node.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/processing/node_generators/unnest_node.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/processing/node_generators/window_node.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/processing/nodes/__init__.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/processing/nodes/base_node.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/processing/nodes/filter_node.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/processing/nodes/group_node.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/processing/nodes/merge_node.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/processing/nodes/select_node_v2.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/processing/nodes/unnest_node.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/core/processing/nodes/window_node.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/dialect/__init__.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/dialect/bigquery.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/dialect/common.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/dialect/config.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/dialect/duckdb.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/dialect/enums.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/dialect/postgres.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/dialect/presto.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/dialect/snowflake.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/dialect/sql_server.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/engine.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/hooks/__init__.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/hooks/base_hook.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/hooks/graph_hook.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/hooks/query_debugger.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/metadata/__init__.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/parser.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/parsing/__init__.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/parsing/config.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/parsing/exceptions.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/parsing/helpers.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/py.typed +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/scripts/__init__.py +0 -0
- {pytrilogy-0.0.2.21 → pytrilogy-0.0.2.23}/trilogy/scripts/trilogy.py +0 -0
- {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.
|
|
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
|
-

|
|
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
|
|
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.
|
|
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
|
|
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
|
|
294
|
+
`key [name] [type];`
|
|
295
295
|
|
|
296
296
|
Property:
|
|
297
|
-
`property
|
|
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
|
|
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
|
-

|
|
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
|
|
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.
|
|
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
|
|
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
|
|
265
|
+
`key [name] [type];`
|
|
266
266
|
|
|
267
267
|
Property:
|
|
268
|
-
`property
|
|
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
|
|
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.
|
|
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
|
-

|
|
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
|
|
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.
|
|
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
|
|
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
|
|
294
|
+
`key [name] [type];`
|
|
295
295
|
|
|
296
296
|
Property:
|
|
297
|
-
`property
|
|
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
|
|
305
|
+
`auto [name] <- [expression];`
|
|
306
|
+
`auto x <- y + 1;`
|
|
301
307
|
|
|
302
308
|
#### DATASOURCE
|
|
303
309
|
```sql
|
|
@@ -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
|
-
|
|
30
|
+
TupleWrapper,
|
|
31
31
|
), type(right)
|
|
32
|
-
assert right
|
|
32
|
+
assert right[0] == 1
|
|
33
33
|
rendered = BaseDialect().render_expr(right)
|
|
34
|
-
assert rendered.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
|
-
|
|
43
|
+
TupleWrapper,
|
|
44
44
|
), type(right)
|
|
45
|
-
assert right
|
|
45
|
+
assert right[0] == 1
|
|
46
46
|
rendered = BaseDialect().render_expr(right)
|
|
47
|
-
assert rendered.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
|
-
|
|
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() == "(
|
|
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 ");
|
|
@@ -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.
|
|
14
|
-
for source in concept.
|
|
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
|
-
|
|
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,
|