pytrilogy 0.3.483__tar.gz → 0.3.485__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.483 → pytrilogy-0.3.485}/PKG-INFO +1 -1
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/__init__.py +1 -1
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/graph_models.py +9 -4
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/v4_helper/group_graph.py +105 -71
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/v4_helper/network_build.py +16 -4
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/v4_helper/network_model.py +5 -4
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/v4_helper/network_search.py +93 -19
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/validation/datasource.py +21 -2
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/execution/assertions.py +63 -17
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/cloud.py +12 -1
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/dependency/Cargo.lock +1 -1
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/dependency/Cargo.toml +1 -1
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/.scripts/__init__.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/.scripts/build_backend.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/.scripts/sync_version.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/LICENSE.md +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/README.md +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/pyproject.toml +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/ai/README.md +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/ai/__init__.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/ai/constants.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/ai/conversation.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/ai/enums.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/ai/execute.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/ai/models.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/ai/prompts.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/ai/providers/__init__.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/ai/providers/anthropic.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/ai/providers/base.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/ai/providers/deepseek.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/ai/providers/google.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/ai/providers/openai.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/ai/providers/openrouter.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/ai/providers/utils.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/ai/syntax_examples.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/authoring/README.md +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/authoring/__init__.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/constants.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/README.md +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/__init__.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/assertions.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/average_parts.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/casts.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/constants.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/domain_graph.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/domain_validation.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/enums.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/env_processor.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/environment_helpers.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/ergonomics.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/exceptions.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/fingerprint.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/functions.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/grain_pin.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/graph.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/having_normalization.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/internal.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/like_patterns.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/models/__init__.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/models/author.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/models/build.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/models/build_environment.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/models/copying.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/models/core.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/models/datasource.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/models/environment.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/models/execute.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/models/keyspace.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/optimization.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/optimizations/__init__.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/optimizations/atom_contract.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/optimizations/base_optimization.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/optimizations/collapse_single_parent.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/optimizations/existence_having_fold.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/optimizations/filtered_aggregate.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/optimizations/full_join_lowering.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/optimizations/hide_unused_concept.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/optimizations/identity_group.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/optimizations/inline_datasource.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/optimizations/join_hoist.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/optimizations/join_upgrade.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/optimizations/merge_irrelevant_group_by.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/optimizations/null_safe_join.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/optimizations/order_inner_joins.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/optimizations/predicate_pushdown.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/optimizations/reuse_parent_lookup.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/optimizations/semi_join_pushdown.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/optimizations/strip_redundant_not_null.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/optimizations/union_dim_pushdown.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/optimizations/utils.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/optimizations/value_set_join_upgrade.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/README.md +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/__init__.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/aggregate_rollup.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/basic_graph.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/concept_strategies_v4.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/condition_utility.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/constants.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/discovery_utility.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/discovery_validation.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/grain_utility.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/join_key_groups.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/join_resolution.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/model_ambiguity.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/node_generators/__init__.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/node_generators/common.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/node_generators/presence_probe.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/node_generators/select_helpers/__init__.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/node_generators/select_helpers/condition_routing.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/node_generators/select_helpers/datasource_injection.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/node_generators/select_helpers/datasource_nodes.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/node_generators/select_helpers/source_scoring.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/node_generators/select_merge_node.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/node_generators/select_node.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/nodes/README.md +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/nodes/__init__.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/nodes/base_node.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/nodes/filter_node.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/nodes/group_node.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/nodes/merge_node.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/nodes/recursive_node.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/nodes/select_node_v2.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/nodes/subselect_node.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/nodes/union_node.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/nodes/unnest_node.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/nodes/window_node.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/null_provenance.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/partial_bridging.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/plan_trace.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/plan_trace_model.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/relation_rollup.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/scan_partials.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/source_dominance.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/statement_scope.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/utility.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/v4_helper/__init__.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/v4_helper/concept_graph.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/v4_helper/condition_injection.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/v4_helper/condition_placement.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/v4_helper/constants.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/v4_helper/edges.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/v4_helper/extent_ownership.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/v4_helper/final_cover.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/v4_helper/functional_dependency.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/v4_helper/group_behaviors.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/v4_helper/group_rules.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/v4_helper/history.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/v4_helper/join_plan.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/v4_helper/keyspace.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/v4_helper/models.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/v4_helper/network_coalescing.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/v4_helper/network_obligations.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/v4_helper/network_topology.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/v4_helper/projection.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/v4_helper/region_domains.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/v4_helper/region_reads.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/v4_helper/renders.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/v4_helper/root_partition.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/v4_helper/source_planning.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/v4_helper/staged_where.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/v4_helper/strategy_builder.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/v4_helper/union_arms.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/v4_node_generators/__init__.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/v4_node_generators/aggregate.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/v4_node_generators/basic.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/v4_node_generators/common.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/v4_node_generators/condition_sources.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/v4_node_generators/constant.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/v4_node_generators/dispatch.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/v4_node_generators/filter.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/v4_node_generators/group_to.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/v4_node_generators/multiselect.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/v4_node_generators/nested_select.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/v4_node_generators/recursive.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/v4_node_generators/root.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/v4_node_generators/rowset.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/v4_node_generators/rowset_witness.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/v4_node_generators/subselect.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/v4_node_generators/union.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/v4_node_generators/union_select.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/v4_node_generators/unnest.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/processing/v4_node_generators/window.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/query_processor.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/scope_diagnostics.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/statements/README.md +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/statements/__init__.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/statements/author.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/statements/build.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/statements/common.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/statements/execute.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/table_processor.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/union_find.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/utility.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/validation/README.md +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/validation/__init__.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/validation/common.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/validation/concept.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/validation/environment.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/validation/fix.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/validation/rows.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/core/where_scope_normalization.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/dialect/__init__.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/dialect/base.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/dialect/bigquery.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/dialect/bigquery_engine.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/dialect/bigquery_persist.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/dialect/bigquery_staging.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/dialect/cancel.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/dialect/clickhouse.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/dialect/clickhouse_chdb.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/dialect/common.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/dialect/config.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/dialect/dataframe.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/dialect/duckdb.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/dialect/duckdb_pool.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/dialect/duckdb_uv.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/dialect/duckdb_vgi.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/dialect/enums.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/dialect/haybarn_engine.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/dialect/metadata.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/dialect/mock.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/dialect/mock_pattern.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/dialect/mysql.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/dialect/postgres.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/dialect/presto.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/dialect/python_source.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/dialect/results.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/dialect/snowflake.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/dialect/source_pushdown.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/dialect/sql_server.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/dialect/sqlite.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/dialect/table_function.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/engine.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/execution/__init__.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/execution/client_copy.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/execution/config.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/execution/envs.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/execution/model_fingerprint.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/execution/outputs.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/execution/report.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/execution/staged_write.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/execution/state/AGENTS.md +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/execution/state/CLAUDE.md +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/execution/state/__init__.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/execution/state/cache.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/execution/state/declaration.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/execution/state/exceptions.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/execution/state/isolation.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/execution/state/partitions.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/execution/state/persistence.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/execution/state/phases.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/execution/state/snapshot.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/execution/state/state_store.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/execution/state/watermarks.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/execution/write_order.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/executor.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/hooks/__init__.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/hooks/base_hook.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/hooks/graph_hook.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/hooks/query_debugger.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/io/__init__.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/io/adapters.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/io/arrow.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/io/click_support.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/io/contract.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/io/describe.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/io/errors.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/io/runner.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/io/sinks.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/io/vgi.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/metadata/__init__.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/parser.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/parsing/README.md +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/parsing/__init__.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/parsing/common.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/parsing/exceptions.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/parsing/helpers.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/parsing/parse_engine_v2.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/parsing/pretty.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/parsing/render.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/parsing/trilogy.lark +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/parsing/v2/README.md +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/parsing/v2/__init__.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/parsing/v2/concept_syntax.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/parsing/v2/errors.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/parsing/v2/function_syntax.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/parsing/v2/hydration.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/parsing/v2/import_service.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/parsing/v2/lark_backend.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/parsing/v2/model.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/parsing/v2/pest_backend.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/parsing/v2/rowset_semantics.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/parsing/v2/rules/__init__.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/parsing/v2/rules/chart_rules.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/parsing/v2/rules/concept_rules.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/parsing/v2/rules/conditional_rules.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/parsing/v2/rules/datasource_rules.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/parsing/v2/rules/expression_rules.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/parsing/v2/rules/function_definition_rules.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/parsing/v2/rules/function_rules.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/parsing/v2/rules/import_rules.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/parsing/v2/rules/merge_rules.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/parsing/v2/rules/multiselect_rules.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/parsing/v2/rules/operational_rules.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/parsing/v2/rules/order_rules.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/parsing/v2/rules/persist_rules.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/parsing/v2/rules/rawsql_rules.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/parsing/v2/rules/rowset_rules.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/parsing/v2/rules/select_rules.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/parsing/v2/rules/select_statement_rules.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/parsing/v2/rules/statement_rules.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/parsing/v2/rules/subselect_rules.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/parsing/v2/rules/token_rules.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/parsing/v2/rules/tvf_rules.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/parsing/v2/rules/type_rules.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/parsing/v2/rules_context.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/parsing/v2/select_finalize.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/parsing/v2/semantic_scope.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/parsing/v2/semantic_state.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/parsing/v2/statement_planner.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/parsing/v2/statement_plans.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/parsing/v2/symbols.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/parsing/v2/syntax.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/py.typed +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/render.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/rendering/__init__.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/rendering/altair_renderer.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/rendering/base.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/rendering/chart_theme.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/rendering/rich_types.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/rendering/terminal_renderer.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/rendering/theme.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/report/__init__.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/report/backends/__init__.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/report/backends/base.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/report/backends/html.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/report/backends/png.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/report/charts.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/report/document.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/report/runner.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/report/tables.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/AGENTS.md +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/CLAUDE.md +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/README.md +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/__init__.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/agent.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/agent_info.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/agent_info_docs/__init__.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/agent_info_docs/cli.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/agent_info_docs/content.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/agent_info_docs/directory.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/agent_sessions.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/agent_sql_tools.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/agent_tools.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/click_utils.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/cloud_models.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/common.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/database.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/dependency/README.md +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/dependency/build.sh +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/dependency/examples/basic_usage.rs +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/dependency/src/directory_resolver.rs +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/dependency/src/graph.rs +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/dependency/src/lib.rs +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/dependency/src/main.rs +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/dependency/src/network_search.rs +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/dependency/src/parser.rs +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/dependency/src/python_bindings.rs +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/dependency/src/resolver.rs +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/dependency/src/trilogy.pest +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/dependency/src/trilogy_parser.rs +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/dependency/tests/base.preql +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/dependency/tests/cli_integration.rs +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/dependency/tests/customer.preql +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/dependency/tests/main.preql +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/dependency/tests/orders.preql +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/dependency/tests/parse_cost.rs +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/dependency/tests/public_api.rs +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/dependency/tests/test_data/base.preql +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/dependency/tests/test_data/consumer.preql +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/dependency.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/display.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/display_core.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/display_execution.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/display_ingest.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/display_init.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/display_models.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/display_parallel.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/display_refresh.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/display_validation.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/env_commands.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/environment.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/explore.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/explore_seen.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/file.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/file_helpers/__init__.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/file_helpers/backends.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/file_helpers/preql_description.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/file_helpers/preql_validation.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/fmt.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/ingest.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/ingest_helpers/__init__.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/ingest_helpers/fk_inference.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/ingest_helpers/foreign_keys.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/ingest_helpers/formatting.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/ingest_helpers/introspection.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/ingest_helpers/typing.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/init.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/parallel_execution.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/plan.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/project_config.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/public.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/refresh.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/render.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/run.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/serve.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/serve_helpers/__init__.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/serve_helpers/connection_spec.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/serve_helpers/file_discovery.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/serve_helpers/index_generation.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/serve_helpers/jobs.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/serve_helpers/mcp_server.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/serve_helpers/models.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/serve_helpers/state_cache.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/serve_helpers/state_computation.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/serve_helpers/studio_bundle.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/single_execution.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/source.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/source_identity.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/state.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/testing.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/trilogy.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/scripts/validate_agent.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/staging.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/std/__init__.py +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/std/bytes.preql +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/std/chart.preql +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/std/collection.preql +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/std/color.preql +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/std/currency.preql +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/std/date.preql +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/std/display.preql +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/std/geography.preql +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/std/metric.preql +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/std/money.preql +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/std/net.preql +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/std/ranking.preql +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/std/report.preql +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/std/semantic.preql +0 -0
- {pytrilogy-0.3.483 → pytrilogy-0.3.485}/trilogy/utility.py +0 -0
|
@@ -132,6 +132,11 @@ def datasource_has_filter_sensitive_aggregate(
|
|
|
132
132
|
return True
|
|
133
133
|
|
|
134
134
|
|
|
135
|
+
def _reads_subselect(groups: Iterable[tuple[BuildConcept, ...]]) -> bool:
|
|
136
|
+
"""A literal `in (...)` list reports one empty existence group."""
|
|
137
|
+
return any(group for group in groups)
|
|
138
|
+
|
|
139
|
+
|
|
135
140
|
def _datasource_is_exact_match(
|
|
136
141
|
ds: BuildDatasource,
|
|
137
142
|
criteria: SearchCriteria,
|
|
@@ -158,7 +163,7 @@ def _datasource_is_exact_match(
|
|
|
158
163
|
requested_addresses = relevant_concepts or ds_output_addresses
|
|
159
164
|
if (
|
|
160
165
|
allow_filter_application
|
|
161
|
-
and not conditions.existence_arguments
|
|
166
|
+
and not _reads_subselect(conditions.existence_arguments)
|
|
162
167
|
and condition_addresses.issubset(ds_output_addresses)
|
|
163
168
|
and condition_addresses.issubset(requested_addresses)
|
|
164
169
|
) and requested_addresses.isdisjoint(partial_addresses):
|
|
@@ -173,7 +178,7 @@ def _datasource_is_exact_match(
|
|
|
173
178
|
has_aggregate_output
|
|
174
179
|
and partial_addresses
|
|
175
180
|
and allow_filter_application
|
|
176
|
-
and not conditions.existence_arguments
|
|
181
|
+
and not _reads_subselect(conditions.existence_arguments)
|
|
177
182
|
and condition_addresses
|
|
178
183
|
and condition_addresses.issubset(ds_output_addresses - partial_addresses)
|
|
179
184
|
):
|
|
@@ -188,7 +193,7 @@ def _datasource_is_exact_match(
|
|
|
188
193
|
has_aggregate_output
|
|
189
194
|
and canonical_to_concept is not None
|
|
190
195
|
and allow_filter_application
|
|
191
|
-
and not conditions.existence_arguments
|
|
196
|
+
and not _reads_subselect(conditions.existence_arguments)
|
|
192
197
|
and condition_addresses
|
|
193
198
|
):
|
|
194
199
|
ds_grain_components = set(ds.grain.components)
|
|
@@ -275,7 +280,7 @@ def _get_collective_condition_matches(
|
|
|
275
280
|
if not datasources:
|
|
276
281
|
return keep
|
|
277
282
|
for atom in decompose_condition(conditions.conditional):
|
|
278
|
-
if
|
|
283
|
+
if _reads_subselect(atom.existence_arguments):
|
|
279
284
|
return set()
|
|
280
285
|
if not is_scalar_condition(atom):
|
|
281
286
|
return set()
|
|
@@ -2344,7 +2344,13 @@ def build_group_graph(
|
|
|
2344
2344
|
environment,
|
|
2345
2345
|
rollup_padded,
|
|
2346
2346
|
)
|
|
2347
|
-
|
|
2347
|
+
grouping = _elect_grouping_providers(
|
|
2348
|
+
group_graph, group_edges, attrs, concept_attrs, environment
|
|
2349
|
+
)
|
|
2350
|
+
_state_projection_grains(attrs, buckets, grouping)
|
|
2351
|
+
_rehome_groups(
|
|
2352
|
+
group_graph, group_edges, attrs, buckets, concept_attrs, environment, grouping
|
|
2353
|
+
)
|
|
2348
2354
|
trace_group_graph(
|
|
2349
2355
|
"FINAL added, concept sets computed, sources regrafted",
|
|
2350
2356
|
group_graph,
|
|
@@ -2452,13 +2458,12 @@ def trace_group_graph(
|
|
|
2452
2458
|
@dataclass(frozen=True)
|
|
2453
2459
|
class RowProvider:
|
|
2454
2460
|
"""The row source a regraftable group is re-homed onto: the parent it
|
|
2455
|
-
reads, the
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2461
|
+
reads, the lineage parents that parent replaces, the dimension ROOT minted
|
|
2462
|
+
for it, and whether the parent renders the group inline. Once elected
|
|
2463
|
+
(`_as_rewrite`) it holds only what the graph lacks: `parent` is None when
|
|
2464
|
+
already a parent."""
|
|
2459
2465
|
|
|
2460
2466
|
parent: str | None
|
|
2461
|
-
grain: frozenset[str] | None = None
|
|
2462
2467
|
drop: frozenset[str] = frozenset()
|
|
2463
2468
|
minted: GroupBucket | None = None
|
|
2464
2469
|
# the parent renders the group in its own SELECT: the group folds into it
|
|
@@ -2473,7 +2478,6 @@ def _regraft_candidate(
|
|
|
2473
2478
|
*,
|
|
2474
2479
|
allow_partial: bool,
|
|
2475
2480
|
environment: BuildEnvironment | None = None,
|
|
2476
|
-
grain: frozenset[str] | None = None,
|
|
2477
2481
|
) -> str | None:
|
|
2478
2482
|
"""Find the richest row-compatible sibling to source `gid`'s inputs.
|
|
2479
2483
|
|
|
@@ -2506,8 +2510,7 @@ def _regraft_candidate(
|
|
|
2506
2510
|
merge.
|
|
2507
2511
|
"""
|
|
2508
2512
|
current = attrs[gid]
|
|
2509
|
-
|
|
2510
|
-
grain = current.grain_components
|
|
2513
|
+
grain = current.grain_components
|
|
2511
2514
|
needed = set(current.input_concepts)
|
|
2512
2515
|
if not needed:
|
|
2513
2516
|
return None
|
|
@@ -2586,14 +2589,16 @@ def _grain_needed_by_independent_sibling(
|
|
|
2586
2589
|
attrs: dict[str, GroupAttrs],
|
|
2587
2590
|
gid: str,
|
|
2588
2591
|
provider_gid: str,
|
|
2592
|
+
grouping: dict[str, str],
|
|
2589
2593
|
) -> bool:
|
|
2590
2594
|
"""Whether an independent FINAL-bound group co-grains on the provider's grain.
|
|
2591
2595
|
|
|
2592
2596
|
Grafting the projection onto the provider fuses it into that group, which
|
|
2593
2597
|
re-labels the provider's grouping key as this alias. Groups inside the
|
|
2594
|
-
provider's own lineage follow that relabeling,
|
|
2595
|
-
|
|
2596
|
-
|
|
2598
|
+
provider's own lineage follow that relabeling, and so does a projection
|
|
2599
|
+
placed at the same provider, but one that merges with it as a separate arm
|
|
2600
|
+
does not: it would look for a key that no longer exists and the merge
|
|
2601
|
+
would degenerate to a cross join.
|
|
2597
2602
|
"""
|
|
2598
2603
|
provider_grain = attrs[provider_gid].grain_components
|
|
2599
2604
|
if not provider_grain:
|
|
@@ -2601,6 +2606,7 @@ def _grain_needed_by_independent_sibling(
|
|
|
2601
2606
|
related = (
|
|
2602
2607
|
nx.ancestors(group_graph, provider_gid)
|
|
2603
2608
|
| nx.descendants(group_graph, provider_gid)
|
|
2609
|
+
| {g for g, p in grouping.items() if p == provider_gid}
|
|
2604
2610
|
| {gid, provider_gid, FINAL_NODE_ID}
|
|
2605
2611
|
)
|
|
2606
2612
|
for other in group_graph.nodes:
|
|
@@ -2680,7 +2686,6 @@ def _synthetic_dimension_regraft_parent(
|
|
|
2680
2686
|
buckets: dict[str, GroupBucket],
|
|
2681
2687
|
concept_attrs: dict[str, ConceptAttrs],
|
|
2682
2688
|
gid: str,
|
|
2683
|
-
grain: frozenset[str],
|
|
2684
2689
|
) -> RowProvider | None:
|
|
2685
2690
|
current = attrs[gid]
|
|
2686
2691
|
if current.derivation != Derivation.BASIC:
|
|
@@ -2691,7 +2696,7 @@ def _synthetic_dimension_regraft_parent(
|
|
|
2691
2696
|
# condition's derived arg needs.
|
|
2692
2697
|
if current.depth_label == DepthLabel.D1:
|
|
2693
2698
|
return None
|
|
2694
|
-
key = set(
|
|
2699
|
+
key = set(current.grain_components)
|
|
2695
2700
|
if not key:
|
|
2696
2701
|
return None
|
|
2697
2702
|
lineage_preds = lineage_predecessors(group_graph, group_edges, gid)
|
|
@@ -2860,6 +2865,45 @@ def _inline_window(
|
|
|
2860
2865
|
return parent
|
|
2861
2866
|
|
|
2862
2867
|
|
|
2868
|
+
def _elect_grouping_providers(
|
|
2869
|
+
group_graph: nx.DiGraph,
|
|
2870
|
+
group_edges: EdgeMap,
|
|
2871
|
+
attrs: dict[str, GroupAttrs],
|
|
2872
|
+
concept_attrs: dict[str, ConceptAttrs],
|
|
2873
|
+
environment: BuildEnvironment,
|
|
2874
|
+
) -> dict[str, str]:
|
|
2875
|
+
"""Each terminal scalar projection's grouping provider, elected over the
|
|
2876
|
+
graph stage 2 built. A WINDOW that renders the projection inline outranks
|
|
2877
|
+
it: that projection folds and keeps its grain."""
|
|
2878
|
+
providers: dict[str, str] = {}
|
|
2879
|
+
for gid in group_graph.nodes:
|
|
2880
|
+
if gid == FINAL_NODE_ID:
|
|
2881
|
+
continue
|
|
2882
|
+
provider = _terminal_basic_grouping_provider(
|
|
2883
|
+
group_graph, attrs, gid, environment
|
|
2884
|
+
)
|
|
2885
|
+
if provider is None or _inline_window(
|
|
2886
|
+
group_graph, group_edges, attrs, concept_attrs, gid
|
|
2887
|
+
):
|
|
2888
|
+
continue
|
|
2889
|
+
providers[gid] = provider
|
|
2890
|
+
return providers
|
|
2891
|
+
|
|
2892
|
+
|
|
2893
|
+
def _state_projection_grains(
|
|
2894
|
+
attrs: dict[str, GroupAttrs],
|
|
2895
|
+
buckets: dict[str, GroupBucket],
|
|
2896
|
+
grouping: dict[str, str],
|
|
2897
|
+
) -> None:
|
|
2898
|
+
"""Place each terminal projection at its grouping provider's grain. No
|
|
2899
|
+
provider is a BASIC, so no statement reads another."""
|
|
2900
|
+
for gid, provider in grouping.items():
|
|
2901
|
+
grain = attrs[provider].grain_components
|
|
2902
|
+
attrs[gid].grain_components = grain
|
|
2903
|
+
if gid in buckets:
|
|
2904
|
+
buckets[gid].grain_components = grain
|
|
2905
|
+
|
|
2906
|
+
|
|
2863
2907
|
def _elect_row_provider(
|
|
2864
2908
|
group_graph: nx.DiGraph,
|
|
2865
2909
|
group_edges: EdgeMap,
|
|
@@ -2867,45 +2911,42 @@ def _elect_row_provider(
|
|
|
2867
2911
|
buckets: dict[str, GroupBucket],
|
|
2868
2912
|
concept_attrs: dict[str, ConceptAttrs],
|
|
2869
2913
|
environment: BuildEnvironment,
|
|
2914
|
+
grouping: dict[str, str],
|
|
2870
2915
|
gid: str,
|
|
2871
2916
|
) -> RowProvider | None:
|
|
2872
2917
|
"""Pick `gid`'s row source over the graph; mutates nothing. The choices,
|
|
2873
|
-
in order: a WINDOW that renders it inline,
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
if pred in provider_ancestors
|
|
2896
|
-
)
|
|
2897
|
-
return RowProvider(provider_gid, grain, drop)
|
|
2898
|
-
own_grain = attrs[gid].grain_components if grain is None else grain
|
|
2918
|
+
in order: a WINDOW that renders it inline, its grouping provider (whose
|
|
2919
|
+
grain it already stands at), a full-coverage sibling, a dimension ROOT, a
|
|
2920
|
+
partial spine."""
|
|
2921
|
+
grouping_provider = grouping.get(gid)
|
|
2922
|
+
if grouping_provider is None:
|
|
2923
|
+
window = _inline_window(group_graph, group_edges, attrs, concept_attrs, gid)
|
|
2924
|
+
if window is not None:
|
|
2925
|
+
return RowProvider(window, inline=True)
|
|
2926
|
+
elif not _grain_needed_by_independent_sibling(
|
|
2927
|
+
group_graph, attrs, gid, grouping_provider, grouping
|
|
2928
|
+
):
|
|
2929
|
+
# Placed at the provider's grain, the projection has no use for a
|
|
2930
|
+
# finer relation the provider was built from. Joined back, it pairs
|
|
2931
|
+
# the provider's groups on a non-key (a region domain on a nullable
|
|
2932
|
+
# description) and drops or multiplies them.
|
|
2933
|
+
provider_ancestors = nx.ancestors(group_graph, grouping_provider)
|
|
2934
|
+
drop = frozenset(
|
|
2935
|
+
pred
|
|
2936
|
+
for pred in lineage_predecessors(group_graph, group_edges, gid)
|
|
2937
|
+
if pred in provider_ancestors
|
|
2938
|
+
)
|
|
2939
|
+
return RowProvider(grouping_provider, drop)
|
|
2899
2940
|
parent_gid = _regraft_candidate(
|
|
2900
2941
|
group_graph, group_edges, attrs, gid, allow_partial=False
|
|
2901
2942
|
)
|
|
2902
2943
|
if parent_gid is not None:
|
|
2903
|
-
return RowProvider(parent_gid
|
|
2944
|
+
return RowProvider(parent_gid)
|
|
2904
2945
|
dimension = _synthetic_dimension_regraft_parent(
|
|
2905
|
-
group_graph, group_edges, attrs, buckets, concept_attrs, gid
|
|
2946
|
+
group_graph, group_edges, attrs, buckets, concept_attrs, gid
|
|
2906
2947
|
)
|
|
2907
2948
|
if dimension is not None:
|
|
2908
|
-
return
|
|
2949
|
+
return dimension
|
|
2909
2950
|
parent_gid = _regraft_candidate(
|
|
2910
2951
|
group_graph,
|
|
2911
2952
|
group_edges,
|
|
@@ -2913,11 +2954,8 @@ def _elect_row_provider(
|
|
|
2913
2954
|
gid,
|
|
2914
2955
|
allow_partial=True,
|
|
2915
2956
|
environment=environment,
|
|
2916
|
-
grain=own_grain,
|
|
2917
2957
|
)
|
|
2918
|
-
if parent_gid is None
|
|
2919
|
-
return None
|
|
2920
|
-
return RowProvider(parent_gid, grain)
|
|
2958
|
+
return None if parent_gid is None else RowProvider(parent_gid)
|
|
2921
2959
|
|
|
2922
2960
|
|
|
2923
2961
|
def _apply_row_provider(
|
|
@@ -2928,10 +2966,6 @@ def _apply_row_provider(
|
|
|
2928
2966
|
gid: str,
|
|
2929
2967
|
provider: RowProvider,
|
|
2930
2968
|
) -> None:
|
|
2931
|
-
if provider.grain is not None:
|
|
2932
|
-
attrs[gid].grain_components = provider.grain
|
|
2933
|
-
if gid in buckets:
|
|
2934
|
-
buckets[gid].grain_components = provider.grain
|
|
2935
2969
|
minted = provider.minted
|
|
2936
2970
|
if minted is not None and minted.group_id not in group_graph:
|
|
2937
2971
|
group_graph.add_node(minted.group_id)
|
|
@@ -2947,23 +2981,13 @@ def _apply_row_provider(
|
|
|
2947
2981
|
|
|
2948
2982
|
|
|
2949
2983
|
def _as_rewrite(
|
|
2950
|
-
group_graph: nx.DiGraph,
|
|
2951
|
-
attrs: dict[str, GroupAttrs],
|
|
2952
|
-
buckets: dict[str, GroupBucket],
|
|
2953
|
-
gid: str,
|
|
2954
|
-
provider: RowProvider,
|
|
2984
|
+
group_graph: nx.DiGraph, gid: str, provider: RowProvider
|
|
2955
2985
|
) -> RowProvider | None:
|
|
2956
2986
|
"""`provider` less what the graph stage 2 built already holds, or None
|
|
2957
|
-
when it changes nothing: its parent is already a parent,
|
|
2958
|
-
|
|
2987
|
+
when it changes nothing: its parent is already a parent, and it drops and
|
|
2988
|
+
mints nothing."""
|
|
2959
2989
|
if provider.inline:
|
|
2960
2990
|
return provider
|
|
2961
|
-
grain = provider.grain
|
|
2962
|
-
bucket = buckets.get(gid)
|
|
2963
|
-
if grain == attrs[gid].grain_components and (
|
|
2964
|
-
bucket is None or grain == bucket.grain_components
|
|
2965
|
-
):
|
|
2966
|
-
grain = None
|
|
2967
2991
|
drop = frozenset(p for p in provider.drop if group_graph.has_edge(p, gid))
|
|
2968
2992
|
minted = provider.minted
|
|
2969
2993
|
if minted is not None and minted.group_id in group_graph:
|
|
@@ -2971,9 +2995,9 @@ def _as_rewrite(
|
|
|
2971
2995
|
parent = provider.parent
|
|
2972
2996
|
if parent is not None and group_graph.has_edge(parent, gid):
|
|
2973
2997
|
parent = None
|
|
2974
|
-
if parent is None and
|
|
2998
|
+
if parent is None and not drop and minted is None:
|
|
2975
2999
|
return None
|
|
2976
|
-
return RowProvider(parent,
|
|
3000
|
+
return RowProvider(parent, drop, minted)
|
|
2977
3001
|
|
|
2978
3002
|
|
|
2979
3003
|
def _elect_row_providers(
|
|
@@ -2983,6 +3007,7 @@ def _elect_row_providers(
|
|
|
2983
3007
|
buckets: dict[str, GroupBucket],
|
|
2984
3008
|
concept_attrs: dict[str, ConceptAttrs],
|
|
2985
3009
|
environment: BuildEnvironment,
|
|
3010
|
+
grouping: dict[str, str],
|
|
2986
3011
|
) -> dict[str, RowProvider]:
|
|
2987
3012
|
"""Each regraftable group whose best row source is already built, elected
|
|
2988
3013
|
over the graph as stage 2 built it, as the rewrite it makes of that graph.
|
|
@@ -3000,10 +3025,17 @@ def _elect_row_providers(
|
|
|
3000
3025
|
):
|
|
3001
3026
|
continue
|
|
3002
3027
|
provider = _elect_row_provider(
|
|
3003
|
-
group_graph,
|
|
3028
|
+
group_graph,
|
|
3029
|
+
group_edges,
|
|
3030
|
+
attrs,
|
|
3031
|
+
buckets,
|
|
3032
|
+
concept_attrs,
|
|
3033
|
+
environment,
|
|
3034
|
+
grouping,
|
|
3035
|
+
gid,
|
|
3004
3036
|
)
|
|
3005
3037
|
if provider is not None:
|
|
3006
|
-
provider = _as_rewrite(group_graph,
|
|
3038
|
+
provider = _as_rewrite(group_graph, gid, provider)
|
|
3007
3039
|
if provider is not None:
|
|
3008
3040
|
providers[gid] = provider
|
|
3009
3041
|
folded = _folds(providers)
|
|
@@ -3029,12 +3061,14 @@ def _rehome_groups(
|
|
|
3029
3061
|
buckets: dict[str, GroupBucket],
|
|
3030
3062
|
concept_attrs: dict[str, ConceptAttrs],
|
|
3031
3063
|
environment: BuildEnvironment,
|
|
3064
|
+
grouping: dict[str, str],
|
|
3032
3065
|
) -> None:
|
|
3033
3066
|
"""Elect every group's row provider over the graph as stage 2 built it,
|
|
3034
|
-
|
|
3035
|
-
|
|
3067
|
+
each projection already at its grouping provider's grain, then fold each
|
|
3068
|
+
group its provider renders inline and apply the rest: no election reads
|
|
3069
|
+
another's fold or edges."""
|
|
3036
3070
|
providers = _elect_row_providers(
|
|
3037
|
-
group_graph, group_edges, attrs, buckets, concept_attrs, environment
|
|
3071
|
+
group_graph, group_edges, attrs, buckets, concept_attrs, environment, grouping
|
|
3038
3072
|
)
|
|
3039
3073
|
for gid, parent in _folds(providers).items():
|
|
3040
3074
|
_absorb_group(gid, parent, group_graph, group_edges, attrs, buckets)
|
|
@@ -96,6 +96,7 @@ from trilogy.core.processing.v4_helper.projection import (
|
|
|
96
96
|
def _condition_fit(
|
|
97
97
|
datasource: BuildDatasource | BuildUnionDatasource,
|
|
98
98
|
conditions: BuildWhereClause | None,
|
|
99
|
+
environment: BuildEnvironment,
|
|
99
100
|
) -> ConditionFit:
|
|
100
101
|
if conditions is None:
|
|
101
102
|
return ConditionFit.NEUTRAL
|
|
@@ -104,9 +105,20 @@ def _condition_fit(
|
|
|
104
105
|
conditions.conditional, non_partial_for.conditional
|
|
105
106
|
):
|
|
106
107
|
return ConditionFit.IMPLIED_EXACT
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
108
|
+
# A condition on a property of the grain's keys selects whole groups, so
|
|
109
|
+
# the aggregate is kept (`Cover.joined_case_exact`); the map is only built
|
|
110
|
+
# when the plain check would refuse.
|
|
111
|
+
if (
|
|
112
|
+
isinstance(datasource, BuildDatasource)
|
|
113
|
+
and datasource_has_filter_sensitive_aggregate(datasource, conditions)
|
|
114
|
+
and datasource_has_filter_sensitive_aggregate(
|
|
115
|
+
datasource,
|
|
116
|
+
conditions,
|
|
117
|
+
canonical_to_concept={
|
|
118
|
+
c.canonical_address: c for c in environment.concepts.values()
|
|
119
|
+
},
|
|
120
|
+
)
|
|
121
|
+
):
|
|
110
122
|
return ConditionFit.SENSITIVE
|
|
111
123
|
return ConditionFit.NEUTRAL
|
|
112
124
|
|
|
@@ -257,7 +269,7 @@ def _candidate(
|
|
|
257
269
|
node=node,
|
|
258
270
|
datasource=datasource,
|
|
259
271
|
bindings=_bindings_for(emitted, partial, stored, equivalence),
|
|
260
|
-
condition=_condition_fit(datasource, conditions),
|
|
272
|
+
condition=_condition_fit(datasource, conditions, environment),
|
|
261
273
|
is_union=isinstance(datasource, BuildUnionDatasource),
|
|
262
274
|
grain=_grain_classes(datasource, equivalence),
|
|
263
275
|
)
|
|
@@ -509,10 +509,11 @@ class SolutionCost:
|
|
|
509
509
|
# connector's subplan. At equal scan count the cover storing the column
|
|
510
510
|
# wins, instead of whichever source sorts first.
|
|
511
511
|
derived_terminals: int
|
|
512
|
-
# Sources
|
|
513
|
-
#
|
|
514
|
-
#
|
|
515
|
-
|
|
512
|
+
# Sources another candidate reading the same columns holds no more of the
|
|
513
|
+
# query's rows than (`Cost.filtered_dominated_le`): one read in full beside
|
|
514
|
+
# a twin the WHERE pre-filters (IMPLIED_EXACT), or a pre-filtered table
|
|
515
|
+
# beside a coarser source that applies the same WHERE.
|
|
516
|
+
dominated_reads: int
|
|
516
517
|
connectors: int
|
|
517
518
|
derived_joins: int
|
|
518
519
|
|
|
@@ -39,6 +39,7 @@ from _preql_import_resolver import enumerate_network_covers
|
|
|
39
39
|
from trilogy.core.graph_models import ReferenceGraph
|
|
40
40
|
from trilogy.core.models.build import (
|
|
41
41
|
BuildConcept,
|
|
42
|
+
BuildDatasource,
|
|
42
43
|
BuildUnionDatasource,
|
|
43
44
|
BuildWhereClause,
|
|
44
45
|
)
|
|
@@ -287,24 +288,65 @@ def _stored_key(candidate: SourceCandidate, address: str) -> bool:
|
|
|
287
288
|
return binding is not None and binding.stored
|
|
288
289
|
|
|
289
290
|
|
|
290
|
-
def
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
291
|
+
def _reads_alike(
|
|
292
|
+
candidate: SourceCandidate, other: SourceCandidate, read: frozenset[str]
|
|
293
|
+
) -> bool:
|
|
294
|
+
return all(
|
|
295
|
+
(mine := candidate.bindings.get(address)) is not None
|
|
296
|
+
and (theirs := other.bindings.get(address)) is not None
|
|
297
|
+
and mine.address == theirs.address
|
|
298
|
+
for address in read
|
|
299
|
+
)
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
def _arm_columns(network: SourceNetwork, candidate: SourceCandidate) -> frozenset[str]:
|
|
303
|
+
arm = candidate.datasource.non_partial_for if candidate.datasource else None
|
|
304
|
+
return frozenset(
|
|
305
|
+
network.equivalence.get(c.address, c.address)
|
|
306
|
+
for c in (arm.conditional.concept_arguments if arm else ())
|
|
307
|
+
)
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
def _filters_coarser(
|
|
311
|
+
network: SourceNetwork, coarse: SourceCandidate, filtered: SourceCandidate
|
|
312
|
+
) -> bool:
|
|
313
|
+
"""`coarse`'s grain is a function of `filtered`'s rows and `coarse` binds
|
|
314
|
+
the WHERE columns `filtered`'s arm reads, so under that WHERE it reads no
|
|
315
|
+
more rows (`Cost.filtered_dominated_le`)."""
|
|
316
|
+
arm = _arm_columns(network, filtered)
|
|
317
|
+
return (
|
|
318
|
+
bool(arm)
|
|
319
|
+
and coarse.grain != filtered.grain
|
|
320
|
+
and all(filtered.binds(address) for address in coarse.grain)
|
|
321
|
+
and all(coarse.binds(address) for address in arm)
|
|
322
|
+
)
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
def _dominated_read(network: SourceNetwork, node: str, read: frozenset[str]) -> bool:
|
|
326
|
+
"""Another candidate reading every value `node` provides or joins on, from
|
|
327
|
+
the same columns, holds no more of the rows the query keeps: a source the
|
|
328
|
+
WHERE pre-filters (IMPLIED_EXACT) beside one read in full, unless the full
|
|
329
|
+
one is the coarser and applies that WHERE itself; or a row-complete source
|
|
330
|
+
at a coarser grain applying the arm of a pre-filtered `node`."""
|
|
294
331
|
candidate = network.candidates[node]
|
|
295
|
-
if not read
|
|
332
|
+
if not read:
|
|
296
333
|
return False
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
334
|
+
filtered = candidate.condition.partial_is_full
|
|
335
|
+
for name, other in network.candidates.items():
|
|
336
|
+
if name == node or not _reads_alike(candidate, other, read):
|
|
337
|
+
continue
|
|
338
|
+
if filtered:
|
|
339
|
+
if (
|
|
340
|
+
network.row_complete(name)
|
|
341
|
+
and all(other.binds_fully(address) for address in read)
|
|
342
|
+
and _filters_coarser(network, other, candidate)
|
|
343
|
+
):
|
|
344
|
+
return True
|
|
345
|
+
elif other.condition.partial_is_full and not _filters_coarser(
|
|
346
|
+
network, candidate, other
|
|
347
|
+
):
|
|
348
|
+
return True
|
|
349
|
+
return False
|
|
308
350
|
|
|
309
351
|
|
|
310
352
|
def _solution_for(
|
|
@@ -364,10 +406,10 @@ def _solution_for(
|
|
|
364
406
|
for address in addresses
|
|
365
407
|
if not _stored_key(network.candidates[node], address)
|
|
366
408
|
),
|
|
367
|
-
|
|
409
|
+
dominated_reads=sum(
|
|
368
410
|
1
|
|
369
411
|
for node in sources
|
|
370
|
-
if
|
|
412
|
+
if _dominated_read(network, node, assignments[node] | joined_on[node])
|
|
371
413
|
),
|
|
372
414
|
connectors=len(connectors),
|
|
373
415
|
derived_joins=derived_joins,
|
|
@@ -478,7 +520,11 @@ def search_sources(network: SourceNetwork) -> SearchResult:
|
|
|
478
520
|
continue
|
|
479
521
|
connected = _reduce(network, cover, targets)
|
|
480
522
|
key = tuple(sorted(connected))
|
|
481
|
-
if
|
|
523
|
+
if (
|
|
524
|
+
key in seen
|
|
525
|
+
or not _reads_a_scan(network, connected)
|
|
526
|
+
or _bridges_unclaimed_rows(network, connected)
|
|
527
|
+
):
|
|
482
528
|
continue
|
|
483
529
|
seen.add(key)
|
|
484
530
|
reduced.append((connected, _binding_profile(network, connected, targets)))
|
|
@@ -501,6 +547,34 @@ def search_sources(network: SourceNetwork) -> SearchResult:
|
|
|
501
547
|
return SearchResult(solution=best, limit=limit)
|
|
502
548
|
|
|
503
549
|
|
|
550
|
+
def _unclaimed_partial(candidate: SourceCandidate) -> bool:
|
|
551
|
+
"""A `partial datasource` the WHERE does not complete: every grain column
|
|
552
|
+
holds only some rows, and no `~` claims the rest have none."""
|
|
553
|
+
datasource = candidate.datasource
|
|
554
|
+
if candidate.condition.partial_is_full or not isinstance(
|
|
555
|
+
datasource, BuildDatasource
|
|
556
|
+
):
|
|
557
|
+
return False
|
|
558
|
+
grain = [candidate.bindings.get(address) for address in candidate.grain]
|
|
559
|
+
return bool(grain) and all(
|
|
560
|
+
binding is not None
|
|
561
|
+
and binding.partial
|
|
562
|
+
and binding.address not in datasource.column_level_partial_addresses
|
|
563
|
+
for binding in grain
|
|
564
|
+
)
|
|
565
|
+
|
|
566
|
+
|
|
567
|
+
def _bridges_unclaimed_rows(network: SourceNetwork, sources: frozenset[str]) -> bool:
|
|
568
|
+
"""A source holding an unknown subset of its rows relates the sources on
|
|
569
|
+
either side of it only for that subset (`Cost.unimplied_partial_summary_loses_rows`):
|
|
570
|
+
it may end a join path, never be the only link between two others."""
|
|
571
|
+
return len(sources) > 2 and any(
|
|
572
|
+
_unclaimed_partial(network.candidates[node])
|
|
573
|
+
and not is_connected(network, sources - {node})
|
|
574
|
+
for node in sources
|
|
575
|
+
)
|
|
576
|
+
|
|
577
|
+
|
|
504
578
|
def _reads_a_scan(network: SourceNetwork, sources: frozenset[str]) -> bool:
|
|
505
579
|
"""A derived connector exists to RELATE scans, so a cover made only of
|
|
506
580
|
connectors reads no rows and is not an answer, however cheap it prices
|
|
@@ -652,10 +652,16 @@ def validate_assertions(
|
|
|
652
652
|
|
|
653
653
|
A refresh checks them against a staged build; here there is one asset and
|
|
654
654
|
no previous one, so an assertion that reads ``prior(...)`` is reported but
|
|
655
|
-
not run.
|
|
655
|
+
not run. Every assertion is still planned against the asset, so one its
|
|
656
|
+
columns cannot answer fails here rather than at the next build.
|
|
656
657
|
"""
|
|
657
658
|
from trilogy.core.assertions import plan_assertion
|
|
658
|
-
from trilogy.execution.assertions import
|
|
659
|
+
from trilogy.execution.assertions import (
|
|
660
|
+
UnanswerableAssertionError,
|
|
661
|
+
check_answerable,
|
|
662
|
+
evaluate_assertion,
|
|
663
|
+
render_assertion,
|
|
664
|
+
)
|
|
659
665
|
|
|
660
666
|
declared = env.datasources.get(datasource.identifier)
|
|
661
667
|
if declared is None or not declared.assertions:
|
|
@@ -663,6 +669,19 @@ def validate_assertions(
|
|
|
663
669
|
results: list[ValidationTest] = []
|
|
664
670
|
for assertion in declared.assertions:
|
|
665
671
|
spelled = render_assertion(assertion)
|
|
672
|
+
if exec is not None:
|
|
673
|
+
try:
|
|
674
|
+
check_answerable(exec, declared, assertion)
|
|
675
|
+
except UnanswerableAssertionError as exc:
|
|
676
|
+
results.append(
|
|
677
|
+
ValidationTest(
|
|
678
|
+
check_type=ExpectationType.ASSERTION,
|
|
679
|
+
expected=spelled,
|
|
680
|
+
ran=True,
|
|
681
|
+
result=DatasourceModelValidationError(str(exc)),
|
|
682
|
+
)
|
|
683
|
+
)
|
|
684
|
+
continue
|
|
666
685
|
if exec is None or plan_assertion(assertion.condition).uses_prior:
|
|
667
686
|
results.append(
|
|
668
687
|
ValidationTest(
|