pytrilogy 0.0.2.28__py3-none-any.whl → 0.0.2.29__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.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pytrilogy
3
- Version: 0.0.2.28
3
+ Version: 0.0.2.29
4
4
  Summary: Declarative, typed query language that compiles to SQL.
5
5
  Home-page:
6
6
  Author:
@@ -1,4 +1,4 @@
1
- trilogy/__init__.py,sha256=Oj4rApJpgEd7VNBVDA5Sy1tHnI0ISyXQcfpiH-fv6UY,291
1
+ trilogy/__init__.py,sha256=0Y9rVM2nobxcrfYQcGTfJVv_-3fbl5QtzNRClHX50TU,291
2
2
  trilogy/compiler.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
3
  trilogy/constants.py,sha256=KiyYnctoZen4Hzv8WG2jeN-IE-dfQbWHdVCUeTZYjBg,1270
4
4
  trilogy/engine.py,sha256=R5ubIxYyrxRExz07aZCUfrTsoXCHQ8DKFTDsobXdWdA,1102
@@ -16,8 +16,8 @@ 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=W_0ZfIIEuyHfYsSXGMJOJPNJf7vSljSrRm42nLyiL8w,159702
20
- trilogy/core/optimization.py,sha256=od_60A9F8J8Nj24MHgrxl4vwRwmBFH13TMdoMQvgVKs,7717
19
+ trilogy/core/models.py,sha256=d0nmbSrR7LObYOpfx9Q5GYrXg-hV0OrBDwrIj90eGX8,159625
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
@@ -25,9 +25,9 @@ trilogy/core/optimizations/inline_constant.py,sha256=kHNyc2UoaPVdYfVAPAFwnWuk4sJ
25
25
  trilogy/core/optimizations/inline_datasource.py,sha256=NqUOVl0pOXF1R_roELVW8I0qN7or2wPtAsRmDD9QJso,3658
26
26
  trilogy/core/optimizations/predicate_pushdown.py,sha256=1l9WnFOSv79e341typG3tTdk0XGl1J_ToQih3LYoGIY,8435
27
27
  trilogy/core/processing/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
- trilogy/core/processing/concept_strategies_v3.py,sha256=7MT_x6QFHrbSDmjz21pYdQB5ux419ES4QS-8lO16eyw,36091
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
- trilogy/core/processing/utility.py,sha256=xlaKqnoWg-mEwTF-erBF9QXnXZtESrTuYrK2RQb7Wi4,17411
30
+ trilogy/core/processing/utility.py,sha256=VFArfoUY5EiacspwQ03uWiKRr5SzEDhIB_iMrOIPBAg,18540
31
31
  trilogy/core/processing/node_generators/__init__.py,sha256=-mzYkRsaRNa_dfTckYkKVFSR8h8a3ihEiPJDU_tAmDo,672
32
32
  trilogy/core/processing/node_generators/basic_node.py,sha256=WQNgJ1MwrMS_BQ-b3XwGGB6eToDykelAVj_fesJuqe0,2069
33
33
  trilogy/core/processing/node_generators/common.py,sha256=eslHTTPFTkmwHwKIuUsbFn54jxj-Avtt-QScqtNwzdg,8945
@@ -37,20 +37,20 @@ trilogy/core/processing/node_generators/group_to_node.py,sha256=R9i_wHipxjXJyfYE
37
37
  trilogy/core/processing/node_generators/multiselect_node.py,sha256=_KO9lqzHQoy4VAviO0ttQlmK0tjaqrJj4SJPhmoIYm8,6229
38
38
  trilogy/core/processing/node_generators/node_merge_node.py,sha256=dIEv5P2MTViAES2MzqJgccYzM3HldjHrQYFwH00cqyc,14003
39
39
  trilogy/core/processing/node_generators/rowset_node.py,sha256=KtdN6t2xM8CJxobc4aQX4W8uX98U6IabeuBF_FtBLR4,4583
40
- trilogy/core/processing/node_generators/select_merge_node.py,sha256=vE7GoPu2_okO3jS96oA5O3jFsrkiSqIvIP5WkyfFil0,11596
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
43
  trilogy/core/processing/node_generators/window_node.py,sha256=jy3FF8uN0VA7yyrBeR40B9CAqR_5qBP4PiS6Gr-f-7w,2590
44
44
  trilogy/core/processing/nodes/__init__.py,sha256=qS5EJDRwwIrCEfS7ibCA2ESE0RPzsAIii1UWd_wNsHA,4760
45
- trilogy/core/processing/nodes/base_node.py,sha256=8nEG3OPE_LzFXI48-Y6FS8MyO79LY0Sm0EqYz31WJ1Q,15719
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
47
47
  trilogy/core/processing/nodes/group_node.py,sha256=PrBHaGq_f8RmokUw9lXLGJ5YbjdP77P7Ag0pgR6e2cU,7293
48
48
  trilogy/core/processing/nodes/merge_node.py,sha256=W3eCjmJbs8Wfw7Y5AgIY2pP-ntPCrrMe11UG-QGJvA8,14835
49
- trilogy/core/processing/nodes/select_node_v2.py,sha256=k5WvqmOkLwnP9SFSF5z33a1SFo4nZ-y9ODLi-P05YkI,8281
49
+ trilogy/core/processing/nodes/select_node_v2.py,sha256=7WoFxeGEAzhpS4y4Zw2nH2tt7OzdlLfMvDFoLF_vb4Y,8108
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=JpC-ig7iRzZxcuHmKRInKfFAoNTzFOcclAvmvUJiWOo,34087
53
+ trilogy/dialect/base.py,sha256=VqBnDwPRzJkb1HPIlZ2X4lLsZzYrgJIOqr8x0UQuESg,34226
54
54
  trilogy/dialect/bigquery.py,sha256=15KJ-cOpBlk9O7FPviPgmg8xIydJeKx7WfmL3SSsPE8,2953
55
55
  trilogy/dialect/common.py,sha256=Pm9naWL5eo-BfZTYFMWhX9lpsGuxEyvvn_EuXbFeos0,3817
56
56
  trilogy/dialect/config.py,sha256=tLVEMctaTDhUgARKXUNfHUcIolGaALkQ0RavUvXAY4w,2994
@@ -75,9 +75,9 @@ trilogy/parsing/render.py,sha256=B9J2GrYQcE76kddMQSeAmvAPX-9pv39mpeSHZ10SNj8,146
75
75
  trilogy/parsing/trilogy.lark,sha256=_z5px2N-e8oLUf7SpPMXXNqbAykDkZOvP4_lPgf5-Uk,12245
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.28.dist-info/LICENSE.md,sha256=5ZRvtTyCCFwz1THxDTjAu3Lidds9WjPvvzgVwPSYNDo,1042
79
- pytrilogy-0.0.2.28.dist-info/METADATA,sha256=Ftsu-RyQ2c7b05KV4JZm7J9f1DEMup2xjMfLUA-PfWQ,8403
80
- pytrilogy-0.0.2.28.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
81
- pytrilogy-0.0.2.28.dist-info/entry_points.txt,sha256=0petKryjvvtEfTlbZC1AuMFumH_WQ9v8A19LvoS6G6c,54
82
- pytrilogy-0.0.2.28.dist-info/top_level.txt,sha256=cAy__NW_eMAa_yT9UnUNlZLFfxcg6eimUAZ184cdNiE,8
83
- pytrilogy-0.0.2.28.dist-info/RECORD,,
78
+ pytrilogy-0.0.2.29.dist-info/LICENSE.md,sha256=5ZRvtTyCCFwz1THxDTjAu3Lidds9WjPvvzgVwPSYNDo,1042
79
+ pytrilogy-0.0.2.29.dist-info/METADATA,sha256=_grlNHrTsokAIFDU4uIYFOrJ8t7X_R5vr0kcuNMzJ6g,8403
80
+ pytrilogy-0.0.2.29.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
81
+ pytrilogy-0.0.2.29.dist-info/entry_points.txt,sha256=0petKryjvvtEfTlbZC1AuMFumH_WQ9v8A19LvoS6G6c,54
82
+ pytrilogy-0.0.2.29.dist-info/top_level.txt,sha256=cAy__NW_eMAa_yT9UnUNlZLFfxcg6eimUAZ184cdNiE,8
83
+ pytrilogy-0.0.2.29.dist-info/RECORD,,
trilogy/__init__.py CHANGED
@@ -4,6 +4,6 @@ from trilogy.executor import Executor
4
4
  from trilogy.parser import parse
5
5
  from trilogy.constants import CONFIG
6
6
 
7
- __version__ = "0.0.2.28"
7
+ __version__ = "0.0.2.29"
8
8
 
9
9
  __all__ = ["parse", "Executor", "Dialects", "Environment", "CONFIG"]
trilogy/core/models.py CHANGED
@@ -1760,7 +1760,6 @@ class SelectStatement(HasUUID, Mergeable, Namespaced, SelectTypeMixin, BaseModel
1760
1760
  grain=grain or self.grain,
1761
1761
  columns=columns,
1762
1762
  namespace=namespace,
1763
- where=WhereClause(conditional=condition) if condition else None,
1764
1763
  non_partial_for=WhereClause(conditional=condition) if condition else None,
1765
1764
  )
1766
1765
  for column in columns:
@@ -13,7 +13,7 @@ from trilogy.core.optimizations import (
13
13
  PredicatePushdownRemove,
14
14
  InlineDatasource,
15
15
  )
16
-
16
+ from trilogy.core.processing.utility import sort_select_output
17
17
 
18
18
  MAX_OPTIMIZATION_LOOPS = 100
19
19
 
@@ -154,20 +154,6 @@ def is_direct_return_eligible(cte: CTE) -> CTE | None:
154
154
  return direct_parent
155
155
 
156
156
 
157
- def sort_select_output(cte: CTE, query: SelectStatement | MultiSelectStatement):
158
- hidden_addresses = [c.address for c in query.hidden_components]
159
- output_addresses = [
160
- c.address for c in query.output_components if c.address not in hidden_addresses
161
- ]
162
-
163
- mapping = {x.address: x for x in cte.output_columns}
164
-
165
- new_output = []
166
- for x in output_addresses:
167
- new_output.append(mapping[x])
168
- cte.output_columns = new_output
169
-
170
-
171
157
  def optimize_ctes(
172
158
  input: list[CTE], root_cte: CTE, select: SelectStatement | MultiSelectStatement
173
159
  ) -> list[CTE]:
@@ -838,9 +838,8 @@ def _search_concepts(
838
838
  f" {accept_partial} (complete: {complete}), have {found} from {[n for n in stack]} (missing {missing} partial {partial} virtual {virtual}), attempted {attempted}, mandatory w/ filter {mandatory_completion}"
839
839
  )
840
840
  if complete == ValidationResult.INCOMPLETE_CONDITION:
841
- raise SyntaxError(
842
- {str(node): node.preexisting_conditions for node in stack}
843
- )
841
+ cond_dict = {str(node): node.preexisting_conditions for node in stack}
842
+ raise SyntaxError(f"Have {cond_dict} and need {str(conditions)}")
844
843
  # early exit if we have a complete stack with one node
845
844
  # we can only early exit if we have a complete stack
846
845
  # and we are not looking for more non-partial sources
@@ -233,7 +233,6 @@ def create_select_node(
233
233
  ]
234
234
  nullable_lcl = LooseConceptList(concepts=nullable_concepts)
235
235
  partial_is_full = conditions and (conditions == datasource.non_partial_for)
236
-
237
236
  bcandidate: StrategyNode = SelectNode(
238
237
  input_concepts=[c.concept for c in datasource.columns],
239
238
  output_concepts=all_concepts,
@@ -249,7 +248,9 @@ def create_select_node(
249
248
  datasource=datasource,
250
249
  grain=Grain(components=all_concepts),
251
250
  conditions=datasource.where.conditional if datasource.where else None,
252
- render_condition=not partial_is_full,
251
+ preexisting_conditions=(
252
+ conditions.conditional if partial_is_full and conditions else None
253
+ ),
253
254
  )
254
255
 
255
256
  # we need to nest the group node one further
@@ -263,6 +264,9 @@ def create_select_node(
263
264
  depth=depth,
264
265
  partial_concepts=bcandidate.partial_concepts,
265
266
  nullable_concepts=bcandidate.nullable_concepts,
267
+ preexisting_conditions=(
268
+ conditions.conditional if partial_is_full and conditions else None
269
+ ),
266
270
  )
267
271
  else:
268
272
  candidate = bcandidate
@@ -340,6 +344,15 @@ def gen_select_merge_node(
340
344
 
341
345
  if len(parents) == 1:
342
346
  return parents[0]
347
+ preexisting_conditions = None
348
+ if conditions and all(
349
+ [
350
+ x.preexisting_conditions
351
+ and x.preexisting_conditions == conditions.conditional
352
+ for x in parents
353
+ ]
354
+ ):
355
+ preexisting_conditions = conditions.conditional
343
356
  return MergeNode(
344
357
  output_concepts=all_concepts,
345
358
  input_concepts=non_constant,
@@ -347,4 +360,5 @@ def gen_select_merge_node(
347
360
  g=g,
348
361
  depth=depth,
349
362
  parents=parents,
363
+ preexisting_conditions=preexisting_conditions,
350
364
  )
@@ -165,7 +165,6 @@ class StrategyNode:
165
165
  hidden_concepts: List[Concept] | None = None,
166
166
  existence_concepts: List[Concept] | None = None,
167
167
  virtual_output_concepts: List[Concept] | None = None,
168
- render_condition: bool = True,
169
168
  ):
170
169
  self.input_concepts: List[Concept] = (
171
170
  unique(input_concepts, "address") if input_concepts else []
@@ -209,7 +208,6 @@ class StrategyNode:
209
208
  )
210
209
  self.validate_parents()
211
210
  self.log = True
212
- self.render_condition = render_condition
213
211
 
214
212
  def add_parents(self, parents: list["StrategyNode"]):
215
213
  self.parents += parents
@@ -382,7 +380,6 @@ class StrategyNode:
382
380
  hidden_concepts=list(self.hidden_concepts),
383
381
  existence_concepts=list(self.existence_concepts),
384
382
  virtual_output_concepts=list(self.virtual_output_concepts),
385
- render_condition=self.render_condition,
386
383
  )
387
384
 
388
385
 
@@ -49,7 +49,6 @@ class SelectNode(StrategyNode):
49
49
  conditions: Conditional | Comparison | Parenthetical | None = None,
50
50
  preexisting_conditions: Conditional | Comparison | Parenthetical | None = None,
51
51
  hidden_concepts: List[Concept] | None = None,
52
- render_condition: bool = True,
53
52
  ):
54
53
  super().__init__(
55
54
  input_concepts=input_concepts,
@@ -66,7 +65,6 @@ class SelectNode(StrategyNode):
66
65
  conditions=conditions,
67
66
  preexisting_conditions=preexisting_conditions,
68
67
  hidden_concepts=hidden_concepts,
69
- render_condition=render_condition,
70
68
  )
71
69
  self.accept_partial = accept_partial
72
70
  self.datasource = datasource
@@ -123,7 +121,7 @@ class SelectNode(StrategyNode):
123
121
  nullable_concepts=[c.concept for c in datasource.columns if c.is_nullable],
124
122
  source_type=SourceType.DIRECT_SELECT,
125
123
  # we can skip rendering conditions
126
- condition=self.conditions if self.render_condition else None,
124
+ condition=self.conditions,
127
125
  # select nodes should never group
128
126
  force_group=self.force_group,
129
127
  hidden_concepts=self.hidden_concepts,
@@ -208,7 +206,6 @@ class SelectNode(StrategyNode):
208
206
  conditions=self.conditions,
209
207
  preexisting_conditions=self.preexisting_conditions,
210
208
  hidden_concepts=self.hidden_concepts,
211
- render_condition=self.render_condition,
212
209
  )
213
210
 
214
211
 
@@ -29,6 +29,10 @@ from trilogy.core.models import (
29
29
  NumericType,
30
30
  ListType,
31
31
  TupleWrapper,
32
+ CTE,
33
+ MultiSelectStatement,
34
+ SelectStatement,
35
+ ProcessedQuery,
32
36
  )
33
37
 
34
38
  from trilogy.core.enums import Purpose, Granularity, BooleanOperator
@@ -528,3 +532,37 @@ def find_nullable_concepts(
528
532
  if set(v).issubset(all_ds):
529
533
  final_nullable.add(k)
530
534
  return list(sorted(final_nullable))
535
+
536
+
537
+ def sort_select_output_processed(cte: CTE, query: ProcessedQuery) -> CTE:
538
+ hidden_addresses = [c.address for c in query.hidden_columns]
539
+ output_addresses = [
540
+ c.address for c in query.output_columns if c.address not in hidden_addresses
541
+ ]
542
+
543
+ mapping = {x.address: x for x in cte.output_columns}
544
+
545
+ new_output = []
546
+ for x in output_addresses:
547
+ new_output.append(mapping[x])
548
+ cte.output_columns = new_output
549
+ return cte
550
+
551
+
552
+ def sort_select_output(
553
+ cte: CTE, query: SelectStatement | MultiSelectStatement | ProcessedQuery
554
+ ) -> CTE:
555
+ if isinstance(query, ProcessedQuery):
556
+ return sort_select_output_processed(cte, query)
557
+ hidden_addresses = [c.address for c in query.hidden_components]
558
+ output_addresses = [
559
+ c.address for c in query.output_components if c.address not in hidden_addresses
560
+ ]
561
+
562
+ mapping = {x.address: x for x in cte.output_columns}
563
+
564
+ new_output = []
565
+ for x in output_addresses:
566
+ new_output.append(mapping[x])
567
+ cte.output_columns = new_output
568
+ return cte
trilogy/dialect/base.py CHANGED
@@ -2,7 +2,11 @@ from typing import List, Union, Optional, Dict, Any, Sequence, Callable
2
2
 
3
3
  from jinja2 import Template
4
4
 
5
- from trilogy.core.processing.utility import is_scalar_condition, decompose_condition
5
+ from trilogy.core.processing.utility import (
6
+ is_scalar_condition,
7
+ decompose_condition,
8
+ sort_select_output,
9
+ )
6
10
  from trilogy.constants import CONFIG, logger, MagicConstants
7
11
  from trilogy.core.internal import DEFAULT_CONCEPTS
8
12
  from trilogy.core.enums import (
@@ -537,7 +541,7 @@ class BaseDialect:
537
541
  else:
538
542
  raise ValueError(f"Unable to render type {type(e)} {e}")
539
543
 
540
- def render_cte(self, cte: CTE):
544
+ def render_cte(self, cte: CTE, auto_sort: bool = True):
541
545
  if self.UNNEST_MODE in (
542
546
  UnnestMode.CROSS_APPLY,
543
547
  UnnestMode.CROSS_JOIN,
@@ -561,6 +565,8 @@ class BaseDialect:
561
565
  for c in cte.output_columns
562
566
  if c.address not in [y.address for y in cte.hidden_concepts]
563
567
  ]
568
+ if auto_sort:
569
+ select_columns = sorted(select_columns, key=lambda x: x)
564
570
  source: str | None = cte.base_name
565
571
  if not cte.render_from_clause:
566
572
  if len(cte.joins) > 0:
@@ -657,8 +663,11 @@ class BaseDialect:
657
663
  def generate_ctes(
658
664
  self,
659
665
  query: ProcessedQuery,
660
- ):
661
- return [self.render_cte(cte) for cte in query.ctes]
666
+ ) -> List[CompiledCTE]:
667
+ return [self.render_cte(cte) for cte in query.ctes[:-1]] + [
668
+ # last CTE needs to respect the user output order
669
+ self.render_cte(sort_select_output(query.ctes[-1], query), auto_sort=False)
670
+ ]
662
671
 
663
672
  def generate_queries(
664
673
  self,
@@ -790,11 +799,6 @@ class BaseDialect:
790
799
 
791
800
  compiled_ctes = self.generate_ctes(query)
792
801
 
793
- # restort selections by the order they were written in
794
- sorted_select: List[str] = []
795
- for output_c in output_addresses:
796
- sorted_select.append(select_columns[output_c])
797
-
798
802
  final = self.SQL_TEMPLATE.render(
799
803
  output=(
800
804
  query.output_to if isinstance(query, ProcessedQueryPersist) else None