pytrilogy 0.0.3.106__tar.gz → 0.0.3.108__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 (161) hide show
  1. {pytrilogy-0.0.3.106/pytrilogy.egg-info → pytrilogy-0.0.3.108}/PKG-INFO +1 -1
  2. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108/pytrilogy.egg-info}/PKG-INFO +1 -1
  3. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/__init__.py +1 -1
  4. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/processing/concept_strategies_v3.py +12 -13
  5. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/processing/discovery_utility.py +22 -3
  6. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/processing/node_generators/group_node.py +1 -0
  7. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/processing/node_generators/select_merge_node.py +9 -4
  8. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/processing/node_generators/window_node.py +7 -5
  9. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/processing/nodes/group_node.py +7 -0
  10. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/parsing/render.py +16 -1
  11. pytrilogy-0.0.3.108/trilogy/std/display.preql +18 -0
  12. pytrilogy-0.0.3.106/trilogy/std/display.preql +0 -9
  13. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/LICENSE.md +0 -0
  14. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/README.md +0 -0
  15. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/pyproject.toml +0 -0
  16. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/pytrilogy.egg-info/SOURCES.txt +0 -0
  17. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/pytrilogy.egg-info/dependency_links.txt +0 -0
  18. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/pytrilogy.egg-info/entry_points.txt +0 -0
  19. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/pytrilogy.egg-info/requires.txt +0 -0
  20. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/pytrilogy.egg-info/top_level.txt +0 -0
  21. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/setup.cfg +0 -0
  22. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/setup.py +0 -0
  23. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/tests/test_datatypes.py +0 -0
  24. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/tests/test_declarations.py +0 -0
  25. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/tests/test_derived_concepts.py +0 -0
  26. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/tests/test_discovery_nodes.py +0 -0
  27. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/tests/test_enums.py +0 -0
  28. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/tests/test_environment.py +0 -0
  29. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/tests/test_execute_models.py +0 -0
  30. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/tests/test_executor.py +0 -0
  31. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/tests/test_failure.py +0 -0
  32. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/tests/test_functions.py +0 -0
  33. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/tests/test_imports.py +0 -0
  34. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/tests/test_metadata.py +0 -0
  35. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/tests/test_models.py +0 -0
  36. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/tests/test_multi_join_assignments.py +0 -0
  37. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/tests/test_parse_engine.py +0 -0
  38. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/tests/test_parsing.py +0 -0
  39. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/tests/test_parsing_failures.py +0 -0
  40. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/tests/test_partial_handling.py +0 -0
  41. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/tests/test_query_processing.py +0 -0
  42. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/tests/test_query_render.py +0 -0
  43. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/tests/test_select.py +0 -0
  44. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/tests/test_show.py +0 -0
  45. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/tests/test_statements.py +0 -0
  46. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/tests/test_typing.py +0 -0
  47. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/tests/test_undefined_concept.py +0 -0
  48. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/tests/test_user_functions.py +0 -0
  49. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/tests/test_validators.py +0 -0
  50. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/tests/test_where_clause.py +0 -0
  51. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/authoring/__init__.py +0 -0
  52. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/constants.py +0 -0
  53. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/__init__.py +0 -0
  54. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/constants.py +0 -0
  55. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/enums.py +0 -0
  56. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/env_processor.py +0 -0
  57. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/environment_helpers.py +0 -0
  58. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/ergonomics.py +0 -0
  59. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/exceptions.py +0 -0
  60. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/functions.py +0 -0
  61. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/graph_models.py +0 -0
  62. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/internal.py +0 -0
  63. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/models/__init__.py +0 -0
  64. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/models/author.py +0 -0
  65. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/models/build.py +0 -0
  66. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/models/build_environment.py +0 -0
  67. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/models/core.py +0 -0
  68. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/models/datasource.py +0 -0
  69. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/models/environment.py +0 -0
  70. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/models/execute.py +0 -0
  71. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/optimization.py +0 -0
  72. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/optimizations/__init__.py +0 -0
  73. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/optimizations/base_optimization.py +0 -0
  74. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/optimizations/hide_unused_concept.py +0 -0
  75. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/optimizations/inline_datasource.py +0 -0
  76. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/optimizations/predicate_pushdown.py +0 -0
  77. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/processing/__init__.py +0 -0
  78. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/processing/discovery_node_factory.py +0 -0
  79. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/processing/discovery_validation.py +0 -0
  80. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/processing/graph_utils.py +0 -0
  81. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/processing/node_generators/__init__.py +0 -0
  82. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/processing/node_generators/basic_node.py +0 -0
  83. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/processing/node_generators/common.py +0 -0
  84. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/processing/node_generators/constant_node.py +0 -0
  85. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/processing/node_generators/filter_node.py +0 -0
  86. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/processing/node_generators/group_to_node.py +0 -0
  87. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/processing/node_generators/multiselect_node.py +0 -0
  88. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/processing/node_generators/node_merge_node.py +0 -0
  89. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/processing/node_generators/recursive_node.py +0 -0
  90. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/processing/node_generators/rowset_node.py +0 -0
  91. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/processing/node_generators/select_helpers/__init__.py +0 -0
  92. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/processing/node_generators/select_helpers/datasource_injection.py +0 -0
  93. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/processing/node_generators/select_node.py +0 -0
  94. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/processing/node_generators/synonym_node.py +0 -0
  95. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/processing/node_generators/union_node.py +0 -0
  96. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/processing/node_generators/unnest_node.py +0 -0
  97. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/processing/nodes/__init__.py +0 -0
  98. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/processing/nodes/base_node.py +0 -0
  99. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/processing/nodes/filter_node.py +0 -0
  100. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/processing/nodes/merge_node.py +0 -0
  101. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/processing/nodes/recursive_node.py +0 -0
  102. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/processing/nodes/select_node_v2.py +0 -0
  103. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/processing/nodes/union_node.py +0 -0
  104. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/processing/nodes/unnest_node.py +0 -0
  105. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/processing/nodes/window_node.py +0 -0
  106. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/processing/utility.py +0 -0
  107. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/query_processor.py +0 -0
  108. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/statements/__init__.py +0 -0
  109. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/statements/author.py +0 -0
  110. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/statements/build.py +0 -0
  111. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/statements/common.py +0 -0
  112. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/statements/execute.py +0 -0
  113. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/utility.py +0 -0
  114. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/validation/__init__.py +0 -0
  115. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/validation/common.py +0 -0
  116. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/validation/concept.py +0 -0
  117. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/validation/datasource.py +0 -0
  118. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/validation/environment.py +0 -0
  119. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/core/validation/fix.py +0 -0
  120. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/dialect/__init__.py +0 -0
  121. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/dialect/base.py +0 -0
  122. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/dialect/bigquery.py +0 -0
  123. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/dialect/common.py +0 -0
  124. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/dialect/config.py +0 -0
  125. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/dialect/dataframe.py +0 -0
  126. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/dialect/duckdb.py +0 -0
  127. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/dialect/enums.py +0 -0
  128. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/dialect/metadata.py +0 -0
  129. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/dialect/postgres.py +0 -0
  130. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/dialect/presto.py +0 -0
  131. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/dialect/snowflake.py +0 -0
  132. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/dialect/sql_server.py +0 -0
  133. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/engine.py +0 -0
  134. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/executor.py +0 -0
  135. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/hooks/__init__.py +0 -0
  136. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/hooks/base_hook.py +0 -0
  137. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/hooks/graph_hook.py +0 -0
  138. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/hooks/query_debugger.py +0 -0
  139. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/metadata/__init__.py +0 -0
  140. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/parser.py +0 -0
  141. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/parsing/__init__.py +0 -0
  142. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/parsing/common.py +0 -0
  143. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/parsing/config.py +0 -0
  144. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/parsing/exceptions.py +0 -0
  145. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/parsing/helpers.py +0 -0
  146. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/parsing/parse_engine.py +0 -0
  147. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/parsing/trilogy.lark +0 -0
  148. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/py.typed +0 -0
  149. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/render.py +0 -0
  150. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/scripts/__init__.py +0 -0
  151. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/scripts/trilogy.py +0 -0
  152. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/std/__init__.py +0 -0
  153. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/std/color.preql +0 -0
  154. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/std/date.preql +0 -0
  155. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/std/geography.preql +0 -0
  156. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/std/metric.preql +0 -0
  157. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/std/money.preql +0 -0
  158. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/std/net.preql +0 -0
  159. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/std/ranking.preql +0 -0
  160. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/std/report.preql +0 -0
  161. {pytrilogy-0.0.3.106 → pytrilogy-0.0.3.108}/trilogy/utility.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pytrilogy
3
- Version: 0.0.3.106
3
+ Version: 0.0.3.108
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.106
3
+ Version: 0.0.3.108
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.106"
7
+ __version__ = "0.0.3.108"
8
8
 
9
9
  __all__ = ["parse", "Executor", "Dialects", "Environment", "CONFIG"]
@@ -350,9 +350,6 @@ def check_for_early_exit(
350
350
  def generate_loop_completion(context: LoopContext, virtual: set[str]) -> StrategyNode:
351
351
  condition_required = True
352
352
  non_virtual = [c for c in context.completion_mandatory if c.address not in virtual]
353
- non_virtual_output = [
354
- c for c in context.original_mandatory if c.address not in virtual
355
- ]
356
353
  non_virtual_different = len(context.completion_mandatory) != len(
357
354
  context.original_mandatory
358
355
  )
@@ -380,11 +377,12 @@ def generate_loop_completion(context: LoopContext, virtual: set[str]) -> Strateg
380
377
  logger.info(
381
378
  f"Condition {context.conditions} not required, parents included filtering! {parent_map}"
382
379
  )
380
+
383
381
  if len(context.stack) == 1:
384
382
  output: StrategyNode = context.stack[0]
385
383
  if non_virtual_different:
386
384
  logger.info(
387
- f"{depth_to_prefix(context.depth)}{LOGGER_PREFIX} Found different non-virtual output concepts ({non_virtual_difference_values}), removing condition injected values by setting outputs to {[x.address for x in output.output_concepts if x.address in non_virtual_output]}"
385
+ f"{depth_to_prefix(context.depth)}{LOGGER_PREFIX} Found added non-virtual output concepts ({non_virtual_difference_values})"
388
386
  )
389
387
  # output.set_output_concepts(
390
388
  # [
@@ -398,13 +396,6 @@ def generate_loop_completion(context: LoopContext, virtual: set[str]) -> Strateg
398
396
  # )
399
397
  # output.set_output_concepts(context.original_mandatory)
400
398
 
401
- # if isinstance(output, MergeNode):
402
- # output.force_group = True
403
- # output.rebuild_cache()
404
-
405
- logger.info(
406
- f"{depth_to_prefix(context.depth)}{LOGGER_PREFIX} Source stack has single node, returning that {type(output)}"
407
- )
408
399
  else:
409
400
  logger.info(
410
401
  f"{depth_to_prefix(context.depth)}{LOGGER_PREFIX} wrapping multiple parent nodes {[type(x) for x in context.stack]} in merge node"
@@ -441,10 +432,18 @@ def generate_loop_completion(context: LoopContext, virtual: set[str]) -> Strateg
441
432
  f"{depth_to_prefix(context.depth)}{LOGGER_PREFIX} Conditions {context.conditions} were injected, checking if we need a group to restore grain"
442
433
  )
443
434
  return group_if_required_v2(
444
- output, context.original_mandatory, context.environment
435
+ output,
436
+ context.original_mandatory,
437
+ context.environment,
438
+ non_virtual_difference_values,
445
439
  )
446
440
 
447
- return group_if_required_v2(output, context.original_mandatory, context.environment)
441
+ return group_if_required_v2(
442
+ output,
443
+ context.original_mandatory,
444
+ context.environment,
445
+ non_virtual_difference_values,
446
+ )
448
447
 
449
448
 
450
449
  def _search_concepts(
@@ -180,8 +180,12 @@ def check_if_group_required(
180
180
 
181
181
 
182
182
  def group_if_required_v2(
183
- root: StrategyNode, final: List[BuildConcept], environment: BuildEnvironment
183
+ root: StrategyNode,
184
+ final: List[BuildConcept],
185
+ environment: BuildEnvironment,
186
+ where_injected: set[str] | None = None,
184
187
  ):
188
+ where_injected = where_injected or set()
185
189
  required = check_if_group_required(
186
190
  downstream_concepts=final, parents=[root.resolve()], environment=environment
187
191
  )
@@ -197,8 +201,23 @@ def group_if_required_v2(
197
201
  root.rebuild_cache()
198
202
  return root
199
203
  elif isinstance(root, GroupNode):
200
- # root.set_output_concepts(final, rebuild=False)
201
- # root.rebuild_cache()
204
+
205
+ if set(x.address for x in final) != set(
206
+ x.address for x in root.output_concepts
207
+ ):
208
+ allowed_outputs = [
209
+ x
210
+ for x in root.output_concepts
211
+ if not (
212
+ x.address in where_injected
213
+ and x.address not in (root.required_outputs or set())
214
+ )
215
+ ]
216
+
217
+ logger.info(
218
+ f"Adjusting group node outputs to remove injected concepts {where_injected}: remaining {allowed_outputs}"
219
+ )
220
+ root.set_output_concepts(allowed_outputs)
202
221
  return root
203
222
  return GroupNode(
204
223
  output_concepts=targets,
@@ -176,6 +176,7 @@ def gen_group_node(
176
176
  parents=parents,
177
177
  depth=depth,
178
178
  preexisting_conditions=conditions.conditional if conditions else None,
179
+ required_outputs=parent_concepts,
179
180
  )
180
181
 
181
182
  # early exit if no optional
@@ -416,17 +416,22 @@ def create_datasource_node(
416
416
  ) -> tuple[StrategyNode, bool]:
417
417
 
418
418
  target_grain = BuildGrain.from_concepts(all_concepts, environment=environment)
419
+ # datasource grain may have changed since reference graph creation
420
+ datasource_grain = BuildGrain.from_concepts(
421
+ datasource.grain.components, environment=environment
422
+ )
423
+ # datasource_grain = datasource.grain
419
424
  force_group = False
420
- if not datasource.grain.issubset(target_grain):
425
+ if not datasource_grain.issubset(target_grain):
421
426
  logger.info(
422
- f"{padding(depth)}{LOGGER_PREFIX}_DS_NODE Select node must be wrapped in group, {datasource.grain} not subset of target grain {target_grain}"
427
+ f"{padding(depth)}{LOGGER_PREFIX}_DS_NODE Select node must be wrapped in group, {datasource_grain} not subset of target grain {target_grain} from {all_concepts}"
423
428
  )
424
429
  force_group = True
425
430
  else:
426
431
  logger.info(
427
- f"{padding(depth)}{LOGGER_PREFIX}_DS_NODE Select node grain {datasource.grain} is subset of target grain {target_grain}, no group required"
432
+ f"{padding(depth)}{LOGGER_PREFIX}_DS_NODE Select node grain {datasource_grain} is subset of target grain {target_grain}, no group required"
428
433
  )
429
- if not datasource.grain.components:
434
+ if not datasource_grain.components:
430
435
  force_group = True
431
436
  partial_concepts = [
432
437
  c.concept
@@ -27,7 +27,7 @@ WINDOW_TYPES = (BuildWindowItem,)
27
27
 
28
28
 
29
29
  def resolve_window_parent_concepts(
30
- concept: BuildConcept, environment: BuildEnvironment
30
+ concept: BuildConcept, environment: BuildEnvironment, depth: int
31
31
  ) -> tuple[BuildConcept, List[BuildConcept]]:
32
32
  if not isinstance(concept.lineage, WINDOW_TYPES):
33
33
  raise ValueError
@@ -39,7 +39,9 @@ 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
+ logger.info(
43
+ f"{padding(depth)}{LOGGER_PREFIX} appending grain item {gitem} to base"
44
+ )
43
45
  base.append(environment.concepts[gitem])
44
46
  return concept.lineage.content, unique(base, "address")
45
47
 
@@ -54,7 +56,7 @@ def gen_window_node(
54
56
  history: History,
55
57
  conditions: BuildWhereClause | None = None,
56
58
  ) -> StrategyNode | None:
57
- base, parent_concepts = resolve_window_parent_concepts(concept, environment)
59
+ base, parent_concepts = resolve_window_parent_concepts(concept, environment, depth)
58
60
  logger.info(
59
61
  f"{padding(depth)}{LOGGER_PREFIX} generating window node for {concept} with parents {[x.address for x in parent_concepts]} and optional {local_optional}"
60
62
  )
@@ -62,7 +64,7 @@ def gen_window_node(
62
64
  x
63
65
  for x in local_optional
64
66
  if isinstance(x.lineage, WINDOW_TYPES)
65
- and resolve_window_parent_concepts(x, environment)[1] == parent_concepts
67
+ and resolve_window_parent_concepts(x, environment, depth)[1] == parent_concepts
66
68
  ]
67
69
 
68
70
  targets = [base]
@@ -79,7 +81,7 @@ def gen_window_node(
79
81
  if equivalent_optional:
80
82
  for x in equivalent_optional:
81
83
  assert isinstance(x.lineage, WINDOW_TYPES)
82
- base, parents = resolve_window_parent_concepts(x, environment)
84
+ base, parents = resolve_window_parent_concepts(x, environment, depth)
83
85
  logger.info(
84
86
  f"{padding(depth)}{LOGGER_PREFIX} found equivalent optional {x} with parents {parents}"
85
87
  )
@@ -49,6 +49,7 @@ class GroupNode(StrategyNode):
49
49
  existence_concepts: List[BuildConcept] | None = None,
50
50
  hidden_concepts: set[str] | None = None,
51
51
  ordering: BuildOrderBy | None = None,
52
+ required_outputs: List[BuildConcept] | None = None,
52
53
  ):
53
54
  super().__init__(
54
55
  input_concepts=input_concepts,
@@ -66,6 +67,9 @@ class GroupNode(StrategyNode):
66
67
  hidden_concepts=hidden_concepts,
67
68
  ordering=ordering,
68
69
  )
70
+ # the set of concepts required to preserve grain
71
+ # set by group by node generation with aggregates
72
+ self.required_outputs = required_outputs
69
73
 
70
74
  @classmethod
71
75
  def check_if_required(
@@ -184,4 +188,7 @@ class GroupNode(StrategyNode):
184
188
  existence_concepts=list(self.existence_concepts),
185
189
  hidden_concepts=set(self.hidden_concepts),
186
190
  ordering=self.ordering,
191
+ required_outputs=(
192
+ list(self.required_outputs) if self.required_outputs else None
193
+ ),
187
194
  )
@@ -8,7 +8,14 @@ from typing import Any
8
8
  from jinja2 import Template
9
9
 
10
10
  from trilogy.constants import DEFAULT_NAMESPACE, VIRTUAL_CONCEPT_PREFIX, MagicConstants
11
- from trilogy.core.enums import ConceptSource, DatePart, FunctionType, Modifier, Purpose
11
+ from trilogy.core.enums import (
12
+ ConceptSource,
13
+ DatePart,
14
+ FunctionType,
15
+ Modifier,
16
+ Purpose,
17
+ ValidationScope,
18
+ )
12
19
  from trilogy.core.models.author import (
13
20
  AggregateWrapper,
14
21
  AlignClause,
@@ -66,6 +73,7 @@ from trilogy.core.statements.author import (
66
73
  SelectItem,
67
74
  SelectStatement,
68
75
  TypeDeclaration,
76
+ ValidateStatement,
69
77
  )
70
78
 
71
79
  QUERY_TEMPLATE = Template(
@@ -445,6 +453,13 @@ class Renderer:
445
453
  final = "".join(prefixes)
446
454
  return f"{final}{self.to_string(arg.content)}"
447
455
 
456
+ @to_string.register
457
+ def _(self, arg: ValidateStatement):
458
+ targets = ",".join(arg.targets) if arg.targets else "*"
459
+ if arg.scope.value == ValidationScope.ALL:
460
+ return "validate all;"
461
+ return f"validate {arg.scope.value} {targets};"
462
+
448
463
  @to_string.register
449
464
  def _(self, arg: SelectStatement):
450
465
  with self.indented():
@@ -0,0 +1,18 @@
1
+
2
+
3
+ type percent float; # Percentage value
4
+
5
+ def calc_percent(a, b, digits=-1) ->
6
+ case
7
+ when digits =-1 then
8
+ case
9
+ when b = 0 then 0.0::numeric
10
+ else (a/b)::numeric
11
+ end
12
+ else round((
13
+ case
14
+ when b = 0 then 0.0::float
15
+ else (a/b)::float
16
+ end
17
+ )::numeric, digits)
18
+ end::numeric::percent;
@@ -1,9 +0,0 @@
1
-
2
-
3
- type percent float; # Percentage value
4
-
5
- def calc_percent(a, b, digits=-1) -> case when digits =-1 then
6
- case when b = 0 then 0.0::numeric::percent else
7
- (a/b)::numeric::percent end
8
- else round((case when b = 0 then 0.0::float::percent else
9
- (a/b)::float::percent end):: numeric::percent, digits) end;
File without changes
File without changes
File without changes
File without changes