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.
- LICENSE.md +19 -0
- _preql_import_resolver/__init__.py +5 -0
- _preql_import_resolver/_preql_import_resolver.cp313-win_amd64.pyd +0 -0
- pytrilogy-0.3.149.dist-info/METADATA +555 -0
- pytrilogy-0.3.149.dist-info/RECORD +207 -0
- pytrilogy-0.3.149.dist-info/WHEEL +4 -0
- pytrilogy-0.3.149.dist-info/entry_points.txt +2 -0
- pytrilogy-0.3.149.dist-info/licenses/LICENSE.md +19 -0
- trilogy/__init__.py +27 -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 +119 -0
- trilogy/core/README.md +52 -0
- trilogy/core/__init__.py +0 -0
- trilogy/core/constants.py +6 -0
- trilogy/core/enums.py +454 -0
- trilogy/core/env_processor.py +239 -0
- trilogy/core/environment_helpers.py +320 -0
- trilogy/core/ergonomics.py +193 -0
- trilogy/core/exceptions.py +123 -0
- trilogy/core/functions.py +1240 -0
- trilogy/core/graph_models.py +142 -0
- trilogy/core/internal.py +85 -0
- trilogy/core/models/__init__.py +0 -0
- trilogy/core/models/author.py +2670 -0
- trilogy/core/models/build.py +2603 -0
- trilogy/core/models/build_environment.py +165 -0
- trilogy/core/models/core.py +506 -0
- trilogy/core/models/datasource.py +436 -0
- trilogy/core/models/environment.py +756 -0
- trilogy/core/models/execute.py +1213 -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 +270 -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 +207 -0
- trilogy/core/processing/node_generators/node_merge_node.py +695 -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 +846 -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 +522 -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 +604 -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 +1432 -0
- trilogy/dialect/bigquery.py +314 -0
- trilogy/dialect/common.py +147 -0
- trilogy/dialect/config.py +159 -0
- trilogy/dialect/dataframe.py +50 -0
- trilogy/dialect/duckdb.py +397 -0
- trilogy/dialect/enums.py +151 -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/__init__.py +17 -0
- trilogy/execution/config.py +119 -0
- trilogy/execution/state/__init__.py +0 -0
- trilogy/execution/state/exceptions.py +26 -0
- trilogy/execution/state/file_state_store.py +0 -0
- trilogy/execution/state/sqllite_state_store.py +0 -0
- trilogy/execution/state/state_store.py +406 -0
- trilogy/executor.py +692 -0
- trilogy/hooks/__init__.py +4 -0
- trilogy/hooks/base_hook.py +40 -0
- trilogy/hooks/graph_hook.py +135 -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 +2876 -0
- trilogy/parsing/render.py +775 -0
- trilogy/parsing/trilogy.lark +546 -0
- trilogy/py.typed +0 -0
- trilogy/render.py +45 -0
- trilogy/scripts/README.md +9 -0
- trilogy/scripts/__init__.py +0 -0
- trilogy/scripts/agent.py +41 -0
- trilogy/scripts/agent_info.py +306 -0
- trilogy/scripts/common.py +432 -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 +387 -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 +311 -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 +555 -0
- trilogy/scripts/environment.py +59 -0
- trilogy/scripts/fmt.py +32 -0
- trilogy/scripts/ingest.py +487 -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 +762 -0
- trilogy/scripts/plan.py +189 -0
- trilogy/scripts/refresh.py +161 -0
- trilogy/scripts/run.py +79 -0
- trilogy/scripts/serve.py +202 -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 +143 -0
- trilogy/scripts/trilogy.py +75 -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,73 @@
|
|
|
1
|
+
from trilogy import Environment, Executor
|
|
2
|
+
from trilogy.authoring import DataType, Function
|
|
3
|
+
from trilogy.core.enums import FunctionType, Purpose, ValidationScope
|
|
4
|
+
from trilogy.core.exceptions import (
|
|
5
|
+
ModelValidationError,
|
|
6
|
+
)
|
|
7
|
+
from trilogy.core.validation.common import ValidationTest
|
|
8
|
+
from trilogy.core.validation.concept import validate_concept
|
|
9
|
+
from trilogy.core.validation.datasource import validate_datasource
|
|
10
|
+
from trilogy.parsing.common import function_to_concept
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def validate_environment(
|
|
14
|
+
env: Environment,
|
|
15
|
+
scope: ValidationScope = ValidationScope.ALL,
|
|
16
|
+
targets: list[str] | None = None,
|
|
17
|
+
exec: Executor | None = None,
|
|
18
|
+
generate_only: bool = False,
|
|
19
|
+
) -> list[ValidationTest]:
|
|
20
|
+
# avoid mutating the environment for validation
|
|
21
|
+
generate_only = exec is None or generate_only
|
|
22
|
+
env = env.duplicate()
|
|
23
|
+
grain_check = function_to_concept(
|
|
24
|
+
parent=Function(
|
|
25
|
+
operator=FunctionType.SUM,
|
|
26
|
+
arguments=[1],
|
|
27
|
+
output_datatype=DataType.INTEGER,
|
|
28
|
+
output_purpose=Purpose.METRIC,
|
|
29
|
+
),
|
|
30
|
+
name="grain_check",
|
|
31
|
+
environment=env,
|
|
32
|
+
)
|
|
33
|
+
env.add_concept(grain_check)
|
|
34
|
+
new_concepts = []
|
|
35
|
+
for concept in env.concepts.values():
|
|
36
|
+
concept_grain_check = function_to_concept(
|
|
37
|
+
parent=Function(
|
|
38
|
+
operator=FunctionType.COUNT_DISTINCT,
|
|
39
|
+
arguments=[concept.reference],
|
|
40
|
+
output_datatype=DataType.INTEGER,
|
|
41
|
+
output_purpose=Purpose.METRIC,
|
|
42
|
+
),
|
|
43
|
+
name=f"grain_check_{concept.safe_address}",
|
|
44
|
+
environment=env,
|
|
45
|
+
)
|
|
46
|
+
new_concepts.append(concept_grain_check)
|
|
47
|
+
for concept in new_concepts:
|
|
48
|
+
env.add_concept(concept)
|
|
49
|
+
build_env = env.materialize_for_select()
|
|
50
|
+
results: list[ValidationTest] = []
|
|
51
|
+
if scope == ValidationScope.ALL or scope == ValidationScope.DATASOURCES:
|
|
52
|
+
for datasource in build_env.datasources.values():
|
|
53
|
+
if targets and datasource.name not in targets:
|
|
54
|
+
continue
|
|
55
|
+
results += validate_datasource(datasource, env, build_env, exec)
|
|
56
|
+
if scope == ValidationScope.ALL or scope == ValidationScope.CONCEPTS:
|
|
57
|
+
|
|
58
|
+
for bconcept in build_env.concepts.values():
|
|
59
|
+
if targets and bconcept.address not in targets:
|
|
60
|
+
continue
|
|
61
|
+
results += validate_concept(bconcept, env, build_env, exec)
|
|
62
|
+
|
|
63
|
+
# raise a nicely formatted union of all exceptions
|
|
64
|
+
exceptions: list[ModelValidationError] = [e.result for e in results if e.result]
|
|
65
|
+
if exceptions:
|
|
66
|
+
if not generate_only:
|
|
67
|
+
messages = "\n".join([str(e) for e in exceptions])
|
|
68
|
+
raise ModelValidationError(
|
|
69
|
+
f"Environment validation failed with the following errors:\n{messages}",
|
|
70
|
+
children=exceptions,
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
return results
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from trilogy import Environment, Executor
|
|
6
|
+
from trilogy.authoring import ConceptDeclarationStatement, Datasource
|
|
7
|
+
from trilogy.core.enums import Modifier
|
|
8
|
+
from trilogy.core.exceptions import DatasourceColumnBindingError
|
|
9
|
+
from trilogy.core.models.author import ConceptRef
|
|
10
|
+
from trilogy.core.models.core import (
|
|
11
|
+
ArrayType,
|
|
12
|
+
DataType,
|
|
13
|
+
MapType,
|
|
14
|
+
NumericType,
|
|
15
|
+
StructType,
|
|
16
|
+
TraitDataType,
|
|
17
|
+
)
|
|
18
|
+
from trilogy.core.models.datasource import ColumnAssignment
|
|
19
|
+
from trilogy.core.validation.environment import validate_environment
|
|
20
|
+
from trilogy.parsing.render import Renderer, safe_address
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@dataclass
|
|
24
|
+
class DatasourceColumnFix:
|
|
25
|
+
"""Represents a fix to apply to a datasource column."""
|
|
26
|
+
|
|
27
|
+
datasource_identifier: str
|
|
28
|
+
column_address: str
|
|
29
|
+
new_modifiers: list[Modifier] | None = None
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@dataclass
|
|
33
|
+
class DatasourceReferenceFix:
|
|
34
|
+
"""Represents a fix to merge a datasource column with an imported reference."""
|
|
35
|
+
|
|
36
|
+
datasource_identifier: str
|
|
37
|
+
column_address: str
|
|
38
|
+
column_alias: str
|
|
39
|
+
reference_concept: ConceptRef
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@dataclass
|
|
43
|
+
class ConceptTypeFix:
|
|
44
|
+
"""Represents a fix to update a concept's data type."""
|
|
45
|
+
|
|
46
|
+
concept_address: str
|
|
47
|
+
new_type: DataType | ArrayType | StructType | MapType | NumericType | TraitDataType
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def update_datasource_column_modifiers(
|
|
51
|
+
datasource: Datasource, column_address: str, new_modifiers: list[Modifier]
|
|
52
|
+
) -> None:
|
|
53
|
+
"""Generic method to update column modifiers in a datasource."""
|
|
54
|
+
for col in datasource.columns:
|
|
55
|
+
if col.concept.address == column_address:
|
|
56
|
+
col.modifiers = list(set(col.modifiers + new_modifiers))
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def process_validation_errors(
|
|
60
|
+
errors: list[DatasourceColumnBindingError],
|
|
61
|
+
) -> tuple[
|
|
62
|
+
list[DatasourceColumnFix], list[ConceptTypeFix], list[DatasourceReferenceFix]
|
|
63
|
+
]:
|
|
64
|
+
"""Process validation errors and generate a list of fixes to apply."""
|
|
65
|
+
column_fixes: list[DatasourceColumnFix] = []
|
|
66
|
+
concept_fixes: list[ConceptTypeFix] = []
|
|
67
|
+
reference_fixes: list[DatasourceReferenceFix] = []
|
|
68
|
+
|
|
69
|
+
for error in errors:
|
|
70
|
+
if isinstance(error, DatasourceColumnBindingError):
|
|
71
|
+
for x in error.errors:
|
|
72
|
+
if x.is_modifier_issue():
|
|
73
|
+
column_fixes.append(
|
|
74
|
+
DatasourceColumnFix(
|
|
75
|
+
datasource_identifier=error.dataset_address,
|
|
76
|
+
column_address=x.address,
|
|
77
|
+
new_modifiers=x.value_modifiers,
|
|
78
|
+
)
|
|
79
|
+
)
|
|
80
|
+
if x.is_type_issue():
|
|
81
|
+
concept_fixes.append(
|
|
82
|
+
ConceptTypeFix(
|
|
83
|
+
concept_address=x.address,
|
|
84
|
+
new_type=x.value_type,
|
|
85
|
+
)
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
return column_fixes, concept_fixes, reference_fixes
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def update_datasource_column_reference(
|
|
92
|
+
datasource: Datasource, column_address: str, new_concept: ConceptRef
|
|
93
|
+
) -> None:
|
|
94
|
+
"""Update a datasource column to reference a different concept."""
|
|
95
|
+
|
|
96
|
+
for i, col in enumerate(datasource.columns):
|
|
97
|
+
if col.concept.address == column_address:
|
|
98
|
+
# Create a new ColumnAssignment with the new concept reference
|
|
99
|
+
new_col = ColumnAssignment(
|
|
100
|
+
alias=col.alias,
|
|
101
|
+
concept=new_concept,
|
|
102
|
+
modifiers=col.modifiers,
|
|
103
|
+
)
|
|
104
|
+
datasource.columns[i] = new_col
|
|
105
|
+
break
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def apply_fixes_to_statements(
|
|
109
|
+
statements: list[Any],
|
|
110
|
+
column_fixes: list[DatasourceColumnFix],
|
|
111
|
+
concept_fixes: list[ConceptTypeFix],
|
|
112
|
+
reference_fixes: list[DatasourceReferenceFix],
|
|
113
|
+
) -> list[Any]:
|
|
114
|
+
"""Apply the generated fixes to the statement list."""
|
|
115
|
+
output = []
|
|
116
|
+
|
|
117
|
+
# Track which concept addresses are being replaced by references
|
|
118
|
+
replaced_concept_addresses = {
|
|
119
|
+
fix.column_address: fix.reference_concept for fix in reference_fixes
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
for statement in statements:
|
|
123
|
+
if isinstance(statement, Datasource):
|
|
124
|
+
for col_fix in column_fixes:
|
|
125
|
+
if (
|
|
126
|
+
statement.identifier == col_fix.datasource_identifier
|
|
127
|
+
and col_fix.new_modifiers
|
|
128
|
+
):
|
|
129
|
+
update_datasource_column_modifiers(
|
|
130
|
+
statement, col_fix.column_address, col_fix.new_modifiers
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
for ref_fix in reference_fixes:
|
|
134
|
+
if statement.identifier == ref_fix.datasource_identifier:
|
|
135
|
+
update_datasource_column_reference(
|
|
136
|
+
statement,
|
|
137
|
+
ref_fix.column_address,
|
|
138
|
+
ref_fix.reference_concept,
|
|
139
|
+
)
|
|
140
|
+
new_grain = set()
|
|
141
|
+
for x in statement.grain.components:
|
|
142
|
+
if safe_address(x) in replaced_concept_addresses:
|
|
143
|
+
new_grain.add(
|
|
144
|
+
replaced_concept_addresses[safe_address(x)].address
|
|
145
|
+
)
|
|
146
|
+
else:
|
|
147
|
+
new_grain.add(x)
|
|
148
|
+
statement.grain.components = new_grain
|
|
149
|
+
|
|
150
|
+
elif isinstance(statement, ConceptDeclarationStatement):
|
|
151
|
+
# Skip concept declarations that are being replaced by references
|
|
152
|
+
if statement.concept.address in replaced_concept_addresses:
|
|
153
|
+
continue
|
|
154
|
+
new_keys = set()
|
|
155
|
+
replace_keys = False
|
|
156
|
+
|
|
157
|
+
for x in statement.concept.keys or set():
|
|
158
|
+
if safe_address(x) in replaced_concept_addresses:
|
|
159
|
+
replace_keys = True
|
|
160
|
+
new_keys.add(replaced_concept_addresses[safe_address(x)].address)
|
|
161
|
+
else:
|
|
162
|
+
new_keys.add(x)
|
|
163
|
+
if replace_keys:
|
|
164
|
+
statement.concept.keys = new_keys
|
|
165
|
+
for concept_fix in concept_fixes:
|
|
166
|
+
if statement.concept.address == concept_fix.concept_address:
|
|
167
|
+
statement.concept.datatype = concept_fix.new_type
|
|
168
|
+
|
|
169
|
+
output.append(statement)
|
|
170
|
+
|
|
171
|
+
return output
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def rewrite_file_with_errors(
|
|
175
|
+
statements: list[Any],
|
|
176
|
+
errors: list[DatasourceColumnBindingError],
|
|
177
|
+
additional_reference_fixes: list[DatasourceReferenceFix] | None = None,
|
|
178
|
+
):
|
|
179
|
+
renderer = Renderer()
|
|
180
|
+
|
|
181
|
+
column_fixes, concept_fixes, reference_fixes = process_validation_errors(errors)
|
|
182
|
+
|
|
183
|
+
# Add any additional reference fixes provided
|
|
184
|
+
if additional_reference_fixes:
|
|
185
|
+
reference_fixes.extend(additional_reference_fixes)
|
|
186
|
+
|
|
187
|
+
output = apply_fixes_to_statements(
|
|
188
|
+
statements, column_fixes, concept_fixes, reference_fixes
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
return renderer.render_statement_string(output)
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def rewrite_file_with_reference_merges(
|
|
195
|
+
statements: list[Any], reference_fixes: list[DatasourceReferenceFix]
|
|
196
|
+
) -> str:
|
|
197
|
+
renderer = Renderer()
|
|
198
|
+
|
|
199
|
+
output = apply_fixes_to_statements(statements, [], [], reference_fixes)
|
|
200
|
+
|
|
201
|
+
return renderer.render_statement_string(output)
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
DEPTH_CUTOFF = 3
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def validate_and_rewrite(
|
|
208
|
+
input: Path | str, exec: Executor | None = None, depth: int = 0
|
|
209
|
+
) -> str | None:
|
|
210
|
+
if depth > DEPTH_CUTOFF:
|
|
211
|
+
print(f"Reached depth cutoff of {DEPTH_CUTOFF}, stopping.")
|
|
212
|
+
return None
|
|
213
|
+
if isinstance(input, str):
|
|
214
|
+
raw = input
|
|
215
|
+
env = Environment()
|
|
216
|
+
else:
|
|
217
|
+
with open(input, "r") as f:
|
|
218
|
+
raw = f.read()
|
|
219
|
+
env = Environment(working_path=input.parent)
|
|
220
|
+
if exec:
|
|
221
|
+
env = exec.environment
|
|
222
|
+
env, statements = env.parse(raw)
|
|
223
|
+
|
|
224
|
+
validation_results = validate_environment(env, exec=exec, generate_only=True)
|
|
225
|
+
|
|
226
|
+
errors = [
|
|
227
|
+
x.result
|
|
228
|
+
for x in validation_results
|
|
229
|
+
if isinstance(x.result, DatasourceColumnBindingError)
|
|
230
|
+
]
|
|
231
|
+
|
|
232
|
+
if not errors:
|
|
233
|
+
print("No validation errors found")
|
|
234
|
+
return None
|
|
235
|
+
print(
|
|
236
|
+
f"Found {len(errors)} validation errors, attempting to fix, current depth: {depth}..."
|
|
237
|
+
)
|
|
238
|
+
for error in errors:
|
|
239
|
+
for item in error.errors:
|
|
240
|
+
print(f"- {item.format_failure()}")
|
|
241
|
+
|
|
242
|
+
new_text = rewrite_file_with_errors(statements, errors)
|
|
243
|
+
|
|
244
|
+
while iteration := validate_and_rewrite(new_text, exec=exec, depth=depth + 1):
|
|
245
|
+
depth = depth + 1
|
|
246
|
+
if depth >= DEPTH_CUTOFF:
|
|
247
|
+
break
|
|
248
|
+
if iteration:
|
|
249
|
+
new_text = iteration
|
|
250
|
+
depth += 1
|
|
251
|
+
if isinstance(input, Path):
|
|
252
|
+
with open(input, "w") as f:
|
|
253
|
+
f.write(new_text)
|
|
254
|
+
return None
|
|
255
|
+
else:
|
|
256
|
+
return new_text
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
from .bigquery import BigqueryDialect
|
|
2
|
+
from .config import (
|
|
3
|
+
BigQueryConfig,
|
|
4
|
+
DialectConfig,
|
|
5
|
+
DuckDBConfig,
|
|
6
|
+
PostgresConfig,
|
|
7
|
+
PrestoConfig,
|
|
8
|
+
SnowflakeConfig,
|
|
9
|
+
SQLServerConfig,
|
|
10
|
+
)
|
|
11
|
+
from .duckdb import DuckDBDialect
|
|
12
|
+
from .postgres import PostgresDialect
|
|
13
|
+
from .presto import PrestoDialect
|
|
14
|
+
from .snowflake import SnowflakeDialect
|
|
15
|
+
from .sql_server import SqlServerDialect
|
|
16
|
+
|
|
17
|
+
__all__ = [
|
|
18
|
+
"BigqueryDialect",
|
|
19
|
+
"PrestoDialect",
|
|
20
|
+
"DuckDBDialect",
|
|
21
|
+
"SnowflakeDialect",
|
|
22
|
+
"PostgresDialect",
|
|
23
|
+
"SqlServerDialect",
|
|
24
|
+
"SQLServerConfig",
|
|
25
|
+
"DialectConfig",
|
|
26
|
+
"DuckDBConfig",
|
|
27
|
+
"BigQueryConfig",
|
|
28
|
+
"SnowflakeConfig",
|
|
29
|
+
"PrestoConfig",
|
|
30
|
+
"PostgresConfig",
|
|
31
|
+
"DialectConfig",
|
|
32
|
+
]
|