pytrilogy 0.3.149__cp313-cp313-win_amd64.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.
Files changed (207) hide show
  1. LICENSE.md +19 -0
  2. _preql_import_resolver/__init__.py +5 -0
  3. _preql_import_resolver/_preql_import_resolver.cp313-win_amd64.pyd +0 -0
  4. pytrilogy-0.3.149.dist-info/METADATA +555 -0
  5. pytrilogy-0.3.149.dist-info/RECORD +207 -0
  6. pytrilogy-0.3.149.dist-info/WHEEL +4 -0
  7. pytrilogy-0.3.149.dist-info/entry_points.txt +2 -0
  8. pytrilogy-0.3.149.dist-info/licenses/LICENSE.md +19 -0
  9. trilogy/__init__.py +27 -0
  10. trilogy/ai/README.md +10 -0
  11. trilogy/ai/__init__.py +19 -0
  12. trilogy/ai/constants.py +92 -0
  13. trilogy/ai/conversation.py +107 -0
  14. trilogy/ai/enums.py +7 -0
  15. trilogy/ai/execute.py +50 -0
  16. trilogy/ai/models.py +34 -0
  17. trilogy/ai/prompts.py +100 -0
  18. trilogy/ai/providers/__init__.py +0 -0
  19. trilogy/ai/providers/anthropic.py +106 -0
  20. trilogy/ai/providers/base.py +24 -0
  21. trilogy/ai/providers/google.py +146 -0
  22. trilogy/ai/providers/openai.py +89 -0
  23. trilogy/ai/providers/utils.py +68 -0
  24. trilogy/authoring/README.md +3 -0
  25. trilogy/authoring/__init__.py +148 -0
  26. trilogy/constants.py +119 -0
  27. trilogy/core/README.md +52 -0
  28. trilogy/core/__init__.py +0 -0
  29. trilogy/core/constants.py +6 -0
  30. trilogy/core/enums.py +454 -0
  31. trilogy/core/env_processor.py +239 -0
  32. trilogy/core/environment_helpers.py +320 -0
  33. trilogy/core/ergonomics.py +193 -0
  34. trilogy/core/exceptions.py +123 -0
  35. trilogy/core/functions.py +1240 -0
  36. trilogy/core/graph_models.py +142 -0
  37. trilogy/core/internal.py +85 -0
  38. trilogy/core/models/__init__.py +0 -0
  39. trilogy/core/models/author.py +2670 -0
  40. trilogy/core/models/build.py +2603 -0
  41. trilogy/core/models/build_environment.py +165 -0
  42. trilogy/core/models/core.py +506 -0
  43. trilogy/core/models/datasource.py +436 -0
  44. trilogy/core/models/environment.py +756 -0
  45. trilogy/core/models/execute.py +1213 -0
  46. trilogy/core/optimization.py +251 -0
  47. trilogy/core/optimizations/__init__.py +12 -0
  48. trilogy/core/optimizations/base_optimization.py +17 -0
  49. trilogy/core/optimizations/hide_unused_concept.py +47 -0
  50. trilogy/core/optimizations/inline_datasource.py +102 -0
  51. trilogy/core/optimizations/predicate_pushdown.py +245 -0
  52. trilogy/core/processing/README.md +94 -0
  53. trilogy/core/processing/READMEv2.md +121 -0
  54. trilogy/core/processing/VIRTUAL_UNNEST.md +30 -0
  55. trilogy/core/processing/__init__.py +0 -0
  56. trilogy/core/processing/concept_strategies_v3.py +508 -0
  57. trilogy/core/processing/constants.py +15 -0
  58. trilogy/core/processing/discovery_node_factory.py +451 -0
  59. trilogy/core/processing/discovery_utility.py +548 -0
  60. trilogy/core/processing/discovery_validation.py +167 -0
  61. trilogy/core/processing/graph_utils.py +43 -0
  62. trilogy/core/processing/node_generators/README.md +9 -0
  63. trilogy/core/processing/node_generators/__init__.py +31 -0
  64. trilogy/core/processing/node_generators/basic_node.py +160 -0
  65. trilogy/core/processing/node_generators/common.py +270 -0
  66. trilogy/core/processing/node_generators/constant_node.py +38 -0
  67. trilogy/core/processing/node_generators/filter_node.py +315 -0
  68. trilogy/core/processing/node_generators/group_node.py +213 -0
  69. trilogy/core/processing/node_generators/group_to_node.py +117 -0
  70. trilogy/core/processing/node_generators/multiselect_node.py +207 -0
  71. trilogy/core/processing/node_generators/node_merge_node.py +695 -0
  72. trilogy/core/processing/node_generators/recursive_node.py +88 -0
  73. trilogy/core/processing/node_generators/rowset_node.py +165 -0
  74. trilogy/core/processing/node_generators/select_helpers/__init__.py +0 -0
  75. trilogy/core/processing/node_generators/select_helpers/datasource_injection.py +261 -0
  76. trilogy/core/processing/node_generators/select_merge_node.py +846 -0
  77. trilogy/core/processing/node_generators/select_node.py +95 -0
  78. trilogy/core/processing/node_generators/synonym_node.py +98 -0
  79. trilogy/core/processing/node_generators/union_node.py +91 -0
  80. trilogy/core/processing/node_generators/unnest_node.py +182 -0
  81. trilogy/core/processing/node_generators/window_node.py +201 -0
  82. trilogy/core/processing/nodes/README.md +28 -0
  83. trilogy/core/processing/nodes/__init__.py +179 -0
  84. trilogy/core/processing/nodes/base_node.py +522 -0
  85. trilogy/core/processing/nodes/filter_node.py +75 -0
  86. trilogy/core/processing/nodes/group_node.py +194 -0
  87. trilogy/core/processing/nodes/merge_node.py +420 -0
  88. trilogy/core/processing/nodes/recursive_node.py +46 -0
  89. trilogy/core/processing/nodes/select_node_v2.py +242 -0
  90. trilogy/core/processing/nodes/union_node.py +53 -0
  91. trilogy/core/processing/nodes/unnest_node.py +62 -0
  92. trilogy/core/processing/nodes/window_node.py +56 -0
  93. trilogy/core/processing/utility.py +823 -0
  94. trilogy/core/query_processor.py +604 -0
  95. trilogy/core/statements/README.md +35 -0
  96. trilogy/core/statements/__init__.py +0 -0
  97. trilogy/core/statements/author.py +536 -0
  98. trilogy/core/statements/build.py +0 -0
  99. trilogy/core/statements/common.py +20 -0
  100. trilogy/core/statements/execute.py +155 -0
  101. trilogy/core/table_processor.py +66 -0
  102. trilogy/core/utility.py +8 -0
  103. trilogy/core/validation/README.md +46 -0
  104. trilogy/core/validation/__init__.py +0 -0
  105. trilogy/core/validation/common.py +161 -0
  106. trilogy/core/validation/concept.py +146 -0
  107. trilogy/core/validation/datasource.py +227 -0
  108. trilogy/core/validation/environment.py +73 -0
  109. trilogy/core/validation/fix.py +256 -0
  110. trilogy/dialect/__init__.py +32 -0
  111. trilogy/dialect/base.py +1432 -0
  112. trilogy/dialect/bigquery.py +314 -0
  113. trilogy/dialect/common.py +147 -0
  114. trilogy/dialect/config.py +159 -0
  115. trilogy/dialect/dataframe.py +50 -0
  116. trilogy/dialect/duckdb.py +397 -0
  117. trilogy/dialect/enums.py +151 -0
  118. trilogy/dialect/metadata.py +173 -0
  119. trilogy/dialect/mock.py +190 -0
  120. trilogy/dialect/postgres.py +117 -0
  121. trilogy/dialect/presto.py +110 -0
  122. trilogy/dialect/results.py +89 -0
  123. trilogy/dialect/snowflake.py +129 -0
  124. trilogy/dialect/sql_server.py +137 -0
  125. trilogy/engine.py +48 -0
  126. trilogy/execution/__init__.py +17 -0
  127. trilogy/execution/config.py +119 -0
  128. trilogy/execution/state/__init__.py +0 -0
  129. trilogy/execution/state/exceptions.py +26 -0
  130. trilogy/execution/state/file_state_store.py +0 -0
  131. trilogy/execution/state/sqllite_state_store.py +0 -0
  132. trilogy/execution/state/state_store.py +406 -0
  133. trilogy/executor.py +692 -0
  134. trilogy/hooks/__init__.py +4 -0
  135. trilogy/hooks/base_hook.py +40 -0
  136. trilogy/hooks/graph_hook.py +135 -0
  137. trilogy/hooks/query_debugger.py +166 -0
  138. trilogy/metadata/__init__.py +0 -0
  139. trilogy/parser.py +10 -0
  140. trilogy/parsing/README.md +21 -0
  141. trilogy/parsing/__init__.py +0 -0
  142. trilogy/parsing/common.py +1069 -0
  143. trilogy/parsing/config.py +5 -0
  144. trilogy/parsing/exceptions.py +8 -0
  145. trilogy/parsing/helpers.py +1 -0
  146. trilogy/parsing/parse_engine.py +2876 -0
  147. trilogy/parsing/render.py +775 -0
  148. trilogy/parsing/trilogy.lark +546 -0
  149. trilogy/py.typed +0 -0
  150. trilogy/render.py +45 -0
  151. trilogy/scripts/README.md +9 -0
  152. trilogy/scripts/__init__.py +0 -0
  153. trilogy/scripts/agent.py +41 -0
  154. trilogy/scripts/agent_info.py +306 -0
  155. trilogy/scripts/common.py +432 -0
  156. trilogy/scripts/dependency/Cargo.lock +617 -0
  157. trilogy/scripts/dependency/Cargo.toml +39 -0
  158. trilogy/scripts/dependency/README.md +131 -0
  159. trilogy/scripts/dependency/build.sh +25 -0
  160. trilogy/scripts/dependency/src/directory_resolver.rs +387 -0
  161. trilogy/scripts/dependency/src/lib.rs +16 -0
  162. trilogy/scripts/dependency/src/main.rs +770 -0
  163. trilogy/scripts/dependency/src/parser.rs +435 -0
  164. trilogy/scripts/dependency/src/preql.pest +208 -0
  165. trilogy/scripts/dependency/src/python_bindings.rs +311 -0
  166. trilogy/scripts/dependency/src/resolver.rs +716 -0
  167. trilogy/scripts/dependency/tests/base.preql +3 -0
  168. trilogy/scripts/dependency/tests/cli_integration.rs +377 -0
  169. trilogy/scripts/dependency/tests/customer.preql +6 -0
  170. trilogy/scripts/dependency/tests/main.preql +9 -0
  171. trilogy/scripts/dependency/tests/orders.preql +7 -0
  172. trilogy/scripts/dependency/tests/test_data/base.preql +9 -0
  173. trilogy/scripts/dependency/tests/test_data/consumer.preql +1 -0
  174. trilogy/scripts/dependency.py +323 -0
  175. trilogy/scripts/display.py +555 -0
  176. trilogy/scripts/environment.py +59 -0
  177. trilogy/scripts/fmt.py +32 -0
  178. trilogy/scripts/ingest.py +487 -0
  179. trilogy/scripts/ingest_helpers/__init__.py +1 -0
  180. trilogy/scripts/ingest_helpers/foreign_keys.py +123 -0
  181. trilogy/scripts/ingest_helpers/formatting.py +93 -0
  182. trilogy/scripts/ingest_helpers/typing.py +161 -0
  183. trilogy/scripts/init.py +105 -0
  184. trilogy/scripts/parallel_execution.py +762 -0
  185. trilogy/scripts/plan.py +189 -0
  186. trilogy/scripts/refresh.py +161 -0
  187. trilogy/scripts/run.py +79 -0
  188. trilogy/scripts/serve.py +202 -0
  189. trilogy/scripts/serve_helpers/__init__.py +41 -0
  190. trilogy/scripts/serve_helpers/file_discovery.py +142 -0
  191. trilogy/scripts/serve_helpers/index_generation.py +206 -0
  192. trilogy/scripts/serve_helpers/models.py +38 -0
  193. trilogy/scripts/single_execution.py +131 -0
  194. trilogy/scripts/testing.py +143 -0
  195. trilogy/scripts/trilogy.py +75 -0
  196. trilogy/std/__init__.py +0 -0
  197. trilogy/std/color.preql +3 -0
  198. trilogy/std/date.preql +13 -0
  199. trilogy/std/display.preql +18 -0
  200. trilogy/std/geography.preql +22 -0
  201. trilogy/std/metric.preql +15 -0
  202. trilogy/std/money.preql +67 -0
  203. trilogy/std/net.preql +14 -0
  204. trilogy/std/ranking.preql +7 -0
  205. trilogy/std/report.preql +5 -0
  206. trilogy/std/semantic.preql +6 -0
  207. trilogy/utility.py +34 -0
@@ -0,0 +1,207 @@
1
+ from collections import defaultdict
2
+ from itertools import combinations
3
+ from typing import List
4
+
5
+ from trilogy.constants import logger
6
+ from trilogy.core.enums import JoinType, Modifier, Purpose
7
+ from trilogy.core.models.build import (
8
+ BuildConcept,
9
+ BuildGrain,
10
+ BuildMultiSelectLineage,
11
+ BuildWhereClause,
12
+ )
13
+ from trilogy.core.models.build_environment import BuildEnvironment
14
+ from trilogy.core.processing.node_generators.common import resolve_join_order
15
+ from trilogy.core.processing.nodes import History, MergeNode, NodeJoin
16
+ from trilogy.core.processing.nodes.base_node import StrategyNode
17
+ from trilogy.core.processing.utility import concept_to_relevant_joins, padding
18
+
19
+ LOGGER_PREFIX = "[GEN_MULTISELECT_NODE]"
20
+
21
+
22
+ def extra_align_joins(
23
+ base: BuildMultiSelectLineage,
24
+ environment: BuildEnvironment,
25
+ parents: List[StrategyNode],
26
+ ) -> List[NodeJoin]:
27
+ node_merge_concept_map = defaultdict(list)
28
+ output = []
29
+ for align in base.align.items:
30
+ jc = environment.concepts[align.aligned_concept]
31
+ if jc.purpose == Purpose.CONSTANT:
32
+ continue
33
+ for node in parents:
34
+ for item in align.concepts:
35
+ if item in node.output_lcl:
36
+ node_merge_concept_map[node].append(jc)
37
+
38
+ for left, right in combinations(node_merge_concept_map.keys(), 2):
39
+ matched_concepts = [
40
+ x
41
+ for x in node_merge_concept_map[left]
42
+ if x in node_merge_concept_map[right]
43
+ ]
44
+ output.append(
45
+ NodeJoin(
46
+ left_node=left,
47
+ right_node=right,
48
+ concepts=matched_concepts,
49
+ join_type=JoinType.FULL,
50
+ modifiers=[Modifier.NULLABLE],
51
+ )
52
+ )
53
+ return resolve_join_order(output)
54
+
55
+
56
+ def gen_multiselect_node(
57
+ concept: BuildConcept,
58
+ local_optional: List[BuildConcept],
59
+ environment: BuildEnvironment,
60
+ g,
61
+ depth: int,
62
+ source_concepts,
63
+ history: History,
64
+ conditions: BuildWhereClause | None = None,
65
+ ) -> MergeNode | None:
66
+ from trilogy.core.query_processor import get_query_node
67
+
68
+ if not isinstance(concept.lineage, BuildMultiSelectLineage):
69
+ logger.info(
70
+ f"{padding(depth)}{LOGGER_PREFIX} Cannot generate multiselect node for {concept}"
71
+ )
72
+ return None
73
+ lineage: BuildMultiSelectLineage = concept.lineage
74
+
75
+ base_parents: List[StrategyNode] = []
76
+ partial = []
77
+ for select in lineage.selects:
78
+
79
+ snode: StrategyNode = get_query_node(history.base_environment, select)
80
+
81
+ logger.info(
82
+ f"{padding(depth)}{LOGGER_PREFIX} Fetched parent node with outputs {select.output_components}"
83
+ )
84
+ if not snode:
85
+ logger.info(
86
+ f"{padding(depth)}{LOGGER_PREFIX} Cannot generate multiselect node for {concept}"
87
+ )
88
+ return None
89
+ merge_concepts: list[BuildConcept] = []
90
+ for x in [*snode.output_concepts]:
91
+ merge_name = lineage.get_merge_concept(x)
92
+ if merge_name:
93
+ merge = environment.concepts[merge_name]
94
+ snode.output_concepts.append(merge)
95
+ merge_concepts.append(merge)
96
+ # clear cache so QPS
97
+ snode.rebuild_cache()
98
+ for mc in merge_concepts:
99
+ assert (
100
+ mc.address in snode.resolve().output_concepts
101
+ ), f"missing {mc} in {snode.resolve().output_concepts}"
102
+ base_parents.append(snode)
103
+ if select.where_clause:
104
+ for item in select.output_components:
105
+ partial.append(item)
106
+ logger.info(snode.hidden_concepts)
107
+
108
+ node_joins = extra_align_joins(lineage, environment, base_parents)
109
+ logger.info(
110
+ f"Non-hidden {[x for y in base_parents for x in y.output_concepts if x.address not in y.hidden_concepts]}"
111
+ )
112
+ node = MergeNode(
113
+ input_concepts=[
114
+ x
115
+ for y in base_parents
116
+ for x in y.output_concepts
117
+ if x.address not in y.hidden_concepts
118
+ ],
119
+ output_concepts=[
120
+ x
121
+ for y in base_parents
122
+ for x in y.output_concepts
123
+ if x.address not in y.hidden_concepts
124
+ ],
125
+ environment=environment,
126
+ depth=depth,
127
+ parents=base_parents,
128
+ node_joins=node_joins,
129
+ grain=BuildGrain.from_concepts(
130
+ [
131
+ x
132
+ for y in base_parents
133
+ for x in y.output_concepts
134
+ if x.address not in y.hidden_concepts
135
+ ],
136
+ environment=environment,
137
+ ),
138
+ )
139
+
140
+ enrichment = set([x.address for x in local_optional])
141
+
142
+ multiselect_relevant = [
143
+ environment.concepts[x]
144
+ for x in lineage.derived_concepts
145
+ if x == concept.address or x in enrichment
146
+ ]
147
+ additional_relevant = [x for x in node.output_concepts if x.address in enrichment]
148
+ # add in other other concepts
149
+
150
+ node.set_output_concepts(multiselect_relevant + additional_relevant)
151
+
152
+ # node.add_partial_concepts(partial)
153
+ # if select.where_clause:
154
+ # for item in additional_relevant:
155
+ # node.partial_concepts.append(item)
156
+ node.grain = BuildGrain.from_concepts(node.output_concepts, environment=environment)
157
+ node.rebuild_cache()
158
+ # we need a better API for refreshing a nodes QDS
159
+ possible_joins = concept_to_relevant_joins(additional_relevant)
160
+ if not local_optional:
161
+ logger.info(
162
+ f"{padding(depth)}{LOGGER_PREFIX} no enrichment required for multiselect node; exiting early"
163
+ )
164
+ return node
165
+ if not possible_joins:
166
+ logger.info(
167
+ f"{padding(depth)}{LOGGER_PREFIX} no possible joins for multiselect node; exiting early"
168
+ )
169
+ return node
170
+ if all(
171
+ [x.address in [y.address for y in node.output_concepts] for x in local_optional]
172
+ ):
173
+ logger.info(
174
+ f"{padding(depth)}{LOGGER_PREFIX} all enriched concepts returned from base multiselect node; exiting early"
175
+ )
176
+ return node
177
+ logger.info(
178
+ f"{padding(depth)}{LOGGER_PREFIX} Missing required concepts {[x for x in local_optional if x.address not in [y.address for y in node.output_concepts]]}"
179
+ )
180
+ enrich_node: MergeNode = source_concepts( # this fetches the parent + join keys
181
+ # to then connect to the rest of the query
182
+ mandatory_list=additional_relevant + local_optional,
183
+ environment=environment,
184
+ g=g,
185
+ depth=depth + 1,
186
+ history=history,
187
+ conditions=conditions,
188
+ )
189
+ if not enrich_node:
190
+ logger.info(
191
+ f"{padding(depth)}{LOGGER_PREFIX} Cannot generate rowset enrichment node for {concept} with optional {local_optional}, returning just rowset node"
192
+ )
193
+ return node
194
+
195
+ return MergeNode(
196
+ input_concepts=enrich_node.output_concepts + node.output_concepts,
197
+ output_concepts=node.output_concepts + local_optional,
198
+ environment=environment,
199
+ depth=depth,
200
+ parents=[
201
+ # this node gets the multiselect
202
+ node,
203
+ # this node gets enrichment
204
+ enrich_node,
205
+ ],
206
+ partial_concepts=node.partial_concepts,
207
+ )