pytrilogy 0.0.2.43__tar.gz → 0.0.2.45__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 (110) hide show
  1. {pytrilogy-0.0.2.43/pytrilogy.egg-info → pytrilogy-0.0.2.45}/PKG-INFO +1 -1
  2. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45/pytrilogy.egg-info}/PKG-INFO +1 -1
  3. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/__init__.py +1 -1
  4. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/core/models.py +20 -10
  5. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/core/processing/node_generators/multiselect_node.py +12 -3
  6. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/core/processing/node_generators/select_merge_node.py +17 -1
  7. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/LICENSE.md +0 -0
  8. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/README.md +0 -0
  9. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/pyproject.toml +0 -0
  10. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/pytrilogy.egg-info/SOURCES.txt +0 -0
  11. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/pytrilogy.egg-info/dependency_links.txt +0 -0
  12. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/pytrilogy.egg-info/entry_points.txt +0 -0
  13. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/pytrilogy.egg-info/requires.txt +0 -0
  14. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/pytrilogy.egg-info/top_level.txt +0 -0
  15. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/setup.cfg +0 -0
  16. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/setup.py +0 -0
  17. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/tests/test_datatypes.py +0 -0
  18. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/tests/test_declarations.py +0 -0
  19. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/tests/test_derived_concepts.py +0 -0
  20. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/tests/test_discovery_nodes.py +0 -0
  21. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/tests/test_enums.py +0 -0
  22. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/tests/test_environment.py +0 -0
  23. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/tests/test_executor.py +0 -0
  24. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/tests/test_functions.py +0 -0
  25. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/tests/test_imports.py +0 -0
  26. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/tests/test_metadata.py +0 -0
  27. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/tests/test_models.py +0 -0
  28. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/tests/test_multi_join_assignments.py +0 -0
  29. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/tests/test_parse_engine.py +0 -0
  30. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/tests/test_parsing.py +0 -0
  31. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/tests/test_partial_handling.py +0 -0
  32. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/tests/test_query_processing.py +0 -0
  33. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/tests/test_select.py +0 -0
  34. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/tests/test_show.py +0 -0
  35. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/tests/test_statements.py +0 -0
  36. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/tests/test_undefined_concept.py +0 -0
  37. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/tests/test_where_clause.py +0 -0
  38. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/compiler.py +0 -0
  39. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/constants.py +0 -0
  40. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/core/__init__.py +0 -0
  41. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/core/constants.py +0 -0
  42. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/core/enums.py +0 -0
  43. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/core/env_processor.py +0 -0
  44. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/core/environment_helpers.py +0 -0
  45. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/core/ergonomics.py +0 -0
  46. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/core/exceptions.py +0 -0
  47. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/core/functions.py +0 -0
  48. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/core/graph_models.py +0 -0
  49. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/core/internal.py +0 -0
  50. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/core/optimization.py +0 -0
  51. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/core/optimizations/__init__.py +0 -0
  52. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/core/optimizations/base_optimization.py +0 -0
  53. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/core/optimizations/inline_constant.py +0 -0
  54. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/core/optimizations/inline_datasource.py +0 -0
  55. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/core/optimizations/predicate_pushdown.py +0 -0
  56. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/core/processing/__init__.py +0 -0
  57. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/core/processing/concept_strategies_v3.py +0 -0
  58. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/core/processing/graph_utils.py +0 -0
  59. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/core/processing/node_generators/__init__.py +0 -0
  60. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/core/processing/node_generators/basic_node.py +0 -0
  61. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/core/processing/node_generators/common.py +0 -0
  62. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/core/processing/node_generators/filter_node.py +0 -0
  63. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/core/processing/node_generators/group_node.py +0 -0
  64. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/core/processing/node_generators/group_to_node.py +0 -0
  65. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/core/processing/node_generators/node_merge_node.py +0 -0
  66. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/core/processing/node_generators/rowset_node.py +0 -0
  67. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/core/processing/node_generators/select_node.py +0 -0
  68. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/core/processing/node_generators/unnest_node.py +0 -0
  69. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/core/processing/node_generators/window_node.py +0 -0
  70. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/core/processing/nodes/__init__.py +0 -0
  71. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/core/processing/nodes/base_node.py +0 -0
  72. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/core/processing/nodes/filter_node.py +0 -0
  73. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/core/processing/nodes/group_node.py +0 -0
  74. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/core/processing/nodes/merge_node.py +0 -0
  75. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/core/processing/nodes/select_node_v2.py +0 -0
  76. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/core/processing/nodes/unnest_node.py +0 -0
  77. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/core/processing/nodes/window_node.py +0 -0
  78. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/core/processing/utility.py +0 -0
  79. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/core/query_processor.py +0 -0
  80. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/dialect/__init__.py +0 -0
  81. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/dialect/base.py +0 -0
  82. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/dialect/bigquery.py +0 -0
  83. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/dialect/common.py +0 -0
  84. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/dialect/config.py +0 -0
  85. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/dialect/duckdb.py +0 -0
  86. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/dialect/enums.py +0 -0
  87. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/dialect/postgres.py +0 -0
  88. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/dialect/presto.py +0 -0
  89. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/dialect/snowflake.py +0 -0
  90. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/dialect/sql_server.py +0 -0
  91. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/engine.py +0 -0
  92. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/executor.py +0 -0
  93. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/hooks/__init__.py +0 -0
  94. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/hooks/base_hook.py +0 -0
  95. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/hooks/graph_hook.py +0 -0
  96. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/hooks/query_debugger.py +0 -0
  97. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/metadata/__init__.py +0 -0
  98. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/parser.py +0 -0
  99. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/parsing/__init__.py +0 -0
  100. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/parsing/common.py +0 -0
  101. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/parsing/config.py +0 -0
  102. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/parsing/exceptions.py +0 -0
  103. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/parsing/helpers.py +0 -0
  104. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/parsing/parse_engine.py +0 -0
  105. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/parsing/render.py +0 -0
  106. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/parsing/trilogy.lark +0 -0
  107. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/py.typed +0 -0
  108. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/scripts/__init__.py +0 -0
  109. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/scripts/trilogy.py +0 -0
  110. {pytrilogy-0.0.2.43 → pytrilogy-0.0.2.45}/trilogy/utility.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pytrilogy
3
- Version: 0.0.2.43
3
+ Version: 0.0.2.45
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.43
3
+ Version: 0.0.2.45
4
4
  Summary: Declarative, typed query language that compiles to SQL.
5
5
  Home-page:
6
6
  Author:
@@ -4,6 +4,6 @@ from trilogy.executor import Executor
4
4
  from trilogy.parser import parse
5
5
  from trilogy.constants import CONFIG
6
6
 
7
- __version__ = "0.0.2.43"
7
+ __version__ = "0.0.2.45"
8
8
 
9
9
  __all__ = ["parse", "Executor", "Dialects", "Environment", "CONFIG"]
@@ -2307,9 +2307,11 @@ class UnnestJoin(BaseModel):
2307
2307
  rendering_required: bool = True
2308
2308
 
2309
2309
  def __hash__(self):
2310
- return (
2311
- self.alias + "".join([str(s.address) for s in self.concepts])
2312
- ).__hash__()
2310
+ return self.safe_identifier.__hash__()
2311
+
2312
+ @property
2313
+ def safe_identifier(self) -> str:
2314
+ return self.alias + "".join([str(s.address) for s in self.concepts])
2313
2315
 
2314
2316
 
2315
2317
  class InstantiatedUnnestJoin(BaseModel):
@@ -2544,7 +2546,7 @@ class QueryDatasource(BaseModel):
2544
2546
  return True
2545
2547
  return False
2546
2548
 
2547
- def __add__(self, other):
2549
+ def __add__(self, other) -> "QueryDatasource":
2548
2550
  # these are syntax errors to avoid being caught by current
2549
2551
  if not isinstance(other, QueryDatasource):
2550
2552
  raise SyntaxError("Can only merge two query datasources")
@@ -2570,7 +2572,7 @@ class QueryDatasource(BaseModel):
2570
2572
  f" {other.name} with {[c.address for c in other.output_concepts]} concepts"
2571
2573
  )
2572
2574
 
2573
- merged_datasources = {}
2575
+ merged_datasources: dict[str, Union[Datasource, "QueryDatasource"]] = {}
2574
2576
 
2575
2577
  for ds in [*self.datasources, *other.datasources]:
2576
2578
  if ds.safe_identifier in merged_datasources:
@@ -2580,20 +2582,29 @@ class QueryDatasource(BaseModel):
2580
2582
  else:
2581
2583
  merged_datasources[ds.safe_identifier] = ds
2582
2584
 
2583
- final_source_map = defaultdict(set)
2585
+ final_source_map: defaultdict[
2586
+ str, Set[Union[Datasource, "QueryDatasource", "UnnestJoin"]]
2587
+ ] = defaultdict(set)
2588
+
2589
+ # add our sources
2584
2590
  for key in self.source_map:
2585
2591
  final_source_map[key] = self.source_map[key].union(
2586
2592
  other.source_map.get(key, set())
2587
2593
  )
2594
+ # add their sources
2588
2595
  for key in other.source_map:
2589
2596
  if key not in final_source_map:
2590
2597
  final_source_map[key] = other.source_map[key]
2598
+
2599
+ # if a ds was merged (to combine columns), we need to update the source map
2600
+ # to use the merged item
2591
2601
  for k, v in final_source_map.items():
2592
2602
  final_source_map[k] = set(
2593
- merged_datasources[x.safe_identifier] for x in list(v)
2603
+ merged_datasources.get(x.safe_identifier, x) for x in list(v)
2594
2604
  )
2595
2605
  self_hidden = self.hidden_concepts or []
2596
2606
  other_hidden = other.hidden_concepts or []
2607
+ # hidden is the minimum overlapping set
2597
2608
  hidden = [x for x in self_hidden if x.address in other_hidden]
2598
2609
  qds = QueryDatasource(
2599
2610
  input_concepts=unique(
@@ -2606,11 +2617,10 @@ class QueryDatasource(BaseModel):
2606
2617
  datasources=list(merged_datasources.values()),
2607
2618
  grain=self.grain,
2608
2619
  joins=unique(self.joins + other.joins, "unique_id"),
2609
- # joins = self.joins,
2610
2620
  condition=(
2611
2621
  self.condition + other.condition
2612
- if (self.condition or other.condition)
2613
- else None
2622
+ if self.condition and other.condition
2623
+ else self.condition or other.condition
2614
2624
  ),
2615
2625
  source_type=self.source_type,
2616
2626
  partial_concepts=unique(
@@ -3,6 +3,7 @@ from trilogy.core.models import (
3
3
  Environment,
4
4
  MultiSelectStatement,
5
5
  WhereClause,
6
+ Conditional,
6
7
  )
7
8
  from trilogy.core.processing.nodes import MergeNode, NodeJoin, History
8
9
  from trilogy.core.processing.nodes.base_node import concept_list_to_grain, StrategyNode
@@ -14,7 +15,7 @@ from trilogy.core.processing.utility import padding
14
15
  from trilogy.core.processing.utility import concept_to_relevant_joins
15
16
  from collections import defaultdict
16
17
  from itertools import combinations
17
- from trilogy.core.enums import Purpose
18
+ from trilogy.core.enums import Purpose, BooleanOperator
18
19
  from trilogy.core.processing.node_generators.common import resolve_join_order
19
20
 
20
21
  LOGGER_PREFIX = "[GEN_MULTISELECT_NODE]"
@@ -76,14 +77,22 @@ def gen_multiselect_node(
76
77
  g=g,
77
78
  depth=depth + 1,
78
79
  history=history,
80
+ conditions=select.where_clause,
79
81
  )
80
82
  if not snode:
81
83
  logger.info(
82
84
  f"{padding(depth)}{LOGGER_PREFIX} Cannot generate multiselect node for {concept}"
83
85
  )
84
86
  return None
85
- if select.where_clause:
86
- snode.conditions = select.where_clause.conditional
87
+ if select.having_clause:
88
+ if snode.conditions:
89
+ snode.conditions = Conditional(
90
+ left=snode.conditions,
91
+ right=select.having_clause.conditional,
92
+ operator=BooleanOperator.AND,
93
+ )
94
+ else:
95
+ snode.conditions = select.having_clause.conditional
87
96
  merge_concepts = []
88
97
  for x in [*snode.output_concepts]:
89
98
  merge = lineage.get_merge_concept(x)
@@ -20,6 +20,9 @@ from trilogy.core.graph_models import concept_to_node
20
20
  from trilogy.constants import logger
21
21
  from trilogy.core.processing.utility import padding
22
22
  from trilogy.core.enums import PurposeLineage
23
+ from trilogy.core.processing.nodes.base_node import (
24
+ concept_list_to_grain,
25
+ )
23
26
 
24
27
  LOGGER_PREFIX = "[GEN_ROOT_MERGE_NODE]"
25
28
 
@@ -353,7 +356,7 @@ def gen_select_merge_node(
353
356
  ]
354
357
  ):
355
358
  preexisting_conditions = conditions.conditional
356
- return MergeNode(
359
+ base = MergeNode(
357
360
  output_concepts=all_concepts,
358
361
  input_concepts=non_constant,
359
362
  environment=environment,
@@ -362,3 +365,16 @@ def gen_select_merge_node(
362
365
  parents=parents,
363
366
  preexisting_conditions=preexisting_conditions,
364
367
  )
368
+ target_grain = concept_list_to_grain(all_concepts, [])
369
+ if not base.resolve().grain.issubset(target_grain):
370
+ return GroupNode(
371
+ output_concepts=all_concepts,
372
+ input_concepts=all_concepts,
373
+ environment=environment,
374
+ g=g,
375
+ parents=[base],
376
+ depth=depth,
377
+ preexisting_conditions=preexisting_conditions,
378
+ partial_concepts=base.partial_concepts,
379
+ )
380
+ return base
File without changes
File without changes
File without changes
File without changes