pytrilogy 0.0.3.28__tar.gz → 0.0.3.30__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.
- {pytrilogy-0.0.3.28/pytrilogy.egg-info → pytrilogy-0.0.3.30}/PKG-INFO +1 -1
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30/pytrilogy.egg-info}/PKG-INFO +1 -1
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/tests/test_user_functions.py +25 -1
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/__init__.py +1 -1
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/enums.py +1 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/functions.py +9 -1
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/models/author.py +68 -2
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/models/build.py +7 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/statements/author.py +4 -1
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/dialect/base.py +1 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/parsing/common.py +8 -1
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/parsing/parse_engine.py +12 -4
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/parsing/render.py +31 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/parsing/trilogy.lark +4 -2
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/std/geography.preql +3 -3
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/LICENSE.md +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/README.md +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/pyproject.toml +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/pytrilogy.egg-info/SOURCES.txt +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/pytrilogy.egg-info/dependency_links.txt +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/pytrilogy.egg-info/entry_points.txt +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/pytrilogy.egg-info/requires.txt +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/pytrilogy.egg-info/top_level.txt +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/setup.cfg +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/setup.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/tests/test_datatypes.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/tests/test_declarations.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/tests/test_derived_concepts.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/tests/test_discovery_nodes.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/tests/test_enums.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/tests/test_environment.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/tests/test_executor.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/tests/test_functions.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/tests/test_imports.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/tests/test_metadata.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/tests/test_models.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/tests/test_multi_join_assignments.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/tests/test_parse_engine.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/tests/test_parsing.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/tests/test_partial_handling.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/tests/test_query_processing.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/tests/test_query_render.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/tests/test_select.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/tests/test_show.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/tests/test_statements.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/tests/test_typing.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/tests/test_undefined_concept.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/tests/test_where_clause.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/authoring/__init__.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/compiler.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/constants.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/__init__.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/constants.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/env_processor.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/environment_helpers.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/ergonomics.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/exceptions.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/graph_models.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/internal.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/models/__init__.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/models/build_environment.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/models/core.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/models/datasource.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/models/environment.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/models/execute.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/optimization.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/optimizations/__init__.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/optimizations/base_optimization.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/optimizations/inline_constant.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/optimizations/inline_datasource.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/optimizations/predicate_pushdown.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/processing/__init__.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/processing/concept_strategies_v3.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/processing/graph_utils.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/processing/node_generators/__init__.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/processing/node_generators/basic_node.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/processing/node_generators/common.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/processing/node_generators/filter_node.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/processing/node_generators/group_node.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/processing/node_generators/group_to_node.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/processing/node_generators/multiselect_node.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/processing/node_generators/node_merge_node.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/processing/node_generators/rowset_node.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/processing/node_generators/select_helpers/__init__.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/processing/node_generators/select_helpers/datasource_injection.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/processing/node_generators/select_merge_node.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/processing/node_generators/select_node.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/processing/node_generators/synonym_node.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/processing/node_generators/union_node.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/processing/node_generators/unnest_node.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/processing/node_generators/window_node.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/processing/nodes/__init__.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/processing/nodes/base_node.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/processing/nodes/filter_node.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/processing/nodes/group_node.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/processing/nodes/merge_node.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/processing/nodes/select_node_v2.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/processing/nodes/union_node.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/processing/nodes/unnest_node.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/processing/nodes/window_node.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/processing/utility.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/query_processor.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/statements/__init__.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/statements/build.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/statements/common.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/statements/execute.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/dialect/__init__.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/dialect/bigquery.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/dialect/common.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/dialect/config.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/dialect/dataframe.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/dialect/duckdb.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/dialect/enums.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/dialect/postgres.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/dialect/presto.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/dialect/snowflake.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/dialect/sql_server.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/engine.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/executor.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/hooks/__init__.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/hooks/base_hook.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/hooks/graph_hook.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/hooks/query_debugger.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/metadata/__init__.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/parser.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/parsing/__init__.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/parsing/config.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/parsing/exceptions.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/parsing/helpers.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/py.typed +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/render.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/scripts/__init__.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/scripts/trilogy.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/std/__init__.py +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/std/dashboard.preql +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/std/date.preql +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/std/money.preql +0 -0
- {pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/utility.py +0 -0
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
from
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
from trilogy import Dialects, Environment
|
|
2
4
|
from trilogy.core.enums import Derivation, Purpose
|
|
3
5
|
|
|
4
6
|
|
|
@@ -204,3 +206,25 @@ auto test <-SUM(CASE WHEN 10 = weekday THEN x ELSE 0 END) +
|
|
|
204
206
|
assert test.keys == set()
|
|
205
207
|
assert test.purpose == Purpose.METRIC
|
|
206
208
|
assert test.derivation == Derivation.BASIC
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def test_user_function_import():
|
|
212
|
+
env = Environment(working_path=Path(__file__).parent)
|
|
213
|
+
x = Dialects.DUCK_DB.default_executor(environment=env)
|
|
214
|
+
|
|
215
|
+
results = x.execute_query(
|
|
216
|
+
"""
|
|
217
|
+
import test_env_functions as test_env_functions;
|
|
218
|
+
|
|
219
|
+
key x int;
|
|
220
|
+
|
|
221
|
+
merge test_env_functions.quad_test into x;
|
|
222
|
+
|
|
223
|
+
select
|
|
224
|
+
x as quad_test,
|
|
225
|
+
@test_env_functions.quadratic(2, 3, 4) as quad_two;
|
|
226
|
+
|
|
227
|
+
"""
|
|
228
|
+
)
|
|
229
|
+
results = results.fetchall()
|
|
230
|
+
assert results[0].quad_test == 16.414213562373096
|
|
@@ -607,7 +607,15 @@ FUNCTION_REGISTRY: dict[FunctionType, FunctionConfig] = {
|
|
|
607
607
|
],
|
|
608
608
|
output_purpose=Purpose.PROPERTY,
|
|
609
609
|
output_type=DataType.INTEGER,
|
|
610
|
-
arg_count=
|
|
610
|
+
arg_count=2,
|
|
611
|
+
),
|
|
612
|
+
FunctionType.SQRT: FunctionConfig(
|
|
613
|
+
valid_inputs=[
|
|
614
|
+
{DataType.INTEGER, DataType.FLOAT, DataType.NUMBER, DataType.NUMERIC},
|
|
615
|
+
],
|
|
616
|
+
output_purpose=Purpose.PROPERTY,
|
|
617
|
+
output_type=DataType.INTEGER,
|
|
618
|
+
arg_count=1,
|
|
611
619
|
),
|
|
612
620
|
FunctionType.ROUND: FunctionConfig(
|
|
613
621
|
valid_inputs=[
|
|
@@ -376,7 +376,7 @@ class Conditional(Mergeable, ConceptArgs, Namespaced, DataTyped, BaseModel):
|
|
|
376
376
|
|
|
377
377
|
|
|
378
378
|
class WhereClause(Mergeable, ConceptArgs, Namespaced, BaseModel):
|
|
379
|
-
conditional: Union[SubselectComparison, Comparison, Conditional,
|
|
379
|
+
conditional: Union[SubselectComparison, Comparison, Conditional, Parenthetical]
|
|
380
380
|
|
|
381
381
|
def __repr__(self):
|
|
382
382
|
return str(self.conditional)
|
|
@@ -564,6 +564,7 @@ class Comparison(ConceptArgs, Mergeable, DataTyped, Namespaced, BaseModel):
|
|
|
564
564
|
"Conditional",
|
|
565
565
|
DataType,
|
|
566
566
|
"Comparison",
|
|
567
|
+
FunctionCallWrapper,
|
|
567
568
|
"Parenthetical",
|
|
568
569
|
MagicConstants,
|
|
569
570
|
WindowItem,
|
|
@@ -583,6 +584,7 @@ class Comparison(ConceptArgs, Mergeable, DataTyped, Namespaced, BaseModel):
|
|
|
583
584
|
Conditional,
|
|
584
585
|
DataType,
|
|
585
586
|
Comparison,
|
|
587
|
+
FunctionCallWrapper,
|
|
586
588
|
Parenthetical,
|
|
587
589
|
MagicConstants,
|
|
588
590
|
WindowItem,
|
|
@@ -1622,7 +1624,6 @@ class Function(DataTyped, ConceptArgs, Mergeable, Namespaced, BaseModel):
|
|
|
1622
1624
|
elif not valid_inputs:
|
|
1623
1625
|
return v
|
|
1624
1626
|
for idx, arg in enumerate(v):
|
|
1625
|
-
|
|
1626
1627
|
if (
|
|
1627
1628
|
isinstance(arg, ConceptRef)
|
|
1628
1629
|
and get_basic_type(arg.datatype.data_type) not in valid_inputs[idx]
|
|
@@ -1753,6 +1754,69 @@ class Function(DataTyped, ConceptArgs, Mergeable, Namespaced, BaseModel):
|
|
|
1753
1754
|
return base_grain
|
|
1754
1755
|
|
|
1755
1756
|
|
|
1757
|
+
class FunctionCallWrapper(
|
|
1758
|
+
DataTyped,
|
|
1759
|
+
ConceptArgs,
|
|
1760
|
+
Mergeable,
|
|
1761
|
+
Namespaced,
|
|
1762
|
+
BaseModel,
|
|
1763
|
+
):
|
|
1764
|
+
content: Expr
|
|
1765
|
+
name: str
|
|
1766
|
+
args: List[Expr]
|
|
1767
|
+
|
|
1768
|
+
def __str__(self):
|
|
1769
|
+
return f'@{self.name}({",".join([str(x) for x in self.args])})'
|
|
1770
|
+
|
|
1771
|
+
def with_namespace(self, namespace) -> "FunctionCallWrapper":
|
|
1772
|
+
return FunctionCallWrapper.model_construct(
|
|
1773
|
+
content=(
|
|
1774
|
+
self.content.with_namespace(namespace)
|
|
1775
|
+
if isinstance(self.content, Namespaced)
|
|
1776
|
+
else self.content
|
|
1777
|
+
),
|
|
1778
|
+
name=self.name,
|
|
1779
|
+
args=[
|
|
1780
|
+
x.with_namespace(namespace) if isinstance(x, Namespaced) else x
|
|
1781
|
+
for x in self.args
|
|
1782
|
+
],
|
|
1783
|
+
)
|
|
1784
|
+
|
|
1785
|
+
def with_merge(
|
|
1786
|
+
self, source: Concept, target: Concept, modifiers: List[Modifier]
|
|
1787
|
+
) -> "FunctionCallWrapper":
|
|
1788
|
+
return FunctionCallWrapper.model_construct(
|
|
1789
|
+
content=(
|
|
1790
|
+
self.content.with_merge(source, target, modifiers)
|
|
1791
|
+
if isinstance(self.content, Mergeable)
|
|
1792
|
+
else self.content
|
|
1793
|
+
),
|
|
1794
|
+
name=self.name,
|
|
1795
|
+
args=[
|
|
1796
|
+
(
|
|
1797
|
+
x.with_merge(source, target, modifiers)
|
|
1798
|
+
if isinstance(x, Mergeable)
|
|
1799
|
+
else x
|
|
1800
|
+
)
|
|
1801
|
+
for x in self.args
|
|
1802
|
+
],
|
|
1803
|
+
)
|
|
1804
|
+
|
|
1805
|
+
@property
|
|
1806
|
+
def concept_arguments(self) -> Sequence[ConceptRef]:
|
|
1807
|
+
base: List[ConceptRef] = []
|
|
1808
|
+
x = self.content
|
|
1809
|
+
if isinstance(x, ConceptRef):
|
|
1810
|
+
base += [x]
|
|
1811
|
+
elif isinstance(x, ConceptArgs):
|
|
1812
|
+
base += x.concept_arguments
|
|
1813
|
+
return base
|
|
1814
|
+
|
|
1815
|
+
@property
|
|
1816
|
+
def output_datatype(self):
|
|
1817
|
+
return arg_to_datatype(self.content)
|
|
1818
|
+
|
|
1819
|
+
|
|
1756
1820
|
class AggregateWrapper(Mergeable, DataTyped, ConceptArgs, Namespaced, BaseModel):
|
|
1757
1821
|
function: Function
|
|
1758
1822
|
by: List[ConceptRef] = Field(default_factory=list)
|
|
@@ -2278,6 +2342,7 @@ Expr = (
|
|
|
2278
2342
|
| ConceptRef
|
|
2279
2343
|
| Comparison
|
|
2280
2344
|
| Conditional
|
|
2345
|
+
| FunctionCallWrapper
|
|
2281
2346
|
| Parenthetical
|
|
2282
2347
|
| Function
|
|
2283
2348
|
| AggregateWrapper
|
|
@@ -2289,6 +2354,7 @@ FuncArgs = (
|
|
|
2289
2354
|
ConceptRef
|
|
2290
2355
|
| AggregateWrapper
|
|
2291
2356
|
| Function
|
|
2357
|
+
| FunctionCallWrapper
|
|
2292
2358
|
| Parenthetical
|
|
2293
2359
|
| CaseWhen
|
|
2294
2360
|
| CaseElse
|
|
@@ -53,6 +53,7 @@ from trilogy.core.models.author import (
|
|
|
53
53
|
FilterItem,
|
|
54
54
|
FuncArgs,
|
|
55
55
|
Function,
|
|
56
|
+
FunctionCallWrapper,
|
|
56
57
|
Grain,
|
|
57
58
|
HavingClause,
|
|
58
59
|
Metadata,
|
|
@@ -1608,6 +1609,12 @@ class Factory:
|
|
|
1608
1609
|
def _(self, base: OrderBy) -> BuildOrderBy:
|
|
1609
1610
|
return BuildOrderBy.model_construct(items=[self.build(x) for x in base.items])
|
|
1610
1611
|
|
|
1612
|
+
@build.register
|
|
1613
|
+
def _(self, base: FunctionCallWrapper) -> BuildExpr:
|
|
1614
|
+
# function calls are kept around purely for the parse tree
|
|
1615
|
+
# so discard at the build point
|
|
1616
|
+
return self.build(base.content)
|
|
1617
|
+
|
|
1611
1618
|
@build.register
|
|
1612
1619
|
def _(self, base: OrderItem) -> BuildOrderItem:
|
|
1613
1620
|
from trilogy.parsing.common import arbitrary_to_concept
|
|
@@ -22,6 +22,7 @@ from trilogy.core.models.author import (
|
|
|
22
22
|
Expr,
|
|
23
23
|
FilterItem,
|
|
24
24
|
Function,
|
|
25
|
+
FunctionCallWrapper,
|
|
25
26
|
Grain,
|
|
26
27
|
HasUUID,
|
|
27
28
|
HavingClause,
|
|
@@ -44,7 +45,9 @@ from trilogy.utility import unique
|
|
|
44
45
|
|
|
45
46
|
|
|
46
47
|
class ConceptTransform(BaseModel):
|
|
47
|
-
function:
|
|
48
|
+
function: (
|
|
49
|
+
Function | FilterItem | WindowItem | AggregateWrapper | FunctionCallWrapper
|
|
50
|
+
)
|
|
48
51
|
output: Concept # this has to be a full concept, as it may not exist in environment
|
|
49
52
|
modifiers: List[Modifier] = Field(default_factory=list)
|
|
50
53
|
|
|
@@ -171,6 +171,7 @@ FUNCTION_MAP = {
|
|
|
171
171
|
FunctionType.MULTIPLY: lambda x: " * ".join(x),
|
|
172
172
|
FunctionType.ROUND: lambda x: f"round({x[0]},{x[1]})",
|
|
173
173
|
FunctionType.MOD: lambda x: f"({x[0]} % {x[1]})",
|
|
174
|
+
FunctionType.SQRT: lambda x: f"sqrt({x[0]})",
|
|
174
175
|
# aggregate types
|
|
175
176
|
FunctionType.COUNT_DISTINCT: lambda x: f"count(distinct {x[0]})",
|
|
176
177
|
FunctionType.COUNT: lambda x: f"count({x[0]})",
|
|
@@ -27,6 +27,7 @@ from trilogy.core.models.author import (
|
|
|
27
27
|
ConceptRef,
|
|
28
28
|
FilterItem,
|
|
29
29
|
Function,
|
|
30
|
+
FunctionCallWrapper,
|
|
30
31
|
Grain,
|
|
31
32
|
HavingClause,
|
|
32
33
|
ListWrapper,
|
|
@@ -595,6 +596,7 @@ def rowset_to_concepts(rowset: RowsetDerivationStatement, environment: Environme
|
|
|
595
596
|
def arbitrary_to_concept(
|
|
596
597
|
parent: (
|
|
597
598
|
AggregateWrapper
|
|
599
|
+
| FunctionCallWrapper
|
|
598
600
|
| WindowItem
|
|
599
601
|
| FilterItem
|
|
600
602
|
| Function
|
|
@@ -610,7 +612,12 @@ def arbitrary_to_concept(
|
|
|
610
612
|
metadata: Metadata | None = None,
|
|
611
613
|
) -> Concept:
|
|
612
614
|
namespace = namespace or environment.namespace
|
|
613
|
-
|
|
615
|
+
# this is purely for the parse tree, discard from derivation
|
|
616
|
+
if isinstance(parent, FunctionCallWrapper):
|
|
617
|
+
return arbitrary_to_concept(
|
|
618
|
+
parent.content, environment, namespace, name, metadata # type: ignore
|
|
619
|
+
)
|
|
620
|
+
elif isinstance(parent, AggregateWrapper):
|
|
614
621
|
if not name:
|
|
615
622
|
name = f"{VIRTUAL_CONCEPT_PREFIX}_agg_{parent.function.operator.value}_{string_to_hash(str(parent))}"
|
|
616
623
|
return agg_wrapper_to_concept(
|
|
@@ -64,6 +64,7 @@ from trilogy.core.models.author import (
|
|
|
64
64
|
Expr,
|
|
65
65
|
FilterItem,
|
|
66
66
|
Function,
|
|
67
|
+
FunctionCallWrapper,
|
|
67
68
|
Grain,
|
|
68
69
|
HavingClause,
|
|
69
70
|
Metadata,
|
|
@@ -202,7 +203,7 @@ def expr_to_boolean(
|
|
|
202
203
|
def unwrap_transformation(
|
|
203
204
|
input: Expr,
|
|
204
205
|
environment: Environment,
|
|
205
|
-
) -> Function | FilterItem | WindowItem | AggregateWrapper:
|
|
206
|
+
) -> Function | FilterItem | WindowItem | AggregateWrapper | FunctionCallWrapper:
|
|
206
207
|
if isinstance(input, Function):
|
|
207
208
|
return input
|
|
208
209
|
elif isinstance(input, AggregateWrapper):
|
|
@@ -219,6 +220,8 @@ def unwrap_transformation(
|
|
|
219
220
|
return input
|
|
220
221
|
elif isinstance(input, WindowItem):
|
|
221
222
|
return input
|
|
223
|
+
elif isinstance(input, FunctionCallWrapper):
|
|
224
|
+
return input
|
|
222
225
|
elif isinstance(input, Parenthetical):
|
|
223
226
|
return unwrap_transformation(input.content, environment)
|
|
224
227
|
else:
|
|
@@ -810,7 +813,6 @@ class ParseToObjects(Transformer):
|
|
|
810
813
|
)
|
|
811
814
|
|
|
812
815
|
metadata = Metadata(line_number=meta.line, concept_source=ConceptSource.SELECT)
|
|
813
|
-
|
|
814
816
|
concept = arbitrary_to_concept(
|
|
815
817
|
transformation,
|
|
816
818
|
environment=self.environment,
|
|
@@ -1248,10 +1250,12 @@ class ParseToObjects(Transformer):
|
|
|
1248
1250
|
)
|
|
1249
1251
|
return FunctionDeclaration(name=identity, args=function_arguments, expr=output)
|
|
1250
1252
|
|
|
1251
|
-
def custom_function(self, args):
|
|
1253
|
+
def custom_function(self, args) -> FunctionCallWrapper:
|
|
1252
1254
|
name = args[0]
|
|
1253
1255
|
args = args[1:]
|
|
1254
|
-
remapped =
|
|
1256
|
+
remapped = FunctionCallWrapper(
|
|
1257
|
+
content=self.environment.functions[name](*args), name=name, args=args
|
|
1258
|
+
)
|
|
1255
1259
|
return remapped
|
|
1256
1260
|
|
|
1257
1261
|
@v_args(meta=True)
|
|
@@ -1723,6 +1727,10 @@ class ParseToObjects(Transformer):
|
|
|
1723
1727
|
def fmod(self, meta: Meta, args) -> Function:
|
|
1724
1728
|
return self.function_factory.create_function(args, FunctionType.MOD, meta)
|
|
1725
1729
|
|
|
1730
|
+
@v_args(meta=True)
|
|
1731
|
+
def fsqrt(self, meta: Meta, args) -> Function:
|
|
1732
|
+
return self.function_factory.create_function(args, FunctionType.SQRT, meta)
|
|
1733
|
+
|
|
1726
1734
|
@v_args(meta=True)
|
|
1727
1735
|
def fround(self, meta, args) -> Function:
|
|
1728
1736
|
return self.function_factory.create_function(args, FunctionType.ROUND, meta)
|
|
@@ -18,6 +18,7 @@ from trilogy.core.models.author import (
|
|
|
18
18
|
Conditional,
|
|
19
19
|
FilterItem,
|
|
20
20
|
Function,
|
|
21
|
+
FunctionCallWrapper,
|
|
21
22
|
Grain,
|
|
22
23
|
OrderBy,
|
|
23
24
|
OrderItem,
|
|
@@ -31,6 +32,7 @@ from trilogy.core.models.core import (
|
|
|
31
32
|
ListType,
|
|
32
33
|
ListWrapper,
|
|
33
34
|
NumericType,
|
|
35
|
+
TraitDataType,
|
|
34
36
|
TupleWrapper,
|
|
35
37
|
)
|
|
36
38
|
from trilogy.core.models.datasource import (
|
|
@@ -42,10 +44,12 @@ from trilogy.core.models.datasource import (
|
|
|
42
44
|
)
|
|
43
45
|
from trilogy.core.models.environment import Environment, Import
|
|
44
46
|
from trilogy.core.statements.author import (
|
|
47
|
+
ArgBinding,
|
|
45
48
|
ConceptDeclarationStatement,
|
|
46
49
|
ConceptDerivationStatement,
|
|
47
50
|
ConceptTransform,
|
|
48
51
|
CopyStatement,
|
|
52
|
+
FunctionDeclaration,
|
|
49
53
|
ImportStatement,
|
|
50
54
|
MergeStatementV2,
|
|
51
55
|
MultiSelectStatement,
|
|
@@ -54,6 +58,7 @@ from trilogy.core.statements.author import (
|
|
|
54
58
|
RowsetDerivationStatement,
|
|
55
59
|
SelectItem,
|
|
56
60
|
SelectStatement,
|
|
61
|
+
TypeDeclaration,
|
|
57
62
|
)
|
|
58
63
|
|
|
59
64
|
QUERY_TEMPLATE = Template(
|
|
@@ -149,6 +154,21 @@ class Renderer:
|
|
|
149
154
|
final = "\n\n".join("\n".join(x) for x in components)
|
|
150
155
|
return final
|
|
151
156
|
|
|
157
|
+
@to_string.register
|
|
158
|
+
def _(self, arg: TypeDeclaration):
|
|
159
|
+
return f"type {arg.type.name} {self.to_string(arg.type.type)};"
|
|
160
|
+
|
|
161
|
+
@to_string.register
|
|
162
|
+
def _(self, arg: ArgBinding):
|
|
163
|
+
if arg.default:
|
|
164
|
+
return f"{arg.name}={self.to_string(arg.default)}"
|
|
165
|
+
return f"{arg.name}"
|
|
166
|
+
|
|
167
|
+
@to_string.register
|
|
168
|
+
def _(self, arg: FunctionDeclaration):
|
|
169
|
+
args = ", ".join([self.to_string(x) for x in arg.args])
|
|
170
|
+
return f"def {arg.name}({args}) -> {self.to_string(arg.expr)};"
|
|
171
|
+
|
|
152
172
|
@to_string.register
|
|
153
173
|
def _(self, arg: Datasource):
|
|
154
174
|
assignments = ",\n ".join([self.to_string(x) for x in arg.columns])
|
|
@@ -198,6 +218,12 @@ class Renderer:
|
|
|
198
218
|
def _(self, arg: "CaseElse"):
|
|
199
219
|
return f"""ELSE {self.to_string(arg.expr)}"""
|
|
200
220
|
|
|
221
|
+
@to_string.register
|
|
222
|
+
def _(self, arg: "FunctionCallWrapper"):
|
|
223
|
+
args = [self.to_string(c) for c in arg.args]
|
|
224
|
+
arg_string = ", ".join(args)
|
|
225
|
+
return f"""@{arg.name}({arg_string})"""
|
|
226
|
+
|
|
201
227
|
@to_string.register
|
|
202
228
|
def _(self, arg: "Parenthetical"):
|
|
203
229
|
return f"""({self.to_string(arg.content)})"""
|
|
@@ -210,6 +236,11 @@ class Renderer:
|
|
|
210
236
|
def _(self, arg: "NumericType"):
|
|
211
237
|
return f"""Numeric({arg.precision},{arg.scale})"""
|
|
212
238
|
|
|
239
|
+
@to_string.register
|
|
240
|
+
def _(self, arg: TraitDataType):
|
|
241
|
+
traits = "::".join([x for x in arg.traits])
|
|
242
|
+
return f"{self.to_string(arg.data_type)}::{traits}"
|
|
243
|
+
|
|
213
244
|
@to_string.register
|
|
214
245
|
def _(self, arg: ListWrapper):
|
|
215
246
|
return "[" + ", ".join([self.to_string(x) for x in arg]) + "]"
|
|
@@ -180,6 +180,7 @@
|
|
|
180
180
|
map_key_access: expr "[" string_lit "]"
|
|
181
181
|
attr_access: expr "." string_lit
|
|
182
182
|
|
|
183
|
+
|
|
183
184
|
expr: _constant_functions | window_item | filter_item | subselect_comparison | between_comparison | fgroup | aggregate_functions | unnest | union | _static_functions | literal | concept_lit | index_access | map_key_access | attr_access | parenthetical | expr_tuple | comparison | alt_like | custom_function
|
|
184
185
|
|
|
185
186
|
// functions
|
|
@@ -191,8 +192,9 @@
|
|
|
191
192
|
fmod: ( "mod"i "(" expr "," (int_lit | concept_lit ) ")") | ( expr "%" (int_lit | concept_lit ) )
|
|
192
193
|
fround: "round"i "(" expr "," expr ")"
|
|
193
194
|
fabs: "abs"i "(" expr ")"
|
|
195
|
+
fsqrt: "sqrt"i "(" expr ")"
|
|
194
196
|
|
|
195
|
-
_math_functions: fmul | fdiv | fadd | fsub | fround | fmod | fabs
|
|
197
|
+
_math_functions: fmul | fdiv | fadd | fsub | fround | fmod | fabs | fsqrt
|
|
196
198
|
|
|
197
199
|
//generic
|
|
198
200
|
_fcast_primary: "cast"i "(" expr "as"i data_type ")"
|
|
@@ -306,7 +308,7 @@
|
|
|
306
308
|
custom_function: "@" IDENTIFIER "(" (expr ",")* expr ")"
|
|
307
309
|
|
|
308
310
|
// base language constructs
|
|
309
|
-
concept_lit: IDENTIFIER
|
|
311
|
+
concept_lit: MINUS? IDENTIFIER
|
|
310
312
|
IDENTIFIER: /[a-zA-Z\_][a-zA-Z0-9\_\.]*/
|
|
311
313
|
WILDCARD_IDENTIFIER: /[a-zA-Z\_][a-zA-Z0-9\_\-\.\*]*/
|
|
312
314
|
QUOTED_IDENTIFIER: /`[a-zA-Z\_][a-zA-Z0-9\_\.\-\*\:\s]*`/
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
|
|
2
2
|
|
|
3
3
|
## us types
|
|
4
|
-
type
|
|
5
|
-
type
|
|
6
|
-
type us_state string; # US state name
|
|
4
|
+
type us_state_short string; # US state abbreviation - ex MA, CA, NY
|
|
5
|
+
type us_state string; # US state name - ex Massachusetts, California, New York
|
|
7
6
|
|
|
7
|
+
type us_zip_code string; # US ZIP code
|
|
8
8
|
|
|
9
9
|
## generic types
|
|
10
10
|
type latitude float; # Latitude in degrees
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
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.28 → pytrilogy-0.0.3.30}/trilogy/core/processing/node_generators/__init__.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/processing/node_generators/basic_node.py
RENAMED
|
File without changes
|
|
File without changes
|
{pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/processing/node_generators/filter_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/processing/node_generators/group_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/processing/node_generators/group_to_node.py
RENAMED
|
File without changes
|
|
File without changes
|
{pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/processing/node_generators/node_merge_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/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.28 → pytrilogy-0.0.3.30}/trilogy/core/processing/node_generators/select_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/processing/node_generators/synonym_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/processing/node_generators/union_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/trilogy/core/processing/node_generators/unnest_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.28 → pytrilogy-0.0.3.30}/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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|