pytrilogy 0.0.2.42__tar.gz → 0.0.2.44__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.42/pytrilogy.egg-info → pytrilogy-0.0.2.44}/PKG-INFO +1 -1
  2. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44/pytrilogy.egg-info}/PKG-INFO +1 -1
  3. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/__init__.py +1 -1
  4. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/core/exceptions.py +4 -0
  5. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/core/models.py +27 -9
  6. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/core/processing/node_generators/multiselect_node.py +12 -3
  7. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/core/processing/node_generators/select_merge_node.py +17 -1
  8. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/core/processing/node_generators/select_node.py +1 -1
  9. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/dialect/base.py +55 -22
  10. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/parsing/parse_engine.py +1 -3
  11. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/LICENSE.md +0 -0
  12. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/README.md +0 -0
  13. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/pyproject.toml +0 -0
  14. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/pytrilogy.egg-info/SOURCES.txt +0 -0
  15. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/pytrilogy.egg-info/dependency_links.txt +0 -0
  16. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/pytrilogy.egg-info/entry_points.txt +0 -0
  17. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/pytrilogy.egg-info/requires.txt +0 -0
  18. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/pytrilogy.egg-info/top_level.txt +0 -0
  19. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/setup.cfg +0 -0
  20. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/setup.py +0 -0
  21. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/tests/test_datatypes.py +0 -0
  22. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/tests/test_declarations.py +0 -0
  23. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/tests/test_derived_concepts.py +0 -0
  24. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/tests/test_discovery_nodes.py +0 -0
  25. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/tests/test_enums.py +0 -0
  26. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/tests/test_environment.py +0 -0
  27. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/tests/test_executor.py +0 -0
  28. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/tests/test_functions.py +0 -0
  29. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/tests/test_imports.py +0 -0
  30. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/tests/test_metadata.py +0 -0
  31. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/tests/test_models.py +0 -0
  32. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/tests/test_multi_join_assignments.py +0 -0
  33. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/tests/test_parse_engine.py +0 -0
  34. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/tests/test_parsing.py +0 -0
  35. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/tests/test_partial_handling.py +0 -0
  36. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/tests/test_query_processing.py +0 -0
  37. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/tests/test_select.py +0 -0
  38. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/tests/test_show.py +0 -0
  39. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/tests/test_statements.py +0 -0
  40. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/tests/test_undefined_concept.py +0 -0
  41. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/tests/test_where_clause.py +0 -0
  42. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/compiler.py +0 -0
  43. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/constants.py +0 -0
  44. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/core/__init__.py +0 -0
  45. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/core/constants.py +0 -0
  46. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/core/enums.py +0 -0
  47. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/core/env_processor.py +0 -0
  48. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/core/environment_helpers.py +0 -0
  49. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/core/ergonomics.py +0 -0
  50. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/core/functions.py +0 -0
  51. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/core/graph_models.py +0 -0
  52. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/core/internal.py +0 -0
  53. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/core/optimization.py +0 -0
  54. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/core/optimizations/__init__.py +0 -0
  55. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/core/optimizations/base_optimization.py +0 -0
  56. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/core/optimizations/inline_constant.py +0 -0
  57. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/core/optimizations/inline_datasource.py +0 -0
  58. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/core/optimizations/predicate_pushdown.py +0 -0
  59. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/core/processing/__init__.py +0 -0
  60. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/core/processing/concept_strategies_v3.py +0 -0
  61. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/core/processing/graph_utils.py +0 -0
  62. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/core/processing/node_generators/__init__.py +0 -0
  63. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/core/processing/node_generators/basic_node.py +0 -0
  64. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/core/processing/node_generators/common.py +0 -0
  65. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/core/processing/node_generators/filter_node.py +0 -0
  66. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/core/processing/node_generators/group_node.py +0 -0
  67. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/core/processing/node_generators/group_to_node.py +0 -0
  68. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/core/processing/node_generators/node_merge_node.py +0 -0
  69. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/core/processing/node_generators/rowset_node.py +0 -0
  70. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/core/processing/node_generators/unnest_node.py +0 -0
  71. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/core/processing/node_generators/window_node.py +0 -0
  72. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/core/processing/nodes/__init__.py +0 -0
  73. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/core/processing/nodes/base_node.py +0 -0
  74. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/core/processing/nodes/filter_node.py +0 -0
  75. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/core/processing/nodes/group_node.py +0 -0
  76. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/core/processing/nodes/merge_node.py +0 -0
  77. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/core/processing/nodes/select_node_v2.py +0 -0
  78. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/core/processing/nodes/unnest_node.py +0 -0
  79. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/core/processing/nodes/window_node.py +0 -0
  80. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/core/processing/utility.py +0 -0
  81. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/core/query_processor.py +0 -0
  82. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/dialect/__init__.py +0 -0
  83. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/dialect/bigquery.py +0 -0
  84. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/dialect/common.py +0 -0
  85. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/dialect/config.py +0 -0
  86. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/dialect/duckdb.py +0 -0
  87. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/dialect/enums.py +0 -0
  88. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/dialect/postgres.py +0 -0
  89. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/dialect/presto.py +0 -0
  90. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/dialect/snowflake.py +0 -0
  91. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/dialect/sql_server.py +0 -0
  92. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/engine.py +0 -0
  93. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/executor.py +0 -0
  94. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/hooks/__init__.py +0 -0
  95. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/hooks/base_hook.py +0 -0
  96. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/hooks/graph_hook.py +0 -0
  97. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/hooks/query_debugger.py +0 -0
  98. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/metadata/__init__.py +0 -0
  99. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/parser.py +0 -0
  100. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/parsing/__init__.py +0 -0
  101. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/parsing/common.py +0 -0
  102. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/parsing/config.py +0 -0
  103. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/parsing/exceptions.py +0 -0
  104. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/parsing/helpers.py +0 -0
  105. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/parsing/render.py +0 -0
  106. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/parsing/trilogy.lark +0 -0
  107. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/py.typed +0 -0
  108. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/scripts/__init__.py +0 -0
  109. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/scripts/trilogy.py +0 -0
  110. {pytrilogy-0.0.2.42 → pytrilogy-0.0.2.44}/trilogy/utility.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pytrilogy
3
- Version: 0.0.2.42
3
+ Version: 0.0.2.44
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.42
3
+ Version: 0.0.2.44
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.42"
7
+ __version__ = "0.0.2.44"
8
8
 
9
9
  __all__ = ["parse", "Executor", "Dialects", "Environment", "CONFIG"]
@@ -16,6 +16,10 @@ class NoDatasourceException(Exception):
16
16
  pass
17
17
 
18
18
 
19
+ class FrozenEnvironmentException(Exception):
20
+ pass
21
+
22
+
19
23
  class AmbiguousRelationshipResolutionException(Exception):
20
24
  def __init__(self, message, parents: List[set[str]]):
21
25
  super().__init__(self, message)
@@ -67,7 +67,10 @@ from trilogy.core.enums import (
67
67
  SelectFiltering,
68
68
  IOType,
69
69
  )
70
- from trilogy.core.exceptions import UndefinedConceptException, InvalidSyntaxException
70
+ from trilogy.core.exceptions import (
71
+ UndefinedConceptException,
72
+ InvalidSyntaxException,
73
+ )
71
74
  from trilogy.utility import unique
72
75
  from collections import UserList, UserDict
73
76
  from functools import cached_property
@@ -555,6 +558,8 @@ class Concept(Mergeable, Namespaced, SelectContext, BaseModel):
555
558
  v = Grain(components=[])
556
559
  elif isinstance(v, Concept):
557
560
  v = Grain(components=[v])
561
+ elif isinstance(v, dict):
562
+ v = Grain.model_validate(v)
558
563
  if not v:
559
564
  raise SyntaxError(f"Invalid grain {v} for concept {values['name']}")
560
565
  return v
@@ -3337,7 +3342,7 @@ class EnvironmentConceptDict(dict):
3337
3342
  class ImportStatement(HasUUID, BaseModel):
3338
3343
  alias: str
3339
3344
  path: Path
3340
- environment: Union["Environment", None] = None
3345
+ # environment: Union["Environment", None] = None
3341
3346
  # TODO: this might result in a lot of duplication
3342
3347
  # environment:"Environment"
3343
3348
 
@@ -3385,9 +3390,13 @@ class Environment(BaseModel):
3385
3390
  environment_config: EnvironmentOptions = Field(default_factory=EnvironmentOptions)
3386
3391
  version: str = Field(default_factory=get_version)
3387
3392
  cte_name_map: Dict[str, str] = Field(default_factory=dict)
3388
-
3389
- materialized_concepts: List[Concept] = Field(default_factory=list)
3393
+ materialized_concepts: set[str] = Field(default_factory=set)
3390
3394
  alias_origin_lookup: Dict[str, Concept] = Field(default_factory=dict)
3395
+ # TODO: support freezing environments to avoid mutation
3396
+ # frozen: bool = False
3397
+
3398
+ def duplicate(self):
3399
+ return self.model_copy(deep=True)
3391
3400
 
3392
3401
  def __init__(self, **data):
3393
3402
  super().__init__(**data)
@@ -3405,6 +3414,12 @@ class Environment(BaseModel):
3405
3414
  )
3406
3415
  self.add_concept(concept)
3407
3416
 
3417
+ # def freeze(self):
3418
+ # self.frozen = True
3419
+
3420
+ # def thaw(self):
3421
+ # self.frozen = False
3422
+
3408
3423
  @classmethod
3409
3424
  def from_file(cls, path: str | Path) -> "Environment":
3410
3425
  with open(path, "r") as f:
@@ -3435,14 +3450,17 @@ class Environment(BaseModel):
3435
3450
  for datasource in self.datasources.values():
3436
3451
  for concept in datasource.output_concepts:
3437
3452
  concrete_addresses.add(concept.address)
3438
- self.materialized_concepts = unique(
3439
- [c for c in self.concepts.values() if c.address in concrete_addresses]
3453
+ self.materialized_concepts = set(
3454
+ [
3455
+ c.address
3456
+ for c in self.concepts.values()
3457
+ if c.address in concrete_addresses
3458
+ ]
3440
3459
  + [
3441
- c
3460
+ c.address
3442
3461
  for c in self.alias_origin_lookup.values()
3443
3462
  if c.address in concrete_addresses
3444
3463
  ],
3445
- "address",
3446
3464
  )
3447
3465
 
3448
3466
  def validate_concept(self, new_concept: Concept, meta: Meta | None = None):
@@ -3602,7 +3620,7 @@ class Environment(BaseModel):
3602
3620
  f"Unable to import file {target.parent}, parsing error: {e}"
3603
3621
  )
3604
3622
  env = nparser.environment
3605
- imps = ImportStatement(alias=alias, path=target, environment=env)
3623
+ imps = ImportStatement(alias=alias, path=target)
3606
3624
  self.add_import(alias, source=env, imp_stm=imps)
3607
3625
  return imps
3608
3626
 
@@ -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
@@ -34,7 +34,7 @@ def gen_select_node(
34
34
  concepts=[
35
35
  x
36
36
  for x in all_concepts
37
- if x.address in [z for z in environment.materialized_concepts]
37
+ if x.address in environment.materialized_concepts
38
38
  or x.derivation == PurposeLineage.CONSTANT
39
39
  ]
40
40
  )
@@ -348,12 +348,31 @@ class BaseDialect:
348
348
  ):
349
349
  rval = f":{c.safe_address}"
350
350
  else:
351
- args = [
352
- self.render_expr(
353
- v, cte=cte, raise_invalid=raise_invalid
354
- ) # , alias=False)
355
- for v in c.lineage.arguments
356
- ]
351
+ args = []
352
+ for arg in c.lineage.arguments:
353
+ if (
354
+ isinstance(arg, Concept)
355
+ and arg.lineage
356
+ and isinstance(arg.lineage, Function)
357
+ and arg.lineage.operator
358
+ in (
359
+ FunctionType.ADD,
360
+ FunctionType.SUBTRACT,
361
+ FunctionType.DIVIDE,
362
+ FunctionType.MULTIPLY,
363
+ )
364
+ ):
365
+ args.append(
366
+ self.render_expr(
367
+ Parenthetical(content=arg),
368
+ cte=cte,
369
+ raise_invalid=raise_invalid,
370
+ )
371
+ )
372
+ else:
373
+ args.append(
374
+ self.render_expr(arg, cte=cte, raise_invalid=raise_invalid)
375
+ )
357
376
 
358
377
  if cte.group_to_grain:
359
378
  rval = f"{self.FUNCTION_MAP[c.lineage.operator](args)}"
@@ -492,25 +511,39 @@ class BaseDialect:
492
511
  elif isinstance(e, CaseElse):
493
512
  return f"ELSE {self.render_expr(e.expr, cte=cte, cte_map=cte_map, raise_invalid=raise_invalid) }"
494
513
  elif isinstance(e, Function):
495
-
496
- if cte and cte.group_to_grain:
497
- return self.FUNCTION_MAP[e.operator](
498
- [
514
+ arguments = []
515
+ for arg in e.arguments:
516
+ if (
517
+ isinstance(arg, Concept)
518
+ and arg.lineage
519
+ and isinstance(arg.lineage, Function)
520
+ and arg.lineage.operator
521
+ in (
522
+ FunctionType.ADD,
523
+ FunctionType.SUBTRACT,
524
+ FunctionType.DIVIDE,
525
+ FunctionType.MULTIPLY,
526
+ )
527
+ ):
528
+ arguments.append(
499
529
  self.render_expr(
500
- z, cte=cte, cte_map=cte_map, raise_invalid=raise_invalid
530
+ Parenthetical(content=arg),
531
+ cte=cte,
532
+ cte_map=cte_map,
533
+ raise_invalid=raise_invalid,
501
534
  )
502
- for z in e.arguments
503
- ]
504
- )
505
-
506
- return self.FUNCTION_GRAIN_MATCH_MAP[e.operator](
507
- [
508
- self.render_expr(
509
- z, cte=cte, cte_map=cte_map, raise_invalid=raise_invalid
510
535
  )
511
- for z in e.arguments
512
- ]
513
- )
536
+ else:
537
+ arguments.append(
538
+ self.render_expr(
539
+ arg, cte=cte, cte_map=cte_map, raise_invalid=raise_invalid
540
+ )
541
+ )
542
+
543
+ if cte and cte.group_to_grain:
544
+ return self.FUNCTION_MAP[e.operator](arguments)
545
+
546
+ return self.FUNCTION_GRAIN_MATCH_MAP[e.operator](arguments)
514
547
  elif isinstance(e, AggregateWrapper):
515
548
  return self.render_expr(
516
549
  e.function, cte, cte_map=cte_map, raise_invalid=raise_invalid
@@ -907,9 +907,7 @@ class ParseToObjects(Transformer):
907
907
  except Exception as e:
908
908
  raise ImportError(f"Unable to import file {target}, parsing error: {e}")
909
909
 
910
- imps = ImportStatement(
911
- alias=alias, path=Path(args[0]), environment=nparser.environment
912
- )
910
+ imps = ImportStatement(alias=alias, path=Path(args[0]))
913
911
  self.environment.add_import(alias, nparser.environment, imps)
914
912
  return imps
915
913
 
File without changes
File without changes
File without changes
File without changes