pytrilogy 0.0.1.117__py3-none-any.whl → 0.0.2.1__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.1.117.dist-info → pytrilogy-0.0.2.1.dist-info}/METADATA +1 -1
- pytrilogy-0.0.2.1.dist-info/RECORD +82 -0
- {pytrilogy-0.0.1.117.dist-info → pytrilogy-0.0.2.1.dist-info}/WHEEL +1 -1
- trilogy/__init__.py +1 -1
- trilogy/constants.py +6 -0
- trilogy/core/enums.py +7 -2
- trilogy/core/env_processor.py +43 -19
- trilogy/core/functions.py +11 -0
- trilogy/core/models.py +737 -146
- trilogy/core/optimization.py +31 -28
- trilogy/core/optimizations/inline_constant.py +4 -1
- trilogy/core/optimizations/inline_datasource.py +25 -4
- trilogy/core/optimizations/predicate_pushdown.py +94 -54
- trilogy/core/processing/concept_strategies_v3.py +69 -39
- trilogy/core/processing/graph_utils.py +3 -3
- trilogy/core/processing/node_generators/__init__.py +0 -2
- trilogy/core/processing/node_generators/basic_node.py +30 -17
- trilogy/core/processing/node_generators/filter_node.py +3 -1
- trilogy/core/processing/node_generators/node_merge_node.py +345 -96
- trilogy/core/processing/node_generators/rowset_node.py +18 -16
- trilogy/core/processing/node_generators/select_node.py +44 -83
- trilogy/core/processing/nodes/__init__.py +2 -0
- trilogy/core/processing/nodes/base_node.py +22 -5
- trilogy/core/processing/nodes/filter_node.py +3 -0
- trilogy/core/processing/nodes/group_node.py +20 -2
- trilogy/core/processing/nodes/merge_node.py +32 -18
- trilogy/core/processing/nodes/select_node_v2.py +17 -3
- trilogy/core/processing/utility.py +100 -8
- trilogy/core/query_processor.py +77 -24
- trilogy/dialect/base.py +11 -46
- trilogy/dialect/bigquery.py +1 -1
- trilogy/dialect/common.py +11 -0
- trilogy/dialect/duckdb.py +1 -1
- trilogy/dialect/presto.py +1 -0
- trilogy/executor.py +29 -0
- trilogy/hooks/graph_hook.py +50 -5
- trilogy/hooks/query_debugger.py +1 -0
- trilogy/parsing/common.py +8 -5
- trilogy/parsing/parse_engine.py +48 -27
- trilogy/parsing/render.py +13 -6
- trilogy/parsing/trilogy.lark +12 -7
- pytrilogy-0.0.1.117.dist-info/RECORD +0 -83
- trilogy/core/processing/node_generators/concept_merge_node.py +0 -214
- {pytrilogy-0.0.1.117.dist-info → pytrilogy-0.0.2.1.dist-info}/LICENSE.md +0 -0
- {pytrilogy-0.0.1.117.dist-info → pytrilogy-0.0.2.1.dist-info}/entry_points.txt +0 -0
- {pytrilogy-0.0.1.117.dist-info → pytrilogy-0.0.2.1.dist-info}/top_level.txt +0 -0
trilogy/parsing/parse_engine.py
CHANGED
|
@@ -32,6 +32,7 @@ from trilogy.core.enums import (
|
|
|
32
32
|
WindowType,
|
|
33
33
|
DatePart,
|
|
34
34
|
ShowCategory,
|
|
35
|
+
SelectFiltering,
|
|
35
36
|
)
|
|
36
37
|
from trilogy.core.exceptions import InvalidSyntaxException, UndefinedConceptException
|
|
37
38
|
from trilogy.core.functions import (
|
|
@@ -68,7 +69,7 @@ from trilogy.core.models import (
|
|
|
68
69
|
ConceptTransform,
|
|
69
70
|
Conditional,
|
|
70
71
|
Datasource,
|
|
71
|
-
|
|
72
|
+
MergeStatementV2,
|
|
72
73
|
Environment,
|
|
73
74
|
FilterItem,
|
|
74
75
|
Function,
|
|
@@ -400,7 +401,7 @@ class ParseToObjects(Transformer):
|
|
|
400
401
|
@v_args(meta=True)
|
|
401
402
|
def concept_property_declaration(self, meta: Meta, args) -> Concept:
|
|
402
403
|
|
|
403
|
-
metadata =
|
|
404
|
+
metadata = Metadata()
|
|
404
405
|
modifiers = []
|
|
405
406
|
for arg in args:
|
|
406
407
|
if isinstance(arg, Metadata):
|
|
@@ -439,7 +440,7 @@ class ParseToObjects(Transformer):
|
|
|
439
440
|
|
|
440
441
|
@v_args(meta=True)
|
|
441
442
|
def concept_declaration(self, meta: Meta, args) -> ConceptDeclarationStatement:
|
|
442
|
-
metadata =
|
|
443
|
+
metadata = Metadata()
|
|
443
444
|
modifiers = []
|
|
444
445
|
for arg in args:
|
|
445
446
|
if isinstance(arg, Metadata):
|
|
@@ -447,9 +448,7 @@ class ParseToObjects(Transformer):
|
|
|
447
448
|
if isinstance(arg, Modifier):
|
|
448
449
|
modifiers.append(arg)
|
|
449
450
|
name = args[1]
|
|
450
|
-
|
|
451
|
-
name, self.environment
|
|
452
|
-
)
|
|
451
|
+
_, namespace, name, _ = parse_concept_reference(name, self.environment)
|
|
453
452
|
concept = Concept(
|
|
454
453
|
name=name,
|
|
455
454
|
datatype=args[2],
|
|
@@ -754,19 +753,21 @@ class ParseToObjects(Transformer):
|
|
|
754
753
|
return [x for x in args]
|
|
755
754
|
|
|
756
755
|
@v_args(meta=True)
|
|
757
|
-
def
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
756
|
+
def merge_statement_v2(self, meta: Meta, args) -> MergeStatementV2:
|
|
757
|
+
modifiers = []
|
|
758
|
+
concepts = []
|
|
759
|
+
for arg in args:
|
|
760
|
+
if isinstance(arg, Modifier):
|
|
761
|
+
modifiers.append(arg)
|
|
762
|
+
else:
|
|
763
|
+
concepts.append(self.environment.concepts[arg])
|
|
764
|
+
new = MergeStatementV2(
|
|
765
|
+
source=concepts[0], target=concepts[1], modifiers=modifiers
|
|
766
|
+
)
|
|
767
|
+
|
|
768
|
+
self.environment.merge_concept(new.source, new.target, modifiers)
|
|
769
|
+
|
|
770
|
+
return new
|
|
770
771
|
|
|
771
772
|
@v_args(meta=True)
|
|
772
773
|
def rawsql_statement(self, meta: Meta, args) -> RawSQLStatement:
|
|
@@ -892,7 +893,7 @@ class ParseToObjects(Transformer):
|
|
|
892
893
|
|
|
893
894
|
@v_args(meta=True)
|
|
894
895
|
def select_statement(self, meta: Meta, args) -> SelectStatement:
|
|
895
|
-
select_items = None
|
|
896
|
+
select_items: List[SelectItem] | None = None
|
|
896
897
|
limit = None
|
|
897
898
|
order_by = None
|
|
898
899
|
where = None
|
|
@@ -919,16 +920,24 @@ class ParseToObjects(Transformer):
|
|
|
919
920
|
# so rebuild at this point in the tree
|
|
920
921
|
# TODO: simplify
|
|
921
922
|
if isinstance(item.content, ConceptTransform):
|
|
922
|
-
new_concept = item.content.output.
|
|
923
|
+
new_concept = item.content.output.with_select_context(
|
|
924
|
+
output.grain,
|
|
925
|
+
conditional=(
|
|
926
|
+
output.where_clause.conditional
|
|
927
|
+
if output.where_clause
|
|
928
|
+
and output.where_clause_category == SelectFiltering.IMPLICIT
|
|
929
|
+
else None
|
|
930
|
+
),
|
|
931
|
+
)
|
|
923
932
|
self.environment.add_concept(new_concept, meta=meta)
|
|
924
933
|
item.content.output = new_concept
|
|
925
934
|
if order_by:
|
|
926
|
-
for
|
|
935
|
+
for orderitem in order_by.items:
|
|
927
936
|
if (
|
|
928
|
-
isinstance(
|
|
929
|
-
and
|
|
937
|
+
isinstance(orderitem.expr, Concept)
|
|
938
|
+
and orderitem.expr.purpose == Purpose.METRIC
|
|
930
939
|
):
|
|
931
|
-
|
|
940
|
+
orderitem.expr = orderitem.expr.with_grain(output.grain)
|
|
932
941
|
return output
|
|
933
942
|
|
|
934
943
|
@v_args(meta=True)
|
|
@@ -1045,8 +1054,20 @@ class ParseToObjects(Transformer):
|
|
|
1045
1054
|
def parenthetical(self, args):
|
|
1046
1055
|
return Parenthetical(content=args[0])
|
|
1047
1056
|
|
|
1057
|
+
def condition_parenthetical(self, args):
|
|
1058
|
+
return Parenthetical(content=args[0])
|
|
1059
|
+
|
|
1048
1060
|
def conditional(self, args):
|
|
1049
|
-
|
|
1061
|
+
def munch_args(args):
|
|
1062
|
+
while args:
|
|
1063
|
+
if len(args) == 1:
|
|
1064
|
+
return args[0]
|
|
1065
|
+
else:
|
|
1066
|
+
return Conditional(
|
|
1067
|
+
left=args[0], operator=args[1], right=munch_args(args[2:])
|
|
1068
|
+
)
|
|
1069
|
+
|
|
1070
|
+
return munch_args(args)
|
|
1050
1071
|
|
|
1051
1072
|
def window_order(self, args):
|
|
1052
1073
|
return WindowOrder(args[0])
|
|
@@ -1723,7 +1744,7 @@ def parse_text(text: str, environment: Optional[Environment] = None) -> Tuple[
|
|
|
1723
1744
|
| None
|
|
1724
1745
|
],
|
|
1725
1746
|
]:
|
|
1726
|
-
environment = environment or Environment(
|
|
1747
|
+
environment = environment or Environment()
|
|
1727
1748
|
parser = ParseToObjects(visit_tokens=True, text=text, environment=environment)
|
|
1728
1749
|
|
|
1729
1750
|
try:
|
trilogy/parsing/render.py
CHANGED
|
@@ -33,13 +33,13 @@ from trilogy.core.models import (
|
|
|
33
33
|
PersistStatement,
|
|
34
34
|
ListWrapper,
|
|
35
35
|
RowsetDerivationStatement,
|
|
36
|
-
MergeStatement,
|
|
37
36
|
MultiSelectStatement,
|
|
38
37
|
OrderBy,
|
|
39
38
|
AlignClause,
|
|
40
39
|
AlignItem,
|
|
41
40
|
RawSQLStatement,
|
|
42
41
|
NumericType,
|
|
42
|
+
MergeStatementV2,
|
|
43
43
|
)
|
|
44
44
|
from trilogy.core.enums import Modifier
|
|
45
45
|
|
|
@@ -142,11 +142,6 @@ class Renderer:
|
|
|
142
142
|
components = ",".join(self.to_string(x) for x in arg.components)
|
|
143
143
|
return f"grain ({components})"
|
|
144
144
|
|
|
145
|
-
@to_string.register
|
|
146
|
-
def _(self, arg: MergeStatement):
|
|
147
|
-
components = ", ".join(self.to_string(x) for x in arg.concepts)
|
|
148
|
-
return f"merge {components};"
|
|
149
|
-
|
|
150
145
|
@to_string.register
|
|
151
146
|
def _(self, arg: "Query"):
|
|
152
147
|
return f"""query {arg.text}"""
|
|
@@ -341,6 +336,18 @@ class Renderer:
|
|
|
341
336
|
return f"{self.to_string(arg.function)} by {self.to_string(arg.by)}"
|
|
342
337
|
return f"{self.to_string(arg.function)}"
|
|
343
338
|
|
|
339
|
+
@to_string.register
|
|
340
|
+
def _(self, arg: MergeStatementV2):
|
|
341
|
+
return f"MERGE {self.to_string(arg.source)} into {''.join([self.to_string(modifier) for modifier in arg.modifiers])}{self.to_string(arg.target)};"
|
|
342
|
+
|
|
343
|
+
@to_string.register
|
|
344
|
+
def _(self, arg: Modifier):
|
|
345
|
+
if arg == Modifier.PARTIAL:
|
|
346
|
+
return "~"
|
|
347
|
+
if arg == Modifier.HIDDEN:
|
|
348
|
+
return "--"
|
|
349
|
+
return arg.value
|
|
350
|
+
|
|
344
351
|
@to_string.register
|
|
345
352
|
def _(self, arg: int):
|
|
346
353
|
return f"{arg}"
|
trilogy/parsing/trilogy.lark
CHANGED
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
| persist_statement
|
|
9
9
|
| rowset_derivation_statement
|
|
10
10
|
| import_statement
|
|
11
|
-
|
|
11
|
+
|
|
12
|
+
| merge_statement_v2
|
|
12
13
|
| rawsql_statement
|
|
13
14
|
|
|
14
15
|
_TERMINATOR: ";"i /\s*/
|
|
@@ -69,8 +70,8 @@
|
|
|
69
70
|
|
|
70
71
|
align_clause: align_item ("AND"i align_item)* "AND"i?
|
|
71
72
|
|
|
72
|
-
//
|
|
73
|
-
|
|
73
|
+
// merge_v2
|
|
74
|
+
merge_statement_v2: "merge"i IDENTIFIER "into"i SHORTHAND_MODIFIER? IDENTIFIER
|
|
74
75
|
|
|
75
76
|
// raw sql statement
|
|
76
77
|
rawsql_statement: "raw_sql"i "(" MULTILINE_STRING ")"
|
|
@@ -125,9 +126,13 @@
|
|
|
125
126
|
|
|
126
127
|
!logical_operator: "and"i | "or"i
|
|
127
128
|
|
|
128
|
-
|
|
129
|
+
condition_parenthetical: "(" conditional ")"
|
|
130
|
+
|
|
131
|
+
_condition_unit: (expr | condition_parenthetical)
|
|
132
|
+
|
|
133
|
+
conditional: _condition_unit (logical_operator _condition_unit)*
|
|
129
134
|
|
|
130
|
-
where: "WHERE"i
|
|
135
|
+
where: "WHERE"i conditional
|
|
131
136
|
|
|
132
137
|
!array_comparison: ( ("NOT"i "IN"i) | "IN"i)
|
|
133
138
|
|
|
@@ -150,7 +155,7 @@
|
|
|
150
155
|
index_access: expr "[" int_lit "]"
|
|
151
156
|
attr_access: expr "[" _string_lit "]"
|
|
152
157
|
|
|
153
|
-
expr: _constant_functions | window_item | filter_item | subselect_comparison | between_comparison | fgroup | aggregate_functions | unnest | _static_functions | literal | concept_lit | index_access | attr_access | parenthetical | expr_tuple | comparison |
|
|
158
|
+
expr: _constant_functions | window_item | filter_item | subselect_comparison | between_comparison | fgroup | aggregate_functions | unnest | _static_functions | literal | concept_lit | index_access | attr_access | parenthetical | expr_tuple | comparison | alt_like
|
|
154
159
|
|
|
155
160
|
// functions
|
|
156
161
|
|
|
@@ -168,7 +173,7 @@
|
|
|
168
173
|
fcast: "cast"i "(" expr "as"i data_type ")"
|
|
169
174
|
concat: ("concat"i "(" (expr ",")* expr ")") | (expr "||" expr)
|
|
170
175
|
fcoalesce: "coalesce"i "(" (expr ",")* expr ")"
|
|
171
|
-
fcase_when: "WHEN"i
|
|
176
|
+
fcase_when: "WHEN"i conditional "THEN"i expr
|
|
172
177
|
fcase_else: "ELSE"i expr
|
|
173
178
|
fcase: "CASE"i (fcase_when)* (fcase_else)? "END"i
|
|
174
179
|
len: "len"i "(" expr ")"
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
trilogy/__init__.py,sha256=1wHuIjygzuHzrQfHKZQ2GJsmw4tMvEXzwEJMg9Lb3Zc,292
|
|
2
|
-
trilogy/compiler.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
-
trilogy/constants.py,sha256=u2dNxhwy0v-6HrvG1GcpDVvuhzdTH5fuyYNCxDPlr2E,770
|
|
4
|
-
trilogy/engine.py,sha256=R5ubIxYyrxRExz07aZCUfrTsoXCHQ8DKFTDsobXdWdA,1102
|
|
5
|
-
trilogy/executor.py,sha256=auuDykCHeqlRWIHOfBfgIIIntEctWaUC-VPJr1DQbYk,10217
|
|
6
|
-
trilogy/parser.py,sha256=UtuqSiGiCjpMAYgo1bvNq-b7NSzCA5hzbUW31RXaMII,281
|
|
7
|
-
trilogy/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
|
-
trilogy/utility.py,sha256=zM__8r29EsyDW7K9VOHz8yvZC2bXFzh7xKy3cL7GKsk,707
|
|
9
|
-
trilogy/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
|
-
trilogy/core/constants.py,sha256=LL8NLvxb3HRnAjvofyLRXqQJijLcYiXAQYQzGarVD-g,128
|
|
11
|
-
trilogy/core/enums.py,sha256=9IzCv0Hzzr3OTJQWzg9yHV_b46Jvk47RNoZjdBi2Its,5678
|
|
12
|
-
trilogy/core/env_processor.py,sha256=SU-jpaGfoWLe9sGTeQYG1qjVnwGQ7TwctmnJRlfzluc,1459
|
|
13
|
-
trilogy/core/environment_helpers.py,sha256=mzBDHhdF9ssZ_-LY8CcaM_ddfJavkpRYrFImUd3cjXI,5972
|
|
14
|
-
trilogy/core/ergonomics.py,sha256=w3gwXdgrxNHCuaRdyKg73t6F36tj-wIjQf47WZkHmJk,1465
|
|
15
|
-
trilogy/core/exceptions.py,sha256=NvV_4qLOgKXbpotgRf7c8BANDEvHxlqRPaA53IThQ2o,561
|
|
16
|
-
trilogy/core/functions.py,sha256=hXp-b29w3vNHQHpTU-VPXJqJaLferNwa681xQ3pf8R0,9129
|
|
17
|
-
trilogy/core/graph_models.py,sha256=oJUMSpmYhqXlavckHLpR07GJxuQ8dZ1VbB1fB0KaS8c,2036
|
|
18
|
-
trilogy/core/internal.py,sha256=jNGFHKENnbMiMCtAgsnLZYVSENDK4b5ALecXFZpTDzQ,1075
|
|
19
|
-
trilogy/core/models.py,sha256=U8gYAvRoob4uj3f-j3N5EwkbBs_tKmcA48IGwmhqrbM,114203
|
|
20
|
-
trilogy/core/optimization.py,sha256=oM3Ry7UpbpTSm2xNkmWx70OHd2V2vWRjM72sZpsZfb8,4116
|
|
21
|
-
trilogy/core/query_processor.py,sha256=clIRJ6IcsqIVBPKFsxt8bqCLsLyajvAu02MUIcKQhTo,15713
|
|
22
|
-
trilogy/core/optimizations/__init__.py,sha256=pxRzNzd2g8oRMy4f_ub5va6bNS2pd4hnyp9JBzTKc1E,300
|
|
23
|
-
trilogy/core/optimizations/base_optimization.py,sha256=tWWT-xnTbnEU-mNi_isMNbywm8B9WTRsNFwGpeh3rqE,468
|
|
24
|
-
trilogy/core/optimizations/inline_constant.py,sha256=neZOFjX7M2pzQ-8m-f8nApy_MfJuowX6SzcGwGFt5w4,927
|
|
25
|
-
trilogy/core/optimizations/inline_datasource.py,sha256=BSp54fwF4RRwInd-09pggemC7JuXj-uqGzi32ufeqYo,2171
|
|
26
|
-
trilogy/core/optimizations/predicate_pushdown.py,sha256=sIojWvoYp6k_ANCyVqxCpEyLY_GLmzsG-Sghj0cbk3k,4135
|
|
27
|
-
trilogy/core/processing/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
28
|
-
trilogy/core/processing/concept_strategies_v3.py,sha256=MYrpNMidqvPOg123RekOcqVTjcj03i_538gBo0MzoWE,23432
|
|
29
|
-
trilogy/core/processing/graph_utils.py,sha256=ulCJ4hYAISbUxLD6VM2fah9RBPGIXSEHEPeRBSFl0Rs,1197
|
|
30
|
-
trilogy/core/processing/utility.py,sha256=acxH5448-j8JXqxMRibyAxjz1Wqu7QudbR0PfMuucww,9902
|
|
31
|
-
trilogy/core/processing/node_generators/__init__.py,sha256=LIs6uBEum8LDc-26zjyAwjxa-ay2ok9tKtPjDNvbVkE,757
|
|
32
|
-
trilogy/core/processing/node_generators/basic_node.py,sha256=HJnIhZLgkUdorKYcofe-QnKSM3Lf_3QO91cbSJhsqf4,2242
|
|
33
|
-
trilogy/core/processing/node_generators/common.py,sha256=liZDth7mvhkF_sUFXK7JitJsiaKD132w3ySLbF7l-nE,8956
|
|
34
|
-
trilogy/core/processing/node_generators/concept_merge_node.py,sha256=x4M8VVZZmBcqHDY1uq7M9KGKCBwjU6mcE_x2BOEk2Mg,7328
|
|
35
|
-
trilogy/core/processing/node_generators/filter_node.py,sha256=y_tqYe2So18vWHASMwVPLzDO-PnyQCO-MAlI4B-rY3Y,4526
|
|
36
|
-
trilogy/core/processing/node_generators/group_node.py,sha256=xWI1xNIXEOj6jlRGD9hcv2_vVNvY6lpzJl6pQ8HuFBE,2988
|
|
37
|
-
trilogy/core/processing/node_generators/group_to_node.py,sha256=BzPdYwzoo8gRMH7BDffTTXq4z-mjfCEzvfB5I-P0_nw,2941
|
|
38
|
-
trilogy/core/processing/node_generators/multiselect_node.py,sha256=vP84dnLQy6dtypi6mUbt9sMAcmmrTgQ1Oz4GI6X1IEo,6421
|
|
39
|
-
trilogy/core/processing/node_generators/node_merge_node.py,sha256=wNDHAbRrKSjsns-EROM_G12mRyOMjbcWpYav2uefXOE,6045
|
|
40
|
-
trilogy/core/processing/node_generators/rowset_node.py,sha256=eNG6rfLifUKraoRGxE8pesQMy5cKT6R5XNIaa3Wuiwk,6081
|
|
41
|
-
trilogy/core/processing/node_generators/select_node.py,sha256=Qb00Kizsv-877UMkGfusl5jXKXMZtZTtLks5pxU07SU,20698
|
|
42
|
-
trilogy/core/processing/node_generators/unnest_node.py,sha256=6CH66eGwpadNX7TzUhWZ8aqIisOtQeHINbLV6X3QBUk,1779
|
|
43
|
-
trilogy/core/processing/node_generators/window_node.py,sha256=9nXUXUgQrNczU1gaOqhOZPNzCUxw-lkxt0R7HORI6ss,2582
|
|
44
|
-
trilogy/core/processing/nodes/__init__.py,sha256=baODkJfvUoWEEbu843GEd7snubwLeOG5FQ8l-CwIaC8,3928
|
|
45
|
-
trilogy/core/processing/nodes/base_node.py,sha256=yhjmsAUmhHDqgbQjz_9YdfP-M5pj4xbrPRDF6Y4XVuw,10498
|
|
46
|
-
trilogy/core/processing/nodes/filter_node.py,sha256=rDw4vfE6tqWxuKT0arihVmIOoOWDDCyzRA-2yONX_Ek,1860
|
|
47
|
-
trilogy/core/processing/nodes/group_node.py,sha256=vzeU9J4xMhRrPj4-KPJTgNbH-KFu2ZS8b57SOynsdw0,4448
|
|
48
|
-
trilogy/core/processing/nodes/merge_node.py,sha256=FvSiTWKOzaUsXBkf6wJD8QQqQxp_aphS_I5VzNRw8Yo,13600
|
|
49
|
-
trilogy/core/processing/nodes/select_node_v2.py,sha256=ERCflBFzKpD5SzweMevnJLyQnxmF_-IQ6VRu5yVeiBg,6552
|
|
50
|
-
trilogy/core/processing/nodes/unnest_node.py,sha256=JFtm90IVM-46aCYkTNIaJah6v9ApAfonjVhcVM1HmDE,1903
|
|
51
|
-
trilogy/core/processing/nodes/window_node.py,sha256=X7qxLUKd3tekjUUsmH_4vz5b-U89gMnGd04VBxuu2Ns,1280
|
|
52
|
-
trilogy/dialect/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
53
|
-
trilogy/dialect/base.py,sha256=ycsxbUL68DsodOsHEgEoNLKMn5vgRN3sDIRfiH9fQDs,31719
|
|
54
|
-
trilogy/dialect/bigquery.py,sha256=9vxQn2BMv_oTGQSWQpoN5ho_OgqMWaHH9e-5vQVf44c,2906
|
|
55
|
-
trilogy/dialect/common.py,sha256=zWrYmvevlXznocw9uGHmY5Ws1rp_kICm9zA_ulTe4eg,2165
|
|
56
|
-
trilogy/dialect/config.py,sha256=tLVEMctaTDhUgARKXUNfHUcIolGaALkQ0RavUvXAY4w,2994
|
|
57
|
-
trilogy/dialect/duckdb.py,sha256=Ddyt68sr8IL2HnZMenyytoD65FXwY_O2pz1McyS0bis,3075
|
|
58
|
-
trilogy/dialect/enums.py,sha256=4NdpsydBpDn6jnh0JzFz5VvQEtnShErWtWHVyT6TNpw,3948
|
|
59
|
-
trilogy/dialect/postgres.py,sha256=r47xbCA7nfEYENofiVfLZ-SnReNfDmUmW4OSHVkkP4E,3206
|
|
60
|
-
trilogy/dialect/presto.py,sha256=UxBodRiV3szpFcQlcjoJaGXEwAhZJf_OT7dHczYvO80,3092
|
|
61
|
-
trilogy/dialect/snowflake.py,sha256=N3HknYgN-fjD7BLX1Ucj-ss_ku2Ox8DgLsF3BIHutHo,2941
|
|
62
|
-
trilogy/dialect/sql_server.py,sha256=HX68vNTrcDaTnOxe6Zbx_PBgrO42e2VuThxO6CYQ2cY,3026
|
|
63
|
-
trilogy/hooks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
64
|
-
trilogy/hooks/base_hook.py,sha256=Xkb-A2qCHozYjum0A36zOy5PwTVwrP3NLDF0U2GpgHo,1100
|
|
65
|
-
trilogy/hooks/graph_hook.py,sha256=i-Tv9sxZU0sMc-God8bLLz-nAg4-wYafogZtHaU8LXw,801
|
|
66
|
-
trilogy/hooks/query_debugger.py,sha256=D2VJUcyvQrVJ8sT6FCMKR3NKTfVrgZQ7gly91avHHpw,4222
|
|
67
|
-
trilogy/metadata/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
68
|
-
trilogy/parsing/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
69
|
-
trilogy/parsing/common.py,sha256=iR3fiiZ7w8VJuUGrQ0v06XGDXov81f4z1ZlFnj6y40E,5804
|
|
70
|
-
trilogy/parsing/config.py,sha256=Z-DaefdKhPDmSXLgg5V4pebhSB0h590vI0_VtHnlukI,111
|
|
71
|
-
trilogy/parsing/exceptions.py,sha256=92E5i2frv5hj9wxObJZsZqj5T6bglvPzvdvco_vW1Zk,38
|
|
72
|
-
trilogy/parsing/helpers.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
73
|
-
trilogy/parsing/parse_engine.py,sha256=F1ok96qT6EhKRKV1Q_YzfHxMFtNV8qAXopK8NaePgU4,57080
|
|
74
|
-
trilogy/parsing/render.py,sha256=TnLf5fg4wimpd9EvhLU-FMDwpyW9pesoedBZ0RrmWD4,11810
|
|
75
|
-
trilogy/parsing/trilogy.lark,sha256=1AZbQGpNmpm4KamAXA5IWcuOr2B8Gb8kUJcAOmKf_zY,10862
|
|
76
|
-
trilogy/scripts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
77
|
-
trilogy/scripts/trilogy.py,sha256=PHxvv6f2ODv0esyyhWxlARgra8dVhqQhYl0lTrSyVNo,3729
|
|
78
|
-
pytrilogy-0.0.1.117.dist-info/LICENSE.md,sha256=5ZRvtTyCCFwz1THxDTjAu3Lidds9WjPvvzgVwPSYNDo,1042
|
|
79
|
-
pytrilogy-0.0.1.117.dist-info/METADATA,sha256=jrHvRWl_dtmpVu_aw08SS-whIymZ6l051tcpYmPQPD0,7878
|
|
80
|
-
pytrilogy-0.0.1.117.dist-info/WHEEL,sha256=R0nc6qTxuoLk7ShA2_Y-UWkN8ZdfDBG2B6Eqpz2WXbs,91
|
|
81
|
-
pytrilogy-0.0.1.117.dist-info/entry_points.txt,sha256=0petKryjvvtEfTlbZC1AuMFumH_WQ9v8A19LvoS6G6c,54
|
|
82
|
-
pytrilogy-0.0.1.117.dist-info/top_level.txt,sha256=cAy__NW_eMAa_yT9UnUNlZLFfxcg6eimUAZ184cdNiE,8
|
|
83
|
-
pytrilogy-0.0.1.117.dist-info/RECORD,,
|
|
@@ -1,214 +0,0 @@
|
|
|
1
|
-
from trilogy.core.models import (
|
|
2
|
-
Concept,
|
|
3
|
-
Environment,
|
|
4
|
-
MergeStatement,
|
|
5
|
-
)
|
|
6
|
-
from trilogy.core.processing.nodes import MergeNode, NodeJoin, History
|
|
7
|
-
from trilogy.core.processing.nodes.base_node import concept_list_to_grain, StrategyNode
|
|
8
|
-
from typing import List
|
|
9
|
-
|
|
10
|
-
from trilogy.core.enums import JoinType, PurposeLineage
|
|
11
|
-
from trilogy.constants import logger
|
|
12
|
-
from trilogy.core.processing.utility import padding
|
|
13
|
-
from trilogy.core.processing.node_generators.common import concept_to_relevant_joins
|
|
14
|
-
from itertools import combinations
|
|
15
|
-
from trilogy.core.processing.node_generators.common import resolve_join_order
|
|
16
|
-
from trilogy.utility import unique
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
LOGGER_PREFIX = "[GEN_CONCEPT_MERGE_NODE]"
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
def merge_joins(
|
|
23
|
-
parents: List[StrategyNode], merge_concepts: List[Concept]
|
|
24
|
-
) -> List[NodeJoin]:
|
|
25
|
-
output = []
|
|
26
|
-
for left, right in combinations(parents, 2):
|
|
27
|
-
output.append(
|
|
28
|
-
NodeJoin(
|
|
29
|
-
left_node=left,
|
|
30
|
-
right_node=right,
|
|
31
|
-
concepts=merge_concepts,
|
|
32
|
-
join_type=JoinType.FULL,
|
|
33
|
-
filter_to_mutual=True,
|
|
34
|
-
)
|
|
35
|
-
)
|
|
36
|
-
return resolve_join_order(output)
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
def gen_concept_merge_node(
|
|
40
|
-
concept: Concept,
|
|
41
|
-
local_optional: List[Concept],
|
|
42
|
-
environment: Environment,
|
|
43
|
-
g,
|
|
44
|
-
depth: int,
|
|
45
|
-
source_concepts,
|
|
46
|
-
history: History | None = None,
|
|
47
|
-
) -> MergeNode | None:
|
|
48
|
-
if not isinstance(concept.lineage, MergeStatement):
|
|
49
|
-
logger.info(
|
|
50
|
-
f"{padding(depth)}{LOGGER_PREFIX} Cannot generate merge node for {concept}"
|
|
51
|
-
)
|
|
52
|
-
return None
|
|
53
|
-
lineage: MergeStatement = concept.lineage
|
|
54
|
-
|
|
55
|
-
base_parents: List[StrategyNode] = []
|
|
56
|
-
|
|
57
|
-
# get additional concepts that should be merged across the environments
|
|
58
|
-
additional_merge: List[Concept] = [*lineage.concepts]
|
|
59
|
-
target_namespaces = set(x.namespace for x in [concept] + local_optional)
|
|
60
|
-
for x in local_optional:
|
|
61
|
-
if x.address in environment.merged_concepts:
|
|
62
|
-
ms = environment.merged_concepts[x.address].lineage
|
|
63
|
-
assert isinstance(ms, MergeStatement)
|
|
64
|
-
additional_merge += ms.concepts
|
|
65
|
-
|
|
66
|
-
for select in lineage.concepts:
|
|
67
|
-
# if it's a merge concept, filter it out of the optional
|
|
68
|
-
if select.namespace not in target_namespaces:
|
|
69
|
-
continue
|
|
70
|
-
sub_optional = [
|
|
71
|
-
x
|
|
72
|
-
for x in local_optional
|
|
73
|
-
if x.address not in environment.merged_concepts
|
|
74
|
-
and x.namespace == select.namespace
|
|
75
|
-
]
|
|
76
|
-
|
|
77
|
-
sub_additional_merge = [
|
|
78
|
-
x for x in additional_merge if x.namespace == select.namespace
|
|
79
|
-
]
|
|
80
|
-
sub_optional += sub_additional_merge
|
|
81
|
-
final: List[Concept] = unique([select] + sub_optional, "address")
|
|
82
|
-
logger.info(
|
|
83
|
-
f"{padding(depth)}{LOGGER_PREFIX} generating concept merge parent node with {[x.address for x in final]}"
|
|
84
|
-
)
|
|
85
|
-
snode: StrategyNode = source_concepts(
|
|
86
|
-
mandatory_list=final,
|
|
87
|
-
environment=environment,
|
|
88
|
-
g=g,
|
|
89
|
-
depth=depth + 1,
|
|
90
|
-
history=history,
|
|
91
|
-
)
|
|
92
|
-
|
|
93
|
-
if not snode:
|
|
94
|
-
logger.info(
|
|
95
|
-
f"{padding(depth)}{LOGGER_PREFIX} Cannot generate merge node for {concept}"
|
|
96
|
-
)
|
|
97
|
-
return None
|
|
98
|
-
for x in sub_additional_merge:
|
|
99
|
-
snode.add_output_concept(environment.merged_concepts[x.address])
|
|
100
|
-
base_parents.append(snode)
|
|
101
|
-
|
|
102
|
-
node_joins = merge_joins(
|
|
103
|
-
base_parents,
|
|
104
|
-
unique(
|
|
105
|
-
[environment.merged_concepts[x.address] for x in additional_merge],
|
|
106
|
-
"address",
|
|
107
|
-
),
|
|
108
|
-
)
|
|
109
|
-
|
|
110
|
-
enrichment = set([x.address for x in local_optional])
|
|
111
|
-
outputs = [
|
|
112
|
-
x
|
|
113
|
-
for y in base_parents
|
|
114
|
-
for x in y.output_concepts
|
|
115
|
-
if x.derivation != PurposeLineage.MERGE
|
|
116
|
-
]
|
|
117
|
-
|
|
118
|
-
additional_relevant = [x for x in outputs if x.address in enrichment]
|
|
119
|
-
final_outputs = outputs + additional_relevant + [concept]
|
|
120
|
-
virtual_outputs = [x for x in final_outputs if x.derivation == PurposeLineage.MERGE]
|
|
121
|
-
node = MergeNode(
|
|
122
|
-
input_concepts=[x for y in base_parents for x in y.output_concepts],
|
|
123
|
-
output_concepts=[
|
|
124
|
-
x for x in final_outputs if x.derivation != PurposeLineage.MERGE
|
|
125
|
-
],
|
|
126
|
-
environment=environment,
|
|
127
|
-
g=g,
|
|
128
|
-
depth=depth,
|
|
129
|
-
parents=base_parents,
|
|
130
|
-
node_joins=node_joins,
|
|
131
|
-
virtual_output_concepts=virtual_outputs,
|
|
132
|
-
)
|
|
133
|
-
|
|
134
|
-
qds = node.rebuild_cache()
|
|
135
|
-
|
|
136
|
-
# assume grain to be outoput of select
|
|
137
|
-
# but don't include anything aggregate at this point
|
|
138
|
-
qds.grain = concept_list_to_grain(
|
|
139
|
-
node.output_concepts, parent_sources=qds.datasources
|
|
140
|
-
)
|
|
141
|
-
possible_joins = concept_to_relevant_joins(additional_relevant)
|
|
142
|
-
if not local_optional:
|
|
143
|
-
logger.info(
|
|
144
|
-
f"{padding(depth)}{LOGGER_PREFIX} no enriched required for merge concept node; exiting early"
|
|
145
|
-
)
|
|
146
|
-
return node
|
|
147
|
-
if not possible_joins:
|
|
148
|
-
logger.info(
|
|
149
|
-
f"{padding(depth)}{LOGGER_PREFIX} no possible joins for merge concept node; exiting early"
|
|
150
|
-
)
|
|
151
|
-
return node
|
|
152
|
-
if all(
|
|
153
|
-
[x.address in [y.address for y in node.output_concepts] for x in local_optional]
|
|
154
|
-
):
|
|
155
|
-
logger.info(
|
|
156
|
-
f"{padding(depth)}{LOGGER_PREFIX} all enriched concepts returned from base merge concept node; exiting early"
|
|
157
|
-
)
|
|
158
|
-
return node
|
|
159
|
-
missing = [
|
|
160
|
-
x
|
|
161
|
-
for x in local_optional
|
|
162
|
-
if x.address not in [y.address for y in node.output_concepts]
|
|
163
|
-
]
|
|
164
|
-
logger.info(
|
|
165
|
-
f"{padding(depth)}{LOGGER_PREFIX} generating merge concept enrichment node for missing {[x.address for x in missing]}"
|
|
166
|
-
)
|
|
167
|
-
enrich_node: MergeNode = source_concepts( # this fetches the parent + join keys
|
|
168
|
-
# to then connect to the rest of the query
|
|
169
|
-
mandatory_list=additional_relevant + missing,
|
|
170
|
-
environment=environment,
|
|
171
|
-
g=g,
|
|
172
|
-
depth=depth + 1,
|
|
173
|
-
history=history,
|
|
174
|
-
)
|
|
175
|
-
if not enrich_node:
|
|
176
|
-
logger.info(
|
|
177
|
-
f"{padding(depth)}{LOGGER_PREFIX} Cannot generate merge concept enrichment node for {concept.address} with optional {[x.address for x in local_optional]}, returning just merge concept"
|
|
178
|
-
)
|
|
179
|
-
return node
|
|
180
|
-
|
|
181
|
-
# we still need the hidden concepts to be returned to the search
|
|
182
|
-
# since they must be on the final node
|
|
183
|
-
# to avoid further recursion
|
|
184
|
-
# TODO: let the downstream search know they were found
|
|
185
|
-
return MergeNode(
|
|
186
|
-
input_concepts=enrich_node.output_concepts + node.output_concepts,
|
|
187
|
-
# also filter out the
|
|
188
|
-
output_concepts=[
|
|
189
|
-
x
|
|
190
|
-
for x in node.output_concepts + local_optional
|
|
191
|
-
if x.derivation != PurposeLineage.MERGE
|
|
192
|
-
],
|
|
193
|
-
hidden_concepts=[],
|
|
194
|
-
environment=environment,
|
|
195
|
-
g=g,
|
|
196
|
-
depth=depth,
|
|
197
|
-
parents=[
|
|
198
|
-
# this node gets the window
|
|
199
|
-
node,
|
|
200
|
-
# this node gets enrichment
|
|
201
|
-
enrich_node,
|
|
202
|
-
],
|
|
203
|
-
node_joins=[
|
|
204
|
-
NodeJoin(
|
|
205
|
-
left_node=enrich_node,
|
|
206
|
-
right_node=node,
|
|
207
|
-
concepts=possible_joins,
|
|
208
|
-
filter_to_mutual=False,
|
|
209
|
-
join_type=JoinType.LEFT_OUTER,
|
|
210
|
-
)
|
|
211
|
-
],
|
|
212
|
-
partial_concepts=node.partial_concepts,
|
|
213
|
-
virtual_output_concepts=virtual_outputs,
|
|
214
|
-
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|