@intentius/chant-lexicon-sql 0.0.0-stage → 0.112.1
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.
- package/README.md +39 -2
- package/dist/clickhouse/apply/apply.d.ts +82 -0
- package/dist/clickhouse/apply/apply.d.ts.map +1 -0
- package/dist/clickhouse/apply/mutations.d.ts +46 -0
- package/dist/clickhouse/apply/mutations.d.ts.map +1 -0
- package/dist/clickhouse/apply/statements.d.ts +99 -0
- package/dist/clickhouse/apply/statements.d.ts.map +1 -0
- package/dist/clickhouse/catalog-types.d.ts +76 -0
- package/dist/clickhouse/catalog-types.d.ts.map +1 -0
- package/dist/clickhouse/container.d.ts +63 -0
- package/dist/clickhouse/container.d.ts.map +1 -0
- package/dist/clickhouse/engine-syntax.d.ts +43 -0
- package/dist/clickhouse/engine-syntax.d.ts.map +1 -0
- package/dist/clickhouse/entities.d.ts +183 -0
- package/dist/clickhouse/entities.d.ts.map +1 -0
- package/dist/clickhouse/http.d.ts +40 -0
- package/dist/clickhouse/http.d.ts.map +1 -0
- package/dist/clickhouse/import/generator.d.ts +16 -0
- package/dist/clickhouse/import/generator.d.ts.map +1 -0
- package/dist/clickhouse/import/ir.d.ts +52 -0
- package/dist/clickhouse/import/ir.d.ts.map +1 -0
- package/dist/clickhouse/import/live-export.d.ts +28 -0
- package/dist/clickhouse/import/live-export.d.ts.map +1 -0
- package/dist/clickhouse/import/parser.d.ts +10 -0
- package/dist/clickhouse/import/parser.d.ts.map +1 -0
- package/dist/clickhouse/live/bind.d.ts +56 -0
- package/dist/clickhouse/live/bind.d.ts.map +1 -0
- package/dist/clickhouse/live/catalog.d.ts +39 -0
- package/dist/clickhouse/live/catalog.d.ts.map +1 -0
- package/dist/clickhouse/live/describe-resources.d.ts +34 -0
- package/dist/clickhouse/live/describe-resources.d.ts.map +1 -0
- package/dist/clickhouse/overlays/codecs.d.ts +28 -0
- package/dist/clickhouse/overlays/codecs.d.ts.map +1 -0
- package/dist/clickhouse/overlays/engines.d.ts +20 -0
- package/dist/clickhouse/overlays/engines.d.ts.map +1 -0
- package/dist/clickhouse/overlays/kinds.d.ts +38 -0
- package/dist/clickhouse/overlays/kinds.d.ts.map +1 -0
- package/dist/clickhouse/overlays/projections.d.ts +27 -0
- package/dist/clickhouse/overlays/projections.d.ts.map +1 -0
- package/dist/clickhouse/overlays/skip-indexes.d.ts +10 -0
- package/dist/clickhouse/overlays/skip-indexes.d.ts.map +1 -0
- package/dist/clickhouse/overlays/ttl.d.ts +35 -0
- package/dist/clickhouse/overlays/ttl.d.ts.map +1 -0
- package/dist/clickhouse/overlays/types.d.ts +21 -0
- package/dist/clickhouse/overlays/types.d.ts.map +1 -0
- package/dist/clickhouse/ownership.d.ts +71 -0
- package/dist/clickhouse/ownership.d.ts.map +1 -0
- package/dist/clickhouse/parser.d.ts +130 -0
- package/dist/clickhouse/parser.d.ts.map +1 -0
- package/dist/clickhouse/plan/commands.d.ts +26 -0
- package/dist/clickhouse/plan/commands.d.ts.map +1 -0
- package/dist/clickhouse/plan/deep.d.ts +32 -0
- package/dist/clickhouse/plan/deep.d.ts.map +1 -0
- package/dist/clickhouse/plan/diff.d.ts +37 -0
- package/dist/clickhouse/plan/diff.d.ts.map +1 -0
- package/dist/clickhouse/plan/disruption.d.ts +17 -0
- package/dist/clickhouse/plan/disruption.d.ts.map +1 -0
- package/dist/clickhouse/plan/normalize.d.ts +97 -0
- package/dist/clickhouse/plan/normalize.d.ts.map +1 -0
- package/dist/clickhouse/plan/rebuild-handoff.d.ts +38 -0
- package/dist/clickhouse/plan/rebuild-handoff.d.ts.map +1 -0
- package/dist/clickhouse/plan/report.d.ts +6 -0
- package/dist/clickhouse/plan/report.d.ts.map +1 -0
- package/dist/clickhouse/plan/rules.d.ts +60 -0
- package/dist/clickhouse/plan/rules.d.ts.map +1 -0
- package/dist/clickhouse/plan/schema.d.ts +23 -0
- package/dist/clickhouse/plan/schema.d.ts.map +1 -0
- package/dist/clickhouse/plan/server-format.d.ts +12 -0
- package/dist/clickhouse/plan/server-format.d.ts.map +1 -0
- package/dist/clickhouse/rebuild/backfill.d.ts +70 -0
- package/dist/clickhouse/rebuild/backfill.d.ts.map +1 -0
- package/dist/clickhouse/rebuild/observe.d.ts +157 -0
- package/dist/clickhouse/rebuild/observe.d.ts.map +1 -0
- package/dist/clickhouse/rebuild/op.d.ts +108 -0
- package/dist/clickhouse/rebuild/op.d.ts.map +1 -0
- package/dist/clickhouse/rebuild/partitions.d.ts +24 -0
- package/dist/clickhouse/rebuild/partitions.d.ts.map +1 -0
- package/dist/clickhouse/rebuild/receipts.d.ts +76 -0
- package/dist/clickhouse/rebuild/receipts.d.ts.map +1 -0
- package/dist/clickhouse/rebuild/replicas.d.ts +78 -0
- package/dist/clickhouse/rebuild/replicas.d.ts.map +1 -0
- package/dist/clickhouse/rebuild/steps.d.ts +151 -0
- package/dist/clickhouse/rebuild/steps.d.ts.map +1 -0
- package/dist/clickhouse/rebuild/verify.d.ts +51 -0
- package/dist/clickhouse/rebuild/verify.d.ts.map +1 -0
- package/dist/clickhouse/testing/fake-server.d.ts +27 -0
- package/dist/clickhouse/testing/fake-server.d.ts.map +1 -0
- package/dist/clickhouse/testing/roundtrip-schema.d.ts +3 -0
- package/dist/clickhouse/testing/roundtrip-schema.d.ts.map +1 -0
- package/dist/clickhouse/testing/writable-server.d.ts +35 -0
- package/dist/clickhouse/testing/writable-server.d.ts.map +1 -0
- package/dist/clickhouse/tokens.d.ts +15 -0
- package/dist/clickhouse/tokens.d.ts.map +1 -0
- package/dist/clickhouse.d.ts +24 -0
- package/dist/clickhouse.d.ts.map +1 -0
- package/dist/codegen/classifier-page.d.ts +6 -0
- package/dist/codegen/classifier-page.d.ts.map +1 -0
- package/dist/codegen/clickhouse-module.d.ts +23 -0
- package/dist/codegen/clickhouse-module.d.ts.map +1 -0
- package/dist/codegen/docs-cli.d.ts +3 -0
- package/dist/codegen/docs-cli.d.ts.map +1 -0
- package/dist/codegen/docs.d.ts +8 -0
- package/dist/codegen/docs.d.ts.map +1 -0
- package/dist/codegen/generate-cli.d.ts +3 -0
- package/dist/codegen/generate-cli.d.ts.map +1 -0
- package/dist/codegen/generate.d.ts +40 -0
- package/dist/codegen/generate.d.ts.map +1 -0
- package/dist/codegen/package.d.ts +7 -0
- package/dist/codegen/package.d.ts.map +1 -0
- package/dist/codegen/postgres-classifier-page.d.ts +7 -0
- package/dist/codegen/postgres-classifier-page.d.ts.map +1 -0
- package/dist/codegen/postgres-module.d.ts +30 -0
- package/dist/codegen/postgres-module.d.ts.map +1 -0
- package/dist/codegen/registry.d.ts +12 -0
- package/dist/codegen/registry.d.ts.map +1 -0
- package/dist/composites/audit-log-table.d.ts +31 -0
- package/dist/composites/audit-log-table.d.ts.map +1 -0
- package/dist/composites/catalog.d.ts +3 -0
- package/dist/composites/catalog.d.ts.map +1 -0
- package/dist/composites/cdc-mirror.d.ts +32 -0
- package/dist/composites/cdc-mirror.d.ts.map +1 -0
- package/dist/composites/clickhouse.d.ts +7 -0
- package/dist/composites/clickhouse.d.ts.map +1 -0
- package/dist/composites/events-table.d.ts +32 -0
- package/dist/composites/events-table.d.ts.map +1 -0
- package/dist/composites/index.d.ts +9 -0
- package/dist/composites/index.d.ts.map +1 -0
- package/dist/composites/join-table.d.ts +41 -0
- package/dist/composites/join-table.d.ts.map +1 -0
- package/dist/composites/postgres.d.ts +7 -0
- package/dist/composites/postgres.d.ts.map +1 -0
- package/dist/composites/refreshed-view.d.ts +32 -0
- package/dist/composites/refreshed-view.d.ts.map +1 -0
- package/dist/composites/replacing-table.d.ts +34 -0
- package/dist/composites/replacing-table.d.ts.map +1 -0
- package/dist/composites/rollup-view.d.ts +39 -0
- package/dist/composites/rollup-view.d.ts.map +1 -0
- package/dist/composites/sharded-table.d.ts +35 -0
- package/dist/composites/sharded-table.d.ts.map +1 -0
- package/dist/composites/soft-delete-table.d.ts +40 -0
- package/dist/composites/soft-delete-table.d.ts.map +1 -0
- package/dist/composites/tenant-table.d.ts +34 -0
- package/dist/composites/tenant-table.d.ts.map +1 -0
- package/dist/config.d.ts +213 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/core/apply.d.ts +89 -0
- package/dist/core/apply.d.ts.map +1 -0
- package/dist/core/classifier.d.ts +88 -0
- package/dist/core/classifier.d.ts.map +1 -0
- package/dist/core/container.d.ts +45 -0
- package/dist/core/container.d.ts.map +1 -0
- package/dist/core/cursor.d.ts +67 -0
- package/dist/core/cursor.d.ts.map +1 -0
- package/dist/core/diff.d.ts +49 -0
- package/dist/core/diff.d.ts.map +1 -0
- package/dist/core/entity.d.ts +41 -0
- package/dist/core/entity.d.ts.map +1 -0
- package/dist/core/find-templates.d.ts +69 -0
- package/dist/core/find-templates.d.ts.map +1 -0
- package/dist/core/handoff.d.ts +36 -0
- package/dist/core/handoff.d.ts.map +1 -0
- package/dist/core/index.d.ts +61 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/interpolation.d.ts +88 -0
- package/dist/core/interpolation.d.ts.map +1 -0
- package/dist/core/normalize.d.ts +18 -0
- package/dist/core/normalize.d.ts.map +1 -0
- package/dist/core/ownership.d.ts +60 -0
- package/dist/core/ownership.d.ts.map +1 -0
- package/dist/core/receipts.d.ts +28 -0
- package/dist/core/receipts.d.ts.map +1 -0
- package/dist/core/references.d.ts +37 -0
- package/dist/core/references.d.ts.map +1 -0
- package/dist/core/template.d.ts +41 -0
- package/dist/core/template.d.ts.map +1 -0
- package/dist/core/testing/http-stub.d.ts +17 -0
- package/dist/core/testing/http-stub.d.ts.map +1 -0
- package/dist/core/tokens.d.ts +102 -0
- package/dist/core/tokens.d.ts.map +1 -0
- package/dist/coverage.d.ts +25 -0
- package/dist/coverage.d.ts.map +1 -0
- package/dist/detect.d.ts +15 -0
- package/dist/detect.d.ts.map +1 -0
- package/dist/dialects.d.ts +20 -0
- package/dist/dialects.d.ts.map +1 -0
- package/dist/generated/clickhouse-types.d.ts +4380 -0
- package/dist/generated/clickhouse-types.d.ts.map +1 -0
- package/dist/generated/clickhouse.d.ts +11 -0
- package/dist/generated/clickhouse.d.ts.map +1 -0
- package/dist/generated/postgres-types.d.ts +1579 -0
- package/dist/generated/postgres-types.d.ts.map +1 -0
- package/dist/generated/postgres.d.ts +9 -0
- package/dist/generated/postgres.d.ts.map +1 -0
- package/dist/import-generator.d.ts +8 -0
- package/dist/import-generator.d.ts.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/init-templates.d.ts +20 -0
- package/dist/init-templates.d.ts.map +1 -0
- package/dist/integrity.json +61 -0
- package/dist/lint/audit-catalog.d.ts +10 -0
- package/dist/lint/audit-catalog.d.ts.map +1 -0
- package/dist/lint/audit-lineage.d.ts +25 -0
- package/dist/lint/audit-lineage.d.ts.map +1 -0
- package/dist/lint/post-synth/audit-entries.d.ts +8 -0
- package/dist/lint/post-synth/audit-entries.d.ts.map +1 -0
- package/dist/lint/post-synth/clickhouse-helpers.d.ts +85 -0
- package/dist/lint/post-synth/clickhouse-helpers.d.ts.map +1 -0
- package/dist/lint/post-synth/index.d.ts +3 -0
- package/dist/lint/post-synth/index.d.ts.map +1 -0
- package/dist/lint/post-synth/postgres-audit-entries.d.ts +9 -0
- package/dist/lint/post-synth/postgres-audit-entries.d.ts.map +1 -0
- package/dist/lint/post-synth/postgres-helpers.d.ts +89 -0
- package/dist/lint/post-synth/postgres-helpers.d.ts.map +1 -0
- package/dist/lint/post-synth/sql-helpers.d.ts +27 -0
- package/dist/lint/post-synth/sql-helpers.d.ts.map +1 -0
- package/dist/lint/post-synth/sqlch101.d.ts +12 -0
- package/dist/lint/post-synth/sqlch101.d.ts.map +1 -0
- package/dist/lint/post-synth/sqlch102.d.ts +9 -0
- package/dist/lint/post-synth/sqlch102.d.ts.map +1 -0
- package/dist/lint/post-synth/sqlch103.d.ts +10 -0
- package/dist/lint/post-synth/sqlch103.d.ts.map +1 -0
- package/dist/lint/post-synth/sqlch104.d.ts +9 -0
- package/dist/lint/post-synth/sqlch104.d.ts.map +1 -0
- package/dist/lint/post-synth/sqlch105.d.ts +10 -0
- package/dist/lint/post-synth/sqlch105.d.ts.map +1 -0
- package/dist/lint/post-synth/sqlch106.d.ts +11 -0
- package/dist/lint/post-synth/sqlch106.d.ts.map +1 -0
- package/dist/lint/post-synth/sqlch107.d.ts +10 -0
- package/dist/lint/post-synth/sqlch107.d.ts.map +1 -0
- package/dist/lint/post-synth/sqlch108.d.ts +11 -0
- package/dist/lint/post-synth/sqlch108.d.ts.map +1 -0
- package/dist/lint/post-synth/sqlch109.d.ts +10 -0
- package/dist/lint/post-synth/sqlch109.d.ts.map +1 -0
- package/dist/lint/post-synth/sqlch110.d.ts +12 -0
- package/dist/lint/post-synth/sqlch110.d.ts.map +1 -0
- package/dist/lint/post-synth/sqlch111.d.ts +11 -0
- package/dist/lint/post-synth/sqlch111.d.ts.map +1 -0
- package/dist/lint/post-synth/sqlch112.d.ts +12 -0
- package/dist/lint/post-synth/sqlch112.d.ts.map +1 -0
- package/dist/lint/post-synth/sqlch113.d.ts +9 -0
- package/dist/lint/post-synth/sqlch113.d.ts.map +1 -0
- package/dist/lint/post-synth/sqlch114.d.ts +8 -0
- package/dist/lint/post-synth/sqlch114.d.ts.map +1 -0
- package/dist/lint/post-synth/sqlch115.d.ts +13 -0
- package/dist/lint/post-synth/sqlch115.d.ts.map +1 -0
- package/dist/lint/post-synth/sqlch116.d.ts +10 -0
- package/dist/lint/post-synth/sqlch116.d.ts.map +1 -0
- package/dist/lint/post-synth/sqlch117.d.ts +9 -0
- package/dist/lint/post-synth/sqlch117.d.ts.map +1 -0
- package/dist/lint/post-synth/sqlch118.d.ts +10 -0
- package/dist/lint/post-synth/sqlch118.d.ts.map +1 -0
- package/dist/lint/post-synth/sqlch119.d.ts +11 -0
- package/dist/lint/post-synth/sqlch119.d.ts.map +1 -0
- package/dist/lint/post-synth/sqlch120.d.ts +10 -0
- package/dist/lint/post-synth/sqlch120.d.ts.map +1 -0
- package/dist/lint/post-synth/sqlpg101.d.ts +12 -0
- package/dist/lint/post-synth/sqlpg101.d.ts.map +1 -0
- package/dist/lint/post-synth/sqlpg102.d.ts +11 -0
- package/dist/lint/post-synth/sqlpg102.d.ts.map +1 -0
- package/dist/lint/post-synth/sqlpg103.d.ts +11 -0
- package/dist/lint/post-synth/sqlpg103.d.ts.map +1 -0
- package/dist/lint/post-synth/sqlpg104.d.ts +10 -0
- package/dist/lint/post-synth/sqlpg104.d.ts.map +1 -0
- package/dist/lint/post-synth/sqlpg105.d.ts +10 -0
- package/dist/lint/post-synth/sqlpg105.d.ts.map +1 -0
- package/dist/lint/post-synth/sqlpg106.d.ts +9 -0
- package/dist/lint/post-synth/sqlpg106.d.ts.map +1 -0
- package/dist/lint/post-synth/sqlpg107.d.ts +10 -0
- package/dist/lint/post-synth/sqlpg107.d.ts.map +1 -0
- package/dist/lint/post-synth/sqlpg108.d.ts +11 -0
- package/dist/lint/post-synth/sqlpg108.d.ts.map +1 -0
- package/dist/lint/post-synth/sqlpg109.d.ts +11 -0
- package/dist/lint/post-synth/sqlpg109.d.ts.map +1 -0
- package/dist/lint/post-synth/sqlpg110.d.ts +12 -0
- package/dist/lint/post-synth/sqlpg110.d.ts.map +1 -0
- package/dist/lint/post-synth/sqlpg111.d.ts +10 -0
- package/dist/lint/post-synth/sqlpg111.d.ts.map +1 -0
- package/dist/lint/post-synth/sqlpg112.d.ts +10 -0
- package/dist/lint/post-synth/sqlpg112.d.ts.map +1 -0
- package/dist/lint/post-synth/sqlpg113.d.ts +11 -0
- package/dist/lint/post-synth/sqlpg113.d.ts.map +1 -0
- package/dist/lint/post-synth/sqlpg114.d.ts +13 -0
- package/dist/lint/post-synth/sqlpg114.d.ts.map +1 -0
- package/dist/lint/post-synth/sqlpg115.d.ts +13 -0
- package/dist/lint/post-synth/sqlpg115.d.ts.map +1 -0
- package/dist/lint/post-synth/sqlpg116.d.ts +11 -0
- package/dist/lint/post-synth/sqlpg116.d.ts.map +1 -0
- package/dist/lint/post-synth/sqlpg117.d.ts +12 -0
- package/dist/lint/post-synth/sqlpg117.d.ts.map +1 -0
- package/dist/lint/post-synth/sqlpg118.d.ts +12 -0
- package/dist/lint/post-synth/sqlpg118.d.ts.map +1 -0
- package/dist/lint/rules/index.d.ts +12 -0
- package/dist/lint/rules/index.d.ts.map +1 -0
- package/dist/lint/rules/postgres-templates.d.ts +18 -0
- package/dist/lint/rules/postgres-templates.d.ts.map +1 -0
- package/dist/lint/rules/sqlch001.d.ts +12 -0
- package/dist/lint/rules/sqlch001.d.ts.map +1 -0
- package/dist/lint/rules/sqlch002.d.ts +11 -0
- package/dist/lint/rules/sqlch002.d.ts.map +1 -0
- package/dist/lint/rules/sqlch003.d.ts +12 -0
- package/dist/lint/rules/sqlch003.d.ts.map +1 -0
- package/dist/lint/rules/sqlpg001.d.ts +16 -0
- package/dist/lint/rules/sqlpg001.d.ts.map +1 -0
- package/dist/lint/rules/sqlpg002.d.ts +12 -0
- package/dist/lint/rules/sqlpg002.d.ts.map +1 -0
- package/dist/lint/rules/sqlpg003.d.ts +16 -0
- package/dist/lint/rules/sqlpg003.d.ts.map +1 -0
- package/dist/lint/rules/sqlpg004.d.ts +21 -0
- package/dist/lint/rules/sqlpg004.d.ts.map +1 -0
- package/dist/lint/rules/templates.d.ts +23 -0
- package/dist/lint/rules/templates.d.ts.map +1 -0
- package/dist/live-dialect.d.ts +25 -0
- package/dist/live-dialect.d.ts.map +1 -0
- package/dist/lsp/catalog.d.ts +22 -0
- package/dist/lsp/catalog.d.ts.map +1 -0
- package/dist/lsp/completions.d.ts +13 -0
- package/dist/lsp/completions.d.ts.map +1 -0
- package/dist/lsp/hover.d.ts +12 -0
- package/dist/lsp/hover.d.ts.map +1 -0
- package/dist/lsp/postgres-catalog.d.ts +85 -0
- package/dist/lsp/postgres-catalog.d.ts.map +1 -0
- package/dist/lsp/postgres-template.d.ts +35 -0
- package/dist/lsp/postgres-template.d.ts.map +1 -0
- package/dist/lsp/postgres.d.ts +20 -0
- package/dist/lsp/postgres.d.ts.map +1 -0
- package/dist/lsp/refs.d.ts +8 -0
- package/dist/lsp/refs.d.ts.map +1 -0
- package/dist/lsp/registry.d.ts +4 -0
- package/dist/lsp/registry.d.ts.map +1 -0
- package/dist/lsp/template.d.ts +34 -0
- package/dist/lsp/template.d.ts.map +1 -0
- package/dist/manifest.json +8 -0
- package/dist/mcp/index.d.ts +13 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/postgres.d.ts +32 -0
- package/dist/mcp/postgres.d.ts.map +1 -0
- package/dist/meta.json +67 -0
- package/dist/okf/index.md +67 -0
- package/dist/okf/rules/SQLCH001.md +11 -0
- package/dist/okf/rules/SQLCH002.md +11 -0
- package/dist/okf/rules/SQLCH003.md +11 -0
- package/dist/okf/rules/SQLCH101.md +15 -0
- package/dist/okf/rules/SQLCH102.md +11 -0
- package/dist/okf/rules/SQLCH103.md +11 -0
- package/dist/okf/rules/SQLCH104.md +11 -0
- package/dist/okf/rules/SQLCH105.md +11 -0
- package/dist/okf/rules/SQLCH106.md +11 -0
- package/dist/okf/rules/SQLCH107.md +11 -0
- package/dist/okf/rules/SQLCH108.md +15 -0
- package/dist/okf/rules/SQLCH109.md +11 -0
- package/dist/okf/rules/SQLCH110.md +11 -0
- package/dist/okf/rules/SQLCH111.md +11 -0
- package/dist/okf/rules/SQLCH112.md +11 -0
- package/dist/okf/rules/SQLCH113.md +11 -0
- package/dist/okf/rules/SQLCH114.md +11 -0
- package/dist/okf/rules/SQLCH115.md +11 -0
- package/dist/okf/rules/SQLCH116.md +11 -0
- package/dist/okf/rules/SQLCH117.md +15 -0
- package/dist/okf/rules/SQLCH118.md +15 -0
- package/dist/okf/rules/SQLCH119.md +15 -0
- package/dist/okf/rules/SQLCH120.md +15 -0
- package/dist/okf/rules/SQLPG001.md +11 -0
- package/dist/okf/rules/SQLPG002.md +11 -0
- package/dist/okf/rules/SQLPG003.md +11 -0
- package/dist/okf/rules/SQLPG004.md +11 -0
- package/dist/okf/rules/SQLPG101.md +11 -0
- package/dist/okf/rules/SQLPG102.md +11 -0
- package/dist/okf/rules/SQLPG103.md +11 -0
- package/dist/okf/rules/SQLPG104.md +11 -0
- package/dist/okf/rules/SQLPG105.md +11 -0
- package/dist/okf/rules/SQLPG106.md +11 -0
- package/dist/okf/rules/SQLPG107.md +11 -0
- package/dist/okf/rules/SQLPG108.md +11 -0
- package/dist/okf/rules/SQLPG109.md +11 -0
- package/dist/okf/rules/SQLPG110.md +11 -0
- package/dist/okf/rules/SQLPG111.md +11 -0
- package/dist/okf/rules/SQLPG112.md +11 -0
- package/dist/okf/rules/SQLPG113.md +24 -0
- package/dist/okf/rules/SQLPG114.md +11 -0
- package/dist/okf/rules/SQLPG115.md +11 -0
- package/dist/okf/rules/SQLPG116.md +15 -0
- package/dist/okf/rules/SQLPG117.md +11 -0
- package/dist/okf/rules/SQLPG118.md +11 -0
- package/dist/okf/types/Database.md +15 -0
- package/dist/okf/types/MaterializedView.md +14 -0
- package/dist/okf/types/PostgresDomain.md +13 -0
- package/dist/okf/types/PostgresEnum.md +13 -0
- package/dist/okf/types/PostgresExtension.md +13 -0
- package/dist/okf/types/PostgresIndex.md +9 -0
- package/dist/okf/types/PostgresMaterializedView.md +13 -0
- package/dist/okf/types/PostgresSchema.md +13 -0
- package/dist/okf/types/PostgresSequence.md +13 -0
- package/dist/okf/types/PostgresTable.md +13 -0
- package/dist/okf/types/PostgresView.md +13 -0
- package/dist/okf/types/Table.md +15 -0
- package/dist/okf/types/View.md +13 -0
- package/dist/op/activities/clickhouse-apply.d.ts +56 -0
- package/dist/op/activities/clickhouse-apply.d.ts.map +1 -0
- package/dist/op/activities/clickhouse-emulator.d.ts +26 -0
- package/dist/op/activities/clickhouse-emulator.d.ts.map +1 -0
- package/dist/op/activities/clickhouse-rebuild.d.ts +43 -0
- package/dist/op/activities/clickhouse-rebuild.d.ts.map +1 -0
- package/dist/op/activities/index.d.ts +19 -0
- package/dist/op/activities/index.d.ts.map +1 -0
- package/dist/op/activities/postgres-apply.d.ts +69 -0
- package/dist/op/activities/postgres-apply.d.ts.map +1 -0
- package/dist/op/activities/postgres-emulator.d.ts +33 -0
- package/dist/op/activities/postgres-emulator.d.ts.map +1 -0
- package/dist/op/activities/postgres-migration.d.ts +48 -0
- package/dist/op/activities/postgres-migration.d.ts.map +1 -0
- package/dist/op/activity-contracts.d.ts +464 -0
- package/dist/op/activity-contracts.d.ts.map +1 -0
- package/dist/package-cli.d.ts +3 -0
- package/dist/package-cli.d.ts.map +1 -0
- package/dist/plugin.d.ts +12 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/postgres/apply/apply.d.ts +163 -0
- package/dist/postgres/apply/apply.d.ts.map +1 -0
- package/dist/postgres/apply/statements.d.ts +138 -0
- package/dist/postgres/apply/statements.d.ts.map +1 -0
- package/dist/postgres/catalog-types.d.ts +50 -0
- package/dist/postgres/catalog-types.d.ts.map +1 -0
- package/dist/postgres/container.d.ts +23 -0
- package/dist/postgres/container.d.ts.map +1 -0
- package/dist/postgres/entities.d.ts +322 -0
- package/dist/postgres/entities.d.ts.map +1 -0
- package/dist/postgres/entity-types.d.ts +17 -0
- package/dist/postgres/entity-types.d.ts.map +1 -0
- package/dist/postgres/import/generator.d.ts +28 -0
- package/dist/postgres/import/generator.d.ts.map +1 -0
- package/dist/postgres/import/ir.d.ts +24 -0
- package/dist/postgres/import/ir.d.ts.map +1 -0
- package/dist/postgres/import/live-export.d.ts +26 -0
- package/dist/postgres/import/live-export.d.ts.map +1 -0
- package/dist/postgres/keywords.d.ts +22 -0
- package/dist/postgres/keywords.d.ts.map +1 -0
- package/dist/postgres/live/bind.d.ts +76 -0
- package/dist/postgres/live/bind.d.ts.map +1 -0
- package/dist/postgres/live/catalog.d.ts +98 -0
- package/dist/postgres/live/catalog.d.ts.map +1 -0
- package/dist/postgres/live/client.d.ts +32 -0
- package/dist/postgres/live/client.d.ts.map +1 -0
- package/dist/postgres/live/describe-resources.d.ts +41 -0
- package/dist/postgres/live/describe-resources.d.ts.map +1 -0
- package/dist/postgres/migrate/backfill.d.ts +103 -0
- package/dist/postgres/migrate/backfill.d.ts.map +1 -0
- package/dist/postgres/migrate/batches.d.ts +90 -0
- package/dist/postgres/migrate/batches.d.ts.map +1 -0
- package/dist/postgres/migrate/carry.d.ts +196 -0
- package/dist/postgres/migrate/carry.d.ts.map +1 -0
- package/dist/postgres/migrate/handoff.d.ts +46 -0
- package/dist/postgres/migrate/handoff.d.ts.map +1 -0
- package/dist/postgres/migrate/names.d.ts +55 -0
- package/dist/postgres/migrate/names.d.ts.map +1 -0
- package/dist/postgres/migrate/observe.d.ts +139 -0
- package/dist/postgres/migrate/observe.d.ts.map +1 -0
- package/dist/postgres/migrate/op.d.ts +128 -0
- package/dist/postgres/migrate/op.d.ts.map +1 -0
- package/dist/postgres/migrate/receipts.d.ts +63 -0
- package/dist/postgres/migrate/receipts.d.ts.map +1 -0
- package/dist/postgres/migrate/replication.d.ts +80 -0
- package/dist/postgres/migrate/replication.d.ts.map +1 -0
- package/dist/postgres/migrate/steps.d.ts +225 -0
- package/dist/postgres/migrate/steps.d.ts.map +1 -0
- package/dist/postgres/overlays/columns.d.ts +6 -0
- package/dist/postgres/overlays/columns.d.ts.map +1 -0
- package/dist/postgres/overlays/constraints.d.ts +8 -0
- package/dist/postgres/overlays/constraints.d.ts.map +1 -0
- package/dist/postgres/overlays/indexes.d.ts +8 -0
- package/dist/postgres/overlays/indexes.d.ts.map +1 -0
- package/dist/postgres/overlays/kinds.d.ts +48 -0
- package/dist/postgres/overlays/kinds.d.ts.map +1 -0
- package/dist/postgres/overlays/partitioning.d.ts +5 -0
- package/dist/postgres/overlays/partitioning.d.ts.map +1 -0
- package/dist/postgres/overlays/relations.d.ts +6 -0
- package/dist/postgres/overlays/relations.d.ts.map +1 -0
- package/dist/postgres/overlays/storage.d.ts +28 -0
- package/dist/postgres/overlays/storage.d.ts.map +1 -0
- package/dist/postgres/overlays/type-ddl.d.ts +7 -0
- package/dist/postgres/overlays/type-ddl.d.ts.map +1 -0
- package/dist/postgres/overlays/types.d.ts +24 -0
- package/dist/postgres/overlays/types.d.ts.map +1 -0
- package/dist/postgres/parser.d.ts +216 -0
- package/dist/postgres/parser.d.ts.map +1 -0
- package/dist/postgres/plan/commands.d.ts +61 -0
- package/dist/postgres/plan/commands.d.ts.map +1 -0
- package/dist/postgres/plan/deep.d.ts +33 -0
- package/dist/postgres/plan/deep.d.ts.map +1 -0
- package/dist/postgres/plan/diff.d.ts +45 -0
- package/dist/postgres/plan/diff.d.ts.map +1 -0
- package/dist/postgres/plan/disruption.d.ts +14 -0
- package/dist/postgres/plan/disruption.d.ts.map +1 -0
- package/dist/postgres/plan/normalize.d.ts +108 -0
- package/dist/postgres/plan/normalize.d.ts.map +1 -0
- package/dist/postgres/plan/report.d.ts +6 -0
- package/dist/postgres/plan/report.d.ts.map +1 -0
- package/dist/postgres/plan/rules.d.ts +84 -0
- package/dist/postgres/plan/rules.d.ts.map +1 -0
- package/dist/postgres/plan/schema.d.ts +50 -0
- package/dist/postgres/plan/schema.d.ts.map +1 -0
- package/dist/postgres/plan/server-normalize.d.ts +26 -0
- package/dist/postgres/plan/server-normalize.d.ts.map +1 -0
- package/dist/postgres/providers/aurora.d.ts +12 -0
- package/dist/postgres/providers/aurora.d.ts.map +1 -0
- package/dist/postgres/providers/azure.d.ts +14 -0
- package/dist/postgres/providers/azure.d.ts.map +1 -0
- package/dist/postgres/providers/cloud-sql.d.ts +11 -0
- package/dist/postgres/providers/cloud-sql.d.ts.map +1 -0
- package/dist/postgres/providers/index.d.ts +35 -0
- package/dist/postgres/providers/index.d.ts.map +1 -0
- package/dist/postgres/providers/neon.d.ts +13 -0
- package/dist/postgres/providers/neon.d.ts.map +1 -0
- package/dist/postgres/providers/rds.d.ts +10 -0
- package/dist/postgres/providers/rds.d.ts.map +1 -0
- package/dist/postgres/providers/supabase.d.ts +12 -0
- package/dist/postgres/providers/supabase.d.ts.map +1 -0
- package/dist/postgres/providers/types.d.ts +59 -0
- package/dist/postgres/providers/types.d.ts.map +1 -0
- package/dist/postgres/testing/fake-client.d.ts +38 -0
- package/dist/postgres/testing/fake-client.d.ts.map +1 -0
- package/dist/postgres/testing/migration.d.ts +25 -0
- package/dist/postgres/testing/migration.d.ts.map +1 -0
- package/dist/postgres/testing/roundtrip-schema.d.ts +11 -0
- package/dist/postgres/testing/roundtrip-schema.d.ts.map +1 -0
- package/dist/postgres/testing/server.d.ts +17 -0
- package/dist/postgres/testing/server.d.ts.map +1 -0
- package/dist/postgres/testing/writable-server.d.ts +45 -0
- package/dist/postgres/testing/writable-server.d.ts.map +1 -0
- package/dist/postgres/tokens.d.ts +26 -0
- package/dist/postgres/tokens.d.ts.map +1 -0
- package/dist/postgres.d.ts +13 -0
- package/dist/postgres.d.ts.map +1 -0
- package/dist/rules/audit-entries.ts +29 -0
- package/dist/rules/clickhouse-helpers.ts +206 -0
- package/dist/rules/postgres-audit-entries.ts +29 -0
- package/dist/rules/postgres-helpers.ts +126 -0
- package/dist/rules/postgres-templates.ts +36 -0
- package/dist/rules/sql-helpers.ts +53 -0
- package/dist/rules/sqlch001.ts +53 -0
- package/dist/rules/sqlch002.ts +115 -0
- package/dist/rules/sqlch003.ts +68 -0
- package/dist/rules/sqlch101.ts +35 -0
- package/dist/rules/sqlch102.ts +23 -0
- package/dist/rules/sqlch103.ts +45 -0
- package/dist/rules/sqlch104.ts +42 -0
- package/dist/rules/sqlch105.ts +35 -0
- package/dist/rules/sqlch106.ts +27 -0
- package/dist/rules/sqlch107.ts +35 -0
- package/dist/rules/sqlch108.ts +27 -0
- package/dist/rules/sqlch109.ts +21 -0
- package/dist/rules/sqlch110.ts +29 -0
- package/dist/rules/sqlch111.ts +40 -0
- package/dist/rules/sqlch112.ts +30 -0
- package/dist/rules/sqlch113.ts +20 -0
- package/dist/rules/sqlch114.ts +26 -0
- package/dist/rules/sqlch115.ts +31 -0
- package/dist/rules/sqlch116.ts +22 -0
- package/dist/rules/sqlch117.ts +25 -0
- package/dist/rules/sqlch118.ts +26 -0
- package/dist/rules/sqlch119.ts +31 -0
- package/dist/rules/sqlch120.ts +21 -0
- package/dist/rules/sqlpg001.ts +88 -0
- package/dist/rules/sqlpg002.ts +68 -0
- package/dist/rules/sqlpg003.ts +59 -0
- package/dist/rules/sqlpg004.ts +73 -0
- package/dist/rules/sqlpg101.ts +24 -0
- package/dist/rules/sqlpg102.ts +30 -0
- package/dist/rules/sqlpg103.ts +23 -0
- package/dist/rules/sqlpg104.ts +23 -0
- package/dist/rules/sqlpg105.ts +22 -0
- package/dist/rules/sqlpg106.ts +22 -0
- package/dist/rules/sqlpg107.ts +22 -0
- package/dist/rules/sqlpg108.ts +27 -0
- package/dist/rules/sqlpg109.ts +37 -0
- package/dist/rules/sqlpg110.ts +33 -0
- package/dist/rules/sqlpg111.ts +23 -0
- package/dist/rules/sqlpg112.ts +25 -0
- package/dist/rules/sqlpg113.ts +28 -0
- package/dist/rules/sqlpg114.ts +37 -0
- package/dist/rules/sqlpg115.ts +38 -0
- package/dist/rules/sqlpg116.ts +25 -0
- package/dist/rules/sqlpg117.ts +24 -0
- package/dist/rules/sqlpg118.ts +22 -0
- package/dist/rules/templates.ts +35 -0
- package/dist/serializer.d.ts +37 -0
- package/dist/serializer.d.ts.map +1 -0
- package/dist/skill-defs.d.ts +3 -0
- package/dist/skill-defs.d.ts.map +1 -0
- package/dist/spec/catalog.d.ts +125 -0
- package/dist/spec/catalog.d.ts.map +1 -0
- package/dist/spec/fetch.d.ts +43 -0
- package/dist/spec/fetch.d.ts.map +1 -0
- package/dist/spec/pin.d.ts +39 -0
- package/dist/spec/pin.d.ts.map +1 -0
- package/dist/spec/postgres-catalog.d.ts +108 -0
- package/dist/spec/postgres-catalog.d.ts.map +1 -0
- package/dist/spec/postgres-fetch.d.ts +46 -0
- package/dist/spec/postgres-fetch.d.ts.map +1 -0
- package/dist/spec/postgres-pin.d.ts +67 -0
- package/dist/spec/postgres-pin.d.ts.map +1 -0
- package/dist/types/index.d.ts +4386 -0
- package/dist/validate-cli.d.ts +3 -0
- package/dist/validate-cli.d.ts.map +1 -0
- package/dist/validate.d.ts +15 -0
- package/dist/validate.d.ts.map +1 -0
- package/package.json +74 -4
- package/src/clickhouse/apply/apply.ts +288 -0
- package/src/clickhouse/apply/mutations.ts +90 -0
- package/src/clickhouse/apply/statements.ts +393 -0
- package/src/clickhouse/catalog-types.ts +84 -0
- package/src/clickhouse/container.ts +176 -0
- package/src/clickhouse/engine-syntax.test.ts +53 -0
- package/src/clickhouse/engine-syntax.ts +173 -0
- package/src/clickhouse/entities.test.ts +188 -0
- package/src/clickhouse/entities.ts +425 -0
- package/src/clickhouse/http.ts +76 -0
- package/src/clickhouse/import/generator.ts +153 -0
- package/src/clickhouse/import/import.test.ts +157 -0
- package/src/clickhouse/import/ir.ts +171 -0
- package/src/clickhouse/import/live-export.ts +53 -0
- package/src/clickhouse/import/parser.ts +27 -0
- package/src/clickhouse/import/roundtrip.test.ts +90 -0
- package/src/clickhouse/live/bind.ts +126 -0
- package/src/clickhouse/live/catalog.ts +96 -0
- package/src/clickhouse/live/describe-resources.ts +98 -0
- package/src/clickhouse/live/live.test.ts +143 -0
- package/src/clickhouse/live/roundtrip.e2e.test.ts +93 -0
- package/src/clickhouse/overlays/codecs.ts +68 -0
- package/src/clickhouse/overlays/engines.ts +108 -0
- package/src/clickhouse/overlays/kinds.ts +38 -0
- package/src/clickhouse/overlays/projections.ts +36 -0
- package/src/clickhouse/overlays/skip-indexes.ts +44 -0
- package/src/clickhouse/overlays/ttl.ts +55 -0
- package/src/clickhouse/overlays/types.ts +58 -0
- package/src/clickhouse/ownership.test.ts +20 -0
- package/src/clickhouse/ownership.ts +103 -0
- package/src/clickhouse/parser.test.ts +166 -0
- package/src/clickhouse/parser.ts +459 -0
- package/src/clickhouse/plan/commands.ts +101 -0
- package/src/clickhouse/plan/deep.ts +124 -0
- package/src/clickhouse/plan/diff.ts +203 -0
- package/src/clickhouse/plan/disruption.ts +61 -0
- package/src/clickhouse/plan/normalize.ts +352 -0
- package/src/clickhouse/plan/plan-wiring.test.ts +77 -0
- package/src/clickhouse/plan/plan.e2e.test.ts +77 -0
- package/src/clickhouse/plan/plan.test.ts +201 -0
- package/src/clickhouse/plan/rebuild-handoff.ts +59 -0
- package/src/clickhouse/plan/report.ts +19 -0
- package/src/clickhouse/plan/rules.ts +241 -0
- package/src/clickhouse/plan/schema.ts +56 -0
- package/src/clickhouse/plan/server-format.ts +39 -0
- package/src/clickhouse/rebuild/backfill.ts +186 -0
- package/src/clickhouse/rebuild/observe.ts +380 -0
- package/src/clickhouse/rebuild/op.ts +206 -0
- package/src/clickhouse/rebuild/partitions.ts +62 -0
- package/src/clickhouse/rebuild/rebuild-replicated.e2e.test.ts +513 -0
- package/src/clickhouse/rebuild/rebuild.e2e.test.ts +351 -0
- package/src/clickhouse/rebuild/rebuild.test.ts +190 -0
- package/src/clickhouse/rebuild/receipts.ts +143 -0
- package/src/clickhouse/rebuild/replicas.test.ts +70 -0
- package/src/clickhouse/rebuild/replicas.ts +148 -0
- package/src/clickhouse/rebuild/steps.ts +382 -0
- package/src/clickhouse/rebuild/verify.ts +124 -0
- package/src/clickhouse/testdata/NOTICE +5 -0
- package/src/clickhouse/testdata/clickhouse-tests-corpus.json +302 -0
- package/src/clickhouse/testing/fake-server.ts +65 -0
- package/src/clickhouse/testing/roundtrip-schema.ts +25 -0
- package/src/clickhouse/testing/writable-server.ts +141 -0
- package/src/clickhouse/tokens.ts +28 -0
- package/src/clickhouse.ts +63 -0
- package/src/codegen/classifier-page.test.ts +16 -0
- package/src/codegen/classifier-page.ts +76 -0
- package/src/codegen/clickhouse-module.test.ts +63 -0
- package/src/codegen/clickhouse-module.ts +269 -0
- package/src/codegen/docs-cli.ts +4 -0
- package/src/codegen/docs.ts +225 -0
- package/src/codegen/generate-cli.ts +13 -0
- package/src/codegen/generate.ts +126 -0
- package/src/codegen/package.ts +36 -0
- package/src/codegen/postgres-classifier-page.ts +81 -0
- package/src/codegen/postgres-module.test.ts +77 -0
- package/src/codegen/postgres-module.ts +434 -0
- package/src/codegen/registry.ts +36 -0
- package/src/composites/audit-log-table.ts +54 -0
- package/src/composites/catalog.test.ts +61 -0
- package/src/composites/catalog.ts +529 -0
- package/src/composites/cdc-mirror.ts +54 -0
- package/src/composites/clickhouse.ts +7 -0
- package/src/composites/composites.test.ts +758 -0
- package/src/composites/events-table.ts +49 -0
- package/src/composites/index.ts +9 -0
- package/src/composites/join-table.ts +57 -0
- package/src/composites/postgres.ts +7 -0
- package/src/composites/refreshed-view.ts +46 -0
- package/src/composites/replacing-table.ts +49 -0
- package/src/composites/rollup-view.ts +55 -0
- package/src/composites/sharded-table.ts +49 -0
- package/src/composites/soft-delete-table.ts +61 -0
- package/src/composites/tenant-table.ts +50 -0
- package/src/config.ts +157 -0
- package/src/core/apply.ts +153 -0
- package/src/core/classifier.ts +186 -0
- package/src/core/container.ts +93 -0
- package/src/core/core.test.ts +254 -0
- package/src/core/cursor.ts +189 -0
- package/src/core/diff.ts +72 -0
- package/src/core/entity.ts +85 -0
- package/src/core/find-templates.ts +158 -0
- package/src/core/handoff.ts +44 -0
- package/src/core/index.ts +61 -0
- package/src/core/interpolation.ts +225 -0
- package/src/core/normalize.ts +39 -0
- package/src/core/ownership.test.ts +36 -0
- package/src/core/ownership.ts +133 -0
- package/src/core/receipts.ts +29 -0
- package/src/core/references.ts +74 -0
- package/src/core/template.ts +83 -0
- package/src/core/testing/http-stub.ts +33 -0
- package/src/core/tokens.ts +252 -0
- package/src/coverage.ts +64 -0
- package/src/detect.ts +32 -0
- package/src/dialects.ts +21 -0
- package/src/generated/clickhouse-types.ts +4386 -0
- package/src/generated/clickhouse.ts +2476 -0
- package/src/generated/index.d.ts +4386 -0
- package/src/generated/lexicon-sql.json +67 -0
- package/src/generated/postgres-types.ts +1190 -0
- package/src/generated/postgres.ts +1039 -0
- package/src/import-generator.ts +18 -0
- package/src/index.ts +21 -0
- package/src/init-templates.test.ts +108 -0
- package/src/init-templates.ts +327 -0
- package/src/lint/audit-catalog.ts +73 -0
- package/src/lint/audit-lineage.ts +47 -0
- package/src/lint/post-synth/audit-entries.ts +29 -0
- package/src/lint/post-synth/clickhouse-checks.test.ts +278 -0
- package/src/lint/post-synth/clickhouse-helpers.ts +206 -0
- package/src/lint/post-synth/index.ts +81 -0
- package/src/lint/post-synth/post-synth.test.ts +33 -0
- package/src/lint/post-synth/postgres-audit-entries.ts +29 -0
- package/src/lint/post-synth/postgres-checks.test.ts +257 -0
- package/src/lint/post-synth/postgres-helpers.ts +126 -0
- package/src/lint/post-synth/sql-helpers.ts +53 -0
- package/src/lint/post-synth/sqlch101.ts +35 -0
- package/src/lint/post-synth/sqlch102.ts +23 -0
- package/src/lint/post-synth/sqlch103.ts +45 -0
- package/src/lint/post-synth/sqlch104.ts +42 -0
- package/src/lint/post-synth/sqlch105.ts +35 -0
- package/src/lint/post-synth/sqlch106.ts +27 -0
- package/src/lint/post-synth/sqlch107.ts +35 -0
- package/src/lint/post-synth/sqlch108.ts +27 -0
- package/src/lint/post-synth/sqlch109.ts +21 -0
- package/src/lint/post-synth/sqlch110.ts +29 -0
- package/src/lint/post-synth/sqlch111.ts +40 -0
- package/src/lint/post-synth/sqlch112.ts +30 -0
- package/src/lint/post-synth/sqlch113.ts +20 -0
- package/src/lint/post-synth/sqlch114.ts +26 -0
- package/src/lint/post-synth/sqlch115.ts +31 -0
- package/src/lint/post-synth/sqlch116.ts +22 -0
- package/src/lint/post-synth/sqlch117.ts +25 -0
- package/src/lint/post-synth/sqlch118.ts +26 -0
- package/src/lint/post-synth/sqlch119.ts +31 -0
- package/src/lint/post-synth/sqlch120.ts +21 -0
- package/src/lint/post-synth/sqlpg101.ts +24 -0
- package/src/lint/post-synth/sqlpg102.ts +30 -0
- package/src/lint/post-synth/sqlpg103.ts +23 -0
- package/src/lint/post-synth/sqlpg104.ts +23 -0
- package/src/lint/post-synth/sqlpg105.ts +22 -0
- package/src/lint/post-synth/sqlpg106.ts +22 -0
- package/src/lint/post-synth/sqlpg107.ts +22 -0
- package/src/lint/post-synth/sqlpg108.ts +27 -0
- package/src/lint/post-synth/sqlpg109.ts +37 -0
- package/src/lint/post-synth/sqlpg110.ts +33 -0
- package/src/lint/post-synth/sqlpg111.ts +23 -0
- package/src/lint/post-synth/sqlpg112.ts +25 -0
- package/src/lint/post-synth/sqlpg113.ts +28 -0
- package/src/lint/post-synth/sqlpg114.ts +37 -0
- package/src/lint/post-synth/sqlpg115.ts +38 -0
- package/src/lint/post-synth/sqlpg116.ts +25 -0
- package/src/lint/post-synth/sqlpg117.ts +24 -0
- package/src/lint/post-synth/sqlpg118.ts +22 -0
- package/src/lint/rules/index.ts +13 -0
- package/src/lint/rules/postgres-templates.ts +36 -0
- package/src/lint/rules/rules.test.ts +228 -0
- package/src/lint/rules/sqlch001.ts +53 -0
- package/src/lint/rules/sqlch002.ts +115 -0
- package/src/lint/rules/sqlch003.ts +68 -0
- package/src/lint/rules/sqlpg001.ts +88 -0
- package/src/lint/rules/sqlpg002.ts +68 -0
- package/src/lint/rules/sqlpg003.ts +59 -0
- package/src/lint/rules/sqlpg004.ts +73 -0
- package/src/lint/rules/templates.ts +35 -0
- package/src/live-dialect.ts +37 -0
- package/src/lsp/catalog.ts +60 -0
- package/src/lsp/completions.test.ts +111 -0
- package/src/lsp/completions.ts +128 -0
- package/src/lsp/diagnostics.test.ts +26 -0
- package/src/lsp/hover.test.ts +90 -0
- package/src/lsp/hover.ts +113 -0
- package/src/lsp/postgres-catalog.ts +234 -0
- package/src/lsp/postgres-template.ts +161 -0
- package/src/lsp/postgres.test.ts +150 -0
- package/src/lsp/postgres.ts +270 -0
- package/src/lsp/refs.ts +53 -0
- package/src/lsp/registry.ts +19 -0
- package/src/lsp/template.ts +166 -0
- package/src/mcp/index.ts +304 -0
- package/src/mcp/mcp.test.ts +184 -0
- package/src/mcp/postgres.ts +125 -0
- package/src/op/activities/clickhouse-apply.e2e.test.ts +150 -0
- package/src/op/activities/clickhouse-apply.test.ts +265 -0
- package/src/op/activities/clickhouse-apply.ts +113 -0
- package/src/op/activities/clickhouse-emulator.test.ts +23 -0
- package/src/op/activities/clickhouse-emulator.ts +37 -0
- package/src/op/activities/clickhouse-rebuild.ts +136 -0
- package/src/op/activities/index.ts +50 -0
- package/src/op/activities/postgres-apply.e2e.test.ts +184 -0
- package/src/op/activities/postgres-apply.test.ts +304 -0
- package/src/op/activities/postgres-apply.ts +170 -0
- package/src/op/activities/postgres-emulator.test.ts +26 -0
- package/src/op/activities/postgres-emulator.ts +44 -0
- package/src/op/activities/postgres-migration.ts +182 -0
- package/src/op/activity-contracts.ts +210 -0
- package/src/package-cli.ts +17 -0
- package/src/plugin.test.ts +74 -0
- package/src/plugin.ts +242 -0
- package/src/postgres/apply/apply.ts +582 -0
- package/src/postgres/apply/statements.test.ts +155 -0
- package/src/postgres/apply/statements.ts +603 -0
- package/src/postgres/catalog-types.ts +59 -0
- package/src/postgres/container.ts +72 -0
- package/src/postgres/entities.test.ts +170 -0
- package/src/postgres/entities.ts +1016 -0
- package/src/postgres/entity-types.ts +18 -0
- package/src/postgres/import/generator.ts +176 -0
- package/src/postgres/import/import.test.ts +71 -0
- package/src/postgres/import/ir.ts +67 -0
- package/src/postgres/import/live-export.ts +53 -0
- package/src/postgres/import/live-warnings.test.ts +45 -0
- package/src/postgres/keywords.ts +40 -0
- package/src/postgres/live/bind.ts +146 -0
- package/src/postgres/live/catalog.ts +581 -0
- package/src/postgres/live/client.ts +84 -0
- package/src/postgres/live/describe-resources.ts +111 -0
- package/src/postgres/live/live.test.ts +198 -0
- package/src/postgres/live/roundtrip.e2e.test.ts +111 -0
- package/src/postgres/migrate/backfill.ts +233 -0
- package/src/postgres/migrate/batches.e2e.test.ts +163 -0
- package/src/postgres/migrate/batches.test.ts +36 -0
- package/src/postgres/migrate/batches.ts +159 -0
- package/src/postgres/migrate/carry.e2e.test.ts +335 -0
- package/src/postgres/migrate/carry.test.ts +103 -0
- package/src/postgres/migrate/carry.ts +653 -0
- package/src/postgres/migrate/handoff.ts +73 -0
- package/src/postgres/migrate/kinds.e2e.test.ts +204 -0
- package/src/postgres/migrate/migrate.e2e.test.ts +362 -0
- package/src/postgres/migrate/migrate.test.ts +322 -0
- package/src/postgres/migrate/names.ts +93 -0
- package/src/postgres/migrate/observe.ts +521 -0
- package/src/postgres/migrate/op.ts +242 -0
- package/src/postgres/migrate/receipts.ts +135 -0
- package/src/postgres/migrate/replication.ts +151 -0
- package/src/postgres/migrate/steps.ts +657 -0
- package/src/postgres/overlays/columns.ts +34 -0
- package/src/postgres/overlays/constraints.ts +56 -0
- package/src/postgres/overlays/indexes.ts +27 -0
- package/src/postgres/overlays/kinds.ts +53 -0
- package/src/postgres/overlays/partitioning.ts +26 -0
- package/src/postgres/overlays/relations.ts +29 -0
- package/src/postgres/overlays/storage.ts +75 -0
- package/src/postgres/overlays/type-ddl.ts +38 -0
- package/src/postgres/overlays/types.ts +56 -0
- package/src/postgres/parser.test.ts +214 -0
- package/src/postgres/parser.ts +1062 -0
- package/src/postgres/plan/commands.ts +124 -0
- package/src/postgres/plan/deep.ts +177 -0
- package/src/postgres/plan/diff.ts +323 -0
- package/src/postgres/plan/disruption.ts +52 -0
- package/src/postgres/plan/normalize.test.ts +148 -0
- package/src/postgres/plan/normalize.ts +542 -0
- package/src/postgres/plan/plan.e2e.test.ts +117 -0
- package/src/postgres/plan/plan.test.ts +244 -0
- package/src/postgres/plan/report.ts +24 -0
- package/src/postgres/plan/rules.ts +276 -0
- package/src/postgres/plan/schema.ts +114 -0
- package/src/postgres/plan/server-normalize.ts +123 -0
- package/src/postgres/providers/aurora.ts +45 -0
- package/src/postgres/providers/azure.ts +54 -0
- package/src/postgres/providers/cloud-sql.ts +42 -0
- package/src/postgres/providers/index.ts +90 -0
- package/src/postgres/providers/neon.ts +45 -0
- package/src/postgres/providers/providers.test.ts +136 -0
- package/src/postgres/providers/rds.ts +48 -0
- package/src/postgres/providers/supabase.ts +46 -0
- package/src/postgres/providers/types.ts +70 -0
- package/src/postgres/testdata/NOTICE +31 -0
- package/src/postgres/testdata/postgres-regress-corpus.json +460 -0
- package/src/postgres/testing/fake-client.ts +42 -0
- package/src/postgres/testing/migration.ts +52 -0
- package/src/postgres/testing/roundtrip-schema.ts +46 -0
- package/src/postgres/testing/server.ts +58 -0
- package/src/postgres/testing/writable-server.ts +188 -0
- package/src/postgres/tokens.ts +46 -0
- package/src/postgres.ts +75 -0
- package/src/serializer.test.ts +128 -0
- package/src/serializer.ts +148 -0
- package/src/skill-defs.test.ts +81 -0
- package/src/skill-defs.ts +102 -0
- package/src/skills/chant-sql-plan.md +123 -0
- package/src/skills/chant-sql-postgres-migration.md +126 -0
- package/src/skills/chant-sql-postgres-plan.md +194 -0
- package/src/skills/chant-sql-postgres.md +165 -0
- package/src/skills/chant-sql-rebuild.md +68 -0
- package/src/skills/chant-sql.md +123 -0
- package/src/spec/catalog.e2e.test.ts +29 -0
- package/src/spec/catalog.test.ts +56 -0
- package/src/spec/catalog.ts +311 -0
- package/src/spec/clickhouse-catalog.snapshot.json +5246 -0
- package/src/spec/fetch.test.ts +77 -0
- package/src/spec/fetch.ts +112 -0
- package/src/spec/pin.ts +47 -0
- package/src/spec/postgres-catalog-14.snapshot.json +3494 -0
- package/src/spec/postgres-catalog-15.snapshot.json +3529 -0
- package/src/spec/postgres-catalog-16.snapshot.json +3597 -0
- package/src/spec/postgres-catalog-17.snapshot.json +3656 -0
- package/src/spec/postgres-catalog-18.snapshot.json +3747 -0
- package/src/spec/postgres-catalog.test.ts +43 -0
- package/src/spec/postgres-catalog.ts +301 -0
- package/src/spec/postgres-fetch.test.ts +75 -0
- package/src/spec/postgres-fetch.ts +112 -0
- package/src/spec/postgres-pin.test.ts +64 -0
- package/src/spec/postgres-pin.ts +101 -0
- package/src/typecheck.test.ts +104 -0
- package/src/validate-cli.ts +6 -0
- package/src/validate.ts +149 -0
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The rebuild migration's view of the server (#3198): which table is being
|
|
3
|
+
* rebuilt, how far the rebuild has got, and what it will do.
|
|
4
|
+
*
|
|
5
|
+
* Every step of the Op re-observes from here rather than trusting what an
|
|
6
|
+
* earlier run or step said, so the Op converges: run it again after a crash,
|
|
7
|
+
* a gate or an approval, and each step finds its work done or still to do.
|
|
8
|
+
* The progress is read off the server's own objects:
|
|
9
|
+
*
|
|
10
|
+
* - the table being rebuilt, `db.t`, as declared and as the server has it;
|
|
11
|
+
* - `db.t__chant_new`, the new table being filled (`role=new` in its comment);
|
|
12
|
+
* - `db.t__chant_dual`, the dual-write materialized view (`role=dual`);
|
|
13
|
+
* - `db.t__chant_old`, the old table kept after the swap (`role=old`, with
|
|
14
|
+
* `retain-until`).
|
|
15
|
+
*
|
|
16
|
+
* Each working object carries chant's ownership trailer plus
|
|
17
|
+
* `rebuild=<db.t>` and its role (`../ownership.ts`), so it is chant's and
|
|
18
|
+
* this rebuild's, and schema reads leave it out.
|
|
19
|
+
*
|
|
20
|
+
* States:
|
|
21
|
+
*
|
|
22
|
+
* - `rebuild`: the declaration differs from the server by at least one
|
|
23
|
+
* rebuild-class change, and the old table has not been swapped out yet.
|
|
24
|
+
* - `swapped`: the swap ran; the old table is retained until its date.
|
|
25
|
+
* - `done`: the server holds the declaration and nothing of the rebuild is
|
|
26
|
+
* left.
|
|
27
|
+
*
|
|
28
|
+
* Anything else is refused with a {@link RebuildRefusal}: a database that is
|
|
29
|
+
* neither Atomic nor Replicated, a table that is not there, a change that is
|
|
30
|
+
* not a rebuild, a working object chant did not make.
|
|
31
|
+
*
|
|
32
|
+
* A Replicated database (#3249) is Atomic on every replica, with its DDL run
|
|
33
|
+
* on each through Keeper, so the same EXCHANGE swaps the table everywhere.
|
|
34
|
+
* Its tables have to be `Replicated*MergeTree` on both sides of the rebuild:
|
|
35
|
+
* a plain MergeTree there keeps a different set of rows on each replica, and
|
|
36
|
+
* a copy run on one replica would fill the new table with that replica's rows
|
|
37
|
+
* alone.
|
|
38
|
+
*/
|
|
39
|
+
|
|
40
|
+
import type { OwnershipMarker } from "@intentius/chant/ownership";
|
|
41
|
+
import { computePlanDigest } from "@intentius/chant/op";
|
|
42
|
+
import { clickhouseQuery } from "../http";
|
|
43
|
+
import type { ClickHouseTarget } from "../live/bind";
|
|
44
|
+
import { canonicalObject, type CanonicalObject } from "../plan/normalize";
|
|
45
|
+
import { diffSchemas, type Change } from "../plan/diff";
|
|
46
|
+
import { dropFormattingOnly } from "../plan/server-format";
|
|
47
|
+
import { CLASSIFIER_RULES } from "../plan/rules";
|
|
48
|
+
import { CLICKHOUSE_ENTITY_TYPES } from "../entities";
|
|
49
|
+
import { carriesMarker, readTrailerPairs, REBUILD_TRAILER_KEY, stripMarkerFromStatement } from "../ownership";
|
|
50
|
+
import { ident, isRebuild, qualifiedIdent, sqlString, type DeclaredObject } from "../apply/statements";
|
|
51
|
+
|
|
52
|
+
/** How the new table keeps up with writes to the old one while it is filled. */
|
|
53
|
+
export type DualWrite =
|
|
54
|
+
| {
|
|
55
|
+
/**
|
|
56
|
+
* A materialized view on the old table writes every row whose
|
|
57
|
+
* `cutoverColumn` is at or after the cut-over into the new table; the
|
|
58
|
+
* backfill copies the rows before it. The cut-over is the server's time
|
|
59
|
+
* when the view is made plus `cutoverDelay` (default `1m`), and the
|
|
60
|
+
* backfill starts once it has passed. The column must be a time
|
|
61
|
+
* (`Date`, `DateTime`, `DateTime64`) that rows arrive in order of, give
|
|
62
|
+
* or take the delay; a row that arrives later than that is caught by
|
|
63
|
+
* the verification, which then fails the run.
|
|
64
|
+
*/
|
|
65
|
+
mode: "materialized-view";
|
|
66
|
+
cutoverColumn: string;
|
|
67
|
+
cutoverDelay?: string;
|
|
68
|
+
}
|
|
69
|
+
| {
|
|
70
|
+
/**
|
|
71
|
+
* The application stops writing to the old table (pauses, or buffers)
|
|
72
|
+
* and a person says so at a gate before the backfill. The backfill then
|
|
73
|
+
* copies every row, and writes resume against the table's own name
|
|
74
|
+
* after the swap.
|
|
75
|
+
*/
|
|
76
|
+
mode: "app";
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
/** A refusal: the rebuild cannot start, or cannot go on, for a reason a person has to act on. */
|
|
80
|
+
export class RebuildRefusal extends Error {
|
|
81
|
+
constructor(message: string) {
|
|
82
|
+
super(message);
|
|
83
|
+
this.name = "RebuildRefusal";
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** The table's name and its working objects' names. */
|
|
88
|
+
export interface RebuildNames {
|
|
89
|
+
/** `db.t`, the rebuild's identity. */
|
|
90
|
+
key: string;
|
|
91
|
+
database: string;
|
|
92
|
+
name: string;
|
|
93
|
+
newName: string;
|
|
94
|
+
dualName: string;
|
|
95
|
+
oldName: string;
|
|
96
|
+
/** Quoted, qualified: `` `db`.`t` `` and so on. */
|
|
97
|
+
table: string;
|
|
98
|
+
newTable: string;
|
|
99
|
+
dualView: string;
|
|
100
|
+
oldTable: string;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export function rebuildNames(database: string, name: string): RebuildNames {
|
|
104
|
+
const newName = `${name}__chant_new`;
|
|
105
|
+
const dualName = `${name}__chant_dual`;
|
|
106
|
+
const oldName = `${name}__chant_old`;
|
|
107
|
+
return {
|
|
108
|
+
key: `${database}.${name}`,
|
|
109
|
+
database,
|
|
110
|
+
name,
|
|
111
|
+
newName,
|
|
112
|
+
dualName,
|
|
113
|
+
oldName,
|
|
114
|
+
table: qualifiedIdent(database, name),
|
|
115
|
+
newTable: qualifiedIdent(database, newName),
|
|
116
|
+
dualView: qualifiedIdent(database, dualName),
|
|
117
|
+
oldTable: qualifiedIdent(database, oldName),
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** One object on the server, as `system.tables` reports it. */
|
|
122
|
+
export interface ServerObject {
|
|
123
|
+
name: string;
|
|
124
|
+
uuid: string;
|
|
125
|
+
engine: string;
|
|
126
|
+
comment: string;
|
|
127
|
+
partitionKey: string;
|
|
128
|
+
/** The working-object pairs in its comment's trailer, if any. */
|
|
129
|
+
pairs?: Map<string, string>;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/** A column copied from the old table into the new one. */
|
|
133
|
+
export interface CopiedColumn {
|
|
134
|
+
/** Its name in the new table. */
|
|
135
|
+
name: string;
|
|
136
|
+
/** Its name in the old table: the same, or the `-- previously:` name. */
|
|
137
|
+
source: string;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export interface RebuildObservation {
|
|
141
|
+
state: "rebuild" | "swapped" | "done";
|
|
142
|
+
names: RebuildNames;
|
|
143
|
+
declared: DeclaredObject;
|
|
144
|
+
/** The table under its own name. */
|
|
145
|
+
live: ServerObject;
|
|
146
|
+
/** Its definition on the server, as the classifier compares it. */
|
|
147
|
+
liveCanonical: CanonicalObject;
|
|
148
|
+
/** The classified changes from the server's table to the declaration. */
|
|
149
|
+
changes: Change[];
|
|
150
|
+
newTable?: ServerObject;
|
|
151
|
+
dual?: ServerObject;
|
|
152
|
+
old?: ServerObject;
|
|
153
|
+
/** After the EXCHANGE and before the swap finished: the old table, still under the new table's name. */
|
|
154
|
+
exchangedOld?: ServerObject;
|
|
155
|
+
/** The swap's EXCHANGE ran and the swap has not finished: the table's own name holds the new table. */
|
|
156
|
+
exchanged: boolean;
|
|
157
|
+
/** The columns the backfill copies, and the verification compares. */
|
|
158
|
+
copied: CopiedColumn[];
|
|
159
|
+
/**
|
|
160
|
+
* The database is Replicated: every replica runs its DDL, the tables'
|
|
161
|
+
* rows replicate through Keeper, and a step reading rows first waits for
|
|
162
|
+
* this replica to catch up (`SYSTEM SYNC REPLICA`).
|
|
163
|
+
*/
|
|
164
|
+
replicated: boolean;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const qualifiedKey = (o: DeclaredObject) => `${o.canonical.database ?? "default"}.${o.canonical.name}`;
|
|
168
|
+
|
|
169
|
+
/** The declared table with the given key (`db.t`), or a refusal naming what is declared. */
|
|
170
|
+
export function declaredTable(declared: readonly DeclaredObject[], key: string): DeclaredObject {
|
|
171
|
+
const found = declared.find((o) => o.key === key || o.exportName === key);
|
|
172
|
+
if (!found) {
|
|
173
|
+
throw new RebuildRefusal(`${key} is not declared in the build. Declared tables: ${declared.filter((o) => o.type === CLICKHOUSE_ENTITY_TYPES.table).map(qualifiedKey).join(", ") || "none"}`);
|
|
174
|
+
}
|
|
175
|
+
if (found.type !== CLICKHOUSE_ENTITY_TYPES.table) throw new RebuildRefusal(`${key} is a ${found.type}, and only a table is rebuilt`);
|
|
176
|
+
return found;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* The columns the backfill copies: every declared column the old table has
|
|
181
|
+
* under its name or its `-- previously:` name, except a `MATERIALIZED`,
|
|
182
|
+
* `ALIAS` or `EPHEMERAL` one, which the new table computes itself.
|
|
183
|
+
*/
|
|
184
|
+
export function copiedColumns(declared: CanonicalObject, live: CanonicalObject): CopiedColumn[] {
|
|
185
|
+
const liveNames = new Set(live.columns.map((c) => c.name));
|
|
186
|
+
const out: CopiedColumn[] = [];
|
|
187
|
+
for (const c of declared.columns) {
|
|
188
|
+
if (c.defaultKind && c.defaultKind !== "DEFAULT") continue;
|
|
189
|
+
const source = liveNames.has(c.name) ? c.name : c.previously && liveNames.has(c.previously) ? c.previously : undefined;
|
|
190
|
+
if (source) out.push({ name: c.name, source });
|
|
191
|
+
}
|
|
192
|
+
return out;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/** A canonical definition without what names it, for comparing and digesting by role. */
|
|
196
|
+
export function anonymous(c: CanonicalObject): Record<string, unknown> {
|
|
197
|
+
const out: Record<string, unknown> = {
|
|
198
|
+
...c,
|
|
199
|
+
columns: c.columns.map((col) => Object.fromEntries(Object.entries(col).filter(([k]) => k !== "text"))),
|
|
200
|
+
};
|
|
201
|
+
for (const k of ["name", "database", "previously", "comment"]) delete out[k];
|
|
202
|
+
return out;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
async function serverObjects(target: ClickHouseTarget, names: RebuildNames): Promise<Map<string, ServerObject>> {
|
|
206
|
+
const rows = await clickhouseQuery<{ name: string; uuid: string; engine: string; comment: string; partition_key: string }>(
|
|
207
|
+
target.endpoint,
|
|
208
|
+
`SELECT name, toString(uuid) AS uuid, engine, comment, partition_key FROM system.tables ` +
|
|
209
|
+
`WHERE database = ${sqlString(names.database)} AND name IN (${[names.name, names.newName, names.dualName, names.oldName].map(sqlString).join(", ")})`,
|
|
210
|
+
);
|
|
211
|
+
return new Map(
|
|
212
|
+
rows.map((r) => {
|
|
213
|
+
const pairs = readTrailerPairs(r.comment);
|
|
214
|
+
return [r.name, { name: r.name, uuid: r.uuid, engine: r.engine, comment: r.comment, partitionKey: r.partition_key, ...(pairs?.has(REBUILD_TRAILER_KEY) ? { pairs } : {}) }];
|
|
215
|
+
}),
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/** The definition `SHOW CREATE` prints, less chant's trailer, canonical. */
|
|
220
|
+
export async function showCreate(target: ClickHouseTarget, qualified: string): Promise<CanonicalObject> {
|
|
221
|
+
const [row] = await clickhouseQuery<{ statement: string }>(target.endpoint, `SHOW CREATE TABLE ${qualified}`);
|
|
222
|
+
return canonicalObject(stripMarkerFromStatement(row?.statement ?? ""), target.defaultDatabase);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/** The classified changes from one definition to another, compared by role, with server formatting differences dropped. */
|
|
226
|
+
export async function changesBetween(target: ClickHouseTarget, key: string, from: CanonicalObject, to: CanonicalObject): Promise<Change[]> {
|
|
227
|
+
const diff = diffSchemas([{ key, canonical: from }], [{ key, canonical: to }]);
|
|
228
|
+
return dropFormattingOnly(target.endpoint, diff.changes);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* A working object is this rebuild's only when it carries this project's
|
|
233
|
+
* marker, names this table and has the role its name says. One that has
|
|
234
|
+
* the name and not the marker is somebody else's, and the rebuild stops
|
|
235
|
+
* rather than drop or fill it.
|
|
236
|
+
*/
|
|
237
|
+
function ownWorkingObject(o: ServerObject | undefined, names: RebuildNames, role: "new" | "dual" | "old", marker: OwnershipMarker | undefined): ServerObject | undefined {
|
|
238
|
+
if (!o) return undefined;
|
|
239
|
+
if (!carriesMarker(o.comment, marker) || o.pairs?.get(REBUILD_TRAILER_KEY) !== names.key || o.pairs.get("role") !== role) {
|
|
240
|
+
throw new RebuildRefusal(
|
|
241
|
+
`${names.database}.${o.name} exists and is not this rebuild's ${role} table (its comment carries no rebuild=${names.key} role=${role} marker for this project). ` +
|
|
242
|
+
`The rebuild uses that name, so it stops rather than touch it; rename or drop it by hand.`,
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
return o;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/** Observe the rebuild of the declared table on the server. */
|
|
249
|
+
export async function observeRebuild(target: ClickHouseTarget, declared: DeclaredObject, marker: OwnershipMarker | undefined): Promise<RebuildObservation> {
|
|
250
|
+
const database = declared.canonical.database ?? target.defaultDatabase;
|
|
251
|
+
const names = rebuildNames(database, declared.canonical.name);
|
|
252
|
+
|
|
253
|
+
const [db] = await clickhouseQuery<{ engine: string }>(target.endpoint, `SELECT engine FROM system.databases WHERE name = ${sqlString(database)}`);
|
|
254
|
+
if (!db) throw new RebuildRefusal(`database ${database} is not on the server, so there is no ${names.key} to rebuild; the applier creates it`);
|
|
255
|
+
if (db.engine !== "Atomic" && db.engine !== "Replicated") {
|
|
256
|
+
throw new RebuildRefusal(
|
|
257
|
+
`database ${database} uses the ${db.engine} engine. The swap is EXCHANGE TABLES, which ClickHouse supports only in an Atomic database ` +
|
|
258
|
+
`(https://clickhouse.com/docs/sql-reference/statements/exchange) and the Replicated one built on it, and two RENAMEs in its place would leave a moment with no ${names.key} for writes to land in. ` +
|
|
259
|
+
`Convert the database to Atomic first (https://clickhouse.com/docs/engines/database-engines/atomic), then run the rebuild.`,
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
const replicated = db.engine === "Replicated";
|
|
263
|
+
|
|
264
|
+
const objects = await serverObjects(target, names);
|
|
265
|
+
const liveRow = objects.get(names.name);
|
|
266
|
+
if (!liveRow) throw new RebuildRefusal(`${names.key} is not on the server, so there is nothing to rebuild; the applier creates it`);
|
|
267
|
+
// Between EXCHANGE and the end of the swap, the table's own name holds the
|
|
268
|
+
// new table, still carrying role=new, and the new table's name holds the
|
|
269
|
+
// old table until it is renamed; the swap step finishes that.
|
|
270
|
+
const exchanged = liveRow.pairs?.get(REBUILD_TRAILER_KEY) === names.key && liveRow.pairs.get("role") === "new";
|
|
271
|
+
const newTable = exchanged ? undefined : ownWorkingObject(objects.get(names.newName), names, "new", marker);
|
|
272
|
+
const exchangedOld = exchanged ? objects.get(names.newName) : undefined;
|
|
273
|
+
const dual = ownWorkingObject(objects.get(names.dualName), names, "dual", marker);
|
|
274
|
+
const old = ownWorkingObject(objects.get(names.oldName), names, "old", marker);
|
|
275
|
+
const liveCanonical = await showCreate(target, names.table);
|
|
276
|
+
const changes = (await changesBetween(target, names.key, { ...liveCanonical, name: declared.canonical.name }, declared.canonical)).filter((c) => !(c.field === "comment" && c.rule === "SQLCH203"));
|
|
277
|
+
const copied = copiedColumns(declared.canonical, liveCanonical);
|
|
278
|
+
|
|
279
|
+
let state: RebuildObservation["state"];
|
|
280
|
+
if (old || exchanged) {
|
|
281
|
+
if (changes.some(isRebuild) && !exchanged) {
|
|
282
|
+
throw new RebuildRefusal(
|
|
283
|
+
`${names.key} differs from its declaration by a rebuild again, and the old table of the last rebuild is still kept as ${names.database}.${names.oldName}. ` +
|
|
284
|
+
`Drop it (the rebuild's drop phase, or DROP TABLE) before rebuilding again.`,
|
|
285
|
+
);
|
|
286
|
+
}
|
|
287
|
+
state = "swapped";
|
|
288
|
+
} else if (changes.some(isRebuild)) {
|
|
289
|
+
state = "rebuild";
|
|
290
|
+
} else if (changes.length === 0) {
|
|
291
|
+
state = "done";
|
|
292
|
+
} else {
|
|
293
|
+
throw new RebuildRefusal(
|
|
294
|
+
`${names.key} has no change that needs a rebuild: ${changes.map((c) => `${c.rule} ${CLASSIFIER_RULES[c.rule].title} on ${c.field}`).join("; ")}. ` +
|
|
295
|
+
`The applier makes these in place (ApplyOp with target "clickhouse").`,
|
|
296
|
+
);
|
|
297
|
+
}
|
|
298
|
+
if (state === "rebuild") {
|
|
299
|
+
if (replicated) refuseUnreplicated(names, liveRow.engine, declared.canonical.engineName);
|
|
300
|
+
refuseSharedKeeperPath(names, liveCanonical.engine, declared.canonical.engine);
|
|
301
|
+
}
|
|
302
|
+
if (state === "done" && (newTable || dual)) {
|
|
303
|
+
throw new RebuildRefusal(
|
|
304
|
+
`${names.key} already holds its declaration, and ${[newTable, dual].filter(Boolean).map((o) => `${names.database}.${o!.name}`).join(" and ")} from an unfinished rebuild is still there. ` +
|
|
305
|
+
`The run fails so onFailure drops it.`,
|
|
306
|
+
);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
return {
|
|
310
|
+
state,
|
|
311
|
+
names,
|
|
312
|
+
declared,
|
|
313
|
+
live: liveRow,
|
|
314
|
+
liveCanonical,
|
|
315
|
+
changes,
|
|
316
|
+
...(newTable ? { newTable } : {}),
|
|
317
|
+
...(dual ? { dual } : {}),
|
|
318
|
+
...(old ? { old } : {}),
|
|
319
|
+
...(exchangedOld ? { exchangedOld } : {}),
|
|
320
|
+
exchanged,
|
|
321
|
+
copied,
|
|
322
|
+
replicated,
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
const REPLICATED_MERGE_TREE = /^Replicated.*MergeTree$/;
|
|
327
|
+
|
|
328
|
+
/** In a Replicated database, both the table and its declaration have to replicate their rows. */
|
|
329
|
+
function refuseUnreplicated(names: RebuildNames, live: string, declared: string | undefined): void {
|
|
330
|
+
const side = !REPLICATED_MERGE_TREE.test(live) ? `the table is ${live}` : declared !== undefined && !REPLICATED_MERGE_TREE.test(declared) ? `the declaration makes it ${declared}` : undefined;
|
|
331
|
+
if (!side) return;
|
|
332
|
+
throw new RebuildRefusal(
|
|
333
|
+
`${names.key} is in a Replicated database and ${side}, which keeps a separate set of rows on each replica. ` +
|
|
334
|
+
`The backfill runs on one replica and would copy that replica's rows alone, while the EXCHANGE runs on every replica, so the others would swap in a table without their rows. ` +
|
|
335
|
+
`Rebuild it from and to a Replicated*MergeTree engine (ENGINE = ReplicatedMergeTree, with no arguments in a Replicated database), or move it to an Atomic database first.`,
|
|
336
|
+
);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/** The Keeper path a `Replicated*MergeTree` engine names, when it names one. */
|
|
340
|
+
function keeperPath(engine: string | undefined): string | undefined {
|
|
341
|
+
const m = /^Replicated\w*MergeTree\(\s*('(?:[^'\\]|\\.)*')/.exec(engine ?? "");
|
|
342
|
+
return m?.[1];
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* The new table is made from the declaration under another name. With an
|
|
347
|
+
* explicit Keeper path that is the old table's own and has no `{uuid}` in
|
|
348
|
+
* it, both tables would be the same replicated table to Keeper, and the
|
|
349
|
+
* create would fail on a replica that is already there or, worse, share parts.
|
|
350
|
+
*/
|
|
351
|
+
function refuseSharedKeeperPath(names: RebuildNames, live: string | undefined, declared: string | undefined): void {
|
|
352
|
+
const path = keeperPath(declared);
|
|
353
|
+
if (!path || path.includes("{uuid}") || path !== keeperPath(live)) return;
|
|
354
|
+
throw new RebuildRefusal(
|
|
355
|
+
`${names.key} names its Keeper path explicitly, ${path}, and the new table made from the declaration would get the same path as the old table. ` +
|
|
356
|
+
`Put {uuid} in the path (or leave the engine's arguments out, which defaults to '/clickhouse/tables/{uuid}/{shard}'), so each table has its own.`,
|
|
357
|
+
);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* What the rebuild will do, independent of how far it has got: the changes,
|
|
362
|
+
* the definitions on both sides, the columns copied and how writes are kept
|
|
363
|
+
* up. The Plan phase publishes its digest; the gate binds a digest of this
|
|
364
|
+
* plus the verification.
|
|
365
|
+
*/
|
|
366
|
+
export function rebuildPlanSubject(o: RebuildObservation, dualWrite: DualWrite): Record<string, unknown> {
|
|
367
|
+
return {
|
|
368
|
+
table: o.names.key,
|
|
369
|
+
from: anonymous(o.liveCanonical),
|
|
370
|
+
to: anonymous(o.declared.canonical),
|
|
371
|
+
changes: o.changes.map((c) => ({ rule: c.rule, field: c.field, ...(c.before !== undefined ? { before: c.before } : {}), ...(c.after !== undefined ? { after: c.after } : {}) })),
|
|
372
|
+
copied: o.copied,
|
|
373
|
+
dualWrite,
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
export const rebuildPlanDigest = (o: RebuildObservation, dualWrite: DualWrite): string => computePlanDigest("clickhouse-rebuild", rebuildPlanSubject(o, dualWrite));
|
|
378
|
+
|
|
379
|
+
/** `ident` re-exported for the steps, which quote column names. */
|
|
380
|
+
export { ident };
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ClickHouseRebuildOp` (#3198): the change ClickHouse cannot make with
|
|
3
|
+
* `ALTER` (a sorting key, a primary key, a partition key, an engine, a key
|
|
4
|
+
* column's type), run as a gated composite Op.
|
|
5
|
+
*
|
|
6
|
+
* export const { op } = ClickHouseRebuildOp({
|
|
7
|
+
* name: "rebuild-shop-events",
|
|
8
|
+
* env: "prod",
|
|
9
|
+
* table: "shop.events",
|
|
10
|
+
* dualWrite: { mode: "materialized-view", cutoverColumn: "ts" },
|
|
11
|
+
* });
|
|
12
|
+
*
|
|
13
|
+
* | Phase | Step |
|
|
14
|
+
* |---|---|
|
|
15
|
+
* | Build | `chant build` (`build: false` skips it) |
|
|
16
|
+
* | Plan | classify the table's change against the server; refuse what is not a rebuild |
|
|
17
|
+
* | Create | the new table, `t__chant_new`, from the declaration |
|
|
18
|
+
* | Dual write | a materialized view from the old table to the new one, or a gate for the app to stop writing |
|
|
19
|
+
* | Backfill | `INSERT ... SELECT` per partition, each with a receipt |
|
|
20
|
+
* | Verify | row counts and checksums per partition |
|
|
21
|
+
* | Approve | a gate bound to the plan and the verification |
|
|
22
|
+
* | Swap | `EXCHANGE TABLES`, then recreate the materialized views that read the table |
|
|
23
|
+
* | Retain | the old table, `t__chant_old`, until `retain` has passed |
|
|
24
|
+
* | Approve drop | a gate bound to that old table |
|
|
25
|
+
* | Drop | the old table, once its date has passed |
|
|
26
|
+
* | onFailure | drop the new table and the dual-write view |
|
|
27
|
+
*
|
|
28
|
+
* Run it until it is done: each run goes as far as the next gate. Every step
|
|
29
|
+
* re-reads the server, so a run after a gate, a crash or an approval picks up
|
|
30
|
+
* where the last stopped. A run killed during the backfill (Ctrl-C, a lost
|
|
31
|
+
* machine) is not a failure, runs no onFailure, and the next run resumes the
|
|
32
|
+
* backfill from its receipts; a step that fails runs onFailure, and the next
|
|
33
|
+
* run starts again from a new table.
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
import { Op, activity, gate, phase, stepOutput, type GateApproval } from "@intentius/chant/op";
|
|
37
|
+
import type { OpResource } from "@intentius/chant/op";
|
|
38
|
+
import type { StepDefinition } from "@intentius/chant/op";
|
|
39
|
+
import type { DualWrite } from "./observe";
|
|
40
|
+
|
|
41
|
+
export interface ClickHouseRebuildOpConfig {
|
|
42
|
+
/** Op name (kebab-case). */
|
|
43
|
+
name: string;
|
|
44
|
+
/** The chant environment: selects `sql.profiles.<env>`. */
|
|
45
|
+
env: string;
|
|
46
|
+
/** The table to rebuild, `database.name` as the server knows it (or its export name). */
|
|
47
|
+
table: string;
|
|
48
|
+
/** How writes reach the new table while it is filled. */
|
|
49
|
+
dualWrite: DualWrite;
|
|
50
|
+
/** The build output the declaration is read from. Default: `dist/schema.json`. */
|
|
51
|
+
output?: string;
|
|
52
|
+
/** Project directory to build. Default: `.`. */
|
|
53
|
+
path?: string;
|
|
54
|
+
/** Run `chant build` first (the project's `build` script). Default: true. */
|
|
55
|
+
build?: boolean;
|
|
56
|
+
/** How long the old table is kept after the swap, as a duration (`7d`, `36h`). Default: `7d`. */
|
|
57
|
+
retain?: string;
|
|
58
|
+
/** The gate before the swap. Default name `approve-<name>`. */
|
|
59
|
+
gate?: {
|
|
60
|
+
gate?: string;
|
|
61
|
+
timeout?: string;
|
|
62
|
+
description?: string;
|
|
63
|
+
/** Quorum, roles and a policy (#2508). With a policy, the verification's counts are added to its context. */
|
|
64
|
+
approval?: GateApproval;
|
|
65
|
+
};
|
|
66
|
+
/** The gate before the old table is dropped. Default name `approve-<name>-drop`. */
|
|
67
|
+
dropGate?: { gate?: string; timeout?: string; description?: string };
|
|
68
|
+
/** App mode: the gate the application's write stop is confirmed at. Default name `<name>-writes-stopped`. */
|
|
69
|
+
writesGate?: { gate?: string; timeout?: string; description?: string };
|
|
70
|
+
/** One attempt of the backfill step. Default: `6h`, the longest a step may run. */
|
|
71
|
+
backfillTimeout?: string;
|
|
72
|
+
/** How long to wait for one table's mutations. Default: `10m`. */
|
|
73
|
+
mutationTimeout?: string;
|
|
74
|
+
/**
|
|
75
|
+
* In a Replicated database, how long a step that reads rows waits for the
|
|
76
|
+
* replica it talks to to fetch what the others wrote, before it stops
|
|
77
|
+
* naming a replica that is down and holds parts no other has. Each attempt
|
|
78
|
+
* of the step waits this long. Default: `2m`.
|
|
79
|
+
*/
|
|
80
|
+
replicaTimeout?: string;
|
|
81
|
+
/** Ownership stack. Default: `ownership.stack` in `chant.config.ts`. */
|
|
82
|
+
stack?: string;
|
|
83
|
+
/** Ownership env. Default: `ownership.env` in `chant.config.ts`. */
|
|
84
|
+
ownershipEnv?: string;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export interface ClickHouseRebuildOpResources {
|
|
88
|
+
op: InstanceType<typeof OpResource>;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** The arguments every rebuild activity takes. */
|
|
92
|
+
export interface ClickHouseRebuildArgs {
|
|
93
|
+
table: string;
|
|
94
|
+
buildPath: string;
|
|
95
|
+
environment?: string;
|
|
96
|
+
dualWrite: DualWrite;
|
|
97
|
+
retain?: string;
|
|
98
|
+
mutationTimeout?: string;
|
|
99
|
+
replicaTimeout?: string;
|
|
100
|
+
stack?: string;
|
|
101
|
+
ownershipEnv?: string;
|
|
102
|
+
cwd?: string;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export function ClickHouseRebuildOp(config: ClickHouseRebuildOpConfig): ClickHouseRebuildOpResources {
|
|
106
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*\.[A-Za-z_][A-Za-z0-9_]*$|^[A-Za-z_][A-Za-z0-9_]*$/.test(config.table)) {
|
|
107
|
+
throw new Error(`ClickHouseRebuildOp "${config.name}": table must be "database.name" or an export name, got ${JSON.stringify(config.table)}`);
|
|
108
|
+
}
|
|
109
|
+
if (config.dualWrite?.mode !== "materialized-view" && config.dualWrite?.mode !== "app") {
|
|
110
|
+
throw new Error(`ClickHouseRebuildOp "${config.name}": dualWrite.mode must be "materialized-view" or "app"`);
|
|
111
|
+
}
|
|
112
|
+
if (config.dualWrite.mode === "materialized-view" && !config.dualWrite.cutoverColumn) {
|
|
113
|
+
throw new Error(`ClickHouseRebuildOp "${config.name}": materialized-view mode needs cutoverColumn, the time column rows are cut over on`);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const args: ClickHouseRebuildArgs = {
|
|
117
|
+
table: config.table,
|
|
118
|
+
buildPath: config.output ?? "dist/schema.json",
|
|
119
|
+
environment: config.env,
|
|
120
|
+
dualWrite: config.dualWrite,
|
|
121
|
+
...(config.retain ? { retain: config.retain } : {}),
|
|
122
|
+
...(config.mutationTimeout ? { mutationTimeout: config.mutationTimeout } : {}),
|
|
123
|
+
...(config.replicaTimeout ? { replicaTimeout: config.replicaTimeout } : {}),
|
|
124
|
+
...(config.stack ? { stack: config.stack } : {}),
|
|
125
|
+
...(config.ownershipEnv ? { ownershipEnv: config.ownershipEnv } : {}),
|
|
126
|
+
...(config.path && config.path !== "." ? { cwd: config.path } : {}),
|
|
127
|
+
};
|
|
128
|
+
const a = args as unknown as Record<string, unknown>;
|
|
129
|
+
const swapGate = config.gate?.gate ?? `approve-${config.name}`;
|
|
130
|
+
const dropGate = config.dropGate?.gate ?? `approve-${config.name}-drop`;
|
|
131
|
+
const policy = config.gate?.approval?.policy;
|
|
132
|
+
|
|
133
|
+
const step = (fn: string, extra: Partial<StepDefinition & { id: string; outcomeAttribute: unknown; profile: string; timeout: string }> = {}): StepDefinition =>
|
|
134
|
+
({ ...activity(fn, a), ...extra }) as StepDefinition;
|
|
135
|
+
|
|
136
|
+
const phases = [
|
|
137
|
+
...(config.build === false ? [] : [phase("Build", [activity("chantBuild", { path: config.path ?? "." })])]),
|
|
138
|
+
phase("Plan", [step("clickhouseRebuildPlan", { id: "plan", outcomeAttribute: { name: "RebuildState", from: "state" } })]),
|
|
139
|
+
phase("Create", [step("clickhouseRebuildCreate")]),
|
|
140
|
+
phase("Dual write", [
|
|
141
|
+
config.dualWrite.mode === "app"
|
|
142
|
+
? gate(config.writesGate?.gate ?? `${config.name}-writes-stopped`, {
|
|
143
|
+
...(config.writesGate?.timeout ? { timeout: config.writesGate.timeout } : {}),
|
|
144
|
+
description:
|
|
145
|
+
config.writesGate?.description ??
|
|
146
|
+
`Stop the application's writes to ${config.table} (pause or buffer them) and approve; they resume against ${config.table} after the swap`,
|
|
147
|
+
})
|
|
148
|
+
: step("clickhouseRebuildDualWrite", { outcomeAttribute: { name: "Cutover", from: "cutover" } }),
|
|
149
|
+
]),
|
|
150
|
+
phase("Backfill", [step("clickhouseRebuildBackfill", { profile: "fastIdempotent", timeout: config.backfillTimeout ?? "6h", outcomeAttribute: [{ name: "Copied", from: "copied" }, { name: "Skipped", from: "skipped" }] })]),
|
|
151
|
+
phase("Verify", [
|
|
152
|
+
step("clickhouseRebuildVerify", {
|
|
153
|
+
id: "verify",
|
|
154
|
+
outcomeAttribute: [
|
|
155
|
+
{ name: "Verification", from: "summary" },
|
|
156
|
+
{ name: "VerifiedPartitions", from: "partitions" },
|
|
157
|
+
{ name: "VerifiedRows", from: "rows" },
|
|
158
|
+
],
|
|
159
|
+
}),
|
|
160
|
+
]),
|
|
161
|
+
phase("Approve", [
|
|
162
|
+
gate(swapGate, {
|
|
163
|
+
...(config.gate?.timeout ? { timeout: config.gate.timeout } : {}),
|
|
164
|
+
plan: stepOutput("verify", "planDigest"),
|
|
165
|
+
description:
|
|
166
|
+
config.gate?.description ??
|
|
167
|
+
`Approve swapping the rebuilt ${config.table} in on ${config.env}: the run record's Verification line has the counts this approval binds`,
|
|
168
|
+
...(config.gate?.approval
|
|
169
|
+
? {
|
|
170
|
+
approval: {
|
|
171
|
+
...config.gate.approval,
|
|
172
|
+
...(policy
|
|
173
|
+
? {
|
|
174
|
+
context: {
|
|
175
|
+
verifiedPartitions: stepOutput("verify", "partitions"),
|
|
176
|
+
verifiedRows: stepOutput("verify", "rows"),
|
|
177
|
+
...config.gate.approval.context,
|
|
178
|
+
},
|
|
179
|
+
}
|
|
180
|
+
: {}),
|
|
181
|
+
},
|
|
182
|
+
}
|
|
183
|
+
: {}),
|
|
184
|
+
}),
|
|
185
|
+
]),
|
|
186
|
+
phase("Swap", [step("clickhouseRebuildSwap", { profile: "longInfra", outcomeAttribute: { name: "Dependents", from: "dependents" } })]),
|
|
187
|
+
phase("Retain", [step("clickhouseRebuildRetain", { id: "retain", outcomeAttribute: { name: "RetainUntil", from: "retainUntil" } })]),
|
|
188
|
+
phase("Approve drop", [
|
|
189
|
+
gate(dropGate, {
|
|
190
|
+
...(config.dropGate?.timeout ? { timeout: config.dropGate.timeout } : {}),
|
|
191
|
+
plan: stepOutput("retain", "dropDigest"),
|
|
192
|
+
description: config.dropGate?.description ?? `Approve dropping the old ${config.table} once its retention has passed`,
|
|
193
|
+
}),
|
|
194
|
+
]),
|
|
195
|
+
phase("Drop", [step("clickhouseRebuildDrop", { outcomeAttribute: { name: "Dropped", from: "dropped" } })]),
|
|
196
|
+
];
|
|
197
|
+
|
|
198
|
+
const op = Op({
|
|
199
|
+
name: config.name,
|
|
200
|
+
overview: `Rebuild ${config.table} on ${config.env}: new table, ${config.dualWrite.mode === "app" ? "writes stopped" : "dual write"}, backfill, verify, gated swap`,
|
|
201
|
+
labels: { Rebuild: "true", Env: config.env, Table: config.table },
|
|
202
|
+
phases,
|
|
203
|
+
onFailure: [phase("Compensate", [step("clickhouseRebuildCompensate")])],
|
|
204
|
+
});
|
|
205
|
+
return { op };
|
|
206
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Partitions, as the backfill copies them and the verification counts them.
|
|
3
|
+
*
|
|
4
|
+
* The unit of work is a partition of the old table. Its rows can land in
|
|
5
|
+
* other partitions of the new table when the rebuild changes the partition
|
|
6
|
+
* key, so "the rows of old partition p" is found on the new table by
|
|
7
|
+
* computing the old partition key over the new table's columns:
|
|
8
|
+
* `partitionID(<old key>)`, which the server computes the same way it named
|
|
9
|
+
* the old partition (`_partition_id`). When the key is unchanged that is the
|
|
10
|
+
* new table's own `_partition_id`; when the old table has no partition key
|
|
11
|
+
* every row is in partition `all`.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { clickhouseQuery } from "../http";
|
|
15
|
+
import type { ClickHouseTarget } from "../live/bind";
|
|
16
|
+
import { ident, sqlString } from "../apply/statements";
|
|
17
|
+
import type { CopiedColumn, RebuildNames } from "./observe";
|
|
18
|
+
|
|
19
|
+
/** The old table's active partitions, by id. */
|
|
20
|
+
export async function sourcePartitions(target: ClickHouseTarget, names: RebuildNames): Promise<string[]> {
|
|
21
|
+
const rows = await clickhouseQuery<{ partition_id: string }>(
|
|
22
|
+
target.endpoint,
|
|
23
|
+
`SELECT partition_id FROM system.parts WHERE database = ${sqlString(names.database)} AND table = ${sqlString(names.name)} AND active ` +
|
|
24
|
+
`GROUP BY partition_id ORDER BY partition_id`,
|
|
25
|
+
);
|
|
26
|
+
return rows.map((r) => r.partition_id);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Rename the columns an expression names, old name to new, leaving function names and qualified names alone. */
|
|
30
|
+
export function renameColumns(expr: string, copied: readonly CopiedColumn[]): string {
|
|
31
|
+
let out = expr;
|
|
32
|
+
for (const c of copied) {
|
|
33
|
+
if (c.source === c.name) continue;
|
|
34
|
+
const re = new RegExp(`(?<![\\w.\`])\`?${c.source.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\`?(?![\\w\`(])`, "g");
|
|
35
|
+
out = out.replace(re, ident(c.name));
|
|
36
|
+
}
|
|
37
|
+
return out;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** A tuple key's elements as arguments (`(a, b)` is `a, b`); any other key as itself. */
|
|
41
|
+
function asArguments(key: string): string {
|
|
42
|
+
const k = key.trim();
|
|
43
|
+
if (!k.startsWith("(") || !k.endsWith(")")) return k;
|
|
44
|
+
let depth = 0;
|
|
45
|
+
for (let i = 0; i < k.length; i++) {
|
|
46
|
+
if (k[i] === "(") depth++;
|
|
47
|
+
else if (k[i] === ")") depth--;
|
|
48
|
+
if (depth === 0 && i < k.length - 1) return k; // `(a) + (b)`: not one outer pair
|
|
49
|
+
}
|
|
50
|
+
return k.slice(1, -1);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* The expression that gives, for a row of the new table, the id of the old
|
|
55
|
+
* table's partition the row came from.
|
|
56
|
+
*/
|
|
57
|
+
export function sourcePartitionExpression(oldKey: string, newKey: string, copied: readonly CopiedColumn[]): string {
|
|
58
|
+
if (oldKey.trim() === "") return "'all'";
|
|
59
|
+
const renamed = renameColumns(oldKey, copied);
|
|
60
|
+
if (renamed === oldKey && oldKey.trim() === newKey.trim()) return "_partition_id";
|
|
61
|
+
return `partitionID(${asArguments(renamed)})`;
|
|
62
|
+
}
|