pytrilogy 0.3.332__tar.gz → 0.3.334__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.
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/PKG-INFO +1 -1
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/__init__.py +1 -1
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/ai/constants.py +6 -10
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/ai/syntax_examples.py +10 -49
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/models/build.py +6 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/models/core.py +4 -5
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/models/execute.py +16 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/join_resolution.py +65 -4
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/nodes/base_node.py +30 -3
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/nodes/filter_node.py +2 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/nodes/select_node_v2.py +2 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/v4_helper/group_graph.py +56 -6
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/v4_helper/strategy_builder.py +204 -136
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/dialect/base.py +13 -3
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/dialect/bigquery.py +46 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/dialect/common.py +8 -2
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/dialect/duckdb.py +2 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/dialect/mysql.py +4 -1
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/agent_info_docs/cli.py +3 -2
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/dependency/Cargo.lock +1 -1
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/dependency/Cargo.toml +1 -1
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/explore.py +1 -2
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/file.py +22 -2
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/.scripts/__init__.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/.scripts/build_backend.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/.scripts/sync_version.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/LICENSE.md +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/README.md +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/pyproject.toml +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/ai/README.md +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/ai/__init__.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/ai/conversation.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/ai/enums.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/ai/execute.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/ai/models.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/ai/prompts.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/ai/providers/__init__.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/ai/providers/anthropic.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/ai/providers/base.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/ai/providers/deepseek.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/ai/providers/google.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/ai/providers/openai.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/ai/providers/openrouter.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/ai/providers/utils.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/authoring/README.md +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/authoring/__init__.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/constants.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/README.md +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/__init__.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/constants.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/domain_graph.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/domain_validation.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/enums.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/env_processor.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/environment_helpers.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/ergonomics.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/exceptions.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/fingerprint.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/functions.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/graph.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/graph_models.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/having_normalization.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/internal.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/models/__init__.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/models/author.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/models/build_environment.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/models/datasource.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/models/environment.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/optimization.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/optimizations/__init__.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/optimizations/base_optimization.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/optimizations/collapse_single_parent.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/optimizations/filtered_aggregate.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/optimizations/filtered_count_join.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/optimizations/full_join_lowering.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/optimizations/hide_unused_concept.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/optimizations/inline_datasource.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/optimizations/join_hoist.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/optimizations/join_upgrade.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/optimizations/keyless_full_join.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/optimizations/merge_irrelevant_group_by.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/optimizations/null_safe_join.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/optimizations/order_inner_joins.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/optimizations/predicate_pushdown.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/optimizations/semi_join_pushdown.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/optimizations/strip_redundant_not_null.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/optimizations/union_dim_pushdown.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/optimizations/utils.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/optimizations/value_set_join_upgrade.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/README.md +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/VIRTUAL_UNNEST.md +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/__init__.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/aggregate_rollup.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/concept_strategies_v4.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/condition_utility.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/constants.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/discovery_utility.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/discovery_validation.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/grain_utility.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/model_ambiguity.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/node_generators/__init__.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/node_generators/common.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/node_generators/presence_probe.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/node_generators/select_helpers/__init__.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/node_generators/select_helpers/condition_routing.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/node_generators/select_helpers/datasource_injection.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/node_generators/select_helpers/datasource_nodes.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/node_generators/select_helpers/source_scoring.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/node_generators/select_merge_node.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/node_generators/select_node.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/nodes/README.md +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/nodes/__init__.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/nodes/group_node.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/nodes/merge_node.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/nodes/recursive_node.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/nodes/subselect_node.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/nodes/union_node.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/nodes/unnest_node.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/nodes/window_node.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/rowset_islanding.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/utility.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/v4_helper/__init__.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/v4_helper/concept_graph.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/v4_helper/condition_injection.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/v4_helper/condition_placement.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/v4_helper/constants.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/v4_helper/edges.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/v4_helper/functional_dependency.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/v4_helper/group_behaviors.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/v4_helper/group_rules.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/v4_helper/history.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/v4_helper/models.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/v4_helper/network_build.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/v4_helper/network_coalescing.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/v4_helper/network_model.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/v4_helper/network_obligations.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/v4_helper/network_search.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/v4_helper/network_topology.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/v4_helper/projection.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/v4_helper/source_planning.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/v4_helper/staged_where.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/v4_node_generators/__init__.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/v4_node_generators/aggregate.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/v4_node_generators/basic.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/v4_node_generators/common.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/v4_node_generators/condition_sources.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/v4_node_generators/constant.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/v4_node_generators/dispatch.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/v4_node_generators/filter.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/v4_node_generators/group_to.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/v4_node_generators/multiselect.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/v4_node_generators/nested_select.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/v4_node_generators/recursive.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/v4_node_generators/root.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/v4_node_generators/rowset.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/v4_node_generators/subselect.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/v4_node_generators/union.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/v4_node_generators/union_select.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/v4_node_generators/unnest.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/processing/v4_node_generators/window.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/query_processor.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/scope_diagnostics.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/statements/README.md +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/statements/__init__.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/statements/author.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/statements/build.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/statements/common.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/statements/execute.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/table_processor.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/utility.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/validation/README.md +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/validation/__init__.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/validation/common.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/validation/concept.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/validation/datasource.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/validation/environment.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/validation/fix.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/validation/rows.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/core/where_scope_normalization.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/dialect/__init__.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/dialect/bigquery_engine.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/dialect/bigquery_persist.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/dialect/bigquery_staging.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/dialect/cancel.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/dialect/clickhouse.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/dialect/clickhouse_chdb.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/dialect/config.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/dialect/dataframe.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/dialect/duckdb_uv.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/dialect/enums.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/dialect/metadata.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/dialect/mock.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/dialect/postgres.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/dialect/presto.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/dialect/python_source.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/dialect/results.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/dialect/snowflake.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/dialect/source_pushdown.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/dialect/sql_server.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/dialect/sqlite.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/engine.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/execution/__init__.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/execution/config.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/execution/envs.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/execution/model_fingerprint.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/execution/report.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/execution/state/AGENTS.md +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/execution/state/CLAUDE.md +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/execution/state/__init__.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/execution/state/cache.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/execution/state/exceptions.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/execution/state/isolation.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/execution/state/partitions.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/execution/state/persistence.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/execution/state/phases.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/execution/state/snapshot.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/execution/state/state_store.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/execution/state/watermarks.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/executor.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/hooks/__init__.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/hooks/base_hook.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/hooks/graph_hook.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/hooks/query_debugger.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/io/__init__.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/io/adapters.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/io/arrow.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/io/click_support.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/io/contract.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/io/describe.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/io/errors.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/io/runner.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/io/sinks.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/metadata/__init__.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/parser.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/parsing/README.md +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/parsing/__init__.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/parsing/common.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/parsing/config.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/parsing/exceptions.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/parsing/helpers.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/parsing/parse_engine_v2.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/parsing/pretty.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/parsing/render.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/parsing/trilogy.lark +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/parsing/v2/README.md +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/parsing/v2/__init__.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/parsing/v2/concept_factory.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/parsing/v2/concept_syntax.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/parsing/v2/errors.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/parsing/v2/function_syntax.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/parsing/v2/hydration.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/parsing/v2/import_service.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/parsing/v2/lark_backend.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/parsing/v2/model.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/parsing/v2/pest_backend.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/parsing/v2/rowset_semantics.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/parsing/v2/rules/__init__.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/parsing/v2/rules/chart_rules.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/parsing/v2/rules/concept_rules.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/parsing/v2/rules/conditional_rules.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/parsing/v2/rules/datasource_rules.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/parsing/v2/rules/expression_rules.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/parsing/v2/rules/function_definition_rules.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/parsing/v2/rules/function_rules.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/parsing/v2/rules/import_rules.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/parsing/v2/rules/merge_rules.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/parsing/v2/rules/multiselect_rules.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/parsing/v2/rules/operational_rules.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/parsing/v2/rules/order_rules.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/parsing/v2/rules/persist_rules.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/parsing/v2/rules/rawsql_rules.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/parsing/v2/rules/rowset_rules.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/parsing/v2/rules/select_rules.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/parsing/v2/rules/select_statement_rules.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/parsing/v2/rules/statement_rules.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/parsing/v2/rules/subselect_rules.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/parsing/v2/rules/token_rules.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/parsing/v2/rules/tvf_rules.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/parsing/v2/rules/type_rules.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/parsing/v2/rules_context.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/parsing/v2/select_finalize.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/parsing/v2/semantic_scope.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/parsing/v2/semantic_state.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/parsing/v2/statement_planner.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/parsing/v2/statement_plans.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/parsing/v2/symbols.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/parsing/v2/syntax.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/py.typed +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/render.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/rendering/__init__.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/rendering/altair_renderer.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/rendering/base.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/rendering/chart_theme.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/rendering/rich_types.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/rendering/terminal_renderer.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/rendering/theme.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/report/__init__.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/report/backends/__init__.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/report/backends/base.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/report/backends/html.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/report/backends/png.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/report/charts.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/report/document.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/report/runner.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/report/tables.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/AGENTS.md +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/CLAUDE.md +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/README.md +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/__init__.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/agent.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/agent_info.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/agent_info_docs/__init__.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/agent_info_docs/content.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/agent_info_docs/directory.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/agent_sessions.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/agent_sql_tools.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/agent_tools.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/click_utils.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/cloud.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/cloud_models.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/common.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/database.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/dependency/README.md +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/dependency/build.sh +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/dependency/examples/basic_usage.rs +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/dependency/src/directory_resolver.rs +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/dependency/src/graph.rs +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/dependency/src/lib.rs +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/dependency/src/main.rs +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/dependency/src/network_search.rs +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/dependency/src/parser.rs +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/dependency/src/python_bindings.rs +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/dependency/src/resolver.rs +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/dependency/src/trilogy.pest +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/dependency/src/trilogy_parser.rs +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/dependency/tests/base.preql +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/dependency/tests/cli_integration.rs +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/dependency/tests/customer.preql +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/dependency/tests/main.preql +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/dependency/tests/orders.preql +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/dependency/tests/public_api.rs +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/dependency/tests/test_data/base.preql +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/dependency/tests/test_data/consumer.preql +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/dependency.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/display.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/display_core.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/display_execution.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/display_ingest.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/display_init.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/display_models.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/display_parallel.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/display_refresh.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/display_validation.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/env_commands.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/environment.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/explore_seen.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/file_helpers/__init__.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/file_helpers/backends.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/file_helpers/preql_description.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/file_helpers/preql_validation.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/fmt.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/ingest.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/ingest_helpers/__init__.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/ingest_helpers/fk_inference.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/ingest_helpers/foreign_keys.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/ingest_helpers/formatting.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/ingest_helpers/introspection.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/ingest_helpers/typing.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/init.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/parallel_execution.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/plan.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/project_config.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/public.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/refresh.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/render.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/run.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/serve.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/serve_helpers/__init__.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/serve_helpers/connection_spec.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/serve_helpers/file_discovery.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/serve_helpers/index_generation.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/serve_helpers/jobs.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/serve_helpers/models.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/serve_helpers/state_cache.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/serve_helpers/state_computation.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/serve_helpers/studio_bundle.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/single_execution.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/source.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/source_identity.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/state.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/testing.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/trilogy.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/scripts/validate_agent.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/staging.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/std/__init__.py +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/std/chart.preql +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/std/color.preql +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/std/currency.preql +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/std/date.preql +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/std/display.preql +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/std/geography.preql +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/std/metric.preql +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/std/money.preql +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/std/net.preql +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/std/ranking.preql +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/std/report.preql +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/std/semantic.preql +0 -0
- {pytrilogy-0.3.332 → pytrilogy-0.3.334}/trilogy/utility.py +0 -0
|
@@ -26,24 +26,20 @@ parameter NAME TYPE [default <literal>]; — a runtime value supplied via `--par
|
|
|
26
26
|
|
|
27
27
|
### Query-scoped join
|
|
28
28
|
|
|
29
|
-
A typical fact already has its dimensions merged in
|
|
29
|
+
A typical fact already has its dimensions merged in, so no join is needed. Blending fact models or rowset outputs takes a scoped join, placed right after the select list, which DECLARES how the key domains relate: `subset join a = b` (a's values are contained in b's, a ⊆ b; b authoritative for the key) or `union join a = b` (neither contains the other; the key is the coalesce of both sides and unmatched rows from BOTH sides are kept).
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
- `union join a = b` — neither domain contains the other; the key is the coalesce of both sides and unmatched rows from BOTH sides are kept.
|
|
31
|
+
Two rules decide whether the numbers are right, so apply them before reaching for the example:
|
|
33
32
|
|
|
34
|
-
|
|
33
|
+
- Joins NEVER drop a row and NULL keys match null-safely; there is NO inner join. An intersection is an explicit `where <optional-side attr> is not null`.
|
|
34
|
+
- JOIN ON THE FULL GRAIN: `explore` prints each fact's grain as @<k1, k2>; write one clause PER key. Matching only one key of a multi-key grain causes duplication.
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
Joins go right after the select list. Full example: trilogy agent-info syntax example scoped-join.
|
|
36
|
+
Chaining, expression keys, union/subset mixing, multi-key and self-pair shapes: trilogy agent-info syntax example scoped-join.
|
|
39
37
|
|
|
40
38
|
merge <a> into ~<b>; is the persistent (whole-file) equivalent of `subset join a = b`; plain `merge a into b;` declares EXACT domain equivalence. Standalone statements; prefer a scoped join unless the connection is universal.
|
|
41
39
|
|
|
42
40
|
### union / except / intersect (row set operations)
|
|
43
41
|
|
|
44
|
-
union(
|
|
45
|
-
|
|
46
|
-
except((armA), (armB), ...) -> (...) and intersect(...) share union's arm shape but are SQL SET operators: output rows are DISTINCT, whole rows compare null-safely, and except subtracts later arms from the FIRST (arm order matters). Prefer except over multi-column `not in` for "in A but never in B". Example: trilogy agent-info syntax example except-intersect-setops.
|
|
42
|
+
`union(...)` row-stacks self-contained select arms positionally (SQL UNION ALL) into one named rowset (`with combined as union((armA), (armB), ...) -> (out1, out2, ...)`); `except(...)` / `intersect(...)` share that arm shape but are SQL SET operators (DISTINCT rows, null-safe whole-row compare, and except subtracts later arms from the FIRST, so arm order matters). Prefer except over a multi-column `not in` for "in A but never in B". Each arm dedups to its own output grain BEFORE stacking, so aggregate INSIDE each arm or the total silently undersums. Examples: trilogy agent-info syntax example union-stack-channels / except-intersect-setops.
|
|
47
43
|
|
|
48
44
|
## Query structure
|
|
49
45
|
|
|
@@ -94,12 +94,7 @@ order by index;
|
|
|
94
94
|
SyntaxExample(
|
|
95
95
|
name="query-structure",
|
|
96
96
|
title="Full query structure - every clause and where it goes (+ rowsets)",
|
|
97
|
-
summary=
|
|
98
|
-
"the clause order of a query (`where` -> `select` <cols> -> join(s) -> "
|
|
99
|
-
"`having` -> `order by` -> `limit`) and how to define a rowset (a NAME "
|
|
100
|
-
"then a select); joins sit right after the select list - filter a "
|
|
101
|
-
"joined or aggregated RESULT in `having`, input rows in `where`"
|
|
102
|
-
),
|
|
97
|
+
summary="the exact clause order of a query, and how to define a rowset",
|
|
103
98
|
body="""\
|
|
104
99
|
# Every Trilogy query has the SAME fixed skeleton. Top-level statements come
|
|
105
100
|
# first (each ends with `;`), then ONE query whose clauses appear in this exact
|
|
@@ -169,9 +164,8 @@ limit 100;
|
|
|
169
164
|
name="filtered-aggregate",
|
|
170
165
|
title="Filtered aggregate - aggregate only the rows matching a condition",
|
|
171
166
|
summary=(
|
|
172
|
-
"
|
|
173
|
-
"
|
|
174
|
-
"when several keys identify it; `by <grain>` pins the aggregate's grain"
|
|
167
|
+
"aggregating only the rows matching a condition, and counting rows "
|
|
168
|
+
"correctly"
|
|
175
169
|
),
|
|
176
170
|
body="""\
|
|
177
171
|
# `?` is a local filter - a filter that applies only to the prior expression-
|
|
@@ -207,11 +201,7 @@ order by iris.species asc;
|
|
|
207
201
|
"Row-level filter (WHERE) vs aggregate filter (HAVING) - don't wrap a "
|
|
208
202
|
"per-row threshold in max()/min()"
|
|
209
203
|
),
|
|
210
|
-
summary=
|
|
211
|
-
"a plain per-ROW condition (`x.col > N`) goes in WHERE (filters the rows "
|
|
212
|
-
"feeding every aggregate); HAVING filters an aggregate RESULT. "
|
|
213
|
-
"`max(col) by g > N` in HAVING filters GROUPS, not rows - different meaning"
|
|
214
|
-
),
|
|
204
|
+
summary="choosing between WHERE and HAVING for a threshold condition",
|
|
215
205
|
body="""\
|
|
216
206
|
# A non-aggregate, per-ROW condition belongs in WHERE - it filters the rows that
|
|
217
207
|
# feed every aggregate, BEFORE grouping. HAVING is ONLY for filtering on an
|
|
@@ -396,12 +386,7 @@ order by enroll.year asc nulls first;
|
|
|
396
386
|
SyntaxExample(
|
|
397
387
|
name="union-stack-channels",
|
|
398
388
|
title="Stack rows from several sources/channels with the union(...) TVF",
|
|
399
|
-
summary=
|
|
400
|
-
"`with combined as union((armA), (armB), (armC), ...) -> (o1, o2, ...)` "
|
|
401
|
-
"row-STACKS self-contained inline selects positionally (SQL UNION ALL) - "
|
|
402
|
-
"the PREFERRED way to combine channels/sources; pass TWO OR MORE arms, one "
|
|
403
|
-
"per source; reference outputs as `combined.o1`"
|
|
404
|
-
),
|
|
389
|
+
summary="stacking several sources/channels together as rows",
|
|
405
390
|
body="""\
|
|
406
391
|
# `union(...)` is a relational table-valued function: it STACKS the rows of TWO OR
|
|
407
392
|
# MORE self-contained `select` arms, positionally (like SQL `UNION ALL`), into one
|
|
@@ -476,14 +461,7 @@ limit 100;
|
|
|
476
461
|
SyntaxExample(
|
|
477
462
|
name="except-intersect-setops",
|
|
478
463
|
title="Set difference / co-occurrence across sources with except(...) / intersect(...)",
|
|
479
|
-
summary=
|
|
480
|
-
"`with only_a as except((armA), (armB)) -> (o1, o2)` keeps the distinct "
|
|
481
|
-
"rows of the FIRST arm that appear in NO later arm (SQL EXCEPT); "
|
|
482
|
-
"`intersect(...)` keeps rows present in EVERY arm. PREFERRED over "
|
|
483
|
-
"multi-column `not in` for 'in A but not B' questions when you also "
|
|
484
|
-
"want the distinct combinations themselves: whole ROWS are compared "
|
|
485
|
-
"(any column mix) and the output is deduplicated"
|
|
486
|
-
),
|
|
464
|
+
summary="set difference or co-occurrence across sources",
|
|
487
465
|
body="""\
|
|
488
466
|
# `except(...)` and `intersect(...)` are relational table-valued functions with the
|
|
489
467
|
# SAME shape as `union(...)`: TWO OR MORE inline self-contained select arms, matched
|
|
@@ -529,12 +507,7 @@ limit 100;
|
|
|
529
507
|
SyntaxExample(
|
|
530
508
|
name="scoped-join",
|
|
531
509
|
title="Blend two models in one query with a scoped subset/union join",
|
|
532
|
-
summary=
|
|
533
|
-
"`select <cols> subset|union join a.key = b.key (= other.key ...)?` (right after "
|
|
534
|
-
"the select list) blends a second model into ONE query - the PREFERRED "
|
|
535
|
-
"alternative to `merge`. JOIN ON THE FULL GRAIN: one clause per key in "
|
|
536
|
-
"the shared `@<k1, k2>` grain"
|
|
537
|
-
),
|
|
510
|
+
summary="blending a second fact model or rowset into one query",
|
|
538
511
|
body="""\
|
|
539
512
|
# A query-scoped `join` blends a second model into ONE select without editing the
|
|
540
513
|
# model files (the query-local equivalent of `merge`). A join DECLARES how the
|
|
@@ -643,11 +616,7 @@ limit 100;
|
|
|
643
616
|
SyntaxExample(
|
|
644
617
|
name="existence-anti-join",
|
|
645
618
|
title="Existence / anti-join across models",
|
|
646
|
-
summary=(
|
|
647
|
-
"keep or exclude rows by whether a key matches another model: "
|
|
648
|
-
"`key in other.key` (semi-join) / `not in` (anti-join); a MULTI-part "
|
|
649
|
-
"key uses a row-wise tuple `(a, b) in (set.a, set.b)`"
|
|
650
|
-
),
|
|
619
|
+
summary=("keeping or excluding rows by whether a key matches another model"),
|
|
651
620
|
body="""\
|
|
652
621
|
# `in` / `not in` against another model's key is the semi-join / anti-join
|
|
653
622
|
# idiom - no manual JOIN. Use it instead of `count(...) is null` hacks.
|
|
@@ -757,12 +726,7 @@ order by unique_sc.course asc;
|
|
|
757
726
|
SyntaxExample(
|
|
758
727
|
name="rollup",
|
|
759
728
|
title="Subtotals + grand total in one pass with `by rollup (…)`",
|
|
760
|
-
summary=
|
|
761
|
-
"the select-level `by rollup (d1, d2)` clause computes EVERY aggregate "
|
|
762
|
-
"in the select at every level (leaf, per-d1 subtotal, grand total) in one "
|
|
763
|
-
"pass; `grouping(d)` = 1 on a rolled-up row - use it to LABEL "
|
|
764
|
-
"subtotal/total rows and to sort by level"
|
|
765
|
-
),
|
|
729
|
+
summary="subtotals and a grand total in one pass, and labeling the levels",
|
|
766
730
|
body="""\
|
|
767
731
|
# A `by rollup (d1, d2)` clause AFTER the select list (before having/order by)
|
|
768
732
|
# computes the whole select at MULTIPLE grain levels in one pass - the grouping
|
|
@@ -858,10 +822,7 @@ limit 100;
|
|
|
858
822
|
SyntaxExample(
|
|
859
823
|
name="staged-membership",
|
|
860
824
|
title="Stage a coarse-grain membership set, then filter a fine-grain query",
|
|
861
|
-
summary=(
|
|
862
|
-
"compute a membership set in a `rowset` (keys meeting a count/HAVING), "
|
|
863
|
-
"then filter the main query with `<key> in <rowset>.<col>`"
|
|
864
|
-
),
|
|
825
|
+
summary=("filtering a fine-grain query by a set computed at a coarser grain"),
|
|
865
826
|
body="""\
|
|
866
827
|
# When a query filters on a condition computed at a COARSER grain (e.g. "items
|
|
867
828
|
# sold in all 3 channels", "courses offered in more than one year"), compute that
|
|
@@ -3607,6 +3607,12 @@ class Factory:
|
|
|
3607
3607
|
self._build_over_items(list(grouping_set))
|
|
3608
3608
|
for grouping_set in grouping_sets_source
|
|
3609
3609
|
]
|
|
3610
|
+
if grouping != AggregateGroupingMode.STANDARD and not by and not grouping_sets:
|
|
3611
|
+
# A rollup/cube over zero keys has exactly one grouping set - the
|
|
3612
|
+
# grand total - which is what a standard grouping with no keys
|
|
3613
|
+
# already renders. `by rollup ()` on a grainless select (only
|
|
3614
|
+
# constants and aggregates projected) lands here.
|
|
3615
|
+
grouping = AggregateGroupingMode.STANDARD
|
|
3610
3616
|
if grouping == AggregateGroupingMode.STANDARD:
|
|
3611
3617
|
by = sorted(by, key=lambda x: x.address)
|
|
3612
3618
|
|
|
@@ -652,11 +652,10 @@ def constant_domain_violation(
|
|
|
652
652
|
comparison provably never match; None when satisfiable or undecidable.
|
|
653
653
|
|
|
654
654
|
Only provably-FALSE predicates are flagged. In-domain predicates — even
|
|
655
|
-
ones matching every declared value — must parse untouched:
|
|
656
|
-
load-bearing join null-rejection
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
legitimate. Error messages must never advise removing a predicate."""
|
|
655
|
+
ones matching every declared value — must parse untouched: through a
|
|
656
|
+
nullable FK they carry load-bearing join null-rejection, and a narrower
|
|
657
|
+
authored intent than the current domain snapshot is legitimate. Error
|
|
658
|
+
messages must never advise removing a predicate."""
|
|
660
659
|
while isinstance(expected, TraitDataType):
|
|
661
660
|
expected = expected.type
|
|
662
661
|
if isinstance(value, Enum):
|
|
@@ -1196,11 +1196,17 @@ class QueryDatasource:
|
|
|
1196
1196
|
|
|
1197
1197
|
@property
|
|
1198
1198
|
def effective_grain(self) -> BuildGrain:
|
|
1199
|
+
# A NULL-padded key is absence, not a row identity: an anti-join
|
|
1200
|
+
# (`orders.id is null`) declares the preserved side's grain but still
|
|
1201
|
+
# projects the rejected key, and counting that key here re-inflates the
|
|
1202
|
+
# grain to the pre-join side and forces a regroup that dedups nothing.
|
|
1203
|
+
nullable = {concept.address for concept in self.nullable_concepts}
|
|
1199
1204
|
key_outputs = {
|
|
1200
1205
|
concept.address
|
|
1201
1206
|
for concept in self.output_concepts
|
|
1202
1207
|
if concept.purpose == Purpose.KEY
|
|
1203
1208
|
and concept.name != RECURSIVE_GATING_CONCEPT
|
|
1209
|
+
and concept.address not in nullable
|
|
1204
1210
|
}
|
|
1205
1211
|
return self.grain + BuildGrain(components=key_outputs)
|
|
1206
1212
|
|
|
@@ -1422,12 +1428,22 @@ class QueryDatasource:
|
|
|
1422
1428
|
limited = f"_limited_{self.limit}"
|
|
1423
1429
|
if self.ordering:
|
|
1424
1430
|
limited += f"_{string_to_hash(str(self.ordering))}"
|
|
1431
|
+
# An UNNEST in the FROM is identity for the mirror-image reason a limit
|
|
1432
|
+
# is: the unnested source is a row MULTIPLE of the same shape without
|
|
1433
|
+
# it, so the two must never collide and merge (``__add__`` rejects the
|
|
1434
|
+
# mismatch rather than silently folding an unnest into a plain scan).
|
|
1435
|
+
unnested = ""
|
|
1436
|
+
if self.join_derived_concepts:
|
|
1437
|
+
unnested = "_unnest_" + "_".join(
|
|
1438
|
+
sorted(c.address.replace(".", "_") for c in self.join_derived_concepts)
|
|
1439
|
+
)
|
|
1425
1440
|
return (
|
|
1426
1441
|
"_join_".join(sorted(d.identifier for d in self.datasources))
|
|
1427
1442
|
+ group
|
|
1428
1443
|
+ (f"_at_{grain}" if grain else "_at_abstract")
|
|
1429
1444
|
+ (f"_filtered_by_{filters}" if filters else "")
|
|
1430
1445
|
+ limited
|
|
1446
|
+
+ unnested
|
|
1431
1447
|
)
|
|
1432
1448
|
|
|
1433
1449
|
def get_alias(
|
|
@@ -525,16 +525,77 @@ def side_nullable(concept: BuildConcept, side: DataSource | None) -> bool:
|
|
|
525
525
|
return bool(args & nullable_addrs)
|
|
526
526
|
|
|
527
527
|
|
|
528
|
+
def _side_outputs(concept: BuildConcept, side: DataSource) -> bool:
|
|
529
|
+
equivalent = concept.equivalent_addresses
|
|
530
|
+
return any(equivalent & c.equivalent_addresses for c in side.output_concepts)
|
|
531
|
+
|
|
532
|
+
|
|
533
|
+
def nulls_are_values(
|
|
534
|
+
concept: BuildConcept,
|
|
535
|
+
side: DataSource,
|
|
536
|
+
_seen: frozenset[tuple[str, int]] = frozenset(),
|
|
537
|
+
) -> bool:
|
|
538
|
+
"""Whether the NULLs this side carries for ``concept`` are VALUES (a `?`
|
|
539
|
+
column, a nullable derivation, a nullable input to a null-propagating
|
|
540
|
+
expression, a ROLLUP grouping key) rather than pure outer-join extension.
|
|
541
|
+
|
|
542
|
+
Outer-join extension means *absent*: there is no row on that side, so no
|
|
543
|
+
key. Pairing that against a real NULL group cross-joins the two (q30: 311
|
|
544
|
+
padded address rows x 20 unknown-customer groups = 6,220)."""
|
|
545
|
+
if concept.is_nullable:
|
|
546
|
+
return True
|
|
547
|
+
# Argument chains can be mutually recursive (q25); a repeat visit of the
|
|
548
|
+
# same concept on the same source contributes nothing new.
|
|
549
|
+
visit = (concept.address, id(side))
|
|
550
|
+
if visit in _seen:
|
|
551
|
+
return False
|
|
552
|
+
seen = _seen | {visit}
|
|
553
|
+
equivalent = concept.equivalent_addresses
|
|
554
|
+
if isinstance(side, BuildDatasource):
|
|
555
|
+
# Column-level `?` is the only value-NULL source on a physical table.
|
|
556
|
+
return any(
|
|
557
|
+
equivalent & nc.equivalent_addresses for nc in side.nullable_concepts
|
|
558
|
+
)
|
|
559
|
+
# A grouping-set NULL is padding too, but a twin-rollup partner pads the
|
|
560
|
+
# same key, so it stays pairable here; get_join_type handles the mismatch.
|
|
561
|
+
if equivalent & rollup_padded_addresses(side):
|
|
562
|
+
return True
|
|
563
|
+
carriers = [p for p in side.datasources if _side_outputs(concept, p)]
|
|
564
|
+
if not carriers:
|
|
565
|
+
# Nothing upstream to attribute the NULL to; stay conservative rather
|
|
566
|
+
# than call an unexplained nullability extension.
|
|
567
|
+
return True
|
|
568
|
+
if any(nulls_are_values(concept, p, seen) for p in carriers):
|
|
569
|
+
return True
|
|
570
|
+
if not propagates_argument_nulls(concept):
|
|
571
|
+
return False
|
|
572
|
+
args = {a.address for a in concept.concept_arguments}
|
|
573
|
+
if not args:
|
|
574
|
+
return False
|
|
575
|
+
return any(
|
|
576
|
+
(args & nc.equivalent_addresses) and nulls_are_values(nc, side, seen)
|
|
577
|
+
for nc in side.nullable_concepts
|
|
578
|
+
)
|
|
579
|
+
|
|
580
|
+
|
|
528
581
|
def get_modifiers(
|
|
529
582
|
left_concept: BuildConcept,
|
|
530
583
|
right_concept: BuildConcept,
|
|
531
584
|
left: DataSource | None,
|
|
532
585
|
right: DataSource | None,
|
|
533
586
|
) -> list[Modifier]:
|
|
534
|
-
"""Use null-safe equality only when both exposed join keys can be NULL.
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
587
|
+
"""Use null-safe equality only when both exposed join keys can be NULL.
|
|
588
|
+
|
|
589
|
+
Asymmetric padding is the exception: when one side's NULLs are outer-join
|
|
590
|
+
extension (absence) and the other's are values, they name nothing in
|
|
591
|
+
common and null-safe equality cross-joins them. Both sides extended is the
|
|
592
|
+
ordinary case again: the padding shares provenance, so those rows pair."""
|
|
593
|
+
if not (side_nullable(left_concept, left) and side_nullable(right_concept, right)):
|
|
594
|
+
return []
|
|
595
|
+
assert left is not None and right is not None
|
|
596
|
+
if nulls_are_values(left_concept, left) != nulls_are_values(right_concept, right):
|
|
597
|
+
return []
|
|
598
|
+
return [Modifier.NULLABLE]
|
|
538
599
|
|
|
539
600
|
|
|
540
601
|
def _collect_deep_partial_addresses(
|
|
@@ -177,6 +177,10 @@ def get_all_parent_nullable(
|
|
|
177
177
|
|
|
178
178
|
class StrategyNode:
|
|
179
179
|
source_type = SourceType.ABSTRACT
|
|
180
|
+
# A node that only projects or filters emits its parents' rows. Subclasses
|
|
181
|
+
# that set this take their parents' grain when none was passed, rather than
|
|
182
|
+
# deriving one from their own outputs; see `_default_grain`.
|
|
183
|
+
inherits_parent_grain: bool = False
|
|
180
184
|
|
|
181
185
|
def __init__(
|
|
182
186
|
self,
|
|
@@ -539,14 +543,37 @@ class StrategyNode:
|
|
|
539
543
|
source_map[concept.address] = {ps}
|
|
540
544
|
break
|
|
541
545
|
|
|
546
|
+
def _default_grain(
|
|
547
|
+
self, parent_sources: list[QueryDatasource | BuildDatasource]
|
|
548
|
+
) -> BuildGrain:
|
|
549
|
+
"""The grain to declare when the planner passed none.
|
|
550
|
+
|
|
551
|
+
Deriving it from ``output_concepts`` states the grain the projection
|
|
552
|
+
*selects*, which is only the row grain if something deduped to it. For a
|
|
553
|
+
row-preserving node nothing did, so it reports its parents' rows: a
|
|
554
|
+
narrowing projection that claims the narrow grain reads as already
|
|
555
|
+
deduped, and consumers skip the GROUP BY that would make it true.
|
|
556
|
+
"""
|
|
557
|
+
if self.inherits_parent_grain and parent_sources and not self.force_group:
|
|
558
|
+
# An existence feeder is read through a subselect: it rejects rows,
|
|
559
|
+
# it never supplies them, so its grain is not part of ours.
|
|
560
|
+
existence = {concept.address for concept in self.existence_concepts}
|
|
561
|
+
inherited = BuildGrain()
|
|
562
|
+
for source in parent_sources:
|
|
563
|
+
supplied = {concept.address for concept in source.output_concepts}
|
|
564
|
+
if existence and supplied <= existence:
|
|
565
|
+
continue
|
|
566
|
+
inherited += source.grain
|
|
567
|
+
if inherited.components:
|
|
568
|
+
return inherited
|
|
569
|
+
return BuildGrain.from_concepts(self.output_concepts)
|
|
570
|
+
|
|
542
571
|
def _resolve(self) -> QueryDatasource:
|
|
543
572
|
parent_sources: list[QueryDatasource | BuildDatasource] = [
|
|
544
573
|
p.resolve() for p in self.parents
|
|
545
574
|
]
|
|
546
575
|
|
|
547
|
-
grain = (
|
|
548
|
-
self.grain if self.grain else BuildGrain.from_concepts(self.output_concepts)
|
|
549
|
-
)
|
|
576
|
+
grain = self.grain if self.grain else self._default_grain(parent_sources)
|
|
550
577
|
source_map = resolve_concept_map(
|
|
551
578
|
parent_sources,
|
|
552
579
|
targets=self.output_concepts,
|
|
@@ -1783,16 +1783,37 @@ def _consumer_required_input_grain(
|
|
|
1783
1783
|
# a raw scan with it is unrenderable. The parent's grain (added below) is
|
|
1784
1784
|
# the joinable identity.
|
|
1785
1785
|
parent_computed: set[str] = set()
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
if
|
|
1790
|
-
|
|
1786
|
+
row_preds = [
|
|
1787
|
+
pred
|
|
1788
|
+
for pred in group_graph.predecessors(gid)
|
|
1789
|
+
if pred != FINAL_NODE_ID
|
|
1790
|
+
and pred in attrs
|
|
1791
|
+
and edge_kind(group_edges, pred, gid) != EdgeKind.EXISTENCE
|
|
1792
|
+
]
|
|
1793
|
+
for pred in row_preds:
|
|
1791
1794
|
if (
|
|
1792
1795
|
attrs[pred].derivation in GROUPING_DERIVATIONS
|
|
1793
1796
|
or attrs[pred].derivation == Derivation.ROWSET
|
|
1794
1797
|
):
|
|
1795
|
-
|
|
1798
|
+
# A pred whose row stream reaches this consumer through a GROUPING
|
|
1799
|
+
# descendant pred that grouped the axis away has no such axis at
|
|
1800
|
+
# this merge: requiring it resurrects the raw pred as a parent CTE
|
|
1801
|
+
# beside the descendant, and the two share no joinable key (rollup
|
|
1802
|
+
# over union-joined rowsets: the raw `r` rowset beside the rollup
|
|
1803
|
+
# aggregate, whose ROLLUP grain is `channel` only). The
|
|
1804
|
+
# descendant's own grain, declared below on its own iteration, is
|
|
1805
|
+
# the merge axis.
|
|
1806
|
+
pred_grain = set(attrs[pred].grain_components)
|
|
1807
|
+
axis_grouped_away = any(
|
|
1808
|
+
other != pred
|
|
1809
|
+
and pred in nx.ancestors(group_graph, other)
|
|
1810
|
+
and attrs[other].derivation in GROUPING_DERIVATIONS
|
|
1811
|
+
and not (pred_grain <= set(attrs[other].output_concepts))
|
|
1812
|
+
for other in row_preds
|
|
1813
|
+
)
|
|
1814
|
+
if axis_grouped_away:
|
|
1815
|
+
continue
|
|
1816
|
+
grain |= pred_grain
|
|
1796
1817
|
return frozenset(grain - parent_computed)
|
|
1797
1818
|
|
|
1798
1819
|
|
|
@@ -2271,6 +2292,21 @@ def _compute_concept_sets(
|
|
|
2271
2292
|
pseudonym_mates = {k: frozenset(v) for k, v in mate_accumulator.items()}
|
|
2272
2293
|
|
|
2273
2294
|
io = GroupIOPlan.for_groups(group_graph)
|
|
2295
|
+
# Non-ROWSET members of authored statement relations that NO group hosts:
|
|
2296
|
+
# the axis vocabulary a fresh scan may advertise below. A member some group
|
|
2297
|
+
# already carries as a primary needs no re-sourcing, and advertising it
|
|
2298
|
+
# there only widens the scan and the merge keys with equalities the fact
|
|
2299
|
+
# grain already determines.
|
|
2300
|
+
scan_advertisable_members: list[str] = []
|
|
2301
|
+
if environment is not None:
|
|
2302
|
+
for member in sorted(_statement_scoped_relation_members(environment)):
|
|
2303
|
+
member_concept = environment.concepts.get(member)
|
|
2304
|
+
if (
|
|
2305
|
+
member_concept is not None
|
|
2306
|
+
and member_concept.derivation != Derivation.ROWSET
|
|
2307
|
+
and member not in all_primary_members
|
|
2308
|
+
):
|
|
2309
|
+
scan_advertisable_members.append(member)
|
|
2274
2310
|
for gid in topo:
|
|
2275
2311
|
if gid == FINAL_NODE_ID:
|
|
2276
2312
|
continue
|
|
@@ -2279,6 +2315,20 @@ def _compute_concept_sets(
|
|
|
2279
2315
|
if fact.behavior is None or fact.derivation == Derivation.ROOT:
|
|
2280
2316
|
for addr in list(cap):
|
|
2281
2317
|
cap.update(source_grain_of.get(addr, frozenset()))
|
|
2318
|
+
# A fresh scan can re-source an authored scoped-join axis member
|
|
2319
|
+
# its columns FD-determine (`billing_customer.sk` determines the
|
|
2320
|
+
# unique `billing_customer.id` a `subset join cust.cid = ...id`
|
|
2321
|
+
# names). Advertise it so the demand rules can elect the axis for
|
|
2322
|
+
# the merge; without it the address intersection fails and the
|
|
2323
|
+
# FINAL merge loses the authored join key (all_sales pivot).
|
|
2324
|
+
# Rowset handles are excluded: a scan that absorbs one would drop
|
|
2325
|
+
# the rowset's internal filter.
|
|
2326
|
+
if environment is not None:
|
|
2327
|
+
for member in scan_advertisable_members:
|
|
2328
|
+
if member not in cap and build_fd_determines(
|
|
2329
|
+
environment, cap, member, include_empty_grain=False
|
|
2330
|
+
):
|
|
2331
|
+
cap.add(member)
|
|
2282
2332
|
io.capability[gid] = cap
|
|
2283
2333
|
continue
|
|
2284
2334
|
# A grouping group's grain component that is a STATEMENT-scoped join axis
|