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.

Files changed (140) hide show
  1. {pytrilogy-0.0.3.35/pytrilogy.egg-info → pytrilogy-0.0.3.37}/PKG-INFO +1 -1
  2. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37/pytrilogy.egg-info}/PKG-INFO +1 -1
  3. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/tests/test_derived_concepts.py +8 -0
  4. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/tests/test_functions.py +19 -1
  5. pytrilogy-0.0.3.37/tests/test_metadata.py +26 -0
  6. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/tests/test_typing.py +21 -0
  7. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/__init__.py +1 -1
  8. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/enums.py +1 -0
  9. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/environment_helpers.py +2 -2
  10. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/functions.py +6 -0
  11. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/models/build.py +12 -0
  12. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/dialect/base.py +9 -0
  13. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/dialect/bigquery.py +17 -0
  14. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/parsing/parse_engine.py +19 -12
  15. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/parsing/trilogy.lark +6 -3
  16. pytrilogy-0.0.3.35/tests/test_metadata.py +0 -29
  17. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/LICENSE.md +0 -0
  18. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/README.md +0 -0
  19. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/pyproject.toml +0 -0
  20. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/pytrilogy.egg-info/SOURCES.txt +0 -0
  21. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/pytrilogy.egg-info/dependency_links.txt +0 -0
  22. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/pytrilogy.egg-info/entry_points.txt +0 -0
  23. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/pytrilogy.egg-info/requires.txt +0 -0
  24. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/pytrilogy.egg-info/top_level.txt +0 -0
  25. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/setup.cfg +0 -0
  26. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/setup.py +0 -0
  27. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/tests/test_datatypes.py +0 -0
  28. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/tests/test_declarations.py +0 -0
  29. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/tests/test_discovery_nodes.py +0 -0
  30. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/tests/test_enums.py +0 -0
  31. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/tests/test_environment.py +0 -0
  32. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/tests/test_executor.py +0 -0
  33. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/tests/test_imports.py +0 -0
  34. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/tests/test_models.py +0 -0
  35. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/tests/test_multi_join_assignments.py +0 -0
  36. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/tests/test_parse_engine.py +0 -0
  37. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/tests/test_parsing.py +0 -0
  38. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/tests/test_partial_handling.py +0 -0
  39. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/tests/test_query_processing.py +0 -0
  40. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/tests/test_query_render.py +0 -0
  41. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/tests/test_select.py +0 -0
  42. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/tests/test_show.py +0 -0
  43. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/tests/test_statements.py +0 -0
  44. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/tests/test_undefined_concept.py +0 -0
  45. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/tests/test_user_functions.py +0 -0
  46. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/tests/test_where_clause.py +0 -0
  47. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/authoring/__init__.py +0 -0
  48. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/compiler.py +0 -0
  49. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/constants.py +0 -0
  50. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/__init__.py +0 -0
  51. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/constants.py +0 -0
  52. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/env_processor.py +0 -0
  53. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/ergonomics.py +0 -0
  54. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/exceptions.py +0 -0
  55. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/graph_models.py +0 -0
  56. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/internal.py +0 -0
  57. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/models/__init__.py +0 -0
  58. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/models/author.py +0 -0
  59. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/models/build_environment.py +0 -0
  60. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/models/core.py +0 -0
  61. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/models/datasource.py +0 -0
  62. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/models/environment.py +0 -0
  63. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/models/execute.py +0 -0
  64. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/optimization.py +0 -0
  65. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/optimizations/__init__.py +0 -0
  66. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/optimizations/base_optimization.py +0 -0
  67. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/optimizations/inline_constant.py +0 -0
  68. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/optimizations/inline_datasource.py +0 -0
  69. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/optimizations/predicate_pushdown.py +0 -0
  70. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/__init__.py +0 -0
  71. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/concept_strategies_v3.py +0 -0
  72. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/graph_utils.py +0 -0
  73. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/node_generators/__init__.py +0 -0
  74. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/node_generators/basic_node.py +0 -0
  75. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/node_generators/common.py +0 -0
  76. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/node_generators/filter_node.py +0 -0
  77. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/node_generators/group_node.py +0 -0
  78. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/node_generators/group_to_node.py +0 -0
  79. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/node_generators/multiselect_node.py +0 -0
  80. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/node_generators/node_merge_node.py +0 -0
  81. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/node_generators/rowset_node.py +0 -0
  82. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/node_generators/select_helpers/__init__.py +0 -0
  83. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/node_generators/select_helpers/datasource_injection.py +0 -0
  84. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/node_generators/select_merge_node.py +0 -0
  85. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/node_generators/select_node.py +0 -0
  86. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/node_generators/synonym_node.py +0 -0
  87. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/node_generators/union_node.py +0 -0
  88. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/node_generators/unnest_node.py +0 -0
  89. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/node_generators/window_node.py +0 -0
  90. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/nodes/__init__.py +0 -0
  91. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/nodes/base_node.py +0 -0
  92. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/nodes/filter_node.py +0 -0
  93. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/nodes/group_node.py +0 -0
  94. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/nodes/merge_node.py +0 -0
  95. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/nodes/select_node_v2.py +0 -0
  96. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/nodes/union_node.py +0 -0
  97. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/nodes/unnest_node.py +0 -0
  98. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/nodes/window_node.py +0 -0
  99. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/processing/utility.py +0 -0
  100. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/query_processor.py +0 -0
  101. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/statements/__init__.py +0 -0
  102. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/statements/author.py +0 -0
  103. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/statements/build.py +0 -0
  104. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/statements/common.py +0 -0
  105. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/core/statements/execute.py +0 -0
  106. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/dialect/__init__.py +0 -0
  107. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/dialect/common.py +0 -0
  108. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/dialect/config.py +0 -0
  109. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/dialect/dataframe.py +0 -0
  110. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/dialect/duckdb.py +0 -0
  111. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/dialect/enums.py +0 -0
  112. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/dialect/postgres.py +0 -0
  113. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/dialect/presto.py +0 -0
  114. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/dialect/snowflake.py +0 -0
  115. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/dialect/sql_server.py +0 -0
  116. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/engine.py +0 -0
  117. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/executor.py +0 -0
  118. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/hooks/__init__.py +0 -0
  119. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/hooks/base_hook.py +0 -0
  120. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/hooks/graph_hook.py +0 -0
  121. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/hooks/query_debugger.py +0 -0
  122. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/metadata/__init__.py +0 -0
  123. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/parser.py +0 -0
  124. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/parsing/__init__.py +0 -0
  125. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/parsing/common.py +0 -0
  126. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/parsing/config.py +0 -0
  127. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/parsing/exceptions.py +0 -0
  128. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/parsing/helpers.py +0 -0
  129. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/parsing/render.py +0 -0
  130. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/py.typed +0 -0
  131. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/render.py +0 -0
  132. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/scripts/__init__.py +0 -0
  133. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/scripts/trilogy.py +0 -0
  134. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/std/__init__.py +0 -0
  135. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/std/date.preql +0 -0
  136. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/std/display.preql +0 -0
  137. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/std/geography.preql +0 -0
  138. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/std/money.preql +0 -0
  139. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/std/report.preql +0 -0
  140. {pytrilogy-0.0.3.35 → pytrilogy-0.0.3.37}/trilogy/utility.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pytrilogy
3
- Version: 0.0.3.35
3
+ Version: 0.0.3.37
4
4
  Summary: Declarative, typed query language that compiles to SQL.
5
5
  Home-page:
6
6
  Author:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pytrilogy
3
- Version: 0.0.3.35
3
+ Version: 0.0.3.37
4
4
  Summary: Declarative, typed query language that compiles to SQL.
5
5
  Home-page:
6
6
  Author:
@@ -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"]
@@ -4,6 +4,6 @@ from trilogy.dialect.enums import Dialects
4
4
  from trilogy.executor import Executor
5
5
  from trilogy.parser import parse
6
6
 
7
- __version__ = "0.0.3.35"
7
+ __version__ = "0.0.3.37"
8
8
 
9
9
  __all__ = ["parse", "Executor", "Dialects", "Environment", "CONFIG"]
@@ -155,6 +155,7 @@ class FunctionType(Enum):
155
155
  ROUND = "round"
156
156
  ABS = "abs"
157
157
  SQRT = "sqrt"
158
+ RANDOM = "random"
158
159
 
159
160
  # Aggregates
160
161
  ## group is not a real aggregate - it just means group by this + some other set of fields
@@ -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=DataType.INTEGER,
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=DataType.INTEGER,
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
- if isinstance(output, ImportStatement):
372
- if len(args) > 1 and isinstance(args[1], Comment):
373
- comment = args[1].text.split("#")[1].strip()
374
- namespace = output.alias
375
- for _, v in self.environment.concepts.items():
376
- if v.namespace == namespace:
377
- if v.metadata.description:
378
- v.metadata.description = (
379
- f"{comment}: {v.metadata.description}"
380
- )
381
- else:
382
- v.metadata.description = comment
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
- fsqrt: "sqrt"i "(" expr ")"
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