nextly 0.0.1 → 0.0.2-alpha.0
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/LICENSE +22 -0
- package/README.md +122 -0
- package/dist/_dts-chunks/collections-handler.d-DjgO74Wt.d.ts +20540 -0
- package/dist/_dts-chunks/config.d-DNwsDnjs.d.ts +2589 -0
- package/dist/_dts-chunks/define-component.d-BUgTHmt3.d.ts +1149 -0
- package/dist/_dts-chunks/image-processor.d-OO1PmMrv.d.ts +335 -0
- package/dist/_dts-chunks/index.d-axCAzZ7m.d.ts +17842 -0
- package/dist/_dts-chunks/media.d-DjDOZo4B.d.ts +117 -0
- package/dist/_dts-chunks/on-error.d-CHIKWNxd.d.ts +38 -0
- package/dist/_dts-chunks/storage.d-BUhQ2we_.d.ts +404 -0
- package/dist/actions/index.d.ts +239 -0
- package/dist/actions/index.mjs +281 -0
- package/dist/api/auth-state.d.ts +5 -0
- package/dist/api/auth-state.mjs +131 -0
- package/dist/api/collections-schema-detail.d.ts +56 -0
- package/dist/api/collections-schema-detail.mjs +244 -0
- package/dist/api/collections-schema-export.d.ts +56 -0
- package/dist/api/collections-schema-export.mjs +129 -0
- package/dist/api/collections-schema.d.ts +59 -0
- package/dist/api/collections-schema.mjs +207 -0
- package/dist/api/components-detail.d.ts +50 -0
- package/dist/api/components-detail.mjs +132 -0
- package/dist/api/components.d.ts +69 -0
- package/dist/api/components.mjs +144 -0
- package/dist/api/email-providers-default.d.ts +40 -0
- package/dist/api/email-providers-default.mjs +75 -0
- package/dist/api/email-providers-detail.d.ts +81 -0
- package/dist/api/email-providers-detail.mjs +109 -0
- package/dist/api/email-providers-test.d.ts +43 -0
- package/dist/api/email-providers-test.mjs +114 -0
- package/dist/api/email-providers.d.ts +69 -0
- package/dist/api/email-providers.mjs +110 -0
- package/dist/api/email-send-template.d.ts +41 -0
- package/dist/api/email-send-template.mjs +58 -0
- package/dist/api/email-send.d.ts +42 -0
- package/dist/api/email-send.mjs +58 -0
- package/dist/api/email-templates-detail.d.ts +74 -0
- package/dist/api/email-templates-detail.mjs +112 -0
- package/dist/api/email-templates-layout.d.ts +55 -0
- package/dist/api/email-templates-layout.mjs +92 -0
- package/dist/api/email-templates-preview.d.ts +48 -0
- package/dist/api/email-templates-preview.mjs +93 -0
- package/dist/api/email-templates.d.ts +61 -0
- package/dist/api/email-templates.mjs +118 -0
- package/dist/api/health.d.ts +68 -0
- package/dist/api/health.mjs +67 -0
- package/dist/api/index.d.ts +54 -0
- package/dist/api/index.mjs +16 -0
- package/dist/api/media-bulk.d.ts +74 -0
- package/dist/api/media-bulk.mjs +196 -0
- package/dist/api/media-folders.d.ts +112 -0
- package/dist/api/media-folders.mjs +187 -0
- package/dist/api/media-handlers.d.ts +102 -0
- package/dist/api/media-handlers.mjs +437 -0
- package/dist/api/media.d.ts +117 -0
- package/dist/api/media.mjs +242 -0
- package/dist/api/singles-detail.d.ts +87 -0
- package/dist/api/singles-detail.mjs +170 -0
- package/dist/api/singles-schema-detail.d.ts +54 -0
- package/dist/api/singles-schema-detail.mjs +182 -0
- package/dist/api/singles.d.ts +34 -0
- package/dist/api/singles.mjs +94 -0
- package/dist/api/storage-upload-url.d.ts +48 -0
- package/dist/api/storage-upload-url.mjs +202 -0
- package/dist/api/uploads.d.ts +109 -0
- package/dist/api/uploads.mjs +359 -0
- package/dist/auth/index.d.ts +425 -0
- package/dist/auth/index.mjs +199 -0
- package/dist/boot-apply-PQSYLDIN.mjs +7 -0
- package/dist/chunk-2OALJTK6.mjs +489 -0
- package/dist/chunk-2Q2SX2CS.mjs +365 -0
- package/dist/chunk-2TFX4ND3.mjs +13 -0
- package/dist/chunk-2TWPDSYD.mjs +87 -0
- package/dist/chunk-2W3DVD7S.mjs +647 -0
- package/dist/chunk-2ZFKXPQM.mjs +88 -0
- package/dist/chunk-3FA7FKAV.mjs +832 -0
- package/dist/chunk-3NZ2KMBL.mjs +58 -0
- package/dist/chunk-4MJLT6PZ.mjs +0 -0
- package/dist/chunk-56WO4WX7.mjs +0 -0
- package/dist/chunk-5APFUGAD.mjs +89 -0
- package/dist/chunk-5HMZ644B.mjs +108 -0
- package/dist/chunk-67GXH6PR.mjs +32 -0
- package/dist/chunk-6JNEPWRW.mjs +14368 -0
- package/dist/chunk-6NFHQIJD.mjs +45 -0
- package/dist/chunk-7P6ASYW6.mjs +9 -0
- package/dist/chunk-A3WPLSDT.mjs +1364 -0
- package/dist/chunk-AGJ6F2T3.mjs +144 -0
- package/dist/chunk-AK6Z23OX.mjs +1464 -0
- package/dist/chunk-APKKRD2G.mjs +102 -0
- package/dist/chunk-B2GV2BWH.mjs +73 -0
- package/dist/chunk-D5HQBNUB.mjs +74 -0
- package/dist/chunk-DNNG377Z.mjs +204 -0
- package/dist/chunk-DP3G27G5.mjs +135 -0
- package/dist/chunk-DV6WVX2Q.mjs +0 -0
- package/dist/chunk-DXGGXIUZ.mjs +57 -0
- package/dist/chunk-EGXBZCGC.mjs +943 -0
- package/dist/chunk-ERCNLX3V.mjs +176 -0
- package/dist/chunk-FQULBZ53.mjs +850 -0
- package/dist/chunk-G2AA4QLC.mjs +262 -0
- package/dist/chunk-GDBJ5JCU.mjs +488 -0
- package/dist/chunk-GJNSJU4S.mjs +19 -0
- package/dist/chunk-GZ6DCQKC.mjs +69 -0
- package/dist/chunk-H26B4FYG.mjs +167 -0
- package/dist/chunk-I4JMR3UR.mjs +21 -0
- package/dist/chunk-INV7QKLG.mjs +508 -0
- package/dist/chunk-IUDOC7N7.mjs +46 -0
- package/dist/chunk-IZWPRDC3.mjs +206 -0
- package/dist/chunk-KIMNCZGV.mjs +15 -0
- package/dist/chunk-L6HW2DA7.mjs +15 -0
- package/dist/chunk-LAZXX4HR.mjs +100 -0
- package/dist/chunk-LDKCUMHK.mjs +95 -0
- package/dist/chunk-LRXMECUA.mjs +0 -0
- package/dist/chunk-M52VMPGA.mjs +119 -0
- package/dist/chunk-MGUWEEI6.mjs +160 -0
- package/dist/chunk-NRUWQ5Z7.mjs +419 -0
- package/dist/chunk-NSEFNNU4.mjs +25360 -0
- package/dist/chunk-NTHVDFGO.mjs +138 -0
- package/dist/chunk-O3QHXMOX.mjs +3166 -0
- package/dist/chunk-P7NH2OSC.mjs +2605 -0
- package/dist/chunk-PKMABBB5.mjs +184 -0
- package/dist/chunk-PWS6XGJK.mjs +76 -0
- package/dist/chunk-R6JJQHFC.mjs +20 -0
- package/dist/chunk-RJLLGGPG.mjs +0 -0
- package/dist/chunk-SBACDPNX.mjs +689 -0
- package/dist/chunk-TO5AFLVQ.mjs +124 -0
- package/dist/chunk-TS7GHTG2.mjs +5436 -0
- package/dist/chunk-UJ2IMJ4W.mjs +133 -0
- package/dist/chunk-UOP63Q54.mjs +102 -0
- package/dist/chunk-UUOFWCM6.mjs +78 -0
- package/dist/chunk-V4EQTOA4.mjs +893 -0
- package/dist/chunk-VJ66NCL4.mjs +193 -0
- package/dist/chunk-VQJQHVEV.mjs +29 -0
- package/dist/chunk-VTJADRO3.mjs +141 -0
- package/dist/chunk-VWF3JO32.mjs +0 -0
- package/dist/chunk-W4MGXIRR.mjs +27 -0
- package/dist/chunk-W5KKPZT5.mjs +1204 -0
- package/dist/chunk-WD34YQ6T.mjs +381 -0
- package/dist/chunk-WZBYMYVW.mjs +14 -0
- package/dist/chunk-X23WKS3Z.mjs +50 -0
- package/dist/chunk-X7TXCYYN.mjs +6496 -0
- package/dist/chunk-XGI4EMS3.mjs +140 -0
- package/dist/chunk-XZKLBMN6.mjs +1153 -0
- package/dist/chunk-YB7INWPY.mjs +0 -0
- package/dist/chunk-YV4Y7SDL.mjs +83 -0
- package/dist/chunk-YZNBLFIW.mjs +1688 -0
- package/dist/chunk-YZZCTONM.mjs +263 -0
- package/dist/chunk-ZE6A3FYH.mjs +289 -0
- package/dist/cli/nextly.mjs +68 -0
- package/dist/cli/utils/index.d.ts +449 -0
- package/dist/cli/utils/index.mjs +49 -0
- package/dist/component-schema-service-5577KVW6.mjs +11 -0
- package/dist/config-loader-23YEMC3Z.mjs +23 -0
- package/dist/config.d.ts +44 -0
- package/dist/config.mjs +109 -0
- package/dist/container-ORGFGYSZ.mjs +9 -0
- package/dist/database/index.d.ts +12 -0
- package/dist/database/index.mjs +40 -0
- package/dist/database/seeders/index.d.ts +93 -0
- package/dist/database/seeders/index.mjs +47 -0
- package/dist/db-sync-demote-LJGKLB3S.mjs +117 -0
- package/dist/db-sync-promote-B26VSYQF.mjs +113 -0
- package/dist/dev-reload-broadcaster-B73IQ53V.mjs +25 -0
- package/dist/dist-M2NOU37V.mjs +19 -0
- package/dist/drizzle-kit-lazy-D2M2PXR2.mjs +13 -0
- package/dist/dynamic-collection-schema-service-IEXTPIZ7.mjs +8 -0
- package/dist/errors/index.d.ts +159 -0
- package/dist/errors/index.mjs +10 -0
- package/dist/factory-IWMBKUJM.mjs +15 -0
- package/dist/first-run-QIVKWJIF.mjs +63 -0
- package/dist/fresh-push-NR67DC3R.mjs +8 -0
- package/dist/index.d.ts +4175 -0
- package/dist/index.mjs +1336 -0
- package/dist/local-plugin-PTET4NAT.mjs +7 -0
- package/dist/logger-NU46DXNY.mjs +15 -0
- package/dist/logger-YE4TC7ZN.mjs +9 -0
- package/dist/migration-journal-EP532Y4L.mjs +139 -0
- package/dist/migrations/mysql/0000_eager_sentry.sql +174 -0
- package/dist/migrations/mysql/0001_soft_giant_girl.sql +27 -0
- package/dist/migrations/mysql/0002_media_table.sql +24 -0
- package/dist/migrations/mysql/0003_dynamic_singles.sql +37 -0
- package/dist/migrations/mysql/0004_dynamic_components.sql +35 -0
- package/dist/migrations/mysql/0005_user_management_tables.sql +92 -0
- package/dist/migrations/mysql/0006_api_keys.sql +36 -0
- package/dist/migrations/mysql/0007_general_settings.sql +20 -0
- package/dist/migrations/mysql/0008_site_settings_logo_url.sql +9 -0
- package/dist/migrations/mysql/0009_activity_log.sql +30 -0
- package/dist/migrations/mysql/0010_site_settings_sidebar.sql +13 -0
- package/dist/migrations/mysql/0011_missing_tables_and_columns.sql +54 -0
- package/dist/migrations/mysql/0012_image_sizes_and_focal_point.sql +30 -0
- package/dist/migrations/mysql/0012_media_folders.sql +43 -0
- package/dist/migrations/mysql/0013_user_brute_force_protection.sql +31 -0
- package/dist/migrations/mysql/0014_email_template_attachments.sql +12 -0
- package/dist/migrations/mysql/0015_media_uploaded_by_nullable.sql +15 -0
- package/dist/migrations/mysql/20260429_000000_000_initial_journal.sql +22 -0
- package/dist/migrations/mysql/20260501_000000_journal_batch.sql +17 -0
- package/dist/migrations/mysql/20260501_000001_audit_log.sql +24 -0
- package/dist/migrations/mysql/20260504_000000_nextly_meta.sql +21 -0
- package/dist/migrations/mysql/meta/0000_snapshot.json +1005 -0
- package/dist/migrations/mysql/meta/0001_snapshot.json +1099 -0
- package/dist/migrations/mysql/meta/_journal.json +41 -0
- package/dist/migrations/postgresql/0000_misty_king_bedlam.sql +169 -0
- package/dist/migrations/postgresql/0001_perpetual_captain_marvel.sql +8 -0
- package/dist/migrations/postgresql/0002_sad_spectrum.sql +16 -0
- package/dist/migrations/postgresql/0003_hesitant_ultron.sql +17 -0
- package/dist/migrations/postgresql/0004_media_table.sql +24 -0
- package/dist/migrations/postgresql/0005_media_folders.sql +36 -0
- package/dist/migrations/postgresql/0006_dynamic_collections_update.sql +50 -0
- package/dist/migrations/postgresql/0007_dynamic_singles.sql +38 -0
- package/dist/migrations/postgresql/0008_dynamic_components.sql +37 -0
- package/dist/migrations/postgresql/0009_user_management_tables.sql +95 -0
- package/dist/migrations/postgresql/0010_api_keys.sql +34 -0
- package/dist/migrations/postgresql/0011_general_settings.sql +20 -0
- package/dist/migrations/postgresql/0012_site_settings_logo_url.sql +9 -0
- package/dist/migrations/postgresql/0013_activity_log.sql +29 -0
- package/dist/migrations/postgresql/0014_image_sizes_and_focal_point.sql +33 -0
- package/dist/migrations/postgresql/0014_site_settings_sidebar.sql +13 -0
- package/dist/migrations/postgresql/0015_user_brute_force_protection.sql +29 -0
- package/dist/migrations/postgresql/0016_email_template_attachments.sql +12 -0
- package/dist/migrations/postgresql/0017_media_uploaded_by_nullable.sql +15 -0
- package/dist/migrations/postgresql/20260429_000000_000_initial_journal.sql +24 -0
- package/dist/migrations/postgresql/20260501_000000_journal_batch.sql +17 -0
- package/dist/migrations/postgresql/20260501_000001_audit_log.sql +24 -0
- package/dist/migrations/postgresql/20260504_000000_nextly_meta.sql +22 -0
- package/dist/migrations/postgresql/meta/0000_snapshot.json +1286 -0
- package/dist/migrations/postgresql/meta/0001_snapshot.json +1407 -0
- package/dist/migrations/postgresql/meta/0002_snapshot.json +1552 -0
- package/dist/migrations/postgresql/meta/0003_snapshot.json +1695 -0
- package/dist/migrations/postgresql/meta/0010_snapshot.json +2345 -0
- package/dist/migrations/postgresql/meta/_journal.json +90 -0
- package/dist/migrations/sqlite/0000_api_keys.sql +34 -0
- package/dist/migrations/sqlite/0001_general_settings.sql +20 -0
- package/dist/migrations/sqlite/0002_site_settings_logo_url.sql +9 -0
- package/dist/migrations/sqlite/0003_activity_log.sql +29 -0
- package/dist/migrations/sqlite/0004_image_sizes_and_focal_point.sql +29 -0
- package/dist/migrations/sqlite/0004_site_settings_sidebar.sql +11 -0
- package/dist/migrations/sqlite/0005_user_brute_force_protection.sql +29 -0
- package/dist/migrations/sqlite/0006_email_template_attachments.sql +12 -0
- package/dist/migrations/sqlite/0007_media_uploaded_by_nullable.sql +111 -0
- package/dist/migrations/sqlite/20260429_000000_000_initial_journal.sql +24 -0
- package/dist/migrations/sqlite/20260501_000000_journal_batch.sql +19 -0
- package/dist/migrations/sqlite/20260501_000001_audit_log.sql +24 -0
- package/dist/migrations/sqlite/20260504_000000_nextly_meta.sql +21 -0
- package/dist/migrations/sqlite/20260505_000000_user_management_tables.sql +77 -0
- package/dist/next.d.ts +57 -0
- package/dist/next.mjs +55 -0
- package/dist/observability/index.d.ts +87 -0
- package/dist/observability/index.mjs +57 -0
- package/dist/permissions-3DZZQZMI.mjs +39 -0
- package/dist/pipeline-YOML7SWF.mjs +29 -0
- package/dist/preview-ZZTR3QGS.mjs +9 -0
- package/dist/program-PW6UB2ZC.mjs +5934 -0
- package/dist/reconcile-single-tables-7ENVXJGB.mjs +7 -0
- package/dist/register-SF6E6FVU.mjs +49 -0
- package/dist/reload-config-HWQ4G5MM.mjs +23 -0
- package/dist/resolve-single-table-name-JSOMUB3R.mjs +7 -0
- package/dist/routeHandler-UNMMJIBM.mjs +77 -0
- package/dist/runtime-schema-generator-NRA6A6Z6.mjs +8 -0
- package/dist/runtime.d.ts +120 -0
- package/dist/runtime.mjs +73 -0
- package/dist/schema-hash-FMMG6VPJ.mjs +13 -0
- package/dist/schema-registry-EQ36FZDP.mjs +7 -0
- package/dist/scripts/load-env.mjs +42 -0
- package/dist/storage/index.d.ts +566 -0
- package/dist/storage/index.mjs +45 -0
- package/dist/super-admin-G5ZK5F4T.mjs +39 -0
- package/dist/system-table-service-WGSRVEGT.mjs +17 -0
- package/dist/users-7KELGRYJ.mjs +38 -0
- package/package.json +308 -9
|
@@ -0,0 +1,689 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getColumnDescriptor,
|
|
3
|
+
getSystemColumnDescriptors
|
|
4
|
+
} from "./chunk-DNNG377Z.mjs";
|
|
5
|
+
|
|
6
|
+
// src/domains/schema/pipeline/classifier/count-helpers.ts
|
|
7
|
+
import { sql } from "drizzle-orm";
|
|
8
|
+
var SAFE_IDENT = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
9
|
+
function quoteIdent(name, dialect) {
|
|
10
|
+
if (!SAFE_IDENT.test(name)) {
|
|
11
|
+
throw new Error(
|
|
12
|
+
`unsafe identifier: ${name} (only [A-Za-z_][A-Za-z0-9_]* allowed)`
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
return dialect === "mysql" ? `\`${name}\`` : `"${name}"`;
|
|
16
|
+
}
|
|
17
|
+
function asNumber(raw) {
|
|
18
|
+
if (raw === void 0) return 0;
|
|
19
|
+
return typeof raw === "string" ? parseInt(raw, 10) : raw;
|
|
20
|
+
}
|
|
21
|
+
function extractCount(raw, dialect) {
|
|
22
|
+
if (dialect === "postgresql") {
|
|
23
|
+
const rows = raw.rows;
|
|
24
|
+
if (!Array.isArray(rows) || rows.length === 0) {
|
|
25
|
+
throw new Error("PG count query returned no rows");
|
|
26
|
+
}
|
|
27
|
+
return asNumber(rows[0].count);
|
|
28
|
+
}
|
|
29
|
+
if (dialect === "mysql") {
|
|
30
|
+
if (Array.isArray(raw) && raw.length > 0 && Array.isArray(raw[0])) {
|
|
31
|
+
const rows = raw[0];
|
|
32
|
+
if (rows.length === 0)
|
|
33
|
+
throw new Error("MySQL count query returned no rows");
|
|
34
|
+
return asNumber(rows[0].count);
|
|
35
|
+
}
|
|
36
|
+
if (Array.isArray(raw)) {
|
|
37
|
+
const rows = raw;
|
|
38
|
+
if (rows.length === 0)
|
|
39
|
+
throw new Error("MySQL count query returned no rows");
|
|
40
|
+
return asNumber(rows[0].count);
|
|
41
|
+
}
|
|
42
|
+
throw new Error("MySQL count query returned unrecognized shape");
|
|
43
|
+
}
|
|
44
|
+
throw new Error(`unrecognized dialect for extractCount: ${dialect}`);
|
|
45
|
+
}
|
|
46
|
+
async function countNulls(db, dialect, table, column) {
|
|
47
|
+
const tbl = quoteIdent(table, dialect);
|
|
48
|
+
const col = quoteIdent(column, dialect);
|
|
49
|
+
const query = sql.raw(
|
|
50
|
+
`SELECT COUNT(*) AS count FROM ${tbl} WHERE ${col} IS NULL`
|
|
51
|
+
);
|
|
52
|
+
if (dialect === "sqlite") {
|
|
53
|
+
const dbTyped2 = db;
|
|
54
|
+
const rows = dbTyped2.all(query);
|
|
55
|
+
if (rows.length === 0)
|
|
56
|
+
throw new Error("SQLite count query returned no rows");
|
|
57
|
+
return asNumber(rows[0].count);
|
|
58
|
+
}
|
|
59
|
+
const dbTyped = db;
|
|
60
|
+
const result = await dbTyped.execute(query);
|
|
61
|
+
return extractCount(result, dialect);
|
|
62
|
+
}
|
|
63
|
+
async function countRows(db, dialect, table) {
|
|
64
|
+
const tbl = quoteIdent(table, dialect);
|
|
65
|
+
const query = sql.raw(`SELECT COUNT(*) AS count FROM ${tbl}`);
|
|
66
|
+
if (dialect === "sqlite") {
|
|
67
|
+
const dbTyped2 = db;
|
|
68
|
+
const rows = dbTyped2.all(query);
|
|
69
|
+
if (rows.length === 0)
|
|
70
|
+
throw new Error("SQLite count query returned no rows");
|
|
71
|
+
return asNumber(rows[0].count);
|
|
72
|
+
}
|
|
73
|
+
const dbTyped = db;
|
|
74
|
+
const result = await dbTyped.execute(query);
|
|
75
|
+
return extractCount(result, dialect);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// src/domains/schema/pipeline/resolution/types.ts
|
|
79
|
+
function formatEventId(kind, table, column) {
|
|
80
|
+
return `${kind}:${table}.${column}`;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// src/domains/schema/pipeline/classifier/type-warnings.ts
|
|
84
|
+
function buildPerDialectWarning(fromType, toType) {
|
|
85
|
+
const change = `${fromType} -> ${toType}`;
|
|
86
|
+
return {
|
|
87
|
+
pg: `Postgres: ${change} will fail if any value cannot be cast to ${toType}. Failed apply rolls back the entire transaction.`,
|
|
88
|
+
mysql: `MySQL: ${change} silently coerces non-conforming values (numeric -> 0, invalid date -> 0000-00-00, truncated strings). No error raised.`,
|
|
89
|
+
sqlite: `SQLite: ${change} uses storage-class affinity \u2014 values that don't match the new affinity are silently coerced (e.g. text "abc" stored as "abc" in an integer column, "42" stored as 42). No error raised.`
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// src/domains/schema/pipeline/classifier/type-widening.ts
|
|
94
|
+
var VARCHAR_RE = /^varchar\((\d+)\)$/i;
|
|
95
|
+
var CHAR_RE = /^char\((\d+)\)$/i;
|
|
96
|
+
var PG_INT_RANK = {
|
|
97
|
+
smallint: 1,
|
|
98
|
+
int2: 1,
|
|
99
|
+
int: 2,
|
|
100
|
+
integer: 2,
|
|
101
|
+
int4: 2,
|
|
102
|
+
bigint: 3,
|
|
103
|
+
int8: 3
|
|
104
|
+
};
|
|
105
|
+
var MYSQL_INT_RANK = {
|
|
106
|
+
tinyint: 1,
|
|
107
|
+
smallint: 2,
|
|
108
|
+
mediumint: 3,
|
|
109
|
+
int: 4,
|
|
110
|
+
integer: 4,
|
|
111
|
+
bigint: 5
|
|
112
|
+
};
|
|
113
|
+
var MYSQL_TEXT_RANK = {
|
|
114
|
+
tinytext: 1,
|
|
115
|
+
text: 2,
|
|
116
|
+
mediumtext: 3,
|
|
117
|
+
longtext: 4
|
|
118
|
+
};
|
|
119
|
+
function widensVarchar(from, to) {
|
|
120
|
+
const fm = VARCHAR_RE.exec(from);
|
|
121
|
+
const tm = VARCHAR_RE.exec(to);
|
|
122
|
+
if (fm && tm) return parseInt(tm[1], 10) >= parseInt(fm[1], 10);
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
function isWideningChange(fromType, toType, dialect) {
|
|
126
|
+
const from = fromType.toLowerCase().trim();
|
|
127
|
+
const to = toType.toLowerCase().trim();
|
|
128
|
+
if (from === to) return true;
|
|
129
|
+
if (dialect === "sqlite") return false;
|
|
130
|
+
const vw = widensVarchar(from, to);
|
|
131
|
+
if (vw !== null) return vw;
|
|
132
|
+
const fromIsCharFamily = CHAR_RE.test(from) || from === "bpchar";
|
|
133
|
+
if (fromIsCharFamily && (to === "varchar" || VARCHAR_RE.test(to))) {
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
136
|
+
if (dialect === "postgresql" && from === "bpchar" && to === "text") {
|
|
137
|
+
return true;
|
|
138
|
+
}
|
|
139
|
+
if (dialect === "postgresql" && (from === "varchar" || VARCHAR_RE.test(from)) && to === "text") {
|
|
140
|
+
return true;
|
|
141
|
+
}
|
|
142
|
+
if (dialect === "mysql" && VARCHAR_RE.test(from) && MYSQL_TEXT_RANK[to] !== void 0) {
|
|
143
|
+
return true;
|
|
144
|
+
}
|
|
145
|
+
const intRank = dialect === "postgresql" ? PG_INT_RANK : MYSQL_INT_RANK;
|
|
146
|
+
if (intRank[from] !== void 0 && intRank[to] !== void 0) {
|
|
147
|
+
return intRank[to] >= intRank[from];
|
|
148
|
+
}
|
|
149
|
+
if (dialect === "mysql" && MYSQL_TEXT_RANK[from] !== void 0 && MYSQL_TEXT_RANK[to] !== void 0) {
|
|
150
|
+
return MYSQL_TEXT_RANK[to] >= MYSQL_TEXT_RANK[from];
|
|
151
|
+
}
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// src/domains/schema/pipeline/classifier/classifier.ts
|
|
156
|
+
var RealClassifier = class {
|
|
157
|
+
async classify(args) {
|
|
158
|
+
const events = [];
|
|
159
|
+
for (const op of args.operations) {
|
|
160
|
+
if (op.type === "change_column_nullable" && op.fromNullable === true && op.toNullable === false) {
|
|
161
|
+
const nullCount = await args.countNulls(op.tableName, op.columnName);
|
|
162
|
+
if (nullCount > 0) {
|
|
163
|
+
const tableRowCount = await args.countRows(op.tableName);
|
|
164
|
+
events.push({
|
|
165
|
+
id: formatEventId(
|
|
166
|
+
"add_not_null_with_nulls",
|
|
167
|
+
op.tableName,
|
|
168
|
+
op.columnName
|
|
169
|
+
),
|
|
170
|
+
kind: "add_not_null_with_nulls",
|
|
171
|
+
tableName: op.tableName,
|
|
172
|
+
columnName: op.columnName,
|
|
173
|
+
nullCount,
|
|
174
|
+
tableRowCount,
|
|
175
|
+
applicableResolutions: [
|
|
176
|
+
"provide_default",
|
|
177
|
+
"make_optional",
|
|
178
|
+
"delete_nonconforming",
|
|
179
|
+
"abort"
|
|
180
|
+
]
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
} else if (op.type === "change_column_type") {
|
|
184
|
+
const widening = isWideningChange(op.fromType, op.toType, args.dialect);
|
|
185
|
+
if (!widening) {
|
|
186
|
+
events.push({
|
|
187
|
+
id: formatEventId("type_change", op.tableName, op.columnName),
|
|
188
|
+
kind: "type_change",
|
|
189
|
+
tableName: op.tableName,
|
|
190
|
+
columnName: op.columnName,
|
|
191
|
+
fromType: op.fromType,
|
|
192
|
+
toType: op.toType,
|
|
193
|
+
isWidening: false,
|
|
194
|
+
perDialectWarning: buildPerDialectWarning(op.fromType, op.toType)
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
} else if (op.type === "add_column" && op.column.nullable === false && op.column.default === void 0) {
|
|
198
|
+
const tableRowCount = await args.countRows(op.tableName);
|
|
199
|
+
if (tableRowCount > 0) {
|
|
200
|
+
events.push({
|
|
201
|
+
id: formatEventId(
|
|
202
|
+
"add_required_field_no_default",
|
|
203
|
+
op.tableName,
|
|
204
|
+
op.column.name
|
|
205
|
+
),
|
|
206
|
+
kind: "add_required_field_no_default",
|
|
207
|
+
tableName: op.tableName,
|
|
208
|
+
columnName: op.column.name,
|
|
209
|
+
tableRowCount,
|
|
210
|
+
applicableResolutions: [
|
|
211
|
+
"provide_default",
|
|
212
|
+
"make_optional",
|
|
213
|
+
"abort"
|
|
214
|
+
]
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
const hasInteractive = events.some((e) => e.kind !== "type_change");
|
|
220
|
+
const level = hasInteractive ? "interactive" : events.length > 0 ? "destructive" : "safe";
|
|
221
|
+
return { level, events };
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
// src/domains/schema/pipeline/diff/build-from-fields.ts
|
|
226
|
+
function buildDesiredTableFromFields(tableName, fields, dialect, options = {}) {
|
|
227
|
+
const columns = [];
|
|
228
|
+
const hasTitleField = fields.some((f) => f.name === "title");
|
|
229
|
+
const hasSlugField = fields.some((f) => f.name === "slug");
|
|
230
|
+
for (const reserved of getSystemColumnDescriptors(dialect, {
|
|
231
|
+
hasTitleField,
|
|
232
|
+
hasSlugField,
|
|
233
|
+
hasStatus: options.hasStatus
|
|
234
|
+
})) {
|
|
235
|
+
columns.push({
|
|
236
|
+
name: reserved.name,
|
|
237
|
+
type: reserved.dialectType,
|
|
238
|
+
nullable: reserved.nullable,
|
|
239
|
+
default: void 0
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
for (const field of fields) {
|
|
243
|
+
const desc = getColumnDescriptor(
|
|
244
|
+
// The descriptor's input type is FieldDefinition; this util is
|
|
245
|
+
// structurally compatible (same name/type/required/hasMany/relationTo
|
|
246
|
+
// keys). Cast through unknown to bridge the two surface types
|
|
247
|
+
// without leaking either back through the module graph.
|
|
248
|
+
field,
|
|
249
|
+
dialect
|
|
250
|
+
);
|
|
251
|
+
if (!desc) continue;
|
|
252
|
+
columns.push({
|
|
253
|
+
name: desc.name,
|
|
254
|
+
type: desc.dialectType,
|
|
255
|
+
nullable: desc.nullable,
|
|
256
|
+
default: void 0
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
return { name: tableName, columns };
|
|
260
|
+
}
|
|
261
|
+
function buildDesiredTableFromComponentFields(tableName, fields, dialect) {
|
|
262
|
+
const columns = [];
|
|
263
|
+
if (dialect === "postgresql") {
|
|
264
|
+
columns.push({ name: "id", type: "text", nullable: false, default: void 0 });
|
|
265
|
+
columns.push({ name: "_parent_id", type: "text", nullable: false, default: void 0 });
|
|
266
|
+
columns.push({ name: "_parent_table", type: "varchar", nullable: false, default: void 0 });
|
|
267
|
+
columns.push({ name: "_parent_field", type: "varchar", nullable: false, default: void 0 });
|
|
268
|
+
columns.push({ name: "_order", type: "int4", nullable: true, default: void 0 });
|
|
269
|
+
columns.push({ name: "_component_type", type: "varchar", nullable: true, default: void 0 });
|
|
270
|
+
} else if (dialect === "mysql") {
|
|
271
|
+
columns.push({ name: "id", type: "varchar(36)", nullable: false, default: void 0 });
|
|
272
|
+
columns.push({ name: "_parent_id", type: "varchar(36)", nullable: false, default: void 0 });
|
|
273
|
+
columns.push({ name: "_parent_table", type: "varchar(255)", nullable: false, default: void 0 });
|
|
274
|
+
columns.push({ name: "_parent_field", type: "varchar(255)", nullable: false, default: void 0 });
|
|
275
|
+
columns.push({ name: "_order", type: "int(11)", nullable: true, default: void 0 });
|
|
276
|
+
columns.push({ name: "_component_type", type: "varchar(255)", nullable: true, default: void 0 });
|
|
277
|
+
} else {
|
|
278
|
+
columns.push({ name: "id", type: "text", nullable: false, default: void 0 });
|
|
279
|
+
columns.push({ name: "_parent_id", type: "text", nullable: false, default: void 0 });
|
|
280
|
+
columns.push({ name: "_parent_table", type: "text", nullable: false, default: void 0 });
|
|
281
|
+
columns.push({ name: "_parent_field", type: "text", nullable: false, default: void 0 });
|
|
282
|
+
columns.push({ name: "_order", type: "integer", nullable: true, default: void 0 });
|
|
283
|
+
columns.push({ name: "_component_type", type: "text", nullable: true, default: void 0 });
|
|
284
|
+
}
|
|
285
|
+
for (const field of fields) {
|
|
286
|
+
const desc = getColumnDescriptor(
|
|
287
|
+
field,
|
|
288
|
+
dialect
|
|
289
|
+
);
|
|
290
|
+
if (!desc) continue;
|
|
291
|
+
columns.push({
|
|
292
|
+
name: desc.name,
|
|
293
|
+
type: desc.dialectType,
|
|
294
|
+
nullable: desc.nullable,
|
|
295
|
+
default: void 0
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
if (dialect === "postgresql") {
|
|
299
|
+
columns.push({ name: "created_at", type: "timestamp", nullable: false, default: void 0 });
|
|
300
|
+
columns.push({ name: "updated_at", type: "timestamp", nullable: false, default: void 0 });
|
|
301
|
+
} else if (dialect === "mysql") {
|
|
302
|
+
columns.push({ name: "created_at", type: "datetime", nullable: false, default: void 0 });
|
|
303
|
+
columns.push({ name: "updated_at", type: "datetime", nullable: false, default: void 0 });
|
|
304
|
+
} else {
|
|
305
|
+
columns.push({ name: "created_at", type: "integer", nullable: false, default: void 0 });
|
|
306
|
+
columns.push({ name: "updated_at", type: "integer", nullable: false, default: void 0 });
|
|
307
|
+
}
|
|
308
|
+
return { name: tableName, columns };
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// src/domains/schema/pipeline/diff/diff.ts
|
|
312
|
+
function diffSnapshots(prev, cur) {
|
|
313
|
+
const prevByName = /* @__PURE__ */ new Map();
|
|
314
|
+
for (const t of prev.tables) prevByName.set(t.name, t);
|
|
315
|
+
const curByName = /* @__PURE__ */ new Map();
|
|
316
|
+
for (const t of cur.tables) curByName.set(t.name, t);
|
|
317
|
+
const tableOps = [];
|
|
318
|
+
const columnOps = [];
|
|
319
|
+
const allTableNames = [
|
|
320
|
+
.../* @__PURE__ */ new Set([...prevByName.keys(), ...curByName.keys()])
|
|
321
|
+
].sort();
|
|
322
|
+
for (const name of allTableNames) {
|
|
323
|
+
const prevT = prevByName.get(name);
|
|
324
|
+
const curT = curByName.get(name);
|
|
325
|
+
if (!prevT && curT) {
|
|
326
|
+
tableOps.push({ type: "add_table", table: curT });
|
|
327
|
+
continue;
|
|
328
|
+
}
|
|
329
|
+
if (prevT && !curT) {
|
|
330
|
+
tableOps.push({
|
|
331
|
+
type: "drop_table",
|
|
332
|
+
tableName: name
|
|
333
|
+
});
|
|
334
|
+
continue;
|
|
335
|
+
}
|
|
336
|
+
if (prevT && curT) {
|
|
337
|
+
columnOps.push(...diffColumns(name, prevT.columns, curT.columns));
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
return [...tableOps, ...columnOps];
|
|
341
|
+
}
|
|
342
|
+
function diffColumns(tableName, prev, cur) {
|
|
343
|
+
const prevByName = /* @__PURE__ */ new Map();
|
|
344
|
+
for (const c of prev) prevByName.set(c.name, c);
|
|
345
|
+
const curByName = /* @__PURE__ */ new Map();
|
|
346
|
+
for (const c of cur) curByName.set(c.name, c);
|
|
347
|
+
const drops = [];
|
|
348
|
+
const adds = [];
|
|
349
|
+
const typeChanges = [];
|
|
350
|
+
const nullableChanges = [];
|
|
351
|
+
const defaultChanges = [];
|
|
352
|
+
const allColumnNames = [
|
|
353
|
+
.../* @__PURE__ */ new Set([...prevByName.keys(), ...curByName.keys()])
|
|
354
|
+
].sort();
|
|
355
|
+
for (const name of allColumnNames) {
|
|
356
|
+
const prevC = prevByName.get(name);
|
|
357
|
+
const curC = curByName.get(name);
|
|
358
|
+
if (!prevC && curC) {
|
|
359
|
+
adds.push({ type: "add_column", tableName, column: curC });
|
|
360
|
+
continue;
|
|
361
|
+
}
|
|
362
|
+
if (prevC && !curC) {
|
|
363
|
+
drops.push({
|
|
364
|
+
type: "drop_column",
|
|
365
|
+
tableName,
|
|
366
|
+
columnName: name,
|
|
367
|
+
columnType: prevC.type
|
|
368
|
+
});
|
|
369
|
+
continue;
|
|
370
|
+
}
|
|
371
|
+
if (prevC && curC) {
|
|
372
|
+
if (prevC.type !== curC.type) {
|
|
373
|
+
typeChanges.push({
|
|
374
|
+
type: "change_column_type",
|
|
375
|
+
tableName,
|
|
376
|
+
columnName: name,
|
|
377
|
+
fromType: prevC.type,
|
|
378
|
+
toType: curC.type
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
if (prevC.nullable !== curC.nullable) {
|
|
382
|
+
nullableChanges.push({
|
|
383
|
+
type: "change_column_nullable",
|
|
384
|
+
tableName,
|
|
385
|
+
columnName: name,
|
|
386
|
+
fromNullable: prevC.nullable,
|
|
387
|
+
toNullable: curC.nullable
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
if (prevC.default !== curC.default) {
|
|
391
|
+
defaultChanges.push({
|
|
392
|
+
type: "change_column_default",
|
|
393
|
+
tableName,
|
|
394
|
+
columnName: name,
|
|
395
|
+
fromDefault: prevC.default,
|
|
396
|
+
toDefault: curC.default
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
return [
|
|
402
|
+
...drops,
|
|
403
|
+
...adds,
|
|
404
|
+
...typeChanges,
|
|
405
|
+
...nullableChanges,
|
|
406
|
+
...defaultChanges
|
|
407
|
+
];
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// src/domains/schema/pipeline/diff/introspect-live.ts
|
|
411
|
+
import { sql as sql2 } from "drizzle-orm";
|
|
412
|
+
async function introspectLiveSnapshot(db, dialect, tableNames) {
|
|
413
|
+
if (tableNames.length === 0) return { tables: [] };
|
|
414
|
+
const tableNamesIn = sql2.join(
|
|
415
|
+
tableNames.map((t) => sql2`${t}`),
|
|
416
|
+
sql2`, `
|
|
417
|
+
);
|
|
418
|
+
if (dialect === "postgresql") {
|
|
419
|
+
const dbTyped2 = db;
|
|
420
|
+
const result = await dbTyped2.execute(
|
|
421
|
+
sql2`SELECT table_name, column_name, udt_name, is_nullable, column_default
|
|
422
|
+
FROM information_schema.columns
|
|
423
|
+
WHERE table_schema = 'public'
|
|
424
|
+
AND table_name IN (${tableNamesIn})
|
|
425
|
+
ORDER BY table_name, ordinal_position`
|
|
426
|
+
);
|
|
427
|
+
return buildSnapshotFromPgRows(result.rows);
|
|
428
|
+
}
|
|
429
|
+
if (dialect === "mysql") {
|
|
430
|
+
const dbTyped2 = db;
|
|
431
|
+
const result = await dbTyped2.execute(
|
|
432
|
+
sql2`SELECT TABLE_NAME, COLUMN_NAME, COLUMN_TYPE, IS_NULLABLE, COLUMN_DEFAULT
|
|
433
|
+
FROM information_schema.columns
|
|
434
|
+
WHERE TABLE_SCHEMA = DATABASE()
|
|
435
|
+
AND TABLE_NAME IN (${tableNamesIn})
|
|
436
|
+
ORDER BY TABLE_NAME, ORDINAL_POSITION`
|
|
437
|
+
);
|
|
438
|
+
const rows = Array.isArray(result) && result.length > 0 && Array.isArray(result[0]) ? result[0] : result;
|
|
439
|
+
return buildSnapshotFromMysqlRows(rows);
|
|
440
|
+
}
|
|
441
|
+
const dbTyped = db;
|
|
442
|
+
const tables = [];
|
|
443
|
+
for (const table of tableNames) {
|
|
444
|
+
const rows = await dbTyped.all(
|
|
445
|
+
sql2`PRAGMA table_info(${sql2.identifier(table)})`
|
|
446
|
+
);
|
|
447
|
+
if (rows.length === 0) continue;
|
|
448
|
+
tables.push({
|
|
449
|
+
name: table,
|
|
450
|
+
columns: rows.map(
|
|
451
|
+
(r) => ({
|
|
452
|
+
name: r.name,
|
|
453
|
+
// SQLite's PRAGMA table_info auto-uppercases the type name
|
|
454
|
+
// ("text" becomes "TEXT"), even though Drizzle emits lowercase
|
|
455
|
+
// declarations in CREATE TABLE. The
|
|
456
|
+
// `field-column-descriptor` (the desired-side source of
|
|
457
|
+
// truth) renders lowercase tokens to match drizzle-orm's
|
|
458
|
+
// own introspection convention. Without this lowercase
|
|
459
|
+
// pass, every boot/HMR diff sees fake `TEXT -> text`
|
|
460
|
+
// type-change events on every column and classifies the
|
|
461
|
+
// collection as "needs review", which silently blocks
|
|
462
|
+
// legitimate code-first applies (rename, add, drop) from
|
|
463
|
+
// ever running. Lowercasing here is safe because SQLite
|
|
464
|
+
// type names are case-insensitive at the engine level.
|
|
465
|
+
type: r.type.toLowerCase(),
|
|
466
|
+
// SQLite stores notnull as 0/1 integer.
|
|
467
|
+
nullable: r.notnull === 0,
|
|
468
|
+
// dflt_value can be string, number, null, or undefined.
|
|
469
|
+
// Coerce primitives to string; treat anything non-primitive as
|
|
470
|
+
// missing (defensive - SQLite never returns object defaults).
|
|
471
|
+
default: stringifyDefault(r.dflt_value)
|
|
472
|
+
})
|
|
473
|
+
)
|
|
474
|
+
});
|
|
475
|
+
}
|
|
476
|
+
return { tables };
|
|
477
|
+
}
|
|
478
|
+
function stringifyDefault(value) {
|
|
479
|
+
if (value === null || value === void 0) return void 0;
|
|
480
|
+
if (typeof value === "string") return value;
|
|
481
|
+
if (typeof value === "number") return value.toString();
|
|
482
|
+
if (typeof value === "boolean") return value ? "true" : "false";
|
|
483
|
+
if (typeof value === "bigint") return value.toString();
|
|
484
|
+
return void 0;
|
|
485
|
+
}
|
|
486
|
+
function buildSnapshotFromPgRows(rows) {
|
|
487
|
+
const byTable = /* @__PURE__ */ new Map();
|
|
488
|
+
for (const r of rows) {
|
|
489
|
+
let cols = byTable.get(r.table_name);
|
|
490
|
+
if (!cols) {
|
|
491
|
+
cols = [];
|
|
492
|
+
byTable.set(r.table_name, cols);
|
|
493
|
+
}
|
|
494
|
+
cols.push({
|
|
495
|
+
name: r.column_name,
|
|
496
|
+
type: r.udt_name,
|
|
497
|
+
nullable: r.is_nullable === "YES",
|
|
498
|
+
default: r.column_default ?? void 0
|
|
499
|
+
});
|
|
500
|
+
}
|
|
501
|
+
return {
|
|
502
|
+
tables: [...byTable.entries()].map(
|
|
503
|
+
([name, columns]) => ({ name, columns })
|
|
504
|
+
)
|
|
505
|
+
};
|
|
506
|
+
}
|
|
507
|
+
function buildSnapshotFromMysqlRows(rows) {
|
|
508
|
+
const byTable = /* @__PURE__ */ new Map();
|
|
509
|
+
for (const r of rows) {
|
|
510
|
+
let cols = byTable.get(r.TABLE_NAME);
|
|
511
|
+
if (!cols) {
|
|
512
|
+
cols = [];
|
|
513
|
+
byTable.set(r.TABLE_NAME, cols);
|
|
514
|
+
}
|
|
515
|
+
cols.push({
|
|
516
|
+
name: r.COLUMN_NAME,
|
|
517
|
+
type: r.COLUMN_TYPE,
|
|
518
|
+
nullable: r.IS_NULLABLE === "YES",
|
|
519
|
+
default: r.COLUMN_DEFAULT ?? void 0
|
|
520
|
+
});
|
|
521
|
+
}
|
|
522
|
+
return {
|
|
523
|
+
tables: [...byTable.entries()].map(
|
|
524
|
+
([name, columns]) => ({ name, columns })
|
|
525
|
+
)
|
|
526
|
+
};
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
// src/domains/schema/pipeline/rename-detector-type-families.ts
|
|
530
|
+
var PG_FAMILIES = {
|
|
531
|
+
// bpchar is what PG's information_schema.columns.udt_name returns for
|
|
532
|
+
// char(N) columns (blank-padded char). Without it here, a legitimate
|
|
533
|
+
// char(N) -> text rename would default to drop_and_add.
|
|
534
|
+
text: ["text", "varchar", "char", "bpchar", "character", "character varying"],
|
|
535
|
+
integer: [
|
|
536
|
+
"smallint",
|
|
537
|
+
"integer",
|
|
538
|
+
"int",
|
|
539
|
+
"int2",
|
|
540
|
+
"int4",
|
|
541
|
+
"int8",
|
|
542
|
+
"bigint",
|
|
543
|
+
"serial",
|
|
544
|
+
"bigserial",
|
|
545
|
+
"smallserial"
|
|
546
|
+
],
|
|
547
|
+
decimal: [
|
|
548
|
+
"decimal",
|
|
549
|
+
"numeric",
|
|
550
|
+
"real",
|
|
551
|
+
"double precision",
|
|
552
|
+
"double",
|
|
553
|
+
"float"
|
|
554
|
+
],
|
|
555
|
+
boolean: ["boolean", "bool"],
|
|
556
|
+
uuid: ["uuid"],
|
|
557
|
+
json: ["json", "jsonb"],
|
|
558
|
+
date_only: ["date"],
|
|
559
|
+
time_only: [
|
|
560
|
+
"time",
|
|
561
|
+
"timetz",
|
|
562
|
+
"time with time zone",
|
|
563
|
+
"time without time zone"
|
|
564
|
+
],
|
|
565
|
+
timestamp: [
|
|
566
|
+
"timestamp",
|
|
567
|
+
"timestamptz",
|
|
568
|
+
"timestamp with time zone",
|
|
569
|
+
"timestamp without time zone"
|
|
570
|
+
],
|
|
571
|
+
binary: ["bytea"]
|
|
572
|
+
};
|
|
573
|
+
var MYSQL_FAMILIES = {
|
|
574
|
+
text: ["text", "varchar", "char", "tinytext", "mediumtext", "longtext"],
|
|
575
|
+
integer: ["tinyint", "smallint", "mediumint", "int", "integer", "bigint"],
|
|
576
|
+
decimal: ["decimal", "numeric", "float", "double", "real"],
|
|
577
|
+
boolean: ["boolean", "bool"],
|
|
578
|
+
uuid: [],
|
|
579
|
+
json: ["json"],
|
|
580
|
+
date_only: ["date"],
|
|
581
|
+
time_only: ["time"],
|
|
582
|
+
timestamp: ["timestamp", "datetime"],
|
|
583
|
+
binary: ["binary", "varbinary", "tinyblob", "blob", "mediumblob", "longblob"]
|
|
584
|
+
};
|
|
585
|
+
var SQLITE_FAMILIES = {
|
|
586
|
+
text: ["text", "varchar", "char", "character"],
|
|
587
|
+
integer: ["integer", "int", "tinyint", "smallint", "mediumint", "bigint"],
|
|
588
|
+
decimal: ["real", "double", "decimal", "numeric", "float"],
|
|
589
|
+
boolean: ["boolean", "bool"],
|
|
590
|
+
uuid: [],
|
|
591
|
+
json: [],
|
|
592
|
+
date_only: [],
|
|
593
|
+
time_only: [],
|
|
594
|
+
timestamp: [],
|
|
595
|
+
binary: ["blob"]
|
|
596
|
+
};
|
|
597
|
+
var FAMILY_TABLES = {
|
|
598
|
+
postgresql: PG_FAMILIES,
|
|
599
|
+
mysql: MYSQL_FAMILIES,
|
|
600
|
+
sqlite: SQLITE_FAMILIES
|
|
601
|
+
};
|
|
602
|
+
function leadingToken(rawType) {
|
|
603
|
+
const trimmed = rawType.trim().toLowerCase();
|
|
604
|
+
if (trimmed.length === 0) return null;
|
|
605
|
+
const parenIdx = trimmed.indexOf("(");
|
|
606
|
+
const modifierMatch = trimmed.match(
|
|
607
|
+
/\s(?:not|null|default|references|primary|unique|collate|check)\b/
|
|
608
|
+
);
|
|
609
|
+
const modifierIdx = modifierMatch?.index ?? -1;
|
|
610
|
+
let endIdx = trimmed.length;
|
|
611
|
+
if (parenIdx >= 0) endIdx = Math.min(endIdx, parenIdx);
|
|
612
|
+
if (modifierIdx >= 0) endIdx = Math.min(endIdx, modifierIdx);
|
|
613
|
+
return trimmed.slice(0, endIdx).trim();
|
|
614
|
+
}
|
|
615
|
+
function typeFamilyOf(rawType, dialect) {
|
|
616
|
+
const token = leadingToken(rawType);
|
|
617
|
+
if (!token) return null;
|
|
618
|
+
const table = FAMILY_TABLES[dialect];
|
|
619
|
+
for (const family of Object.keys(table)) {
|
|
620
|
+
if (table[family].includes(token)) return family;
|
|
621
|
+
}
|
|
622
|
+
return null;
|
|
623
|
+
}
|
|
624
|
+
function isTypesCompatible(fromType, toType, dialect) {
|
|
625
|
+
const fromFamily = typeFamilyOf(fromType, dialect);
|
|
626
|
+
const toFamily = typeFamilyOf(toType, dialect);
|
|
627
|
+
if (fromFamily === null || toFamily === null) return false;
|
|
628
|
+
return fromFamily === toFamily;
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
// src/domains/schema/pipeline/rename-detector.ts
|
|
632
|
+
var RegexRenameDetector = class {
|
|
633
|
+
detect(operations, dialect) {
|
|
634
|
+
const dropsByTable = /* @__PURE__ */ new Map();
|
|
635
|
+
const addsByTable = /* @__PURE__ */ new Map();
|
|
636
|
+
for (const op of operations) {
|
|
637
|
+
if (op.type === "drop_column") {
|
|
638
|
+
const list = dropsByTable.get(op.tableName) ?? [];
|
|
639
|
+
list.push(op);
|
|
640
|
+
dropsByTable.set(op.tableName, list);
|
|
641
|
+
} else if (op.type === "add_column") {
|
|
642
|
+
const list = addsByTable.get(op.tableName) ?? [];
|
|
643
|
+
list.push(op);
|
|
644
|
+
addsByTable.set(op.tableName, list);
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
const candidates = [];
|
|
648
|
+
for (const [tableName, drops] of dropsByTable) {
|
|
649
|
+
const adds = addsByTable.get(tableName);
|
|
650
|
+
if (!adds || adds.length === 0) continue;
|
|
651
|
+
for (const drop of drops) {
|
|
652
|
+
for (const add of adds) {
|
|
653
|
+
const fromType = drop.columnType;
|
|
654
|
+
const toType = add.column.type;
|
|
655
|
+
const compatible = fromType === "" ? false : isTypesCompatible(fromType, toType, dialect);
|
|
656
|
+
candidates.push({
|
|
657
|
+
tableName,
|
|
658
|
+
fromColumn: drop.columnName,
|
|
659
|
+
toColumn: add.column.name,
|
|
660
|
+
fromType,
|
|
661
|
+
toType,
|
|
662
|
+
typesCompatible: compatible,
|
|
663
|
+
defaultSuggestion: compatible ? "rename" : "drop_and_add"
|
|
664
|
+
});
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
candidates.sort((a, b) => {
|
|
669
|
+
if (a.tableName !== b.tableName)
|
|
670
|
+
return a.tableName < b.tableName ? -1 : 1;
|
|
671
|
+
if (a.fromColumn !== b.fromColumn)
|
|
672
|
+
return a.fromColumn < b.fromColumn ? -1 : 1;
|
|
673
|
+
if (a.toColumn !== b.toColumn) return a.toColumn < b.toColumn ? -1 : 1;
|
|
674
|
+
return 0;
|
|
675
|
+
});
|
|
676
|
+
return candidates;
|
|
677
|
+
}
|
|
678
|
+
};
|
|
679
|
+
|
|
680
|
+
export {
|
|
681
|
+
countNulls,
|
|
682
|
+
countRows,
|
|
683
|
+
RealClassifier,
|
|
684
|
+
buildDesiredTableFromFields,
|
|
685
|
+
buildDesiredTableFromComponentFields,
|
|
686
|
+
diffSnapshots,
|
|
687
|
+
introspectLiveSnapshot,
|
|
688
|
+
RegexRenameDetector
|
|
689
|
+
};
|