sql-code-graph 1.4.1__tar.gz → 1.5.0__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.
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/PKG-INFO +1 -1
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/docs/cli.md +18 -10
- sql_code_graph-1.5.0/plan/diff-impact-producer-file.md +321 -0
- sql_code_graph-1.5.0/plan/issue-38-backfill-cte-bridge.md +870 -0
- sql_code_graph-1.5.0/plan/version-parity-and-restart.md +390 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/pyproject.toml +1 -1
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/__init__.py +1 -1
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/cli/commands/install.py +56 -43
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/cli/commands/mcp.py +58 -10
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/cli/main.py +34 -3
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/core/queries.py +4 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/core/queries.sql +60 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/parsers/ansi_parser.py +7 -2
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/server/models.py +9 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/server/server.py +9 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/server/tools.py +180 -28
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/integration/test_anchor_tools.py +130 -6
- sql_code_graph-1.5.0/tests/integration/test_backfill_impact_consistency.py +427 -0
- sql_code_graph-1.5.0/tests/integration/test_case_split_seed_regression.py +152 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_hygiene_config_warning.py +4 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_include_working_tree.py +4 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_index_cmd.py +4 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_index_flags.py +11 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_install.py +80 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_mcp_control.py +130 -0
- sql_code_graph-1.5.0/tests/unit/test_version_parity.py +148 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/uv.lock +1 -1
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/.claude/agents/api-documenter.md +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/.claude/agents/architect-planner.md +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/.claude/agents/architect-reviewer.md +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/.claude/agents/code-reviewer.md +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/.claude/agents/developer.md +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/.claude/agents/plan-reviewer.md +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/.claude/agents/sprint-planner.md +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/.github/workflows/benchmark.yml +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/.github/workflows/e2e-tests.yml +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/.github/workflows/release.yml +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/.github/workflows/test.yml +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/.gitignore +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/.pre-commit-config.yaml +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/.sqlcgignore +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/ARCHITECTURE_REVIEW.md +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/CHANGELOG.md +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/CLAUDE.md +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/README.md +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/docs/AIRBNB_PARSE_REPORT.md +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/e2e_firstuser_report.md +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/e2e_run_20260528_101413.output +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/main.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/plan/WORKFLOW.md +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/plan/blueprint.md +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/plan/bundle_claude_skill.md +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/plan/feature_34_unused_presentation_segregation.md +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/plan/feature_35_external_downstream_injection.md +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/plan/feature_F2_bundle_claude_skill.md +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/plan/feature_kuzu_to_duckdb_migration.md +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/plan/fix_downstream_sink_location.md +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/plan/fix_dynamic_table_parsing.md +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/plan/fix_expand_qualify_perf.md +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/plan/fix_firstuser_findings.md +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/plan/fix_issue29_live_test_followups.md +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/plan/fix_schema_case_mismatch.md +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/plan/hygiene_config_path_and_survivors.md +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/plan/investigation_e5_e4.md +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/plan/living_codebase_resync.md +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/plan/measurements/schema_comparison_with_schema.json +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/plan/measurements/schema_comparison_without_schema.json +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/plan/measurements/sprint_08_changelogs_fullindex.json +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/plan/measurements/sprint_08_fullcorpus_index.json +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/plan/measurements/sprint_pool_300s_plan.json +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/plan/parse_diagnostics.md +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/plan/parsing_errors_experiment.md +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/plan/snowflake_en_test_suite.md +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/plan/sprint_01.md +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/plan/sprint_01_deployment_pypi.md +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/plan/sprint_02.md +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/plan/sprint_02_v0.3.0_core.md +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/plan/sprint_03.md +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/plan/sprint_03_v0.3.1_postmortem.md +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/plan/sprint_04_column_lineage.md +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/plan/sprint_04_column_lineage_fix.md +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/plan/sprint_05_star_resolution.md +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/plan/sprint_06_lineage_coverage.md +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/plan/sprint_07_open_ecodes.md +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/plan/sprint_07_perf_and_live_test.md +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/plan/sprint_08_perf_upsert.md +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/plan/sprint_09_lineage_coverage.md +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/plan/sprint_10_anchor_tools.md +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/plan/sprint_11_v1.0.2_bugfix.md +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/plan/sprint_12_v1.1.0.md +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/plan/sprint_13_v1.1.0_cluster_b.md +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/plan/sprint_3.1_postmortem.md +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/plan/sqlcg.md +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/plan/trust_layer.md +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/plan/v1.1.0_cluster_b_provenance_trust.md +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/plan/v1.1.0_live_graph_freshness.md +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/plan/v1.1.1_batch_upsert_perf.md +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/plan/v1_1_2_bugfix.md +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/plan/v1_1_3_union_cte_star.md +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/plan/v1_2_0_read_proxy.md +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/plan/v1_2_1_bugfix.md +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/profile.html +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/pyrightconfig.json +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/scripts/collect_parse_errors.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/scripts/generate_cli_docs.sh +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/__main__.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/cli/__init__.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/cli/commands/__init__.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/cli/commands/analyze.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/cli/commands/db.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/cli/commands/find.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/cli/commands/gain.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/cli/commands/git.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/cli/commands/index.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/cli/commands/reindex.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/cli/commands/report.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/cli/commands/uninstall.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/cli/commands/watch.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/core/__init__.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/core/config.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/core/duckdb_backend.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/core/freshness.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/core/graph_db.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/core/jobs.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/core/queries.cypher +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/core/schema.cypher +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/core/schema.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/indexer/__init__.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/indexer/dbt_adapter.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/indexer/error_classify.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/indexer/git_delta.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/indexer/indexer.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/indexer/pool.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/indexer/walker.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/indexer/watcher.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/lineage/__init__.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/lineage/aggregator.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/lineage/schema_resolver.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/metrics/__init__.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/metrics/store.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/parsers/__init__.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/parsers/base.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/parsers/bigquery_parser.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/parsers/postgres_parser.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/parsers/registry.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/parsers/snowflake_parser.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/parsers/tsql_parser.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/server/__init__.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/server/control.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/server/exceptions.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/server/noise_filter.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/server/read_client.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/server/skill.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/server/writer.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/utils/__init__.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/utils/hashing.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/utils/ignore.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/src/sqlcg/utils/logging.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/__init__.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/benchmarks/__init__.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/benchmarks/adversarial/200_join.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/benchmarks/adversarial/500_union.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/benchmarks/bench_indexer.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/benchmarks/conftest.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/benchmarks/golden_corpus/snowflake/case_normalization.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/benchmarks/golden_corpus/snowflake/colon_cast.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/benchmarks/golden_corpus/snowflake/colon_reserved_word.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/benchmarks/golden_corpus/snowflake/copy_into.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/benchmarks/golden_corpus/snowflake/create_procedure.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/benchmarks/golden_corpus/snowflake/identifier_dynamic.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/benchmarks/golden_corpus/snowflake/lateral_flatten.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/benchmarks/golden_corpus/snowflake/qualify.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/benchmarks/golden_corpus/snowflake/scripting_block.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/benchmarks/golden_corpus/snowflake/three_part.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/benchmarks/tpch/q01.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/benchmarks/tpch/q02.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/benchmarks/tpch/q03.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/benchmarks/tpch/q04.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/benchmarks/tpch/q05.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/e2e/__init__.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/e2e/conftest.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/e2e/test_F2_skill_install_e2e.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/e2e/test_airbnb_e2e.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/e2e/test_cli_index.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/e2e/test_git_hook_install.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/e2e/test_golden_lineage.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/e2e/test_mcp_lifecycle.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/e2e/test_mcp_tools.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/e2e/test_parse_diagnostics_cli.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/e2e/test_star_resolution_e2e.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/e2e/test_watch.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/fixtures/airbnb/dim_hosts_cleansed.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/fixtures/airbnb/dim_listings_cleansed.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/fixtures/airbnb/fct_reviews.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/fixtures/airbnb/mart_fullmoon_reviews.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/fixtures/airbnb/raw_hosts.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/fixtures/airbnb/raw_listings.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/fixtures/airbnb/raw_reviews.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/fixtures/airbnb/src_hosts.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/fixtures/airbnb/src_listings.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/fixtures/airbnb/src_reviews.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/fixtures/bigquery/.gitkeep +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/fixtures/duckdb_parity/kuzu_reference.json +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/fixtures/jaffle_shop/customers.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/fixtures/jaffle_shop/orders.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/fixtures/jaffle_shop/raw_orders.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/fixtures/snowflake/base_tables.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/fixtures/snowflake/reports.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/fixtures/snowflake/views.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/fixtures/star_corpus/ddl_src.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/fixtures/star_corpus/ddl_tgt.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/fixtures/star_corpus/etl_alias_star.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/fixtures/star_corpus/etl_star.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/fixtures/synthetic/base_tables.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/fixtures/synthetic/reports.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/fixtures/synthetic/views.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/integration/__init__.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/integration/snowflake/__init__.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/integration/snowflake/test_insert_select.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/integration/test_T34_presentation_segregation.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/integration/test_T35_external_consumers.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/integration/test_analyze_case_fold.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/integration/test_bare_column_cte_lineage.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/integration/test_bulk_upsert.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/integration/test_column_lineage_e2e.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/integration/test_cross_file_lineage.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/integration/test_cte_recall_guard.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/integration/test_cte_schema_alias_guard.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/integration/test_cte_source_node_invariant.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/integration/test_dialect_auto_resolution.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/integration/test_dialect_matrix.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/integration/test_duckdb_parity.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/integration/test_e36_xfile_regression_guard.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/integration/test_freshness_mcp.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/integration/test_hygiene_config_root_reconciliation.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/integration/test_indexer_batching.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/integration/test_indexer_commits.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/integration/test_indexer_to_graph.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/integration/test_live_anchors.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/integration/test_mvcc_rebuild.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/integration/test_parse_diagnostics.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/integration/test_pr1_confidence_reason.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/integration/test_pr2_source_location.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/integration/test_pr3_kind_tagging.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/integration/test_read_via_server.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/integration/test_readonly_under_lock.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/integration/test_reindex_via_server.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/integration/test_resync.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/integration/test_single_writer_queue.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/integration/test_star_resolution.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/integration/test_temp_table_lineage.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/integration/test_union_cte_star_recall_guard.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/integration/test_user_surface_recall_guard.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/integration/test_v141_surface_guards.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/perf/__init__.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/perf/test_perf.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E10/__init__.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E11/__init__.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E12/__init__.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E12/e12_json_path.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E12/e12_lateral_flatten.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E12/test_e12.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E13/__init__.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E14/__init__.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E15/__init__.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E16/__init__.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E16/e16_merge.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E16/e16_merge_delete.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E16/test_e16.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E17/__init__.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E18/__init__.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E18/e18_decode.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E18/e18_iff_decode.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E18/e18_nvl2.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E18/test_e18.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E19/__init__.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E2/__init__.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E2/e2_expr_alias.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E2/e2_function_alias.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E2/e2_multiply_alias.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E2/test_e2.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E20/__init__.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E21/__init__.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E21/e21_alias_forward_ref.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E21/e21_three_level_chain.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E21/test_e21.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E22/__init__.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E23/__init__.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E23/e23_stored_proc.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E23/e23_stored_proc_multi.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E23/test_e23.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E24/__init__.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E25/__init__.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E25/e25_cross_db.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E25/e25_two_part.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E25/test_e25.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E25/test_e25_full_id.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E26/__init__.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E27/__init__.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E27/e27_nested_udf.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E27/e27_udf.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E27/test_e27.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E28/__init__.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E29/__init__.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E3/__init__.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E3/e3_alter_table.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E3/e3_create_sequence.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E3/e3_ddl_only.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E3/test_e3.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E30/__init__.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E31/__init__.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E32/__init__.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E33/__init__.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E34/__init__.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E35/__init__.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E36/__init__.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E36/e36_temp_multi_use.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E36/e36_temp_table.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E36/test_e36.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E36/test_e36_xfile.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E37/__init__.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E38/__init__.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E4/__init__.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E4/e4_execute_immediate.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E4/e4_if_not_exists.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E4/e4_unexpected_token.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E4/e4_unpivot.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E4/test_e4.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E5/__init__.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E5/e5_cte_missing_source.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E5/e5_multi_cte.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E5/e5_nested_cte.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E5/test_e5.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E5/test_e5_cte_projection.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E8/__init__.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E8/e8_dynamic_sources.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E8/e8_seq_nextval.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E8/e8_uuid.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E8/test_e8.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E9/__init__.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E_aggregates/__init__.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E_aggregates/fixture_sum_absent_cross_schema.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E_aggregates/fixture_sum_case_when.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E_aggregates/fixture_sum_present_source.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E_aggregates/test_e_aggregates.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E_date_functions/__init__.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E_date_functions/fixture_date_aliased.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E_date_functions/fixture_date_unaliased.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E_date_functions/fixture_datediff_unaliased.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E_date_functions/fixture_year_unaliased.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/E_date_functions/test_e_date_functions.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/README.md +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/__init__.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/anchors/__init__.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/anchors/fixture_etl.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/anchors/fixture_omloopsnelheid.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/anchors/fixture_semantic.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/anchors/fixture_source.sql +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/anchors/test_anchor_ma_aantal_op_order.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/anchors/test_anchor_omloopsnelheid.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/conftest.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/snowflake/test_plan_review_gates.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/__init__.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/snowflake/__init__.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/snowflake/test_scripting_noise.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_BugB_escalation_uses_init_path.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_BugC_hook_upgrade.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_F2_install_skill.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_F2_skill_render.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_F2_uninstall_skill.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_T09_01_qualify_once.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_T09_02_ddl_skip.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_T09_04_subprocess_isolate.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_T09_06_log_verbosity.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_T35_config_external_consumers.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_aggregator.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_aggregator_skip.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_analyze_case_fold.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_base_parser.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_branch_monitor.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_bulk_upsert_invariant.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_canonical_target_resolution.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_cli.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_cli_help.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_closure_depth.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_column_lineage_wiring.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_config.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_data_models.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_db_info.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_dominant_cause.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_duckdb_backend.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_duckdb_backend_shared.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_find_cmd.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_firstuser_findings.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_freshness_helper.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_gain_ratio.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_git_delta.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_git_hooks.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_git_hooks_notify.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_graph_backend.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_graph_completeness_invariant.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_hard_kill_pool.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_index_progress.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_indexer_progress.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_indexer_quality.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_install_message.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_jobs.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_judgement.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_lineage_conversion.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_literal_column_skip.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_mcp_best_practices.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_mcp_stdio_smoke.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_metrics.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_noise_filter.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_parse_file_dependency_filter.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_parse_quality.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_parser.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_perf_scaling_guard.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_pr07_observability.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_queries_loader.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_read_client.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_resolve_pass2_passes_dependency_filter.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_schema_resolver.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_server.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_snowflake_strip_alter_set_tag.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_sprint_06_t04_t05.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_star_resolution_unit.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_star_schema_unit.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_submit_feedback.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_subprocess_isolate.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_t02_expression_name_extraction.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_t03_ddl_skip.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_timeout_cancel.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_tools_hints.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_tools_warnings.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_uninstall.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_unqualified_fallback.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_upsert_batch_invariant.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_walker.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_watcher.py +0 -0
- {sql_code_graph-1.4.1 → sql_code_graph-1.5.0}/tests/unit/test_writer_queue.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sql-code-graph
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.5.0
|
|
4
4
|
Summary: SQL code graph analyzer and lineage tracer
|
|
5
5
|
Project-URL: Homepage, https://github.com/Warhorze/sql-code-graph
|
|
6
6
|
Project-URL: Repository, https://github.com/Warhorze/sql-code-graph
|
|
@@ -51,6 +51,7 @@ Note: Binary is `sqlcg`; PyPI package is `sql-code-graph`.
|
|
|
51
51
|
|
|
52
52
|
| Option | Type | Required | Repeatable | Default | Description |
|
|
53
53
|
| --- | --- | --- | --- | --- | --- |
|
|
54
|
+
| --version | BOOLEAN | No | No | False | Show version and exit. |
|
|
54
55
|
| --install-completion | BOOLEAN | No | No | | Install completion for the current shell. |
|
|
55
56
|
| --show-completion | BOOLEAN | No | No | | Show completion for the current shell, to copy it or customize the installation. |
|
|
56
57
|
|
|
@@ -547,9 +548,19 @@ sqlcg mcp status [OPTIONS]
|
|
|
547
548
|
|
|
548
549
|
Print server status JSON (connects to control socket).
|
|
549
550
|
|
|
550
|
-
Returns JSON with fields: running, pid, db_path, indexed_sha,
|
|
551
|
-
stale_by_commits, connected_clients, uptime, writer_queue
|
|
552
|
-
is live.
|
|
551
|
+
Returns JSON with fields: running, version, pid, db_path, indexed_sha,
|
|
552
|
+
head_sha, stale_by_commits, connected_clients, uptime, writer_queue,
|
|
553
|
+
stale_by_version when a server is live.
|
|
554
|
+
|
|
555
|
+
`version` is the *running* server's reported sqlcg.__version__ (read live
|
|
556
|
+
over the control socket — the build the editor is currently talking to).
|
|
557
|
+
`stale_by_version` compares it against the *installed* sqlcg.__version__
|
|
558
|
+
(the CLI process you just invoked): true when they differ, false when they
|
|
559
|
+
match, null when the running version cannot be determined (degraded mode).
|
|
560
|
+
When stale, a warning is printed telling you to restart the MCP server via
|
|
561
|
+
your editor or run `sqlcg install` (which stops the stale server for you).
|
|
562
|
+
This is distinct from `stale_by_commits` (graph-vs-repo freshness, not
|
|
563
|
+
package-vs-binary drift).
|
|
553
564
|
|
|
554
565
|
The status response is length-prefixed framed (v1.3.0, B3) so large
|
|
555
566
|
writer_queue payloads are received in full — the client uses the
|
|
@@ -557,7 +568,8 @@ recv-exactly makefile+readline+read(n) pattern, NOT a single recv(4096).
|
|
|
557
568
|
|
|
558
569
|
When no server is found: {"running": false}.
|
|
559
570
|
When the PID file exists with a live process but the socket is unavailable:
|
|
560
|
-
{"running": true, "degraded": "socket unavailable", ...}
|
|
571
|
+
{"running": true, "degraded": "socket unavailable", "stale_by_version": null, ...}
|
|
572
|
+
(the running version cannot be read without a live socket).
|
|
561
573
|
|
|
562
574
|
R3 (stale socket): if the socket file exists but the server is not
|
|
563
575
|
responding (ConnectionRefusedError / FileNotFoundError), falls through
|
|
@@ -577,12 +589,8 @@ sqlcg mcp stop [OPTIONS]
|
|
|
577
589
|
|
|
578
590
|
Stop the running MCP server gracefully.
|
|
579
591
|
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
on the PID-file PID if the socket is unavailable.
|
|
583
|
-
|
|
584
|
-
R3 (stale socket): ``ConnectionRefusedError`` / ``FileNotFoundError`` are
|
|
585
|
-
caught — never hangs on a dead socket.
|
|
592
|
+
Delegates to ``stop_server()`` (shared with ``sqlcg install``) and prints
|
|
593
|
+
a final message based on whether a server was found.
|
|
586
594
|
|
|
587
595
|
### Options
|
|
588
596
|
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
# Feature Plan: `diff_impact` under-reports blast radius for ETL producer files
|
|
2
|
+
|
|
3
|
+
## Summary
|
|
4
|
+
|
|
5
|
+
[`diff_impact`](../src/sqlcg/server/tools.py) resolves each changed file to its
|
|
6
|
+
produced tables via `DEFINED_IN` only, which the indexer populates **solely from
|
|
7
|
+
DDL `CREATE TABLE`/`CREATE VIEW` provenance**. On repos where DDL lives in
|
|
8
|
+
separate files from the ETL `INSERT…SELECT` producers (the DWH layout: DDL
|
|
9
|
+
changelog files vs `etl/sql/...` producers), passing a producer file returns
|
|
10
|
+
**no produced table → an empty, silently under-counted blast radius**. This is a
|
|
11
|
+
correctness bug for the tool's primary use case ("here are my PR's changed files,
|
|
12
|
+
what breaks?"). The fix makes `diff_impact`'s file→table resolution additionally
|
|
13
|
+
consult `QUERY_DEFINED_IN` → `SqlQuery.target_table`, unioned with the existing
|
|
14
|
+
`DEFINED_IN`-derived set.
|
|
15
|
+
|
|
16
|
+
This is a **separate issue from #38** (fixed in PR #57): own branch, own PR, own
|
|
17
|
+
patch bump.
|
|
18
|
+
|
|
19
|
+
## Scope
|
|
20
|
+
|
|
21
|
+
### In Scope
|
|
22
|
+
- A new read query (proposed `GET_TARGET_TABLES_FOR_FILE`) joining
|
|
23
|
+
`QUERY_DEFINED_IN` (query→file) → `SqlQuery`, filtered to non-empty
|
|
24
|
+
`target_table`, returning the produced/populated tables for a file.
|
|
25
|
+
- Additive change to [`diff_impact`](../src/sqlcg/server/tools.py#L1014) so the
|
|
26
|
+
per-file resolution loop unions `DEFINED_IN`-derived tables with
|
|
27
|
+
`QUERY_DEFINED_IN`-derived target tables, de-duplicated against `seen_changed`.
|
|
28
|
+
- An integration test reproducing the gap (separate DDL file + separate
|
|
29
|
+
`INSERT…SELECT` producer file + downstream consumer), mirroring the
|
|
30
|
+
[`test_anchor_tools.py`](../tests/integration/test_anchor_tools.py) style and
|
|
31
|
+
`_index_fixture` helper.
|
|
32
|
+
- Patch version bump (re-check current version at implementation time; expected
|
|
33
|
+
`1.4.3` once #38's `1.4.2` ships).
|
|
34
|
+
|
|
35
|
+
### Non-Goals
|
|
36
|
+
- **No** change to `DEFINED_IN` semantics, the indexer's "prefer DDL provenance"
|
|
37
|
+
merge ([`indexer.py` ~L126](../src/sqlcg/indexer/indexer.py#L126)), or any
|
|
38
|
+
perf-invariant surface ([`base.py`](../src/sqlcg/parsers/base.py),
|
|
39
|
+
[`indexer.py`](../src/sqlcg/indexer/indexer.py)).
|
|
40
|
+
- **No** re-index requirement: the fix reads edges that already exist in any
|
|
41
|
+
current graph.
|
|
42
|
+
- **No** change to `get_change_scope` / `get_backfill_order` / `scope_change`'s
|
|
43
|
+
downstream computation — those key off `HAS_COLUMN` + `COLUMN_LINEAGE` and were
|
|
44
|
+
verified correct on the live DWH. Out of scope.
|
|
45
|
+
- The secondary advisory finding (`defining_files` / `get_definition` show only
|
|
46
|
+
the DDL file) — **deferred**, see "Secondary finding" below.
|
|
47
|
+
- No tag, no issue close (user verifies and tags).
|
|
48
|
+
|
|
49
|
+
## Background / evidence
|
|
50
|
+
|
|
51
|
+
### How an `INSERT…SELECT` producer is recorded
|
|
52
|
+
An ETL `INSERT INTO t SELECT …` statement is parsed into a `SqlQuery` node with
|
|
53
|
+
`target` set (`QueryKind.INSERT`, see
|
|
54
|
+
[`base.py` ~L317/L645](../src/sqlcg/parsers/base.py#L317)), producing:
|
|
55
|
+
- a `SqlQuery` row with **`target_table` = the populated table** (schema:
|
|
56
|
+
[`schema.cypher` L44](../src/sqlcg/core/schema.cypher#L44), `target_table STRING`),
|
|
57
|
+
- a `QUERY_DEFINED_IN` edge **query→file** (`qdi.src_key = query.id`,
|
|
58
|
+
`qdi.dst_key = file.path`),
|
|
59
|
+
- **but no `DEFINED_IN` edge** — that edge is emitted only by DDL
|
|
60
|
+
`CREATE TABLE`/`CREATE VIEW` provenance.
|
|
61
|
+
|
|
62
|
+
### Why `diff_impact` misses it today
|
|
63
|
+
The resolution loop calls `GET_TABLES_DEFINED_IN_FILE`
|
|
64
|
+
([`tools.py` L1047](../src/sqlcg/server/tools.py#L1047)), whose query is purely
|
|
65
|
+
`SqlTable` ⋈ `DEFINED_IN` ⋈ filter `di.dst_key = ?`
|
|
66
|
+
([`queries.sql` L194](../src/sqlcg/core/queries.sql#L194)). A producer file has no
|
|
67
|
+
`DEFINED_IN` edge, so `changed_tables` stays empty → empty blast radius. The
|
|
68
|
+
existing "No tables are defined in the given files" hint
|
|
69
|
+
([`tools.py` L1090](../src/sqlcg/server/tools.py#L1090)) fires, but a caller passing
|
|
70
|
+
a real changed producer file reasonably reads an empty result as "safe". Silent
|
|
71
|
+
under-count is the worst failure mode for an impact tool.
|
|
72
|
+
|
|
73
|
+
### The edges/columns the fix relies on already exist and are already used
|
|
74
|
+
- `QUERY_DEFINED_IN` query→file is joined identically in `SEARCH_SQL_PATTERN`
|
|
75
|
+
([`queries.sql` L79](../src/sqlcg/core/queries.sql#L79)),
|
|
76
|
+
`DEPENDENT_FILES_OF_TABLES` ([L227](../src/sqlcg/core/queries.sql#L227)), and
|
|
77
|
+
`FIND_TABLE_USAGES` ([L57](../src/sqlcg/core/queries.sql#L57)).
|
|
78
|
+
- `SqlQuery.target_table` filtered to non-empty (`<> ''`) is exactly the pattern
|
|
79
|
+
in `HUB_RANKING` ([L215](../src/sqlcg/core/queries.sql#L215)) and the
|
|
80
|
+
`EXPAND_STAR_SOURCES` family ([L111](../src/sqlcg/core/queries.sql#L111)).
|
|
81
|
+
|
|
82
|
+
So no schema change, no new edge type, no indexer change, no re-index.
|
|
83
|
+
|
|
84
|
+
## Chosen fix approach: query-layer union (vs. index-time `DEFINED_IN` edge)
|
|
85
|
+
|
|
86
|
+
**Chosen: query-layer.** Add `GET_TARGET_TABLES_FOR_FILE` and union its result
|
|
87
|
+
into `diff_impact`'s per-file resolution. Rationale:
|
|
88
|
+
|
|
89
|
+
| Criterion | Query-layer (chosen) | Index-time DEFINED_IN edge (rejected) |
|
|
90
|
+
|---|---|---|
|
|
91
|
+
| Re-index required | No — reads existing edges | **Yes** — every user must re-index before the fix takes effect |
|
|
92
|
+
| Perf-invariant surface | Untouched | Touches `indexer.py` edge emission; must re-justify every CLAUDE.md invariant |
|
|
93
|
+
| `DEFINED_IN` semantics | Unchanged (DDL-only) — incremental-reindex closure stays correct | **Changes** the meaning of `DEFINED_IN`; would pollute `find_definition`, `GET_TABLE_DEFINING_FILES`, and the resync closure-frontier seeding ([`indexer.py` L670/L748](../src/sqlcg/indexer/indexer.py#L670)) with producer files, conflating "where defined" with "where populated" |
|
|
94
|
+
| Blast radius of change | One query + one loop union in `diff_impact` | Indexer dedup/merge rules, reindex delete-capture, multiple downstream queries |
|
|
95
|
+
| Cost | One extra read per changed file (cheap; same JOIN shape already used elsewhere) | N/A |
|
|
96
|
+
|
|
97
|
+
The index-time alternative has a **fatal coherence flaw**: `DEFINED_IN` is the
|
|
98
|
+
backbone of `find_definition` and the incremental-reindex closure. Overloading it
|
|
99
|
+
to also mean "populated here" would silently change `find_definition`'s
|
|
100
|
+
authoritative-file detection and the resync delete-capture set — exactly the
|
|
101
|
+
sensitive paths this plan must NOT disturb. The query-layer fix keeps "defined"
|
|
102
|
+
(DDL) and "produced/populated" (DML target) as distinct concepts and unions them
|
|
103
|
+
only at the one call site that needs both.
|
|
104
|
+
|
|
105
|
+
## Design
|
|
106
|
+
|
|
107
|
+
### New query — `GET_TARGET_TABLES_FOR_FILE`
|
|
108
|
+
Add to [`queries.sql`](../src/sqlcg/core/queries.sql) and register in
|
|
109
|
+
[`queries.py`](../src/sqlcg/core/queries.py) as
|
|
110
|
+
`GET_TARGET_TABLES_FOR_FILE_QUERY` (mirroring the existing
|
|
111
|
+
`GET_TABLES_DEFINED_IN_FILE_QUERY` registration at
|
|
112
|
+
[L59](../src/sqlcg/core/queries.py#L59)). Return the same column name
|
|
113
|
+
`table_qualified` so the `diff_impact` loop can treat both result sets uniformly:
|
|
114
|
+
|
|
115
|
+
```sql
|
|
116
|
+
-- GET_TARGET_TABLES_FOR_FILE
|
|
117
|
+
-- params: [file_path]
|
|
118
|
+
SELECT DISTINCT q.target_table AS table_qualified
|
|
119
|
+
FROM "SqlQuery" q
|
|
120
|
+
JOIN "QUERY_DEFINED_IN" qdi ON qdi.src_key = q.id
|
|
121
|
+
WHERE qdi.dst_key = ?
|
|
122
|
+
AND q.target_table <> ''
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Notes:
|
|
126
|
+
- `q.target_table <> ''` excludes SELECT-only queries (no produced table). Confirm
|
|
127
|
+
at implementation that the parser writes `''` (not NULL) for SELECT-only
|
|
128
|
+
queries; the `EXPAND_STAR_SOURCES`/`HUB_RANKING` queries already rely on `<> ''`
|
|
129
|
+
on this same column, so `''` is the established empty sentinel. If NULL is
|
|
130
|
+
possible, add `AND q.target_table IS NOT NULL`.
|
|
131
|
+
- `target_table` is stored as written by the parser. The `diff_impact` produced
|
|
132
|
+
tables flow straight into `GET_COLUMNS_FOR_TABLE` /
|
|
133
|
+
`_affected_columns_closure`, which already key off `SqlTable.qualified` /
|
|
134
|
+
`HAS_COLUMN`; an unresolved `target_table` simply yields an empty column set
|
|
135
|
+
(no downstream), which is correct degradation, not a crash.
|
|
136
|
+
|
|
137
|
+
### `diff_impact` change (additive)
|
|
138
|
+
In the per-file loop ([`tools.py` L1041-L1052](../src/sqlcg/server/tools.py#L1041)),
|
|
139
|
+
after the existing `GET_TABLES_DEFINED_IN_FILE_QUERY` read, run
|
|
140
|
+
`GET_TARGET_TABLES_FOR_FILE_QUERY` against the same resolved `str(fp)` and feed its
|
|
141
|
+
rows through the **same** `seen_changed` de-dup append. Shape:
|
|
142
|
+
|
|
143
|
+
```python
|
|
144
|
+
for query in (GET_TABLES_DEFINED_IN_FILE_QUERY, GET_TARGET_TABLES_FOR_FILE_QUERY):
|
|
145
|
+
rows = db.run_read(query, {"file_path": str(fp)})
|
|
146
|
+
for row in rows:
|
|
147
|
+
tq = row["table_qualified"]
|
|
148
|
+
if tq and tq not in seen_changed:
|
|
149
|
+
seen_changed.add(tq)
|
|
150
|
+
changed_tables.append(tq)
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
The `seen_changed` set already de-dups a table that is both DDL-defined and
|
|
154
|
+
DML-populated in the changed set, so the union is order-preserving and
|
|
155
|
+
idempotent. No change to the downstream closure, noise filter, presentation, topo
|
|
156
|
+
sort, or external-consumer batch — they all consume `changed_tables` unchanged.
|
|
157
|
+
|
|
158
|
+
### Data models
|
|
159
|
+
No model changes. `DiffImpactResult` is returned unchanged; only `changed_tables`
|
|
160
|
+
(and therefore `affected_tables`/`backfill_order`/`external_consumers`) become
|
|
161
|
+
correctly populated for producer files.
|
|
162
|
+
|
|
163
|
+
### Dependencies
|
|
164
|
+
None new.
|
|
165
|
+
|
|
166
|
+
## Implementation Steps
|
|
167
|
+
|
|
168
|
+
### Phase 1: Query
|
|
169
|
+
**Step 1.1**: Add `GET_TARGET_TABLES_FOR_FILE` block to
|
|
170
|
+
[`queries.sql`](../src/sqlcg/core/queries.sql) (after `GET_TABLES_DEFINED_IN_FILE`,
|
|
171
|
+
~L199) and register `GET_TARGET_TABLES_FOR_FILE_QUERY` in
|
|
172
|
+
[`queries.py`](../src/sqlcg/core/queries.py).
|
|
173
|
+
- Files affected: `queries.sql`, `queries.py`.
|
|
174
|
+
- Acceptance: a unit/integration assertion confirms the query, run against a graph
|
|
175
|
+
containing one `INSERT…SELECT` producer, returns the produced table by qualified
|
|
176
|
+
name and excludes SELECT-only queries.
|
|
177
|
+
|
|
178
|
+
### Phase 2: Tool
|
|
179
|
+
**Step 2.1**: Import `GET_TARGET_TABLES_FOR_FILE_QUERY` in
|
|
180
|
+
[`tools.py`](../src/sqlcg/server/tools.py) (alongside the existing import at
|
|
181
|
+
[L26](../src/sqlcg/server/tools.py#L26)) and union it into the `diff_impact`
|
|
182
|
+
per-file loop as designed above. Add `if tq` guard against empty/NULL.
|
|
183
|
+
- Files affected: `tools.py`.
|
|
184
|
+
- Acceptance: grep-confirmed call site — `GET_TARGET_TABLES_FOR_FILE_QUERY` is
|
|
185
|
+
imported AND invoked inside `diff_impact` (not merely defined). The new query is
|
|
186
|
+
called, not just registered.
|
|
187
|
+
|
|
188
|
+
### Phase 3: Repro test
|
|
189
|
+
**Step 3.1**: Add `test_diff_impact_producer_file_blast_radius` to
|
|
190
|
+
[`test_anchor_tools.py`](../tests/integration/test_anchor_tools.py) using
|
|
191
|
+
`_index_fixture`, with three SEPARATE files:
|
|
192
|
+
- `ddl.sql`: `CREATE TABLE ba.dim (id INT);` (DDL only — DEFINED_IN edge, no producer query)
|
|
193
|
+
- `producer.sql`: `INSERT INTO ba.dim SELECT id FROM ba.source;` plus a
|
|
194
|
+
`CREATE TABLE ba.source (id INT);` (so `ba.source` resolves) — OR put
|
|
195
|
+
`ba.source` DDL in its own file; the key is `ba.dim` is **populated** by
|
|
196
|
+
`producer.sql`, not DDL-defined there.
|
|
197
|
+
- `consumer.sql`: `CREATE TABLE ba.mart AS SELECT id FROM ba.dim;` (downstream).
|
|
198
|
+
|
|
199
|
+
Assertions (observable output, not "no exception"):
|
|
200
|
+
- `result = tools.diff_impact([str(tmp_path / "producer.sql")])`
|
|
201
|
+
- `"ba.dim" in result.changed_tables` — the produced table IS resolved from the
|
|
202
|
+
producer file (the core fix; fails pre-fix with an empty `changed_tables`).
|
|
203
|
+
- `"ba.mart" in result.affected_tables` — its downstream consumer appears in the
|
|
204
|
+
blast radius.
|
|
205
|
+
- Optionally assert `result.hint is None` (no "no tables defined" hint) to pin
|
|
206
|
+
that the silent-empty path is gone.
|
|
207
|
+
- Files affected: `tests/integration/test_anchor_tools.py`.
|
|
208
|
+
- Acceptance: test is RED on `master`+#38 baseline (confirm by running before the
|
|
209
|
+
`tools.py` edit) and GREEN after the fix.
|
|
210
|
+
|
|
211
|
+
**Step 3.2** (regression guard): keep the existing CTAS-based
|
|
212
|
+
`test_diff_impact_file_to_blast_radius` ([L265](../tests/integration/test_anchor_tools.py#L265))
|
|
213
|
+
green — it pins the `DEFINED_IN` path still works (the union must be additive, not
|
|
214
|
+
a replacement).
|
|
215
|
+
|
|
216
|
+
### Phase 4: Version + housekeeping
|
|
217
|
+
**Step 4.1**: Re-check current version at implementation time. If `1.4.2` (#38)
|
|
218
|
+
has shipped to `master`, bump to `1.4.3` (patch — pure bug fix, additive query, no
|
|
219
|
+
surface change) in [`pyproject.toml`](../pyproject.toml) and
|
|
220
|
+
[`src/sqlcg/__init__.py`](../src/sqlcg/__init__.py); run `uv lock`. If `1.4.2` has
|
|
221
|
+
NOT yet merged, coordinate so this branch bumps to the next patch after it. No tag
|
|
222
|
+
(user tags after merge), no issue close.
|
|
223
|
+
|
|
224
|
+
## Test Strategy
|
|
225
|
+
- **Integration** (primary): the producer-file repro in Phase 3 — the only test
|
|
226
|
+
that exercises the real DEFINED_IN-vs-QUERY_DEFINED_IN gap end to end through a
|
|
227
|
+
real DuckDB graph and the actual `diff_impact` tool.
|
|
228
|
+
- **Regression**: existing CTAS `test_diff_impact_file_to_blast_radius`,
|
|
229
|
+
presentation tests, and the full `test_anchor_tools.py` suite stay green.
|
|
230
|
+
- **Reindex non-interference**: assert (or reason in PR) that
|
|
231
|
+
`GET_TABLES_DEFINED_IN_FILE_QUERY` is unchanged and the new query is referenced
|
|
232
|
+
ONLY from `diff_impact`. The incremental-reindex paths at
|
|
233
|
+
[`indexer.py` L670](../src/sqlcg/indexer/indexer.py#L670) and
|
|
234
|
+
[L748](../src/sqlcg/indexer/indexer.py#L748) (delete-capture and closure-frontier
|
|
235
|
+
seeding) intentionally use DDL provenance and must keep using
|
|
236
|
+
`GET_TABLES_DEFINED_IN_FILE_QUERY` only — verify via grep that
|
|
237
|
+
`GET_TARGET_TABLES_FOR_FILE_QUERY` has zero references in
|
|
238
|
+
[`indexer.py`](../src/sqlcg/indexer/indexer.py).
|
|
239
|
+
- No new unit test of the query in isolation is required beyond what the
|
|
240
|
+
integration repro covers, but a thin query-level assertion (Step 1.1) is welcome.
|
|
241
|
+
|
|
242
|
+
## Acceptance Criteria
|
|
243
|
+
- [ ] `GET_TARGET_TABLES_FOR_FILE` exists in `queries.sql` and is registered as
|
|
244
|
+
`GET_TARGET_TABLES_FOR_FILE_QUERY` in `queries.py`.
|
|
245
|
+
- [ ] `diff_impact` imports AND invokes `GET_TARGET_TABLES_FOR_FILE_QUERY` inside
|
|
246
|
+
its per-file loop (grep-confirmed call site, not just a definition).
|
|
247
|
+
- [ ] New integration test: `diff_impact([producer_file])` returns the produced
|
|
248
|
+
table in `changed_tables` and its downstream consumer in `affected_tables`;
|
|
249
|
+
the test is demonstrably RED before the `tools.py` edit and GREEN after.
|
|
250
|
+
- [ ] Existing CTAS `test_diff_impact_file_to_blast_radius` and all
|
|
251
|
+
`test_anchor_tools.py` tests remain green (additive, non-regressive).
|
|
252
|
+
- [ ] `GET_TARGET_TABLES_FOR_FILE_QUERY` has zero references in
|
|
253
|
+
[`indexer.py`](../src/sqlcg/indexer/indexer.py); `GET_TABLES_DEFINED_IN_FILE`
|
|
254
|
+
query text is byte-for-byte unchanged.
|
|
255
|
+
- [ ] No edit to [`base.py`](../src/sqlcg/parsers/base.py) or
|
|
256
|
+
[`indexer.py`](../src/sqlcg/indexer/indexer.py) (perf-invariant surface
|
|
257
|
+
untouched); no re-index required for the fix to take effect.
|
|
258
|
+
- [ ] SELECT-only queries (`target_table = ''`/NULL) do not pollute
|
|
259
|
+
`changed_tables`.
|
|
260
|
+
- [ ] Version bumped to the correct next patch (expected `1.4.3`) with `uv lock`
|
|
261
|
+
refreshed; no tag, no issue close.
|
|
262
|
+
- [ ] Full gate green: `uv run pytest`, `uv run pyright`, `uv run ruff check`.
|
|
263
|
+
|
|
264
|
+
## Secondary finding — DEFER (recommended)
|
|
265
|
+
`get_change_scope.defining_files` and `find_definition` report only the DDL file,
|
|
266
|
+
not the ETL producer, because both run `GET_TABLE_DEFINING_FILES_QUERY` (DDL
|
|
267
|
+
`DEFINED_IN` only — [`tools.py` L907](../src/sqlcg/server/tools.py#L907),
|
|
268
|
+
[`queries.sql` L167](../src/sqlcg/core/queries.sql#L167)).
|
|
269
|
+
|
|
270
|
+
**Recommendation: defer to a separate follow-up, do NOT bundle here.** Reasons:
|
|
271
|
+
1. **Different semantics, different decision.** `defining_files` answers "where is
|
|
272
|
+
this table *defined*" (an authoritativeness/governance question that
|
|
273
|
+
`find_definition` builds is_authoritative/is_backup/duplicate_ddl on top of).
|
|
274
|
+
Folding producer files in changes the meaning of that field and would ripple
|
|
275
|
+
into `find_definition`'s authoritative-file logic and its model — a design
|
|
276
|
+
choice that deserves its own plan, not a rider on an impact-tool patch.
|
|
277
|
+
2. **`diff_impact` is the bug with the silent-under-count failure mode**; the
|
|
278
|
+
secondary one is advisory (a user inspecting a *table* still gets correct
|
|
279
|
+
downstream via `get_change_scope`). Coupling them widens the PR's blast radius
|
|
280
|
+
and review surface for no urgency.
|
|
281
|
+
3. **Memory rule** "never fold new work into an already-reviewed PR / ship a
|
|
282
|
+
separate patch" applies in spirit: keep this PR tightly scoped to the
|
|
283
|
+
file→produced-table resolution fix.
|
|
284
|
+
|
|
285
|
+
If pursued later, the shape would be a new `producing_files` field (NOT overloading
|
|
286
|
+
`defining_files`) sourced from `QUERY_DEFINED_IN` + non-empty `target_table` for
|
|
287
|
+
the given table — a clean additive surface. Note it in `ARCHITECTURE_REVIEW.md` as
|
|
288
|
+
a deferred follow-up.
|
|
289
|
+
|
|
290
|
+
## Risks and Mitigations
|
|
291
|
+
- **Risk: unresolved `target_table` (no matching `SqlTable`).** A produced table
|
|
292
|
+
whose `qualified` does not match any `SqlTable` row yields an empty
|
|
293
|
+
`GET_COLUMNS_FOR_TABLE` result → no downstream contribution, but it still
|
|
294
|
+
correctly appears in `changed_tables`. Degrades gracefully; no crash.
|
|
295
|
+
*Mitigation*: covered by the repro (the produced `ba.dim` has DDL elsewhere so it
|
|
296
|
+
resolves; assert it appears in `changed_tables` regardless).
|
|
297
|
+
- **Risk: NULL vs empty-string `target_table`.** *Mitigation*: confirm parser
|
|
298
|
+
writes `''`; the `<> ''` filter matches existing `HUB_RANKING`/`EXPAND_STAR`
|
|
299
|
+
convention. Add `IS NOT NULL` if NULL is observed.
|
|
300
|
+
- **Risk: double-count when a table is both DDL-defined and DML-populated in the
|
|
301
|
+
same changed set.** *Mitigation*: `seen_changed` de-dup already handles this;
|
|
302
|
+
union is idempotent.
|
|
303
|
+
- **Risk: perf — one extra read per changed file.** *Mitigation*: `diff_impact`
|
|
304
|
+
operates on a PR-sized file list (tens, not thousands); the new query reuses an
|
|
305
|
+
index-friendly JOIN already present in three other queries. Not on the
|
|
306
|
+
index/parse hot path; CLAUDE.md perf invariants are untouched.
|
|
307
|
+
- **Risk: breaking incremental reindex.** *Mitigation*: the fix never touches
|
|
308
|
+
`GET_TABLES_DEFINED_IN_FILE` or `DEFINED_IN`; acceptance criterion pins zero
|
|
309
|
+
`indexer.py` references to the new query.
|
|
310
|
+
|
|
311
|
+
## Rollout / rollback
|
|
312
|
+
- Rollout: ships in the patch release; takes effect immediately on existing graphs
|
|
313
|
+
(no re-index).
|
|
314
|
+
- Rollback: revert the `tools.py` union and the two query additions — fully
|
|
315
|
+
isolated, no migration, no data shape change.
|
|
316
|
+
|
|
317
|
+
### Blocking Questions
|
|
318
|
+
None. `QUERY_DEFINED_IN` (query→file via `dst_key`) and `SqlQuery.target_table`
|
|
319
|
+
are confirmed present in [`schema.cypher`](../src/sqlcg/core/schema.cypher) and
|
|
320
|
+
already used by `SEARCH_SQL_PATTERN` / `DEPENDENT_FILES_OF_TABLES` /
|
|
321
|
+
`GET_TABLE_DIRECT_UPSTREAMS`; the empty sentinel `''` convention is established.
|