pytrilogy 0.0.2.39__py3-none-any.whl → 0.0.2.41__py3-none-any.whl
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.39.dist-info → pytrilogy-0.0.2.41.dist-info}/METADATA +4 -4
- {pytrilogy-0.0.2.39.dist-info → pytrilogy-0.0.2.41.dist-info}/RECORD +15 -15
- {pytrilogy-0.0.2.39.dist-info → pytrilogy-0.0.2.41.dist-info}/WHEEL +1 -1
- trilogy/__init__.py +1 -1
- trilogy/core/models.py +9 -3
- trilogy/core/optimizations/predicate_pushdown.py +11 -2
- trilogy/core/processing/node_generators/basic_node.py +30 -2
- trilogy/core/processing/node_generators/window_node.py +23 -7
- trilogy/dialect/base.py +9 -6
- trilogy/parsing/parse_engine.py +4 -4
- trilogy/parsing/render.py +4 -4
- trilogy/parsing/trilogy.lark +1 -1
- {pytrilogy-0.0.2.39.dist-info → pytrilogy-0.0.2.41.dist-info}/LICENSE.md +0 -0
- {pytrilogy-0.0.2.39.dist-info → pytrilogy-0.0.2.41.dist-info}/entry_points.txt +0 -0
- {pytrilogy-0.0.2.39.dist-info → pytrilogy-0.0.2.41.dist-info}/top_level.txt +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.41
|
|
4
4
|
Summary: Declarative, typed query language that compiles to SQL.
|
|
5
5
|
Home-page:
|
|
6
6
|
Author:
|
|
@@ -21,10 +21,10 @@ Requires-Dist: pyodbc
|
|
|
21
21
|
Requires-Dist: pydantic
|
|
22
22
|
Requires-Dist: duckdb-engine
|
|
23
23
|
Requires-Dist: click
|
|
24
|
-
Provides-Extra: bigquery
|
|
25
|
-
Requires-Dist: sqlalchemy-bigquery; extra == "bigquery"
|
|
26
24
|
Provides-Extra: postgres
|
|
27
25
|
Requires-Dist: psycopg2-binary; extra == "postgres"
|
|
26
|
+
Provides-Extra: bigquery
|
|
27
|
+
Requires-Dist: sqlalchemy-bigquery; extra == "bigquery"
|
|
28
28
|
Provides-Extra: snowflake
|
|
29
29
|
Requires-Dist: snowflake-sqlalchemy; extra == "snowflake"
|
|
30
30
|
|
|
@@ -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,4 +1,4 @@
|
|
|
1
|
-
trilogy/__init__.py,sha256=
|
|
1
|
+
trilogy/__init__.py,sha256=TkwxYmJ568eljR1wX8-wzP48QWvm0V6gSnZBN5DX-jk,291
|
|
2
2
|
trilogy/compiler.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
3
|
trilogy/constants.py,sha256=UPymm94T2c6a55XdDaXw0aleTe1pOJ6lf6gOWLKZyKg,1430
|
|
4
4
|
trilogy/engine.py,sha256=R5ubIxYyrxRExz07aZCUfrTsoXCHQ8DKFTDsobXdWdA,1102
|
|
@@ -16,20 +16,20 @@ trilogy/core/exceptions.py,sha256=NvV_4qLOgKXbpotgRf7c8BANDEvHxlqRPaA53IThQ2o,56
|
|
|
16
16
|
trilogy/core/functions.py,sha256=IhVpt3n6wEanKHnGu3oA2w6-hKIlxWpEyz7fHN66mpo,10720
|
|
17
17
|
trilogy/core/graph_models.py,sha256=mameUTiuCajtihDw_2-W218xyJlvTusOWrEKP1yAWgk,2003
|
|
18
18
|
trilogy/core/internal.py,sha256=jNGFHKENnbMiMCtAgsnLZYVSENDK4b5ALecXFZpTDzQ,1075
|
|
19
|
-
trilogy/core/models.py,sha256=
|
|
19
|
+
trilogy/core/models.py,sha256=5pUsZoiEHEFLvZTddpy-_u_2w_lH9tJIPe5lQH5Ru-s,163252
|
|
20
20
|
trilogy/core/optimization.py,sha256=VFSvJLNoCCOraip-PZUKeE4qrlxtXARjQUzJZiW-yRk,7325
|
|
21
21
|
trilogy/core/query_processor.py,sha256=mbcZlgjChrRjDHkdmMbKe-T70UpbBkJhS09MyU5a6UY,17785
|
|
22
22
|
trilogy/core/optimizations/__init__.py,sha256=bWQecbeiwiDx9LJnLsa7dkWxdbl2wcnkcTN69JyP8iI,356
|
|
23
23
|
trilogy/core/optimizations/base_optimization.py,sha256=tWWT-xnTbnEU-mNi_isMNbywm8B9WTRsNFwGpeh3rqE,468
|
|
24
24
|
trilogy/core/optimizations/inline_constant.py,sha256=kHNyc2UoaPVdYfVAPAFwnWuk4sJ_IF5faRtVcDOrBtw,1110
|
|
25
25
|
trilogy/core/optimizations/inline_datasource.py,sha256=NqUOVl0pOXF1R_roELVW8I0qN7or2wPtAsRmDD9QJso,3658
|
|
26
|
-
trilogy/core/optimizations/predicate_pushdown.py,sha256=
|
|
26
|
+
trilogy/core/optimizations/predicate_pushdown.py,sha256=oJy09U7lb8FMKexWISjg4Ksyf98Nx22bzIxmm9WuXtk,8899
|
|
27
27
|
trilogy/core/processing/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
28
28
|
trilogy/core/processing/concept_strategies_v3.py,sha256=Qy3WHiKaF371dDmbA0DWVQqSMKptH_gK714Uc41wbqc,36132
|
|
29
29
|
trilogy/core/processing/graph_utils.py,sha256=aq-kqk4Iado2HywDxWEejWc-7PGO6Oa-ZQLAM6XWPHw,1199
|
|
30
30
|
trilogy/core/processing/utility.py,sha256=_sWLDuV8WAEWdEIcAPM8-FcXgBai30UV12i4O9u5Mpc,18680
|
|
31
31
|
trilogy/core/processing/node_generators/__init__.py,sha256=-mzYkRsaRNa_dfTckYkKVFSR8h8a3ihEiPJDU_tAmDo,672
|
|
32
|
-
trilogy/core/processing/node_generators/basic_node.py,sha256=
|
|
32
|
+
trilogy/core/processing/node_generators/basic_node.py,sha256=qsQ8HegQ2qOSpXFleq7yHJ-rYfF6XQGCC7h2pC-t1kQ,2878
|
|
33
33
|
trilogy/core/processing/node_generators/common.py,sha256=eslHTTPFTkmwHwKIuUsbFn54jxj-Avtt-QScqtNwzdg,8945
|
|
34
34
|
trilogy/core/processing/node_generators/filter_node.py,sha256=Vz9Rb67e1dfZgnliekwwLeDPVkthMbdrnrKRdz7J1ik,7654
|
|
35
35
|
trilogy/core/processing/node_generators/group_node.py,sha256=r54IVEhXW-tzod6uEHIQObrxgQt6aNySk5emWkWyqCU,4938
|
|
@@ -40,7 +40,7 @@ trilogy/core/processing/node_generators/rowset_node.py,sha256=KtdN6t2xM8CJxobc4a
|
|
|
40
40
|
trilogy/core/processing/node_generators/select_merge_node.py,sha256=UF4xra2sJ6dGg9TLJUgqtTX-UxqUaCEfAGo-uq7HlVs,12139
|
|
41
41
|
trilogy/core/processing/node_generators/select_node.py,sha256=nwXHQF6C-aQUIelx9dyxN2pK3muL-4-6RIqnqQqNwtw,1808
|
|
42
42
|
trilogy/core/processing/node_generators/unnest_node.py,sha256=cZ26CN338CBnd6asML1OBUtNcDzmNlFpY0Vnade4yrc,2256
|
|
43
|
-
trilogy/core/processing/node_generators/window_node.py,sha256=
|
|
43
|
+
trilogy/core/processing/node_generators/window_node.py,sha256=Jfjjdvn8RqFzrQ1gZc6vS0Bsh_iTA5AmRZ0zLlT4574,3155
|
|
44
44
|
trilogy/core/processing/nodes/__init__.py,sha256=qS5EJDRwwIrCEfS7ibCA2ESE0RPzsAIii1UWd_wNsHA,4760
|
|
45
45
|
trilogy/core/processing/nodes/base_node.py,sha256=sc3HrXkWk-xpsAQ7B7ltX1ZejYAkqFiv8Ei8Jg5VGkQ,15579
|
|
46
46
|
trilogy/core/processing/nodes/filter_node.py,sha256=GfZ9eghpFDI-s7iQP2UqTljCmn25LT_T5TAxDlh7PkQ,2343
|
|
@@ -50,7 +50,7 @@ trilogy/core/processing/nodes/select_node_v2.py,sha256=7WoFxeGEAzhpS4y4Zw2nH2tt7
|
|
|
50
50
|
trilogy/core/processing/nodes/unnest_node.py,sha256=mAmFluzm2yeeiQ6NfIB7BU_8atRGh-UJfPf9ROwbhr8,2152
|
|
51
51
|
trilogy/core/processing/nodes/window_node.py,sha256=ro0QfMFi4ZmIn5Q4D0M_vJWfnHH_C0MN7XkVkx8Gygg,1214
|
|
52
52
|
trilogy/dialect/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
53
|
-
trilogy/dialect/base.py,sha256=
|
|
53
|
+
trilogy/dialect/base.py,sha256=bevM9mUGSfwt_F-kJpi0nHmMRmE0pINqqvCteqnu5FM,34880
|
|
54
54
|
trilogy/dialect/bigquery.py,sha256=15KJ-cOpBlk9O7FPviPgmg8xIydJeKx7WfmL3SSsPE8,2953
|
|
55
55
|
trilogy/dialect/common.py,sha256=eqJi_Si1iyb2sV0siTf8g8JOHueWu6RkdtQZtutKazk,3826
|
|
56
56
|
trilogy/dialect/config.py,sha256=tLVEMctaTDhUgARKXUNfHUcIolGaALkQ0RavUvXAY4w,2994
|
|
@@ -70,14 +70,14 @@ trilogy/parsing/common.py,sha256=_GW9LU6_4RuUgcdcr8EE1ybCRd-7cz3idZtjHZ66pYA,101
|
|
|
70
70
|
trilogy/parsing/config.py,sha256=Z-DaefdKhPDmSXLgg5V4pebhSB0h590vI0_VtHnlukI,111
|
|
71
71
|
trilogy/parsing/exceptions.py,sha256=92E5i2frv5hj9wxObJZsZqj5T6bglvPzvdvco_vW1Zk,38
|
|
72
72
|
trilogy/parsing/helpers.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
73
|
-
trilogy/parsing/parse_engine.py,sha256=
|
|
74
|
-
trilogy/parsing/render.py,sha256
|
|
75
|
-
trilogy/parsing/trilogy.lark,sha256=
|
|
73
|
+
trilogy/parsing/parse_engine.py,sha256=KMeHQf8iW-UKd4JstGgcoo6O3OZ14MaQW50g1PMjEEQ,65256
|
|
74
|
+
trilogy/parsing/render.py,sha256=-qqpXQg4yHcv284Vosjnsc_vrPveH6oaYbeCd3ZSvs0,15682
|
|
75
|
+
trilogy/parsing/trilogy.lark,sha256=B6NM3-rBHtYB_WSEti0DiS8Z-I8YH3kZU47xNzQvBx4,12389
|
|
76
76
|
trilogy/scripts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
77
77
|
trilogy/scripts/trilogy.py,sha256=PHxvv6f2ODv0esyyhWxlARgra8dVhqQhYl0lTrSyVNo,3729
|
|
78
|
-
pytrilogy-0.0.2.
|
|
79
|
-
pytrilogy-0.0.2.
|
|
80
|
-
pytrilogy-0.0.2.
|
|
81
|
-
pytrilogy-0.0.2.
|
|
82
|
-
pytrilogy-0.0.2.
|
|
83
|
-
pytrilogy-0.0.2.
|
|
78
|
+
pytrilogy-0.0.2.41.dist-info/LICENSE.md,sha256=5ZRvtTyCCFwz1THxDTjAu3Lidds9WjPvvzgVwPSYNDo,1042
|
|
79
|
+
pytrilogy-0.0.2.41.dist-info/METADATA,sha256=PGYuvWWThHh9Vucj7-eZIWLGu7db7pN7iVyXL9f42-Q,8426
|
|
80
|
+
pytrilogy-0.0.2.41.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
|
|
81
|
+
pytrilogy-0.0.2.41.dist-info/entry_points.txt,sha256=0petKryjvvtEfTlbZC1AuMFumH_WQ9v8A19LvoS6G6c,54
|
|
82
|
+
pytrilogy-0.0.2.41.dist-info/top_level.txt,sha256=cAy__NW_eMAa_yT9UnUNlZLFfxcg6eimUAZ184cdNiE,8
|
|
83
|
+
pytrilogy-0.0.2.41.dist-info/RECORD,,
|
trilogy/__init__.py
CHANGED
trilogy/core/models.py
CHANGED
|
@@ -448,8 +448,8 @@ class Concept(Mergeable, Namespaced, SelectContext, BaseModel):
|
|
|
448
448
|
] = None
|
|
449
449
|
namespace: Optional[str] = Field(default=DEFAULT_NAMESPACE, validate_default=True)
|
|
450
450
|
keys: Optional[Tuple["Concept", ...]] = None
|
|
451
|
-
grain: "Grain" = Field(default=None, validate_default=True)
|
|
452
|
-
modifiers:
|
|
451
|
+
grain: "Grain" = Field(default=None, validate_default=True) # type: ignore
|
|
452
|
+
modifiers: List[Modifier] = Field(default_factory=list) # type: ignore
|
|
453
453
|
pseudonyms: set[str] = Field(default_factory=set)
|
|
454
454
|
_address_cache: str | None = None
|
|
455
455
|
|
|
@@ -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
|
|
@@ -3372,7 +3378,7 @@ class Environment(BaseModel):
|
|
|
3372
3378
|
functions: Dict[str, Function] = Field(default_factory=dict)
|
|
3373
3379
|
data_types: Dict[str, DataType] = Field(default_factory=dict)
|
|
3374
3380
|
imports: Dict[str, list[ImportStatement]] = Field(
|
|
3375
|
-
default_factory=lambda: defaultdict(list)
|
|
3381
|
+
default_factory=lambda: defaultdict(list) # type: ignore
|
|
3376
3382
|
)
|
|
3377
3383
|
namespace: str = DEFAULT_NAMESPACE
|
|
3378
3384
|
working_path: str | Path = Field(default_factory=lambda: os.getcwd())
|
|
@@ -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
|
|
@@ -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
|
]
|
|
@@ -10,16 +10,16 @@ from trilogy.core.processing.utility import padding
|
|
|
10
10
|
LOGGER_PREFIX = "[GEN_WINDOW_NODE]"
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
def resolve_window_parent_concepts(concept: Concept) -> List[Concept]:
|
|
13
|
+
def resolve_window_parent_concepts(concept: Concept) -> tuple[Concept, List[Concept]]:
|
|
14
14
|
if not isinstance(concept.lineage, WindowItem):
|
|
15
15
|
raise ValueError
|
|
16
|
-
base = [
|
|
16
|
+
base = []
|
|
17
17
|
if concept.lineage.over:
|
|
18
18
|
base += concept.lineage.over
|
|
19
19
|
if concept.lineage.order_by:
|
|
20
20
|
for item in concept.lineage.order_by:
|
|
21
21
|
base += [item.expr.output]
|
|
22
|
-
return unique(base, "address")
|
|
22
|
+
return concept.lineage.content, unique(base, "address")
|
|
23
23
|
|
|
24
24
|
|
|
25
25
|
def gen_window_node(
|
|
@@ -32,9 +32,25 @@ def gen_window_node(
|
|
|
32
32
|
history: History | None = None,
|
|
33
33
|
conditions: WhereClause | None = None,
|
|
34
34
|
) -> StrategyNode | None:
|
|
35
|
-
parent_concepts = resolve_window_parent_concepts(concept)
|
|
36
|
-
|
|
37
|
-
|
|
35
|
+
base, parent_concepts = resolve_window_parent_concepts(concept)
|
|
36
|
+
equivalent_optional = [
|
|
37
|
+
x
|
|
38
|
+
for x in local_optional
|
|
39
|
+
if isinstance(x.lineage, WindowItem)
|
|
40
|
+
and resolve_window_parent_concepts(x)[1] == parent_concepts
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
non_equivalent_optional = [
|
|
44
|
+
x for x in local_optional if x.address not in equivalent_optional
|
|
45
|
+
]
|
|
46
|
+
targets = [base]
|
|
47
|
+
if equivalent_optional:
|
|
48
|
+
for x in equivalent_optional:
|
|
49
|
+
assert isinstance(x.lineage, WindowItem)
|
|
50
|
+
targets.append(x.lineage.content)
|
|
51
|
+
|
|
52
|
+
parent_node: StrategyNode = source_concepts(
|
|
53
|
+
mandatory_list=parent_concepts + targets + non_equivalent_optional,
|
|
38
54
|
environment=environment,
|
|
39
55
|
g=g,
|
|
40
56
|
depth=depth + 1,
|
|
@@ -61,7 +77,7 @@ def gen_window_node(
|
|
|
61
77
|
)
|
|
62
78
|
raise SyntaxError
|
|
63
79
|
_window_node = WindowNode(
|
|
64
|
-
input_concepts=parent_concepts +
|
|
80
|
+
input_concepts=parent_concepts + targets + non_equivalent_optional,
|
|
65
81
|
output_concepts=[concept] + parent_concepts + local_optional,
|
|
66
82
|
environment=environment,
|
|
67
83
|
g=g,
|
trilogy/dialect/base.py
CHANGED
|
@@ -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})"
|
|
@@ -138,10 +138,10 @@ FUNCTION_MAP = {
|
|
|
138
138
|
FunctionType.STRUCT: lambda x: f"{{{', '.join(struct_arg(x))}}}",
|
|
139
139
|
FunctionType.ARRAY: lambda x: f"[{', '.join(x)}]",
|
|
140
140
|
# math
|
|
141
|
-
FunctionType.ADD: lambda x:
|
|
142
|
-
FunctionType.SUBTRACT: lambda x:
|
|
143
|
-
FunctionType.DIVIDE: lambda x:
|
|
144
|
-
FunctionType.MULTIPLY: lambda x:
|
|
141
|
+
FunctionType.ADD: lambda x: " + ".join(x),
|
|
142
|
+
FunctionType.SUBTRACT: lambda x: " - ".join(x),
|
|
143
|
+
FunctionType.DIVIDE: lambda x: " / ".join(x),
|
|
144
|
+
FunctionType.MULTIPLY: lambda x: " * ".join(x),
|
|
145
145
|
FunctionType.ROUND: lambda x: f"round({x[0]},{x[1]})",
|
|
146
146
|
FunctionType.MOD: lambda x: f"({x[0]} % {x[1]})",
|
|
147
147
|
# aggregate types
|
|
@@ -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:
|
trilogy/parsing/parse_engine.py
CHANGED
|
@@ -1777,7 +1777,7 @@ class ParseToObjects(Transformer):
|
|
|
1777
1777
|
output_datatype=output_datatype,
|
|
1778
1778
|
output_purpose=function_args_to_output_purpose(args),
|
|
1779
1779
|
valid_inputs={DataType.INTEGER, DataType.FLOAT, DataType.NUMBER},
|
|
1780
|
-
arg_count
|
|
1780
|
+
arg_count=-1,
|
|
1781
1781
|
)
|
|
1782
1782
|
|
|
1783
1783
|
@v_args(meta=True)
|
|
@@ -1790,7 +1790,7 @@ class ParseToObjects(Transformer):
|
|
|
1790
1790
|
output_datatype=output_datatype,
|
|
1791
1791
|
output_purpose=function_args_to_output_purpose(args),
|
|
1792
1792
|
valid_inputs={DataType.INTEGER, DataType.FLOAT, DataType.NUMBER},
|
|
1793
|
-
arg_count
|
|
1793
|
+
arg_count=-1,
|
|
1794
1794
|
)
|
|
1795
1795
|
|
|
1796
1796
|
@v_args(meta=True)
|
|
@@ -1803,7 +1803,7 @@ class ParseToObjects(Transformer):
|
|
|
1803
1803
|
output_datatype=output_datatype,
|
|
1804
1804
|
output_purpose=function_args_to_output_purpose(args),
|
|
1805
1805
|
valid_inputs={DataType.INTEGER, DataType.FLOAT, DataType.NUMBER},
|
|
1806
|
-
arg_count
|
|
1806
|
+
arg_count=-1,
|
|
1807
1807
|
)
|
|
1808
1808
|
|
|
1809
1809
|
@v_args(meta=True)
|
|
@@ -1817,7 +1817,7 @@ class ParseToObjects(Transformer):
|
|
|
1817
1817
|
output_datatype=DataType.FLOAT, # division always returns a float
|
|
1818
1818
|
output_purpose=function_args_to_output_purpose(args),
|
|
1819
1819
|
valid_inputs={DataType.INTEGER, DataType.FLOAT, DataType.NUMBER},
|
|
1820
|
-
arg_count
|
|
1820
|
+
arg_count=-1,
|
|
1821
1821
|
)
|
|
1822
1822
|
|
|
1823
1823
|
@v_args(meta=True)
|
trilogy/parsing/render.py
CHANGED
|
@@ -395,13 +395,13 @@ class Renderer:
|
|
|
395
395
|
args = [self.to_string(c) for c in arg.arguments]
|
|
396
396
|
|
|
397
397
|
if arg.operator == FunctionType.SUBTRACT:
|
|
398
|
-
return
|
|
398
|
+
return " - ".join(args)
|
|
399
399
|
if arg.operator == FunctionType.ADD:
|
|
400
|
-
return
|
|
400
|
+
return " + ".join(args)
|
|
401
401
|
if arg.operator == FunctionType.MULTIPLY:
|
|
402
|
-
return
|
|
402
|
+
return " * ".join(args)
|
|
403
403
|
if arg.operator == FunctionType.DIVIDE:
|
|
404
|
-
return
|
|
404
|
+
return " / ".join(args)
|
|
405
405
|
if arg.operator == FunctionType.MOD:
|
|
406
406
|
return f"{args[0]} % {args[1]}"
|
|
407
407
|
|
trilogy/parsing/trilogy.lark
CHANGED
|
@@ -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
|