pytrilogy 0.3.142__cp313-cp313-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.
- LICENSE.md +19 -0
- _preql_import_resolver/__init__.py +5 -0
- _preql_import_resolver/_preql_import_resolver.cpython-313-x86_64-linux-gnu.so +0 -0
- pytrilogy-0.3.142.dist-info/METADATA +555 -0
- pytrilogy-0.3.142.dist-info/RECORD +200 -0
- pytrilogy-0.3.142.dist-info/WHEEL +5 -0
- pytrilogy-0.3.142.dist-info/entry_points.txt +2 -0
- pytrilogy-0.3.142.dist-info/licenses/LICENSE.md +19 -0
- trilogy/__init__.py +16 -0
- trilogy/ai/README.md +10 -0
- trilogy/ai/__init__.py +19 -0
- trilogy/ai/constants.py +92 -0
- trilogy/ai/conversation.py +107 -0
- trilogy/ai/enums.py +7 -0
- trilogy/ai/execute.py +50 -0
- trilogy/ai/models.py +34 -0
- trilogy/ai/prompts.py +100 -0
- trilogy/ai/providers/__init__.py +0 -0
- trilogy/ai/providers/anthropic.py +106 -0
- trilogy/ai/providers/base.py +24 -0
- trilogy/ai/providers/google.py +146 -0
- trilogy/ai/providers/openai.py +89 -0
- trilogy/ai/providers/utils.py +68 -0
- trilogy/authoring/README.md +3 -0
- trilogy/authoring/__init__.py +148 -0
- trilogy/constants.py +113 -0
- trilogy/core/README.md +52 -0
- trilogy/core/__init__.py +0 -0
- trilogy/core/constants.py +6 -0
- trilogy/core/enums.py +443 -0
- trilogy/core/env_processor.py +120 -0
- trilogy/core/environment_helpers.py +320 -0
- trilogy/core/ergonomics.py +193 -0
- trilogy/core/exceptions.py +123 -0
- trilogy/core/functions.py +1227 -0
- trilogy/core/graph_models.py +139 -0
- trilogy/core/internal.py +85 -0
- trilogy/core/models/__init__.py +0 -0
- trilogy/core/models/author.py +2669 -0
- trilogy/core/models/build.py +2521 -0
- trilogy/core/models/build_environment.py +180 -0
- trilogy/core/models/core.py +501 -0
- trilogy/core/models/datasource.py +322 -0
- trilogy/core/models/environment.py +751 -0
- trilogy/core/models/execute.py +1177 -0
- trilogy/core/optimization.py +251 -0
- trilogy/core/optimizations/__init__.py +12 -0
- trilogy/core/optimizations/base_optimization.py +17 -0
- trilogy/core/optimizations/hide_unused_concept.py +47 -0
- trilogy/core/optimizations/inline_datasource.py +102 -0
- trilogy/core/optimizations/predicate_pushdown.py +245 -0
- trilogy/core/processing/README.md +94 -0
- trilogy/core/processing/READMEv2.md +121 -0
- trilogy/core/processing/VIRTUAL_UNNEST.md +30 -0
- trilogy/core/processing/__init__.py +0 -0
- trilogy/core/processing/concept_strategies_v3.py +508 -0
- trilogy/core/processing/constants.py +15 -0
- trilogy/core/processing/discovery_node_factory.py +451 -0
- trilogy/core/processing/discovery_utility.py +548 -0
- trilogy/core/processing/discovery_validation.py +167 -0
- trilogy/core/processing/graph_utils.py +43 -0
- trilogy/core/processing/node_generators/README.md +9 -0
- trilogy/core/processing/node_generators/__init__.py +31 -0
- trilogy/core/processing/node_generators/basic_node.py +160 -0
- trilogy/core/processing/node_generators/common.py +268 -0
- trilogy/core/processing/node_generators/constant_node.py +38 -0
- trilogy/core/processing/node_generators/filter_node.py +315 -0
- trilogy/core/processing/node_generators/group_node.py +213 -0
- trilogy/core/processing/node_generators/group_to_node.py +117 -0
- trilogy/core/processing/node_generators/multiselect_node.py +205 -0
- trilogy/core/processing/node_generators/node_merge_node.py +653 -0
- trilogy/core/processing/node_generators/recursive_node.py +88 -0
- trilogy/core/processing/node_generators/rowset_node.py +165 -0
- trilogy/core/processing/node_generators/select_helpers/__init__.py +0 -0
- trilogy/core/processing/node_generators/select_helpers/datasource_injection.py +261 -0
- trilogy/core/processing/node_generators/select_merge_node.py +748 -0
- trilogy/core/processing/node_generators/select_node.py +95 -0
- trilogy/core/processing/node_generators/synonym_node.py +98 -0
- trilogy/core/processing/node_generators/union_node.py +91 -0
- trilogy/core/processing/node_generators/unnest_node.py +182 -0
- trilogy/core/processing/node_generators/window_node.py +201 -0
- trilogy/core/processing/nodes/README.md +28 -0
- trilogy/core/processing/nodes/__init__.py +179 -0
- trilogy/core/processing/nodes/base_node.py +519 -0
- trilogy/core/processing/nodes/filter_node.py +75 -0
- trilogy/core/processing/nodes/group_node.py +194 -0
- trilogy/core/processing/nodes/merge_node.py +420 -0
- trilogy/core/processing/nodes/recursive_node.py +46 -0
- trilogy/core/processing/nodes/select_node_v2.py +242 -0
- trilogy/core/processing/nodes/union_node.py +53 -0
- trilogy/core/processing/nodes/unnest_node.py +62 -0
- trilogy/core/processing/nodes/window_node.py +56 -0
- trilogy/core/processing/utility.py +823 -0
- trilogy/core/query_processor.py +596 -0
- trilogy/core/statements/README.md +35 -0
- trilogy/core/statements/__init__.py +0 -0
- trilogy/core/statements/author.py +536 -0
- trilogy/core/statements/build.py +0 -0
- trilogy/core/statements/common.py +20 -0
- trilogy/core/statements/execute.py +155 -0
- trilogy/core/table_processor.py +66 -0
- trilogy/core/utility.py +8 -0
- trilogy/core/validation/README.md +46 -0
- trilogy/core/validation/__init__.py +0 -0
- trilogy/core/validation/common.py +161 -0
- trilogy/core/validation/concept.py +146 -0
- trilogy/core/validation/datasource.py +227 -0
- trilogy/core/validation/environment.py +73 -0
- trilogy/core/validation/fix.py +256 -0
- trilogy/dialect/__init__.py +32 -0
- trilogy/dialect/base.py +1392 -0
- trilogy/dialect/bigquery.py +308 -0
- trilogy/dialect/common.py +147 -0
- trilogy/dialect/config.py +144 -0
- trilogy/dialect/dataframe.py +50 -0
- trilogy/dialect/duckdb.py +231 -0
- trilogy/dialect/enums.py +147 -0
- trilogy/dialect/metadata.py +173 -0
- trilogy/dialect/mock.py +190 -0
- trilogy/dialect/postgres.py +117 -0
- trilogy/dialect/presto.py +110 -0
- trilogy/dialect/results.py +89 -0
- trilogy/dialect/snowflake.py +129 -0
- trilogy/dialect/sql_server.py +137 -0
- trilogy/engine.py +48 -0
- trilogy/execution/config.py +75 -0
- trilogy/executor.py +568 -0
- trilogy/hooks/__init__.py +4 -0
- trilogy/hooks/base_hook.py +40 -0
- trilogy/hooks/graph_hook.py +139 -0
- trilogy/hooks/query_debugger.py +166 -0
- trilogy/metadata/__init__.py +0 -0
- trilogy/parser.py +10 -0
- trilogy/parsing/README.md +21 -0
- trilogy/parsing/__init__.py +0 -0
- trilogy/parsing/common.py +1069 -0
- trilogy/parsing/config.py +5 -0
- trilogy/parsing/exceptions.py +8 -0
- trilogy/parsing/helpers.py +1 -0
- trilogy/parsing/parse_engine.py +2813 -0
- trilogy/parsing/render.py +769 -0
- trilogy/parsing/trilogy.lark +540 -0
- trilogy/py.typed +0 -0
- trilogy/render.py +42 -0
- trilogy/scripts/README.md +9 -0
- trilogy/scripts/__init__.py +0 -0
- trilogy/scripts/agent.py +41 -0
- trilogy/scripts/agent_info.py +303 -0
- trilogy/scripts/common.py +355 -0
- trilogy/scripts/dependency/Cargo.lock +617 -0
- trilogy/scripts/dependency/Cargo.toml +39 -0
- trilogy/scripts/dependency/README.md +131 -0
- trilogy/scripts/dependency/build.sh +25 -0
- trilogy/scripts/dependency/src/directory_resolver.rs +177 -0
- trilogy/scripts/dependency/src/lib.rs +16 -0
- trilogy/scripts/dependency/src/main.rs +770 -0
- trilogy/scripts/dependency/src/parser.rs +435 -0
- trilogy/scripts/dependency/src/preql.pest +208 -0
- trilogy/scripts/dependency/src/python_bindings.rs +303 -0
- trilogy/scripts/dependency/src/resolver.rs +716 -0
- trilogy/scripts/dependency/tests/base.preql +3 -0
- trilogy/scripts/dependency/tests/cli_integration.rs +377 -0
- trilogy/scripts/dependency/tests/customer.preql +6 -0
- trilogy/scripts/dependency/tests/main.preql +9 -0
- trilogy/scripts/dependency/tests/orders.preql +7 -0
- trilogy/scripts/dependency/tests/test_data/base.preql +9 -0
- trilogy/scripts/dependency/tests/test_data/consumer.preql +1 -0
- trilogy/scripts/dependency.py +323 -0
- trilogy/scripts/display.py +512 -0
- trilogy/scripts/environment.py +46 -0
- trilogy/scripts/fmt.py +32 -0
- trilogy/scripts/ingest.py +471 -0
- trilogy/scripts/ingest_helpers/__init__.py +1 -0
- trilogy/scripts/ingest_helpers/foreign_keys.py +123 -0
- trilogy/scripts/ingest_helpers/formatting.py +93 -0
- trilogy/scripts/ingest_helpers/typing.py +161 -0
- trilogy/scripts/init.py +105 -0
- trilogy/scripts/parallel_execution.py +713 -0
- trilogy/scripts/plan.py +189 -0
- trilogy/scripts/run.py +63 -0
- trilogy/scripts/serve.py +140 -0
- trilogy/scripts/serve_helpers/__init__.py +41 -0
- trilogy/scripts/serve_helpers/file_discovery.py +142 -0
- trilogy/scripts/serve_helpers/index_generation.py +206 -0
- trilogy/scripts/serve_helpers/models.py +38 -0
- trilogy/scripts/single_execution.py +131 -0
- trilogy/scripts/testing.py +119 -0
- trilogy/scripts/trilogy.py +68 -0
- trilogy/std/__init__.py +0 -0
- trilogy/std/color.preql +3 -0
- trilogy/std/date.preql +13 -0
- trilogy/std/display.preql +18 -0
- trilogy/std/geography.preql +22 -0
- trilogy/std/metric.preql +15 -0
- trilogy/std/money.preql +67 -0
- trilogy/std/net.preql +14 -0
- trilogy/std/ranking.preql +7 -0
- trilogy/std/report.preql +5 -0
- trilogy/std/semantic.preql +6 -0
- 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
|
+
)
|