pytrilogy 0.0.3.71__tar.gz → 0.0.3.72__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 (150) hide show
  1. {pytrilogy-0.0.3.71/pytrilogy.egg-info → pytrilogy-0.0.3.72}/PKG-INFO +1 -1
  2. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72/pytrilogy.egg-info}/PKG-INFO +1 -1
  3. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/__init__.py +1 -1
  4. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/enums.py +1 -0
  5. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/functions.py +5 -0
  6. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/models/build.py +35 -19
  7. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/processing/node_generators/window_node.py +2 -1
  8. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/dialect/base.py +1 -0
  9. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/parsing/common.py +10 -16
  10. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/parsing/parse_engine.py +9 -0
  11. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/std/net.preql +2 -1
  12. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/LICENSE.md +0 -0
  13. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/README.md +0 -0
  14. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/pyproject.toml +0 -0
  15. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/pytrilogy.egg-info/SOURCES.txt +0 -0
  16. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/pytrilogy.egg-info/dependency_links.txt +0 -0
  17. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/pytrilogy.egg-info/entry_points.txt +0 -0
  18. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/pytrilogy.egg-info/requires.txt +0 -0
  19. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/pytrilogy.egg-info/top_level.txt +0 -0
  20. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/setup.cfg +0 -0
  21. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/setup.py +0 -0
  22. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/tests/test_datatypes.py +0 -0
  23. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/tests/test_declarations.py +0 -0
  24. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/tests/test_derived_concepts.py +0 -0
  25. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/tests/test_discovery_nodes.py +0 -0
  26. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/tests/test_enums.py +0 -0
  27. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/tests/test_environment.py +0 -0
  28. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/tests/test_execute_models.py +0 -0
  29. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/tests/test_executor.py +0 -0
  30. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/tests/test_failure.py +0 -0
  31. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/tests/test_functions.py +0 -0
  32. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/tests/test_imports.py +0 -0
  33. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/tests/test_metadata.py +0 -0
  34. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/tests/test_models.py +0 -0
  35. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/tests/test_multi_join_assignments.py +0 -0
  36. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/tests/test_parse_engine.py +0 -0
  37. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/tests/test_parsing.py +0 -0
  38. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/tests/test_parsing_failures.py +0 -0
  39. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/tests/test_partial_handling.py +0 -0
  40. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/tests/test_query_processing.py +0 -0
  41. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/tests/test_query_render.py +0 -0
  42. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/tests/test_select.py +0 -0
  43. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/tests/test_show.py +0 -0
  44. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/tests/test_statements.py +0 -0
  45. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/tests/test_typing.py +0 -0
  46. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/tests/test_undefined_concept.py +0 -0
  47. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/tests/test_user_functions.py +0 -0
  48. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/tests/test_where_clause.py +0 -0
  49. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/authoring/__init__.py +0 -0
  50. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/compiler.py +0 -0
  51. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/constants.py +0 -0
  52. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/__init__.py +0 -0
  53. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/constants.py +0 -0
  54. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/env_processor.py +0 -0
  55. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/environment_helpers.py +0 -0
  56. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/ergonomics.py +0 -0
  57. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/exceptions.py +0 -0
  58. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/graph_models.py +0 -0
  59. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/internal.py +0 -0
  60. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/models/__init__.py +0 -0
  61. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/models/author.py +0 -0
  62. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/models/build_environment.py +0 -0
  63. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/models/core.py +0 -0
  64. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/models/datasource.py +0 -0
  65. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/models/environment.py +0 -0
  66. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/models/execute.py +0 -0
  67. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/optimization.py +0 -0
  68. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/optimizations/__init__.py +0 -0
  69. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/optimizations/base_optimization.py +0 -0
  70. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/optimizations/inline_datasource.py +0 -0
  71. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/optimizations/predicate_pushdown.py +0 -0
  72. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/processing/__init__.py +0 -0
  73. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/processing/concept_strategies_v3.py +0 -0
  74. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/processing/discovery_loop.py +0 -0
  75. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/processing/discovery_node_factory.py +0 -0
  76. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/processing/discovery_utility.py +0 -0
  77. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/processing/discovery_validation.py +0 -0
  78. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/processing/graph_utils.py +0 -0
  79. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/processing/node_generators/__init__.py +0 -0
  80. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/processing/node_generators/basic_node.py +0 -0
  81. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/processing/node_generators/common.py +0 -0
  82. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/processing/node_generators/filter_node.py +0 -0
  83. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/processing/node_generators/group_node.py +0 -0
  84. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/processing/node_generators/group_to_node.py +0 -0
  85. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/processing/node_generators/multiselect_node.py +0 -0
  86. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/processing/node_generators/node_merge_node.py +0 -0
  87. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/processing/node_generators/recursive_node.py +0 -0
  88. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/processing/node_generators/rowset_node.py +0 -0
  89. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/processing/node_generators/select_helpers/__init__.py +0 -0
  90. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/processing/node_generators/select_helpers/datasource_injection.py +0 -0
  91. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/processing/node_generators/select_merge_node.py +0 -0
  92. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/processing/node_generators/select_node.py +0 -0
  93. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/processing/node_generators/synonym_node.py +0 -0
  94. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/processing/node_generators/union_node.py +0 -0
  95. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/processing/node_generators/unnest_node.py +0 -0
  96. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/processing/nodes/__init__.py +0 -0
  97. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/processing/nodes/base_node.py +0 -0
  98. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/processing/nodes/filter_node.py +0 -0
  99. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/processing/nodes/group_node.py +0 -0
  100. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/processing/nodes/merge_node.py +0 -0
  101. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/processing/nodes/recursive_node.py +0 -0
  102. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/processing/nodes/select_node_v2.py +0 -0
  103. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/processing/nodes/union_node.py +0 -0
  104. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/processing/nodes/unnest_node.py +0 -0
  105. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/processing/nodes/window_node.py +0 -0
  106. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/processing/utility.py +0 -0
  107. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/query_processor.py +0 -0
  108. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/statements/__init__.py +0 -0
  109. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/statements/author.py +0 -0
  110. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/statements/build.py +0 -0
  111. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/statements/common.py +0 -0
  112. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/statements/execute.py +0 -0
  113. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/core/utility.py +0 -0
  114. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/dialect/__init__.py +0 -0
  115. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/dialect/bigquery.py +0 -0
  116. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/dialect/common.py +0 -0
  117. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/dialect/config.py +0 -0
  118. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/dialect/dataframe.py +0 -0
  119. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/dialect/duckdb.py +0 -0
  120. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/dialect/enums.py +0 -0
  121. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/dialect/postgres.py +0 -0
  122. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/dialect/presto.py +0 -0
  123. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/dialect/snowflake.py +0 -0
  124. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/dialect/sql_server.py +0 -0
  125. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/engine.py +0 -0
  126. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/executor.py +0 -0
  127. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/hooks/__init__.py +0 -0
  128. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/hooks/base_hook.py +0 -0
  129. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/hooks/graph_hook.py +0 -0
  130. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/hooks/query_debugger.py +0 -0
  131. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/metadata/__init__.py +0 -0
  132. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/parser.py +0 -0
  133. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/parsing/__init__.py +0 -0
  134. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/parsing/config.py +0 -0
  135. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/parsing/exceptions.py +0 -0
  136. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/parsing/helpers.py +0 -0
  137. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/parsing/render.py +0 -0
  138. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/parsing/trilogy.lark +0 -0
  139. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/py.typed +0 -0
  140. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/render.py +0 -0
  141. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/scripts/__init__.py +0 -0
  142. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/scripts/trilogy.py +0 -0
  143. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/std/__init__.py +0 -0
  144. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/std/date.preql +0 -0
  145. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/std/display.preql +0 -0
  146. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/std/geography.preql +0 -0
  147. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/std/money.preql +0 -0
  148. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/std/ranking.preql +0 -0
  149. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/std/report.preql +0 -0
  150. {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.72}/trilogy/utility.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pytrilogy
3
- Version: 0.0.3.71
3
+ Version: 0.0.3.72
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.71
3
+ Version: 0.0.3.72
4
4
  Summary: Declarative, typed query language that compiles to SQL.
5
5
  Home-page:
6
6
  Author:
@@ -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.71"
7
+ __version__ = "0.0.3.72"
8
8
 
9
9
  __all__ = ["parse", "Executor", "Dialects", "Environment", "CONFIG"]
@@ -134,6 +134,7 @@ class FunctionType(Enum):
134
134
  CAST = "cast"
135
135
  CONCAT = "concat"
136
136
  CONSTANT = "constant"
137
+ TYPED_CONSTANT = "typed_constant"
137
138
  COALESCE = "coalesce"
138
139
  IS_NULL = "isnull"
139
140
  NULLIF = "nullif"
@@ -704,6 +704,11 @@ FUNCTION_REGISTRY: dict[FunctionType, FunctionConfig] = {
704
704
  output_purpose=Purpose.CONSTANT,
705
705
  arg_count=1,
706
706
  ),
707
+ FunctionType.TYPED_CONSTANT: FunctionConfig(
708
+ output_purpose=Purpose.CONSTANT,
709
+ output_type_function=get_cast_output_type,
710
+ arg_count=2,
711
+ ),
707
712
  FunctionType.IS_NULL: FunctionConfig(
708
713
  output_purpose=Purpose.PROPERTY,
709
714
  output_type=DataType.BOOL,
@@ -1486,6 +1486,17 @@ def get_canonical_pseudonyms(environment: Environment) -> dict[str, set[str]]:
1486
1486
  return roots
1487
1487
 
1488
1488
 
1489
+ def requires_concept_nesting(
1490
+ expr,
1491
+ ) -> AggregateWrapper | WindowItem | FilterItem | Function | None:
1492
+ if isinstance(expr, (AggregateWrapper, WindowItem, FilterItem)):
1493
+ return expr
1494
+ if isinstance(expr, Function) and expr.operator == FunctionType.GROUP:
1495
+ # group by requires nesting
1496
+ return expr
1497
+ return None
1498
+
1499
+
1489
1500
  class Factory:
1490
1501
 
1491
1502
  def __init__(
@@ -1509,11 +1520,12 @@ class Factory:
1509
1520
  | WindowItem
1510
1521
  | FilterItem
1511
1522
  | Function
1512
- | ListWrapper[Any]
1513
- | MapWrapper[Any, Any]
1523
+ | ListWrapper
1524
+ | MapWrapper
1514
1525
  | int
1515
1526
  | float
1516
1527
  | str
1528
+ | date
1517
1529
  ),
1518
1530
  ) -> tuple[Concept, BuildConcept]:
1519
1531
  from trilogy.parsing.common import arbitrary_to_concept
@@ -1572,7 +1584,8 @@ class Factory:
1572
1584
 
1573
1585
  raw_args: list[Concept | FuncArgs] = []
1574
1586
  for arg in base.arguments:
1575
- # to do proper discovery, we need to inject virtual intermediate ocncepts
1587
+ # to do proper discovery, we need to inject virtual intermediate concepts
1588
+ # we don't use requires_concept_nesting here by design
1576
1589
  if isinstance(arg, (AggregateWrapper, FilterItem, WindowItem)):
1577
1590
  narg, _ = self.instantiate_concept(arg)
1578
1591
  raw_args.append(narg)
@@ -1640,11 +1653,10 @@ class Factory:
1640
1653
  def _(self, base: CaseWhen) -> BuildCaseWhen:
1641
1654
 
1642
1655
  comparison = base.comparison
1643
- if isinstance(comparison, (AggregateWrapper, FilterItem, WindowItem)):
1644
- comparison, _ = self.instantiate_concept(comparison)
1645
1656
  expr: Concept | FuncArgs = base.expr
1646
- if isinstance(expr, (AggregateWrapper, FilterItem, WindowItem)):
1647
- expr, _ = self.instantiate_concept(expr)
1657
+ validation = requires_concept_nesting(expr)
1658
+ if validation:
1659
+ expr, _ = self.instantiate_concept(validation)
1648
1660
  return BuildCaseWhen.model_construct(
1649
1661
  comparison=self.build(comparison),
1650
1662
  expr=self.build(expr),
@@ -1653,8 +1665,9 @@ class Factory:
1653
1665
  @build.register
1654
1666
  def _(self, base: CaseElse) -> BuildCaseElse:
1655
1667
  expr: Concept | FuncArgs = base.expr
1656
- if isinstance(expr, (AggregateWrapper, FilterItem, WindowItem)):
1657
- expr, _ = self.instantiate_concept(expr)
1668
+ validation = requires_concept_nesting(expr)
1669
+ if validation:
1670
+ expr, _ = self.instantiate_concept(validation)
1658
1671
  return BuildCaseElse.model_construct(expr=self.build(expr))
1659
1672
 
1660
1673
  @build.register
@@ -1753,10 +1766,9 @@ class Factory:
1753
1766
  def _(self, base: OrderItem) -> BuildOrderItem:
1754
1767
 
1755
1768
  bexpr: Any
1756
- if isinstance(base.expr, (AggregateWrapper, WindowItem, FilterItem)) or (
1757
- isinstance(base.expr, Function) and base.expr.operator == FunctionType.GROUP
1758
- ):
1759
- bexpr, _ = self.instantiate_concept(base.expr)
1769
+ validation = requires_concept_nesting(base.expr)
1770
+ if validation:
1771
+ bexpr, _ = self.instantiate_concept(validation)
1760
1772
  else:
1761
1773
  bexpr = base.expr
1762
1774
  return BuildOrderItem.model_construct(
@@ -1781,8 +1793,9 @@ class Factory:
1781
1793
  def _(self, base: WindowItem) -> BuildWindowItem:
1782
1794
 
1783
1795
  content: Concept | FuncArgs = base.content
1784
- if isinstance(content, (AggregateWrapper, FilterItem, WindowItem)):
1785
- content, _ = self.instantiate_concept(content)
1796
+ validation = requires_concept_nesting(base.content)
1797
+ if validation:
1798
+ content, _ = self.instantiate_concept(validation)
1786
1799
  final_by = []
1787
1800
  for x in base.order_by:
1788
1801
  if (
@@ -1811,6 +1824,7 @@ class Factory:
1811
1824
  @build.register
1812
1825
  def _(self, base: SubselectComparison) -> BuildSubselectComparison:
1813
1826
  right: Any = base.right
1827
+ # this has specialized logic - include all Functions
1814
1828
  if isinstance(base.right, (AggregateWrapper, WindowItem, FilterItem, Function)):
1815
1829
  right_c, _ = self.instantiate_concept(base.right)
1816
1830
  right = right_c
@@ -1824,12 +1838,14 @@ class Factory:
1824
1838
  def _(self, base: Comparison) -> BuildComparison:
1825
1839
 
1826
1840
  left = base.left
1827
- if isinstance(left, (AggregateWrapper, WindowItem, FilterItem)):
1828
- left_c, _ = self.instantiate_concept(left)
1841
+ validation = requires_concept_nesting(base.left)
1842
+ if validation:
1843
+ left_c, _ = self.instantiate_concept(validation)
1829
1844
  left = left_c # type: ignore
1830
1845
  right = base.right
1831
- if isinstance(right, (AggregateWrapper, WindowItem, FilterItem)):
1832
- right_c, _ = self.instantiate_concept(right)
1846
+ validation = requires_concept_nesting(base.right)
1847
+ if validation:
1848
+ right_c, _ = self.instantiate_concept(validation)
1833
1849
  right = right_c # type: ignore
1834
1850
  return BuildComparison.model_construct(
1835
1851
  left=self.handle_constant(self.build(left)),
@@ -39,6 +39,7 @@ def resolve_window_parent_concepts(
39
39
  base += item.concept_arguments
40
40
  if concept.grain:
41
41
  for gitem in concept.grain.components:
42
+ logger.info(f"{LOGGER_PREFIX} appending grain item {gitem} to base")
42
43
  base.append(environment.concepts[gitem])
43
44
  return concept.lineage.content, unique(base, "address")
44
45
 
@@ -55,7 +56,7 @@ def gen_window_node(
55
56
  ) -> StrategyNode | None:
56
57
  base, parent_concepts = resolve_window_parent_concepts(concept, environment)
57
58
  logger.info(
58
- f"{padding(depth)}{LOGGER_PREFIX} generating window node for {concept} with parents {parent_concepts} and optional {local_optional}"
59
+ f"{padding(depth)}{LOGGER_PREFIX} generating window node for {concept} with parents {[x.address for x in parent_concepts]} and optional {local_optional}"
59
60
  )
60
61
  equivalent_optional = [
61
62
  x
@@ -163,6 +163,7 @@ FUNCTION_MAP = {
163
163
  FunctionType.ALIAS: lambda x: f"{x[0]}",
164
164
  FunctionType.GROUP: lambda x: f"{x[0]}",
165
165
  FunctionType.CONSTANT: lambda x: f"{x[0]}",
166
+ FunctionType.TYPED_CONSTANT: lambda x: f"{x[0]}",
166
167
  FunctionType.COALESCE: lambda x: f"coalesce({','.join(x)})",
167
168
  FunctionType.NULLIF: lambda x: f"nullif({x[0]},{x[1]})",
168
169
  FunctionType.CAST: lambda x: f"cast({x[0]} as {x[1]})",
@@ -173,7 +173,9 @@ def concept_list_to_keys(
173
173
 
174
174
 
175
175
  def constant_to_concept(
176
- parent: ListWrapper | TupleWrapper | MapWrapper | int | float | str,
176
+ parent: (
177
+ ListWrapper | TupleWrapper | MapWrapper | int | float | str | date | datetime
178
+ ),
177
179
  name: str,
178
180
  namespace: str,
179
181
  metadata: Metadata | None = None,
@@ -368,9 +370,9 @@ def _get_relevant_parent_concepts(arg) -> tuple[list[ConceptRef], bool]:
368
370
  return get_concept_arguments(arg), False
369
371
 
370
372
 
371
- def get_relevant_parent_concepts(arg):
372
- results = _get_relevant_parent_concepts(arg)
373
- return results
373
+ def get_relevant_parent_concepts(arg) -> tuple[list[ConceptRef], bool]:
374
+ concepts, status = _get_relevant_parent_concepts(arg)
375
+ return unique(concepts, "address"), status
374
376
 
375
377
 
376
378
  def group_function_to_concept(
@@ -626,20 +628,11 @@ def window_item_to_concept(
626
628
 
627
629
  # when including the order by in discovery grain
628
630
  if parent.order_by:
631
+
629
632
  grain_components = parent.over + [bcontent.output]
630
633
  for item in parent.order_by:
631
- # confirm that it's not just an aggregate at the grain of the stuff we're already keying of of
632
- # in which case we can ignore contributions
633
- if (
634
- isinstance(item.expr, AggregateWrapper)
635
- and set([x.address for x in item.expr.by]) == keys
636
- ):
637
- continue
638
- elif isinstance(item.expr, AggregateWrapper):
639
-
640
- grain_components += item.expr.by
641
- else:
642
- grain_components += item.concept_arguments
634
+ relevant, _ = get_relevant_parent_concepts(item.expr)
635
+ grain_components += relevant
643
636
  else:
644
637
  grain_components = parent.over + [bcontent.output]
645
638
 
@@ -842,6 +835,7 @@ def arbitrary_to_concept(
842
835
  | int
843
836
  | float
844
837
  | str
838
+ | date
845
839
  ),
846
840
  environment: Environment,
847
841
  namespace: str | None = None,
@@ -640,6 +640,7 @@ class ParseToObjects(Transformer):
640
640
 
641
641
  @v_args(meta=True)
642
642
  def concept_derivation(self, meta: Meta, args) -> ConceptDerivationStatement:
643
+
643
644
  if len(args) > 3:
644
645
  metadata = args[3]
645
646
  else:
@@ -733,6 +734,7 @@ class ParseToObjects(Transformer):
733
734
 
734
735
  @v_args(meta=True)
735
736
  def constant_derivation(self, meta: Meta, args) -> Concept:
737
+
736
738
  if len(args) > 3:
737
739
  metadata = args[3]
738
740
  else:
@@ -1405,6 +1407,7 @@ class ParseToObjects(Transformer):
1405
1407
  def string_lit(self, args) -> str:
1406
1408
  if not args:
1407
1409
  return ""
1410
+
1408
1411
  return args[0]
1409
1412
 
1410
1413
  @v_args(meta=True)
@@ -1890,7 +1893,9 @@ class ParseToObjects(Transformer):
1890
1893
 
1891
1894
  def internal_fcast(self, meta, args) -> Function:
1892
1895
  args = process_function_args(args, meta=meta, environment=self.environment)
1896
+
1893
1897
  if isinstance(args[0], str):
1898
+
1894
1899
  processed: date | datetime | int | float | bool | str
1895
1900
  if args[1] == DataType.DATE:
1896
1901
  processed = date.fromisoformat(args[0])
@@ -1908,6 +1913,10 @@ class ParseToObjects(Transformer):
1908
1913
  processed = args[0]
1909
1914
  else:
1910
1915
  raise SyntaxError(f"Invalid cast type {args[1]}")
1916
+ if isinstance(args[1], TraitDataType):
1917
+ return self.function_factory.create_function(
1918
+ [processed, args[1]], FunctionType.TYPED_CONSTANT, meta
1919
+ )
1911
1920
  return self.function_factory.create_function(
1912
1921
  [processed], FunctionType.CONSTANT, meta
1913
1922
  )
@@ -5,4 +5,5 @@ type domain string;
5
5
  type ip_net_mask string;
6
6
  type ipv6_address string;
7
7
  type ipv4_address string;
8
- type suffix string;
8
+ type suffix string;
9
+ type url_image string;
File without changes
File without changes
File without changes
File without changes