pytrilogy 0.0.2.40__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.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pytrilogy
3
- Version: 0.0.2.40
3
+ Version: 0.0.2.41
4
4
  Summary: Declarative, typed query language that compiles to SQL.
5
5
  Home-page:
6
6
  Author:
@@ -186,7 +186,7 @@ datasource usa_names(
186
186
  gender:gender,
187
187
  state:state
188
188
  )
189
- address bigquery-public-data.usa_names.usa_1910_2013;
189
+ address `bigquery-public-data.usa_names.usa_1910_2013`;
190
190
 
191
191
  '''
192
192
  )
@@ -1,4 +1,4 @@
1
- trilogy/__init__.py,sha256=2E7nMoyCbDG8XWcPC2wKkOfnlTRrPzFPzBTUxxpk8U4,291
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=S_Qq1HpDDTFI1JRrr9Ky-2K2VusiUkpe7rfq44CclBQ,163041
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=1l9WnFOSv79e341typG3tTdk0XGl1J_ToQih3LYoGIY,8435
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=WQNgJ1MwrMS_BQ-b3XwGGB6eToDykelAVj_fesJuqe0,2069
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=jy3FF8uN0VA7yyrBeR40B9CAqR_5qBP4PiS6Gr-f-7w,2590
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=ubBrXe-Pb-9LjG1bCvZW7U3M0Nor4R1Ulgu1u6YcULY,34606
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
@@ -72,12 +72,12 @@ trilogy/parsing/exceptions.py,sha256=92E5i2frv5hj9wxObJZsZqj5T6bglvPzvdvco_vW1Zk
72
72
  trilogy/parsing/helpers.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
73
73
  trilogy/parsing/parse_engine.py,sha256=KMeHQf8iW-UKd4JstGgcoo6O3OZ14MaQW50g1PMjEEQ,65256
74
74
  trilogy/parsing/render.py,sha256=-qqpXQg4yHcv284Vosjnsc_vrPveH6oaYbeCd3ZSvs0,15682
75
- trilogy/parsing/trilogy.lark,sha256=YOgt-rE_0ZHRex_fTeqZiHvu5a4BX5UBOUu1LAVCyug,12391
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.40.dist-info/LICENSE.md,sha256=5ZRvtTyCCFwz1THxDTjAu3Lidds9WjPvvzgVwPSYNDo,1042
79
- pytrilogy-0.0.2.40.dist-info/METADATA,sha256=xgH5_k_JkGbPM1lpHQYkEQvbPizwXPjnZduBAZUrdzs,8424
80
- pytrilogy-0.0.2.40.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
81
- pytrilogy-0.0.2.40.dist-info/entry_points.txt,sha256=0petKryjvvtEfTlbZC1AuMFumH_WQ9v8A19LvoS6G6c,54
82
- pytrilogy-0.0.2.40.dist-info/top_level.txt,sha256=cAy__NW_eMAa_yT9UnUNlZLFfxcg6eimUAZ184cdNiE,8
83
- pytrilogy-0.0.2.40.dist-info/RECORD,,
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
@@ -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.40"
7
+ __version__ = "0.0.2.41"
8
8
 
9
9
  __all__ = ["parse", "Executor", "Dialects", "Environment", "CONFIG"]
trilogy/core/models.py CHANGED
@@ -1375,6 +1375,9 @@ class WindowItem(Mergeable, Namespaced, SelectContext, BaseModel):
1375
1375
  over: List["Concept"] = Field(default_factory=list)
1376
1376
  index: Optional[int] = None
1377
1377
 
1378
+ def __repr__(self) -> str:
1379
+ return f"{self.type}({self.content} {self.index}, {self.over}, {self.order_by})"
1380
+
1378
1381
  def with_merge(
1379
1382
  self, source: Concept, target: Concept, modifiers: List[Modifier]
1380
1383
  ) -> "WindowItem":
@@ -1383,6 +1386,7 @@ class WindowItem(Mergeable, Namespaced, SelectContext, BaseModel):
1383
1386
  content=self.content.with_merge(source, target, modifiers),
1384
1387
  over=[x.with_merge(source, target, modifiers) for x in self.over],
1385
1388
  order_by=[x.with_merge(source, target, modifiers) for x in self.order_by],
1389
+ index=self.index,
1386
1390
  )
1387
1391
 
1388
1392
  def with_namespace(self, namespace: str) -> "WindowItem":
@@ -1391,6 +1395,7 @@ class WindowItem(Mergeable, Namespaced, SelectContext, BaseModel):
1391
1395
  content=self.content.with_namespace(namespace),
1392
1396
  over=[x.with_namespace(namespace) for x in self.over],
1393
1397
  order_by=[x.with_namespace(namespace) for x in self.order_by],
1398
+ index=self.index,
1394
1399
  )
1395
1400
 
1396
1401
  def with_select_context(
@@ -1410,6 +1415,7 @@ class WindowItem(Mergeable, Namespaced, SelectContext, BaseModel):
1410
1415
  x.with_select_context(grain, conditional, environment)
1411
1416
  for x in self.order_by
1412
1417
  ],
1418
+ index=self.index,
1413
1419
  )
1414
1420
 
1415
1421
  @property
@@ -6,6 +6,7 @@ from trilogy.core.models import (
6
6
  ConceptArgs,
7
7
  Comparison,
8
8
  Parenthetical,
9
+ WindowItem,
9
10
  )
10
11
  from trilogy.core.optimizations.base_optimization import OptimizationRule
11
12
  from trilogy.core.processing.utility import is_scalar_condition
@@ -45,7 +46,15 @@ class PredicatePushdown(OptimizationRule):
45
46
  all_inputs = {x.address for x in candidate.concept_arguments}
46
47
  if is_child_of(candidate, parent_cte.condition):
47
48
  return False
48
-
49
+ non_materialized = [k for k, v in parent_cte.source_map.items() if v == []]
50
+ concrete = [
51
+ x for x in parent_cte.output_columns if x.address in non_materialized
52
+ ]
53
+ if any(isinstance(x.lineage, WindowItem) for x in concrete):
54
+ self.debug(
55
+ f"CTE {parent_cte.name} has window clause calculation, cannot push up to this without changing results"
56
+ )
57
+ return False
49
58
  materialized = {k for k, v in parent_cte.source_map.items() if v != []}
50
59
  if not row_conditions or not materialized:
51
60
  return False
@@ -108,12 +117,12 @@ class PredicatePushdown(OptimizationRule):
108
117
 
109
118
  if not cte.parent_ctes:
110
119
  self.debug(f"No parent CTEs for {cte.name}")
111
-
112
120
  return False
113
121
 
114
122
  if not cte.condition:
115
123
  self.debug(f"No CTE condition for {cte.name}")
116
124
  return False
125
+
117
126
  if self.complete.get(cte.name):
118
127
  self.debug("Have done this CTE before")
119
128
  return False
@@ -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 Concept, WhereClause
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 x.lineage == concept.lineage and x.address != concept.address
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 = [concept.lineage.content]
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
- parent_node = source_concepts(
37
- mandatory_list=parent_concepts + local_optional,
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 + local_optional,
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})"
@@ -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, cte=cte, alias=False, raise_invalid=raise_invalid), window=','.join(rendered_over_components), sort=','.join(rendered_order_components))}" # noqa: E501
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:
@@ -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\_\.\-\*\:]*`/