pytrilogy 0.3.138__cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.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 (182) hide show
  1. LICENSE.md +19 -0
  2. _preql_import_resolver/__init__.py +5 -0
  3. _preql_import_resolver/_preql_import_resolver.cpython-311-x86_64-linux-gnu.so +0 -0
  4. pytrilogy-0.3.138.dist-info/METADATA +525 -0
  5. pytrilogy-0.3.138.dist-info/RECORD +182 -0
  6. pytrilogy-0.3.138.dist-info/WHEEL +5 -0
  7. pytrilogy-0.3.138.dist-info/entry_points.txt +2 -0
  8. pytrilogy-0.3.138.dist-info/licenses/LICENSE.md +19 -0
  9. trilogy/__init__.py +9 -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 +87 -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 +143 -0
  26. trilogy/constants.py +113 -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 +443 -0
  31. trilogy/core/env_processor.py +120 -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 +1227 -0
  36. trilogy/core/graph_models.py +139 -0
  37. trilogy/core/internal.py +85 -0
  38. trilogy/core/models/__init__.py +0 -0
  39. trilogy/core/models/author.py +2672 -0
  40. trilogy/core/models/build.py +2521 -0
  41. trilogy/core/models/build_environment.py +180 -0
  42. trilogy/core/models/core.py +494 -0
  43. trilogy/core/models/datasource.py +322 -0
  44. trilogy/core/models/environment.py +748 -0
  45. trilogy/core/models/execute.py +1177 -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 +517 -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 +268 -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 +205 -0
  71. trilogy/core/processing/node_generators/node_merge_node.py +653 -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 +748 -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 +519 -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 +596 -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 +106 -0
  110. trilogy/dialect/__init__.py +32 -0
  111. trilogy/dialect/base.py +1359 -0
  112. trilogy/dialect/bigquery.py +256 -0
  113. trilogy/dialect/common.py +147 -0
  114. trilogy/dialect/config.py +144 -0
  115. trilogy/dialect/dataframe.py +50 -0
  116. trilogy/dialect/duckdb.py +177 -0
  117. trilogy/dialect/enums.py +147 -0
  118. trilogy/dialect/metadata.py +173 -0
  119. trilogy/dialect/mock.py +190 -0
  120. trilogy/dialect/postgres.py +91 -0
  121. trilogy/dialect/presto.py +104 -0
  122. trilogy/dialect/results.py +89 -0
  123. trilogy/dialect/snowflake.py +90 -0
  124. trilogy/dialect/sql_server.py +92 -0
  125. trilogy/engine.py +48 -0
  126. trilogy/execution/config.py +75 -0
  127. trilogy/executor.py +568 -0
  128. trilogy/hooks/__init__.py +4 -0
  129. trilogy/hooks/base_hook.py +40 -0
  130. trilogy/hooks/graph_hook.py +139 -0
  131. trilogy/hooks/query_debugger.py +166 -0
  132. trilogy/metadata/__init__.py +0 -0
  133. trilogy/parser.py +10 -0
  134. trilogy/parsing/README.md +21 -0
  135. trilogy/parsing/__init__.py +0 -0
  136. trilogy/parsing/common.py +1069 -0
  137. trilogy/parsing/config.py +5 -0
  138. trilogy/parsing/exceptions.py +8 -0
  139. trilogy/parsing/helpers.py +1 -0
  140. trilogy/parsing/parse_engine.py +2813 -0
  141. trilogy/parsing/render.py +750 -0
  142. trilogy/parsing/trilogy.lark +540 -0
  143. trilogy/py.typed +0 -0
  144. trilogy/render.py +42 -0
  145. trilogy/scripts/README.md +7 -0
  146. trilogy/scripts/__init__.py +0 -0
  147. trilogy/scripts/dependency/Cargo.lock +617 -0
  148. trilogy/scripts/dependency/Cargo.toml +39 -0
  149. trilogy/scripts/dependency/README.md +131 -0
  150. trilogy/scripts/dependency/build.sh +25 -0
  151. trilogy/scripts/dependency/src/directory_resolver.rs +162 -0
  152. trilogy/scripts/dependency/src/lib.rs +16 -0
  153. trilogy/scripts/dependency/src/main.rs +770 -0
  154. trilogy/scripts/dependency/src/parser.rs +435 -0
  155. trilogy/scripts/dependency/src/preql.pest +208 -0
  156. trilogy/scripts/dependency/src/python_bindings.rs +289 -0
  157. trilogy/scripts/dependency/src/resolver.rs +716 -0
  158. trilogy/scripts/dependency/tests/base.preql +3 -0
  159. trilogy/scripts/dependency/tests/cli_integration.rs +377 -0
  160. trilogy/scripts/dependency/tests/customer.preql +6 -0
  161. trilogy/scripts/dependency/tests/main.preql +9 -0
  162. trilogy/scripts/dependency/tests/orders.preql +7 -0
  163. trilogy/scripts/dependency/tests/test_data/base.preql +9 -0
  164. trilogy/scripts/dependency/tests/test_data/consumer.preql +1 -0
  165. trilogy/scripts/dependency.py +323 -0
  166. trilogy/scripts/display.py +460 -0
  167. trilogy/scripts/environment.py +46 -0
  168. trilogy/scripts/parallel_execution.py +483 -0
  169. trilogy/scripts/single_execution.py +131 -0
  170. trilogy/scripts/trilogy.py +772 -0
  171. trilogy/std/__init__.py +0 -0
  172. trilogy/std/color.preql +3 -0
  173. trilogy/std/date.preql +13 -0
  174. trilogy/std/display.preql +18 -0
  175. trilogy/std/geography.preql +22 -0
  176. trilogy/std/metric.preql +15 -0
  177. trilogy/std/money.preql +67 -0
  178. trilogy/std/net.preql +14 -0
  179. trilogy/std/ranking.preql +7 -0
  180. trilogy/std/report.preql +5 -0
  181. trilogy/std/semantic.preql +6 -0
  182. trilogy/utility.py +34 -0
@@ -0,0 +1,205 @@
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 = []
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 mc in snode.resolve().output_concepts
100
+ base_parents.append(snode)
101
+ if select.where_clause:
102
+ for item in select.output_components:
103
+ partial.append(item)
104
+ logger.info(snode.hidden_concepts)
105
+
106
+ node_joins = extra_align_joins(lineage, environment, base_parents)
107
+ logger.info(
108
+ f"Non-hidden {[x for y in base_parents for x in y.output_concepts if x.address not in y.hidden_concepts]}"
109
+ )
110
+ node = MergeNode(
111
+ input_concepts=[
112
+ x
113
+ for y in base_parents
114
+ for x in y.output_concepts
115
+ if x.address not in y.hidden_concepts
116
+ ],
117
+ output_concepts=[
118
+ x
119
+ for y in base_parents
120
+ for x in y.output_concepts
121
+ if x.address not in y.hidden_concepts
122
+ ],
123
+ environment=environment,
124
+ depth=depth,
125
+ parents=base_parents,
126
+ node_joins=node_joins,
127
+ grain=BuildGrain.from_concepts(
128
+ [
129
+ x
130
+ for y in base_parents
131
+ for x in y.output_concepts
132
+ if x.address not in y.hidden_concepts
133
+ ],
134
+ environment=environment,
135
+ ),
136
+ )
137
+
138
+ enrichment = set([x.address for x in local_optional])
139
+
140
+ multiselect_relevant = [
141
+ environment.concepts[x]
142
+ for x in lineage.derived_concepts
143
+ if x == concept.address or x in enrichment
144
+ ]
145
+ additional_relevant = [x for x in node.output_concepts if x.address in enrichment]
146
+ # add in other other concepts
147
+
148
+ node.set_output_concepts(multiselect_relevant + additional_relevant)
149
+
150
+ # node.add_partial_concepts(partial)
151
+ # if select.where_clause:
152
+ # for item in additional_relevant:
153
+ # node.partial_concepts.append(item)
154
+ node.grain = BuildGrain.from_concepts(node.output_concepts, environment=environment)
155
+ node.rebuild_cache()
156
+ # we need a better API for refreshing a nodes QDS
157
+ possible_joins = concept_to_relevant_joins(additional_relevant)
158
+ if not local_optional:
159
+ logger.info(
160
+ f"{padding(depth)}{LOGGER_PREFIX} no enrichment required for multiselect node; exiting early"
161
+ )
162
+ return node
163
+ if not possible_joins:
164
+ logger.info(
165
+ f"{padding(depth)}{LOGGER_PREFIX} no possible joins for multiselect node; exiting early"
166
+ )
167
+ return node
168
+ if all(
169
+ [x.address in [y.address for y in node.output_concepts] for x in local_optional]
170
+ ):
171
+ logger.info(
172
+ f"{padding(depth)}{LOGGER_PREFIX} all enriched concepts returned from base multiselect node; exiting early"
173
+ )
174
+ return node
175
+ logger.info(
176
+ 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]]}"
177
+ )
178
+ enrich_node: MergeNode = source_concepts( # this fetches the parent + join keys
179
+ # to then connect to the rest of the query
180
+ mandatory_list=additional_relevant + local_optional,
181
+ environment=environment,
182
+ g=g,
183
+ depth=depth + 1,
184
+ history=history,
185
+ conditions=conditions,
186
+ )
187
+ if not enrich_node:
188
+ logger.info(
189
+ f"{padding(depth)}{LOGGER_PREFIX} Cannot generate rowset enrichment node for {concept} with optional {local_optional}, returning just rowset node"
190
+ )
191
+ return node
192
+
193
+ return MergeNode(
194
+ input_concepts=enrich_node.output_concepts + node.output_concepts,
195
+ output_concepts=node.output_concepts + local_optional,
196
+ environment=environment,
197
+ depth=depth,
198
+ parents=[
199
+ # this node gets the multiselect
200
+ node,
201
+ # this node gets enrichment
202
+ enrich_node,
203
+ ],
204
+ partial_concepts=node.partial_concepts,
205
+ )