pytrilogy 0.0.2.58__tar.gz → 0.0.3.0__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 (130) hide show
  1. {pytrilogy-0.0.2.58/pytrilogy.egg-info → pytrilogy-0.0.3.0}/PKG-INFO +9 -2
  2. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0/pytrilogy.egg-info}/PKG-INFO +9 -2
  3. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/pytrilogy.egg-info/SOURCES.txt +13 -1
  4. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/tests/test_datatypes.py +1 -1
  5. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/tests/test_derived_concepts.py +4 -1
  6. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/tests/test_discovery_nodes.py +15 -2
  7. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/tests/test_environment.py +40 -4
  8. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/tests/test_executor.py +2 -1
  9. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/tests/test_functions.py +6 -3
  10. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/tests/test_imports.py +1 -1
  11. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/tests/test_metadata.py +2 -1
  12. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/tests/test_models.py +71 -39
  13. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/tests/test_multi_join_assignments.py +2 -1
  14. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/tests/test_parse_engine.py +1 -2
  15. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/tests/test_parsing.py +14 -7
  16. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/tests/test_partial_handling.py +13 -8
  17. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/tests/test_query_processing.py +28 -15
  18. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/tests/test_select.py +40 -9
  19. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/tests/test_show.py +1 -1
  20. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/tests/test_statements.py +6 -1
  21. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/tests/test_undefined_concept.py +3 -1
  22. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/tests/test_where_clause.py +19 -7
  23. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/__init__.py +2 -2
  24. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/core/enums.py +1 -7
  25. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/core/env_processor.py +17 -5
  26. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/core/environment_helpers.py +11 -25
  27. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/core/exceptions.py +4 -0
  28. pytrilogy-0.0.3.0/trilogy/core/functions.py +817 -0
  29. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/core/graph_models.py +10 -10
  30. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/core/internal.py +11 -2
  31. pytrilogy-0.0.3.0/trilogy/core/models/author.py +2110 -0
  32. pytrilogy-0.0.3.0/trilogy/core/models/build.py +1845 -0
  33. pytrilogy-0.0.3.0/trilogy/core/models/build_environment.py +151 -0
  34. pytrilogy-0.0.3.0/trilogy/core/models/core.py +370 -0
  35. pytrilogy-0.0.3.0/trilogy/core/models/datasource.py +297 -0
  36. pytrilogy-0.0.3.0/trilogy/core/models/environment.py +696 -0
  37. pytrilogy-0.0.3.0/trilogy/core/models/execute.py +931 -0
  38. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/core/optimization.py +14 -16
  39. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/core/optimizations/base_optimization.py +1 -1
  40. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/core/optimizations/inline_constant.py +6 -6
  41. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/core/optimizations/inline_datasource.py +17 -11
  42. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/core/optimizations/predicate_pushdown.py +17 -16
  43. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/core/processing/concept_strategies_v3.py +180 -145
  44. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/core/processing/graph_utils.py +1 -1
  45. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/core/processing/node_generators/basic_node.py +19 -18
  46. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/core/processing/node_generators/common.py +50 -44
  47. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/core/processing/node_generators/filter_node.py +26 -13
  48. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/core/processing/node_generators/group_node.py +26 -21
  49. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/core/processing/node_generators/group_to_node.py +11 -8
  50. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/core/processing/node_generators/multiselect_node.py +60 -43
  51. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/core/processing/node_generators/node_merge_node.py +76 -38
  52. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/core/processing/node_generators/rowset_node.py +57 -36
  53. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/core/processing/node_generators/select_helpers/datasource_injection.py +27 -34
  54. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/core/processing/node_generators/select_merge_node.py +161 -64
  55. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/core/processing/node_generators/select_node.py +13 -13
  56. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/core/processing/node_generators/union_node.py +12 -11
  57. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/core/processing/node_generators/unnest_node.py +9 -7
  58. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/core/processing/node_generators/window_node.py +19 -16
  59. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/core/processing/nodes/__init__.py +21 -18
  60. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/core/processing/nodes/base_node.py +82 -66
  61. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/core/processing/nodes/filter_node.py +19 -13
  62. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/core/processing/nodes/group_node.py +50 -35
  63. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/core/processing/nodes/merge_node.py +45 -36
  64. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/core/processing/nodes/select_node_v2.py +53 -39
  65. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/core/processing/nodes/union_node.py +5 -7
  66. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/core/processing/nodes/unnest_node.py +7 -11
  67. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/core/processing/nodes/window_node.py +9 -4
  68. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/core/processing/utility.py +103 -75
  69. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/core/query_processor.py +65 -47
  70. pytrilogy-0.0.3.0/trilogy/core/statements/author.py +413 -0
  71. pytrilogy-0.0.3.0/trilogy/core/statements/common.py +30 -0
  72. pytrilogy-0.0.3.0/trilogy/core/statements/execute.py +42 -0
  73. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/dialect/base.py +146 -106
  74. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/dialect/common.py +9 -10
  75. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/dialect/duckdb.py +1 -1
  76. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/dialect/enums.py +4 -2
  77. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/dialect/presto.py +1 -1
  78. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/dialect/sql_server.py +1 -1
  79. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/executor.py +44 -32
  80. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/hooks/base_hook.py +6 -4
  81. pytrilogy-0.0.3.0/trilogy/hooks/query_debugger.py +167 -0
  82. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/parser.py +1 -1
  83. pytrilogy-0.0.3.0/trilogy/parsing/__init__.py +0 -0
  84. pytrilogy-0.0.3.0/trilogy/parsing/common.py +618 -0
  85. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/parsing/parse_engine.py +263 -617
  86. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/parsing/render.py +50 -26
  87. pytrilogy-0.0.3.0/trilogy/py.typed +0 -0
  88. pytrilogy-0.0.3.0/trilogy/scripts/__init__.py +0 -0
  89. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/scripts/trilogy.py +2 -1
  90. pytrilogy-0.0.2.58/trilogy/core/functions.py +0 -383
  91. pytrilogy-0.0.2.58/trilogy/core/models.py +0 -4960
  92. pytrilogy-0.0.2.58/trilogy/hooks/query_debugger.py +0 -150
  93. pytrilogy-0.0.2.58/trilogy/parsing/common.py +0 -379
  94. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/LICENSE.md +0 -0
  95. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/README.md +0 -0
  96. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/pyproject.toml +0 -0
  97. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/pytrilogy.egg-info/dependency_links.txt +0 -0
  98. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/pytrilogy.egg-info/entry_points.txt +0 -0
  99. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/pytrilogy.egg-info/requires.txt +0 -0
  100. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/pytrilogy.egg-info/top_level.txt +0 -0
  101. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/setup.cfg +0 -0
  102. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/setup.py +0 -0
  103. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/tests/test_declarations.py +0 -0
  104. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/tests/test_enums.py +0 -0
  105. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/compiler.py +0 -0
  106. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/constants.py +0 -0
  107. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/core/__init__.py +0 -0
  108. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/core/constants.py +0 -0
  109. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/core/ergonomics.py +0 -0
  110. {pytrilogy-0.0.2.58/trilogy/core/processing → pytrilogy-0.0.3.0/trilogy/core/models}/__init__.py +0 -0
  111. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/core/optimizations/__init__.py +0 -0
  112. {pytrilogy-0.0.2.58/trilogy/core/processing/node_generators/select_helpers → pytrilogy-0.0.3.0/trilogy/core/processing}/__init__.py +0 -0
  113. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/core/processing/node_generators/__init__.py +0 -0
  114. {pytrilogy-0.0.2.58/trilogy/dialect → pytrilogy-0.0.3.0/trilogy/core/processing/node_generators/select_helpers}/__init__.py +0 -0
  115. {pytrilogy-0.0.2.58/trilogy/hooks → pytrilogy-0.0.3.0/trilogy/core/statements}/__init__.py +0 -0
  116. /pytrilogy-0.0.2.58/trilogy/metadata/__init__.py → /pytrilogy-0.0.3.0/trilogy/core/statements/build.py +0 -0
  117. {pytrilogy-0.0.2.58/trilogy/parsing → pytrilogy-0.0.3.0/trilogy/dialect}/__init__.py +0 -0
  118. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/dialect/bigquery.py +0 -0
  119. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/dialect/config.py +0 -0
  120. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/dialect/postgres.py +0 -0
  121. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/dialect/snowflake.py +0 -0
  122. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/engine.py +0 -0
  123. {pytrilogy-0.0.2.58/trilogy/scripts → pytrilogy-0.0.3.0/trilogy/hooks}/__init__.py +0 -0
  124. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/hooks/graph_hook.py +0 -0
  125. /pytrilogy-0.0.2.58/trilogy/py.typed → /pytrilogy-0.0.3.0/trilogy/metadata/__init__.py +0 -0
  126. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/parsing/config.py +0 -0
  127. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/parsing/exceptions.py +0 -0
  128. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/parsing/helpers.py +0 -0
  129. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/parsing/trilogy.lark +0 -0
  130. {pytrilogy-0.0.2.58 → pytrilogy-0.0.3.0}/trilogy/utility.py +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: pytrilogy
3
- Version: 0.0.2.58
3
+ Version: 0.0.3.0
4
4
  Summary: Declarative, typed query language that compiles to SQL.
5
5
  Home-page:
6
6
  Author:
@@ -27,6 +27,13 @@ Provides-Extra: bigquery
27
27
  Requires-Dist: sqlalchemy-bigquery; extra == "bigquery"
28
28
  Provides-Extra: snowflake
29
29
  Requires-Dist: snowflake-sqlalchemy; extra == "snowflake"
30
+ Dynamic: author-email
31
+ Dynamic: classifier
32
+ Dynamic: description
33
+ Dynamic: description-content-type
34
+ Dynamic: provides-extra
35
+ Dynamic: requires-dist
36
+ Dynamic: summary
30
37
 
31
38
  ## Trilogy
32
39
  [![Website](https://img.shields.io/badge/INTRO-WEB-orange?)](https://trilogydata.dev/)
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: pytrilogy
3
- Version: 0.0.2.58
3
+ Version: 0.0.3.0
4
4
  Summary: Declarative, typed query language that compiles to SQL.
5
5
  Home-page:
6
6
  Author:
@@ -27,6 +27,13 @@ Provides-Extra: bigquery
27
27
  Requires-Dist: sqlalchemy-bigquery; extra == "bigquery"
28
28
  Provides-Extra: snowflake
29
29
  Requires-Dist: snowflake-sqlalchemy; extra == "snowflake"
30
+ Dynamic: author-email
31
+ Dynamic: classifier
32
+ Dynamic: description
33
+ Dynamic: description-content-type
34
+ Dynamic: provides-extra
35
+ Dynamic: requires-dist
36
+ Dynamic: summary
30
37
 
31
38
  ## Trilogy
32
39
  [![Website](https://img.shields.io/badge/INTRO-WEB-orange?)](https://trilogydata.dev/)
@@ -47,9 +47,16 @@ trilogy/core/exceptions.py
47
47
  trilogy/core/functions.py
48
48
  trilogy/core/graph_models.py
49
49
  trilogy/core/internal.py
50
- trilogy/core/models.py
51
50
  trilogy/core/optimization.py
52
51
  trilogy/core/query_processor.py
52
+ trilogy/core/models/__init__.py
53
+ trilogy/core/models/author.py
54
+ trilogy/core/models/build.py
55
+ trilogy/core/models/build_environment.py
56
+ trilogy/core/models/core.py
57
+ trilogy/core/models/datasource.py
58
+ trilogy/core/models/environment.py
59
+ trilogy/core/models/execute.py
53
60
  trilogy/core/optimizations/__init__.py
54
61
  trilogy/core/optimizations/base_optimization.py
55
62
  trilogy/core/optimizations/inline_constant.py
@@ -84,6 +91,11 @@ trilogy/core/processing/nodes/select_node_v2.py
84
91
  trilogy/core/processing/nodes/union_node.py
85
92
  trilogy/core/processing/nodes/unnest_node.py
86
93
  trilogy/core/processing/nodes/window_node.py
94
+ trilogy/core/statements/__init__.py
95
+ trilogy/core/statements/author.py
96
+ trilogy/core/statements/build.py
97
+ trilogy/core/statements/common.py
98
+ trilogy/core/statements/execute.py
87
99
  trilogy/dialect/__init__.py
88
100
  trilogy/dialect/base.py
89
101
  trilogy/dialect/bigquery.py
@@ -1,5 +1,5 @@
1
1
  from trilogy.core.exceptions import InvalidSyntaxException
2
- from trilogy.core.models import (
2
+ from trilogy.core.models.core import (
3
3
  NumericType,
4
4
  )
5
5
  from trilogy.parsing.parse_engine import (
@@ -33,7 +33,10 @@ def test_filtering_where_on_derived_aggregate(test_environment):
33
33
  )
34
34
  except Exception as e:
35
35
  exception = True
36
- assert "Undefined concept: local.filtered_cst" in str(e)
36
+ assert (
37
+ "Cannot reference an aggregate derived in the select (local.filtered_cst)"
38
+ in str(e)
39
+ )
37
40
  assert exception, "should have an exception"
38
41
 
39
42
 
@@ -1,13 +1,17 @@
1
1
  from trilogy.core.constants import ALL_ROWS_CONCEPT, INTERNAL_NAMESPACE
2
- from trilogy.core.models import Environment, Grain
2
+ from trilogy.core.models.build import BuildGrain
3
+ from trilogy.core.models.environment import Environment
3
4
  from trilogy.core.processing.concept_strategies_v3 import (
4
5
  GroupNode,
6
+ History,
5
7
  search_concepts,
6
8
  )
7
9
  from trilogy.core.processing.node_generators import gen_group_node
8
10
 
9
11
 
10
12
  def test_group_node(test_environment, test_environment_graph):
13
+ history = History(base_environment=test_environment)
14
+ test_environment = test_environment.materialize_for_select()
11
15
  total_revenue = test_environment.concepts["total_revenue"]
12
16
  revenue = test_environment.concepts["revenue"]
13
17
  category = test_environment.concepts["category_name"]
@@ -21,6 +25,7 @@ def test_group_node(test_environment, test_environment_graph):
21
25
  environment=test_environment,
22
26
  g=test_environment_graph,
23
27
  depth=0,
28
+ history=history,
24
29
  )
25
30
  ],
26
31
  )
@@ -28,6 +33,8 @@ def test_group_node(test_environment, test_environment_graph):
28
33
 
29
34
 
30
35
  def test_group_node_property(test_environment: Environment, test_environment_graph):
36
+ history = History(base_environment=test_environment)
37
+ test_environment = test_environment.materialize_for_select()
31
38
  sum_name_length = test_environment.concepts["category_name_length_sum"]
32
39
 
33
40
  group_node = gen_group_node(
@@ -36,6 +43,7 @@ def test_group_node_property(test_environment: Environment, test_environment_gra
36
43
  environment=test_environment,
37
44
  g=test_environment_graph,
38
45
  source_concepts=search_concepts,
46
+ history=history,
39
47
  depth=0,
40
48
  )
41
49
  input_concept_names = {
@@ -50,15 +58,20 @@ def test_group_node_property(test_environment: Environment, test_environment_gra
50
58
 
51
59
 
52
60
  def test_group_node_property_all(test_environment: Environment, test_environment_graph):
61
+ history = History(base_environment=test_environment)
62
+ test_environment = test_environment.materialize_for_select()
53
63
  sum_name_length = test_environment.concepts["category_name_length_sum"]
54
64
  all_rows = test_environment.concepts[f"{INTERNAL_NAMESPACE}.{ALL_ROWS_CONCEPT}"]
55
- sum_name_length_all_rows = sum_name_length.with_grain(Grain(components=[all_rows]))
65
+ sum_name_length_all_rows = sum_name_length.with_grain(
66
+ BuildGrain(components=[all_rows])
67
+ )
56
68
  group_node = gen_group_node(
57
69
  sum_name_length_all_rows,
58
70
  local_optional=[],
59
71
  environment=test_environment,
60
72
  g=test_environment_graph,
61
73
  source_concepts=search_concepts,
74
+ history=history,
62
75
  depth=0,
63
76
  )
64
77
  input_concept_names = {
@@ -1,15 +1,21 @@
1
1
  from pathlib import Path
2
2
 
3
+ from pytest import raises
4
+
3
5
  from trilogy import Dialects
4
- from trilogy.core.enums import Modifier
5
- from trilogy.core.exceptions import UndefinedConceptException
6
- from trilogy.core.models import Environment
6
+ from trilogy.core.enums import Modifier, Purpose
7
+ from trilogy.core.exceptions import (
8
+ FrozenEnvironmentException,
9
+ UndefinedConceptException,
10
+ )
11
+ from trilogy.core.models.author import Concept
12
+ from trilogy.core.models.core import DataType
13
+ from trilogy.core.models.environment import Environment, LazyEnvironment
7
14
 
8
15
 
9
16
  def test_environment_serialization(test_environment: Environment):
10
17
 
11
18
  path = test_environment.to_cache()
12
- print(path)
13
19
  test_environment2 = Environment.from_cache(path)
14
20
  assert test_environment2
15
21
 
@@ -25,6 +31,36 @@ def test_environment_from_path():
25
31
  assert "local.id" in env.concepts
26
32
 
27
33
 
34
+ def test_lazy_environment_from_path():
35
+ env = LazyEnvironment(load_path=Path(__file__).parent / "test_env.preql")
36
+
37
+ assert not env.loaded
38
+
39
+ _ = len(env.concepts)
40
+
41
+ assert env.loaded
42
+
43
+ env2 = Environment.from_file(Path(__file__).parent / "test_env.preql")
44
+
45
+ assert env.concepts == env2.concepts
46
+
47
+
48
+ def test_frozen_environment():
49
+ env = Environment.from_file(Path(__file__).parent / "test_env.preql")
50
+
51
+ exec = Dialects.DUCK_DB.default_executor(environment=env)
52
+
53
+ run = exec.execute_query(
54
+ """select id+5 ->id_plus_5 order by id_plus_5 asc;"""
55
+ ).fetchall()
56
+ assert run[0].id_plus_5 == 6
57
+ env.freeze()
58
+ with raises(FrozenEnvironmentException):
59
+ env.add_concept(
60
+ Concept(name="test", datatype=DataType.INTEGER, purpose=Purpose.KEY)
61
+ )
62
+
63
+
28
64
  def test_environment_invalid():
29
65
  env = Environment()
30
66
  env.concepts.fail_on_missing = False
@@ -1,6 +1,7 @@
1
1
  from pathlib import Path
2
2
 
3
- from trilogy import Dialects, Environment, parse
3
+ from trilogy import Dialects, parse
4
+ from trilogy.core.models.environment import Environment
4
5
 
5
6
 
6
7
  def test_file_parsing():
@@ -6,10 +6,12 @@ from pytest import raises
6
6
 
7
7
  from trilogy import Dialects
8
8
  from trilogy.constants import logger
9
- from trilogy.core.enums import Purpose, PurposeLineage
9
+ from trilogy.core.enums import Derivation, Purpose
10
10
  from trilogy.core.exceptions import InvalidSyntaxException
11
- from trilogy.core.models import DataType, Environment, ListType, SelectStatement
11
+ from trilogy.core.models.core import DataType, ListType
12
+ from trilogy.core.models.environment import Environment
12
13
  from trilogy.core.query_processor import process_query
14
+ from trilogy.core.statements.author import SelectStatement
13
15
  from trilogy.dialect.base import BaseDialect
14
16
  from trilogy.dialect.bigquery import BigqueryDialect
15
17
  from trilogy.dialect.duckdb import DuckDBDialect
@@ -107,6 +109,7 @@ def test_date_functions(test_environment):
107
109
 
108
110
  select
109
111
  order_id,
112
+ order_timestamp,
110
113
  date(order_timestamp) -> order_date,
111
114
  datetime(order_timestamp) -> order_timestamp_datetime,
112
115
  timestamp(order_timestamp) -> order_timestamp_dos,
@@ -344,4 +347,4 @@ def test_validate_constant_functions():
344
347
  """
345
348
  )
346
349
  assert env.concepts["current_date"].purpose == Purpose.CONSTANT
347
- assert env.concepts["current_date"].derivation == PurposeLineage.CONSTANT
350
+ assert env.concepts["current_date"].derivation == Derivation.CONSTANT
@@ -1,6 +1,6 @@
1
1
  from pathlib import Path
2
2
 
3
- from trilogy import Environment
3
+ from trilogy.core.models.environment import Environment
4
4
 
5
5
 
6
6
  def test_multi_environment():
@@ -1,6 +1,7 @@
1
1
  from pathlib import Path
2
2
 
3
- from trilogy import Environment, parse
3
+ from trilogy import parse
4
+ from trilogy.core.models.environment import Environment
4
5
 
5
6
 
6
7
  def test_metadata():
@@ -1,29 +1,43 @@
1
1
  from copy import deepcopy
2
2
 
3
3
  from trilogy import parse
4
- from trilogy.core.enums import BooleanOperator, ComparisonOperator, JoinType, Purpose
5
- from trilogy.core.models import (
6
- CTE,
7
- Address,
4
+ from trilogy.core.enums import (
5
+ BooleanOperator,
6
+ ComparisonOperator,
7
+ FunctionType,
8
+ JoinType,
9
+ Purpose,
10
+ )
11
+ from trilogy.core.models.author import (
8
12
  AggregateWrapper,
9
- BaseJoin,
10
13
  Comparison,
11
14
  Concept,
12
15
  Conditional,
13
- CTEConceptPair,
14
- DataType,
15
- Environment,
16
+ Function,
16
17
  Grain,
17
- Join,
18
- QueryDatasource,
18
+ Parenthetical,
19
19
  RowsetItem,
20
- SelectStatement,
21
- TupleWrapper,
22
20
  UndefinedConcept,
23
21
  )
22
+ from trilogy.core.models.build import BuildGrain
23
+ from trilogy.core.models.core import (
24
+ DataType,
25
+ TupleWrapper,
26
+ )
27
+ from trilogy.core.models.datasource import Address
28
+ from trilogy.core.models.environment import Environment
29
+ from trilogy.core.models.execute import (
30
+ CTE,
31
+ BaseJoin,
32
+ CTEConceptPair,
33
+ Join,
34
+ QueryDatasource,
35
+ )
36
+ from trilogy.core.statements.author import SelectStatement
24
37
 
25
38
 
26
39
  def test_cte_merge(test_environment, test_environment_graph):
40
+ test_environment = test_environment.materialize_for_select()
27
41
  datasource = list(test_environment.datasources.values())[0]
28
42
  outputs = [c.concept for c in datasource.columns]
29
43
  output_map = {
@@ -35,12 +49,12 @@ def test_cte_merge(test_environment, test_environment_graph):
35
49
  a = CTE(
36
50
  name="test",
37
51
  output_columns=[outputs[0]],
38
- grain=Grain(),
52
+ grain=BuildGrain(),
39
53
  source=QueryDatasource(
40
54
  input_concepts=[outputs[0]],
41
55
  output_concepts=[outputs[0]],
42
56
  datasources=[datasource],
43
- grain=Grain(),
57
+ grain=BuildGrain(),
44
58
  joins=[],
45
59
  source_map={outputs[0].address: {datasource}},
46
60
  ),
@@ -49,12 +63,12 @@ def test_cte_merge(test_environment, test_environment_graph):
49
63
  b = CTE(
50
64
  name="testb",
51
65
  output_columns=outputs,
52
- grain=Grain(),
66
+ grain=BuildGrain(),
53
67
  source=QueryDatasource(
54
68
  input_concepts=outputs,
55
69
  output_concepts=outputs,
56
70
  datasources=[datasource],
57
- grain=Grain(),
71
+ grain=BuildGrain(),
58
72
  joins=[],
59
73
  source_map=output_map,
60
74
  ),
@@ -151,33 +165,22 @@ def test_select(test_environment: Environment):
151
165
  selection=[oid, pid, cid, cname], grain=Grain(components=[oid, pid, cid])
152
166
  )
153
167
  ds = x.to_datasource(
154
- test_environment.namespace, "test", address=Address(location="test")
168
+ test_environment.namespace,
169
+ "test",
170
+ address=Address(location="test"),
171
+ environment=test_environment,
155
172
  )
156
173
 
157
174
  assert ds.grain.components == Grain(components=[oid, pid, cid]).components
158
175
 
159
176
 
160
177
  def test_undefined(test_environment: Environment):
161
- x = UndefinedConcept(
162
- name="test",
163
- datatype="int",
164
- purpose=Purpose.CONSTANT,
165
- grain=Grain(),
166
- namespace="test",
167
- environment=test_environment.concepts,
168
- )
169
-
170
- # y = x.with_select_context({}, Grain(components=[test_environment.concepts["order_id"]]), test_environment)
171
-
172
- # assert y.grain == Grain(components=[test_environment.concepts["order_id"]])
173
-
174
- z = x.with_default_grain()
175
-
176
- assert z.grain == Grain()
178
+ UndefinedConcept(address="test.test")
177
179
 
178
180
 
179
181
  def test_base_join(test_environment: Environment):
180
182
  exc: SyntaxError | None = None
183
+ test_environment = test_environment.materialize_for_select()
181
184
  try:
182
185
  BaseJoin(
183
186
  left_datasource=test_environment.datasources["revenue"],
@@ -211,6 +214,7 @@ def test_comparison():
211
214
 
212
215
 
213
216
  def test_join(test_environment: Environment):
217
+ test_environment = test_environment.materialize_for_select()
214
218
  datasource = list(test_environment.datasources.values())[0]
215
219
  outputs = [c.concept for c in datasource.columns]
216
220
  output_map = {
@@ -222,12 +226,12 @@ def test_join(test_environment: Environment):
222
226
  a = CTE(
223
227
  name="test",
224
228
  output_columns=[outputs[0]],
225
- grain=Grain(),
229
+ grain=BuildGrain(),
226
230
  source=QueryDatasource(
227
231
  input_concepts=[outputs[0]],
228
232
  output_concepts=[outputs[0]],
229
233
  datasources=[datasource],
230
- grain=Grain(),
234
+ grain=BuildGrain(),
231
235
  joins=[],
232
236
  source_map={outputs[0].address: {datasource}},
233
237
  ),
@@ -237,12 +241,12 @@ def test_join(test_environment: Environment):
237
241
  b = CTE(
238
242
  name="testb",
239
243
  output_columns=outputs,
240
- grain=Grain(),
244
+ grain=BuildGrain(),
241
245
  source=QueryDatasource(
242
246
  input_concepts=outputs,
243
247
  output_concepts=outputs,
244
248
  datasources=[datasource],
245
- grain=Grain(),
249
+ grain=BuildGrain(),
246
250
  joins=[],
247
251
  source_map=output_map,
248
252
  ),
@@ -270,7 +274,6 @@ def test_concept_address_in_check():
270
274
  datatype="int",
271
275
  purpose=Purpose.CONSTANT,
272
276
  grain=Grain(),
273
- environment={},
274
277
  )
275
278
  assert target.address == "local.test"
276
279
  x = [target]
@@ -304,10 +307,39 @@ select avg_greater_ten;
304
307
 
305
308
  lineage = env.concepts["avg_greater_ten"].lineage
306
309
  assert isinstance(lineage, AggregateWrapper)
307
- assert isinstance(lineage.function.concept_arguments[0].lineage, RowsetItem)
310
+ assert isinstance(
311
+ env.concepts[lineage.function.concept_arguments[0]].lineage, RowsetItem
312
+ )
308
313
 
309
314
 
310
315
  def test_tuple_clone():
311
316
  x = TupleWrapper([1, 2, 3], type=DataType.INTEGER)
312
317
  y = deepcopy(x)
313
318
  assert y == x
319
+
320
+
321
+ def test_parenthetical(test_environment: Environment):
322
+ x = Parenthetical(content=TupleWrapper([1, 2, 3], type=DataType.INTEGER))
323
+
324
+ assert x.concept_arguments == []
325
+
326
+ x = Parenthetical(
327
+ content=test_environment.concepts["order_id"], type=DataType.INTEGER
328
+ )
329
+ # return concept if it's a concept
330
+ assert x.concept_arguments == [test_environment.concepts["order_id"]]
331
+ function = Function(
332
+ operator=FunctionType.COUNT,
333
+ output_datatype=DataType.INTEGER,
334
+ output_purpose=Purpose.METRIC,
335
+ arguments=[test_environment.concepts["order_id"]],
336
+ )
337
+ assert function.concept_arguments == [
338
+ test_environment.concepts["order_id"].reference
339
+ ]
340
+ x = Parenthetical(content=function)
341
+ # else pass through parent
342
+ assert x.concept_arguments == [test_environment.concepts["order_id"].reference]
343
+
344
+ merged = x + x
345
+ assert isinstance(merged, Conditional)
@@ -1,6 +1,7 @@
1
1
  # from trilogy.compiler import compile
2
- from trilogy.core.models import Grain, SelectStatement
2
+ from trilogy.core.models.author import Grain
3
3
  from trilogy.core.query_processor import process_query
4
+ from trilogy.core.statements.author import SelectStatement
4
5
  from trilogy.parser import parse
5
6
 
6
7
  TEST_SETUP = r"""
@@ -1,7 +1,7 @@
1
1
  from pytest import raises
2
2
 
3
- from trilogy import Environment
4
3
  from trilogy.core.exceptions import UndefinedConceptException
4
+ from trilogy.core.models.environment import Environment
5
5
  from trilogy.parsing.parse_engine import PARSER, ParseToObjects, unpack_visit_error
6
6
 
7
7
  TEXT = """
@@ -17,7 +17,6 @@ select
17
17
  def test_parser():
18
18
  env = Environment()
19
19
  x = ParseToObjects(environment=env)
20
- x.environment.concepts.fail_on_missing = False
21
20
  x.set_text(TEXT)
22
21
 
23
22
  failed = False
@@ -2,16 +2,15 @@ from trilogy import Dialects
2
2
  from trilogy.constants import MagicConstants
3
3
  from trilogy.core.enums import BooleanOperator, ComparisonOperator, Purpose
4
4
  from trilogy.core.functions import argument_to_purpose, function_args_to_output_purpose
5
- from trilogy.core.models import (
6
- Comparison,
7
- Datasource,
5
+ from trilogy.core.models.author import Comparison
6
+ from trilogy.core.models.core import (
8
7
  DataType,
9
- Environment,
10
- ProcessedQuery,
11
- SelectStatement,
12
- ShowStatement,
13
8
  TupleWrapper,
14
9
  )
10
+ from trilogy.core.models.datasource import Datasource
11
+ from trilogy.core.models.environment import Environment
12
+ from trilogy.core.statements.author import SelectStatement, ShowStatement
13
+ from trilogy.core.statements.execute import ProcessedQuery
15
14
  from trilogy.dialect.base import BaseDialect
16
15
  from trilogy.parsing.parse_engine import (
17
16
  arg_to_datatype,
@@ -390,6 +389,14 @@ select composite_id;
390
389
  """
391
390
  executor.parse_text(test_case)
392
391
 
392
+ assert (
393
+ "local.composite_id_alt"
394
+ in executor.environment.concepts["local.composite_id"].pseudonyms
395
+ )
396
+ assert (
397
+ "local.composite_id"
398
+ in executor.environment.alias_origin_lookup["local.composite_id_alt"].pseudonyms
399
+ )
393
400
  results = executor.execute_text(test_case)[0].fetchall()
394
401
 
395
402
  assert results == [("123-abc",)]
@@ -1,16 +1,14 @@
1
- # from trilogy.core.models import Environment
2
1
  from sqlalchemy import create_engine
3
2
 
4
3
  from trilogy import Dialects, Executor
5
4
  from trilogy.core.enums import Purpose
6
- from trilogy.core.models import (
7
- ColumnAssignment,
8
- Concept,
9
- Datasource,
5
+ from trilogy.core.models.author import Concept
6
+ from trilogy.core.models.core import (
10
7
  DataType,
11
- Environment,
12
8
  )
13
- from trilogy.core.processing.concept_strategies_v3 import search_concepts
9
+ from trilogy.core.models.datasource import ColumnAssignment, Datasource
10
+ from trilogy.core.models.environment import Environment
11
+ from trilogy.core.processing.concept_strategies_v3 import History, search_concepts
14
12
  from trilogy.core.processing.node_generators import (
15
13
  gen_filter_node,
16
14
  )
@@ -104,12 +102,14 @@ def test_partial_assignment():
104
102
 
105
103
  executor = setup_engine()
106
104
  env = Environment()
105
+ history = History(base_environment=env)
107
106
  setup_titanic(env)
108
107
  executor.environment = env
109
108
  executor.hooks = [DebuggingHook()]
110
109
  test = """property passenger.id.family <- split(passenger.name, ',')[1];
111
110
  auto surviving_passenger<- filter passenger.id where passenger.survived =1;"""
112
111
  _ = executor.parse_text(test)
112
+ env = env.materialize_for_select()
113
113
  family = env.concepts["passenger.family"]
114
114
  # id = env.concepts["passenger.id"]
115
115
  # survived = env.concepts["passenger.survived"]
@@ -117,6 +117,7 @@ def test_partial_assignment():
117
117
  filtered_node = gen_filter_node(
118
118
  env.concepts["surviving_passenger"],
119
119
  [family],
120
+ history=history,
120
121
  environment=env,
121
122
  g=g,
122
123
  depth=0,
@@ -132,7 +133,11 @@ def test_partial_assignment():
132
133
 
133
134
  # check at the source level
134
135
  sourced = search_concepts(
135
- [family, env.concepts["surviving_passenger"]], environment=env, g=g, depth=0
136
+ [family, env.concepts["surviving_passenger"]],
137
+ history=history,
138
+ environment=env,
139
+ g=g,
140
+ depth=0,
136
141
  )
137
142
  assert isinstance(sourced, MergeNode)
138
143
  assert len(sourced.parents) == 2