pytrilogy 0.0.2.36__tar.gz → 0.0.2.37__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.36/pytrilogy.egg-info → pytrilogy-0.0.2.37}/PKG-INFO +1 -1
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37/pytrilogy.egg-info}/PKG-INFO +1 -1
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/tests/test_select.py +1 -1
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/__init__.py +1 -1
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/constants.py +8 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/core/models.py +17 -16
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/dialect/base.py +8 -1
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/executor.py +47 -8
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/parsing/parse_engine.py +2 -1
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/parsing/trilogy.lark +1 -1
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/LICENSE.md +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/README.md +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/pyproject.toml +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/pytrilogy.egg-info/SOURCES.txt +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/pytrilogy.egg-info/dependency_links.txt +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/pytrilogy.egg-info/entry_points.txt +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/pytrilogy.egg-info/requires.txt +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/pytrilogy.egg-info/top_level.txt +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/setup.cfg +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/setup.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/tests/test_datatypes.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/tests/test_declarations.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/tests/test_derived_concepts.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/tests/test_discovery_nodes.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/tests/test_enums.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/tests/test_environment.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/tests/test_executor.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/tests/test_functions.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/tests/test_imports.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/tests/test_metadata.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/tests/test_models.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/tests/test_multi_join_assignments.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/tests/test_parse_engine.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/tests/test_parsing.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/tests/test_partial_handling.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/tests/test_query_processing.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/tests/test_show.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/tests/test_statements.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/tests/test_undefined_concept.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/tests/test_where_clause.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/compiler.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/core/__init__.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/core/constants.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/core/enums.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/core/env_processor.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/core/environment_helpers.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/core/ergonomics.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/core/exceptions.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/core/functions.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/core/graph_models.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/core/internal.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/core/optimization.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/core/optimizations/__init__.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/core/optimizations/base_optimization.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/core/optimizations/inline_constant.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/core/optimizations/inline_datasource.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/core/optimizations/predicate_pushdown.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/core/processing/__init__.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/core/processing/concept_strategies_v3.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/core/processing/graph_utils.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/core/processing/node_generators/__init__.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/core/processing/node_generators/basic_node.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/core/processing/node_generators/common.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/core/processing/node_generators/filter_node.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/core/processing/node_generators/group_node.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/core/processing/node_generators/group_to_node.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/core/processing/node_generators/multiselect_node.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/core/processing/node_generators/node_merge_node.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/core/processing/node_generators/rowset_node.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/core/processing/node_generators/select_merge_node.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/core/processing/node_generators/select_node.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/core/processing/node_generators/unnest_node.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/core/processing/node_generators/window_node.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/core/processing/nodes/__init__.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/core/processing/nodes/base_node.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/core/processing/nodes/filter_node.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/core/processing/nodes/group_node.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/core/processing/nodes/merge_node.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/core/processing/nodes/select_node_v2.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/core/processing/nodes/unnest_node.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/core/processing/nodes/window_node.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/core/processing/utility.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/core/query_processor.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/dialect/__init__.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/dialect/bigquery.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/dialect/common.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/dialect/config.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/dialect/duckdb.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/dialect/enums.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/dialect/postgres.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/dialect/presto.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/dialect/snowflake.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/dialect/sql_server.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/engine.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/hooks/__init__.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/hooks/base_hook.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/hooks/graph_hook.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/hooks/query_debugger.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/metadata/__init__.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/parser.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/parsing/__init__.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/parsing/common.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/parsing/config.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/parsing/exceptions.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/parsing/helpers.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/parsing/render.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/py.typed +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/scripts/__init__.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/scripts/trilogy.py +0 -0
- {pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/utility.py +0 -0
|
@@ -39,6 +39,13 @@ class Comments:
|
|
|
39
39
|
partial: bool = True
|
|
40
40
|
|
|
41
41
|
|
|
42
|
+
@dataclass
|
|
43
|
+
class Rendering:
|
|
44
|
+
"""Control how the SQL is rendered"""
|
|
45
|
+
|
|
46
|
+
parameters: bool = True
|
|
47
|
+
|
|
48
|
+
|
|
42
49
|
# TODO: support loading from environments
|
|
43
50
|
@dataclass
|
|
44
51
|
class Config:
|
|
@@ -48,6 +55,7 @@ class Config:
|
|
|
48
55
|
validate_missing: bool = True
|
|
49
56
|
comments: Comments = field(default_factory=Comments)
|
|
50
57
|
optimizations: Optimizations = field(default_factory=Optimizations)
|
|
58
|
+
rendering: Rendering = field(default_factory=Rendering)
|
|
51
59
|
|
|
52
60
|
@property
|
|
53
61
|
def show_comments(self) -> bool:
|
|
@@ -3381,6 +3381,21 @@ class Environment(BaseModel):
|
|
|
3381
3381
|
materialized_concepts: List[Concept] = Field(default_factory=list)
|
|
3382
3382
|
alias_origin_lookup: Dict[str, Concept] = Field(default_factory=dict)
|
|
3383
3383
|
|
|
3384
|
+
def __init__(self, **data):
|
|
3385
|
+
super().__init__(**data)
|
|
3386
|
+
self.concepts["_env_working_path"] = Concept(
|
|
3387
|
+
name="_env_working_path",
|
|
3388
|
+
namespace=self.namespace,
|
|
3389
|
+
lineage=Function(
|
|
3390
|
+
operator=FunctionType.CONSTANT,
|
|
3391
|
+
arguments=[str(self.working_path)],
|
|
3392
|
+
output_datatype=DataType.STRING,
|
|
3393
|
+
output_purpose=Purpose.CONSTANT,
|
|
3394
|
+
),
|
|
3395
|
+
datatype=DataType.STRING,
|
|
3396
|
+
purpose=Purpose.CONSTANT,
|
|
3397
|
+
)
|
|
3398
|
+
|
|
3384
3399
|
@classmethod
|
|
3385
3400
|
def from_file(cls, path: str | Path) -> "Environment":
|
|
3386
3401
|
with open(path, "r") as f:
|
|
@@ -3554,16 +3569,7 @@ class Environment(BaseModel):
|
|
|
3554
3569
|
target = target.with_suffix(".preql")
|
|
3555
3570
|
else:
|
|
3556
3571
|
target = path
|
|
3557
|
-
if
|
|
3558
|
-
imports = self.imports[alias]
|
|
3559
|
-
for x in imports:
|
|
3560
|
-
if x.path == target:
|
|
3561
|
-
return imports
|
|
3562
|
-
if env:
|
|
3563
|
-
self.imports[alias].append(
|
|
3564
|
-
ImportStatement(alias=alias, path=target, environment=env)
|
|
3565
|
-
)
|
|
3566
|
-
else:
|
|
3572
|
+
if not env:
|
|
3567
3573
|
parse_address = gen_cache_lookup(str(target), alias, str(self.working_path))
|
|
3568
3574
|
try:
|
|
3569
3575
|
with open(target, "r", encoding="utf-8") as f:
|
|
@@ -3587,13 +3593,8 @@ class Environment(BaseModel):
|
|
|
3587
3593
|
f"Unable to import file {target.parent}, parsing error: {e}"
|
|
3588
3594
|
)
|
|
3589
3595
|
env = nparser.environment
|
|
3590
|
-
for _, concept in env.concepts.items():
|
|
3591
|
-
self.add_concept(concept.with_namespace(alias))
|
|
3592
|
-
|
|
3593
|
-
for _, datasource in env.datasources.items():
|
|
3594
|
-
self.add_datasource(datasource.with_namespace(alias))
|
|
3595
3596
|
imps = ImportStatement(alias=alias, path=target, environment=env)
|
|
3596
|
-
self.
|
|
3597
|
+
self.add_import(alias, source=env, imp_stm=imps)
|
|
3597
3598
|
return imps
|
|
3598
3599
|
|
|
3599
3600
|
def parse(
|
|
@@ -337,6 +337,13 @@ class BaseDialect:
|
|
|
337
337
|
" target grain"
|
|
338
338
|
)
|
|
339
339
|
rval = f"{self.FUNCTION_GRAIN_MATCH_MAP[c.lineage.function.operator](args)}"
|
|
340
|
+
elif (
|
|
341
|
+
isinstance(c.lineage, Function)
|
|
342
|
+
and c.lineage.operator == FunctionType.CONSTANT
|
|
343
|
+
and CONFIG.rendering.parameters is True
|
|
344
|
+
and c.datatype.data_type != DataType.MAP
|
|
345
|
+
):
|
|
346
|
+
rval = f":{c.safe_address}"
|
|
340
347
|
else:
|
|
341
348
|
args = [
|
|
342
349
|
self.render_expr(
|
|
@@ -541,7 +548,7 @@ class BaseDialect:
|
|
|
541
548
|
else:
|
|
542
549
|
raise ValueError(f"Unable to render type {type(e)} {e}")
|
|
543
550
|
|
|
544
|
-
def render_cte(self, cte: CTE, auto_sort: bool = True):
|
|
551
|
+
def render_cte(self, cte: CTE, auto_sort: bool = True) -> CompiledCTE:
|
|
545
552
|
if self.UNNEST_MODE in (
|
|
546
553
|
UnnestMode.CROSS_APPLY,
|
|
547
554
|
UnnestMode.CROSS_JOIN,
|
|
@@ -22,10 +22,14 @@ from trilogy.core.models import (
|
|
|
22
22
|
CopyStatement,
|
|
23
23
|
ImportStatement,
|
|
24
24
|
MergeStatementV2,
|
|
25
|
+
Function,
|
|
26
|
+
FunctionType,
|
|
27
|
+
MapWrapper,
|
|
28
|
+
ListWrapper,
|
|
25
29
|
)
|
|
26
30
|
from trilogy.dialect.base import BaseDialect
|
|
27
31
|
from trilogy.dialect.enums import Dialects
|
|
28
|
-
from trilogy.core.enums import IOType
|
|
32
|
+
from trilogy.core.enums import IOType, Granularity
|
|
29
33
|
from trilogy.parser import parse_text
|
|
30
34
|
from trilogy.hooks.base_hook import BaseHook
|
|
31
35
|
from pathlib import Path
|
|
@@ -185,7 +189,6 @@ class Executor(object):
|
|
|
185
189
|
|
|
186
190
|
@execute_query.register
|
|
187
191
|
def _(self, query: ImportStatement) -> CursorResult:
|
|
188
|
-
self.environment.add_file_import(query.path, query.alias)
|
|
189
192
|
return MockResult(
|
|
190
193
|
[
|
|
191
194
|
{
|
|
@@ -219,8 +222,7 @@ class Executor(object):
|
|
|
219
222
|
@execute_query.register
|
|
220
223
|
def _(self, query: ProcessedQuery) -> CursorResult:
|
|
221
224
|
sql = self.generator.compile_statement(query)
|
|
222
|
-
|
|
223
|
-
output = self.connection.execute(text(sql))
|
|
225
|
+
output = self.execute_raw_sql(sql)
|
|
224
226
|
return output
|
|
225
227
|
|
|
226
228
|
@execute_query.register
|
|
@@ -228,14 +230,14 @@ class Executor(object):
|
|
|
228
230
|
|
|
229
231
|
sql = self.generator.compile_statement(query)
|
|
230
232
|
|
|
231
|
-
output = self.
|
|
233
|
+
output = self.execute_raw_sql(sql)
|
|
232
234
|
self.environment.add_datasource(query.datasource)
|
|
233
235
|
return output
|
|
234
236
|
|
|
235
237
|
@execute_query.register
|
|
236
238
|
def _(self, query: ProcessedCopyStatement) -> CursorResult:
|
|
237
239
|
sql = self.generator.compile_statement(query)
|
|
238
|
-
output: CursorResult = self.
|
|
240
|
+
output: CursorResult = self.execute_raw_sql(sql)
|
|
239
241
|
if query.target_type == IOType.CSV:
|
|
240
242
|
import csv
|
|
241
243
|
|
|
@@ -244,7 +246,7 @@ class Executor(object):
|
|
|
244
246
|
outcsv.writerow(output.keys())
|
|
245
247
|
outcsv.writerows(output)
|
|
246
248
|
else:
|
|
247
|
-
raise NotImplementedError(f"Unsupported
|
|
249
|
+
raise NotImplementedError(f"Unsupported IO Type {query.target_type}")
|
|
248
250
|
# now return the query we ran through IO
|
|
249
251
|
# TODO: instead return how many rows were written?
|
|
250
252
|
return generate_result_set(
|
|
@@ -370,13 +372,50 @@ class Executor(object):
|
|
|
370
372
|
if persist and isinstance(x, ProcessedQueryPersist):
|
|
371
373
|
self.environment.add_datasource(x.datasource)
|
|
372
374
|
|
|
375
|
+
def _hydrate_param(self, param: str) -> Any:
|
|
376
|
+
matched = [
|
|
377
|
+
v
|
|
378
|
+
for v in self.environment.concepts.values()
|
|
379
|
+
if v.safe_address == param or v.address == param
|
|
380
|
+
]
|
|
381
|
+
if not matched:
|
|
382
|
+
raise SyntaxError(f"No concept found for parameter {param}")
|
|
383
|
+
|
|
384
|
+
concept: Concept = matched.pop()
|
|
385
|
+
if not concept.granularity == Granularity.SINGLE_ROW:
|
|
386
|
+
raise SyntaxError(f"Cannot bind non-singleton concept {concept.address}")
|
|
387
|
+
if (
|
|
388
|
+
isinstance(concept.lineage, Function)
|
|
389
|
+
and concept.lineage.operator == FunctionType.CONSTANT
|
|
390
|
+
):
|
|
391
|
+
rval = concept.lineage.arguments[0]
|
|
392
|
+
if isinstance(rval, ListWrapper):
|
|
393
|
+
return [x for x in rval]
|
|
394
|
+
if isinstance(rval, MapWrapper):
|
|
395
|
+
return {k: v for k, v in rval.items()}
|
|
396
|
+
return rval
|
|
397
|
+
else:
|
|
398
|
+
results = self.execute_query(f"select {concept.name} limit 1;").fetchone()
|
|
399
|
+
if not results:
|
|
400
|
+
return None
|
|
401
|
+
return results[0]
|
|
402
|
+
|
|
373
403
|
def execute_raw_sql(
|
|
374
404
|
self, command: str, variables: dict | None = None
|
|
375
405
|
) -> CursorResult:
|
|
376
406
|
"""Run a command against the raw underlying
|
|
377
407
|
execution engine"""
|
|
408
|
+
final_params = None
|
|
409
|
+
q = text(command)
|
|
378
410
|
if variables:
|
|
379
|
-
|
|
411
|
+
final_params = variables
|
|
412
|
+
else:
|
|
413
|
+
params = q.compile().params
|
|
414
|
+
if params:
|
|
415
|
+
final_params = {x: self._hydrate_param(x) for x in params}
|
|
416
|
+
|
|
417
|
+
if final_params:
|
|
418
|
+
return self.connection.execute(text(command), final_params)
|
|
380
419
|
return self.connection.execute(
|
|
381
420
|
text(command),
|
|
382
421
|
)
|
|
@@ -804,7 +804,8 @@ class ParseToObjects(Transformer):
|
|
|
804
804
|
|
|
805
805
|
@v_args(meta=True)
|
|
806
806
|
def rawsql_statement(self, meta: Meta, args) -> RawSQLStatement:
|
|
807
|
-
|
|
807
|
+
statement = RawSQLStatement(meta=Metadata(line_number=meta.line), text=args[0])
|
|
808
|
+
return statement
|
|
808
809
|
|
|
809
810
|
def COPY_TYPE(self, args) -> IOType:
|
|
810
811
|
return IOType(args.value)
|
|
@@ -302,7 +302,7 @@
|
|
|
302
302
|
SINGLE_STRING_CHARS: /(?:(?!\${)([^'\\]|\\.))+/+ // any character except '
|
|
303
303
|
_single_quote: "'" ( SINGLE_STRING_CHARS )* "'"
|
|
304
304
|
_double_quote: "\"" ( DOUBLE_STRING_CHARS )* "\""
|
|
305
|
-
string_lit: _single_quote | _double_quote
|
|
305
|
+
string_lit: _single_quote | _double_quote | MULTILINE_STRING
|
|
306
306
|
|
|
307
307
|
MINUS: "-"
|
|
308
308
|
|
|
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.2.36 → pytrilogy-0.0.2.37}/trilogy/core/processing/node_generators/__init__.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/core/processing/node_generators/basic_node.py
RENAMED
|
File without changes
|
|
File without changes
|
{pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/core/processing/node_generators/filter_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/core/processing/node_generators/group_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/core/processing/node_generators/group_to_node.py
RENAMED
|
File without changes
|
|
File without changes
|
{pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/core/processing/node_generators/node_merge_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/core/processing/node_generators/rowset_node.py
RENAMED
|
File without changes
|
|
File without changes
|
{pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/core/processing/node_generators/select_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/trilogy/core/processing/node_generators/unnest_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.2.36 → pytrilogy-0.0.2.37}/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
|