pytrilogy 0.0.2.14__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.14
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=PE4Dy9UVhAPcaUZRWLaQUxC1U27eYhtTOKd-DOtVDh8,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
@@ -31,12 +31,12 @@ trilogy/core/processing/utility.py,sha256=jFLZmzxHq94q29FInr8XjS5YiqJOPPBYqh8Tlg
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=IHj5jEloUe5yojGRLAzt35FcfHqGviWQdS8ETyvr39Q,3292
33
33
  trilogy/core/processing/node_generators/common.py,sha256=3_Ivrq_wersDZ5pnvyHvsAUc07mRggxRGTiDq47O0Rk,8840
34
- trilogy/core/processing/node_generators/filter_node.py,sha256=Tq9_Q6Xe95_-0S5H1EfCgwmKwVfXNoiclqV8QHKhvig,7723
34
+ trilogy/core/processing/node_generators/filter_node.py,sha256=gCiv76Cu4idkZRyGkZG44BO50mTqrxYdUSDcZdpd0i4,7724
35
35
  trilogy/core/processing/node_generators/group_node.py,sha256=G7SrU2X5kjgzeqzzpnPscQBTDcFMc4m7TR6n8VHLC_A,3762
36
36
  trilogy/core/processing/node_generators/group_to_node.py,sha256=yX0uw6YMxhyWVRMZoMFzEkJe3tB5ByFqrTnuRWVcRh4,2446
37
37
  trilogy/core/processing/node_generators/multiselect_node.py,sha256=OUjndYjA8xR6yKr-J7R-JxDeYfO6DxmMNNcJiFJzk7g,6138
38
38
  trilogy/core/processing/node_generators/node_merge_node.py,sha256=D_jsnfoLMrQc08_JvT0wEDvjyzJAxBpdcZFyDN-feV0,13192
39
- trilogy/core/processing/node_generators/rowset_node.py,sha256=qYt0Ngk-WpmAA_gZZORXR-WpLdFqyYAuJiZnrxBmNvw,4201
39
+ trilogy/core/processing/node_generators/rowset_node.py,sha256=tc8jt9bMq_HIdLM24sx_ivc7tTlpucQDEvsC2nkOtrY,4454
40
40
  trilogy/core/processing/node_generators/select_node.py,sha256=XSMA4kvFdoXlfCpbciXXkbexXkemwUorcAU6P3EwuZY,19843
41
41
  trilogy/core/processing/node_generators/unnest_node.py,sha256=aZeixbOzMtXi7BPahKr9bOkIhTciyD9Klsj0kZ56F6s,2189
42
42
  trilogy/core/processing/node_generators/window_node.py,sha256=LSlXe41elFGVRlxRX3MEFimhduGn3o5WE0kLx2JtA4M,3322
@@ -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.14.dist-info/LICENSE.md,sha256=5ZRvtTyCCFwz1THxDTjAu3Lidds9WjPvvzgVwPSYNDo,1042
78
- pytrilogy-0.0.2.14.dist-info/METADATA,sha256=MqQy1FLZVBpbDh36uTVMwYujLjDB4JkYdz9r5cytOgA,7907
79
- pytrilogy-0.0.2.14.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
80
- pytrilogy-0.0.2.14.dist-info/entry_points.txt,sha256=0petKryjvvtEfTlbZC1AuMFumH_WQ9v8A19LvoS6G6c,54
81
- pytrilogy-0.0.2.14.dist-info/top_level.txt,sha256=cAy__NW_eMAa_yT9UnUNlZLFfxcg6eimUAZ184cdNiE,8
82
- pytrilogy-0.0.2.14.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.14"
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
@@ -212,5 +212,5 @@ def gen_filter_node(
212
212
  # this node fetches only what we need to filter
213
213
  filter_node,
214
214
  enrich_node,
215
- ]
215
+ ],
216
216
  )
@@ -71,12 +71,22 @@ def gen_rowset_node(
71
71
  and x.derivation != PurposeLineage.ROWSET
72
72
  ]
73
73
  node.hide_output_concepts(final_hidden)
74
- # assume grain to be output of select
75
- # but don't include anything aggregate at this point
76
- assert node.resolution_cache
77
74
 
75
+ assert node.resolution_cache
76
+ # assume grain to be output of select
77
+ # but don't include anything hidden(the non-rowset concepts)
78
78
  node.grain = concept_list_to_grain(
79
- node.output_concepts, parent_sources=node.resolution_cache.datasources
79
+ [
80
+ x
81
+ for x in node.output_concepts
82
+ if x.address
83
+ not in [
84
+ y.address
85
+ for y in node.hidden_concepts
86
+ if y.derivation != PurposeLineage.ROWSET
87
+ ]
88
+ ],
89
+ parent_sources=node.resolution_cache.datasources,
80
90
  )
81
91
 
82
92
  node.rebuild_cache()
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