pytrilogy 0.0.2.4__tar.gz → 0.0.2.6__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.2.4/pytrilogy.egg-info → pytrilogy-0.0.2.6}/PKG-INFO +1 -1
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6/pytrilogy.egg-info}/PKG-INFO +1 -1
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/tests/test_parsing.py +45 -1
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/tests/test_where_clause.py +31 -2
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/__init__.py +1 -1
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/core/enums.py +1 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/core/models.py +21 -6
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/core/optimizations/inline_datasource.py +6 -2
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/dialect/base.py +8 -5
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/dialect/common.py +2 -1
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/dialect/duckdb.py +0 -1
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/dialect/presto.py +2 -1
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/parsing/parse_engine.py +6 -3
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/parsing/trilogy.lark +3 -2
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/LICENSE.md +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/README.md +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/pyproject.toml +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/pytrilogy.egg-info/SOURCES.txt +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/pytrilogy.egg-info/dependency_links.txt +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/pytrilogy.egg-info/entry_points.txt +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/pytrilogy.egg-info/requires.txt +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/pytrilogy.egg-info/top_level.txt +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/setup.cfg +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/setup.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/tests/test_datatypes.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/tests/test_declarations.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/tests/test_derived_concepts.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/tests/test_discovery_nodes.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/tests/test_environment.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/tests/test_functions.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/tests/test_imports.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/tests/test_metadata.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/tests/test_models.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/tests/test_multi_join_assignments.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/tests/test_partial_handling.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/tests/test_query_processing.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/tests/test_select.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/tests/test_statements.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/tests/test_undefined_concept.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/compiler.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/constants.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/core/__init__.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/core/constants.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/core/env_processor.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/core/environment_helpers.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/core/ergonomics.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/core/exceptions.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/core/functions.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/core/graph_models.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/core/internal.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/core/optimization.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/core/optimizations/__init__.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/core/optimizations/base_optimization.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/core/optimizations/inline_constant.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/core/optimizations/predicate_pushdown.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/core/processing/__init__.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/core/processing/concept_strategies_v3.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/core/processing/graph_utils.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/core/processing/node_generators/__init__.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/core/processing/node_generators/basic_node.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/core/processing/node_generators/common.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/core/processing/node_generators/filter_node.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/core/processing/node_generators/group_node.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/core/processing/node_generators/group_to_node.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/core/processing/node_generators/multiselect_node.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/core/processing/node_generators/node_merge_node.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/core/processing/node_generators/rowset_node.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/core/processing/node_generators/select_node.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/core/processing/node_generators/unnest_node.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/core/processing/node_generators/window_node.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/core/processing/nodes/__init__.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/core/processing/nodes/base_node.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/core/processing/nodes/filter_node.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/core/processing/nodes/group_node.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/core/processing/nodes/merge_node.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/core/processing/nodes/select_node_v2.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/core/processing/nodes/unnest_node.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/core/processing/nodes/window_node.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/core/processing/utility.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/core/query_processor.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/dialect/__init__.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/dialect/bigquery.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/dialect/config.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/dialect/enums.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/dialect/postgres.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/dialect/snowflake.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/dialect/sql_server.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/engine.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/executor.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/hooks/__init__.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/hooks/base_hook.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/hooks/graph_hook.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/hooks/query_debugger.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/metadata/__init__.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/parser.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/parsing/__init__.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/parsing/common.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/parsing/config.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/parsing/exceptions.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/parsing/helpers.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/parsing/render.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/py.typed +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/scripts/__init__.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/scripts/trilogy.py +0 -0
- {pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/utility.py +0 -0
|
@@ -160,7 +160,8 @@ address `preqldata.analytics_411641820.events_*`
|
|
|
160
160
|
;"""
|
|
161
161
|
)
|
|
162
162
|
query = parsed[-1]
|
|
163
|
-
assert query.address.
|
|
163
|
+
assert query.address.quoted is True
|
|
164
|
+
assert query.address.location == "preqldata.analytics_411641820.events_*"
|
|
164
165
|
|
|
165
166
|
|
|
166
167
|
def test_purpose_and_keys():
|
|
@@ -448,3 +449,46 @@ select
|
|
|
448
449
|
{"a": 1, "b": 2, "c": 3},
|
|
449
450
|
1,
|
|
450
451
|
)
|
|
452
|
+
|
|
453
|
+
|
|
454
|
+
def test_datasource_colon():
|
|
455
|
+
|
|
456
|
+
text = """
|
|
457
|
+
key x int;
|
|
458
|
+
key y int;
|
|
459
|
+
|
|
460
|
+
datasource test (
|
|
461
|
+
x:x,
|
|
462
|
+
y:y)
|
|
463
|
+
grain(x)
|
|
464
|
+
address `abc:def`
|
|
465
|
+
;
|
|
466
|
+
|
|
467
|
+
|
|
468
|
+
select x;
|
|
469
|
+
"""
|
|
470
|
+
env, parsed = parse_text(text)
|
|
471
|
+
|
|
472
|
+
results = Dialects.DUCK_DB.default_executor().generate_sql(text)[0]
|
|
473
|
+
|
|
474
|
+
assert '"abc:def" as test' in results
|
|
475
|
+
|
|
476
|
+
text = """
|
|
477
|
+
key x int;
|
|
478
|
+
key y int;
|
|
479
|
+
|
|
480
|
+
datasource test (
|
|
481
|
+
x:x,
|
|
482
|
+
y:y)
|
|
483
|
+
grain(x)
|
|
484
|
+
address abcdef
|
|
485
|
+
;
|
|
486
|
+
|
|
487
|
+
|
|
488
|
+
select x;
|
|
489
|
+
"""
|
|
490
|
+
env, parsed = parse_text(text)
|
|
491
|
+
|
|
492
|
+
results = Dialects.DUCK_DB.default_executor().generate_sql(text)[0]
|
|
493
|
+
|
|
494
|
+
assert "abcdef as test" in results, results
|
|
@@ -227,5 +227,34 @@ where
|
|
|
227
227
|
select: SelectStatement = parsed[-1]
|
|
228
228
|
|
|
229
229
|
assert is_scalar_condition(select.where_clause.conditional) is False
|
|
230
|
-
|
|
231
|
-
|
|
230
|
+
_ = BaseDialect().compile_statement(process_query(test_environment, select))
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
def test_case_where(test_environment):
|
|
234
|
+
from trilogy.hooks.query_debugger import DebuggingHook
|
|
235
|
+
|
|
236
|
+
declarations = """property order_id_even_name <- CASE
|
|
237
|
+
when order_id %2 = 0 then 'even'
|
|
238
|
+
else 'odd'
|
|
239
|
+
END;
|
|
240
|
+
|
|
241
|
+
const test <- 1;
|
|
242
|
+
|
|
243
|
+
auto order_even_class_filter <- filter category_id where order_id_even_name = 'even' and 1= test;
|
|
244
|
+
|
|
245
|
+
select
|
|
246
|
+
category_id,
|
|
247
|
+
category_name
|
|
248
|
+
where
|
|
249
|
+
category_name like '%abc%' and category_id not in order_even_class_filter
|
|
250
|
+
and category_id = test
|
|
251
|
+
;"""
|
|
252
|
+
env, parsed = parse(declarations, environment=test_environment)
|
|
253
|
+
select: SelectStatement = parsed[-1]
|
|
254
|
+
|
|
255
|
+
query = BaseDialect().compile_statement(
|
|
256
|
+
process_query(test_environment, select, hooks=[DebuggingHook()])
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
# check to make sure our subselect is well-formed
|
|
260
|
+
assert "`category_id` not in (select" in query, query
|
|
@@ -1817,6 +1817,7 @@ class MultiSelectStatement(SelectTypeMixin, Mergeable, Namespaced, BaseModel):
|
|
|
1817
1817
|
class Address(BaseModel):
|
|
1818
1818
|
location: str
|
|
1819
1819
|
is_query: bool = False
|
|
1820
|
+
quoted: bool = False
|
|
1820
1821
|
|
|
1821
1822
|
|
|
1822
1823
|
class Query(BaseModel):
|
|
@@ -2433,7 +2434,13 @@ class CTE(BaseModel):
|
|
|
2433
2434
|
# if we've entirely removed the need to join to someplace to get the concept
|
|
2434
2435
|
# drop the join as well.
|
|
2435
2436
|
for removed_cte in removed:
|
|
2436
|
-
still_required = any(
|
|
2437
|
+
still_required = any(
|
|
2438
|
+
[
|
|
2439
|
+
removed_cte in x
|
|
2440
|
+
for x in self.source_map.values()
|
|
2441
|
+
or self.existence_source_map.values()
|
|
2442
|
+
]
|
|
2443
|
+
)
|
|
2437
2444
|
if not still_required:
|
|
2438
2445
|
self.joins = [
|
|
2439
2446
|
join
|
|
@@ -2451,6 +2458,7 @@ class CTE(BaseModel):
|
|
|
2451
2458
|
candidates = [x.name for x in self.parent_ctes]
|
|
2452
2459
|
self.base_name_override = candidates[0] if candidates else None
|
|
2453
2460
|
self.base_alias_override = candidates[0] if candidates else None
|
|
2461
|
+
return True
|
|
2454
2462
|
|
|
2455
2463
|
def inline_parent_datasource(self, parent: CTE, force_group: bool = False) -> bool:
|
|
2456
2464
|
qds_being_inlined = parent.source
|
|
@@ -2572,6 +2580,16 @@ class CTE(BaseModel):
|
|
|
2572
2580
|
return self.relevant_base_ctes[0].name
|
|
2573
2581
|
return self.source.name
|
|
2574
2582
|
|
|
2583
|
+
@property
|
|
2584
|
+
def quote_address(self) -> bool:
|
|
2585
|
+
if self.is_root_datasource:
|
|
2586
|
+
candidate = self.source.datasources[0]
|
|
2587
|
+
if isinstance(candidate, Datasource) and isinstance(
|
|
2588
|
+
candidate.address, Address
|
|
2589
|
+
):
|
|
2590
|
+
return candidate.address.quoted
|
|
2591
|
+
return False
|
|
2592
|
+
|
|
2575
2593
|
@property
|
|
2576
2594
|
def base_alias(self) -> str:
|
|
2577
2595
|
if self.base_alias_override:
|
|
@@ -3315,7 +3333,7 @@ class Comparison(
|
|
|
3315
3333
|
and self.operator == other.operator
|
|
3316
3334
|
)
|
|
3317
3335
|
|
|
3318
|
-
def inline_constant(self, constant: Concept)
|
|
3336
|
+
def inline_constant(self, constant: Concept):
|
|
3319
3337
|
assert isinstance(constant.lineage, Function)
|
|
3320
3338
|
new_val = constant.lineage.arguments[0]
|
|
3321
3339
|
if isinstance(self.left, ConstantInlineable):
|
|
@@ -3332,10 +3350,7 @@ class Comparison(
|
|
|
3332
3350
|
else:
|
|
3333
3351
|
new_right = self.right
|
|
3334
3352
|
|
|
3335
|
-
|
|
3336
|
-
new_right = new_val
|
|
3337
|
-
|
|
3338
|
-
return Comparison(
|
|
3353
|
+
return self.__class__(
|
|
3339
3354
|
left=new_left,
|
|
3340
3355
|
right=new_right,
|
|
3341
3356
|
operator=self.operator,
|
|
@@ -43,10 +43,14 @@ class InlineDatasource(OptimizationRule):
|
|
|
43
43
|
continue
|
|
44
44
|
root_outputs = {x.address for x in root.output_concepts}
|
|
45
45
|
cte_outputs = {x.address for x in cte.output_columns}
|
|
46
|
+
inherited = {x for x, v in cte.source_map.items() if v}
|
|
46
47
|
# cte_inherited_outputs = {x.address for x in parent_cte.output_columns if parent_cte.source_map.get(x.address)}
|
|
47
48
|
grain_components = {x.address for x in root.grain.components}
|
|
48
|
-
if not
|
|
49
|
-
|
|
49
|
+
if not inherited.issubset(root_outputs):
|
|
50
|
+
cte_missing = inherited - root_outputs
|
|
51
|
+
self.log(
|
|
52
|
+
f"Not all {parent_cte.name} require inputs are found on datasource, missing {cte_missing}"
|
|
53
|
+
)
|
|
50
54
|
continue
|
|
51
55
|
if not grain_components.issubset(cte_outputs):
|
|
52
56
|
self.log("Not all datasource components in cte outputs, forcing group")
|
|
@@ -188,10 +188,11 @@ FUNCTION_GRAIN_MATCH_MAP = {
|
|
|
188
188
|
GENERIC_SQL_TEMPLATE = Template(
|
|
189
189
|
"""{%- if ctes %}
|
|
190
190
|
WITH {% for cte in ctes %}
|
|
191
|
-
{{cte.name}} as (
|
|
191
|
+
{{cte.name}} as (
|
|
192
|
+
{{cte.statement}}){% if not loop.last %},{% endif %}{% endfor %}{% endif %}
|
|
192
193
|
{%- if full_select -%}
|
|
193
194
|
{{full_select}}
|
|
194
|
-
{
|
|
195
|
+
{% else -%}
|
|
195
196
|
SELECT
|
|
196
197
|
{%- if limit is not none %}
|
|
197
198
|
TOP {{ limit }}{% endif %}
|
|
@@ -498,10 +499,12 @@ class BaseDialect:
|
|
|
498
499
|
for c in cte.output_columns
|
|
499
500
|
if c.address not in [y.address for y in cte.hidden_concepts]
|
|
500
501
|
]
|
|
501
|
-
if cte.
|
|
502
|
-
source = cte.base_name
|
|
502
|
+
if cte.quote_address:
|
|
503
|
+
source = f"{self.QUOTE_CHARACTER}{cte.base_name}{self.QUOTE_CHARACTER}"
|
|
503
504
|
else:
|
|
504
|
-
source =
|
|
505
|
+
source = cte.base_name
|
|
506
|
+
if cte.base_name != cte.base_alias:
|
|
507
|
+
source = f"{source} as {cte.base_alias}"
|
|
505
508
|
return CompiledCTE(
|
|
506
509
|
name=cte.name,
|
|
507
510
|
statement=self.SQL_TEMPLATE.render(
|
|
@@ -26,7 +26,8 @@ def render_join(
|
|
|
26
26
|
raise ValueError("must provide a cte to build an unnest joins")
|
|
27
27
|
if unnest_mode == UnnestMode.CROSS_JOIN:
|
|
28
28
|
return f"CROSS JOIN {render_func(join.concept, cte, False)} as {quote_character}{join.concept.safe_address}{quote_character}"
|
|
29
|
-
|
|
29
|
+
if unnest_mode == UnnestMode.CROSS_JOIN_ALIAS:
|
|
30
|
+
return f"CROSS JOIN {render_func(join.concept, cte, False)} as array_unnest ({quote_character}{join.concept.safe_address}{quote_character})"
|
|
30
31
|
return f"FULL JOIN {render_func(join.concept, cte, False)} as unnest_wrapper({quote_character}{join.concept.safe_address}{quote_character})"
|
|
31
32
|
left_name = join.left_name
|
|
32
33
|
right_name = join.right_name
|
|
@@ -49,7 +49,6 @@ WITH {% for cte in ctes %}
|
|
|
49
49
|
{{cte.name}} as ({{cte.statement}}){% if not loop.last %},{% endif %}{% endfor %}{% endif %}
|
|
50
50
|
{% if full_select -%}{{full_select}}
|
|
51
51
|
{% else -%}
|
|
52
|
-
|
|
53
52
|
SELECT
|
|
54
53
|
{%- for select in select_columns %}
|
|
55
54
|
{{ select }}{% if not loop.last %},{% endif %}{% endfor %}
|
|
@@ -5,7 +5,7 @@ from jinja2 import Template
|
|
|
5
5
|
from trilogy.core.enums import FunctionType, WindowType
|
|
6
6
|
from trilogy.dialect.base import BaseDialect
|
|
7
7
|
from trilogy.core.models import DataType
|
|
8
|
-
|
|
8
|
+
from trilogy.core.enums import UnnestMode
|
|
9
9
|
|
|
10
10
|
WINDOW_FUNCTION_MAP: Mapping[WindowType, Callable[[Any, Any, Any], str]] = {}
|
|
11
11
|
|
|
@@ -86,6 +86,7 @@ class PrestoDialect(BaseDialect):
|
|
|
86
86
|
QUOTE_CHARACTER = '"'
|
|
87
87
|
SQL_TEMPLATE = SQL_TEMPLATE
|
|
88
88
|
DATATYPE_MAP = {**BaseDialect.DATATYPE_MAP, DataType.NUMERIC: "DECIMAL"}
|
|
89
|
+
UNNEST_MODE = UnnestMode.CROSS_JOIN
|
|
89
90
|
|
|
90
91
|
|
|
91
92
|
class TrinoDialect(PrestoDialect):
|
|
@@ -297,8 +297,11 @@ class ParseToObjects(Transformer):
|
|
|
297
297
|
def concept_lit(self, args) -> Concept:
|
|
298
298
|
return self.environment.concepts.__getitem__(args[0])
|
|
299
299
|
|
|
300
|
-
def ADDRESS(self, args) ->
|
|
301
|
-
return args.value
|
|
300
|
+
def ADDRESS(self, args) -> Address:
|
|
301
|
+
return Address(location=args.value, quoted=False)
|
|
302
|
+
|
|
303
|
+
def QUOTED_ADDRESS(self, args) -> Address:
|
|
304
|
+
return Address(location=args.value[1:-1], quoted=True)
|
|
302
305
|
|
|
303
306
|
def STRING_CHARS(self, args) -> str:
|
|
304
307
|
return args.value
|
|
@@ -1010,7 +1013,7 @@ class ParseToObjects(Transformer):
|
|
|
1010
1013
|
|
|
1011
1014
|
@v_args(meta=True)
|
|
1012
1015
|
def address(self, meta: Meta, args):
|
|
1013
|
-
return
|
|
1016
|
+
return args[0]
|
|
1014
1017
|
|
|
1015
1018
|
@v_args(meta=True)
|
|
1016
1019
|
def query(self, meta: Meta, args):
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
|
|
40
40
|
grain_clause: "grain" "(" column_list ")"
|
|
41
41
|
|
|
42
|
-
address: "address" ADDRESS
|
|
42
|
+
address: "address" (QUOTED_ADDRESS | ADDRESS)
|
|
43
43
|
|
|
44
44
|
query: "query" MULTILINE_STRING
|
|
45
45
|
|
|
@@ -258,7 +258,8 @@
|
|
|
258
258
|
// base language constructs
|
|
259
259
|
concept_lit: IDENTIFIER
|
|
260
260
|
IDENTIFIER: /[a-zA-Z\_][a-zA-Z0-9\_\-\.\-]*/
|
|
261
|
-
|
|
261
|
+
QUOTED_ADDRESS: /`[a-zA-Z\_][a-zA-Z0-9\_\-\.\-\*\:]*`/
|
|
262
|
+
ADDRESS: IDENTIFIER
|
|
262
263
|
|
|
263
264
|
MULTILINE_STRING: /\'{3}(.*?)\'{3}/s
|
|
264
265
|
|
|
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.2.4 → pytrilogy-0.0.2.6}/trilogy/core/processing/node_generators/basic_node.py
RENAMED
|
File without changes
|
|
File without changes
|
{pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/core/processing/node_generators/filter_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/core/processing/node_generators/group_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/core/processing/node_generators/group_to_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/core/processing/node_generators/multiselect_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/core/processing/node_generators/node_merge_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/core/processing/node_generators/rowset_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/core/processing/node_generators/select_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/trilogy/core/processing/node_generators/unnest_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.2.4 → pytrilogy-0.0.2.6}/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
|