pytrilogy 0.0.2.50__tar.gz → 0.0.2.51__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 (114) hide show
  1. {pytrilogy-0.0.2.50/pytrilogy.egg-info → pytrilogy-0.0.2.51}/PKG-INFO +1 -1
  2. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51/pytrilogy.egg-info}/PKG-INFO +1 -1
  3. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/pytrilogy.egg-info/SOURCES.txt +2 -0
  4. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/tests/test_environment.py +2 -2
  5. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/tests/test_functions.py +4 -3
  6. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/tests/test_models.py +5 -3
  7. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/tests/test_query_processing.py +28 -9
  8. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/__init__.py +1 -1
  9. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/core/internal.py +5 -1
  10. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/core/models.py +124 -263
  11. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/core/processing/concept_strategies_v3.py +14 -4
  12. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/core/processing/node_generators/basic_node.py +7 -3
  13. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/core/processing/node_generators/common.py +8 -3
  14. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/core/processing/node_generators/filter_node.py +5 -5
  15. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/core/processing/node_generators/group_node.py +24 -8
  16. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/core/processing/node_generators/multiselect_node.py +4 -3
  17. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/core/processing/node_generators/node_merge_node.py +14 -2
  18. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/core/processing/node_generators/rowset_node.py +3 -4
  19. pytrilogy-0.0.2.51/trilogy/core/processing/node_generators/select_helpers/datasource_injection.py +203 -0
  20. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/core/processing/node_generators/select_merge_node.py +17 -9
  21. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/core/processing/nodes/base_node.py +2 -33
  22. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/core/processing/nodes/group_node.py +19 -10
  23. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/core/processing/nodes/merge_node.py +2 -2
  24. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/hooks/graph_hook.py +3 -1
  25. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/parsing/common.py +54 -12
  26. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/parsing/parse_engine.py +39 -20
  27. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/parsing/render.py +8 -1
  28. pytrilogy-0.0.2.51/trilogy/scripts/__init__.py +0 -0
  29. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/LICENSE.md +0 -0
  30. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/README.md +0 -0
  31. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/pyproject.toml +0 -0
  32. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/pytrilogy.egg-info/dependency_links.txt +0 -0
  33. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/pytrilogy.egg-info/entry_points.txt +0 -0
  34. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/pytrilogy.egg-info/requires.txt +0 -0
  35. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/pytrilogy.egg-info/top_level.txt +0 -0
  36. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/setup.cfg +0 -0
  37. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/setup.py +0 -0
  38. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/tests/test_datatypes.py +0 -0
  39. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/tests/test_declarations.py +0 -0
  40. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/tests/test_derived_concepts.py +0 -0
  41. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/tests/test_discovery_nodes.py +0 -0
  42. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/tests/test_enums.py +0 -0
  43. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/tests/test_executor.py +0 -0
  44. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/tests/test_imports.py +0 -0
  45. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/tests/test_metadata.py +0 -0
  46. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/tests/test_multi_join_assignments.py +0 -0
  47. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/tests/test_parse_engine.py +0 -0
  48. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/tests/test_parsing.py +0 -0
  49. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/tests/test_partial_handling.py +0 -0
  50. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/tests/test_select.py +0 -0
  51. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/tests/test_show.py +0 -0
  52. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/tests/test_statements.py +0 -0
  53. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/tests/test_undefined_concept.py +0 -0
  54. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/tests/test_where_clause.py +0 -0
  55. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/compiler.py +0 -0
  56. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/constants.py +0 -0
  57. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/core/__init__.py +0 -0
  58. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/core/constants.py +0 -0
  59. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/core/enums.py +0 -0
  60. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/core/env_processor.py +0 -0
  61. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/core/environment_helpers.py +0 -0
  62. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/core/ergonomics.py +0 -0
  63. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/core/exceptions.py +0 -0
  64. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/core/functions.py +0 -0
  65. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/core/graph_models.py +0 -0
  66. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/core/optimization.py +0 -0
  67. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/core/optimizations/__init__.py +0 -0
  68. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/core/optimizations/base_optimization.py +0 -0
  69. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/core/optimizations/inline_constant.py +0 -0
  70. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/core/optimizations/inline_datasource.py +0 -0
  71. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/core/optimizations/predicate_pushdown.py +0 -0
  72. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/core/processing/__init__.py +0 -0
  73. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/core/processing/graph_utils.py +0 -0
  74. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/core/processing/node_generators/__init__.py +0 -0
  75. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/core/processing/node_generators/group_to_node.py +0 -0
  76. {pytrilogy-0.0.2.50/trilogy/dialect → pytrilogy-0.0.2.51/trilogy/core/processing/node_generators/select_helpers}/__init__.py +0 -0
  77. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/core/processing/node_generators/select_node.py +0 -0
  78. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/core/processing/node_generators/union_node.py +0 -0
  79. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/core/processing/node_generators/unnest_node.py +0 -0
  80. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/core/processing/node_generators/window_node.py +0 -0
  81. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/core/processing/nodes/__init__.py +0 -0
  82. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/core/processing/nodes/filter_node.py +0 -0
  83. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/core/processing/nodes/select_node_v2.py +0 -0
  84. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/core/processing/nodes/union_node.py +0 -0
  85. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/core/processing/nodes/unnest_node.py +0 -0
  86. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/core/processing/nodes/window_node.py +0 -0
  87. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/core/processing/utility.py +0 -0
  88. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/core/query_processor.py +0 -0
  89. {pytrilogy-0.0.2.50/trilogy/hooks → pytrilogy-0.0.2.51/trilogy/dialect}/__init__.py +0 -0
  90. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/dialect/base.py +0 -0
  91. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/dialect/bigquery.py +0 -0
  92. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/dialect/common.py +0 -0
  93. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/dialect/config.py +0 -0
  94. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/dialect/duckdb.py +0 -0
  95. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/dialect/enums.py +0 -0
  96. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/dialect/postgres.py +0 -0
  97. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/dialect/presto.py +0 -0
  98. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/dialect/snowflake.py +0 -0
  99. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/dialect/sql_server.py +0 -0
  100. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/engine.py +0 -0
  101. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/executor.py +0 -0
  102. {pytrilogy-0.0.2.50/trilogy/metadata → pytrilogy-0.0.2.51/trilogy/hooks}/__init__.py +0 -0
  103. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/hooks/base_hook.py +0 -0
  104. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/hooks/query_debugger.py +0 -0
  105. {pytrilogy-0.0.2.50/trilogy/parsing → pytrilogy-0.0.2.51/trilogy/metadata}/__init__.py +0 -0
  106. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/parser.py +0 -0
  107. {pytrilogy-0.0.2.50/trilogy/scripts → pytrilogy-0.0.2.51/trilogy/parsing}/__init__.py +0 -0
  108. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/parsing/config.py +0 -0
  109. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/parsing/exceptions.py +0 -0
  110. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/parsing/helpers.py +0 -0
  111. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/parsing/trilogy.lark +0 -0
  112. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/py.typed +0 -0
  113. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/scripts/trilogy.py +0 -0
  114. {pytrilogy-0.0.2.50 → pytrilogy-0.0.2.51}/trilogy/utility.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pytrilogy
3
- Version: 0.0.2.50
3
+ Version: 0.0.2.51
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.1
2
2
  Name: pytrilogy
3
- Version: 0.0.2.50
3
+ Version: 0.0.2.51
4
4
  Summary: Declarative, typed query language that compiles to SQL.
5
5
  Home-page:
6
6
  Author:
@@ -73,6 +73,8 @@ trilogy/core/processing/node_generators/select_node.py
73
73
  trilogy/core/processing/node_generators/union_node.py
74
74
  trilogy/core/processing/node_generators/unnest_node.py
75
75
  trilogy/core/processing/node_generators/window_node.py
76
+ trilogy/core/processing/node_generators/select_helpers/__init__.py
77
+ trilogy/core/processing/node_generators/select_helpers/datasource_injection.py
76
78
  trilogy/core/processing/nodes/__init__.py
77
79
  trilogy/core/processing/nodes/base_node.py
78
80
  trilogy/core/processing/nodes/filter_node.py
@@ -7,9 +7,9 @@ from trilogy.core.models import Environment
7
7
 
8
8
 
9
9
  def test_environment_serialization(test_environment: Environment):
10
- str(test_environment)
11
- path = test_environment.to_cache()
12
10
 
11
+ path = test_environment.to_cache()
12
+ print(path)
13
13
  test_environment2 = Environment.from_cache(path)
14
14
  assert test_environment2
15
15
 
@@ -1,8 +1,10 @@
1
1
  # from trilogy.compiler import compile
2
+ from datetime import date, datetime
2
3
  from logging import INFO
3
4
 
4
5
  from pytest import raises
5
6
 
7
+ from trilogy import Dialects
6
8
  from trilogy.constants import logger
7
9
  from trilogy.core.enums import Purpose, PurposeLineage
8
10
  from trilogy.core.exceptions import InvalidSyntaxException
@@ -14,8 +16,6 @@ from trilogy.dialect.duckdb import DuckDBDialect
14
16
  from trilogy.dialect.snowflake import SnowflakeDialect
15
17
  from trilogy.dialect.sql_server import SqlServerDialect
16
18
  from trilogy.parser import parse
17
- from trilogy import Dialects
18
- from datetime import date, datetime
19
19
 
20
20
  logger.setLevel(INFO)
21
21
 
@@ -181,7 +181,7 @@ select
181
181
  assert z[0].one_datetime == datetime(
182
182
  year=2024, month=1, day=1, hour=1, minute=1, second=1
183
183
  )
184
- assert z[0].one_bool == True
184
+ assert z[0].one_bool
185
185
  for dialect in TEST_DIALECTS:
186
186
  dialect.compile_statement(process_query(test_environment, select))
187
187
 
@@ -242,6 +242,7 @@ def test_case_function(test_environment):
242
242
  test_upper_case
243
243
  ;"""
244
244
  env, parsed = parse(declarations, environment=test_environment)
245
+
245
246
  assert (
246
247
  test_environment.concepts["category_name"]
247
248
  in test_environment.concepts["test_upper_case"].lineage.concept_arguments
@@ -68,7 +68,7 @@ def test_cte_merge(test_environment, test_environment_graph):
68
68
 
69
69
 
70
70
  def test_concept(test_environment, test_environment_graph):
71
- test_concept = list(test_environment.concepts.values())[0]
71
+ test_concept: Concept = list(test_environment.concepts.values())[0]
72
72
  new = test_concept.with_namespace("test")
73
73
  assert (
74
74
  new.namespace == ("test" + "." + test_concept.namespace)
@@ -129,7 +129,7 @@ def test_grain(test_environment):
129
129
  x = Grain(components=[oid, pid])
130
130
  y = Grain(components=[pid, cid])
131
131
  z = Grain(components=[cid])
132
- z2 = Grain(components=[cid, cname])
132
+ z2 = Grain.from_concepts([cid, cname], environment=test_environment)
133
133
 
134
134
  assert x.intersection(y) == Grain(components=[pid])
135
135
  assert x.union(y) == Grain(components=[oid, pid, cid])
@@ -137,7 +137,9 @@ def test_grain(test_environment):
137
137
  assert z.isdisjoint(x)
138
138
  assert z.issubset(y)
139
139
 
140
- assert z2 == z, f"Property should be removed from grain ({z.set}) vs {z2.set}"
140
+ assert (
141
+ z2 == z
142
+ ), f"Property should be removed from grain ({z.components}) vs {z2.components}"
141
143
 
142
144
 
143
145
  def test_select(test_environment: Environment):
@@ -1,4 +1,10 @@
1
- from trilogy.core.models import Environment, Grain, QueryDatasource, SelectStatement
1
+ from trilogy.core.models import (
2
+ Environment,
3
+ Grain,
4
+ QueryDatasource,
5
+ SelectStatement,
6
+ SourceType,
7
+ )
2
8
  from trilogy.core.processing.concept_strategies_v3 import search_concepts
3
9
  from trilogy.core.query_processor import get_query_datasources, process_query
4
10
 
@@ -7,7 +13,7 @@ def test_direct_select(test_environment, test_environment_graph):
7
13
  product = test_environment.concepts["product_id"]
8
14
  # concept, grain: Grain, environment: Environment, g: ReferenceGraph, query_graph: ReferenceGraph
9
15
  datasource = search_concepts(
10
- [product] + product.grain.components_copy,
16
+ [product] + [test_environment.concepts[c] for c in product.grain.components],
11
17
  environment=test_environment,
12
18
  g=test_environment_graph,
13
19
  depth=0,
@@ -27,7 +33,8 @@ def test_get_datasource_from_window_function(
27
33
  # concept, grain: Grain, environment: Environment, g: ReferenceGraph, query_graph: ReferenceGraph
28
34
  # assert product_rank.grain.components[0] == test_environment.concepts['name']
29
35
  node = search_concepts(
30
- [product_rank] + product_rank.grain.components_copy,
36
+ [product_rank]
37
+ + [test_environment.concepts[c] for c in product_rank.grain.components],
31
38
  environment=test_environment,
32
39
  g=test_environment_graph,
33
40
  depth=0,
@@ -38,14 +45,18 @@ def test_get_datasource_from_window_function(
38
45
  assert product_rank in datasource.output_concepts
39
46
  # assert datasource.grain == product_rank.grain
40
47
  assert isinstance(datasource, QueryDatasource)
41
- assert datasource.grain.set == product_rank.grain.set
48
+ assert datasource.grain.components == product_rank.grain.components
42
49
 
43
50
  product_rank_by_category = test_environment.concepts[
44
51
  "product_revenue_rank_by_category"
45
52
  ]
46
53
  # concept, grain: Grain, environment: Environment, g: ReferenceGraph, query_graph: ReferenceGraph
47
54
  datasource = search_concepts(
48
- [product_rank_by_category] + product_rank_by_category.grain.components_copy,
55
+ [product_rank_by_category]
56
+ + [
57
+ test_environment.concepts[c]
58
+ for c in product_rank_by_category.grain.components
59
+ ],
49
60
  environment=test_environment,
50
61
  g=test_environment_graph,
51
62
  depth=0,
@@ -68,7 +79,8 @@ def test_get_datasource_for_filter(
68
79
  "product_id",
69
80
  }
70
81
  datasource = search_concepts(
71
- [hi_rev_product] + hi_rev_product.grain.components_copy,
82
+ [hi_rev_product]
83
+ + [test_environment.concepts[c] for c in hi_rev_product.grain.components],
72
84
  environment=test_environment,
73
85
  g=test_environment_graph,
74
86
  depth=0,
@@ -86,7 +98,7 @@ def test_select_output(test_environment, test_environment_graph):
86
98
  # concept, grain: Grain, environment: Environment, g: ReferenceGraph, query_graph: ReferenceGraph
87
99
 
88
100
  datasource = search_concepts(
89
- [product] + product.grain.components_copy,
101
+ [product] + [test_environment.concepts[c] for c in product.grain.components],
90
102
  environment=test_environment,
91
103
  g=test_environment_graph,
92
104
  depth=0,
@@ -114,18 +126,25 @@ def test_basic_aggregate(test_environment: Environment, test_environment_graph):
114
126
 
115
127
 
116
128
  def test_join_aggregate(test_environment: Environment, test_environment_graph):
129
+ from trilogy.hooks.query_debugger import DebuggingHook
130
+
131
+ DebuggingHook()
117
132
  category_id = test_environment.concepts["category_id"]
118
133
  total_revenue = test_environment.concepts["total_revenue"]
119
134
  # concept, grain: Grain, environment: Environment, g: ReferenceGraph, query_graph: ReferenceGraph
120
135
  datasource = search_concepts(
121
- [total_revenue.with_grain(category_id), category_id],
136
+ [
137
+ total_revenue.with_grain(Grain(components={"local.category_id"})),
138
+ category_id,
139
+ ],
122
140
  environment=test_environment,
123
141
  g=test_environment_graph,
124
142
  depth=0,
125
143
  ).resolve()
126
144
  assert isinstance(datasource, QueryDatasource)
145
+ assert datasource.source_type == SourceType.GROUP
127
146
  assert len(set([datasource.name for datasource in datasource.datasources])) == 1
128
- assert datasource.grain.components == [category_id]
147
+ assert datasource.grain.components == {"local.category_id"}
129
148
 
130
149
 
131
150
  def test_query_aggregation(test_environment, test_environment_graph):
@@ -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.2.50"
7
+ __version__ = "0.0.2.51"
8
8
 
9
9
  __all__ = ["parse", "Executor", "Dialects", "Environment", "CONFIG"]
@@ -1,6 +1,6 @@
1
1
  from trilogy.core.constants import ALL_ROWS_CONCEPT, INTERNAL_NAMESPACE
2
2
  from trilogy.core.enums import FunctionType, Purpose
3
- from trilogy.core.models import Concept, DataType, Function
3
+ from trilogy.core.models import Concept, DataType, Function, Grain
4
4
 
5
5
  DEFAULT_CONCEPTS = {
6
6
  ALL_ROWS_CONCEPT: Concept(
@@ -8,6 +8,7 @@ DEFAULT_CONCEPTS = {
8
8
  namespace=INTERNAL_NAMESPACE,
9
9
  datatype=DataType.INTEGER,
10
10
  purpose=Purpose.CONSTANT,
11
+ grain=Grain(),
11
12
  lineage=Function(
12
13
  operator=FunctionType.CONSTANT,
13
14
  arguments=[1],
@@ -20,17 +21,20 @@ DEFAULT_CONCEPTS = {
20
21
  namespace=INTERNAL_NAMESPACE,
21
22
  datatype=DataType.STRING,
22
23
  purpose=Purpose.KEY,
24
+ grain=Grain(),
23
25
  ),
24
26
  "datasource": Concept(
25
27
  name="datasource",
26
28
  namespace=INTERNAL_NAMESPACE,
27
29
  datatype=DataType.STRING,
28
30
  purpose=Purpose.KEY,
31
+ grain=Grain(),
29
32
  ),
30
33
  "query_text": Concept(
31
34
  name="query_text",
32
35
  namespace=INTERNAL_NAMESPACE,
33
36
  datatype=DataType.STRING,
34
37
  purpose=Purpose.KEY,
38
+ grain=Grain(),
35
39
  ),
36
40
  }