pytrilogy 0.0.3.71__tar.gz → 0.0.3.73__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.
- {pytrilogy-0.0.3.71/pytrilogy.egg-info → pytrilogy-0.0.3.73}/PKG-INFO +1 -1
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73/pytrilogy.egg-info}/PKG-INFO +1 -1
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/__init__.py +1 -1
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/constants.py +1 -1
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/enums.py +1 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/functions.py +5 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/models/build.py +35 -19
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/models/execute.py +0 -1
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/processing/node_generators/window_node.py +4 -1
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/processing/utility.py +18 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/dialect/base.py +1 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/dialect/bigquery.py +2 -1
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/dialect/common.py +1 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/dialect/postgres.py +2 -1
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/dialect/presto.py +2 -1
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/dialect/snowflake.py +2 -1
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/dialect/sql_server.py +2 -1
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/parsing/common.py +10 -16
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/parsing/parse_engine.py +9 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/std/net.preql +2 -1
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/LICENSE.md +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/README.md +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/pyproject.toml +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/pytrilogy.egg-info/SOURCES.txt +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/pytrilogy.egg-info/dependency_links.txt +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/pytrilogy.egg-info/entry_points.txt +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/pytrilogy.egg-info/requires.txt +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/pytrilogy.egg-info/top_level.txt +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/setup.cfg +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/setup.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/tests/test_datatypes.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/tests/test_declarations.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/tests/test_derived_concepts.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/tests/test_discovery_nodes.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/tests/test_enums.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/tests/test_environment.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/tests/test_execute_models.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/tests/test_executor.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/tests/test_failure.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/tests/test_functions.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/tests/test_imports.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/tests/test_metadata.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/tests/test_models.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/tests/test_multi_join_assignments.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/tests/test_parse_engine.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/tests/test_parsing.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/tests/test_parsing_failures.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/tests/test_partial_handling.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/tests/test_query_processing.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/tests/test_query_render.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/tests/test_select.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/tests/test_show.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/tests/test_statements.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/tests/test_typing.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/tests/test_undefined_concept.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/tests/test_user_functions.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/tests/test_where_clause.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/authoring/__init__.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/compiler.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/__init__.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/constants.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/env_processor.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/environment_helpers.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/ergonomics.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/exceptions.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/graph_models.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/internal.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/models/__init__.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/models/author.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/models/build_environment.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/models/core.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/models/datasource.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/models/environment.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/optimization.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/optimizations/__init__.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/optimizations/base_optimization.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/optimizations/inline_datasource.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/optimizations/predicate_pushdown.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/processing/__init__.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/processing/concept_strategies_v3.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/processing/discovery_loop.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/processing/discovery_node_factory.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/processing/discovery_utility.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/processing/discovery_validation.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/processing/graph_utils.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/processing/node_generators/__init__.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/processing/node_generators/basic_node.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/processing/node_generators/common.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/processing/node_generators/filter_node.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/processing/node_generators/group_node.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/processing/node_generators/group_to_node.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/processing/node_generators/multiselect_node.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/processing/node_generators/node_merge_node.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/processing/node_generators/recursive_node.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/processing/node_generators/rowset_node.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/processing/node_generators/select_helpers/__init__.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/processing/node_generators/select_helpers/datasource_injection.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/processing/node_generators/select_merge_node.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/processing/node_generators/select_node.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/processing/node_generators/synonym_node.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/processing/node_generators/union_node.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/processing/node_generators/unnest_node.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/processing/nodes/__init__.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/processing/nodes/base_node.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/processing/nodes/filter_node.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/processing/nodes/group_node.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/processing/nodes/merge_node.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/processing/nodes/recursive_node.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/processing/nodes/select_node_v2.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/processing/nodes/union_node.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/processing/nodes/unnest_node.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/processing/nodes/window_node.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/query_processor.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/statements/__init__.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/statements/author.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/statements/build.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/statements/common.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/statements/execute.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/utility.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/dialect/__init__.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/dialect/config.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/dialect/dataframe.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/dialect/duckdb.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/dialect/enums.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/engine.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/executor.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/hooks/__init__.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/hooks/base_hook.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/hooks/graph_hook.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/hooks/query_debugger.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/metadata/__init__.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/parser.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/parsing/__init__.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/parsing/config.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/parsing/exceptions.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/parsing/helpers.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/parsing/render.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/parsing/trilogy.lark +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/py.typed +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/render.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/scripts/__init__.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/scripts/trilogy.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/std/__init__.py +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/std/date.preql +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/std/display.preql +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/std/geography.preql +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/std/money.preql +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/std/ranking.preql +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/std/report.preql +0 -0
- {pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/utility.py +0 -0
|
@@ -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
|
|
1513
|
-
| MapWrapper
|
|
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
|
|
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
|
-
|
|
1647
|
-
|
|
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
|
-
|
|
1657
|
-
|
|
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
|
-
|
|
1757
|
-
|
|
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
|
-
|
|
1785
|
-
|
|
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
|
-
|
|
1828
|
-
|
|
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
|
-
|
|
1832
|
-
|
|
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)),
|
|
@@ -501,7 +501,6 @@ class BaseJoin(BaseModel):
|
|
|
501
501
|
f"Cannot join a dataself to itself, joining {self.left_datasource} and"
|
|
502
502
|
f" {self.right_datasource}"
|
|
503
503
|
)
|
|
504
|
-
|
|
505
504
|
# Early returns maintained as in original code
|
|
506
505
|
if self.concept_pairs or self.concepts == []:
|
|
507
506
|
return self
|
{pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/processing/node_generators/window_node.py
RENAMED
|
@@ -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
|
|
@@ -68,6 +69,8 @@ def gen_window_node(
|
|
|
68
69
|
# append in keys to get the right grain
|
|
69
70
|
if concept.keys:
|
|
70
71
|
for item in concept.keys:
|
|
72
|
+
if item in targets:
|
|
73
|
+
continue
|
|
71
74
|
logger.info(
|
|
72
75
|
f"{padding(depth)}{LOGGER_PREFIX} appending search for key {item}"
|
|
73
76
|
)
|
|
@@ -13,6 +13,7 @@ from trilogy.core.enums import (
|
|
|
13
13
|
FunctionClass,
|
|
14
14
|
Granularity,
|
|
15
15
|
JoinType,
|
|
16
|
+
Modifier,
|
|
16
17
|
Purpose,
|
|
17
18
|
)
|
|
18
19
|
from trilogy.core.models.build import (
|
|
@@ -355,6 +356,20 @@ def reduce_concept_pairs(input: list[ConceptPair]) -> list[ConceptPair]:
|
|
|
355
356
|
return final
|
|
356
357
|
|
|
357
358
|
|
|
359
|
+
def get_modifiers(
|
|
360
|
+
concept: str,
|
|
361
|
+
join: JoinOrderOutput,
|
|
362
|
+
ds_node_map: dict[str, QueryDatasource | BuildDatasource],
|
|
363
|
+
):
|
|
364
|
+
base = []
|
|
365
|
+
|
|
366
|
+
if join.right and concept in ds_node_map[join.right].nullable_concepts:
|
|
367
|
+
base.append(Modifier.NULLABLE)
|
|
368
|
+
if join.left and concept in ds_node_map[join.left].nullable_concepts:
|
|
369
|
+
base.append(Modifier.NULLABLE)
|
|
370
|
+
return list(set(base))
|
|
371
|
+
|
|
372
|
+
|
|
358
373
|
def get_node_joins(
|
|
359
374
|
datasources: List[QueryDatasource | BuildDatasource],
|
|
360
375
|
environment: BuildEnvironment,
|
|
@@ -400,6 +415,9 @@ def get_node_joins(
|
|
|
400
415
|
concept_map[concept], ds_node_map[j.right]
|
|
401
416
|
),
|
|
402
417
|
existing_datasource=ds_node_map[k],
|
|
418
|
+
modifiers=get_modifiers(
|
|
419
|
+
concept_map[concept].address, j, ds_node_map
|
|
420
|
+
),
|
|
403
421
|
)
|
|
404
422
|
for k, v in j.keys.items()
|
|
405
423
|
for concept in v
|
|
@@ -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]})",
|
|
@@ -43,7 +43,8 @@ FUNCTION_MAP = {
|
|
|
43
43
|
|
|
44
44
|
FUNCTION_GRAIN_MATCH_MAP = {
|
|
45
45
|
**FUNCTION_MAP,
|
|
46
|
-
FunctionType.
|
|
46
|
+
FunctionType.COUNT_DISTINCT: lambda args: f"CASE WHEN{args[0]} IS NOT NULL THEN 1 ELSE 0 END",
|
|
47
|
+
FunctionType.COUNT: lambda args: f"CASE WHEN {args[0]} IS NOT NULL THEN 1 ELSE 0 END",
|
|
47
48
|
FunctionType.SUM: lambda args: f"{args[0]}",
|
|
48
49
|
FunctionType.AVG: lambda args: f"{args[0]}",
|
|
49
50
|
}
|
|
@@ -20,6 +20,7 @@ from trilogy.core.models.execute import (
|
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
def null_wrapper(lval: str, rval: str, modifiers: list[Modifier]) -> str:
|
|
23
|
+
|
|
23
24
|
if Modifier.NULLABLE in modifiers:
|
|
24
25
|
return f"({lval} = {rval} or ({lval} is null and {rval} is null))"
|
|
25
26
|
return f"{lval} = {rval}"
|
|
@@ -37,7 +37,8 @@ FUNCTION_MAP = {
|
|
|
37
37
|
|
|
38
38
|
FUNCTION_GRAIN_MATCH_MAP = {
|
|
39
39
|
**FUNCTION_MAP,
|
|
40
|
-
FunctionType.
|
|
40
|
+
FunctionType.COUNT_DISTINCT: lambda args: f"CASE WHEN{args[0]} IS NOT NULL THEN 1 ELSE 0 END",
|
|
41
|
+
FunctionType.COUNT: lambda args: f"CASE WHEN {args[0]} IS NOT NULL THEN 1 ELSE 0 END",
|
|
41
42
|
FunctionType.SUM: lambda args: f"{args[0]}",
|
|
42
43
|
FunctionType.AVG: lambda args: f"{args[0]}",
|
|
43
44
|
}
|
|
@@ -39,7 +39,8 @@ FUNCTION_MAP = {
|
|
|
39
39
|
|
|
40
40
|
FUNCTION_GRAIN_MATCH_MAP = {
|
|
41
41
|
**FUNCTION_MAP,
|
|
42
|
-
FunctionType.
|
|
42
|
+
FunctionType.COUNT_DISTINCT: lambda args: f"CASE WHEN{args[0]} IS NOT NULL THEN 1 ELSE 0 END",
|
|
43
|
+
FunctionType.COUNT: lambda args: f"CASE WHEN {args[0]} IS NOT NULL THEN 1 ELSE 0 END",
|
|
43
44
|
FunctionType.SUM: lambda args: f"{args[0]}",
|
|
44
45
|
FunctionType.AVG: lambda args: f"{args[0]}",
|
|
45
46
|
}
|
|
@@ -36,7 +36,8 @@ FUNCTION_MAP = {
|
|
|
36
36
|
|
|
37
37
|
FUNCTION_GRAIN_MATCH_MAP = {
|
|
38
38
|
**FUNCTION_MAP,
|
|
39
|
-
FunctionType.
|
|
39
|
+
FunctionType.COUNT_DISTINCT: lambda args: f"CASE WHEN{args[0]} IS NOT NULL THEN 1 ELSE 0 END",
|
|
40
|
+
FunctionType.COUNT: lambda args: f"CASE WHEN {args[0]} IS NOT NULL THEN 1 ELSE 0 END",
|
|
40
41
|
FunctionType.SUM: lambda args: f"{args[0]}",
|
|
41
42
|
FunctionType.AVG: lambda args: f"{args[0]}",
|
|
42
43
|
}
|
|
@@ -31,7 +31,8 @@ FUNCTION_MAP = {
|
|
|
31
31
|
# we may return a static value
|
|
32
32
|
FUNCTION_GRAIN_MATCH_MAP = {
|
|
33
33
|
**FUNCTION_MAP,
|
|
34
|
-
FunctionType.
|
|
34
|
+
FunctionType.COUNT_DISTINCT: lambda args: f"CASE WHEN{args[0]} IS NOT NULL THEN 1 ELSE 0 END",
|
|
35
|
+
FunctionType.COUNT: lambda args: f"CASE WHEN {args[0]} IS NOT NULL THEN 1 ELSE 0 END",
|
|
35
36
|
FunctionType.SUM: lambda args: f"{args[0]}",
|
|
36
37
|
FunctionType.AVG: lambda args: f"{args[0]}",
|
|
37
38
|
}
|
|
@@ -173,7 +173,9 @@ def concept_list_to_keys(
|
|
|
173
173
|
|
|
174
174
|
|
|
175
175
|
def constant_to_concept(
|
|
176
|
-
parent:
|
|
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
|
-
|
|
373
|
-
return
|
|
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
|
-
|
|
632
|
-
|
|
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
|
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/processing/node_generators/__init__.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/processing/node_generators/basic_node.py
RENAMED
|
File without changes
|
|
File without changes
|
{pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/processing/node_generators/filter_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/processing/node_generators/group_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/processing/node_generators/group_to_node.py
RENAMED
|
File without changes
|
|
File without changes
|
{pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/processing/node_generators/node_merge_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/processing/node_generators/recursive_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/processing/node_generators/rowset_node.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/processing/node_generators/select_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/processing/node_generators/synonym_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/processing/node_generators/union_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.71 → pytrilogy-0.0.3.73}/trilogy/core/processing/node_generators/unnest_node.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|