pytrilogy 0.0.2.15__tar.gz → 0.0.2.18__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.15/pytrilogy.egg-info → pytrilogy-0.0.2.18}/PKG-INFO +12 -8
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/README.md +11 -7
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18/pytrilogy.egg-info}/PKG-INFO +12 -8
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/pytrilogy.egg-info/SOURCES.txt +1 -0
- pytrilogy-0.0.2.18/tests/test_derived_concepts.py +89 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/tests/test_discovery_nodes.py +0 -2
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/tests/test_models.py +46 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/tests/test_query_processing.py +9 -9
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/__init__.py +1 -1
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/constants.py +1 -1
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/core/enums.py +1 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/core/functions.py +11 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/core/models.py +105 -59
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/core/optimization.py +15 -9
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/core/processing/concept_strategies_v3.py +372 -145
- pytrilogy-0.0.2.18/trilogy/core/processing/node_generators/basic_node.py +71 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/core/processing/node_generators/common.py +6 -7
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/core/processing/node_generators/filter_node.py +28 -31
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/core/processing/node_generators/group_node.py +14 -2
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/core/processing/node_generators/group_to_node.py +3 -1
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/core/processing/node_generators/multiselect_node.py +3 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/core/processing/node_generators/node_merge_node.py +14 -9
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/core/processing/node_generators/rowset_node.py +12 -12
- pytrilogy-0.0.2.18/trilogy/core/processing/node_generators/select_merge_node.py +302 -0
- pytrilogy-0.0.2.18/trilogy/core/processing/node_generators/select_node.py +57 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/core/processing/node_generators/unnest_node.py +4 -3
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/core/processing/node_generators/window_node.py +12 -37
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/core/processing/nodes/__init__.py +0 -2
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/core/processing/nodes/base_node.py +69 -20
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/core/processing/nodes/filter_node.py +3 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/core/processing/nodes/group_node.py +18 -17
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/core/processing/nodes/merge_node.py +4 -10
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/core/processing/nodes/select_node_v2.py +28 -14
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/core/processing/nodes/window_node.py +1 -2
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/core/processing/utility.py +51 -3
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/core/query_processor.py +17 -73
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/dialect/base.py +8 -3
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/dialect/common.py +65 -10
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/dialect/duckdb.py +4 -1
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/dialect/sql_server.py +3 -3
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/executor.py +5 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/hooks/query_debugger.py +5 -3
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/parsing/parse_engine.py +67 -39
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/parsing/render.py +2 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/parsing/trilogy.lark +6 -3
- pytrilogy-0.0.2.15/tests/test_derived_concepts.py +0 -8
- pytrilogy-0.0.2.15/trilogy/core/processing/node_generators/basic_node.py +0 -99
- pytrilogy-0.0.2.15/trilogy/core/processing/node_generators/select_node.py +0 -561
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/LICENSE.md +0 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/pyproject.toml +0 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/pytrilogy.egg-info/dependency_links.txt +0 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/pytrilogy.egg-info/entry_points.txt +0 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/pytrilogy.egg-info/requires.txt +0 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/pytrilogy.egg-info/top_level.txt +0 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/setup.cfg +0 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/setup.py +0 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/tests/test_datatypes.py +0 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/tests/test_declarations.py +0 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/tests/test_environment.py +0 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/tests/test_functions.py +0 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/tests/test_imports.py +0 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/tests/test_metadata.py +0 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/tests/test_multi_join_assignments.py +0 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/tests/test_parsing.py +0 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/tests/test_partial_handling.py +0 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/tests/test_select.py +0 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/tests/test_statements.py +0 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/tests/test_undefined_concept.py +0 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/tests/test_where_clause.py +0 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/compiler.py +0 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/core/__init__.py +0 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/core/constants.py +0 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/core/env_processor.py +0 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/core/environment_helpers.py +0 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/core/ergonomics.py +0 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/core/exceptions.py +0 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/core/graph_models.py +0 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/core/internal.py +0 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/core/optimizations/__init__.py +0 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/core/optimizations/base_optimization.py +0 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/core/optimizations/inline_constant.py +0 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/core/optimizations/inline_datasource.py +0 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/core/optimizations/predicate_pushdown.py +0 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/core/processing/__init__.py +0 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/core/processing/graph_utils.py +0 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/core/processing/node_generators/__init__.py +0 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/core/processing/nodes/unnest_node.py +0 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/dialect/__init__.py +0 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/dialect/bigquery.py +0 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/dialect/config.py +0 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/dialect/enums.py +0 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/dialect/postgres.py +0 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/dialect/presto.py +0 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/dialect/snowflake.py +0 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/engine.py +0 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/hooks/__init__.py +0 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/hooks/base_hook.py +0 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/hooks/graph_hook.py +0 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/metadata/__init__.py +0 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/parser.py +0 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/parsing/__init__.py +0 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/parsing/common.py +0 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/parsing/config.py +0 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/parsing/exceptions.py +0 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/parsing/helpers.py +0 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/py.typed +0 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/scripts/__init__.py +0 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/trilogy/scripts/trilogy.py +0 -0
- {pytrilogy-0.0.2.15 → pytrilogy-0.0.2.18}/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.18
|
|
4
4
|
Summary: Declarative, typed query language that compiles to SQL.
|
|
5
5
|
Home-page:
|
|
6
6
|
Author:
|
|
@@ -42,15 +42,15 @@ Installation: `pip install pytrilogy`
|
|
|
42
42
|
|
|
43
43
|
`pytrilogy` can be run locally to parse and execute trilogy model [.preql] files using the `trilogy` CLI tool, or can be run in python by importing the `trilogy` package.
|
|
44
44
|
|
|
45
|
-
You can read more about the project [here](https://trilogydata.dev/) and try out an interactive demo
|
|
45
|
+
You can read more about the project [here](https://trilogydata.dev/) and try out an interactive demo [here](https://trilogydata.dev/demo/).
|
|
46
46
|
|
|
47
47
|
Trilogy:
|
|
48
48
|
```sql
|
|
49
|
+
WHERE
|
|
50
|
+
name like '%lvis%'
|
|
49
51
|
SELECT
|
|
50
52
|
name,
|
|
51
53
|
count(name) as name_count
|
|
52
|
-
WHERE
|
|
53
|
-
name='Elvis'
|
|
54
54
|
ORDER BY
|
|
55
55
|
name_count desc
|
|
56
56
|
LIMIT 10;
|
|
@@ -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
|
|
|
@@ -214,7 +214,7 @@ for row in results:
|
|
|
214
214
|
|
|
215
215
|
## Basic Example - CLI
|
|
216
216
|
|
|
217
|
-
Trilogy can be run through a CLI tool,
|
|
217
|
+
Trilogy can be run through a CLI tool, also named 'trilogy'.
|
|
218
218
|
|
|
219
219
|
After installing trilogy, you can run the trilogy CLI with two required positional arguments; the first the path to a file or a direct command,
|
|
220
220
|
and second the dialect to run.
|
|
@@ -252,7 +252,7 @@ N/A, only supports default auth. In python you can pass in a custom client.
|
|
|
252
252
|
|
|
253
253
|
## More Examples
|
|
254
254
|
|
|
255
|
-
[Interactive demo](https://trilogydata.dev/demo).
|
|
255
|
+
[Interactive demo](https://trilogydata.dev/demo/).
|
|
256
256
|
|
|
257
257
|
Additional examples can be found in the [public model repository](https://github.com/trilogydata/trilogy-public-models).
|
|
258
258
|
|
|
@@ -267,11 +267,15 @@ 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:
|
|
271
|
+
|
|
272
|
+
Python "semantic layers" are tools for defining data access to a warehouse in a more abstract way.
|
|
273
|
+
|
|
274
|
+
- [metricsflow](https://github.com/dbt-labs/metricflow)
|
|
270
275
|
|
|
271
276
|
"Better SQL" has been a popular space. We believe Trilogy takes a different approach then the following,
|
|
272
277
|
but all are worth checking out. Please open PRs/comment for anything missed!
|
|
273
278
|
|
|
274
|
-
|
|
275
279
|
- [malloy](https://github.com/malloydata/malloy)
|
|
276
280
|
- [preql](https://github.com/erezsh/Preql)
|
|
277
281
|
- [PREQL](https://github.com/PRQL/prql)
|
|
@@ -13,15 +13,15 @@ Installation: `pip install pytrilogy`
|
|
|
13
13
|
|
|
14
14
|
`pytrilogy` can be run locally to parse and execute trilogy model [.preql] files using the `trilogy` CLI tool, or can be run in python by importing the `trilogy` package.
|
|
15
15
|
|
|
16
|
-
You can read more about the project [here](https://trilogydata.dev/) and try out an interactive demo
|
|
16
|
+
You can read more about the project [here](https://trilogydata.dev/) and try out an interactive demo [here](https://trilogydata.dev/demo/).
|
|
17
17
|
|
|
18
18
|
Trilogy:
|
|
19
19
|
```sql
|
|
20
|
+
WHERE
|
|
21
|
+
name like '%lvis%'
|
|
20
22
|
SELECT
|
|
21
23
|
name,
|
|
22
24
|
count(name) as name_count
|
|
23
|
-
WHERE
|
|
24
|
-
name='Elvis'
|
|
25
25
|
ORDER BY
|
|
26
26
|
name_count desc
|
|
27
27
|
LIMIT 10;
|
|
@@ -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
|
|
|
@@ -185,7 +185,7 @@ for row in results:
|
|
|
185
185
|
|
|
186
186
|
## Basic Example - CLI
|
|
187
187
|
|
|
188
|
-
Trilogy can be run through a CLI tool,
|
|
188
|
+
Trilogy can be run through a CLI tool, also named 'trilogy'.
|
|
189
189
|
|
|
190
190
|
After installing trilogy, you can run the trilogy CLI with two required positional arguments; the first the path to a file or a direct command,
|
|
191
191
|
and second the dialect to run.
|
|
@@ -223,7 +223,7 @@ N/A, only supports default auth. In python you can pass in a custom client.
|
|
|
223
223
|
|
|
224
224
|
## More Examples
|
|
225
225
|
|
|
226
|
-
[Interactive demo](https://trilogydata.dev/demo).
|
|
226
|
+
[Interactive demo](https://trilogydata.dev/demo/).
|
|
227
227
|
|
|
228
228
|
Additional examples can be found in the [public model repository](https://github.com/trilogydata/trilogy-public-models).
|
|
229
229
|
|
|
@@ -238,11 +238,15 @@ 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:
|
|
242
|
+
|
|
243
|
+
Python "semantic layers" are tools for defining data access to a warehouse in a more abstract way.
|
|
244
|
+
|
|
245
|
+
- [metricsflow](https://github.com/dbt-labs/metricflow)
|
|
241
246
|
|
|
242
247
|
"Better SQL" has been a popular space. We believe Trilogy takes a different approach then the following,
|
|
243
248
|
but all are worth checking out. Please open PRs/comment for anything missed!
|
|
244
249
|
|
|
245
|
-
|
|
246
250
|
- [malloy](https://github.com/malloydata/malloy)
|
|
247
251
|
- [preql](https://github.com/erezsh/Preql)
|
|
248
252
|
- [PREQL](https://github.com/PRQL/prql)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: pytrilogy
|
|
3
|
-
Version: 0.0.2.
|
|
3
|
+
Version: 0.0.2.18
|
|
4
4
|
Summary: Declarative, typed query language that compiles to SQL.
|
|
5
5
|
Home-page:
|
|
6
6
|
Author:
|
|
@@ -42,15 +42,15 @@ Installation: `pip install pytrilogy`
|
|
|
42
42
|
|
|
43
43
|
`pytrilogy` can be run locally to parse and execute trilogy model [.preql] files using the `trilogy` CLI tool, or can be run in python by importing the `trilogy` package.
|
|
44
44
|
|
|
45
|
-
You can read more about the project [here](https://trilogydata.dev/) and try out an interactive demo
|
|
45
|
+
You can read more about the project [here](https://trilogydata.dev/) and try out an interactive demo [here](https://trilogydata.dev/demo/).
|
|
46
46
|
|
|
47
47
|
Trilogy:
|
|
48
48
|
```sql
|
|
49
|
+
WHERE
|
|
50
|
+
name like '%lvis%'
|
|
49
51
|
SELECT
|
|
50
52
|
name,
|
|
51
53
|
count(name) as name_count
|
|
52
|
-
WHERE
|
|
53
|
-
name='Elvis'
|
|
54
54
|
ORDER BY
|
|
55
55
|
name_count desc
|
|
56
56
|
LIMIT 10;
|
|
@@ -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
|
|
|
@@ -214,7 +214,7 @@ for row in results:
|
|
|
214
214
|
|
|
215
215
|
## Basic Example - CLI
|
|
216
216
|
|
|
217
|
-
Trilogy can be run through a CLI tool,
|
|
217
|
+
Trilogy can be run through a CLI tool, also named 'trilogy'.
|
|
218
218
|
|
|
219
219
|
After installing trilogy, you can run the trilogy CLI with two required positional arguments; the first the path to a file or a direct command,
|
|
220
220
|
and second the dialect to run.
|
|
@@ -252,7 +252,7 @@ N/A, only supports default auth. In python you can pass in a custom client.
|
|
|
252
252
|
|
|
253
253
|
## More Examples
|
|
254
254
|
|
|
255
|
-
[Interactive demo](https://trilogydata.dev/demo).
|
|
255
|
+
[Interactive demo](https://trilogydata.dev/demo/).
|
|
256
256
|
|
|
257
257
|
Additional examples can be found in the [public model repository](https://github.com/trilogydata/trilogy-public-models).
|
|
258
258
|
|
|
@@ -267,11 +267,15 @@ 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:
|
|
271
|
+
|
|
272
|
+
Python "semantic layers" are tools for defining data access to a warehouse in a more abstract way.
|
|
273
|
+
|
|
274
|
+
- [metricsflow](https://github.com/dbt-labs/metricflow)
|
|
270
275
|
|
|
271
276
|
"Better SQL" has been a popular space. We believe Trilogy takes a different approach then the following,
|
|
272
277
|
but all are worth checking out. Please open PRs/comment for anything missed!
|
|
273
278
|
|
|
274
|
-
|
|
275
279
|
- [malloy](https://github.com/malloydata/malloy)
|
|
276
280
|
- [preql](https://github.com/erezsh/Preql)
|
|
277
281
|
- [PREQL](https://github.com/PRQL/prql)
|
|
@@ -64,6 +64,7 @@ trilogy/core/processing/node_generators/group_to_node.py
|
|
|
64
64
|
trilogy/core/processing/node_generators/multiselect_node.py
|
|
65
65
|
trilogy/core/processing/node_generators/node_merge_node.py
|
|
66
66
|
trilogy/core/processing/node_generators/rowset_node.py
|
|
67
|
+
trilogy/core/processing/node_generators/select_merge_node.py
|
|
67
68
|
trilogy/core/processing/node_generators/select_node.py
|
|
68
69
|
trilogy/core/processing/node_generators/unnest_node.py
|
|
69
70
|
trilogy/core/processing/node_generators/window_node.py
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
from trilogy import parse
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def test_derivations(test_environment):
|
|
5
|
+
assert (
|
|
6
|
+
test_environment.concepts["order_timestamp"].address == "local.order_timestamp"
|
|
7
|
+
)
|
|
8
|
+
assert (
|
|
9
|
+
test_environment.concepts["order_timestamp.date"].address
|
|
10
|
+
== "local.order_timestamp.date"
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def test_filtering_where_on_derived_aggregate(test_environment):
|
|
15
|
+
exception = False
|
|
16
|
+
try:
|
|
17
|
+
env, _ = parse(
|
|
18
|
+
"""key x int;
|
|
19
|
+
property x.cost float;
|
|
20
|
+
|
|
21
|
+
datasource x_source (
|
|
22
|
+
x:x,
|
|
23
|
+
cost:cost)
|
|
24
|
+
grain(x)
|
|
25
|
+
address x_source;
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
SELECT
|
|
29
|
+
sum(cost)-> filtered_cst
|
|
30
|
+
where
|
|
31
|
+
x > 10 and filtered_cst >1000;
|
|
32
|
+
"""
|
|
33
|
+
)
|
|
34
|
+
except Exception as e:
|
|
35
|
+
exception = True
|
|
36
|
+
assert str(e).startswith(
|
|
37
|
+
"Cannot reference an aggregate derived in the select (local.filtered_cst) in the same statement where clause"
|
|
38
|
+
)
|
|
39
|
+
assert exception, "should have an exception"
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def test_filtering_having_on_unincluded_value(test_environment):
|
|
43
|
+
exception = False
|
|
44
|
+
try:
|
|
45
|
+
env, _ = parse(
|
|
46
|
+
"""key x int;
|
|
47
|
+
property x.cost float;
|
|
48
|
+
|
|
49
|
+
datasource x_source (
|
|
50
|
+
x:x,
|
|
51
|
+
cost:cost)
|
|
52
|
+
grain(x)
|
|
53
|
+
address x_source;
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
SELECT
|
|
57
|
+
sum(cost)-> filtered_cst
|
|
58
|
+
having
|
|
59
|
+
x > 10 and filtered_cst >1000;
|
|
60
|
+
"""
|
|
61
|
+
)
|
|
62
|
+
except Exception as e:
|
|
63
|
+
exception = True
|
|
64
|
+
assert str(e).startswith(
|
|
65
|
+
"Cannot reference a column (local.x) that is not in the select projection in the HAVING clause, move to WHERE"
|
|
66
|
+
), str(e)
|
|
67
|
+
assert exception, "should have an exception"
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def test_filtering_valid(test_environment):
|
|
71
|
+
|
|
72
|
+
env, _ = parse(
|
|
73
|
+
"""key x int;
|
|
74
|
+
property x.cost float;
|
|
75
|
+
|
|
76
|
+
datasource x_source (
|
|
77
|
+
x:x,
|
|
78
|
+
cost:cost)
|
|
79
|
+
grain(x)
|
|
80
|
+
address x_source;
|
|
81
|
+
|
|
82
|
+
where
|
|
83
|
+
x>-10
|
|
84
|
+
SELECT
|
|
85
|
+
sum(cost)-> filtered_cst
|
|
86
|
+
having
|
|
87
|
+
filtered_cst >1000;
|
|
88
|
+
"""
|
|
89
|
+
)
|
|
@@ -45,8 +45,6 @@ def test_group_node_property(test_environment: Environment, test_environment_gra
|
|
|
45
45
|
if x not in group_node.parents[0].hidden_concepts
|
|
46
46
|
}
|
|
47
47
|
assert input_concept_names == {"category_name_length", "category_id"}
|
|
48
|
-
# assert len(input_concept.grain.components) == 1
|
|
49
|
-
# assert input_concept.grain.components[0].name == "category_id"
|
|
50
48
|
final = group_node.resolve()
|
|
51
49
|
assert len(final.datasources) == 1
|
|
52
50
|
assert final.datasources[0].group_required is False
|
|
@@ -13,7 +13,10 @@ from trilogy.core.models import (
|
|
|
13
13
|
Join,
|
|
14
14
|
JoinKey,
|
|
15
15
|
Concept,
|
|
16
|
+
AggregateWrapper,
|
|
17
|
+
RowsetItem,
|
|
16
18
|
)
|
|
19
|
+
from trilogy import parse
|
|
17
20
|
|
|
18
21
|
|
|
19
22
|
def test_cte_merge(test_environment, test_environment_graph):
|
|
@@ -262,3 +265,46 @@ def test_join(test_environment: Environment):
|
|
|
262
265
|
str(test)
|
|
263
266
|
== "right outer JOIN test and testb on local.product_id<local.product_id>,local.category_id<local.category_id>"
|
|
264
267
|
), str(test)
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
def test_concept_address_in_check():
|
|
271
|
+
target = Concept(
|
|
272
|
+
name="test",
|
|
273
|
+
datatype="int",
|
|
274
|
+
purpose=Purpose.CONSTANT,
|
|
275
|
+
grain=Grain(),
|
|
276
|
+
environment={},
|
|
277
|
+
)
|
|
278
|
+
assert target.address == "local.test"
|
|
279
|
+
x = [target]
|
|
280
|
+
|
|
281
|
+
assert "local.test" in x
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
def test_rowset_with_filter_derivation():
|
|
285
|
+
env, statements = parse(
|
|
286
|
+
"""
|
|
287
|
+
key x int;
|
|
288
|
+
|
|
289
|
+
datasource test (
|
|
290
|
+
x:x
|
|
291
|
+
)
|
|
292
|
+
grain (x)
|
|
293
|
+
address test
|
|
294
|
+
;
|
|
295
|
+
|
|
296
|
+
with greater_than_ten as
|
|
297
|
+
select x
|
|
298
|
+
where
|
|
299
|
+
x >10;
|
|
300
|
+
|
|
301
|
+
auto avg_greater_ten <- avg(greater_than_ten.x) by *;
|
|
302
|
+
|
|
303
|
+
select avg_greater_ten;
|
|
304
|
+
|
|
305
|
+
"""
|
|
306
|
+
)
|
|
307
|
+
|
|
308
|
+
lineage = env.concepts["avg_greater_ten"].lineage
|
|
309
|
+
assert isinstance(lineage, AggregateWrapper)
|
|
310
|
+
assert isinstance(lineage.function.concept_arguments[0].lineage, RowsetItem)
|
|
@@ -26,22 +26,19 @@ def test_get_datasource_from_window_function(
|
|
|
26
26
|
product_rank = test_environment.concepts["product_revenue_rank"]
|
|
27
27
|
# concept, grain: Grain, environment: Environment, g: ReferenceGraph, query_graph: ReferenceGraph
|
|
28
28
|
# assert product_rank.grain.components[0] == test_environment.concepts['name']
|
|
29
|
-
|
|
29
|
+
node = search_concepts(
|
|
30
30
|
[product_rank] + product_rank.grain.components_copy,
|
|
31
31
|
environment=test_environment,
|
|
32
32
|
g=test_environment_graph,
|
|
33
33
|
depth=0,
|
|
34
|
-
)
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
# raise SyntaxError(product_rank.grain)
|
|
37
|
+
datasource = node.resolve()
|
|
35
38
|
assert product_rank in datasource.output_concepts
|
|
36
39
|
# assert datasource.grain == product_rank.grain
|
|
37
40
|
assert isinstance(datasource, QueryDatasource)
|
|
38
|
-
assert
|
|
39
|
-
datasource.grain.set
|
|
40
|
-
== Grain(
|
|
41
|
-
components=[test_environment.concepts["total_revenue"]]
|
|
42
|
-
+ product_rank.grain.components_copy
|
|
43
|
-
).set
|
|
44
|
-
)
|
|
41
|
+
assert datasource.grain.set == product_rank.grain.set
|
|
45
42
|
|
|
46
43
|
product_rank_by_category = test_environment.concepts[
|
|
47
44
|
"product_revenue_rank_by_category"
|
|
@@ -82,6 +79,9 @@ def test_get_datasource_for_filter(
|
|
|
82
79
|
|
|
83
80
|
|
|
84
81
|
def test_select_output(test_environment, test_environment_graph):
|
|
82
|
+
from trilogy.hooks.query_debugger import DebuggingHook
|
|
83
|
+
|
|
84
|
+
DebuggingHook()
|
|
85
85
|
product = test_environment.concepts["product_id"]
|
|
86
86
|
# concept, grain: Grain, environment: Environment, g: ReferenceGraph, query_graph: ReferenceGraph
|
|
87
87
|
|
|
@@ -340,6 +340,17 @@ def IsNull(args: list[Concept]) -> Function:
|
|
|
340
340
|
)
|
|
341
341
|
|
|
342
342
|
|
|
343
|
+
def Bool(args: list[Concept]) -> Function:
|
|
344
|
+
return Function(
|
|
345
|
+
operator=FunctionType.BOOL,
|
|
346
|
+
arguments=args,
|
|
347
|
+
output_datatype=DataType.BOOL,
|
|
348
|
+
output_purpose=function_args_to_output_purpose(args),
|
|
349
|
+
arg_count=1,
|
|
350
|
+
# output_grain=Grain(components=arguments),
|
|
351
|
+
)
|
|
352
|
+
|
|
353
|
+
|
|
343
354
|
def StrPos(args: list[Concept]) -> Function:
|
|
344
355
|
return Function(
|
|
345
356
|
operator=FunctionType.STRPOS,
|