@intentius/chant-lexicon-sql 0.124.46 → 0.124.48
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/dist/change-set.d.ts +1 -1
- package/dist/change-set.d.ts.map +1 -1
- package/dist/change-set.js +2 -1
- package/dist/clickhouse/apply/statements.d.ts +9 -0
- package/dist/clickhouse/apply/statements.d.ts.map +1 -1
- package/dist/clickhouse/apply/statements.js +24 -0
- package/dist/clickhouse/import/live-export.d.ts +7 -3
- package/dist/clickhouse/import/live-export.d.ts.map +1 -1
- package/dist/clickhouse/import/live-export.js +21 -5
- package/dist/clickhouse/live/named-collections.d.ts +27 -0
- package/dist/clickhouse/live/named-collections.d.ts.map +1 -0
- package/dist/clickhouse/live/named-collections.js +53 -0
- package/dist/clickhouse/live/undeclarable.d.ts +15 -3
- package/dist/clickhouse/live/undeclarable.d.ts.map +1 -1
- package/dist/clickhouse/live/undeclarable.js +18 -4
- package/dist/clickhouse/named-collections.d.ts +83 -0
- package/dist/clickhouse/named-collections.d.ts.map +1 -0
- package/dist/clickhouse/named-collections.js +203 -0
- package/dist/clickhouse/parser.d.ts.map +1 -1
- package/dist/clickhouse/parser.js +1 -1
- package/dist/clickhouse/plan/commands.d.ts +2 -1
- package/dist/clickhouse/plan/commands.d.ts.map +1 -1
- package/dist/clickhouse/plan/commands.js +17 -2
- package/dist/clickhouse/plan/diff.d.ts +15 -0
- package/dist/clickhouse/plan/diff.d.ts.map +1 -1
- package/dist/clickhouse/plan/diff.js +43 -1
- package/dist/clickhouse/plan/disruption.d.ts.map +1 -1
- package/dist/clickhouse/plan/disruption.js +5 -0
- package/dist/clickhouse/plan/rebuild-handoff.d.ts.map +1 -1
- package/dist/clickhouse/plan/rebuild-handoff.js +4 -0
- package/dist/clickhouse/plan/report.d.ts.map +1 -1
- package/dist/clickhouse/plan/report.js +6 -1
- package/dist/clickhouse/plan/rules.d.ts +5 -1
- package/dist/clickhouse/plan/rules.d.ts.map +1 -1
- package/dist/clickhouse/plan/rules.js +7 -3
- package/dist/clickhouse/plan/stream.d.ts +40 -0
- package/dist/clickhouse/plan/stream.d.ts.map +1 -0
- package/dist/clickhouse/plan/stream.js +107 -0
- package/dist/clickhouse/rebuild/observe.d.ts +3 -1
- package/dist/clickhouse/rebuild/observe.d.ts.map +1 -1
- package/dist/clickhouse/rebuild/observe.js +14 -1
- package/dist/clickhouse/review-catalog.d.ts +213 -0
- package/dist/clickhouse/review-catalog.d.ts.map +1 -0
- package/dist/clickhouse/review-catalog.js +330 -0
- package/dist/codegen/classifier-page.d.ts.map +1 -1
- package/dist/codegen/classifier-page.js +21 -4
- package/dist/codegen/clickhouse-module.d.ts.map +1 -1
- package/dist/codegen/clickhouse-module.js +3 -0
- package/dist/codegen/coverage-page.d.ts.map +1 -1
- package/dist/codegen/coverage-page.js +5 -3
- package/dist/codegen/docs.js +1 -1
- package/dist/codegen/postgres-classifier-page.js +1 -1
- package/dist/codegen/registry.d.ts.map +1 -1
- package/dist/codegen/registry.js +5 -0
- package/dist/composites/catalog.d.ts.map +1 -1
- package/dist/composites/catalog.js +100 -0
- package/dist/composites/clickhouse.d.ts +2 -0
- package/dist/composites/clickhouse.d.ts.map +1 -1
- package/dist/composites/clickhouse.js +2 -0
- package/dist/composites/otel-tables.d.ts +100 -0
- package/dist/composites/otel-tables.d.ts.map +1 -0
- package/dist/composites/otel-tables.js +282 -0
- package/dist/composites/stream-ingest.d.ts +63 -0
- package/dist/composites/stream-ingest.d.ts.map +1 -0
- package/dist/composites/stream-ingest.js +39 -0
- package/dist/coverage/clickhouse.json +1 -1
- package/dist/coverage/postgres.json +7 -7
- package/dist/coverage.d.ts +16 -6
- package/dist/coverage.d.ts.map +1 -1
- package/dist/coverage.js +10 -5
- package/dist/drizzle-command.d.ts +17 -0
- package/dist/drizzle-command.d.ts.map +1 -0
- package/dist/drizzle-command.js +91 -0
- package/dist/drizzle.d.ts +70 -0
- package/dist/drizzle.d.ts.map +1 -0
- package/dist/drizzle.js +684 -0
- package/dist/files/clickhouse.d.ts.map +1 -1
- package/dist/files/clickhouse.js +8 -1
- package/dist/files/common.d.ts +13 -0
- package/dist/files/common.d.ts.map +1 -1
- package/dist/files/common.js +5 -0
- package/dist/files/postgres.js +12 -2
- package/dist/generated/clickhouse.d.ts +2 -0
- package/dist/generated/clickhouse.d.ts.map +1 -1
- package/dist/generated/clickhouse.js +2 -0
- package/dist/import-parser.d.ts +21 -1
- package/dist/import-parser.d.ts.map +1 -1
- package/dist/import-parser.js +79 -5
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/integrity.json +6 -5
- package/dist/lint/post-synth/audit-entries.d.ts.map +1 -1
- package/dist/lint/post-synth/audit-entries.js +1 -0
- package/dist/lint/post-synth/index.d.ts.map +1 -1
- package/dist/lint/post-synth/index.js +2 -0
- package/dist/lint/post-synth/sqlch128.d.ts +18 -0
- package/dist/lint/post-synth/sqlch128.d.ts.map +1 -0
- package/dist/lint/post-synth/sqlch128.js +222 -0
- package/dist/lint/rules/postgres-templates.js +2 -2
- package/dist/lsp/postgres-template.d.ts.map +1 -1
- package/dist/lsp/postgres-template.js +11 -0
- package/dist/manifest.json +1 -1
- package/dist/mcp/postgres.js +1 -1
- package/dist/meta.json +25 -0
- package/dist/migrate/from-postgres/detect.d.ts +4 -0
- package/dist/migrate/from-postgres/detect.d.ts.map +1 -0
- package/dist/migrate/from-postgres/detect.js +7 -0
- package/dist/migrate/from-postgres/emit.d.ts +26 -0
- package/dist/migrate/from-postgres/emit.d.ts.map +1 -0
- package/dist/migrate/from-postgres/emit.js +86 -0
- package/dist/migrate/from-postgres/index.d.ts +51 -0
- package/dist/migrate/from-postgres/index.d.ts.map +1 -0
- package/dist/migrate/from-postgres/index.js +115 -0
- package/dist/migrate/from-postgres/translate.d.ts +73 -0
- package/dist/migrate/from-postgres/translate.d.ts.map +1 -0
- package/dist/migrate/from-postgres/translate.js +261 -0
- package/dist/migrate/from-postgres/types.d.ts +51 -0
- package/dist/migrate/from-postgres/types.d.ts.map +1 -0
- package/dist/migrate/from-postgres/types.js +211 -0
- package/dist/migration-replay.d.ts +73 -0
- package/dist/migration-replay.d.ts.map +1 -0
- package/dist/migration-replay.js +294 -0
- package/dist/okf/index.md +6 -0
- package/dist/okf/rules/SQLCH128.md +11 -0
- package/dist/okf/types/PostgresForeignDataWrapper.md +9 -0
- package/dist/okf/types/PostgresForeignServer.md +9 -0
- package/dist/okf/types/PostgresOperator.md +9 -0
- package/dist/okf/types/PostgresPublication.md +9 -0
- package/dist/okf/types/PostgresStatistics.md +9 -0
- package/dist/op/activities/postgres-migration.d.ts.map +1 -1
- package/dist/op/activities/postgres-migration.js +4 -0
- package/dist/op/activity-contracts.d.ts +20 -0
- package/dist/op/activity-contracts.d.ts.map +1 -1
- package/dist/op/activity-contracts.js +2 -0
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +36 -2
- package/dist/postgres/apply/apply.js +8 -1
- package/dist/postgres/apply/statements.d.ts.map +1 -1
- package/dist/postgres/apply/statements.js +87 -2
- package/dist/postgres/constraint-names.d.ts +30 -0
- package/dist/postgres/constraint-names.d.ts.map +1 -0
- package/dist/postgres/constraint-names.js +72 -0
- package/dist/postgres/entities.d.ts +110 -1
- package/dist/postgres/entities.d.ts.map +1 -1
- package/dist/postgres/entities.js +146 -0
- package/dist/postgres/entity-types.d.ts +5 -0
- package/dist/postgres/entity-types.d.ts.map +1 -1
- package/dist/postgres/entity-types.js +5 -0
- package/dist/postgres/import/generator.d.ts.map +1 -1
- package/dist/postgres/import/generator.js +50 -2
- package/dist/postgres/import/live-export.d.ts.map +1 -1
- package/dist/postgres/import/live-export.js +2 -0
- package/dist/postgres/live/catalog-kinds.d.ts +14 -0
- package/dist/postgres/live/catalog-kinds.d.ts.map +1 -1
- package/dist/postgres/live/catalog-kinds.js +206 -0
- package/dist/postgres/live/catalog.d.ts +2 -0
- package/dist/postgres/live/catalog.d.ts.map +1 -1
- package/dist/postgres/live/catalog.js +3 -1
- package/dist/postgres/live/describe-resources.d.ts.map +1 -1
- package/dist/postgres/live/describe-resources.js +10 -2
- package/dist/postgres/migrate/backfill.d.ts +2 -0
- package/dist/postgres/migrate/backfill.d.ts.map +1 -1
- package/dist/postgres/migrate/backfill.js +7 -1
- package/dist/postgres/migrate/carry.d.ts +45 -1
- package/dist/postgres/migrate/carry.d.ts.map +1 -1
- package/dist/postgres/migrate/carry.js +72 -8
- package/dist/postgres/migrate/observe.d.ts +28 -4
- package/dist/postgres/migrate/observe.d.ts.map +1 -1
- package/dist/postgres/migrate/observe.js +41 -12
- package/dist/postgres/migrate/op.d.ts +26 -1
- package/dist/postgres/migrate/op.d.ts.map +1 -1
- package/dist/postgres/migrate/op.js +3 -1
- package/dist/postgres/migrate/steps.d.ts +35 -2
- package/dist/postgres/migrate/steps.d.ts.map +1 -1
- package/dist/postgres/migrate/steps.js +158 -12
- package/dist/postgres/parser.d.ts +72 -1
- package/dist/postgres/parser.d.ts.map +1 -1
- package/dist/postgres/parser.js +194 -2
- package/dist/postgres/plan/deep.d.ts.map +1 -1
- package/dist/postgres/plan/deep.js +29 -1
- package/dist/postgres/plan/diff.d.ts.map +1 -1
- package/dist/postgres/plan/diff.js +39 -1
- package/dist/postgres/plan/normalize.d.ts +17 -2
- package/dist/postgres/plan/normalize.d.ts.map +1 -1
- package/dist/postgres/plan/normalize.js +109 -1
- package/dist/postgres/plan/rules.d.ts +1 -0
- package/dist/postgres/plan/rules.d.ts.map +1 -1
- package/dist/postgres/plan/rules.js +3 -2
- package/dist/postgres/plan/schema.js +1 -1
- package/dist/postgres/secret-options.d.ts +10 -0
- package/dist/postgres/secret-options.d.ts.map +1 -0
- package/dist/postgres/secret-options.js +9 -0
- package/dist/postgres/testing/roundtrip-schema.d.ts +3 -2
- package/dist/postgres/testing/roundtrip-schema.d.ts.map +1 -1
- package/dist/postgres/testing/roundtrip-schema.js +13 -1
- package/dist/postgres.d.ts +1 -1
- package/dist/postgres.d.ts.map +1 -1
- package/dist/postgres.js +1 -1
- package/dist/rules/audit-entries.ts +1 -0
- package/dist/rules/postgres-templates.ts +2 -2
- package/dist/rules/sqlch128.ts +230 -0
- package/dist/serializer.d.ts +5 -0
- package/dist/serializer.d.ts.map +1 -1
- package/dist/serializer.js +13 -2
- package/dist/sql-types-command.d.ts +13 -0
- package/dist/sql-types-command.d.ts.map +1 -1
- package/dist/sql-types-command.js +31 -16
- package/dist/sql-types.d.ts +22 -0
- package/dist/sql-types.d.ts.map +1 -1
- package/dist/sql-types.js +10 -6
- package/dist/sqlserver/lexer.d.ts +37 -0
- package/dist/sqlserver/lexer.d.ts.map +1 -0
- package/dist/sqlserver/lexer.js +254 -0
- package/dist/sqlserver/parse.d.ts +185 -0
- package/dist/sqlserver/parse.d.ts.map +1 -0
- package/dist/sqlserver/parse.js +767 -0
- package/dist/sqlserver/translate.d.ts +34 -0
- package/dist/sqlserver/translate.d.ts.map +1 -0
- package/dist/sqlserver/translate.js +495 -0
- package/dist/sqlserver/types.d.ts +44 -0
- package/dist/sqlserver/types.d.ts.map +1 -0
- package/dist/sqlserver/types.js +133 -0
- package/dist/sqlserver/validate.d.ts +31 -0
- package/dist/sqlserver/validate.d.ts.map +1 -0
- package/dist/sqlserver/validate.js +67 -0
- package/dist/validate.d.ts.map +1 -1
- package/dist/validate.js +5 -0
- package/package.json +2 -2
- package/src/change-set.ts +2 -1
- package/src/clickhouse/apply/statements.ts +25 -0
- package/src/clickhouse/import/live-export.ts +20 -5
- package/src/clickhouse/live/named-collections.e2e.test.ts +88 -0
- package/src/clickhouse/live/named-collections.ts +61 -0
- package/src/clickhouse/live/undeclarable.e2e.test.ts +5 -3
- package/src/clickhouse/live/undeclarable.ts +20 -4
- package/src/clickhouse/named-collections.test.ts +187 -0
- package/src/clickhouse/named-collections.ts +224 -0
- package/src/clickhouse/parser.ts +2 -1
- package/src/clickhouse/plan/commands.ts +17 -2
- package/src/clickhouse/plan/diff.ts +57 -1
- package/src/clickhouse/plan/disruption.ts +5 -0
- package/src/clickhouse/plan/rebuild-handoff.ts +3 -0
- package/src/clickhouse/plan/report.ts +6 -1
- package/src/clickhouse/plan/rules.ts +14 -4
- package/src/clickhouse/plan/stream-s3queue.e2e.test.ts +148 -0
- package/src/clickhouse/plan/stream.test.ts +237 -0
- package/src/clickhouse/plan/stream.ts +111 -0
- package/src/clickhouse/rebuild/observe.ts +15 -1
- package/src/clickhouse/review-catalog.test.ts +181 -0
- package/src/clickhouse/review-catalog.ts +489 -0
- package/src/codegen/classifier-page.ts +21 -4
- package/src/codegen/clickhouse-module.ts +3 -0
- package/src/codegen/coverage-page.ts +5 -3
- package/src/codegen/docs.ts +1 -1
- package/src/codegen/postgres-classifier-page.ts +1 -1
- package/src/codegen/registry.ts +5 -0
- package/src/composites/catalog.test.ts +6 -1
- package/src/composites/catalog.ts +100 -0
- package/src/composites/clickhouse.ts +2 -0
- package/src/composites/composites.test.ts +1 -1
- package/src/composites/otel-tables.test.ts +118 -0
- package/src/composites/otel-tables.ts +339 -0
- package/src/composites/stream-ingest.test.ts +114 -0
- package/src/composites/stream-ingest.ts +82 -0
- package/src/core/undeclarable.test.ts +6 -5
- package/src/coverage/clickhouse.json +1 -1
- package/src/coverage/postgres.json +7 -7
- package/src/coverage.test.ts +27 -2
- package/src/coverage.ts +18 -7
- package/src/drizzle-command.ts +94 -0
- package/src/drizzle-kit.e2e.test.ts +89 -0
- package/src/drizzle-types.e2e.test.ts +67 -0
- package/src/drizzle.test.ts +358 -0
- package/src/drizzle.ts +737 -0
- package/src/files/clickhouse.ts +8 -1
- package/src/files/common.ts +14 -1
- package/src/files/postgres.ts +12 -2
- package/src/generated/clickhouse.ts +3 -0
- package/src/generated/lexicon-sql.json +25 -0
- package/src/import-parser.sqlserver.test.ts +92 -0
- package/src/import-parser.ts +79 -5
- package/src/index.ts +1 -1
- package/src/lint/post-synth/audit-entries.ts +1 -0
- package/src/lint/post-synth/index.ts +2 -0
- package/src/lint/post-synth/sqlch128.test.ts +107 -0
- package/src/lint/post-synth/sqlch128.ts +230 -0
- package/src/lint/rules/postgres-templates.ts +2 -2
- package/src/lsp/postgres-template.ts +11 -0
- package/src/mcp/postgres.ts +1 -1
- package/src/migrate/from-postgres/cli.test.ts +165 -0
- package/src/migrate/from-postgres/detect.ts +7 -0
- package/src/migrate/from-postgres/emit.ts +96 -0
- package/src/migrate/from-postgres/example.test.ts +205 -0
- package/src/migrate/from-postgres/index.ts +122 -0
- package/src/migrate/from-postgres/translate.test.ts +242 -0
- package/src/migrate/from-postgres/translate.ts +359 -0
- package/src/migrate/from-postgres/types.test.ts +116 -0
- package/src/migrate/from-postgres/types.ts +236 -0
- package/src/migrate/from-postgres/validate.e2e.test.ts +44 -0
- package/src/migrate/from-postgres/workspace.e2e.test.ts +114 -0
- package/src/migration-replay.e2e.test.ts +155 -0
- package/src/migration-replay.test.ts +173 -0
- package/src/migration-replay.ts +289 -0
- package/src/op/__snapshots__/watch-pipeline.test.ts.snap +2 -2
- package/src/op/activities/postgres-migration.ts +4 -0
- package/src/op/activity-contracts.ts +2 -0
- package/src/plugin.ts +37 -2
- package/src/postgres/apply/apply.ts +9 -1
- package/src/postgres/apply/statements.ts +74 -1
- package/src/postgres/constraint-names.ts +71 -0
- package/src/postgres/database-kinds.test.ts +384 -0
- package/src/postgres/entities.ts +266 -1
- package/src/postgres/entity-types.ts +5 -0
- package/src/postgres/import/generator.ts +42 -2
- package/src/postgres/import/live-export.ts +1 -0
- package/src/postgres/live/catalog-kinds.ts +223 -0
- package/src/postgres/live/catalog.ts +6 -1
- package/src/postgres/live/database-kinds.e2e.test.ts +164 -0
- package/src/postgres/live/describe-resources.ts +11 -2
- package/src/postgres/live/undeclarable.e2e.test.ts +13 -6
- package/src/postgres/migrate/backfill.ts +13 -1
- package/src/postgres/migrate/carry.ts +103 -8
- package/src/postgres/migrate/followups.e2e.test.ts +218 -0
- package/src/postgres/migrate/followups.test.ts +199 -0
- package/src/postgres/migrate/kinds.e2e.test.ts +5 -5
- package/src/postgres/migrate/observe.ts +53 -14
- package/src/postgres/migrate/op.ts +28 -1
- package/src/postgres/migrate/partition.e2e.test.ts +129 -0
- package/src/postgres/migrate/partition.test.ts +206 -0
- package/src/postgres/migrate/steps.ts +157 -12
- package/src/postgres/parser.ts +234 -2
- package/src/postgres/plan/deep.ts +28 -1
- package/src/postgres/plan/diff.ts +36 -1
- package/src/postgres/plan/normalize.ts +122 -1
- package/src/postgres/plan/rules.ts +10 -3
- package/src/postgres/plan/schema.ts +1 -1
- package/src/postgres/secret-options.ts +10 -0
- package/src/postgres/testing/roundtrip-schema.ts +13 -1
- package/src/postgres.ts +16 -0
- package/src/serializer.ts +13 -2
- package/src/skills/chant-sql-postgres-migration.md +3 -3
- package/src/skills/chant-sql-postgres.md +6 -1
- package/src/skills/chant-sql.md +2 -1
- package/src/sql-types-command.ts +38 -16
- package/src/sql-types.ts +11 -6
- package/src/sqlserver/fixture.test.ts +186 -0
- package/src/sqlserver/import-cli.test.ts +61 -0
- package/src/sqlserver/lexer.ts +260 -0
- package/src/sqlserver/parse.ts +865 -0
- package/src/sqlserver/translate.test.ts +396 -0
- package/src/sqlserver/translate.ts +558 -0
- package/src/sqlserver/types.test.ts +102 -0
- package/src/sqlserver/types.ts +154 -0
- package/src/sqlserver/validate.e2e.test.ts +32 -0
- package/src/sqlserver/validate.test.ts +49 -0
- package/src/sqlserver/validate.ts +76 -0
- package/src/validate.ts +5 -0
- package/src/workspace-kinds.test.ts +11 -0
- package/workspace-kinds.json +100 -2
package/dist/drizzle.js
ADDED
|
@@ -0,0 +1,684 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Drizzle schema module `chant sql drizzle` writes (#4401): a Postgres
|
|
3
|
+
* build's tables, enums, sequences and views as `drizzle-orm/pg-core`
|
|
4
|
+
* declarations, so an application queries with Drizzle's row types while
|
|
5
|
+
* chant owns the schema, the plan and the apply.
|
|
6
|
+
*
|
|
7
|
+
* {@link renderDrizzle} is pure: the entities of a build in, the module's
|
|
8
|
+
* text and a list of what it left out. It reads the objects as the
|
|
9
|
+
* serializer writes them, as `sql-types.ts` does, so a `.sql` file's objects
|
|
10
|
+
* and a composite's members are covered as the build covers them.
|
|
11
|
+
*
|
|
12
|
+
* The API it writes is drizzle-orm {@link DRIZZLE_ORM_CHECKED}'s `pg-core`
|
|
13
|
+
* (type definitions read from the published package):
|
|
14
|
+
*
|
|
15
|
+
* - `pgTable(name, columns, (t) => [...])`, or `pgSchema(name).table(...)`
|
|
16
|
+
* for a schema other than `public` (`pgSchema("public")` throws);
|
|
17
|
+
* - column builders, `.notNull()`, `.default()`, `.primaryKey()`,
|
|
18
|
+
* `.generatedAlwaysAsIdentity()`, `.generatedAlwaysAs()`, `.array()`;
|
|
19
|
+
* - `foreignKey({ name, columns, foreignColumns })` with `.onDelete()` and
|
|
20
|
+
* `.onUpdate()`, `unique(name).on()`, `check(name, sql)`,
|
|
21
|
+
* `index(name).on()`, `uniqueIndex(name).on()`;
|
|
22
|
+
* - `pgEnum`, `pgSequence`, and `pgView(name, columns).existing()`;
|
|
23
|
+
* - `customType` for a column type Drizzle has no builder for.
|
|
24
|
+
*
|
|
25
|
+
* Each column key is the column's name in the database, so a row has the
|
|
26
|
+
* keys `RowOf` has. Every constraint and index carries the name Postgres
|
|
27
|
+
* would give it (`./postgres/constraint-names.ts`) when the DDL names none,
|
|
28
|
+
* so `drizzle-kit` compares equal names.
|
|
29
|
+
*
|
|
30
|
+
* Foreign keys use `foreignKey()` and not a column's `.references()`: the
|
|
31
|
+
* latter takes no name, and Drizzle derives `orders_user_id_users_id_fk`
|
|
32
|
+
* where Postgres says `orders_user_id_fkey`.
|
|
33
|
+
*
|
|
34
|
+
* Views are `.existing()`: chant creates them, and `drizzle-kit` must not.
|
|
35
|
+
*/
|
|
36
|
+
import { GENERATED_MARKER } from "@intentius/chant/discovery/files";
|
|
37
|
+
import { PINNED_MAJOR } from "./lint/post-synth/postgres-helpers.js";
|
|
38
|
+
import { parseType, projectFromObjects, resolveType } from "./lint/post-synth/postgres-names.js";
|
|
39
|
+
import { checkName, chooseName, columnsAddition } from "./postgres/constraint-names.js";
|
|
40
|
+
import { dialectOf, passthrough, pgType, runtimeColumns, serializedObjects } from "./sql-types.js";
|
|
41
|
+
import { quoteIdent } from "./postgres/keywords.js";
|
|
42
|
+
import { isPostgresObject } from "./postgres/entities.js";
|
|
43
|
+
/** The drizzle-orm version whose type definitions the output was written against. */
|
|
44
|
+
export const DRIZZLE_ORM_CHECKED = "0.45.4";
|
|
45
|
+
/** Thrown for a build that is not Postgres. */
|
|
46
|
+
export class DrizzleDialectError extends Error {
|
|
47
|
+
}
|
|
48
|
+
const SKIP_REASONS = {
|
|
49
|
+
"Postgres::Index": "an index on something that is not a table in the file",
|
|
50
|
+
"Postgres::CompositeType": "Drizzle has no composite type; a column of one is a customType",
|
|
51
|
+
"Postgres::RangeType": "Drizzle has no range type; a column of one is a customType",
|
|
52
|
+
"Postgres::Domain": "Drizzle has no domain; a column of one is a customType named by the domain",
|
|
53
|
+
"Postgres::Function": "Drizzle has no routines",
|
|
54
|
+
"Postgres::Procedure": "Drizzle has no routines",
|
|
55
|
+
"Postgres::Aggregate": "Drizzle has no routines",
|
|
56
|
+
"Postgres::Trigger": "Drizzle has no triggers",
|
|
57
|
+
"Postgres::EventTrigger": "Drizzle has no triggers",
|
|
58
|
+
"Postgres::Extension": "Drizzle has no extension declaration",
|
|
59
|
+
"Postgres::Collation": "Drizzle has no collation",
|
|
60
|
+
"Postgres::Cast": "Drizzle has no cast",
|
|
61
|
+
"Postgres::Operator": "Drizzle has no operator",
|
|
62
|
+
"Postgres::Statistics": "Drizzle has no extended statistics",
|
|
63
|
+
"Postgres::ForeignDataWrapper": "Drizzle has no foreign data wrapper",
|
|
64
|
+
"Postgres::ForeignServer": "Drizzle has no foreign server",
|
|
65
|
+
"Postgres::Publication": "Drizzle has no publication",
|
|
66
|
+
"Postgres::Policy": "Drizzle has pgPolicy, which is left out: chant owns access, and queries do not read policies",
|
|
67
|
+
"Postgres::Role": "Drizzle has pgRole, which is left out: chant owns access, and queries do not read roles",
|
|
68
|
+
"Postgres::Grant": "Drizzle has no grant",
|
|
69
|
+
"Postgres::DefaultPrivileges": "Drizzle has no default privileges",
|
|
70
|
+
};
|
|
71
|
+
// ── Names ───────────────────────────────────────────────────────────────
|
|
72
|
+
const RESERVED = new Set([
|
|
73
|
+
"break", "case", "catch", "class", "const", "continue", "debugger", "default", "delete", "do", "else", "enum", "export", "extends", "false", "finally", "for",
|
|
74
|
+
"function", "if", "import", "in", "instanceof", "new", "null", "return", "super", "switch", "this", "throw", "true", "try", "typeof", "var", "void", "while",
|
|
75
|
+
"with", "yield", "let", "static", "implements", "interface", "package", "private", "protected", "public", "await", "async", "of", "type", "undefined", "NaN",
|
|
76
|
+
"Infinity", "arguments", "eval",
|
|
77
|
+
]);
|
|
78
|
+
/** The names the module imports, which no declaration may take. */
|
|
79
|
+
const IMPORTABLE = [
|
|
80
|
+
"sql", "bigint", "bigserial", "boolean", "char", "check", "cidr", "customType", "date", "doublePrecision", "foreignKey", "index", "inet", "integer", "interval",
|
|
81
|
+
"json", "jsonb", "line", "macaddr", "macaddr8", "numeric", "pgEnum", "pgSchema", "pgSequence", "pgTable", "pgView", "pgMaterializedView", "point", "primaryKey",
|
|
82
|
+
"real", "serial", "smallint", "smallserial", "text", "time", "timestamp", "unique", "uniqueIndex", "uuid", "varchar", "unknownColumn",
|
|
83
|
+
];
|
|
84
|
+
const propertyName = (name) => (/^[A-Za-z_$][\w$]*$/.test(name) ? name : JSON.stringify(name));
|
|
85
|
+
const member = (obj, name) => (/^[A-Za-z_$][\w$]*$/.test(name) ? `${obj}.${name}` : `${obj}[${JSON.stringify(name)}]`);
|
|
86
|
+
const str = (s) => JSON.stringify(s);
|
|
87
|
+
/** A template literal's body for `text`. */
|
|
88
|
+
const template = (text) => text.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${");
|
|
89
|
+
const sqlText = (c, text) => {
|
|
90
|
+
c.used.add("sql");
|
|
91
|
+
return `sql\`${template(text.trim())}\``;
|
|
92
|
+
};
|
|
93
|
+
const byName = (a, b) => (a < b ? -1 : a > b ? 1 : 0);
|
|
94
|
+
const use = (c, name) => {
|
|
95
|
+
c.used.add(name);
|
|
96
|
+
return name;
|
|
97
|
+
};
|
|
98
|
+
const slug = (s) => s.replace(/[^A-Za-z0-9]+/g, "_").replace(/^_+|_+$/g, "") || "type";
|
|
99
|
+
function custom(c, dbType, ts) {
|
|
100
|
+
if (/^[^"]+\.[^"]+$/.test(dbType))
|
|
101
|
+
c.note(`a column of type ${dbType} is a customType, and drizzle-kit quotes a qualified type name as one identifier`);
|
|
102
|
+
const base = `${slug(dbType)}Type`;
|
|
103
|
+
// Two spellings that slug alike get their own identifier.
|
|
104
|
+
let id = base;
|
|
105
|
+
for (let n = 2; c.customs.has(id) && c.customs.get(id).dbType !== dbType; n++)
|
|
106
|
+
id = `${base}${n}`;
|
|
107
|
+
if (!c.customs.has(id))
|
|
108
|
+
c.customs.set(id, { dbType, ts });
|
|
109
|
+
use(c, "customType");
|
|
110
|
+
return { expr: `${id}()`, data: "other", serial: false, integer: false };
|
|
111
|
+
}
|
|
112
|
+
const precisionArg = (t) => {
|
|
113
|
+
const m = t.modifiers?.[0];
|
|
114
|
+
return m !== undefined && /^[0-6]$/.test(m) ? Number(m) : undefined;
|
|
115
|
+
};
|
|
116
|
+
function objectArg(fields) {
|
|
117
|
+
const parts = fields.filter(([, v]) => v !== undefined).map(([k, v]) => `${k}: ${typeof v === "string" ? str(v) : String(v)}`);
|
|
118
|
+
return parts.length > 0 ? `{ ${parts.join(", ")} }` : "";
|
|
119
|
+
}
|
|
120
|
+
/** A column's Drizzle builder, from the type as the declaration wrote it. */
|
|
121
|
+
function columnType(c, text) {
|
|
122
|
+
const t = parseType(text);
|
|
123
|
+
const unknown = () => {
|
|
124
|
+
c.used.add("customType");
|
|
125
|
+
c.used.add("unknownColumn");
|
|
126
|
+
return { expr: "unknownColumn()", data: "other", serial: false, integer: false };
|
|
127
|
+
};
|
|
128
|
+
if (!t)
|
|
129
|
+
return text === undefined ? unknown() : custom(c, text.trim(), "unknown");
|
|
130
|
+
const r = resolveType(c.p, t, { serial: true });
|
|
131
|
+
let built;
|
|
132
|
+
if (r.kind === "builtin") {
|
|
133
|
+
const call = (fn, arg = "", data = "other", integer = false) => ({ expr: `${use(c, fn)}(${arg})`, data, serial: false, integer });
|
|
134
|
+
const mods = t.modifiers ?? [];
|
|
135
|
+
switch (r.canonical) {
|
|
136
|
+
case "smallint":
|
|
137
|
+
built = r.serial ? { ...call("smallserial", "", "number"), serial: true } : call("smallint", "", "number", true);
|
|
138
|
+
break;
|
|
139
|
+
case "integer":
|
|
140
|
+
built = r.serial ? { ...call("serial", "", "number"), serial: true } : call("integer", "", "number", true);
|
|
141
|
+
break;
|
|
142
|
+
case "bigint": {
|
|
143
|
+
const mode = c.bigintMode;
|
|
144
|
+
const b = call(r.serial ? "bigserial" : "bigint", `{ mode: ${str(mode)} }`, mode === "number" ? "number" : "bigint", true);
|
|
145
|
+
built = r.serial ? { ...b, serial: true } : b;
|
|
146
|
+
break;
|
|
147
|
+
}
|
|
148
|
+
case "real":
|
|
149
|
+
built = call("real", "", "number");
|
|
150
|
+
break;
|
|
151
|
+
case "double precision":
|
|
152
|
+
built = call("doublePrecision", "", "number");
|
|
153
|
+
break;
|
|
154
|
+
case "numeric": {
|
|
155
|
+
const [prec, scale] = mods;
|
|
156
|
+
built = call("numeric", objectArg([["precision", prec !== undefined ? Number(prec) : undefined], ["scale", scale !== undefined ? Number(scale) : undefined]]));
|
|
157
|
+
break;
|
|
158
|
+
}
|
|
159
|
+
case "boolean":
|
|
160
|
+
built = call("boolean", "", "boolean");
|
|
161
|
+
break;
|
|
162
|
+
case "text":
|
|
163
|
+
built = call("text", "", "string");
|
|
164
|
+
break;
|
|
165
|
+
case "uuid":
|
|
166
|
+
built = call("uuid", "", "string");
|
|
167
|
+
break;
|
|
168
|
+
case "character varying":
|
|
169
|
+
built = call("varchar", objectArg([["length", mods[0] !== undefined ? Number(mods[0]) : undefined]]), "string");
|
|
170
|
+
break;
|
|
171
|
+
case "character":
|
|
172
|
+
built = call("char", objectArg([["length", mods[0] !== undefined ? Number(mods[0]) : undefined]]), "string");
|
|
173
|
+
break;
|
|
174
|
+
case "json":
|
|
175
|
+
built = call("json");
|
|
176
|
+
break;
|
|
177
|
+
case "jsonb":
|
|
178
|
+
built = call("jsonb");
|
|
179
|
+
break;
|
|
180
|
+
case "date":
|
|
181
|
+
built = call("date");
|
|
182
|
+
break;
|
|
183
|
+
case "timestamp without time zone":
|
|
184
|
+
case "timestamp with time zone":
|
|
185
|
+
built = call("timestamp", objectArg([["precision", precisionArg(t)], ["withTimezone", r.canonical.endsWith("with time zone") ? true : undefined]]));
|
|
186
|
+
break;
|
|
187
|
+
case "time without time zone":
|
|
188
|
+
case "time with time zone":
|
|
189
|
+
built = call("time", objectArg([["precision", precisionArg(t)], ["withTimezone", r.canonical.endsWith("with time zone") ? true : undefined]]), "string");
|
|
190
|
+
break;
|
|
191
|
+
case "interval":
|
|
192
|
+
built = call("interval", objectArg([["fields", t.fields?.toLowerCase()], ["precision", precisionArg(t)]]), "string");
|
|
193
|
+
break;
|
|
194
|
+
case "inet":
|
|
195
|
+
case "cidr":
|
|
196
|
+
case "macaddr":
|
|
197
|
+
case "macaddr8":
|
|
198
|
+
built = call(r.canonical, "", "string");
|
|
199
|
+
break;
|
|
200
|
+
case "point":
|
|
201
|
+
built = call("point", `{ mode: "xy" }`);
|
|
202
|
+
break;
|
|
203
|
+
case "line":
|
|
204
|
+
built = call("line", `{ mode: "abc" }`);
|
|
205
|
+
break;
|
|
206
|
+
default: {
|
|
207
|
+
// No builder in pg-core: the type, as format_type spells it, with the row type RowOf gives it.
|
|
208
|
+
const ty = pgType(c.p, text);
|
|
209
|
+
built = custom(c, ty.sqlType.replace(/\[\]$/, ""), ty.ts.replace(/\[\]$/, "") || "unknown");
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
else if (r.kind === "declared" && r.object.type === "Postgres::Enum" && c.enums.has(qualified(r.object.schema, r.object.name))) {
|
|
214
|
+
built = { expr: `${c.enums.get(qualified(r.object.schema, r.object.name))}()`, data: "string", serial: false, integer: false };
|
|
215
|
+
}
|
|
216
|
+
else if (r.kind !== "declared" && c.enums.has(qualified(t.schema, t.name))) {
|
|
217
|
+
// An enum in the public schema, which the project does not list as a schema of its own.
|
|
218
|
+
built = { expr: `${c.enums.get(qualified(t.schema, t.name))}()`, data: "string", serial: false, integer: false };
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
const ty = pgType(c.p, text);
|
|
222
|
+
built = custom(c, ty.sqlType.replace(/\[\]$/, ""), ty.ts.replace(/\[\]$/, "") || "unknown");
|
|
223
|
+
}
|
|
224
|
+
return t.array ? { ...built, expr: `${built.expr}.array()`, data: "other", serial: false, integer: false } : built;
|
|
225
|
+
}
|
|
226
|
+
/** The argument of `.default()` for `expr`, a literal where one fits the column's value type. */
|
|
227
|
+
function defaultArg(c, expr, data) {
|
|
228
|
+
const e = expr.trim();
|
|
229
|
+
if (data === "boolean" && /^(true|false)$/i.test(e))
|
|
230
|
+
return e.toLowerCase();
|
|
231
|
+
if (data === "number" && /^-?\d+$/.test(e))
|
|
232
|
+
return e;
|
|
233
|
+
if (data === "bigint" && /^-?\d+$/.test(e))
|
|
234
|
+
return `${e}n`;
|
|
235
|
+
const lit = /^'((?:[^']|'')*)'$/.exec(e);
|
|
236
|
+
if (data === "string" && lit)
|
|
237
|
+
return str(lit[1].replace(/''/g, "'"));
|
|
238
|
+
return sqlText(c, e);
|
|
239
|
+
}
|
|
240
|
+
// ── Identity and sequence options ───────────────────────────────────────
|
|
241
|
+
const OPTION_KEYS = { increment: "increment", minvalue: "minValue", maxvalue: "maxValue", start: "startWith", cache: "cache" };
|
|
242
|
+
/** `START WITH 100 INCREMENT BY 5 CYCLE` as the options object; undefined when something is not understood. */
|
|
243
|
+
function identityOptions(text) {
|
|
244
|
+
const body = text.trim().replace(/^\(/, "").replace(/\)$/, "");
|
|
245
|
+
const re = /\s*(?:(START)(?:\s+WITH)?|(INCREMENT)(?:\s+BY)?|(MINVALUE)|(MAXVALUE)|(CACHE)|(NO\s+CYCLE|CYCLE)|(NO\s+MINVALUE|NO\s+MAXVALUE))\s*(-?\d+)?/gy;
|
|
246
|
+
const out = [];
|
|
247
|
+
let at = 0;
|
|
248
|
+
while (at < body.length) {
|
|
249
|
+
re.lastIndex = at;
|
|
250
|
+
const m = re.exec(body);
|
|
251
|
+
if (!m || m.index !== at)
|
|
252
|
+
return undefined;
|
|
253
|
+
at = re.lastIndex;
|
|
254
|
+
const word = m.slice(1, 8).find((x) => x !== undefined).toUpperCase().replace(/\s+/g, " ");
|
|
255
|
+
if (word === "CYCLE")
|
|
256
|
+
out.push("cycle: true");
|
|
257
|
+
else if (word === "NO CYCLE" || word.startsWith("NO "))
|
|
258
|
+
continue;
|
|
259
|
+
else if (m[8] === undefined)
|
|
260
|
+
return undefined;
|
|
261
|
+
else
|
|
262
|
+
out.push(`${OPTION_KEYS[word.toLowerCase()]}: ${m[8]}`);
|
|
263
|
+
}
|
|
264
|
+
return out.length > 0 ? `{ ${out.join(", ")} }` : "";
|
|
265
|
+
}
|
|
266
|
+
const ACTIONS = { cascade: "cascade", restrict: "restrict", "no action": "no action", "set null": "set null", "set default": "set default" };
|
|
267
|
+
function action(text) {
|
|
268
|
+
if (text === undefined)
|
|
269
|
+
return undefined;
|
|
270
|
+
return ACTIONS[text.trim().toLowerCase().replace(/\s+/g, " ")] ?? null;
|
|
271
|
+
}
|
|
272
|
+
/** `schema.name`, with `public` for no schema. */
|
|
273
|
+
const qualified = (schema, name) => `${schema ?? "public"}.${name}`;
|
|
274
|
+
const isDefaultSchema = (schema) => schema === undefined || schema === "public";
|
|
275
|
+
/**
|
|
276
|
+
* The Drizzle schema module for a build's entities. Throws
|
|
277
|
+
* {@link DrizzleDialectError} when the build is not Postgres.
|
|
278
|
+
*/
|
|
279
|
+
export function renderDrizzle(entities, opts = {}) {
|
|
280
|
+
const config = opts.config ?? {};
|
|
281
|
+
const dialect = dialectOf(entities, config);
|
|
282
|
+
if (dialect !== "postgres") {
|
|
283
|
+
throw new DrizzleDialectError(`the build declares ${dialect} objects, and Drizzle has no ${dialect} dialect; the Drizzle export is for Postgres`);
|
|
284
|
+
}
|
|
285
|
+
const sqlEntities = new Map([...entities].filter(([, e]) => isPostgresObject(e)));
|
|
286
|
+
const doc = sqlEntities.size > 0 ? serializedObjects(entities, config) : { objects: [], postgresMajor: PINNED_MAJOR };
|
|
287
|
+
const objects = doc.objects;
|
|
288
|
+
const p = projectFromObjects(objects, doc.postgresMajor ?? PINNED_MAJOR);
|
|
289
|
+
const notes = [];
|
|
290
|
+
const skipped = new Map();
|
|
291
|
+
const skip = (kind, name, reason) => {
|
|
292
|
+
const s = skipped.get(`${kind}\0${reason}`) ?? { names: [], reason };
|
|
293
|
+
s.names.push(name);
|
|
294
|
+
skipped.set(`${kind}\0${reason}`, s);
|
|
295
|
+
};
|
|
296
|
+
// Identifiers: the export name, made safe and unique.
|
|
297
|
+
const used = new Set([...IMPORTABLE, ...RESERVED]);
|
|
298
|
+
const idents = new Map();
|
|
299
|
+
const identOf = (o) => {
|
|
300
|
+
const have = idents.get(o.export);
|
|
301
|
+
if (have)
|
|
302
|
+
return have;
|
|
303
|
+
let base = o.export.replace(/[^A-Za-z0-9_$]/g, "_");
|
|
304
|
+
if (/^\d/.test(base))
|
|
305
|
+
base = `_${base}`;
|
|
306
|
+
let id = base || "_";
|
|
307
|
+
for (let n = 2; used.has(id); n++)
|
|
308
|
+
id = `${base}_${n}`;
|
|
309
|
+
used.add(id);
|
|
310
|
+
idents.set(o.export, id);
|
|
311
|
+
return id;
|
|
312
|
+
};
|
|
313
|
+
const c = { p, bigintMode: opts.bigintMode ?? "number", enums: new Map(), customs: new Map(), used: new Set(), note: (t) => notes.push(t) };
|
|
314
|
+
const sqlName = (o) => String(o.sqlName ?? o.name);
|
|
315
|
+
const label = (o) => sqlName(o);
|
|
316
|
+
// Schemas: one pgSchema each, except public.
|
|
317
|
+
const schemaIds = new Map();
|
|
318
|
+
const schemaIdent = (schema) => {
|
|
319
|
+
const have = schemaIds.get(schema);
|
|
320
|
+
if (have)
|
|
321
|
+
return have;
|
|
322
|
+
const declared = objects.find((o) => o.type === "Postgres::Schema" && o.name === schema);
|
|
323
|
+
let base = declared ? declared.export.replace(/[^A-Za-z0-9_$]/g, "_") : `${schema.replace(/[^A-Za-z0-9_$]/g, "_")}Schema`;
|
|
324
|
+
if (/^\d/.test(base))
|
|
325
|
+
base = `_${base}`;
|
|
326
|
+
let id = base;
|
|
327
|
+
for (let n = 2; used.has(id); n++)
|
|
328
|
+
id = `${base}_${n}`;
|
|
329
|
+
used.add(id);
|
|
330
|
+
schemaIds.set(schema, id);
|
|
331
|
+
return id;
|
|
332
|
+
};
|
|
333
|
+
const owner = (schema, kind) => {
|
|
334
|
+
if (isDefaultSchema(schema)) {
|
|
335
|
+
return use(c, { table: "pgTable", view: "pgView", materializedView: "pgMaterializedView", enum: "pgEnum", sequence: "pgSequence" }[kind]);
|
|
336
|
+
}
|
|
337
|
+
use(c, "pgSchema");
|
|
338
|
+
return `${schemaIdent(schema)}.${kind}`;
|
|
339
|
+
};
|
|
340
|
+
// Enums and sequences come before the tables that read them.
|
|
341
|
+
const blocks = { enums: [], sequences: [], tables: [], views: [] };
|
|
342
|
+
let annotated = false;
|
|
343
|
+
const counts = { tables: 0, views: 0, enums: 0, sequences: 0 };
|
|
344
|
+
const enumObjects = objects.filter((o) => o.type === "Postgres::Enum").sort((a, b) => byName(sqlName(a), sqlName(b)));
|
|
345
|
+
for (const o of enumObjects) {
|
|
346
|
+
const labels = o.labels ?? [];
|
|
347
|
+
if (labels.length === 0) {
|
|
348
|
+
skip(o.type, label(o), "an enum with no labels, which Drizzle's pgEnum cannot take");
|
|
349
|
+
continue;
|
|
350
|
+
}
|
|
351
|
+
const id = identOf(o);
|
|
352
|
+
c.enums.set(qualified(o.schema, o.name), id);
|
|
353
|
+
const fn = owner(o.schema, "enum");
|
|
354
|
+
blocks.enums.push(`export const ${id} = ${fn}(${str(o.name)}, [${labels.map(str).join(", ")}]);`);
|
|
355
|
+
counts.enums++;
|
|
356
|
+
}
|
|
357
|
+
// Constraint and index names are taken per schema (index-backed) and per table (the rest).
|
|
358
|
+
const relationNames = new Map();
|
|
359
|
+
const relationSet = (schema) => {
|
|
360
|
+
const key = schema ?? "public";
|
|
361
|
+
let s = relationNames.get(key);
|
|
362
|
+
if (!s)
|
|
363
|
+
relationNames.set(key, (s = new Set()));
|
|
364
|
+
return s;
|
|
365
|
+
};
|
|
366
|
+
for (const o of objects) {
|
|
367
|
+
if (["Postgres::Table", "Postgres::View", "Postgres::MaterializedView", "Postgres::Sequence", "Postgres::Index"].includes(o.type))
|
|
368
|
+
relationSet(o.schema).add(o.name);
|
|
369
|
+
if (o.type === "Postgres::Table") {
|
|
370
|
+
const t = o;
|
|
371
|
+
for (const k of [t.primaryKey, ...t.uniques])
|
|
372
|
+
if (k?.name)
|
|
373
|
+
relationSet(o.schema).add(k.name);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
const sequenceObjects = objects.filter((o) => o.type === "Postgres::Sequence").sort((a, b) => byName(sqlName(a), sqlName(b)));
|
|
377
|
+
for (const o of sequenceObjects) {
|
|
378
|
+
const dataType = o.dataType?.trim().toLowerCase();
|
|
379
|
+
if (dataType !== undefined && dataType !== "bigint" && dataType !== "int8") {
|
|
380
|
+
skip(o.type, label(o), `a sequence of type ${dataType}: pgSequence has no data type, and its defaults are bigint's`);
|
|
381
|
+
continue;
|
|
382
|
+
}
|
|
383
|
+
const fields = [];
|
|
384
|
+
const num = (key, v) => {
|
|
385
|
+
if (typeof v === "string" && /^-?\d+$/.test(v.trim()))
|
|
386
|
+
fields.push([key, v.trim()]);
|
|
387
|
+
};
|
|
388
|
+
num("increment", o.increment);
|
|
389
|
+
num("minValue", o.minValue);
|
|
390
|
+
num("maxValue", o.maxValue);
|
|
391
|
+
num("startWith", o.start);
|
|
392
|
+
num("cache", o.cache);
|
|
393
|
+
if (o.cycle === true)
|
|
394
|
+
fields.push(["cycle", "true"]);
|
|
395
|
+
const id = identOf(o);
|
|
396
|
+
const args = fields.length > 0 ? `, { ${fields.map(([k, v]) => `${k}: ${v}`).join(", ")} }` : "";
|
|
397
|
+
blocks.sequences.push(`export const ${id} = ${owner(o.schema, "sequence")}(${str(o.name)}${args});`);
|
|
398
|
+
counts.sequences++;
|
|
399
|
+
}
|
|
400
|
+
// Tables.
|
|
401
|
+
const tables = objects.filter((o) => o.type === "Postgres::Table");
|
|
402
|
+
const tableById = new Map(tables.map((t) => [t.export, t]));
|
|
403
|
+
const tableBySqlName = new Map(tables.map((t) => [qualified(t.schema, t.name), t]));
|
|
404
|
+
const indexesOf = new Map();
|
|
405
|
+
for (const o of objects)
|
|
406
|
+
if (o.type === "Postgres::Index")
|
|
407
|
+
(indexesOf.get(o.table) ?? indexesOf.set(o.table, []).get(o.table)).push(o);
|
|
408
|
+
const mappedTable = (t) => t.partitionOf === undefined && t.ofType === undefined;
|
|
409
|
+
const builders = new Map();
|
|
410
|
+
for (const t of tables.slice().sort((a, b) => byName(sqlName(a), sqlName(b)))) {
|
|
411
|
+
if (!mappedTable(t)) {
|
|
412
|
+
skip(t.type, label(t), t.partitionOf !== undefined ? "a partition: its parent is the table to query" : "a table of a composite type, whose columns Drizzle cannot read from the type");
|
|
413
|
+
continue;
|
|
414
|
+
}
|
|
415
|
+
const entity = entities.get(t.export);
|
|
416
|
+
const names = runtimeColumns(entity);
|
|
417
|
+
const own = new Map(t.columns.map((col) => [col.name, col]));
|
|
418
|
+
const inherited = new Map();
|
|
419
|
+
for (const parent of t.inherits) {
|
|
420
|
+
const pt = typeof parent === "string" ? tableById.get(parent) : undefined;
|
|
421
|
+
for (const col of pt?.columns ?? [])
|
|
422
|
+
if (!inherited.has(col.name))
|
|
423
|
+
inherited.set(col.name, col.type);
|
|
424
|
+
}
|
|
425
|
+
const pkColumns = t.primaryKey?.columns ?? [];
|
|
426
|
+
const table = t.name;
|
|
427
|
+
const cols = [];
|
|
428
|
+
const extra = [];
|
|
429
|
+
// A foreign key to another table: two tables can reference each other, and tsc cannot infer either's type through the other's callback.
|
|
430
|
+
let crossFk = false;
|
|
431
|
+
const built = new Map();
|
|
432
|
+
const tableNotes = (msg) => notes.push(`${label(t)}: ${msg}`);
|
|
433
|
+
c.note = tableNotes;
|
|
434
|
+
const schemaNames = relationSet(t.schema);
|
|
435
|
+
const constraintNames = new Set();
|
|
436
|
+
for (const x of [...t.checks, ...t.foreignKeys, ...t.uniques])
|
|
437
|
+
if (x.name)
|
|
438
|
+
constraintNames.add(x.name);
|
|
439
|
+
const singlePk = t.primaryKey && t.primaryKey.columns.length === 1 && (t.primaryKey.name === undefined || t.primaryKey.name === `${table}_pkey`) ? t.primaryKey.columns[0] : undefined;
|
|
440
|
+
for (const name of names) {
|
|
441
|
+
const col = own.get(name);
|
|
442
|
+
const text = col?.type ?? inherited.get(name);
|
|
443
|
+
const b = columnType(c, text);
|
|
444
|
+
built.set(name, b);
|
|
445
|
+
let expr = b.expr;
|
|
446
|
+
const identity = col?.generated?.kind === "identity" ? col.generated : undefined;
|
|
447
|
+
const stored = col?.generated?.kind === "stored" ? col.generated : undefined;
|
|
448
|
+
if (col?.generated?.kind === "virtual")
|
|
449
|
+
tableNotes(`column ${name} is a virtual generated column, which Drizzle cannot say; it is a plain column`);
|
|
450
|
+
if (identity) {
|
|
451
|
+
if (b.integer) {
|
|
452
|
+
const opts = identity.options !== undefined ? identityOptions(identity.options) : "";
|
|
453
|
+
if (opts === undefined)
|
|
454
|
+
tableNotes(`column ${name}: identity options "${identity.options}" are not mapped`);
|
|
455
|
+
expr += `.${identity.always ? "generatedAlwaysAsIdentity" : "generatedByDefaultAsIdentity"}(${opts ?? ""})`;
|
|
456
|
+
}
|
|
457
|
+
else
|
|
458
|
+
tableNotes(`column ${name} is an identity column on a type Drizzle's identity does not take`);
|
|
459
|
+
}
|
|
460
|
+
else if (stored?.expr)
|
|
461
|
+
expr += `.generatedAlwaysAs(${sqlText(c, stored.expr)})`;
|
|
462
|
+
const isPk = singlePk === name;
|
|
463
|
+
const notNull = col?.notNull === true || pkColumns.includes(name) || identity !== undefined || b.serial;
|
|
464
|
+
if (notNull && !isPk)
|
|
465
|
+
expr += ".notNull()";
|
|
466
|
+
if (col?.default !== undefined && !stored && !identity && !b.serial)
|
|
467
|
+
expr += `.default(${defaultArg(c, col.default, b.data)})`;
|
|
468
|
+
if (isPk)
|
|
469
|
+
expr += ".primaryKey()";
|
|
470
|
+
if (col?.collate)
|
|
471
|
+
tableNotes(`column ${name}: COLLATE ${col.collate} is not mapped`);
|
|
472
|
+
cols.push(` ${propertyName(name)}: ${expr},`);
|
|
473
|
+
}
|
|
474
|
+
builders.set(t.export, built);
|
|
475
|
+
if (t.like.length > 0)
|
|
476
|
+
tableNotes("LIKE clauses copy columns that the build does not list; they are not in the table");
|
|
477
|
+
if (t.persistence === "unlogged")
|
|
478
|
+
tableNotes("UNLOGGED is not mapped");
|
|
479
|
+
// Extra config: primary key, uniques, foreign keys, checks, indexes.
|
|
480
|
+
if (t.primaryKey && singlePk === undefined) {
|
|
481
|
+
const name = t.primaryKey.name ?? chooseName(table, undefined, "pkey", schemaNames);
|
|
482
|
+
extra.push(`${use(c, "primaryKey")}({ name: ${str(name)}, columns: [${t.primaryKey.columns.map((x) => member("t", x)).join(", ")}] }),`);
|
|
483
|
+
}
|
|
484
|
+
for (const u of t.uniques) {
|
|
485
|
+
const name = u.name ?? chooseName(table, columnsAddition(u.columns), "key", schemaNames);
|
|
486
|
+
if (!u.name)
|
|
487
|
+
schemaNames.add(name);
|
|
488
|
+
if (u.include || u.with)
|
|
489
|
+
tableNotes(`unique ${name}: INCLUDE and WITH are not mapped`);
|
|
490
|
+
extra.push(`${use(c, "unique")}(${str(name)}).on(${u.columns.map((x) => member("t", x)).join(", ")})${u.nullsNotDistinct ? ".nullsNotDistinct()" : ""},`);
|
|
491
|
+
}
|
|
492
|
+
for (const f of t.foreignKeys) {
|
|
493
|
+
const target = tableById.get(f.references) ?? tableBySqlName.get(f.refTable.includes(".") ? f.refTable : qualified(t.schema, f.refTable));
|
|
494
|
+
if (!target || !mappedTable(target)) {
|
|
495
|
+
skip("Postgres::ForeignKey", `${label(t)} (${f.columns.join(", ")}) -> ${f.refTable}`, "a foreign key to a table that is not in the file");
|
|
496
|
+
continue;
|
|
497
|
+
}
|
|
498
|
+
const refColumns = f.refColumns.length > 0 ? f.refColumns : (target.primaryKey?.columns ?? []);
|
|
499
|
+
if (refColumns.length !== f.columns.length) {
|
|
500
|
+
skip("Postgres::ForeignKey", `${label(t)} (${f.columns.join(", ")}) -> ${f.refTable}`, "a foreign key whose referenced columns could not be read");
|
|
501
|
+
continue;
|
|
502
|
+
}
|
|
503
|
+
const onDelete = action(f.onDelete);
|
|
504
|
+
const onUpdate = action(f.onUpdate);
|
|
505
|
+
const name = f.name ?? chooseName(table, columnsAddition(f.columns), "fkey", constraintNames);
|
|
506
|
+
constraintNames.add(name);
|
|
507
|
+
const targetRef = target.export === t.export ? "t" : identOf(target);
|
|
508
|
+
if (target.export !== t.export)
|
|
509
|
+
crossFk = true;
|
|
510
|
+
let line = `${use(c, "foreignKey")}({ name: ${str(name)}, columns: [${f.columns.map((x) => member("t", x)).join(", ")}], foreignColumns: [${refColumns.map((x) => member(targetRef, x)).join(", ")}] })`;
|
|
511
|
+
if (onDelete)
|
|
512
|
+
line += `.onDelete(${str(onDelete)})`;
|
|
513
|
+
else if (onDelete === null)
|
|
514
|
+
tableNotes(`foreign key ${name}: ON DELETE ${f.onDelete} is not mapped`);
|
|
515
|
+
if (onUpdate)
|
|
516
|
+
line += `.onUpdate(${str(onUpdate)})`;
|
|
517
|
+
else if (onUpdate === null)
|
|
518
|
+
tableNotes(`foreign key ${name}: ON UPDATE ${f.onUpdate} is not mapped`);
|
|
519
|
+
if (f.match || f.deferrable || f.initiallyDeferred)
|
|
520
|
+
tableNotes(`foreign key ${name}: MATCH and DEFERRABLE are not mapped`);
|
|
521
|
+
extra.push(`${line},`);
|
|
522
|
+
}
|
|
523
|
+
for (const k of t.checks) {
|
|
524
|
+
const name = k.name ?? checkName(table, k.expr, names, constraintNames);
|
|
525
|
+
constraintNames.add(name);
|
|
526
|
+
extra.push(`${use(c, "check")}(${str(name)}, ${sqlText(c, k.expr)}),`);
|
|
527
|
+
}
|
|
528
|
+
for (const x of t.exclusions) {
|
|
529
|
+
skip("Postgres::Exclusion", label(t), "an exclusion constraint, which Drizzle has no way to say");
|
|
530
|
+
void x;
|
|
531
|
+
}
|
|
532
|
+
for (const ix of (indexesOf.get(t.export) ?? []).sort((a, b) => byName(a.name, b.name))) {
|
|
533
|
+
const line = indexLine(c, ix, names, skip, label(ix));
|
|
534
|
+
if (line)
|
|
535
|
+
extra.push(`${line},`);
|
|
536
|
+
}
|
|
537
|
+
const id = identOf(t);
|
|
538
|
+
const fn = owner(t.schema, "table");
|
|
539
|
+
const body = `{\n${cols.join("\n")}\n}`;
|
|
540
|
+
if (crossFk)
|
|
541
|
+
annotated = true;
|
|
542
|
+
blocks.tables.push(extra.length > 0
|
|
543
|
+
? `export const ${id} = ${fn}(${str(t.name)}, ${body}, (t)${crossFk ? ": PgTableExtraConfigValue[]" : ""} => [\n${extra.map((x) => ` ${x}`).join("\n")}\n]);`
|
|
544
|
+
: `export const ${id} = ${fn}(${str(t.name)}, ${body});`);
|
|
545
|
+
counts.tables++;
|
|
546
|
+
}
|
|
547
|
+
c.note = (text) => notes.push(text);
|
|
548
|
+
// Views and materialized views: .existing(), with the columns whose types can be read.
|
|
549
|
+
const relationsDone = new Map(builders);
|
|
550
|
+
const viewObjects = objects.filter((o) => o.type === "Postgres::View" || o.type === "Postgres::MaterializedView").sort((a, b) => byName(sqlName(a), sqlName(b)));
|
|
551
|
+
const viewBuilders = (o, depth = 0) => {
|
|
552
|
+
const have = relationsDone.get(o.export);
|
|
553
|
+
if (have)
|
|
554
|
+
return have;
|
|
555
|
+
const names = runtimeColumns(entities.get(o.export));
|
|
556
|
+
const map = new Map();
|
|
557
|
+
relationsDone.set(o.export, map);
|
|
558
|
+
for (const name of names) {
|
|
559
|
+
const via = passthrough(o, name, quoteIdent);
|
|
560
|
+
const sourceObject = via ? objects.find((x) => x.export === via.export) : undefined;
|
|
561
|
+
let source;
|
|
562
|
+
if (via && sourceObject && depth < 8) {
|
|
563
|
+
source = (sourceObject.type === "Postgres::Table" ? relationsDone.get(sourceObject.export) : viewBuilders(sourceObject, depth + 1))?.get(via.column);
|
|
564
|
+
}
|
|
565
|
+
if (source)
|
|
566
|
+
map.set(name, source);
|
|
567
|
+
else {
|
|
568
|
+
c.used.add("customType");
|
|
569
|
+
c.used.add("unknownColumn");
|
|
570
|
+
map.set(name, { expr: "unknownColumn()", data: "other", serial: false, integer: false });
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
return map;
|
|
574
|
+
};
|
|
575
|
+
for (const o of viewObjects) {
|
|
576
|
+
const cols = viewBuilders(o);
|
|
577
|
+
const unreadable = [...cols].filter(([, b]) => b.expr === "unknownColumn()").map(([n]) => n);
|
|
578
|
+
if (unreadable.length > 0)
|
|
579
|
+
notes.push(`${label(o)}: ${unreadable.join(", ")} ${unreadable.length === 1 ? "is an expression" : "are expressions"}, so ${unreadable.length === 1 ? "its type is" : "their types are"} unknown`);
|
|
580
|
+
const kind = o.type === "Postgres::View" ? "view" : "materializedView";
|
|
581
|
+
const id = identOf(o);
|
|
582
|
+
const body = [...cols].map(([n, b]) => ` ${propertyName(n)}: ${b.expr},`).join("\n");
|
|
583
|
+
blocks.views.push(`export const ${id} = ${owner(o.schema, kind)}(${str(o.name)}, {\n${body}\n}).existing();`);
|
|
584
|
+
counts.views++;
|
|
585
|
+
}
|
|
586
|
+
// Everything else Drizzle has no declaration for.
|
|
587
|
+
for (const o of objects) {
|
|
588
|
+
if (["Postgres::Schema", "Postgres::Table", "Postgres::Index", "Postgres::View", "Postgres::MaterializedView", "Postgres::Sequence", "Postgres::Enum"].includes(o.type))
|
|
589
|
+
continue;
|
|
590
|
+
skip(o.type, label(o), SKIP_REASONS[o.type] ?? "Drizzle has no declaration for it");
|
|
591
|
+
}
|
|
592
|
+
// An index on a table that is not mapped.
|
|
593
|
+
for (const [tableExport, list] of indexesOf) {
|
|
594
|
+
const t = tableById.get(tableExport);
|
|
595
|
+
if (!t || !mappedTable(t))
|
|
596
|
+
for (const ix of list)
|
|
597
|
+
skip(ix.type, label(ix), SKIP_REASONS["Postgres::Index"]);
|
|
598
|
+
}
|
|
599
|
+
// Assemble.
|
|
600
|
+
const lines = [
|
|
601
|
+
`// ${GENERATED_MARKER}. \`chant sql drizzle\` writes it from the build's entities.`,
|
|
602
|
+
`// It targets drizzle-orm ${DRIZZLE_ORM_CHECKED}'s pg-core. chant owns the schema: query with these tables, and do not run drizzle-kit push or migrate.`,
|
|
603
|
+
];
|
|
604
|
+
const skippedList = [...skipped].map(([key, v]) => ({ kind: key.split("\0")[0], names: v.names, reason: v.reason }));
|
|
605
|
+
skippedList.sort((a, b) => (a.kind + a.reason < b.kind + b.reason ? -1 : 1));
|
|
606
|
+
const uniqueNotes = [...new Set(notes)].sort();
|
|
607
|
+
if (skippedList.length > 0) {
|
|
608
|
+
lines.push("//", "// Not in this file, because Drizzle has no way to say it:");
|
|
609
|
+
for (const s of skippedList)
|
|
610
|
+
lines.push(`// ${s.kind}: ${s.names.join(", ")} (${s.reason})`);
|
|
611
|
+
}
|
|
612
|
+
if (uniqueNotes.length > 0) {
|
|
613
|
+
lines.push("//", "// In this file, with a part left out:");
|
|
614
|
+
for (const n of uniqueNotes)
|
|
615
|
+
lines.push(`// ${n}`);
|
|
616
|
+
}
|
|
617
|
+
lines.push("");
|
|
618
|
+
const coreNames = [...c.used].filter((n) => n !== "unknownColumn" && n !== "sql").sort();
|
|
619
|
+
const imports = [];
|
|
620
|
+
if (coreNames.length > 0)
|
|
621
|
+
imports.push(`import { ${coreNames.join(", ")} } from "drizzle-orm/pg-core";`);
|
|
622
|
+
if (annotated)
|
|
623
|
+
imports.push(`import type { PgTableExtraConfigValue } from "drizzle-orm/pg-core";`);
|
|
624
|
+
if (c.used.has("sql"))
|
|
625
|
+
imports.unshift(`import { sql } from "drizzle-orm";`);
|
|
626
|
+
if (imports.length > 0)
|
|
627
|
+
lines.push(...imports, "");
|
|
628
|
+
const helpers = [];
|
|
629
|
+
if (c.used.has("unknownColumn"))
|
|
630
|
+
helpers.push(`const unknownColumn = customType<{ data: unknown }>({ dataType: () => "unknown" });`);
|
|
631
|
+
for (const [id, v] of [...c.customs].sort(([a], [b]) => (a < b ? -1 : 1))) {
|
|
632
|
+
helpers.push(`const ${id} = customType<{ data: ${v.ts} }>({ dataType: () => ${str(v.dbType)} });`);
|
|
633
|
+
}
|
|
634
|
+
if (helpers.length > 0)
|
|
635
|
+
lines.push("// Column types pg-core has no builder for.", ...helpers, "");
|
|
636
|
+
const schemaDecls = [...schemaIds].sort(([a], [b]) => (a < b ? -1 : 1)).map(([name, id]) => `export const ${id} = pgSchema(${str(name)});`);
|
|
637
|
+
const sections = [schemaDecls, blocks.enums, blocks.sequences, blocks.tables, blocks.views].filter((s) => s.length > 0);
|
|
638
|
+
for (const section of sections)
|
|
639
|
+
lines.push(section.join("\n\n"), "");
|
|
640
|
+
if (sections.length === 0)
|
|
641
|
+
lines.push("export {};", "");
|
|
642
|
+
return { text: `${lines.join("\n").replace(/\n+$/, "")}\n`, skipped: skippedList, approximated: uniqueNotes, counts };
|
|
643
|
+
}
|
|
644
|
+
/** One `index(...)` or `uniqueIndex(...)` call, or undefined (with the index skipped) when Drizzle cannot say it. */
|
|
645
|
+
function indexLine(c, ix, columns, skip, name) {
|
|
646
|
+
if (ix.include || ix.with || ix.tablespace || ix.nullsNotDistinct) {
|
|
647
|
+
skip(ix.type, name, "an index with INCLUDE, WITH, TABLESPACE or NULLS NOT DISTINCT, which Drizzle's index builder has no way to say");
|
|
648
|
+
return undefined;
|
|
649
|
+
}
|
|
650
|
+
const args = [];
|
|
651
|
+
for (const el of ix.elements) {
|
|
652
|
+
const expr = el.expr.trim();
|
|
653
|
+
const nulls = /\s+NULLS\s+(FIRST|LAST)\s*$/i.exec(expr);
|
|
654
|
+
const withoutNulls = expr.replace(/\s+NULLS\s+(?:FIRST|LAST)\s*$/i, "");
|
|
655
|
+
const order = /\s+(ASC|DESC)\s*$/i.exec(withoutNulls);
|
|
656
|
+
const core = withoutNulls.replace(/\s+(?:ASC|DESC)\s*$/i, "").trim();
|
|
657
|
+
if (el.column !== undefined && columns.includes(el.column)) {
|
|
658
|
+
// Anything after the column besides its order (an operator class, COLLATE) is not something Drizzle can say.
|
|
659
|
+
if (core.replace(/^(?:"(?:[^"]|"")+"|[A-Za-z_][\w$]*)/, "").trim() !== "") {
|
|
660
|
+
skip(ix.type, name, "an index element with an operator class or COLLATE, which Drizzle's index builder has no way to say");
|
|
661
|
+
return undefined;
|
|
662
|
+
}
|
|
663
|
+
let a = member("t", el.column);
|
|
664
|
+
if (order)
|
|
665
|
+
a += `.${order[1].toLowerCase()}()`;
|
|
666
|
+
// Postgres sorts NULLs first in a DESC key and last in an ASC one; drizzle-kit writes NULLS LAST unless told.
|
|
667
|
+
const nullsFirst = nulls ? nulls[1].toUpperCase() === "FIRST" : order?.[1].toUpperCase() === "DESC";
|
|
668
|
+
if (nulls || nullsFirst)
|
|
669
|
+
a += nullsFirst ? ".nullsFirst()" : ".nullsLast()";
|
|
670
|
+
args.push(a);
|
|
671
|
+
}
|
|
672
|
+
else {
|
|
673
|
+
args.push(sqlText(c, core));
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
if (args.length === 0)
|
|
677
|
+
return undefined;
|
|
678
|
+
const fn = use(c, ix.unique ? "uniqueIndex" : "index");
|
|
679
|
+
const method = ix.method && ix.method.toLowerCase() !== "btree" ? ix.method.toLowerCase() : undefined;
|
|
680
|
+
let line = `${fn}(${str(ix.name)}).${method ? `using(${str(method)}, ` : "on("}${args.join(", ")})`;
|
|
681
|
+
if (ix.where)
|
|
682
|
+
line += `.where(${sqlText(c, ix.where)})`;
|
|
683
|
+
return line;
|
|
684
|
+
}
|