pytrilogy 0.0.3.10__tar.gz → 0.0.3.12__tar.gz
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.
Potentially problematic release.
This version of pytrilogy might be problematic. Click here for more details.
- {pytrilogy-0.0.3.10/pytrilogy.egg-info → pytrilogy-0.0.3.12}/PKG-INFO +1 -1
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12/pytrilogy.egg-info}/PKG-INFO +1 -1
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/pytrilogy.egg-info/SOURCES.txt +2 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/tests/test_parsing.py +43 -1
- pytrilogy-0.0.3.12/tests/test_query_render.py +13 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/__init__.py +1 -1
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/authoring/__init__.py +8 -1
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/models/environment.py +18 -3
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/processing/nodes/group_node.py +1 -1
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/dialect/bigquery.py +2 -3
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/dialect/duckdb.py +2 -2
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/dialect/enums.py +5 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/dialect/presto.py +1 -1
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/dialect/sql_server.py +1 -1
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/engine.py +21 -1
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/executor.py +2 -34
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/parsing/parse_engine.py +35 -8
- pytrilogy-0.0.3.12/trilogy/render.py +38 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/LICENSE.md +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/README.md +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/pyproject.toml +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/pytrilogy.egg-info/dependency_links.txt +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/pytrilogy.egg-info/entry_points.txt +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/pytrilogy.egg-info/requires.txt +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/pytrilogy.egg-info/top_level.txt +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/setup.cfg +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/setup.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/tests/test_datatypes.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/tests/test_declarations.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/tests/test_derived_concepts.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/tests/test_discovery_nodes.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/tests/test_enums.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/tests/test_environment.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/tests/test_executor.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/tests/test_functions.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/tests/test_imports.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/tests/test_metadata.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/tests/test_models.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/tests/test_multi_join_assignments.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/tests/test_parse_engine.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/tests/test_partial_handling.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/tests/test_query_processing.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/tests/test_select.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/tests/test_show.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/tests/test_statements.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/tests/test_typing.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/tests/test_undefined_concept.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/tests/test_user_functions.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/tests/test_where_clause.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/compiler.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/constants.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/__init__.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/constants.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/enums.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/env_processor.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/environment_helpers.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/ergonomics.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/exceptions.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/functions.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/graph_models.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/internal.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/models/__init__.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/models/author.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/models/build.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/models/build_environment.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/models/core.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/models/datasource.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/models/execute.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/optimization.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/optimizations/__init__.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/optimizations/base_optimization.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/optimizations/inline_constant.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/optimizations/inline_datasource.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/optimizations/predicate_pushdown.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/processing/__init__.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/processing/concept_strategies_v3.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/processing/graph_utils.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/processing/node_generators/__init__.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/processing/node_generators/basic_node.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/processing/node_generators/common.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/processing/node_generators/filter_node.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/processing/node_generators/group_node.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/processing/node_generators/group_to_node.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/processing/node_generators/multiselect_node.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/processing/node_generators/node_merge_node.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/processing/node_generators/rowset_node.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/processing/node_generators/select_helpers/__init__.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/processing/node_generators/select_helpers/datasource_injection.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/processing/node_generators/select_merge_node.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/processing/node_generators/select_node.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/processing/node_generators/synonym_node.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/processing/node_generators/union_node.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/processing/node_generators/unnest_node.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/processing/node_generators/window_node.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/processing/nodes/__init__.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/processing/nodes/base_node.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/processing/nodes/filter_node.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/processing/nodes/merge_node.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/processing/nodes/select_node_v2.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/processing/nodes/union_node.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/processing/nodes/unnest_node.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/processing/nodes/window_node.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/processing/utility.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/query_processor.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/statements/__init__.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/statements/author.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/statements/build.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/statements/common.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/statements/execute.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/dialect/__init__.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/dialect/base.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/dialect/common.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/dialect/config.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/dialect/dataframe.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/dialect/postgres.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/dialect/snowflake.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/hooks/__init__.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/hooks/base_hook.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/hooks/graph_hook.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/hooks/query_debugger.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/metadata/__init__.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/parser.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/parsing/__init__.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/parsing/common.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/parsing/config.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/parsing/exceptions.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/parsing/helpers.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/parsing/render.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/parsing/trilogy.lark +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/py.typed +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/scripts/__init__.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/scripts/trilogy.py +0 -0
- {pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/utility.py +0 -0
|
@@ -24,6 +24,7 @@ tests/test_parse_engine.py
|
|
|
24
24
|
tests/test_parsing.py
|
|
25
25
|
tests/test_partial_handling.py
|
|
26
26
|
tests/test_query_processing.py
|
|
27
|
+
tests/test_query_render.py
|
|
27
28
|
tests/test_select.py
|
|
28
29
|
tests/test_show.py
|
|
29
30
|
tests/test_statements.py
|
|
@@ -38,6 +39,7 @@ trilogy/engine.py
|
|
|
38
39
|
trilogy/executor.py
|
|
39
40
|
trilogy/parser.py
|
|
40
41
|
trilogy/py.typed
|
|
42
|
+
trilogy/render.py
|
|
41
43
|
trilogy/utility.py
|
|
42
44
|
trilogy/authoring/__init__.py
|
|
43
45
|
trilogy/core/__init__.py
|
|
@@ -8,7 +8,11 @@ from trilogy.core.models.core import (
|
|
|
8
8
|
TupleWrapper,
|
|
9
9
|
)
|
|
10
10
|
from trilogy.core.models.datasource import Datasource
|
|
11
|
-
from trilogy.core.models.environment import
|
|
11
|
+
from trilogy.core.models.environment import (
|
|
12
|
+
DictImportResolver,
|
|
13
|
+
Environment,
|
|
14
|
+
EnvironmentOptions,
|
|
15
|
+
)
|
|
12
16
|
from trilogy.core.statements.author import SelectStatement, ShowStatement
|
|
13
17
|
from trilogy.core.statements.execute import ProcessedQuery
|
|
14
18
|
from trilogy.dialect.base import BaseDialect
|
|
@@ -619,3 +623,41 @@ select [1,2,3,4] as int_array, 2 as scalar
|
|
|
619
623
|
|
|
620
624
|
env, parsed = parse_text(x)
|
|
621
625
|
assert env.concepts["split"].datatype == DataType.INTEGER
|
|
626
|
+
|
|
627
|
+
|
|
628
|
+
def test_non_file_imports():
|
|
629
|
+
|
|
630
|
+
env = Environment(
|
|
631
|
+
config=EnvironmentOptions(
|
|
632
|
+
import_resolver=DictImportResolver(
|
|
633
|
+
content={
|
|
634
|
+
"test": """
|
|
635
|
+
import test_dep as test_dep;
|
|
636
|
+
key x int;
|
|
637
|
+
|
|
638
|
+
datasource test (
|
|
639
|
+
x: x)
|
|
640
|
+
grain(x)
|
|
641
|
+
query '''
|
|
642
|
+
select 1 as x
|
|
643
|
+
union all
|
|
644
|
+
select 11 as x
|
|
645
|
+
''';
|
|
646
|
+
""",
|
|
647
|
+
"test_dep": """
|
|
648
|
+
key x int;
|
|
649
|
+
""",
|
|
650
|
+
}
|
|
651
|
+
)
|
|
652
|
+
)
|
|
653
|
+
)
|
|
654
|
+
assert isinstance(env.config.import_resolver, DictImportResolver)
|
|
655
|
+
env.parse(
|
|
656
|
+
"""
|
|
657
|
+
import test;
|
|
658
|
+
|
|
659
|
+
select x % 10 -> x_mod_10;
|
|
660
|
+
|
|
661
|
+
|
|
662
|
+
"""
|
|
663
|
+
)
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from trilogy import Dialects, Environment
|
|
2
|
+
from trilogy.core.query_processor import process_query
|
|
3
|
+
from trilogy.render import get_dialect_generator
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def test_sql_generators():
|
|
7
|
+
env = Environment()
|
|
8
|
+
_, statements = env.parse("""const a <- 1; select a;""")
|
|
9
|
+
processed = process_query(env, statements[-1])
|
|
10
|
+
for dialect in Dialects:
|
|
11
|
+
generator = get_dialect_generator(dialect)
|
|
12
|
+
compiled = generator.compile_statement(processed)
|
|
13
|
+
assert compiled.startswith("""SELECT\n :a"""), f"{dialect} compiled"
|
|
@@ -33,7 +33,13 @@ from trilogy.core.models.author import (
|
|
|
33
33
|
WindowOrder,
|
|
34
34
|
WindowType,
|
|
35
35
|
)
|
|
36
|
-
from trilogy.core.models.core import
|
|
36
|
+
from trilogy.core.models.core import (
|
|
37
|
+
DataType,
|
|
38
|
+
ListType,
|
|
39
|
+
ListWrapper,
|
|
40
|
+
MapType,
|
|
41
|
+
StructType,
|
|
42
|
+
)
|
|
37
43
|
from trilogy.core.models.environment import Environment
|
|
38
44
|
from trilogy.core.statements.author import (
|
|
39
45
|
ConceptDeclarationStatement,
|
|
@@ -63,6 +69,7 @@ __all__ = [
|
|
|
63
69
|
"DataType",
|
|
64
70
|
"StructType",
|
|
65
71
|
"ListType",
|
|
72
|
+
"MapType",
|
|
66
73
|
"ListWrapper",
|
|
67
74
|
"FunctionType",
|
|
68
75
|
"FunctionFactory",
|
|
@@ -60,8 +60,23 @@ class Import:
|
|
|
60
60
|
path: Path
|
|
61
61
|
|
|
62
62
|
|
|
63
|
+
class BaseImportResolver(BaseModel):
|
|
64
|
+
pass
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class FileSystemImportResolver(BaseImportResolver):
|
|
68
|
+
pass
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class DictImportResolver(BaseImportResolver):
|
|
72
|
+
content: Dict[str, str]
|
|
73
|
+
|
|
74
|
+
|
|
63
75
|
class EnvironmentOptions(BaseModel):
|
|
64
76
|
allow_duplicate_declaration: bool = True
|
|
77
|
+
import_resolver: BaseImportResolver = Field(
|
|
78
|
+
default_factory=FileSystemImportResolver
|
|
79
|
+
)
|
|
65
80
|
|
|
66
81
|
|
|
67
82
|
class EnvironmentConceptDict(dict):
|
|
@@ -199,7 +214,7 @@ class Environment(BaseModel):
|
|
|
199
214
|
)
|
|
200
215
|
namespace: str = DEFAULT_NAMESPACE
|
|
201
216
|
working_path: str | Path = Field(default_factory=lambda: os.getcwd())
|
|
202
|
-
|
|
217
|
+
config: EnvironmentOptions = Field(default_factory=EnvironmentOptions)
|
|
203
218
|
version: str = Field(default_factory=get_version)
|
|
204
219
|
cte_name_map: Dict[str, str] = Field(default_factory=dict)
|
|
205
220
|
materialized_concepts: set[str] = Field(default_factory=set)
|
|
@@ -234,7 +249,7 @@ class Environment(BaseModel):
|
|
|
234
249
|
imports=dict(self.imports),
|
|
235
250
|
namespace=self.namespace,
|
|
236
251
|
working_path=self.working_path,
|
|
237
|
-
environment_config=self.
|
|
252
|
+
environment_config=self.config,
|
|
238
253
|
version=self.version,
|
|
239
254
|
cte_name_map=dict(self.cte_name_map),
|
|
240
255
|
materialized_concepts=set(self.materialized_concepts),
|
|
@@ -342,7 +357,7 @@ class Environment(BaseModel):
|
|
|
342
357
|
|
|
343
358
|
return None
|
|
344
359
|
|
|
345
|
-
if existing and self.
|
|
360
|
+
if existing and self.config.allow_duplicate_declaration:
|
|
346
361
|
if existing.metadata.concept_source == ConceptSource.PERSIST_STATEMENT:
|
|
347
362
|
return handle_persist()
|
|
348
363
|
return
|
|
@@ -92,7 +92,7 @@ class GroupNode(StrategyNode):
|
|
|
92
92
|
comp_grain += source.grain
|
|
93
93
|
for x in source.output_concepts:
|
|
94
94
|
concept_map[x.address] = x
|
|
95
|
-
lookups = [
|
|
95
|
+
lookups: list[BuildConcept | str] = [
|
|
96
96
|
concept_map[x] if x in concept_map else x for x in comp_grain.components
|
|
97
97
|
]
|
|
98
98
|
comp_grain = BuildGrain.from_concepts(lookups, environment=environment)
|
|
@@ -42,10 +42,9 @@ CREATE OR REPLACE TABLE {{ output.address.location }} AS
|
|
|
42
42
|
{% endif %}{%- if ctes %}
|
|
43
43
|
WITH {% for cte in ctes %}
|
|
44
44
|
{{cte.name}} as ({{cte.statement}}){% if not loop.last %},{% endif %}{% endfor %}{% endif %}
|
|
45
|
-
{%- if full_select
|
|
45
|
+
{%- if full_select -%}
|
|
46
46
|
{{full_select}}
|
|
47
|
-
{
|
|
48
|
-
|
|
47
|
+
{%- else -%}
|
|
49
48
|
SELECT
|
|
50
49
|
{%- for select in select_columns %}
|
|
51
50
|
{{ select }}{% if not loop.last %},{% endif %}{% endfor %}
|
|
@@ -57,8 +57,8 @@ CREATE OR REPLACE TABLE {{ output.address.location }} AS
|
|
|
57
57
|
WITH {% for cte in ctes %}
|
|
58
58
|
{{cte.name}} as ({{cte.statement}}){% if not loop.last %},{% endif %}{% endfor %}{% endif %}
|
|
59
59
|
{%- if full_select -%}{{full_select}}
|
|
60
|
-
{%- else -%}{%- if comment
|
|
61
|
-
-- {{ comment }}{
|
|
60
|
+
{%- else -%}{%- if comment -%}
|
|
61
|
+
-- {{ comment }}{%- endif -%}
|
|
62
62
|
SELECT
|
|
63
63
|
{%- for select in select_columns %}
|
|
64
64
|
{{ select }}{% if not loop.last %},{% endif %}{% endfor %}
|
|
@@ -41,6 +41,11 @@ class Dialects(Enum):
|
|
|
41
41
|
return cls.DUCK_DB
|
|
42
42
|
return super()._missing_(value)
|
|
43
43
|
|
|
44
|
+
def default_renderer(self, conf=None, _engine_factory: Callable = default_factory):
|
|
45
|
+
from trilogy.render import get_dialect_generator
|
|
46
|
+
|
|
47
|
+
return get_dialect_generator(self)
|
|
48
|
+
|
|
44
49
|
def default_engine(self, conf=None, _engine_factory: Callable = default_factory):
|
|
45
50
|
if self == Dialects.BIGQUERY:
|
|
46
51
|
from google.auth import default
|
|
@@ -50,7 +50,7 @@ WITH {% for cte in ctes %}
|
|
|
50
50
|
{{cte.name}} as ({{cte.statement}}){% if not loop.last %},{% endif %}{% endfor %}{% endif %}
|
|
51
51
|
{%- if full_select -%}
|
|
52
52
|
{{full_select}}
|
|
53
|
-
{%- else
|
|
53
|
+
{%- else -%}
|
|
54
54
|
SELECT
|
|
55
55
|
{%- for select in select_columns %}
|
|
56
56
|
{{ select }}{% if not loop.last %},{% endif %}{% endfor %}
|
|
@@ -42,7 +42,7 @@ WITH {% for cte in ctes %}
|
|
|
42
42
|
{{cte.name}} as ({{cte.statement}}){% if not loop.last %},{% endif %}{% endfor %}{% endif %}
|
|
43
43
|
{%- if full_select -%}{{full_select}}
|
|
44
44
|
{%- else -%}{%- if comment %}
|
|
45
|
-
-- {{ comment }}{
|
|
45
|
+
-- {{ comment }}{%- endif -%}
|
|
46
46
|
SELECT
|
|
47
47
|
{%- if limit is not none %}
|
|
48
48
|
TOP {{ limit }}{% endif %}
|
|
@@ -18,6 +18,15 @@ class EngineConnection(Protocol):
|
|
|
18
18
|
def execute(self, statement: str, parameters: Any | None = None) -> EngineResult:
|
|
19
19
|
pass
|
|
20
20
|
|
|
21
|
+
def commit(self):
|
|
22
|
+
raise NotImplementedError()
|
|
23
|
+
|
|
24
|
+
def begin(self):
|
|
25
|
+
raise NotImplementedError()
|
|
26
|
+
|
|
27
|
+
def rollback(self):
|
|
28
|
+
raise NotImplementedError()
|
|
29
|
+
|
|
21
30
|
|
|
22
31
|
class ExecutionEngine(Protocol):
|
|
23
32
|
pass
|
|
@@ -40,13 +49,24 @@ class SqlAlchemyResult(EngineResult):
|
|
|
40
49
|
|
|
41
50
|
class SqlAlchemyConnection(EngineConnection):
|
|
42
51
|
def __init__(self, connection: Connection):
|
|
43
|
-
|
|
52
|
+
from sqlalchemy.future import Connection
|
|
53
|
+
|
|
54
|
+
self.connection: Connection = connection
|
|
44
55
|
|
|
45
56
|
def execute(
|
|
46
57
|
self, statement: str, parameters: Any | None = None
|
|
47
58
|
) -> SqlAlchemyResult:
|
|
48
59
|
return SqlAlchemyResult(self.connection.execute(statement, parameters))
|
|
49
60
|
|
|
61
|
+
def commit(self):
|
|
62
|
+
self.connection.commit()
|
|
63
|
+
|
|
64
|
+
def begin(self):
|
|
65
|
+
self.connection.begin()
|
|
66
|
+
|
|
67
|
+
def rollback(self):
|
|
68
|
+
self.connection.rollback()
|
|
69
|
+
|
|
50
70
|
|
|
51
71
|
class SqlAlchemyEngine(ExecutionEngine):
|
|
52
72
|
def __init__(self, engine: Engine):
|
|
@@ -36,6 +36,7 @@ from trilogy.dialect.enums import Dialects
|
|
|
36
36
|
from trilogy.engine import ExecutionEngine
|
|
37
37
|
from trilogy.hooks.base_hook import BaseHook
|
|
38
38
|
from trilogy.parser import parse_text
|
|
39
|
+
from trilogy.render import get_dialect_generator
|
|
39
40
|
|
|
40
41
|
|
|
41
42
|
class ResultProtocol(Protocol):
|
|
@@ -82,40 +83,7 @@ class Executor(object):
|
|
|
82
83
|
self.generator: BaseDialect
|
|
83
84
|
self.logger = logger
|
|
84
85
|
self.hooks = hooks
|
|
85
|
-
|
|
86
|
-
from trilogy.dialect.bigquery import BigqueryDialect
|
|
87
|
-
|
|
88
|
-
self.generator = BigqueryDialect()
|
|
89
|
-
elif self.dialect == Dialects.SQL_SERVER:
|
|
90
|
-
from trilogy.dialect.sql_server import SqlServerDialect
|
|
91
|
-
|
|
92
|
-
self.generator = SqlServerDialect()
|
|
93
|
-
elif self.dialect == Dialects.DUCK_DB:
|
|
94
|
-
from trilogy.dialect.duckdb import DuckDBDialect
|
|
95
|
-
|
|
96
|
-
self.generator = DuckDBDialect()
|
|
97
|
-
elif self.dialect == Dialects.PRESTO:
|
|
98
|
-
from trilogy.dialect.presto import PrestoDialect
|
|
99
|
-
|
|
100
|
-
self.generator = PrestoDialect()
|
|
101
|
-
elif self.dialect == Dialects.TRINO:
|
|
102
|
-
from trilogy.dialect.presto import TrinoDialect
|
|
103
|
-
|
|
104
|
-
self.generator = TrinoDialect()
|
|
105
|
-
elif self.dialect == Dialects.POSTGRES:
|
|
106
|
-
from trilogy.dialect.postgres import PostgresDialect
|
|
107
|
-
|
|
108
|
-
self.generator = PostgresDialect()
|
|
109
|
-
elif self.dialect == Dialects.SNOWFLAKE:
|
|
110
|
-
from trilogy.dialect.snowflake import SnowflakeDialect
|
|
111
|
-
|
|
112
|
-
self.generator = SnowflakeDialect()
|
|
113
|
-
elif self.dialect == Dialects.DATAFRAME:
|
|
114
|
-
from trilogy.dialect.dataframe import DataframeDialect
|
|
115
|
-
|
|
116
|
-
self.generator = DataframeDialect()
|
|
117
|
-
else:
|
|
118
|
-
raise ValueError(f"Unsupported dialect {self.dialect}")
|
|
86
|
+
self.generator = get_dialect_generator(self.dialect)
|
|
119
87
|
self.connection = self.engine.connect()
|
|
120
88
|
# TODO: make generic
|
|
121
89
|
if self.dialect == Dialects.DATAFRAME:
|
|
@@ -97,7 +97,12 @@ from trilogy.core.models.datasource import (
|
|
|
97
97
|
Query,
|
|
98
98
|
RawColumnExpr,
|
|
99
99
|
)
|
|
100
|
-
from trilogy.core.models.environment import
|
|
100
|
+
from trilogy.core.models.environment import (
|
|
101
|
+
DictImportResolver,
|
|
102
|
+
Environment,
|
|
103
|
+
FileSystemImportResolver,
|
|
104
|
+
Import,
|
|
105
|
+
)
|
|
101
106
|
from trilogy.core.statements.author import (
|
|
102
107
|
ConceptDeclarationStatement,
|
|
103
108
|
ConceptDerivationStatement,
|
|
@@ -223,7 +228,7 @@ class ParseToObjects(Transformer):
|
|
|
223
228
|
self,
|
|
224
229
|
environment: Environment,
|
|
225
230
|
parse_address: str | None = None,
|
|
226
|
-
token_address: Path | None = None,
|
|
231
|
+
token_address: Path | str | None = None,
|
|
227
232
|
parsed: dict[str, "ParseToObjects"] | None = None,
|
|
228
233
|
tokens: dict[Path | str, ParseTree] | None = None,
|
|
229
234
|
text_lookup: dict[Path | str, str] | None = None,
|
|
@@ -854,8 +859,22 @@ class ParseToObjects(Transformer):
|
|
|
854
859
|
)
|
|
855
860
|
|
|
856
861
|
def resolve_import_address(self, address) -> str:
|
|
857
|
-
|
|
858
|
-
|
|
862
|
+
if isinstance(
|
|
863
|
+
self.environment.config.import_resolver, FileSystemImportResolver
|
|
864
|
+
):
|
|
865
|
+
with open(address, "r", encoding="utf-8") as f:
|
|
866
|
+
text = f.read()
|
|
867
|
+
elif isinstance(self.environment.config.import_resolver, DictImportResolver):
|
|
868
|
+
lookup = address
|
|
869
|
+
if lookup not in self.environment.config.import_resolver.content:
|
|
870
|
+
raise ImportError(
|
|
871
|
+
f"Unable to import file {lookup}, not found in import resolver"
|
|
872
|
+
)
|
|
873
|
+
text = self.environment.config.import_resolver.content[lookup]
|
|
874
|
+
else:
|
|
875
|
+
raise ImportError(
|
|
876
|
+
f"Unable to import file {address}, resolver type {type(self.environment.config.import_resolver)} not supported"
|
|
877
|
+
)
|
|
859
878
|
return text
|
|
860
879
|
|
|
861
880
|
def import_statement(self, args: list[str]) -> ImportStatement:
|
|
@@ -867,10 +886,17 @@ class ParseToObjects(Transformer):
|
|
|
867
886
|
cache_key = args[0]
|
|
868
887
|
path = args[0].split(".")
|
|
869
888
|
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
889
|
+
if isinstance(
|
|
890
|
+
self.environment.config.import_resolver, FileSystemImportResolver
|
|
891
|
+
):
|
|
892
|
+
target = join(self.environment.working_path, *path) + ".preql"
|
|
893
|
+
# tokens + text are cached by path
|
|
894
|
+
token_lookup: Path | str = Path(target)
|
|
895
|
+
elif isinstance(self.environment.config.import_resolver, DictImportResolver):
|
|
896
|
+
target = ".".join(path)
|
|
897
|
+
token_lookup = target
|
|
898
|
+
else:
|
|
899
|
+
raise NotImplementedError
|
|
874
900
|
|
|
875
901
|
# parser + env has to be cached by prior import path + current key
|
|
876
902
|
key_path = self.import_keys + [cache_key]
|
|
@@ -901,6 +927,7 @@ class ParseToObjects(Transformer):
|
|
|
901
927
|
new_env = Environment(
|
|
902
928
|
working_path=dirname(target),
|
|
903
929
|
env_file_path=token_lookup,
|
|
930
|
+
config=self.environment.config,
|
|
904
931
|
)
|
|
905
932
|
new_env.concepts.fail_on_missing = False
|
|
906
933
|
self.parsed[self.parse_address] = self
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from trilogy.dialect.enums import Dialects
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def get_dialect_generator(dialect: Dialects):
|
|
5
|
+
if dialect == Dialects.BIGQUERY:
|
|
6
|
+
from trilogy.dialect.bigquery import BigqueryDialect
|
|
7
|
+
|
|
8
|
+
return BigqueryDialect()
|
|
9
|
+
elif dialect == Dialects.SQL_SERVER:
|
|
10
|
+
from trilogy.dialect.sql_server import SqlServerDialect
|
|
11
|
+
|
|
12
|
+
return SqlServerDialect()
|
|
13
|
+
elif dialect == Dialects.DUCK_DB:
|
|
14
|
+
from trilogy.dialect.duckdb import DuckDBDialect
|
|
15
|
+
|
|
16
|
+
return DuckDBDialect()
|
|
17
|
+
elif dialect == Dialects.PRESTO:
|
|
18
|
+
from trilogy.dialect.presto import PrestoDialect
|
|
19
|
+
|
|
20
|
+
return PrestoDialect()
|
|
21
|
+
elif dialect == Dialects.TRINO:
|
|
22
|
+
from trilogy.dialect.presto import TrinoDialect
|
|
23
|
+
|
|
24
|
+
return TrinoDialect()
|
|
25
|
+
elif dialect == Dialects.POSTGRES:
|
|
26
|
+
from trilogy.dialect.postgres import PostgresDialect
|
|
27
|
+
|
|
28
|
+
return PostgresDialect()
|
|
29
|
+
elif dialect == Dialects.SNOWFLAKE:
|
|
30
|
+
from trilogy.dialect.snowflake import SnowflakeDialect
|
|
31
|
+
|
|
32
|
+
return SnowflakeDialect()
|
|
33
|
+
elif dialect == Dialects.DATAFRAME:
|
|
34
|
+
from trilogy.dialect.dataframe import DataframeDialect
|
|
35
|
+
|
|
36
|
+
return DataframeDialect()
|
|
37
|
+
else:
|
|
38
|
+
raise ValueError(f"Unsupported dialect {dialect}")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/processing/node_generators/__init__.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/processing/node_generators/basic_node.py
RENAMED
|
File without changes
|
|
File without changes
|
{pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/processing/node_generators/filter_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/processing/node_generators/group_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/processing/node_generators/group_to_node.py
RENAMED
|
File without changes
|
|
File without changes
|
{pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/processing/node_generators/node_merge_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/processing/node_generators/rowset_node.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/processing/node_generators/select_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/processing/node_generators/synonym_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/processing/node_generators/union_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/processing/node_generators/unnest_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.10 → pytrilogy-0.0.3.12}/trilogy/core/processing/node_generators/window_node.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|