pytrilogy 0.0.2.15__py3-none-any.whl → 0.0.2.17__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pytrilogy
3
- Version: 0.0.2.15
3
+ Version: 0.0.2.17
4
4
  Summary: Declarative, typed query language that compiles to SQL.
5
5
  Home-page:
6
6
  Author:
@@ -1,8 +1,8 @@
1
- trilogy/__init__.py,sha256=blYi5mQGhWKBA8TAqC2T8y01GnT4mPEI1MaT2P3gwAI,291
1
+ trilogy/__init__.py,sha256=nBRkHW4Ndpv-I3-gUX1LDgrm4e5zxD2GFDWRZjwJ7A8,291
2
2
  trilogy/compiler.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
3
  trilogy/constants.py,sha256=Ijos7_TEajKhZ7OJ_TreEYFddW1V33AVymDDrxP-ZHk,1234
4
4
  trilogy/engine.py,sha256=R5ubIxYyrxRExz07aZCUfrTsoXCHQ8DKFTDsobXdWdA,1102
5
- trilogy/executor.py,sha256=PZr7IF8wS1Oi2WJGE-B3lp70Y8ue2uuauODw02chjdQ,11175
5
+ trilogy/executor.py,sha256=An6YLpHQOt96E7ozRQhwZels2hMsDbh0WV767kKCGU0,11294
6
6
  trilogy/parser.py,sha256=UtuqSiGiCjpMAYgo1bvNq-b7NSzCA5hzbUW31RXaMII,281
7
7
  trilogy/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
8
  trilogy/utility.py,sha256=zM__8r29EsyDW7K9VOHz8yvZC2bXFzh7xKy3cL7GKsk,707
@@ -16,7 +16,7 @@ trilogy/core/exceptions.py,sha256=NvV_4qLOgKXbpotgRf7c8BANDEvHxlqRPaA53IThQ2o,56
16
16
  trilogy/core/functions.py,sha256=ARJAyBjeS415-54k3G_bx807rkPZonEulMaLRxSP7vU,10371
17
17
  trilogy/core/graph_models.py,sha256=oJUMSpmYhqXlavckHLpR07GJxuQ8dZ1VbB1fB0KaS8c,2036
18
18
  trilogy/core/internal.py,sha256=jNGFHKENnbMiMCtAgsnLZYVSENDK4b5ALecXFZpTDzQ,1075
19
- trilogy/core/models.py,sha256=bWCklm8A9I0vx8fXWoN0jKJjLkXuyMUUQetT_zbhyRc,149031
19
+ trilogy/core/models.py,sha256=j55CLTR-vADhDd0va3maMPgNW4fj9GVJ8Kx5S25vu3w,149259
20
20
  trilogy/core/optimization.py,sha256=7E-Ol51u6ZAxF56F_bzLxgRO-Hu6Yl1ZbPopZJB2tqk,7533
21
21
  trilogy/core/query_processor.py,sha256=qMVkaK1Lvr9jEftJwAidMdkb_tRx12G07qynEyl91C8,18801
22
22
  trilogy/core/optimizations/__init__.py,sha256=bWQecbeiwiDx9LJnLsa7dkWxdbl2wcnkcTN69JyP8iI,356
@@ -49,9 +49,9 @@ trilogy/core/processing/nodes/select_node_v2.py,sha256=yoU2PWu-BkiUDECd7V7CKAPjz
49
49
  trilogy/core/processing/nodes/unnest_node.py,sha256=mAmFluzm2yeeiQ6NfIB7BU_8atRGh-UJfPf9ROwbhr8,2152
50
50
  trilogy/core/processing/nodes/window_node.py,sha256=X7qxLUKd3tekjUUsmH_4vz5b-U89gMnGd04VBxuu2Ns,1280
51
51
  trilogy/dialect/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
52
- trilogy/dialect/base.py,sha256=kQek_ufZC9HDVOKlWasvIx6xyew8wv3JNIU6r53_IR4,32842
52
+ trilogy/dialect/base.py,sha256=CcLIEqjRYSbxiCQWIjcn0XYb_jXvjY65-SeGAdIFioQ,32888
53
53
  trilogy/dialect/bigquery.py,sha256=15KJ-cOpBlk9O7FPviPgmg8xIydJeKx7WfmL3SSsPE8,2953
54
- trilogy/dialect/common.py,sha256=QCsqo5morOOL6kwaCYh1RBmaInaoPI6lKtzdgroWvuM,3440
54
+ trilogy/dialect/common.py,sha256=Hr0mxcNxjSvhpBM5Wvb_Q7aklAuYj5aBDrW433py0Zs,4403
55
55
  trilogy/dialect/config.py,sha256=tLVEMctaTDhUgARKXUNfHUcIolGaALkQ0RavUvXAY4w,2994
56
56
  trilogy/dialect/duckdb.py,sha256=u_gpL35kouWxoBLas1h0ABYY2QzlVtEh22hm5h0lCOM,3182
57
57
  trilogy/dialect/enums.py,sha256=4NdpsydBpDn6jnh0JzFz5VvQEtnShErWtWHVyT6TNpw,3948
@@ -69,14 +69,14 @@ trilogy/parsing/common.py,sha256=-4LM71ocidA8DI2RngqFEOmhzBrIt8VdBTO4x2BpD8E,950
69
69
  trilogy/parsing/config.py,sha256=Z-DaefdKhPDmSXLgg5V4pebhSB0h590vI0_VtHnlukI,111
70
70
  trilogy/parsing/exceptions.py,sha256=92E5i2frv5hj9wxObJZsZqj5T6bglvPzvdvco_vW1Zk,38
71
71
  trilogy/parsing/helpers.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
72
- trilogy/parsing/parse_engine.py,sha256=_DNpdZOQoZZio_mW8nxcCKoJHny7hnQQtOGG1msoCFU,63265
73
- trilogy/parsing/render.py,sha256=Gy_6wVYPwYLf35Iota08sbqveuWILtUhI8MYStcvtJM,12174
74
- trilogy/parsing/trilogy.lark,sha256=-9y4oVAIlKi-6pE58G4RwGGTBeG7P3T_V4gV8mILd8w,11549
72
+ trilogy/parsing/parse_engine.py,sha256=w-O1UNA7IMeYZPRB-bK1G-qM3nmM_mrQ-eVGSCkyIvM,63265
73
+ trilogy/parsing/render.py,sha256=8yxerPAi4AhlhPBlAfbYbOM3F9rz6HzpWVEWPtK2VEg,12321
74
+ trilogy/parsing/trilogy.lark,sha256=MFPDmqF0IntySCe7u8ZrLhoyzYYon4dYhnNRdERtEew,11583
75
75
  trilogy/scripts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
76
76
  trilogy/scripts/trilogy.py,sha256=PHxvv6f2ODv0esyyhWxlARgra8dVhqQhYl0lTrSyVNo,3729
77
- pytrilogy-0.0.2.15.dist-info/LICENSE.md,sha256=5ZRvtTyCCFwz1THxDTjAu3Lidds9WjPvvzgVwPSYNDo,1042
78
- pytrilogy-0.0.2.15.dist-info/METADATA,sha256=u9wzNtWDmhTjKdAmncckSd1lZv1j_Rkefq6kxifmvCI,7907
79
- pytrilogy-0.0.2.15.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
80
- pytrilogy-0.0.2.15.dist-info/entry_points.txt,sha256=0petKryjvvtEfTlbZC1AuMFumH_WQ9v8A19LvoS6G6c,54
81
- pytrilogy-0.0.2.15.dist-info/top_level.txt,sha256=cAy__NW_eMAa_yT9UnUNlZLFfxcg6eimUAZ184cdNiE,8
82
- pytrilogy-0.0.2.15.dist-info/RECORD,,
77
+ pytrilogy-0.0.2.17.dist-info/LICENSE.md,sha256=5ZRvtTyCCFwz1THxDTjAu3Lidds9WjPvvzgVwPSYNDo,1042
78
+ pytrilogy-0.0.2.17.dist-info/METADATA,sha256=Qy6SlBRVmnn77Iq8QubcjHFBhhRpT0FN16RMXtODzVA,7907
79
+ pytrilogy-0.0.2.17.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
80
+ pytrilogy-0.0.2.17.dist-info/entry_points.txt,sha256=0petKryjvvtEfTlbZC1AuMFumH_WQ9v8A19LvoS6G6c,54
81
+ pytrilogy-0.0.2.17.dist-info/top_level.txt,sha256=cAy__NW_eMAa_yT9UnUNlZLFfxcg6eimUAZ184cdNiE,8
82
+ pytrilogy-0.0.2.17.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.15"
7
+ __version__ = "0.0.2.17"
8
8
 
9
9
  __all__ = ["parse", "Executor", "Dialects", "Environment", "CONFIG"]
trilogy/core/models.py CHANGED
@@ -2660,9 +2660,9 @@ class CTE(BaseModel):
2660
2660
  if isinstance(join, InstantiatedUnnestJoin):
2661
2661
  continue
2662
2662
  if join.left_cte.name == parent.name:
2663
- join.left_cte = ds_being_inlined
2663
+ join.inline_cte(parent)
2664
2664
  if join.right_cte.name == parent.name:
2665
- join.right_cte = ds_being_inlined
2665
+ join.inline_cte(parent)
2666
2666
  for k, v in self.source_map.items():
2667
2667
  if isinstance(v, list):
2668
2668
  self.source_map[k] = [
@@ -2885,34 +2885,38 @@ class JoinKey(BaseModel):
2885
2885
 
2886
2886
 
2887
2887
  class Join(BaseModel):
2888
- left_cte: CTE | Datasource
2889
- right_cte: CTE | Datasource
2888
+ left_cte: CTE
2889
+ right_cte: CTE
2890
2890
  jointype: JoinType
2891
2891
  joinkeys: List[JoinKey]
2892
2892
  joinkey_pairs: List[ConceptPair] | None = None
2893
+ inlined_ctes: set[str] = Field(default_factory=set)
2894
+
2895
+ def inline_cte(self, cte: CTE):
2896
+ self.inlined_ctes.add(cte.name)
2893
2897
 
2894
2898
  @property
2895
2899
  def left_name(self) -> str:
2896
- if isinstance(self.left_cte, Datasource):
2897
- return self.left_cte.identifier
2900
+ if self.left_cte.name in self.inlined_ctes:
2901
+ return self.left_cte.source.datasources[0].identifier
2898
2902
  return self.left_cte.name
2899
2903
 
2900
2904
  @property
2901
2905
  def right_name(self) -> str:
2902
- if isinstance(self.right_cte, Datasource):
2903
- return self.right_cte.identifier
2906
+ if self.right_cte.name in self.inlined_ctes:
2907
+ return self.right_cte.source.datasources[0].identifier
2904
2908
  return self.right_cte.name
2905
2909
 
2906
2910
  @property
2907
2911
  def left_ref(self) -> str:
2908
- if isinstance(self.left_cte, Datasource):
2909
- return f"{self.left_cte.safe_location} as {self.left_cte.identifier}"
2912
+ if self.left_cte.name in self.inlined_ctes:
2913
+ return f"{self.left_cte.source.datasources[0].safe_location} as {self.left_cte.source.datasources[0].identifier}"
2910
2914
  return self.left_cte.name
2911
2915
 
2912
2916
  @property
2913
2917
  def right_ref(self) -> str:
2914
- if isinstance(self.right_cte, Datasource):
2915
- return f"{self.right_cte.safe_location} as {self.right_cte.identifier}"
2918
+ if self.right_cte.name in self.inlined_ctes:
2919
+ return f"{self.right_cte.source.datasources[0].safe_location} as {self.right_cte.source.datasources[0].identifier}"
2916
2920
  return self.right_cte.name
2917
2921
 
2918
2922
  @property
trilogy/dialect/base.py CHANGED
@@ -608,6 +608,7 @@ class BaseDialect:
608
608
  join,
609
609
  self.QUOTE_CHARACTER,
610
610
  self.render_concept_sql,
611
+ self.render_expr,
611
612
  cte,
612
613
  self.UNNEST_MODE,
613
614
  )
trilogy/dialect/common.py CHANGED
@@ -1,6 +1,13 @@
1
- from trilogy.core.models import Join, InstantiatedUnnestJoin, CTE, Concept, Datasource
1
+ from trilogy.core.models import (
2
+ Join,
3
+ InstantiatedUnnestJoin,
4
+ CTE,
5
+ Concept,
6
+ Function,
7
+ RawColumnExpr,
8
+ )
2
9
  from trilogy.core.enums import UnnestMode, Modifier
3
- from typing import Optional, Callable
10
+ from typing import Callable
4
11
 
5
12
 
6
13
  def null_wrapper(lval: str, rval: str, modifiers: list[Modifier]) -> str:
@@ -21,19 +28,39 @@ def render_unnest(
21
28
  return f"{render_func(concept, cte, False)} as unnest_wrapper ({quote_character}{concept.safe_address}{quote_character})"
22
29
 
23
30
 
31
+ def render_join_concept(
32
+ name: str,
33
+ quote_character: str,
34
+ cte: CTE,
35
+ concept: Concept,
36
+ render_expr,
37
+ inlined_ctes: set[str],
38
+ ):
39
+ if cte.name in inlined_ctes:
40
+ ds = cte.source.datasources[0]
41
+ raw_content = ds.get_alias(concept)
42
+ if isinstance(raw_content, RawColumnExpr):
43
+ rval = raw_content.text
44
+ return rval
45
+ elif isinstance(raw_content, Function):
46
+ rval = render_expr(raw_content, cte=cte)
47
+ return rval
48
+ return f"{name}.{quote_character}{raw_content}{quote_character}"
49
+ return f"{name}.{quote_character}{concept.safe_address}{quote_character}"
50
+
51
+
24
52
  def render_join(
25
53
  join: Join | InstantiatedUnnestJoin,
26
54
  quote_character: str,
27
- render_func: Optional[Callable[[Concept, CTE, bool], str]] = None,
28
- cte: Optional[CTE] = None,
55
+ render_func: Callable[[Concept, CTE, bool], str],
56
+ render_expr_func: Callable[[Concept, CTE], str],
57
+ cte: CTE,
29
58
  unnest_mode: UnnestMode = UnnestMode.CROSS_APPLY,
30
59
  ) -> str | None:
31
60
  # {% for key in join.joinkeys %}{{ key.inner }} = {{ key.outer}}{% endfor %}
32
61
  if isinstance(join, InstantiatedUnnestJoin):
33
62
  if unnest_mode == UnnestMode.DIRECT:
34
63
  return None
35
- if not render_func:
36
- raise ValueError("must provide a render function to build an unnest joins")
37
64
  if not cte:
38
65
  raise ValueError("must provide a cte to build an unnest joins")
39
66
  if unnest_mode == UnnestMode.CROSS_JOIN:
@@ -46,8 +73,22 @@ def render_join(
46
73
  right_base = join.right_ref
47
74
  base_joinkeys = [
48
75
  null_wrapper(
49
- f"{left_name}.{quote_character}{join.left_cte.get_alias(key.concept) if isinstance(join.left_cte, Datasource) else key.concept.safe_address}{quote_character}",
50
- f"{right_name}.{quote_character}{join.right_cte.get_alias(key.concept) if isinstance(join.right_cte, Datasource) else key.concept.safe_address}{quote_character}",
76
+ render_join_concept(
77
+ left_name,
78
+ quote_character,
79
+ join.left_cte,
80
+ key.concept,
81
+ render_expr_func,
82
+ join.inlined_ctes,
83
+ ),
84
+ render_join_concept(
85
+ right_name,
86
+ quote_character,
87
+ join.right_cte,
88
+ key.concept,
89
+ render_expr_func,
90
+ join.inlined_ctes,
91
+ ),
51
92
  modifiers=key.concept.modifiers or [],
52
93
  )
53
94
  for key in join.joinkeys
@@ -56,8 +97,22 @@ def render_join(
56
97
  base_joinkeys.extend(
57
98
  [
58
99
  null_wrapper(
59
- f"{left_name}.{quote_character}{join.left_cte.get_alias(pair.left) if isinstance(join.left_cte, Datasource) else pair.left.safe_address}{quote_character}",
60
- f"{right_name}.{quote_character}{join.right_cte.get_alias(pair.right) if isinstance(join.right_cte, Datasource) else pair.right.safe_address}{quote_character}",
100
+ render_join_concept(
101
+ left_name,
102
+ quote_character,
103
+ join.left_cte,
104
+ pair.left,
105
+ render_expr_func,
106
+ join.inlined_ctes,
107
+ ),
108
+ render_join_concept(
109
+ right_name,
110
+ quote_character,
111
+ join.right_cte,
112
+ pair.right,
113
+ render_expr_func,
114
+ join.inlined_ctes,
115
+ ),
61
116
  modifiers=pair.modifiers
62
117
  + (pair.left.modifiers or [])
63
118
  + (pair.right.modifiers or []),
trilogy/executor.py CHANGED
@@ -129,6 +129,11 @@ class Executor(object):
129
129
  ["name"],
130
130
  )
131
131
 
132
+ @execute_query.register
133
+ def _(self, query: str) -> CursorResult:
134
+
135
+ return self.execute_text(query)[-1]
136
+
132
137
  @execute_query.register
133
138
  def _(self, query: SelectStatement) -> CursorResult:
134
139
  sql = self.generator.generate_queries(
@@ -600,7 +600,7 @@ class ParseToObjects(Transformer):
600
600
  return args[3:-3]
601
601
 
602
602
  def raw_column_assignment(self, args):
603
- return RawColumnExpr(text=args[0])
603
+ return RawColumnExpr(text=args[1])
604
604
 
605
605
  @v_args(meta=True)
606
606
  def datasource(self, meta: Meta, args):
trilogy/parsing/render.py CHANGED
@@ -328,6 +328,8 @@ class Renderer:
328
328
  inputs = ",".join(self.to_string(c) for c in arg.arguments)
329
329
  if arg.operator == FunctionType.CONSTANT:
330
330
  return f"{inputs}"
331
+ if arg.operator == FunctionType.INDEX_ACCESS:
332
+ return f"{self.to_string(arg.arguments[0])}[{self.to_string(arg.arguments[1])}]"
331
333
  return f"{arg.operator.value}({inputs})"
332
334
 
333
335
  @to_string.register
@@ -47,9 +47,11 @@
47
47
 
48
48
  //column_assignment
49
49
  //figure out if we want static
50
- column_assignment: ((IDENTIFIER | _static_functions | raw_column_assignment ) ":" concept_assignment)
50
+ column_assignment: (raw_column_assignment | IDENTIFIER | _static_functions ) ":" concept_assignment
51
+
52
+ RAW_ENTRY.1: /raw\s*\(/s
51
53
 
52
- raw_column_assignment: "raw" "(" MULTILINE_STRING ")"
54
+ raw_column_assignment: RAW_ENTRY MULTILINE_STRING ")"
53
55
 
54
56
  column_assignment_list : column_assignment ("," column_assignment)* ","?
55
57