pytrilogy 0.0.3.35__tar.gz → 0.0.3.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.3.35/pytrilogy.egg-info → pytrilogy-0.0.3.37}/PKG-INFO +1 -1
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37/pytrilogy.egg-info}/PKG-INFO +1 -1
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/tests/test_derived_concepts.py +8 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/tests/test_functions.py +19 -1
- pytrilogy-0.0.3.37/tests/test_metadata.py +26 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/tests/test_typing.py +21 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/__init__.py +1 -1
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/enums.py +1 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/environment_helpers.py +2 -2
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/functions.py +6 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/models/build.py +12 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/dialect/base.py +9 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/dialect/bigquery.py +17 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/parsing/parse_engine.py +19 -12
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/parsing/trilogy.lark +6 -3
- pytrilogy-0.0.3.35/tests/test_metadata.py +0 -29
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/LICENSE.md +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/README.md +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/pyproject.toml +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/pytrilogy.egg-info/SOURCES.txt +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/pytrilogy.egg-info/dependency_links.txt +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/pytrilogy.egg-info/entry_points.txt +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/pytrilogy.egg-info/requires.txt +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/pytrilogy.egg-info/top_level.txt +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/setup.cfg +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/setup.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/tests/test_datatypes.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/tests/test_declarations.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/tests/test_discovery_nodes.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/tests/test_enums.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/tests/test_environment.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/tests/test_executor.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/tests/test_imports.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/tests/test_models.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/tests/test_multi_join_assignments.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/tests/test_parse_engine.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/tests/test_parsing.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/tests/test_partial_handling.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/tests/test_query_processing.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/tests/test_query_render.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/tests/test_select.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/tests/test_show.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/tests/test_statements.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/tests/test_undefined_concept.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/tests/test_user_functions.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/tests/test_where_clause.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/authoring/__init__.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/compiler.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/constants.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/__init__.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/constants.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/env_processor.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/ergonomics.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/exceptions.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/graph_models.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/internal.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/models/__init__.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/models/author.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/models/build_environment.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/models/core.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/models/datasource.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/models/environment.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/models/execute.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/optimization.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/optimizations/__init__.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/optimizations/base_optimization.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/optimizations/inline_constant.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/optimizations/inline_datasource.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/optimizations/predicate_pushdown.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/__init__.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/concept_strategies_v3.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/graph_utils.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/node_generators/__init__.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/node_generators/basic_node.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/node_generators/common.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/node_generators/filter_node.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/node_generators/group_node.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/node_generators/group_to_node.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/node_generators/multiselect_node.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/node_generators/node_merge_node.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/node_generators/rowset_node.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/node_generators/select_helpers/__init__.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/node_generators/select_helpers/datasource_injection.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/node_generators/select_merge_node.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/node_generators/select_node.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/node_generators/synonym_node.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/node_generators/union_node.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/node_generators/unnest_node.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/node_generators/window_node.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/nodes/__init__.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/nodes/base_node.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/nodes/filter_node.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/nodes/group_node.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/nodes/merge_node.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/nodes/select_node_v2.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/nodes/union_node.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/nodes/unnest_node.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/nodes/window_node.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/utility.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/query_processor.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/statements/__init__.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/statements/author.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/statements/build.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/statements/common.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/statements/execute.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/dialect/__init__.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/dialect/common.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/dialect/config.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/dialect/dataframe.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/dialect/duckdb.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/dialect/enums.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/dialect/postgres.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/dialect/presto.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/dialect/snowflake.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/dialect/sql_server.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/engine.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/executor.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/hooks/__init__.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/hooks/base_hook.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/hooks/graph_hook.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/hooks/query_debugger.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/metadata/__init__.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/parser.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/parsing/__init__.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/parsing/common.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/parsing/config.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/parsing/exceptions.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/parsing/helpers.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/parsing/render.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/py.typed +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/render.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/scripts/__init__.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/scripts/trilogy.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/std/__init__.py +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/std/date.preql +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/std/display.preql +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/std/geography.preql +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/std/money.preql +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/std/report.preql +0 -0
- {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/utility.py +0 -0
|
@@ -11,6 +11,14 @@ def test_derivations(test_environment):
|
|
|
11
11
|
)
|
|
12
12
|
|
|
13
13
|
|
|
14
|
+
def test_hour_derivation(test_environment):
|
|
15
|
+
hour_derived = test_environment.concepts["order_timestamp.hour"]
|
|
16
|
+
assert "hour" in hour_derived.datatype.traits, hour_derived
|
|
17
|
+
|
|
18
|
+
year_derived = test_environment.concepts["order_timestamp.year"]
|
|
19
|
+
assert "year" in year_derived.datatype.traits, year_derived
|
|
20
|
+
|
|
21
|
+
|
|
14
22
|
def test_filtering_where_on_derived_aggregate(test_environment):
|
|
15
23
|
exception = False
|
|
16
24
|
try:
|
|
@@ -212,6 +212,7 @@ def test_math_functions(test_environment):
|
|
|
212
212
|
property order_add <- revenue + 2;
|
|
213
213
|
property order_id.order_nested <- revenue * 2/2;
|
|
214
214
|
property order_id.rounded <- round(revenue + 2.01,2);
|
|
215
|
+
constant random <- random(1);
|
|
215
216
|
select
|
|
216
217
|
order_id,
|
|
217
218
|
inflated_order_value,
|
|
@@ -219,7 +220,8 @@ def test_math_functions(test_environment):
|
|
|
219
220
|
fixed_order_value,
|
|
220
221
|
order_sub,
|
|
221
222
|
order_add,
|
|
222
|
-
rounded
|
|
223
|
+
rounded,
|
|
224
|
+
random,
|
|
223
225
|
;"""
|
|
224
226
|
env, parsed = parse(declarations, environment=test_environment)
|
|
225
227
|
select: SelectStatement = parsed[-1]
|
|
@@ -227,6 +229,22 @@ def test_math_functions(test_environment):
|
|
|
227
229
|
dialect.compile_statement(process_query(test_environment, select))
|
|
228
230
|
|
|
229
231
|
|
|
232
|
+
def test_random_randomness(test_environment):
|
|
233
|
+
declarations = """
|
|
234
|
+
auto x <- unnest([1,2,3,4]);
|
|
235
|
+
select
|
|
236
|
+
x,
|
|
237
|
+
random(x) -> random_1,
|
|
238
|
+
;"""
|
|
239
|
+
env, parsed = parse(declarations, environment=test_environment)
|
|
240
|
+
z = (
|
|
241
|
+
Dialects.DUCK_DB.default_executor(environment=test_environment)
|
|
242
|
+
.execute_query(parsed[-1])
|
|
243
|
+
.fetchall()
|
|
244
|
+
)
|
|
245
|
+
assert z[0].random_1 != z[1].random_1, f"{z[0].random_1} == {z[1].random_1}"
|
|
246
|
+
|
|
247
|
+
|
|
230
248
|
def test_string_functions(test_environment):
|
|
231
249
|
declarations = """
|
|
232
250
|
property test_name <- concat(category_name, '_test');
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from trilogy import parse
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def test_metadata():
|
|
5
|
+
env, _ = parse(
|
|
6
|
+
"""key user_id int metadata(description="the description");
|
|
7
|
+
property user_id.display_name string metadata(description="The display name");"""
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
assert env.concepts["user_id"].metadata.description == "the description"
|
|
11
|
+
assert env.concepts["display_name"].metadata.description == "The display name"
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# def test_import_metadata():
|
|
15
|
+
# env = Environment(working_path=Path(__file__).parent)
|
|
16
|
+
# env, _ = parse(
|
|
17
|
+
# """import test_env as env; # Dragon metrics
|
|
18
|
+
# import test_env as env2;""",
|
|
19
|
+
# environment=env,
|
|
20
|
+
# )
|
|
21
|
+
|
|
22
|
+
# assert "Dragon metrics" in env.concepts["env.id"].metadata.description
|
|
23
|
+
|
|
24
|
+
# env2 = env.concepts["env2.id"]
|
|
25
|
+
# assert env2.namespace == "env2"
|
|
26
|
+
# assert env.concepts["env2.id"].metadata.description is None
|
|
@@ -214,3 +214,24 @@ sum(
|
|
|
214
214
|
)
|
|
215
215
|
|
|
216
216
|
assert env.environment.concepts["total"].datatype.traits == ["money"]
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def test_custom_trait_unnest_typing():
|
|
220
|
+
env = Dialects.DUCK_DB.default_executor()
|
|
221
|
+
env.environment.parse(
|
|
222
|
+
"""
|
|
223
|
+
import std.geography;
|
|
224
|
+
|
|
225
|
+
const array <- ['VT', 'MA', 'NY', 'CA']::array<string::us_state_short>;
|
|
226
|
+
|
|
227
|
+
"""
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
_ = env.execute_query(
|
|
231
|
+
"""
|
|
232
|
+
SELECT
|
|
233
|
+
unnest(array)->state;
|
|
234
|
+
"""
|
|
235
|
+
)
|
|
236
|
+
|
|
237
|
+
assert env.environment.concepts["state"].datatype.traits == ["us_state_short"]
|
|
@@ -47,7 +47,7 @@ def generate_date_concepts(concept: Concept, environment: Environment):
|
|
|
47
47
|
)
|
|
48
48
|
new_concept = Concept(
|
|
49
49
|
name=f"{concept.name}.{fname}",
|
|
50
|
-
datatype=
|
|
50
|
+
datatype=function.output_datatype,
|
|
51
51
|
purpose=default_type,
|
|
52
52
|
lineage=function,
|
|
53
53
|
grain=concept.grain,
|
|
@@ -119,7 +119,7 @@ def generate_datetime_concepts(concept: Concept, environment: Environment):
|
|
|
119
119
|
)
|
|
120
120
|
new_concept = Concept(
|
|
121
121
|
name=f"{concept.name}.{fname}",
|
|
122
|
-
datatype=
|
|
122
|
+
datatype=const_function.output_datatype,
|
|
123
123
|
purpose=default_type,
|
|
124
124
|
lineage=const_function,
|
|
125
125
|
grain=concept.grain,
|
|
@@ -620,6 +620,12 @@ FUNCTION_REGISTRY: dict[FunctionType, FunctionConfig] = {
|
|
|
620
620
|
output_type=DataType.INTEGER,
|
|
621
621
|
arg_count=1,
|
|
622
622
|
),
|
|
623
|
+
FunctionType.RANDOM: FunctionConfig(
|
|
624
|
+
valid_inputs=[],
|
|
625
|
+
output_purpose=Purpose.PROPERTY,
|
|
626
|
+
output_type=DataType.FLOAT,
|
|
627
|
+
arg_count=1,
|
|
628
|
+
),
|
|
623
629
|
FunctionType.ROUND: FunctionConfig(
|
|
624
630
|
valid_inputs=[
|
|
625
631
|
{DataType.INTEGER, DataType.FLOAT, DataType.NUMBER, DataType.NUMERIC},
|
|
@@ -1929,6 +1929,18 @@ class Factory:
|
|
|
1929
1929
|
def _(self, base: TraitDataType):
|
|
1930
1930
|
return base
|
|
1931
1931
|
|
|
1932
|
+
@build.register
|
|
1933
|
+
def _(self, base: ListType):
|
|
1934
|
+
return base
|
|
1935
|
+
|
|
1936
|
+
@build.register
|
|
1937
|
+
def _(self, base: StructType):
|
|
1938
|
+
return base
|
|
1939
|
+
|
|
1940
|
+
@build.register
|
|
1941
|
+
def _(self, base: MapType):
|
|
1942
|
+
return base
|
|
1943
|
+
|
|
1932
1944
|
@build.register
|
|
1933
1945
|
def _(self, base: Datasource):
|
|
1934
1946
|
local_cache: dict[str, BuildConcept] = {}
|
|
@@ -132,6 +132,11 @@ DATATYPE_MAP: dict[DataType, str] = {
|
|
|
132
132
|
DataType.MAP: "map",
|
|
133
133
|
DataType.DATE: "date",
|
|
134
134
|
DataType.DATETIME: "datetime",
|
|
135
|
+
DataType.LIST: "list",
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
COMPLEX_DATATYPE_MAP = {
|
|
139
|
+
DataType.LIST: lambda x: f"{x}[]",
|
|
135
140
|
}
|
|
136
141
|
|
|
137
142
|
|
|
@@ -172,6 +177,7 @@ FUNCTION_MAP = {
|
|
|
172
177
|
FunctionType.ROUND: lambda x: f"round({x[0]},{x[1]})",
|
|
173
178
|
FunctionType.MOD: lambda x: f"({x[0]} % {x[1]})",
|
|
174
179
|
FunctionType.SQRT: lambda x: f"sqrt({x[0]})",
|
|
180
|
+
FunctionType.RANDOM: lambda x: "random()",
|
|
175
181
|
# aggregate types
|
|
176
182
|
FunctionType.COUNT_DISTINCT: lambda x: f"count(distinct {x[0]})",
|
|
177
183
|
FunctionType.COUNT: lambda x: f"count({x[0]})",
|
|
@@ -283,6 +289,7 @@ class BaseDialect:
|
|
|
283
289
|
QUOTE_CHARACTER = "`"
|
|
284
290
|
SQL_TEMPLATE = GENERIC_SQL_TEMPLATE
|
|
285
291
|
DATATYPE_MAP = DATATYPE_MAP
|
|
292
|
+
COMPLEX_DATATYPE_MAP = COMPLEX_DATATYPE_MAP
|
|
286
293
|
UNNEST_MODE = UnnestMode.CROSS_APPLY
|
|
287
294
|
|
|
288
295
|
def __init__(self, rendering: Rendering | None = None):
|
|
@@ -682,6 +689,8 @@ class BaseDialect:
|
|
|
682
689
|
return self.FUNCTION_MAP[FunctionType.DATETIME_LITERAL](e)
|
|
683
690
|
elif isinstance(e, TraitDataType):
|
|
684
691
|
return self.render_expr(e.type, cte=cte, cte_map=cte_map)
|
|
692
|
+
elif isinstance(e, ListType):
|
|
693
|
+
return f"{self.COMPLEX_DATATYPE_MAP[DataType.LIST](self.render_expr(e.value_data_type, cte=cte, cte_map=cte_map))}"
|
|
685
694
|
else:
|
|
686
695
|
raise ValueError(f"Unable to render type {type(e)} {e}")
|
|
687
696
|
|
|
@@ -3,6 +3,9 @@ from typing import Any, Callable, Mapping
|
|
|
3
3
|
from jinja2 import Template
|
|
4
4
|
|
|
5
5
|
from trilogy.core.enums import FunctionType, UnnestMode, WindowType
|
|
6
|
+
from trilogy.core.models.core import (
|
|
7
|
+
DataType,
|
|
8
|
+
)
|
|
6
9
|
from trilogy.dialect.base import BaseDialect
|
|
7
10
|
|
|
8
11
|
WINDOW_FUNCTION_MAP: Mapping[WindowType, Callable[[Any, Any, Any], str]] = {}
|
|
@@ -36,6 +39,19 @@ FUNCTION_GRAIN_MATCH_MAP = {
|
|
|
36
39
|
FunctionType.AVG: lambda args: f"{args[0]}",
|
|
37
40
|
}
|
|
38
41
|
|
|
42
|
+
DATATYPE_MAP: dict[DataType, str] = {
|
|
43
|
+
DataType.STRING: "STRING",
|
|
44
|
+
DataType.INTEGER: "INT64",
|
|
45
|
+
DataType.FLOAT: "FLOAT64",
|
|
46
|
+
DataType.BOOL: "BOOL",
|
|
47
|
+
DataType.NUMERIC: "NUMERIC",
|
|
48
|
+
DataType.MAP: "MAP",
|
|
49
|
+
DataType.DATE: "DATE",
|
|
50
|
+
DataType.DATETIME: "DATETIME",
|
|
51
|
+
DataType.TIMESTAMP: "TIMESTAMP",
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
|
|
39
55
|
BQ_SQL_TEMPLATE = Template(
|
|
40
56
|
"""{%- if output %}
|
|
41
57
|
CREATE OR REPLACE TABLE {{ output.address.location }} AS
|
|
@@ -80,3 +96,4 @@ class BigqueryDialect(BaseDialect):
|
|
|
80
96
|
QUOTE_CHARACTER = "`"
|
|
81
97
|
SQL_TEMPLATE = BQ_SQL_TEMPLATE
|
|
82
98
|
UNNEST_MODE = UnnestMode.CROSS_JOIN
|
|
99
|
+
DATATYPE_MAP = DATATYPE_MAP
|
|
@@ -368,18 +368,21 @@ class ParseToObjects(Transformer):
|
|
|
368
368
|
output.concept.metadata.description
|
|
369
369
|
or args[1].text.split("#")[1].strip()
|
|
370
370
|
)
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
371
|
+
# this is a bad plan for now;
|
|
372
|
+
# because a comment after an import statement is very common
|
|
373
|
+
# and it's not intuitive that it modifies the import description
|
|
374
|
+
# if isinstance(output, ImportStatement):
|
|
375
|
+
# if len(args) > 1 and isinstance(args[1], Comment):
|
|
376
|
+
# comment = args[1].text.split("#")[1].strip()
|
|
377
|
+
# namespace = output.alias
|
|
378
|
+
# for _, v in self.environment.concepts.items():
|
|
379
|
+
# if v.namespace == namespace:
|
|
380
|
+
# if v.metadata.description:
|
|
381
|
+
# v.metadata.description = (
|
|
382
|
+
# f"{comment}: {v.metadata.description}"
|
|
383
|
+
# )
|
|
384
|
+
# else:
|
|
385
|
+
# v.metadata.description = comment
|
|
383
386
|
|
|
384
387
|
return args[0]
|
|
385
388
|
|
|
@@ -1762,6 +1765,10 @@ class ParseToObjects(Transformer):
|
|
|
1762
1765
|
def fsqrt(self, meta: Meta, args) -> Function:
|
|
1763
1766
|
return self.function_factory.create_function(args, FunctionType.SQRT, meta)
|
|
1764
1767
|
|
|
1768
|
+
@v_args(meta=True)
|
|
1769
|
+
def frandom(self, meta: Meta, args) -> Function:
|
|
1770
|
+
return self.function_factory.create_function(args, FunctionType.RANDOM, meta)
|
|
1771
|
+
|
|
1765
1772
|
@v_args(meta=True)
|
|
1766
1773
|
def fround(self, meta, args) -> Function:
|
|
1767
1774
|
return self.function_factory.create_function(args, FunctionType.ROUND, meta)
|
|
@@ -196,9 +196,12 @@
|
|
|
196
196
|
fmod: ( "mod"i "(" expr "," (int_lit | concept_lit ) ")") | ( expr "%" (int_lit | concept_lit ) )
|
|
197
197
|
fround: "round"i "(" expr "," expr ")"
|
|
198
198
|
fabs: "abs"i "(" expr ")"
|
|
199
|
-
|
|
199
|
+
_SQRT.1: "sqrt("
|
|
200
|
+
fsqrt: _SQRT expr ")"
|
|
201
|
+
_RANDOM.1: "random("i
|
|
202
|
+
frandom: _RANDOM expr ")"
|
|
200
203
|
|
|
201
|
-
_math_functions: fmul | fdiv | fadd | fsub | fround | fmod | fabs | fsqrt
|
|
204
|
+
_math_functions: fmul | fdiv | fadd | fsub | fround | fmod | fabs | fsqrt | frandom
|
|
202
205
|
|
|
203
206
|
//generic
|
|
204
207
|
_fcast_primary: "cast"i "(" expr "as"i data_type ")"
|
|
@@ -354,7 +357,7 @@
|
|
|
354
357
|
|
|
355
358
|
struct_type: "struct"i "<" ((data_type | IDENTIFIER) ",")* (data_type | IDENTIFIER) ","? ">"
|
|
356
359
|
|
|
357
|
-
list_type: "list"i "<" data_type ">"
|
|
360
|
+
list_type: ("list"i "<" data_type ">" ) | ("array"i "<" data_type ">" )
|
|
358
361
|
|
|
359
362
|
numeric_type: "numeric"i "(" int_lit "," int_lit ")"
|
|
360
363
|
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
from pathlib import Path
|
|
2
|
-
|
|
3
|
-
from trilogy import parse
|
|
4
|
-
from trilogy.core.models.environment import Environment
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
def test_metadata():
|
|
8
|
-
env, _ = parse(
|
|
9
|
-
"""key user_id int metadata(description="the description");
|
|
10
|
-
property user_id.display_name string metadata(description="The display name");"""
|
|
11
|
-
)
|
|
12
|
-
|
|
13
|
-
assert env.concepts["user_id"].metadata.description == "the description"
|
|
14
|
-
assert env.concepts["display_name"].metadata.description == "The display name"
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
def test_import_metadata():
|
|
18
|
-
env = Environment(working_path=Path(__file__).parent)
|
|
19
|
-
env, _ = parse(
|
|
20
|
-
"""import test_env as env; # Dragon metrics
|
|
21
|
-
import test_env as env2;""",
|
|
22
|
-
environment=env,
|
|
23
|
-
)
|
|
24
|
-
|
|
25
|
-
assert "Dragon metrics" in env.concepts["env.id"].metadata.description
|
|
26
|
-
|
|
27
|
-
env2 = env.concepts["env2.id"]
|
|
28
|
-
assert env2.namespace == "env2"
|
|
29
|
-
assert env.concepts["env2.id"].metadata.description is None
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
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.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/node_generators/__init__.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/node_generators/basic_node.py
RENAMED
|
File without changes
|
|
File without changes
|
{pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/node_generators/filter_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/node_generators/group_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/node_generators/group_to_node.py
RENAMED
|
File without changes
|
|
File without changes
|
{pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/node_generators/node_merge_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/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.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/node_generators/select_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/node_generators/synonym_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/node_generators/union_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/node_generators/unnest_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.35 → pytrilogy-0.0.3.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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|