pytrilogy 0.0.2.37__tar.gz → 0.0.2.38__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.37/pytrilogy.egg-info → pytrilogy-0.0.2.38}/PKG-INFO +1 -1
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38/pytrilogy.egg-info}/PKG-INFO +1 -1
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/__init__.py +1 -1
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/core/models.py +6 -4
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/executor.py +30 -7
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/parsing/parse_engine.py +44 -12
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/parsing/render.py +3 -1
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/parsing/trilogy.lark +3 -3
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/LICENSE.md +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/README.md +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/pyproject.toml +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/pytrilogy.egg-info/SOURCES.txt +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/pytrilogy.egg-info/dependency_links.txt +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/pytrilogy.egg-info/entry_points.txt +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/pytrilogy.egg-info/requires.txt +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/pytrilogy.egg-info/top_level.txt +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/setup.cfg +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/setup.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/tests/test_datatypes.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/tests/test_declarations.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/tests/test_derived_concepts.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/tests/test_discovery_nodes.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/tests/test_enums.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/tests/test_environment.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/tests/test_executor.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/tests/test_functions.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/tests/test_imports.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/tests/test_metadata.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/tests/test_models.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/tests/test_multi_join_assignments.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/tests/test_parse_engine.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/tests/test_parsing.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/tests/test_partial_handling.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/tests/test_query_processing.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/tests/test_select.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/tests/test_show.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/tests/test_statements.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/tests/test_undefined_concept.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/tests/test_where_clause.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/compiler.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/constants.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/core/__init__.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/core/constants.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/core/enums.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/core/env_processor.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/core/environment_helpers.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/core/ergonomics.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/core/exceptions.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/core/functions.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/core/graph_models.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/core/internal.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/core/optimization.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/core/optimizations/__init__.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/core/optimizations/base_optimization.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/core/optimizations/inline_constant.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/core/optimizations/inline_datasource.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/core/optimizations/predicate_pushdown.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/core/processing/__init__.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/core/processing/concept_strategies_v3.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/core/processing/graph_utils.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/core/processing/node_generators/__init__.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/core/processing/node_generators/basic_node.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/core/processing/node_generators/common.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/core/processing/node_generators/filter_node.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/core/processing/node_generators/group_node.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/core/processing/node_generators/group_to_node.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/core/processing/node_generators/multiselect_node.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/core/processing/node_generators/node_merge_node.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/core/processing/node_generators/rowset_node.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/core/processing/node_generators/select_merge_node.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/core/processing/node_generators/select_node.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/core/processing/node_generators/unnest_node.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/core/processing/node_generators/window_node.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/core/processing/nodes/__init__.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/core/processing/nodes/base_node.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/core/processing/nodes/filter_node.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/core/processing/nodes/group_node.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/core/processing/nodes/merge_node.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/core/processing/nodes/select_node_v2.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/core/processing/nodes/unnest_node.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/core/processing/nodes/window_node.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/core/processing/utility.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/core/query_processor.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/dialect/__init__.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/dialect/base.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/dialect/bigquery.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/dialect/common.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/dialect/config.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/dialect/duckdb.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/dialect/enums.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/dialect/postgres.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/dialect/presto.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/dialect/snowflake.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/dialect/sql_server.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/engine.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/hooks/__init__.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/hooks/base_hook.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/hooks/graph_hook.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/hooks/query_debugger.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/metadata/__init__.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/parser.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/parsing/__init__.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/parsing/common.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/parsing/config.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/parsing/exceptions.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/parsing/helpers.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/py.typed +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/scripts/__init__.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/scripts/trilogy.py +0 -0
- {pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/utility.py +0 -0
|
@@ -2085,14 +2085,16 @@ class DatasourceMetadata(BaseModel):
|
|
|
2085
2085
|
|
|
2086
2086
|
|
|
2087
2087
|
class MergeStatementV2(HasUUID, Namespaced, BaseModel):
|
|
2088
|
-
|
|
2089
|
-
|
|
2088
|
+
sources: list[Concept]
|
|
2089
|
+
targets: dict[str, Concept]
|
|
2090
|
+
source_wildcard: str | None = None
|
|
2091
|
+
target_wildcard: str | None = None
|
|
2090
2092
|
modifiers: List[Modifier] = Field(default_factory=list)
|
|
2091
2093
|
|
|
2092
2094
|
def with_namespace(self, namespace: str) -> "MergeStatementV2":
|
|
2093
2095
|
new = MergeStatementV2(
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
+
sources=[x.with_namespace(namespace) for x in self.sources],
|
|
2097
|
+
targets={k: v.with_namespace(namespace) for k, v in self.targets.items()},
|
|
2096
2098
|
modifiers=self.modifiers,
|
|
2097
2099
|
)
|
|
2098
2100
|
return new
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import List, Optional, Any, Generator
|
|
1
|
+
from typing import List, Optional, Any, Generator, Protocol
|
|
2
2
|
from functools import singledispatchmethod
|
|
3
3
|
from sqlalchemy import text
|
|
4
4
|
from sqlalchemy.engine import Engine, CursorResult
|
|
@@ -36,6 +36,15 @@ from pathlib import Path
|
|
|
36
36
|
from dataclasses import dataclass
|
|
37
37
|
|
|
38
38
|
|
|
39
|
+
class ResultProtocol(Protocol):
|
|
40
|
+
values: List[Any]
|
|
41
|
+
columns: List[str]
|
|
42
|
+
|
|
43
|
+
def fetchall(self) -> List[Any]: ...
|
|
44
|
+
|
|
45
|
+
def keys(self) -> List[str]: ...
|
|
46
|
+
|
|
47
|
+
|
|
39
48
|
@dataclass
|
|
40
49
|
class MockResult:
|
|
41
50
|
values: list[Any]
|
|
@@ -201,15 +210,16 @@ class Executor(object):
|
|
|
201
210
|
|
|
202
211
|
@execute_query.register
|
|
203
212
|
def _(self, query: MergeStatementV2) -> CursorResult:
|
|
213
|
+
for concept in query.sources:
|
|
214
|
+
self.environment.merge_concept(
|
|
215
|
+
concept, query.targets[concept.address], modifiers=query.modifiers
|
|
216
|
+
)
|
|
204
217
|
|
|
205
|
-
self.environment.merge_concept(
|
|
206
|
-
query.source, query.target, modifiers=query.modifiers
|
|
207
|
-
)
|
|
208
218
|
return MockResult(
|
|
209
219
|
[
|
|
210
220
|
{
|
|
211
|
-
"
|
|
212
|
-
"
|
|
221
|
+
"sources": ",".join([x.address for x in query.sources]),
|
|
222
|
+
"targets": ",".join([x.address for _, x in query.targets.items()]),
|
|
213
223
|
}
|
|
214
224
|
],
|
|
215
225
|
["source", "target"],
|
|
@@ -309,7 +319,20 @@ class Executor(object):
|
|
|
309
319
|
output.append(compiled_sql)
|
|
310
320
|
return output
|
|
311
321
|
|
|
312
|
-
def parse_file(
|
|
322
|
+
def parse_file(
|
|
323
|
+
self, file: str | Path, persist: bool = False
|
|
324
|
+
) -> list[
|
|
325
|
+
ProcessedQuery
|
|
326
|
+
| ProcessedQueryPersist
|
|
327
|
+
| ProcessedShowStatement
|
|
328
|
+
| ProcessedRawSQLStatement
|
|
329
|
+
| ProcessedCopyStatement,
|
|
330
|
+
]:
|
|
331
|
+
return list(self.parse_file_generator(file, persist=persist))
|
|
332
|
+
|
|
333
|
+
def parse_file_generator(
|
|
334
|
+
self, file: str | Path, persist: bool = False
|
|
335
|
+
) -> Generator[
|
|
313
336
|
ProcessedQuery
|
|
314
337
|
| ProcessedQueryPersist
|
|
315
338
|
| ProcessedShowStatement
|
|
@@ -302,6 +302,9 @@ class ParseToObjects(Transformer):
|
|
|
302
302
|
def IDENTIFIER(self, args) -> str:
|
|
303
303
|
return args.value
|
|
304
304
|
|
|
305
|
+
def WILDCARD_IDENTIFIER(self, args) -> str:
|
|
306
|
+
return args.value
|
|
307
|
+
|
|
305
308
|
def QUOTED_IDENTIFIER(self, args) -> str:
|
|
306
309
|
return args.value[1:-1]
|
|
307
310
|
|
|
@@ -786,19 +789,47 @@ class ParseToObjects(Transformer):
|
|
|
786
789
|
return [x for x in args]
|
|
787
790
|
|
|
788
791
|
@v_args(meta=True)
|
|
789
|
-
def
|
|
792
|
+
def merge_statement(self, meta: Meta, args) -> MergeStatementV2:
|
|
790
793
|
modifiers = []
|
|
791
|
-
|
|
794
|
+
cargs: list[str] = []
|
|
795
|
+
source_wildcard = None
|
|
796
|
+
target_wildcard = None
|
|
792
797
|
for arg in args:
|
|
793
798
|
if isinstance(arg, Modifier):
|
|
794
799
|
modifiers.append(arg)
|
|
795
800
|
else:
|
|
796
|
-
|
|
801
|
+
cargs.append(arg)
|
|
802
|
+
source, target = cargs
|
|
803
|
+
if source.endswith(".*"):
|
|
804
|
+
if not target.endswith(".*"):
|
|
805
|
+
raise ValueError("Invalid merge, source is wildcard, target is not")
|
|
806
|
+
source_wildcard = source[:-2]
|
|
807
|
+
target_wildcard = target[:-2]
|
|
808
|
+
sources = [
|
|
809
|
+
v
|
|
810
|
+
for k, v in self.environment.concepts.items()
|
|
811
|
+
if v.namespace == source_wildcard
|
|
812
|
+
]
|
|
813
|
+
targets = {}
|
|
814
|
+
for x in sources:
|
|
815
|
+
target = target_wildcard + "." + x.name
|
|
816
|
+
if target in self.environment.concepts:
|
|
817
|
+
targets[x.address] = self.environment.concepts[target]
|
|
818
|
+
sources = [x for x in sources if x.address in targets]
|
|
819
|
+
else:
|
|
820
|
+
sources = [self.environment.concepts[source]]
|
|
821
|
+
targets = {sources[0].address: self.environment.concepts[target]}
|
|
797
822
|
new = MergeStatementV2(
|
|
798
|
-
|
|
823
|
+
sources=sources,
|
|
824
|
+
targets=targets,
|
|
825
|
+
modifiers=modifiers,
|
|
826
|
+
source_wildcard=source_wildcard,
|
|
827
|
+
target_wildcard=target_wildcard,
|
|
799
828
|
)
|
|
800
|
-
|
|
801
|
-
|
|
829
|
+
for source_c in new.sources:
|
|
830
|
+
self.environment.merge_concept(
|
|
831
|
+
source_c, targets[source_c.address], modifiers
|
|
832
|
+
)
|
|
802
833
|
|
|
803
834
|
return new
|
|
804
835
|
|
|
@@ -1745,7 +1776,7 @@ class ParseToObjects(Transformer):
|
|
|
1745
1776
|
arguments=args,
|
|
1746
1777
|
output_datatype=output_datatype,
|
|
1747
1778
|
output_purpose=function_args_to_output_purpose(args),
|
|
1748
|
-
|
|
1779
|
+
valid_inputs={DataType.INTEGER, DataType.FLOAT, DataType.NUMBER},
|
|
1749
1780
|
arg_count=2,
|
|
1750
1781
|
)
|
|
1751
1782
|
|
|
@@ -1758,7 +1789,7 @@ class ParseToObjects(Transformer):
|
|
|
1758
1789
|
arguments=args,
|
|
1759
1790
|
output_datatype=output_datatype,
|
|
1760
1791
|
output_purpose=function_args_to_output_purpose(args),
|
|
1761
|
-
|
|
1792
|
+
valid_inputs={DataType.INTEGER, DataType.FLOAT, DataType.NUMBER},
|
|
1762
1793
|
arg_count=2,
|
|
1763
1794
|
)
|
|
1764
1795
|
|
|
@@ -1771,20 +1802,21 @@ class ParseToObjects(Transformer):
|
|
|
1771
1802
|
arguments=args,
|
|
1772
1803
|
output_datatype=output_datatype,
|
|
1773
1804
|
output_purpose=function_args_to_output_purpose(args),
|
|
1774
|
-
|
|
1805
|
+
valid_inputs={DataType.INTEGER, DataType.FLOAT, DataType.NUMBER},
|
|
1775
1806
|
arg_count=2,
|
|
1776
1807
|
)
|
|
1777
1808
|
|
|
1778
1809
|
@v_args(meta=True)
|
|
1779
1810
|
def fdiv(self, meta: Meta, args):
|
|
1780
1811
|
args = process_function_args(args, meta=meta, environment=self.environment)
|
|
1781
|
-
|
|
1812
|
+
# 2024-11-18 - this is a bit of a hack, but division always returns a float
|
|
1813
|
+
# output_datatype = merge_datatypes([arg_to_datatype(x) for x in args])
|
|
1782
1814
|
return Function(
|
|
1783
1815
|
operator=FunctionType.DIVIDE,
|
|
1784
1816
|
arguments=args,
|
|
1785
|
-
output_datatype=
|
|
1817
|
+
output_datatype=DataType.FLOAT, # division always returns a float
|
|
1786
1818
|
output_purpose=function_args_to_output_purpose(args),
|
|
1787
|
-
|
|
1819
|
+
valid_inputs={DataType.INTEGER, DataType.FLOAT, DataType.NUMBER},
|
|
1788
1820
|
arg_count=2,
|
|
1789
1821
|
)
|
|
1790
1822
|
|
|
@@ -432,7 +432,9 @@ class Renderer:
|
|
|
432
432
|
|
|
433
433
|
@to_string.register
|
|
434
434
|
def _(self, arg: MergeStatementV2):
|
|
435
|
-
|
|
435
|
+
if len(arg.sources) == 1:
|
|
436
|
+
return f"MERGE {self.to_string(arg.sources[0])} into {''.join([self.to_string(modifier) for modifier in arg.modifiers])}{self.to_string(arg.targets[arg.sources[0].address])};"
|
|
437
|
+
return f"MERGE {arg.source_wildcard}.* into {''.join([self.to_string(modifier) for modifier in arg.modifiers])}{arg.target_wildcard}.*;"
|
|
436
438
|
|
|
437
439
|
@to_string.register
|
|
438
440
|
def _(self, arg: Modifier):
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
| rowset_derivation_statement
|
|
10
10
|
| import_statement
|
|
11
11
|
| copy_statement
|
|
12
|
-
|
|
|
12
|
+
| merge_statement
|
|
13
13
|
| rawsql_statement
|
|
14
14
|
|
|
15
15
|
_TERMINATOR: ";"i /\s*/
|
|
@@ -74,8 +74,7 @@
|
|
|
74
74
|
|
|
75
75
|
align_clause: align_item ("AND"i align_item)* "AND"i?
|
|
76
76
|
|
|
77
|
-
|
|
78
|
-
merge_statement_v2: "merge"i IDENTIFIER "into"i SHORTHAND_MODIFIER? IDENTIFIER
|
|
77
|
+
merge_statement: "merge"i WILDCARD_IDENTIFIER "into"i SHORTHAND_MODIFIER? WILDCARD_IDENTIFIER
|
|
79
78
|
|
|
80
79
|
// raw sql statement
|
|
81
80
|
rawsql_statement: "raw_sql"i "(" MULTILINE_STRING ")"
|
|
@@ -292,6 +291,7 @@
|
|
|
292
291
|
// base language constructs
|
|
293
292
|
concept_lit: IDENTIFIER
|
|
294
293
|
IDENTIFIER: /[a-zA-Z\_][a-zA-Z0-9\_\-\.]*/
|
|
294
|
+
WILDCARD_IDENTIFIER: /[a-zA-Z\_][a-zA-Z0-9\_\-\.\*]*/
|
|
295
295
|
QUOTED_IDENTIFIER: /`[a-zA-Z\_][a-zA-Z0-9\_\.\-\*\:\s]*`/
|
|
296
296
|
QUOTED_ADDRESS: /`[a-zA-Z\_][a-zA-Z0-9\_\.\-\*\:]*`/
|
|
297
297
|
ADDRESS: IDENTIFIER
|
|
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.2.37 → pytrilogy-0.0.2.38}/trilogy/core/processing/node_generators/__init__.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/core/processing/node_generators/basic_node.py
RENAMED
|
File without changes
|
|
File without changes
|
{pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/core/processing/node_generators/filter_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/core/processing/node_generators/group_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/core/processing/node_generators/group_to_node.py
RENAMED
|
File without changes
|
|
File without changes
|
{pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/core/processing/node_generators/node_merge_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/core/processing/node_generators/rowset_node.py
RENAMED
|
File without changes
|
|
File without changes
|
{pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/core/processing/node_generators/select_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/trilogy/core/processing/node_generators/unnest_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.2.37 → pytrilogy-0.0.2.38}/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
|