pytrilogy 0.0.2.48__py3-none-any.whl → 0.0.2.49__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.48.dist-info → pytrilogy-0.0.2.49.dist-info}/METADATA +1 -1
- {pytrilogy-0.0.2.48.dist-info → pytrilogy-0.0.2.49.dist-info}/RECORD +17 -17
- trilogy/__init__.py +1 -1
- trilogy/core/models.py +18 -14
- trilogy/core/processing/concept_strategies_v3.py +3 -0
- trilogy/core/processing/node_generators/rowset_node.py +27 -7
- trilogy/core/processing/nodes/base_node.py +28 -0
- trilogy/core/processing/nodes/group_node.py +9 -3
- trilogy/core/processing/nodes/merge_node.py +3 -1
- trilogy/core/processing/nodes/select_node_v2.py +5 -0
- trilogy/core/processing/utility.py +1 -1
- trilogy/core/query_processor.py +3 -7
- trilogy/parsing/parse_engine.py +1 -0
- {pytrilogy-0.0.2.48.dist-info → pytrilogy-0.0.2.49.dist-info}/LICENSE.md +0 -0
- {pytrilogy-0.0.2.48.dist-info → pytrilogy-0.0.2.49.dist-info}/WHEEL +0 -0
- {pytrilogy-0.0.2.48.dist-info → pytrilogy-0.0.2.49.dist-info}/entry_points.txt +0 -0
- {pytrilogy-0.0.2.48.dist-info → pytrilogy-0.0.2.49.dist-info}/top_level.txt +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
trilogy/__init__.py,sha256=
|
|
1
|
+
trilogy/__init__.py,sha256=hG5X0wOuxbm75ZaOS3dSSefwEZ4P5yCHSSmZ1x9LX4I,291
|
|
2
2
|
trilogy/compiler.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
3
|
trilogy/constants.py,sha256=qZ1d0hoKPPV2HHCoFwPYTVB7b6bXjpWvXd3lE-zEhy8,1494
|
|
4
4
|
trilogy/engine.py,sha256=yOPnR7XCjWG82Gym_LLZBkYKKJdLCvqdCyt8zguNcnM,1103
|
|
@@ -16,18 +16,18 @@ trilogy/core/exceptions.py,sha256=1c1lQCwSw4_5CQS3q7scOkXU8GQvullJXfPHubprl90,61
|
|
|
16
16
|
trilogy/core/functions.py,sha256=qpVLwTNU_qHQyIvNish5O2AlbpRMQQOqZWEUiSMnpqE,10721
|
|
17
17
|
trilogy/core/graph_models.py,sha256=mameUTiuCajtihDw_2-W218xyJlvTusOWrEKP1yAWgk,2003
|
|
18
18
|
trilogy/core/internal.py,sha256=-CykZknaWieFh5begaQJ4EgGP9qJccGg4XXdmBirxEc,1074
|
|
19
|
-
trilogy/core/models.py,sha256=
|
|
19
|
+
trilogy/core/models.py,sha256=GLy30_Rhvb9Z1atXPlK-sOSeN4lBzBspyMiqti5wS50,166562
|
|
20
20
|
trilogy/core/optimization.py,sha256=Jy3tVJNeqhpK6VSyTvgIWKCao6y-VCZ7mYA69MIF6L0,7989
|
|
21
|
-
trilogy/core/query_processor.py,sha256=
|
|
21
|
+
trilogy/core/query_processor.py,sha256=keXQMpvM-S4rYU1YhzRAkvB1bVlbcX4CKNFafhVRgiI,18635
|
|
22
22
|
trilogy/core/optimizations/__init__.py,sha256=EBanqTXEzf1ZEYjAneIWoIcxtMDite5-n2dQ5xcfUtg,356
|
|
23
23
|
trilogy/core/optimizations/base_optimization.py,sha256=P4kF-eCXkBxO-5c6tLHhMZ4ODRH1A04hb_6ovkaVyLw,505
|
|
24
24
|
trilogy/core/optimizations/inline_constant.py,sha256=c-YHOg6eAufL4EaCf4-0PbY_D4skBHW0ldR55_phsMA,1277
|
|
25
25
|
trilogy/core/optimizations/inline_datasource.py,sha256=LsngRKBy-LYcx1sfo1-rnDym_ly73YV9WkEngSjpFx8,3943
|
|
26
26
|
trilogy/core/optimizations/predicate_pushdown.py,sha256=XPWEBv8jXnc0OL2JDPNwFvJ5AtOE7dLzJK0LzdmdZMo,9252
|
|
27
27
|
trilogy/core/processing/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
28
|
-
trilogy/core/processing/concept_strategies_v3.py,sha256=
|
|
28
|
+
trilogy/core/processing/concept_strategies_v3.py,sha256=0xN1AMBGPKfl2Bbl0zIIGJYcmaNl9PFl2ESzBniVO24,37104
|
|
29
29
|
trilogy/core/processing/graph_utils.py,sha256=stbYnDxnK-1kbo9L4XNU85FQhWCP-oZYO7LCXhAdC5M,1198
|
|
30
|
-
trilogy/core/processing/utility.py,sha256=
|
|
30
|
+
trilogy/core/processing/utility.py,sha256=RG0v0hCgyWsxRHzDx2-ME0ENp1LlahLk4zB--Hfrsbc,18717
|
|
31
31
|
trilogy/core/processing/node_generators/__init__.py,sha256=s_YV1OYc336DuS9591259qjI_K_CtOCuhkf4t2aOgYs,733
|
|
32
32
|
trilogy/core/processing/node_generators/basic_node.py,sha256=VqVyb4wXI_B2OmfwtpsypimzcevoPe_pnstlKLU3S5s,2878
|
|
33
33
|
trilogy/core/processing/node_generators/common.py,sha256=kETikLR2fWbrKywPL0TXXj6YY4rpOA8PjsUSyx_mNyE,8907
|
|
@@ -36,18 +36,18 @@ trilogy/core/processing/node_generators/group_node.py,sha256=wlj8N4Nd1_8cpmccoe0
|
|
|
36
36
|
trilogy/core/processing/node_generators/group_to_node.py,sha256=RNvDo0x1TNFCDi97IAZ4taLMEe9Wv0XzNtuCCM9vjvw,2537
|
|
37
37
|
trilogy/core/processing/node_generators/multiselect_node.py,sha256=abS8mWWoTxRXYdjKTgRgdfeLiWcJjZ7qgESYwDv5e_o,6510
|
|
38
38
|
trilogy/core/processing/node_generators/node_merge_node.py,sha256=IYDS5DNF-5_dpgwre_n1Kh7RBnt4srzgYkaUahe_K_o,14001
|
|
39
|
-
trilogy/core/processing/node_generators/rowset_node.py,sha256=
|
|
39
|
+
trilogy/core/processing/node_generators/rowset_node.py,sha256=kM4N8n20U0zGeHgQBfyXC7PP-ABIdWUHc1q1vnWkfOw,5297
|
|
40
40
|
trilogy/core/processing/node_generators/select_merge_node.py,sha256=JFoBKETwhmd2KdmoNq4wT2SOrd3Jh-GGcO5qMiUh8JE,12691
|
|
41
41
|
trilogy/core/processing/node_generators/select_node.py,sha256=bjTylBa-vYbmzpuSpphmIo_Oi78YZpI8ppHnN9KDYDk,1795
|
|
42
42
|
trilogy/core/processing/node_generators/union_node.py,sha256=MVmLqOZbCEVqZYVZxxWxtDMvyEdSnAg7pU9NzoOXy1I,2517
|
|
43
43
|
trilogy/core/processing/node_generators/unnest_node.py,sha256=MNNjWW7Dp3A_Xv_XGjzdHU1PHQBauZHMBVKRJhqRZJY,2255
|
|
44
44
|
trilogy/core/processing/node_generators/window_node.py,sha256=x4n5NWEouMsOS0V9myyJNmEg2e3kUDPLWXQhq3PyUdY,3510
|
|
45
45
|
trilogy/core/processing/nodes/__init__.py,sha256=WNUmYmZF3uqF2qiJ1L7y0u9qiVD9YnluKds0wA5opJE,4813
|
|
46
|
-
trilogy/core/processing/nodes/base_node.py,sha256=
|
|
46
|
+
trilogy/core/processing/nodes/base_node.py,sha256=t0SQW6z3OdAMDfyuUUtI8NCbDruJLq2-FgZxPuWZS0Q,16567
|
|
47
47
|
trilogy/core/processing/nodes/filter_node.py,sha256=metDcI7b2QsONOy5l0Mx7by1OhXac0N8yKUDoL_2WWo,2342
|
|
48
|
-
trilogy/core/processing/nodes/group_node.py,sha256=
|
|
49
|
-
trilogy/core/processing/nodes/merge_node.py,sha256=
|
|
50
|
-
trilogy/core/processing/nodes/select_node_v2.py,sha256=
|
|
48
|
+
trilogy/core/processing/nodes/group_node.py,sha256=NdIrmBg7DjFy8KwvRoI653cOyAi1xChcWdXZS8tqMW0,7488
|
|
49
|
+
trilogy/core/processing/nodes/merge_node.py,sha256=7lhmTyWLV5e9zT_m_UJnUgXVGBEoyX98lcUABstcf3w,14916
|
|
50
|
+
trilogy/core/processing/nodes/select_node_v2.py,sha256=Xx2zT1RLFJCMmRQ0GaZnrrgRo33aI53Lgw3PqHRSCp4,8284
|
|
51
51
|
trilogy/core/processing/nodes/union_node.py,sha256=WHycDepNr16flkgQdwyZRo1g-kzYKWVUb6CZ7N_U4OA,1402
|
|
52
52
|
trilogy/core/processing/nodes/unnest_node.py,sha256=aR1XKa-bT7f45QYKUOS0EUuc0t4GbvYAEG8ZYFJ67sI,2151
|
|
53
53
|
trilogy/core/processing/nodes/window_node.py,sha256=kXHhOZ9CZ8AQvUbJXCIxUPQ-NF3ooZT7VBgNUyM3VM8,1213
|
|
@@ -72,14 +72,14 @@ trilogy/parsing/common.py,sha256=haPZbJrola5Fvwp940A-MJ1o-EhGXKsRFa-Y2e7OsjU,103
|
|
|
72
72
|
trilogy/parsing/config.py,sha256=Z-DaefdKhPDmSXLgg5V4pebhSB0h590vI0_VtHnlukI,111
|
|
73
73
|
trilogy/parsing/exceptions.py,sha256=92E5i2frv5hj9wxObJZsZqj5T6bglvPzvdvco_vW1Zk,38
|
|
74
74
|
trilogy/parsing/helpers.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
75
|
-
trilogy/parsing/parse_engine.py,sha256=
|
|
75
|
+
trilogy/parsing/parse_engine.py,sha256=CrXaK3KDsMt7C6qYIGy5lH4p3-dQNqRn-34VbI8XRRw,67200
|
|
76
76
|
trilogy/parsing/render.py,sha256=Dr0QKIaAUi9uxfZZJVNV-todKoTA-tsWXNXPJ4Ohjn0,15650
|
|
77
77
|
trilogy/parsing/trilogy.lark,sha256=d_d3H8ExBcrVffPLq1TgTcEyWDppPJO2zB6cC6mdq9I,12489
|
|
78
78
|
trilogy/scripts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
79
79
|
trilogy/scripts/trilogy.py,sha256=DQDW81E5mDMWFP8oPw8q-IyrR2JGxQSDWgUWe2VTSRQ,3731
|
|
80
|
-
pytrilogy-0.0.2.
|
|
81
|
-
pytrilogy-0.0.2.
|
|
82
|
-
pytrilogy-0.0.2.
|
|
83
|
-
pytrilogy-0.0.2.
|
|
84
|
-
pytrilogy-0.0.2.
|
|
85
|
-
pytrilogy-0.0.2.
|
|
80
|
+
pytrilogy-0.0.2.49.dist-info/LICENSE.md,sha256=5ZRvtTyCCFwz1THxDTjAu3Lidds9WjPvvzgVwPSYNDo,1042
|
|
81
|
+
pytrilogy-0.0.2.49.dist-info/METADATA,sha256=dI1KF17Tz1MjU5LMQwL9wLiQwzI3pUNc469_XthJuTQ,8426
|
|
82
|
+
pytrilogy-0.0.2.49.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
|
|
83
|
+
pytrilogy-0.0.2.49.dist-info/entry_points.txt,sha256=0petKryjvvtEfTlbZC1AuMFumH_WQ9v8A19LvoS6G6c,54
|
|
84
|
+
pytrilogy-0.0.2.49.dist-info/top_level.txt,sha256=cAy__NW_eMAa_yT9UnUNlZLFfxcg6eimUAZ184cdNiE,8
|
|
85
|
+
pytrilogy-0.0.2.49.dist-info/RECORD,,
|
trilogy/__init__.py
CHANGED
trilogy/core/models.py
CHANGED
|
@@ -467,7 +467,7 @@ class Concept(Mergeable, Namespaced, SelectContext, BaseModel):
|
|
|
467
467
|
)
|
|
468
468
|
|
|
469
469
|
def __repr__(self):
|
|
470
|
-
base = f"{self.
|
|
470
|
+
base = f"{self.address}@{self.grain}"
|
|
471
471
|
return base
|
|
472
472
|
|
|
473
473
|
@property
|
|
@@ -662,11 +662,24 @@ class Concept(Mergeable, Namespaced, SelectContext, BaseModel):
|
|
|
662
662
|
local_concepts=local_concepts, grain=grain, environment=environment
|
|
663
663
|
)
|
|
664
664
|
final_grain = self.grain
|
|
665
|
-
|
|
665
|
+
keys = (
|
|
666
|
+
tuple(
|
|
667
|
+
[
|
|
668
|
+
x.with_select_context(local_concepts, grain, environment)
|
|
669
|
+
for x in self.keys
|
|
670
|
+
]
|
|
671
|
+
)
|
|
672
|
+
if self.keys
|
|
673
|
+
else None
|
|
674
|
+
)
|
|
666
675
|
if self.is_aggregate and isinstance(new_lineage, Function):
|
|
667
676
|
new_lineage = AggregateWrapper(function=new_lineage, by=grain.components)
|
|
668
677
|
final_grain = grain
|
|
669
|
-
|
|
678
|
+
keys = tuple(grain.components)
|
|
679
|
+
elif (
|
|
680
|
+
self.is_aggregate and not keys and isinstance(new_lineage, AggregateWrapper)
|
|
681
|
+
):
|
|
682
|
+
keys = tuple(new_lineage.by)
|
|
670
683
|
return self.__class__(
|
|
671
684
|
name=self.name,
|
|
672
685
|
datatype=self.datatype,
|
|
@@ -675,16 +688,7 @@ class Concept(Mergeable, Namespaced, SelectContext, BaseModel):
|
|
|
675
688
|
lineage=new_lineage,
|
|
676
689
|
grain=final_grain,
|
|
677
690
|
namespace=self.namespace,
|
|
678
|
-
keys=
|
|
679
|
-
tuple(
|
|
680
|
-
[
|
|
681
|
-
x.with_select_context(local_concepts, grain, environment)
|
|
682
|
-
for x in self.keys
|
|
683
|
-
]
|
|
684
|
-
)
|
|
685
|
-
if self.keys
|
|
686
|
-
else None
|
|
687
|
-
),
|
|
691
|
+
keys=keys,
|
|
688
692
|
modifiers=self.modifiers,
|
|
689
693
|
# a select needs to always defer to the environment for pseudonyms
|
|
690
694
|
# TODO: evaluate if this should be cached
|
|
@@ -2626,7 +2630,7 @@ class QueryDatasource(BaseModel):
|
|
|
2626
2630
|
and CONFIG.validate_missing
|
|
2627
2631
|
):
|
|
2628
2632
|
raise SyntaxError(
|
|
2629
|
-
f"
|
|
2633
|
+
f"On query datasource missing source map for {concept.address} on {key}, have {v}"
|
|
2630
2634
|
)
|
|
2631
2635
|
return v
|
|
2632
2636
|
|
|
@@ -569,6 +569,8 @@ def validate_stack(
|
|
|
569
569
|
resolved = node.resolve()
|
|
570
570
|
|
|
571
571
|
for concept in resolved.output_concepts:
|
|
572
|
+
if concept in resolved.hidden_concepts:
|
|
573
|
+
continue
|
|
572
574
|
validate_concept(
|
|
573
575
|
concept,
|
|
574
576
|
node,
|
|
@@ -836,6 +838,7 @@ def _search_concepts(
|
|
|
836
838
|
PurposeLineage.ROWSET,
|
|
837
839
|
PurposeLineage.BASIC,
|
|
838
840
|
PurposeLineage.MULTISELECT,
|
|
841
|
+
PurposeLineage.UNION,
|
|
839
842
|
]:
|
|
840
843
|
skip.add(priority_concept.address)
|
|
841
844
|
break
|
|
@@ -38,7 +38,7 @@ def gen_rowset_node(
|
|
|
38
38
|
rowset: RowsetDerivationStatement = lineage.rowset
|
|
39
39
|
select: SelectStatement | MultiSelectStatement = lineage.rowset.select
|
|
40
40
|
|
|
41
|
-
node = get_query_node(environment, select
|
|
41
|
+
node = get_query_node(environment, select)
|
|
42
42
|
|
|
43
43
|
if not node:
|
|
44
44
|
logger.info(
|
|
@@ -94,15 +94,22 @@ def gen_rowset_node(
|
|
|
94
94
|
logger.info(
|
|
95
95
|
f"{padding(depth)}{LOGGER_PREFIX} no enrichment required for rowset node as all optional found or no optional; exiting early."
|
|
96
96
|
)
|
|
97
|
-
# node.set_preexisting_conditions(conditions.conditional if conditions else None)
|
|
98
97
|
return node
|
|
99
|
-
|
|
100
|
-
|
|
98
|
+
possible_joins = concept_to_relevant_joins(
|
|
99
|
+
[x for x in node.output_concepts if x.derivation != PurposeLineage.ROWSET]
|
|
100
|
+
)
|
|
101
|
+
logger.info({x.address: x.keys for x in possible_joins})
|
|
101
102
|
if not possible_joins:
|
|
102
103
|
logger.info(
|
|
103
104
|
f"{padding(depth)}{LOGGER_PREFIX} no possible joins for rowset node to get {[x.address for x in local_optional]}; have {[x.address for x in node.output_concepts]}"
|
|
104
105
|
)
|
|
105
106
|
return node
|
|
107
|
+
if any(x.derivation == PurposeLineage.ROWSET for x in possible_joins):
|
|
108
|
+
logger.info(
|
|
109
|
+
f"{padding(depth)}{LOGGER_PREFIX} cannot enrich rowset node with rowset concepts; exiting early"
|
|
110
|
+
)
|
|
111
|
+
return node
|
|
112
|
+
logger.info([x.address for x in possible_joins + local_optional])
|
|
106
113
|
enrich_node: MergeNode = source_concepts( # this fetches the parent + join keys
|
|
107
114
|
# to then connect to the rest of the query
|
|
108
115
|
mandatory_list=possible_joins + local_optional,
|
|
@@ -110,15 +117,28 @@ def gen_rowset_node(
|
|
|
110
117
|
g=g,
|
|
111
118
|
depth=depth + 1,
|
|
112
119
|
conditions=conditions,
|
|
120
|
+
history=history,
|
|
113
121
|
)
|
|
114
122
|
if not enrich_node:
|
|
115
123
|
logger.info(
|
|
116
124
|
f"{padding(depth)}{LOGGER_PREFIX} Cannot generate rowset enrichment node for {concept} with optional {local_optional}, returning just rowset node"
|
|
117
125
|
)
|
|
118
126
|
return node
|
|
127
|
+
|
|
128
|
+
non_hidden = [
|
|
129
|
+
x for x in node.output_concepts if x.address not in node.hidden_concepts
|
|
130
|
+
]
|
|
131
|
+
for x in possible_joins:
|
|
132
|
+
if x.address in node.hidden_concepts:
|
|
133
|
+
node.unhide_output_concepts([x])
|
|
134
|
+
non_hidden_enrich = [
|
|
135
|
+
x
|
|
136
|
+
for x in enrich_node.output_concepts
|
|
137
|
+
if x.address not in enrich_node.hidden_concepts
|
|
138
|
+
]
|
|
119
139
|
return MergeNode(
|
|
120
|
-
input_concepts=
|
|
121
|
-
output_concepts=
|
|
140
|
+
input_concepts=non_hidden + non_hidden_enrich,
|
|
141
|
+
output_concepts=non_hidden + local_optional,
|
|
122
142
|
environment=environment,
|
|
123
143
|
g=g,
|
|
124
144
|
depth=depth,
|
|
@@ -126,6 +146,6 @@ def gen_rowset_node(
|
|
|
126
146
|
node,
|
|
127
147
|
enrich_node,
|
|
128
148
|
],
|
|
129
|
-
partial_concepts=node.partial_concepts,
|
|
149
|
+
partial_concepts=node.partial_concepts + enrich_node.partial_concepts,
|
|
130
150
|
preexisting_conditions=conditions.conditional if conditions else None,
|
|
131
151
|
)
|
|
@@ -211,8 +211,22 @@ class StrategyNode:
|
|
|
211
211
|
operator=BooleanOperator.AND,
|
|
212
212
|
)
|
|
213
213
|
self.validate_parents()
|
|
214
|
+
self.validate_inputs()
|
|
214
215
|
self.log = True
|
|
215
216
|
|
|
217
|
+
def validate_inputs(self):
|
|
218
|
+
if not self.parents:
|
|
219
|
+
return
|
|
220
|
+
non_hidden = set()
|
|
221
|
+
for x in self.parents:
|
|
222
|
+
for z in x.usable_outputs:
|
|
223
|
+
non_hidden.add(z.address)
|
|
224
|
+
if not all([x.address in non_hidden for x in self.input_concepts]):
|
|
225
|
+
missing = [x for x in self.input_concepts if x.address not in non_hidden]
|
|
226
|
+
raise ValueError(
|
|
227
|
+
f"Invalid input concepts; {missing} are missing non-hidden parent nodes"
|
|
228
|
+
)
|
|
229
|
+
|
|
216
230
|
def add_parents(self, parents: list["StrategyNode"]):
|
|
217
231
|
self.parents += parents
|
|
218
232
|
self.validate_parents()
|
|
@@ -288,6 +302,14 @@ class StrategyNode:
|
|
|
288
302
|
self.rebuild_cache()
|
|
289
303
|
return self
|
|
290
304
|
|
|
305
|
+
def unhide_output_concepts(self, concepts: List[Concept], rebuild: bool = True):
|
|
306
|
+
self.hidden_concepts = [
|
|
307
|
+
x for x in self.hidden_concepts if x.address not in concepts
|
|
308
|
+
]
|
|
309
|
+
if rebuild:
|
|
310
|
+
self.rebuild_cache()
|
|
311
|
+
return self
|
|
312
|
+
|
|
291
313
|
def remove_output_concepts(self, concepts: List[Concept], rebuild: bool = True):
|
|
292
314
|
for x in concepts:
|
|
293
315
|
self.hidden_concepts.append(x)
|
|
@@ -299,6 +321,12 @@ class StrategyNode:
|
|
|
299
321
|
self.rebuild_cache()
|
|
300
322
|
return self
|
|
301
323
|
|
|
324
|
+
@property
|
|
325
|
+
def usable_outputs(self) -> list[Concept]:
|
|
326
|
+
return [
|
|
327
|
+
x for x in self.output_concepts if x.address not in self.hidden_concepts
|
|
328
|
+
]
|
|
329
|
+
|
|
302
330
|
@property
|
|
303
331
|
def logging_prefix(self) -> str:
|
|
304
332
|
return "\t" * self.depth
|
|
@@ -105,9 +105,9 @@ class GroupNode(StrategyNode):
|
|
|
105
105
|
logger.info(
|
|
106
106
|
f"{self.logging_prefix}{LOGGER_PREFIX} Parent node"
|
|
107
107
|
f" {[c.address for c in parent.output_concepts[:2]]}... has"
|
|
108
|
-
" grain"
|
|
108
|
+
" set node grain"
|
|
109
109
|
f" {parent.grain}"
|
|
110
|
-
f" resolved grain {parent.resolve().grain}"
|
|
110
|
+
f" and resolved grain {parent.resolve().grain}"
|
|
111
111
|
f" {type(parent)}"
|
|
112
112
|
)
|
|
113
113
|
source_type = SourceType.GROUP
|
|
@@ -146,7 +146,13 @@ class GroupNode(StrategyNode):
|
|
|
146
146
|
# inject an additional CTE
|
|
147
147
|
if self.conditions and not is_scalar_condition(self.conditions):
|
|
148
148
|
base.condition = None
|
|
149
|
-
base.output_concepts =
|
|
149
|
+
base.output_concepts = unique(
|
|
150
|
+
base.output_concepts + self.conditions.row_arguments, "address"
|
|
151
|
+
)
|
|
152
|
+
# re-visible any hidden concepts
|
|
153
|
+
base.hidden_concepts = [
|
|
154
|
+
x for x in base.hidden_concepts if x not in base.output_concepts
|
|
155
|
+
]
|
|
150
156
|
source_map = resolve_concept_map(
|
|
151
157
|
[base],
|
|
152
158
|
targets=self.output_concepts,
|
|
@@ -330,8 +330,9 @@ class MergeNode(StrategyNode):
|
|
|
330
330
|
force_group = None
|
|
331
331
|
|
|
332
332
|
qd_joins: List[BaseJoin | UnnestJoin] = [*joins]
|
|
333
|
+
|
|
333
334
|
source_map = resolve_concept_map(
|
|
334
|
-
|
|
335
|
+
final_datasets,
|
|
335
336
|
targets=self.output_concepts,
|
|
336
337
|
inherited_inputs=self.input_concepts + self.existence_concepts,
|
|
337
338
|
full_joins=full_join_concepts,
|
|
@@ -339,6 +340,7 @@ class MergeNode(StrategyNode):
|
|
|
339
340
|
nullable_concepts = find_nullable_concepts(
|
|
340
341
|
source_map=source_map, joins=joins, datasources=final_datasets
|
|
341
342
|
)
|
|
343
|
+
|
|
342
344
|
qds = QueryDatasource(
|
|
343
345
|
input_concepts=unique(self.input_concepts, "address"),
|
|
344
346
|
output_concepts=unique(self.output_concepts, "address"),
|
|
@@ -67,6 +67,11 @@ class SelectNode(StrategyNode):
|
|
|
67
67
|
self.accept_partial = accept_partial
|
|
68
68
|
self.datasource = datasource
|
|
69
69
|
|
|
70
|
+
def validate_inputs(self):
|
|
71
|
+
# we do not need to validate inputs for a select node
|
|
72
|
+
# as it will be a root
|
|
73
|
+
return
|
|
74
|
+
|
|
70
75
|
def resolve_from_provided_datasource(
|
|
71
76
|
self,
|
|
72
77
|
) -> QueryDatasource:
|
|
@@ -214,7 +214,7 @@ def concept_to_relevant_joins(concepts: list[Concept]) -> List[Concept]:
|
|
|
214
214
|
x for x in concepts if x.keys and all([key in addresses for key in x.keys])
|
|
215
215
|
]
|
|
216
216
|
)
|
|
217
|
-
final = [c for c in concepts if c not in sub_props]
|
|
217
|
+
final = [c for c in concepts if c.address not in sub_props]
|
|
218
218
|
return unique(final, "address")
|
|
219
219
|
|
|
220
220
|
|
trilogy/core/query_processor.py
CHANGED
|
@@ -7,7 +7,6 @@ from trilogy.core.constants import CONSTANT_DATASET
|
|
|
7
7
|
from trilogy.core.enums import BooleanOperator, SourceType
|
|
8
8
|
from trilogy.core.env_processor import generate_graph
|
|
9
9
|
from trilogy.core.ergonomics import generate_cte_names
|
|
10
|
-
from trilogy.core.graph_models import ReferenceGraph
|
|
11
10
|
from trilogy.core.models import (
|
|
12
11
|
CTE,
|
|
13
12
|
BaseJoin,
|
|
@@ -353,13 +352,12 @@ def datasource_to_cte(
|
|
|
353
352
|
def get_query_node(
|
|
354
353
|
environment: Environment,
|
|
355
354
|
statement: SelectStatement | MultiSelectStatement,
|
|
356
|
-
graph: Optional[ReferenceGraph] = None,
|
|
357
355
|
history: History | None = None,
|
|
358
356
|
) -> StrategyNode:
|
|
359
357
|
environment = environment.duplicate()
|
|
360
358
|
for k, v in statement.local_concepts.items():
|
|
361
359
|
environment.concepts[k] = v
|
|
362
|
-
graph =
|
|
360
|
+
graph = generate_graph(environment)
|
|
363
361
|
logger.info(
|
|
364
362
|
f"{LOGGER_PREFIX} getting source datasource for query with filtering {statement.where_clause_category} and output {[str(c) for c in statement.output_components]}"
|
|
365
363
|
)
|
|
@@ -403,11 +401,10 @@ def get_query_node(
|
|
|
403
401
|
def get_query_datasources(
|
|
404
402
|
environment: Environment,
|
|
405
403
|
statement: SelectStatement | MultiSelectStatement,
|
|
406
|
-
graph: Optional[ReferenceGraph] = None,
|
|
407
404
|
hooks: Optional[List[BaseHook]] = None,
|
|
408
405
|
) -> QueryDatasource:
|
|
409
406
|
|
|
410
|
-
ds = get_query_node(environment, statement
|
|
407
|
+
ds = get_query_node(environment, statement)
|
|
411
408
|
final_qds = ds.resolve()
|
|
412
409
|
if hooks:
|
|
413
410
|
for hook in hooks:
|
|
@@ -479,10 +476,9 @@ def process_query(
|
|
|
479
476
|
hooks: List[BaseHook] | None = None,
|
|
480
477
|
) -> ProcessedQuery:
|
|
481
478
|
hooks = hooks or []
|
|
482
|
-
graph = generate_graph(environment)
|
|
483
479
|
|
|
484
480
|
root_datasource = get_query_datasources(
|
|
485
|
-
environment=environment,
|
|
481
|
+
environment=environment, statement=statement, hooks=hooks
|
|
486
482
|
)
|
|
487
483
|
for hook in hooks:
|
|
488
484
|
hook.process_root_datasource(root_datasource)
|
trilogy/parsing/parse_engine.py
CHANGED
|
@@ -570,6 +570,7 @@ class ParseToObjects(Transformer):
|
|
|
570
570
|
for new_concept in output.derived_concepts:
|
|
571
571
|
if new_concept.metadata:
|
|
572
572
|
new_concept.metadata.line_number = meta.line
|
|
573
|
+
# output.select.local_concepts[new_concept.address] = new_concept
|
|
573
574
|
self.environment.add_concept(new_concept)
|
|
574
575
|
|
|
575
576
|
return output
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|