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.
- LICENSE.md +19 -0
- _preql_import_resolver/__init__.py +5 -0
- _preql_import_resolver/_preql_import_resolver.cpython-311-x86_64-linux-gnu.so +0 -0
- pytrilogy-0.3.138.dist-info/METADATA +525 -0
- pytrilogy-0.3.138.dist-info/RECORD +182 -0
- pytrilogy-0.3.138.dist-info/WHEEL +5 -0
- pytrilogy-0.3.138.dist-info/entry_points.txt +2 -0
- pytrilogy-0.3.138.dist-info/licenses/LICENSE.md +19 -0
- trilogy/__init__.py +9 -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 +87 -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 +143 -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 +2672 -0
- trilogy/core/models/build.py +2521 -0
- trilogy/core/models/build_environment.py +180 -0
- trilogy/core/models/core.py +494 -0
- trilogy/core/models/datasource.py +322 -0
- trilogy/core/models/environment.py +748 -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 +517 -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 +106 -0
- trilogy/dialect/__init__.py +32 -0
- trilogy/dialect/base.py +1359 -0
- trilogy/dialect/bigquery.py +256 -0
- trilogy/dialect/common.py +147 -0
- trilogy/dialect/config.py +144 -0
- trilogy/dialect/dataframe.py +50 -0
- trilogy/dialect/duckdb.py +177 -0
- trilogy/dialect/enums.py +147 -0
- trilogy/dialect/metadata.py +173 -0
- trilogy/dialect/mock.py +190 -0
- trilogy/dialect/postgres.py +91 -0
- trilogy/dialect/presto.py +104 -0
- trilogy/dialect/results.py +89 -0
- trilogy/dialect/snowflake.py +90 -0
- trilogy/dialect/sql_server.py +92 -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 +750 -0
- trilogy/parsing/trilogy.lark +540 -0
- trilogy/py.typed +0 -0
- trilogy/render.py +42 -0
- trilogy/scripts/README.md +7 -0
- trilogy/scripts/__init__.py +0 -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 +162 -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 +289 -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 +460 -0
- trilogy/scripts/environment.py +46 -0
- trilogy/scripts/parallel_execution.py +483 -0
- trilogy/scripts/single_execution.py +131 -0
- trilogy/scripts/trilogy.py +772 -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,139 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from os import environ
|
|
3
|
+
|
|
4
|
+
import networkx as nx
|
|
5
|
+
|
|
6
|
+
from trilogy.hooks.base_hook import BaseHook
|
|
7
|
+
|
|
8
|
+
if not environ.get("TCL_LIBRARY"):
|
|
9
|
+
minor = sys.version_info.minor
|
|
10
|
+
if minor == 13:
|
|
11
|
+
environ["TCL_LIBRARY"] = r"C:\Program Files\Python313\tcl\tcl8.6"
|
|
12
|
+
elif minor == 12:
|
|
13
|
+
environ["TCL_LIBRARY"] = r"C:\Program Files\Python312\tcl\tcl8.6"
|
|
14
|
+
else:
|
|
15
|
+
pass
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class GraphHook(BaseHook):
|
|
19
|
+
def __init__(self):
|
|
20
|
+
super().__init__()
|
|
21
|
+
try:
|
|
22
|
+
pass
|
|
23
|
+
except ImportError:
|
|
24
|
+
raise ImportError("GraphHook requires matplotlib and scipy to be installed")
|
|
25
|
+
# https://github.com/python/cpython/issues/125235#issuecomment-2412948604
|
|
26
|
+
|
|
27
|
+
def query_graph_built(
|
|
28
|
+
self,
|
|
29
|
+
graph: nx.DiGraph,
|
|
30
|
+
target: str | None = None,
|
|
31
|
+
highlight_nodes: list[str] | None = None,
|
|
32
|
+
remove_isolates: bool = True,
|
|
33
|
+
):
|
|
34
|
+
from matplotlib import pyplot as plt
|
|
35
|
+
|
|
36
|
+
graph = graph.copy()
|
|
37
|
+
nodes = [*graph.nodes]
|
|
38
|
+
for node in nodes:
|
|
39
|
+
if "__preql_internal" in node:
|
|
40
|
+
graph.remove_node(node)
|
|
41
|
+
|
|
42
|
+
if remove_isolates:
|
|
43
|
+
graph.remove_nodes_from(list(nx.isolates(graph)))
|
|
44
|
+
|
|
45
|
+
color_map = []
|
|
46
|
+
highlight_nodes = highlight_nodes or []
|
|
47
|
+
for node in graph:
|
|
48
|
+
if node in highlight_nodes:
|
|
49
|
+
color_map.append("orange")
|
|
50
|
+
elif str(node).startswith("ds"):
|
|
51
|
+
color_map.append("blue")
|
|
52
|
+
else:
|
|
53
|
+
color_map.append("green")
|
|
54
|
+
|
|
55
|
+
pos = nx.spring_layout(graph)
|
|
56
|
+
kwargs = {}
|
|
57
|
+
|
|
58
|
+
if target:
|
|
59
|
+
edge_colors = []
|
|
60
|
+
descendents = nx.descendants(graph, target)
|
|
61
|
+
for edge in graph.edges():
|
|
62
|
+
if edge[0] == target:
|
|
63
|
+
edge_colors.append("blue")
|
|
64
|
+
elif edge[1] == target:
|
|
65
|
+
edge_colors.append("blue")
|
|
66
|
+
elif edge[1] in descendents:
|
|
67
|
+
edge_colors.append("green")
|
|
68
|
+
else:
|
|
69
|
+
edge_colors.append("black")
|
|
70
|
+
kwargs["edge_color"] = edge_colors
|
|
71
|
+
|
|
72
|
+
# Draw the graph without labels first
|
|
73
|
+
nx.draw(
|
|
74
|
+
graph,
|
|
75
|
+
pos=pos,
|
|
76
|
+
node_color=color_map,
|
|
77
|
+
connectionstyle="arc3, rad = 0.1",
|
|
78
|
+
with_labels=False, # Important: don't draw labels with nx.draw
|
|
79
|
+
**kwargs
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
# Draw labels with manual spacing
|
|
83
|
+
self._draw_labels_with_manual_spacing(graph, pos)
|
|
84
|
+
|
|
85
|
+
plt.show()
|
|
86
|
+
|
|
87
|
+
def _draw_labels_with_manual_spacing(self, graph, pos):
|
|
88
|
+
import numpy as np
|
|
89
|
+
|
|
90
|
+
pos_labels = {}
|
|
91
|
+
node_positions = list(pos.values())
|
|
92
|
+
|
|
93
|
+
# Calculate average distance between nodes to determine spacing
|
|
94
|
+
if len(node_positions) > 1:
|
|
95
|
+
distances = []
|
|
96
|
+
for i, (x1, y1) in enumerate(node_positions):
|
|
97
|
+
for j, (x2, y2) in enumerate(node_positions[i + 1 :], i + 1):
|
|
98
|
+
dist = np.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)
|
|
99
|
+
distances.append(dist)
|
|
100
|
+
|
|
101
|
+
avg_distance = np.mean(distances)
|
|
102
|
+
min_spacing = max(
|
|
103
|
+
0.1, avg_distance * 0.3
|
|
104
|
+
) # Minimum spacing as fraction of average distance
|
|
105
|
+
else:
|
|
106
|
+
min_spacing = 0.1
|
|
107
|
+
|
|
108
|
+
# Simple spacing algorithm - offset labels that are too close
|
|
109
|
+
for i, node in enumerate(graph.nodes()):
|
|
110
|
+
x, y = pos[node]
|
|
111
|
+
|
|
112
|
+
# Check for nearby labels and adjust position
|
|
113
|
+
adjusted_x, adjusted_y = x, y
|
|
114
|
+
for j, other_node in enumerate(
|
|
115
|
+
list(graph.nodes())[:i]
|
|
116
|
+
): # Only check previous nodes
|
|
117
|
+
other_x, other_y = pos_labels.get(other_node, pos[other_node])
|
|
118
|
+
distance = np.sqrt(
|
|
119
|
+
(adjusted_x - other_x) ** 2 + (adjusted_y - other_y) ** 2
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
if distance < min_spacing:
|
|
123
|
+
# Calculate offset direction
|
|
124
|
+
if distance > 0:
|
|
125
|
+
offset_x = (adjusted_x - other_x) / distance * min_spacing
|
|
126
|
+
offset_y = (adjusted_y - other_y) / distance * min_spacing
|
|
127
|
+
else:
|
|
128
|
+
# If nodes are at exact same position, use random offset
|
|
129
|
+
angle = np.random.random() * 2 * np.pi
|
|
130
|
+
offset_x = np.cos(angle) * min_spacing
|
|
131
|
+
offset_y = np.sin(angle) * min_spacing
|
|
132
|
+
|
|
133
|
+
adjusted_x = other_x + offset_x
|
|
134
|
+
adjusted_y = other_y + offset_y
|
|
135
|
+
|
|
136
|
+
pos_labels[node] = (adjusted_x, adjusted_y)
|
|
137
|
+
|
|
138
|
+
# Draw the labels at adjusted positions
|
|
139
|
+
nx.draw_networkx_labels(graph, pos=pos_labels, font_size=10)
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
from logging import DEBUG, StreamHandler
|
|
3
|
+
from typing import Union
|
|
4
|
+
from uuid import uuid4
|
|
5
|
+
|
|
6
|
+
from trilogy.constants import logger
|
|
7
|
+
from trilogy.core.models.build import BuildDatasource
|
|
8
|
+
from trilogy.core.models.execute import (
|
|
9
|
+
CTE,
|
|
10
|
+
QueryDatasource,
|
|
11
|
+
UnionCTE,
|
|
12
|
+
)
|
|
13
|
+
from trilogy.core.processing.nodes import StrategyNode
|
|
14
|
+
from trilogy.core.statements.author import SelectStatement
|
|
15
|
+
from trilogy.hooks.base_hook import BaseHook
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class PrintMode(Enum):
|
|
19
|
+
OFF = False
|
|
20
|
+
BASIC = True
|
|
21
|
+
FULL = 3
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class DebuggingHook(BaseHook):
|
|
25
|
+
def __init__(
|
|
26
|
+
self,
|
|
27
|
+
level=DEBUG,
|
|
28
|
+
max_depth: int | None = None,
|
|
29
|
+
process_ctes: PrintMode | bool = True,
|
|
30
|
+
process_nodes: PrintMode | bool = True,
|
|
31
|
+
process_datasources: PrintMode | bool = True,
|
|
32
|
+
process_other: bool = True,
|
|
33
|
+
):
|
|
34
|
+
if not any([isinstance(x, StreamHandler) for x in logger.handlers]):
|
|
35
|
+
logger.addHandler(StreamHandler())
|
|
36
|
+
logger.setLevel(level)
|
|
37
|
+
|
|
38
|
+
self.max_depth = max_depth
|
|
39
|
+
self.process_ctes = PrintMode(process_ctes)
|
|
40
|
+
self.process_nodes = PrintMode(process_nodes)
|
|
41
|
+
self.process_datasources = PrintMode(process_datasources)
|
|
42
|
+
self.process_other = PrintMode(process_other)
|
|
43
|
+
self.messages: list[str] = []
|
|
44
|
+
self.uuid = uuid4()
|
|
45
|
+
from trilogy.dialect.bigquery import BigqueryDialect
|
|
46
|
+
|
|
47
|
+
self.renderer = BigqueryDialect()
|
|
48
|
+
|
|
49
|
+
def print(self, *args):
|
|
50
|
+
merged = " ".join([str(x) for x in args])
|
|
51
|
+
self.messages.append(merged)
|
|
52
|
+
|
|
53
|
+
def write(self):
|
|
54
|
+
with open(f"debug_{self.uuid}.log", "w") as f:
|
|
55
|
+
f.write("\n".join(self.messages))
|
|
56
|
+
|
|
57
|
+
def process_select_info(self, select: SelectStatement):
|
|
58
|
+
if self.process_datasources != PrintMode.OFF:
|
|
59
|
+
self.print(f"grain: {str(select.grain)}")
|
|
60
|
+
|
|
61
|
+
def process_root_datasource(self, datasource: QueryDatasource):
|
|
62
|
+
if self.process_datasources != PrintMode.OFF:
|
|
63
|
+
printed = self.print_recursive_resolved(
|
|
64
|
+
datasource, self.process_datasources
|
|
65
|
+
)
|
|
66
|
+
for row in printed:
|
|
67
|
+
self.print("".join([str(v) for v in row]))
|
|
68
|
+
|
|
69
|
+
def process_root_cte(self, cte: CTE | UnionCTE):
|
|
70
|
+
if self.process_ctes != PrintMode.OFF:
|
|
71
|
+
self.print_recursive_ctes(cte, max_depth=self.max_depth)
|
|
72
|
+
|
|
73
|
+
def process_root_strategy_node(self, node: StrategyNode):
|
|
74
|
+
if self.process_nodes != PrintMode.OFF:
|
|
75
|
+
printed = self.print_recursive_nodes(node, mode=self.process_nodes)
|
|
76
|
+
for row in printed:
|
|
77
|
+
# logger.info("".join([str(v) for v in row]))
|
|
78
|
+
self.print("".join([str(v) for v in row]))
|
|
79
|
+
|
|
80
|
+
def print_recursive_resolved(
|
|
81
|
+
self,
|
|
82
|
+
input: Union[QueryDatasource, BuildDatasource],
|
|
83
|
+
mode: PrintMode,
|
|
84
|
+
depth: int = 0,
|
|
85
|
+
):
|
|
86
|
+
extra = []
|
|
87
|
+
if isinstance(input, QueryDatasource):
|
|
88
|
+
if input.joins:
|
|
89
|
+
extra.append("join")
|
|
90
|
+
if input.condition:
|
|
91
|
+
extra.append("filter")
|
|
92
|
+
if input.group_required:
|
|
93
|
+
extra.append("group")
|
|
94
|
+
output = [c.address for c in input.output_concepts[:3]]
|
|
95
|
+
if len(input.output_concepts) > 3:
|
|
96
|
+
output.append("...")
|
|
97
|
+
display = [
|
|
98
|
+
(
|
|
99
|
+
" " * depth,
|
|
100
|
+
input.__class__.__name__,
|
|
101
|
+
"<",
|
|
102
|
+
",".join(extra),
|
|
103
|
+
">",
|
|
104
|
+
# [c.address for c in input.input_concepts],
|
|
105
|
+
"->",
|
|
106
|
+
output,
|
|
107
|
+
)
|
|
108
|
+
]
|
|
109
|
+
if isinstance(input, QueryDatasource):
|
|
110
|
+
for child in input.datasources:
|
|
111
|
+
display += self.print_recursive_resolved(
|
|
112
|
+
child, mode=mode, depth=depth + 1
|
|
113
|
+
)
|
|
114
|
+
return display
|
|
115
|
+
|
|
116
|
+
def print_recursive_ctes(
|
|
117
|
+
self, input: CTE | UnionCTE, depth: int = 0, max_depth: int | None = None
|
|
118
|
+
):
|
|
119
|
+
if max_depth and depth > max_depth:
|
|
120
|
+
return
|
|
121
|
+
select_statement = [c.address for c in input.output_columns]
|
|
122
|
+
self.print(
|
|
123
|
+
" " * depth, input.name, "->", input.group_to_grain, "->", select_statement
|
|
124
|
+
)
|
|
125
|
+
sql = self.renderer.render_cte(input).statement
|
|
126
|
+
for line in sql.split("\n"):
|
|
127
|
+
logger.debug(" " * (depth) + line)
|
|
128
|
+
if isinstance(input, CTE):
|
|
129
|
+
for child in input.parent_ctes:
|
|
130
|
+
self.print_recursive_ctes(child, depth + 1)
|
|
131
|
+
elif isinstance(input, UnionCTE):
|
|
132
|
+
for child in input.parent_ctes:
|
|
133
|
+
for parent in child.parent_ctes:
|
|
134
|
+
self.print_recursive_ctes(parent, depth + 1)
|
|
135
|
+
|
|
136
|
+
def print_recursive_nodes(
|
|
137
|
+
self, input: StrategyNode, mode: PrintMode = PrintMode.BASIC, depth: int = 0
|
|
138
|
+
):
|
|
139
|
+
resolved = input.resolve()
|
|
140
|
+
if mode == PrintMode.FULL:
|
|
141
|
+
display = [
|
|
142
|
+
[
|
|
143
|
+
" " * depth,
|
|
144
|
+
input,
|
|
145
|
+
"->",
|
|
146
|
+
resolved.grain,
|
|
147
|
+
"->",
|
|
148
|
+
[c.address for c in resolved.output_concepts],
|
|
149
|
+
]
|
|
150
|
+
]
|
|
151
|
+
elif mode == PrintMode.BASIC:
|
|
152
|
+
display = [
|
|
153
|
+
[
|
|
154
|
+
" " * depth,
|
|
155
|
+
input,
|
|
156
|
+
"->",
|
|
157
|
+
resolved.grain,
|
|
158
|
+
]
|
|
159
|
+
]
|
|
160
|
+
for child in input.parents:
|
|
161
|
+
display += self.print_recursive_nodes(
|
|
162
|
+
child,
|
|
163
|
+
mode=mode,
|
|
164
|
+
depth=depth + 1,
|
|
165
|
+
)
|
|
166
|
+
return display
|
|
File without changes
|
trilogy/parser.py
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
from trilogy.core.models.environment import Environment
|
|
4
|
+
from trilogy.parsing.parse_engine import parse_text
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def parse(
|
|
8
|
+
input: str, environment: Optional[Environment] = None
|
|
9
|
+
) -> tuple[Environment, list]:
|
|
10
|
+
return parse_text(input, environment=environment)
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Grammar Overview
|
|
2
|
+
|
|
3
|
+
```
|
|
4
|
+
!start: ( block | show_statement )*
|
|
5
|
+
block: statement _TERMINATOR PARSE_COMMENT?
|
|
6
|
+
?statement: concept
|
|
7
|
+
| datasource
|
|
8
|
+
| function
|
|
9
|
+
| multi_select_statement
|
|
10
|
+
| select_statement
|
|
11
|
+
| persist_statement
|
|
12
|
+
| rowset_derivation_statement
|
|
13
|
+
| import_statement
|
|
14
|
+
| copy_statement
|
|
15
|
+
| merge_statement
|
|
16
|
+
| rawsql_statement
|
|
17
|
+
|
|
18
|
+
_TERMINATOR: ";"i /\s*/
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Full grammar in trilogy.lark.
|
|
File without changes
|