pytrilogy 0.0.2.40__tar.gz → 0.0.2.42__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.40/pytrilogy.egg-info → pytrilogy-0.0.2.42}/PKG-INFO +2 -2
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/README.md +1 -1
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42/pytrilogy.egg-info}/PKG-INFO +2 -2
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/tests/test_functions.py +10 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/tests/test_select.py +4 -4
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/tests/test_show.py +2 -2
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/tests/test_statements.py +2 -2
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/__init__.py +1 -1
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/core/models.py +6 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/core/optimizations/predicate_pushdown.py +11 -2
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/core/processing/node_generators/basic_node.py +30 -2
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/core/processing/node_generators/window_node.py +30 -7
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/dialect/base.py +5 -2
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/parsing/common.py +12 -2
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/parsing/trilogy.lark +1 -1
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/LICENSE.md +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/pyproject.toml +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/pytrilogy.egg-info/SOURCES.txt +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/pytrilogy.egg-info/dependency_links.txt +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/pytrilogy.egg-info/entry_points.txt +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/pytrilogy.egg-info/requires.txt +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/pytrilogy.egg-info/top_level.txt +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/setup.cfg +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/setup.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/tests/test_datatypes.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/tests/test_declarations.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/tests/test_derived_concepts.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/tests/test_discovery_nodes.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/tests/test_enums.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/tests/test_environment.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/tests/test_executor.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/tests/test_imports.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/tests/test_metadata.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/tests/test_models.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/tests/test_multi_join_assignments.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/tests/test_parse_engine.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/tests/test_parsing.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/tests/test_partial_handling.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/tests/test_query_processing.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/tests/test_undefined_concept.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/tests/test_where_clause.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/compiler.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/constants.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/core/__init__.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/core/constants.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/core/enums.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/core/env_processor.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/core/environment_helpers.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/core/ergonomics.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/core/exceptions.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/core/functions.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/core/graph_models.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/core/internal.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/core/optimization.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/core/optimizations/__init__.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/core/optimizations/base_optimization.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/core/optimizations/inline_constant.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/core/optimizations/inline_datasource.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/core/processing/__init__.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/core/processing/concept_strategies_v3.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/core/processing/graph_utils.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/core/processing/node_generators/__init__.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/core/processing/node_generators/common.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/core/processing/node_generators/filter_node.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/core/processing/node_generators/group_node.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/core/processing/node_generators/group_to_node.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/core/processing/node_generators/multiselect_node.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/core/processing/node_generators/node_merge_node.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/core/processing/node_generators/rowset_node.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/core/processing/node_generators/select_merge_node.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/core/processing/node_generators/select_node.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/core/processing/node_generators/unnest_node.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/core/processing/nodes/__init__.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/core/processing/nodes/base_node.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/core/processing/nodes/filter_node.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/core/processing/nodes/group_node.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/core/processing/nodes/merge_node.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/core/processing/nodes/select_node_v2.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/core/processing/nodes/unnest_node.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/core/processing/nodes/window_node.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/core/processing/utility.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/core/query_processor.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/dialect/__init__.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/dialect/bigquery.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/dialect/common.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/dialect/config.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/dialect/duckdb.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/dialect/enums.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/dialect/postgres.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/dialect/presto.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/dialect/snowflake.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/dialect/sql_server.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/engine.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/executor.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/hooks/__init__.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/hooks/base_hook.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/hooks/graph_hook.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/hooks/query_debugger.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/metadata/__init__.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/parser.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/parsing/__init__.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/parsing/config.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/parsing/exceptions.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/parsing/helpers.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/parsing/parse_engine.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/parsing/render.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/py.typed +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/scripts/__init__.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/scripts/trilogy.py +0 -0
- {pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/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.42
|
|
4
4
|
Summary: Declarative, typed query language that compiles to SQL.
|
|
5
5
|
Home-page:
|
|
6
6
|
Author:
|
|
@@ -186,7 +186,7 @@ datasource usa_names(
|
|
|
186
186
|
gender:gender,
|
|
187
187
|
state:state
|
|
188
188
|
)
|
|
189
|
-
address bigquery-public-data.usa_names.usa_1910_2013
|
|
189
|
+
address `bigquery-public-data.usa_names.usa_1910_2013`;
|
|
190
190
|
|
|
191
191
|
'''
|
|
192
192
|
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: pytrilogy
|
|
3
|
-
Version: 0.0.2.
|
|
3
|
+
Version: 0.0.2.42
|
|
4
4
|
Summary: Declarative, typed query language that compiles to SQL.
|
|
5
5
|
Home-page:
|
|
6
6
|
Author:
|
|
@@ -186,7 +186,7 @@ datasource usa_names(
|
|
|
186
186
|
gender:gender,
|
|
187
187
|
state:state
|
|
188
188
|
)
|
|
189
|
-
address bigquery-public-data.usa_names.usa_1910_2013
|
|
189
|
+
address `bigquery-public-data.usa_names.usa_1910_2013`;
|
|
190
190
|
|
|
191
191
|
'''
|
|
192
192
|
)
|
|
@@ -89,6 +89,16 @@ def test_window_functions(test_environment):
|
|
|
89
89
|
dialect.compile_statement(process_query(test_environment, select))
|
|
90
90
|
|
|
91
91
|
|
|
92
|
+
def test_window_datatype(test_environment):
|
|
93
|
+
declarations = """
|
|
94
|
+
|
|
95
|
+
auto category_rank <- rank category_name order by count(order_id) desc;
|
|
96
|
+
|
|
97
|
+
"""
|
|
98
|
+
env, parsed = parse(declarations, environment=test_environment)
|
|
99
|
+
assert env.concepts["category_rank"].datatype == DataType.INTEGER
|
|
100
|
+
|
|
101
|
+
|
|
92
102
|
def test_date_functions(test_environment):
|
|
93
103
|
declarations = """
|
|
94
104
|
|
|
@@ -19,7 +19,7 @@ datasource posts (
|
|
|
19
19
|
id: post_id
|
|
20
20
|
)
|
|
21
21
|
grain (post_id)
|
|
22
|
-
address bigquery-public-data.stackoverflow.post_history
|
|
22
|
+
address `bigquery-public-data.stackoverflow.post_history`
|
|
23
23
|
;
|
|
24
24
|
|
|
25
25
|
|
|
@@ -29,7 +29,7 @@ datasource users (
|
|
|
29
29
|
about_me: about_me,
|
|
30
30
|
)
|
|
31
31
|
grain (user_id)
|
|
32
|
-
address bigquery-public-data.stackoverflow.users
|
|
32
|
+
address `bigquery-public-data.stackoverflow.users`
|
|
33
33
|
;
|
|
34
34
|
|
|
35
35
|
|
|
@@ -70,7 +70,7 @@ def test_double_aggregate():
|
|
|
70
70
|
id: post_id
|
|
71
71
|
)
|
|
72
72
|
grain (post_id)
|
|
73
|
-
address bigquery-public-data.stackoverflow.post_history
|
|
73
|
+
address `bigquery-public-data.stackoverflow.post_history`
|
|
74
74
|
;
|
|
75
75
|
|
|
76
76
|
|
|
@@ -80,7 +80,7 @@ def test_double_aggregate():
|
|
|
80
80
|
about_me: about_me,
|
|
81
81
|
)
|
|
82
82
|
grain (user_id)
|
|
83
|
-
address bigquery-public-data.stackoverflow.users
|
|
83
|
+
address `bigquery-public-data.stackoverflow.users`
|
|
84
84
|
;
|
|
85
85
|
|
|
86
86
|
|
|
@@ -16,7 +16,7 @@ def test_show_bigquery():
|
|
|
16
16
|
id: post_id
|
|
17
17
|
)
|
|
18
18
|
grain (post_id)
|
|
19
|
-
address bigquery-public-data.stackoverflow.post_history
|
|
19
|
+
address `bigquery-public-data.stackoverflow.post_history`
|
|
20
20
|
;
|
|
21
21
|
|
|
22
22
|
|
|
@@ -26,7 +26,7 @@ def test_show_bigquery():
|
|
|
26
26
|
about_me: about_me,
|
|
27
27
|
)
|
|
28
28
|
grain (user_id)
|
|
29
|
-
address bigquery-public-data.stackoverflow.users
|
|
29
|
+
address `bigquery-public-data.stackoverflow.users`
|
|
30
30
|
;
|
|
31
31
|
|
|
32
32
|
|
|
@@ -40,7 +40,7 @@ datasource posts (
|
|
|
40
40
|
id: post_id
|
|
41
41
|
)
|
|
42
42
|
grain (post_id)
|
|
43
|
-
address bigquery-public-data.stackoverflow.post_history
|
|
43
|
+
address `bigquery-public-data.stackoverflow.post_history`
|
|
44
44
|
;
|
|
45
45
|
"""
|
|
46
46
|
parse(text)
|
|
@@ -76,7 +76,7 @@ datasource x_posts (
|
|
|
76
76
|
id: post_id
|
|
77
77
|
)
|
|
78
78
|
grain (post_id)
|
|
79
|
-
address bigquery-public-data.stackoverflow.post_history
|
|
79
|
+
address `bigquery-public-data.stackoverflow.post_history`
|
|
80
80
|
where post_id = 2
|
|
81
81
|
;
|
|
82
82
|
"""
|
|
@@ -1375,6 +1375,9 @@ class WindowItem(Mergeable, Namespaced, SelectContext, BaseModel):
|
|
|
1375
1375
|
over: List["Concept"] = Field(default_factory=list)
|
|
1376
1376
|
index: Optional[int] = None
|
|
1377
1377
|
|
|
1378
|
+
def __repr__(self) -> str:
|
|
1379
|
+
return f"{self.type}({self.content} {self.index}, {self.over}, {self.order_by})"
|
|
1380
|
+
|
|
1378
1381
|
def with_merge(
|
|
1379
1382
|
self, source: Concept, target: Concept, modifiers: List[Modifier]
|
|
1380
1383
|
) -> "WindowItem":
|
|
@@ -1383,6 +1386,7 @@ class WindowItem(Mergeable, Namespaced, SelectContext, BaseModel):
|
|
|
1383
1386
|
content=self.content.with_merge(source, target, modifiers),
|
|
1384
1387
|
over=[x.with_merge(source, target, modifiers) for x in self.over],
|
|
1385
1388
|
order_by=[x.with_merge(source, target, modifiers) for x in self.order_by],
|
|
1389
|
+
index=self.index,
|
|
1386
1390
|
)
|
|
1387
1391
|
|
|
1388
1392
|
def with_namespace(self, namespace: str) -> "WindowItem":
|
|
@@ -1391,6 +1395,7 @@ class WindowItem(Mergeable, Namespaced, SelectContext, BaseModel):
|
|
|
1391
1395
|
content=self.content.with_namespace(namespace),
|
|
1392
1396
|
over=[x.with_namespace(namespace) for x in self.over],
|
|
1393
1397
|
order_by=[x.with_namespace(namespace) for x in self.order_by],
|
|
1398
|
+
index=self.index,
|
|
1394
1399
|
)
|
|
1395
1400
|
|
|
1396
1401
|
def with_select_context(
|
|
@@ -1410,6 +1415,7 @@ class WindowItem(Mergeable, Namespaced, SelectContext, BaseModel):
|
|
|
1410
1415
|
x.with_select_context(grain, conditional, environment)
|
|
1411
1416
|
for x in self.order_by
|
|
1412
1417
|
],
|
|
1418
|
+
index=self.index,
|
|
1413
1419
|
)
|
|
1414
1420
|
|
|
1415
1421
|
@property
|
|
@@ -6,6 +6,7 @@ from trilogy.core.models import (
|
|
|
6
6
|
ConceptArgs,
|
|
7
7
|
Comparison,
|
|
8
8
|
Parenthetical,
|
|
9
|
+
WindowItem,
|
|
9
10
|
)
|
|
10
11
|
from trilogy.core.optimizations.base_optimization import OptimizationRule
|
|
11
12
|
from trilogy.core.processing.utility import is_scalar_condition
|
|
@@ -45,7 +46,15 @@ class PredicatePushdown(OptimizationRule):
|
|
|
45
46
|
all_inputs = {x.address for x in candidate.concept_arguments}
|
|
46
47
|
if is_child_of(candidate, parent_cte.condition):
|
|
47
48
|
return False
|
|
48
|
-
|
|
49
|
+
non_materialized = [k for k, v in parent_cte.source_map.items() if v == []]
|
|
50
|
+
concrete = [
|
|
51
|
+
x for x in parent_cte.output_columns if x.address in non_materialized
|
|
52
|
+
]
|
|
53
|
+
if any(isinstance(x.lineage, WindowItem) for x in concrete):
|
|
54
|
+
self.debug(
|
|
55
|
+
f"CTE {parent_cte.name} has window clause calculation, cannot push up to this without changing results"
|
|
56
|
+
)
|
|
57
|
+
return False
|
|
49
58
|
materialized = {k for k, v in parent_cte.source_map.items() if v != []}
|
|
50
59
|
if not row_conditions or not materialized:
|
|
51
60
|
return False
|
|
@@ -108,12 +117,12 @@ class PredicatePushdown(OptimizationRule):
|
|
|
108
117
|
|
|
109
118
|
if not cte.parent_ctes:
|
|
110
119
|
self.debug(f"No parent CTEs for {cte.name}")
|
|
111
|
-
|
|
112
120
|
return False
|
|
113
121
|
|
|
114
122
|
if not cte.condition:
|
|
115
123
|
self.debug(f"No CTE condition for {cte.name}")
|
|
116
124
|
return False
|
|
125
|
+
|
|
117
126
|
if self.complete.get(cte.name):
|
|
118
127
|
self.debug("Have done this CTE before")
|
|
119
128
|
return False
|
{pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/core/processing/node_generators/basic_node.py
RENAMED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
# directly select out a basic derivation
|
|
2
2
|
from typing import List
|
|
3
3
|
|
|
4
|
-
from trilogy.core.models import
|
|
4
|
+
from trilogy.core.models import (
|
|
5
|
+
Concept,
|
|
6
|
+
WhereClause,
|
|
7
|
+
Function,
|
|
8
|
+
FunctionClass,
|
|
9
|
+
)
|
|
5
10
|
from trilogy.core.processing.nodes import StrategyNode, History
|
|
6
11
|
from trilogy.core.processing.node_generators.common import (
|
|
7
12
|
resolve_function_parent_concepts,
|
|
@@ -12,6 +17,22 @@ from trilogy.core.enums import SourceType
|
|
|
12
17
|
LOGGER_PREFIX = "[GEN_BASIC_NODE]"
|
|
13
18
|
|
|
14
19
|
|
|
20
|
+
def is_equivalent_basic_function_lineage(
|
|
21
|
+
x: Concept,
|
|
22
|
+
y: Concept,
|
|
23
|
+
):
|
|
24
|
+
if not isinstance(x.lineage, Function) or not isinstance(y.lineage, Function):
|
|
25
|
+
return False
|
|
26
|
+
if x.lineage.operator == y.lineage.operator:
|
|
27
|
+
return True
|
|
28
|
+
if (
|
|
29
|
+
y.lineage.operator in FunctionClass.AGGREGATE_FUNCTIONS.value
|
|
30
|
+
or y.lineage.operator in FunctionClass.ONE_TO_MANY.value
|
|
31
|
+
):
|
|
32
|
+
return False
|
|
33
|
+
return True
|
|
34
|
+
|
|
35
|
+
|
|
15
36
|
def gen_basic_node(
|
|
16
37
|
concept: Concept,
|
|
17
38
|
local_optional: List[Concept],
|
|
@@ -32,8 +53,15 @@ def gen_basic_node(
|
|
|
32
53
|
equivalent_optional = [
|
|
33
54
|
x
|
|
34
55
|
for x in local_optional
|
|
35
|
-
if
|
|
56
|
+
if is_equivalent_basic_function_lineage(concept, x)
|
|
57
|
+
and x.address != concept.address
|
|
36
58
|
]
|
|
59
|
+
if equivalent_optional:
|
|
60
|
+
logger.info(
|
|
61
|
+
f"{depth_prefix}{LOGGER_PREFIX} basic node for {concept} has equivalent optional {[x.address for x in equivalent_optional]}"
|
|
62
|
+
)
|
|
63
|
+
for eo in equivalent_optional:
|
|
64
|
+
parent_concepts += resolve_function_parent_concepts(eo)
|
|
37
65
|
non_equivalent_optional = [
|
|
38
66
|
x for x in local_optional if x not in equivalent_optional
|
|
39
67
|
]
|
{pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/core/processing/node_generators/window_node.py
RENAMED
|
@@ -10,16 +10,23 @@ from trilogy.core.processing.utility import padding
|
|
|
10
10
|
LOGGER_PREFIX = "[GEN_WINDOW_NODE]"
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
def resolve_window_parent_concepts(
|
|
13
|
+
def resolve_window_parent_concepts(
|
|
14
|
+
concept: Concept, environment: Environment
|
|
15
|
+
) -> tuple[Concept, List[Concept]]:
|
|
14
16
|
if not isinstance(concept.lineage, WindowItem):
|
|
15
17
|
raise ValueError
|
|
16
|
-
base = [
|
|
18
|
+
base = []
|
|
17
19
|
if concept.lineage.over:
|
|
18
20
|
base += concept.lineage.over
|
|
19
21
|
if concept.lineage.order_by:
|
|
20
22
|
for item in concept.lineage.order_by:
|
|
23
|
+
# TODO: we do want to use the rehydrated value, but
|
|
24
|
+
# that introduces a circular dependency on an aggregate
|
|
25
|
+
# that is grouped by a window
|
|
26
|
+
# need to figure out how to resolve this
|
|
27
|
+
# base += [environment.concepts[item.expr.output.address]]
|
|
21
28
|
base += [item.expr.output]
|
|
22
|
-
return unique(base, "address")
|
|
29
|
+
return concept.lineage.content, unique(base, "address")
|
|
23
30
|
|
|
24
31
|
|
|
25
32
|
def gen_window_node(
|
|
@@ -32,9 +39,25 @@ def gen_window_node(
|
|
|
32
39
|
history: History | None = None,
|
|
33
40
|
conditions: WhereClause | None = None,
|
|
34
41
|
) -> StrategyNode | None:
|
|
35
|
-
parent_concepts = resolve_window_parent_concepts(concept)
|
|
36
|
-
|
|
37
|
-
|
|
42
|
+
base, parent_concepts = resolve_window_parent_concepts(concept, environment)
|
|
43
|
+
equivalent_optional = [
|
|
44
|
+
x
|
|
45
|
+
for x in local_optional
|
|
46
|
+
if isinstance(x.lineage, WindowItem)
|
|
47
|
+
and resolve_window_parent_concepts(x, environment)[1] == parent_concepts
|
|
48
|
+
]
|
|
49
|
+
|
|
50
|
+
non_equivalent_optional = [
|
|
51
|
+
x for x in local_optional if x.address not in equivalent_optional
|
|
52
|
+
]
|
|
53
|
+
targets = [base]
|
|
54
|
+
if equivalent_optional:
|
|
55
|
+
for x in equivalent_optional:
|
|
56
|
+
assert isinstance(x.lineage, WindowItem)
|
|
57
|
+
targets.append(x.lineage.content)
|
|
58
|
+
|
|
59
|
+
parent_node: StrategyNode = source_concepts(
|
|
60
|
+
mandatory_list=parent_concepts + targets + non_equivalent_optional,
|
|
38
61
|
environment=environment,
|
|
39
62
|
g=g,
|
|
40
63
|
depth=depth + 1,
|
|
@@ -61,7 +84,7 @@ def gen_window_node(
|
|
|
61
84
|
)
|
|
62
85
|
raise SyntaxError
|
|
63
86
|
_window_node = WindowNode(
|
|
64
|
-
input_concepts=parent_concepts +
|
|
87
|
+
input_concepts=parent_concepts + targets + non_equivalent_optional,
|
|
65
88
|
output_concepts=[concept] + parent_concepts + local_optional,
|
|
66
89
|
environment=environment,
|
|
67
90
|
g=g,
|
|
@@ -75,7 +75,7 @@ def window_factory(string: str, include_concept: bool = False) -> Callable:
|
|
|
75
75
|
) -> str:
|
|
76
76
|
if not include_concept:
|
|
77
77
|
concept = ""
|
|
78
|
-
if offset:
|
|
78
|
+
if offset is not None:
|
|
79
79
|
base = f"{string}({concept}, {offset})"
|
|
80
80
|
else:
|
|
81
81
|
base = f"{string}({concept})"
|
|
@@ -313,7 +313,10 @@ class BaseDialect:
|
|
|
313
313
|
)
|
|
314
314
|
for x in c.lineage.over
|
|
315
315
|
]
|
|
316
|
-
rval = f"{self.WINDOW_FUNCTION_MAP[c.lineage.type](concept = self.render_concept_sql(c.lineage.content,
|
|
316
|
+
rval = f"{self.WINDOW_FUNCTION_MAP[c.lineage.type](concept = self.render_concept_sql(c.lineage.content,
|
|
317
|
+
cte=cte, alias=False, raise_invalid=raise_invalid),
|
|
318
|
+
window=','.join(rendered_over_components), sort=','.join(rendered_order_components),
|
|
319
|
+
offset=c.lineage.index)}" # noqa: E501
|
|
317
320
|
elif isinstance(c.lineage, FilterItem):
|
|
318
321
|
# for cases when we've optimized this
|
|
319
322
|
if cte.condition == c.lineage.where.conditional:
|
|
@@ -13,6 +13,7 @@ from trilogy.core.models import (
|
|
|
13
13
|
Parenthetical,
|
|
14
14
|
FunctionClass,
|
|
15
15
|
Environment,
|
|
16
|
+
DataType,
|
|
16
17
|
)
|
|
17
18
|
from typing import List, Tuple
|
|
18
19
|
from trilogy.core.functions import (
|
|
@@ -25,7 +26,7 @@ from trilogy.core.enums import PurposeLineage
|
|
|
25
26
|
from trilogy.constants import (
|
|
26
27
|
VIRTUAL_CONCEPT_PREFIX,
|
|
27
28
|
)
|
|
28
|
-
from trilogy.core.enums import Modifier
|
|
29
|
+
from trilogy.core.enums import Modifier, WindowType
|
|
29
30
|
|
|
30
31
|
|
|
31
32
|
def get_upstream_modifiers(keys: List[Concept]) -> list[Modifier]:
|
|
@@ -234,9 +235,18 @@ def window_item_to_concept(
|
|
|
234
235
|
else:
|
|
235
236
|
grain = parent.over + [parent.content.output]
|
|
236
237
|
modifiers = get_upstream_modifiers(parent.content.concept_arguments)
|
|
238
|
+
datatype = parent.content.datatype
|
|
239
|
+
if parent.type in (
|
|
240
|
+
WindowType.RANK,
|
|
241
|
+
WindowType.ROW_NUMBER,
|
|
242
|
+
WindowType.COUNT,
|
|
243
|
+
WindowType.COUNT_DISTINCT,
|
|
244
|
+
):
|
|
245
|
+
datatype = DataType.INTEGER
|
|
246
|
+
|
|
237
247
|
return Concept(
|
|
238
248
|
name=name,
|
|
239
|
-
datatype=
|
|
249
|
+
datatype=datatype,
|
|
240
250
|
purpose=local_purpose,
|
|
241
251
|
lineage=parent,
|
|
242
252
|
metadata=fmetadata,
|
|
@@ -290,7 +290,7 @@
|
|
|
290
290
|
|
|
291
291
|
// base language constructs
|
|
292
292
|
concept_lit: IDENTIFIER
|
|
293
|
-
IDENTIFIER: /[a-zA-Z\_][a-zA-Z0-9\_
|
|
293
|
+
IDENTIFIER: /[a-zA-Z\_][a-zA-Z0-9\_\.]*/
|
|
294
294
|
WILDCARD_IDENTIFIER: /[a-zA-Z\_][a-zA-Z0-9\_\-\.\*]*/
|
|
295
295
|
QUOTED_IDENTIFIER: /`[a-zA-Z\_][a-zA-Z0-9\_\.\-\*\:\s]*`/
|
|
296
296
|
QUOTED_ADDRESS: /`[a-zA-Z\_][a-zA-Z0-9\_\.\-\*\:]*`/
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/core/processing/node_generators/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/core/processing/node_generators/filter_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/core/processing/node_generators/group_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/core/processing/node_generators/group_to_node.py
RENAMED
|
File without changes
|
|
File without changes
|
{pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/core/processing/node_generators/node_merge_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/core/processing/node_generators/rowset_node.py
RENAMED
|
File without changes
|
|
File without changes
|
{pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/core/processing/node_generators/select_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.2.40 → pytrilogy-0.0.2.42}/trilogy/core/processing/node_generators/unnest_node.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|