@schemalens/cli 0.1.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/README.md +154 -0
- package/dist/commands/ci.d.ts +15 -0
- package/dist/commands/ci.js +78 -0
- package/dist/commands/ci.js.map +1 -0
- package/dist/commands/deploy.d.ts +8 -0
- package/dist/commands/deploy.js +212 -0
- package/dist/commands/deploy.js.map +1 -0
- package/dist/commands/diff.d.ts +1 -0
- package/dist/commands/diff.js +96 -0
- package/dist/commands/diff.js.map +1 -0
- package/dist/commands/init.d.ts +1 -0
- package/dist/commands/init.js +197 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/migrate.d.ts +1 -0
- package/dist/commands/migrate.js +50 -0
- package/dist/commands/migrate.js.map +1 -0
- package/dist/commands/pull.d.ts +1 -0
- package/dist/commands/pull.js +80 -0
- package/dist/commands/pull.js.map +1 -0
- package/dist/commands/status.d.ts +1 -0
- package/dist/commands/status.js +59 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +133 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/config.d.ts +34 -0
- package/dist/lib/config.js +150 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/differ.d.ts +13 -0
- package/dist/lib/differ.js +130 -0
- package/dist/lib/differ.js.map +1 -0
- package/dist/lib/git.d.ts +16 -0
- package/dist/lib/git.js +65 -0
- package/dist/lib/git.js.map +1 -0
- package/dist/lib/introspector.d.ts +2 -0
- package/dist/lib/introspector.js +7 -0
- package/dist/lib/introspector.js.map +1 -0
- package/dist/lib/planner.d.ts +26 -0
- package/dist/lib/planner.js +501 -0
- package/dist/lib/planner.js.map +1 -0
- package/dist/lib/reader.d.ts +19 -0
- package/dist/lib/reader.js +106 -0
- package/dist/lib/reader.js.map +1 -0
- package/dist/lib/sync.d.ts +13 -0
- package/dist/lib/sync.js +46 -0
- package/dist/lib/sync.js.map +1 -0
- package/dist/lib/writer.d.ts +7 -0
- package/dist/lib/writer.js +191 -0
- package/dist/lib/writer.js.map +1 -0
- package/package.json +37 -0
|
@@ -0,0 +1,501 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.buildDeployPlan = buildDeployPlan;
|
|
7
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
// Helpers
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
function md5(content) {
|
|
12
|
+
return crypto_1.default.createHash('md5').update(content).digest('hex');
|
|
13
|
+
}
|
|
14
|
+
function stripHeader(content) {
|
|
15
|
+
return content.split('\n').slice(2).join('\n');
|
|
16
|
+
}
|
|
17
|
+
function bodyHash(content) {
|
|
18
|
+
return md5(stripHeader(content));
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Normalize SQL body for comparison: trim, strip trailing semicolons/newlines.
|
|
22
|
+
* This prevents false diffs caused by the writer appending semicolons.
|
|
23
|
+
*/
|
|
24
|
+
function normalizeForComparison(body) {
|
|
25
|
+
return body.trim().replace(/;\s*$/, '').trim();
|
|
26
|
+
}
|
|
27
|
+
// Languages that indicate extension-owned objects — cannot be deployed via SQL
|
|
28
|
+
const EXTENSION_LANGUAGES = new Set(['c', 'internal']);
|
|
29
|
+
/**
|
|
30
|
+
* Parse a CREATE TABLE definition.sql to extract column info.
|
|
31
|
+
* Returns a map of column_name -> { type, nullable, defaultVal }.
|
|
32
|
+
*/
|
|
33
|
+
function parseColumnsFromDisk(content) {
|
|
34
|
+
const cols = new Map();
|
|
35
|
+
const body = stripHeader(content);
|
|
36
|
+
// Match lines inside CREATE TABLE (...) that look like column defs
|
|
37
|
+
const tableBodyMatch = body.match(/CREATE TABLE[^(]*\(([\s\S]*)\);/);
|
|
38
|
+
if (!tableBodyMatch)
|
|
39
|
+
return cols;
|
|
40
|
+
const lines = tableBodyMatch[1].split('\n');
|
|
41
|
+
for (const line of lines) {
|
|
42
|
+
const trimmed = line.trim().replace(/,$/, '');
|
|
43
|
+
// Skip constraints (CONSTRAINT keyword or lines starting with PRIMARY/FOREIGN/UNIQUE/CHECK)
|
|
44
|
+
if (/^\s*(CONSTRAINT|PRIMARY|FOREIGN|UNIQUE|CHECK|EXCLUDE)\b/i.test(trimmed))
|
|
45
|
+
continue;
|
|
46
|
+
if (!trimmed || trimmed.startsWith('--'))
|
|
47
|
+
continue;
|
|
48
|
+
// Pattern: "col_name" type [NOT NULL] [DEFAULT ...]
|
|
49
|
+
const colMatch = trimmed.match(/^"([^"]+)"\s+(\S+)(.*)/);
|
|
50
|
+
if (!colMatch)
|
|
51
|
+
continue;
|
|
52
|
+
const name = colMatch[1];
|
|
53
|
+
const type = colMatch[2];
|
|
54
|
+
const rest = colMatch[3] || '';
|
|
55
|
+
const nullable = !rest.includes('NOT NULL');
|
|
56
|
+
const defaultMatch = rest.match(/DEFAULT\s+(.*?)(?:\s*$)/i);
|
|
57
|
+
const defaultVal = defaultMatch ? defaultMatch[1].replace(/,$/, '').trim() : null;
|
|
58
|
+
cols.set(name, { type, nullable, defaultVal });
|
|
59
|
+
}
|
|
60
|
+
return cols;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Parse enum values from a disk enum file.
|
|
64
|
+
*/
|
|
65
|
+
function parseEnumValuesFromDisk(content) {
|
|
66
|
+
const body = stripHeader(content);
|
|
67
|
+
const values = [];
|
|
68
|
+
const matches = body.matchAll(/'([^']+)'/g);
|
|
69
|
+
for (const m of matches) {
|
|
70
|
+
values.push(m[1]);
|
|
71
|
+
}
|
|
72
|
+
return values;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Parse index names from a disk indexes.sql file.
|
|
76
|
+
*/
|
|
77
|
+
function parseIndexNamesFromDisk(content) {
|
|
78
|
+
const body = stripHeader(content);
|
|
79
|
+
const indexes = new Map();
|
|
80
|
+
const regex = /CREATE\s+(?:UNIQUE\s+)?INDEX\s+(?:IF NOT EXISTS\s+)?(?:"([^"]+)"|(\S+))/gi;
|
|
81
|
+
let m;
|
|
82
|
+
while ((m = regex.exec(body)) !== null) {
|
|
83
|
+
const name = m[1] || m[2];
|
|
84
|
+
const startIdx = m.index;
|
|
85
|
+
const endIdx = body.indexOf(';', startIdx);
|
|
86
|
+
const stmt = body.substring(startIdx, endIdx >= 0 ? endIdx + 1 : undefined).trim();
|
|
87
|
+
indexes.set(name, stmt);
|
|
88
|
+
}
|
|
89
|
+
return indexes;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Parse policy names from a disk policies.sql file.
|
|
93
|
+
*/
|
|
94
|
+
function parsePolicyNamesFromDisk(content) {
|
|
95
|
+
const body = stripHeader(content);
|
|
96
|
+
const policies = new Set();
|
|
97
|
+
const regex = /CREATE POLICY\s+"([^"]+)"/gi;
|
|
98
|
+
let m;
|
|
99
|
+
while ((m = regex.exec(body)) !== null) {
|
|
100
|
+
policies.add(m[1]);
|
|
101
|
+
}
|
|
102
|
+
return policies;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Detect if two types are compatible for rename detection.
|
|
106
|
+
*/
|
|
107
|
+
function typesCompatible(a, b) {
|
|
108
|
+
const normalize = (t) => t.toLowerCase().replace(/\s+/g, '');
|
|
109
|
+
return normalize(a) === normalize(b);
|
|
110
|
+
}
|
|
111
|
+
// ---------------------------------------------------------------------------
|
|
112
|
+
// Dependency ordering
|
|
113
|
+
// ---------------------------------------------------------------------------
|
|
114
|
+
const CATEGORY_ORDER = {
|
|
115
|
+
'extension': 0,
|
|
116
|
+
'enum': 1,
|
|
117
|
+
'table-def': 2,
|
|
118
|
+
'table-indexes': 3,
|
|
119
|
+
'view': 4,
|
|
120
|
+
'function': 5,
|
|
121
|
+
'table-triggers': 6,
|
|
122
|
+
'table-policies': 7,
|
|
123
|
+
};
|
|
124
|
+
// Supabase-managed schemas — never deploy into these
|
|
125
|
+
const MANAGED_SCHEMAS = new Set([
|
|
126
|
+
'auth', 'storage', 'realtime', 'vault', 'pgsodium',
|
|
127
|
+
'pgsodium_masks', 'graphql', 'graphql_public', 'supabase_functions',
|
|
128
|
+
'supabase_migrations', 'net', 'cron', '_realtime', '_analytics',
|
|
129
|
+
]);
|
|
130
|
+
// ---------------------------------------------------------------------------
|
|
131
|
+
// Core planner
|
|
132
|
+
// ---------------------------------------------------------------------------
|
|
133
|
+
function buildDeployPlan(diskFiles, liveSnapshot, renames) {
|
|
134
|
+
const steps = [];
|
|
135
|
+
const renameCandidates = [];
|
|
136
|
+
let stepNum = 0;
|
|
137
|
+
// Filter out Supabase-managed schemas, then sort by dependency order
|
|
138
|
+
const userFiles = diskFiles.filter(f => {
|
|
139
|
+
if (f.category === 'extension')
|
|
140
|
+
return true; // extensions are global
|
|
141
|
+
return !MANAGED_SCHEMAS.has(f.schemaName);
|
|
142
|
+
});
|
|
143
|
+
const sorted = [...userFiles].sort((a, b) => {
|
|
144
|
+
return (CATEGORY_ORDER[a.category] ?? 99) - (CATEGORY_ORDER[b.category] ?? 99);
|
|
145
|
+
});
|
|
146
|
+
// Build lookup maps from live snapshot
|
|
147
|
+
const liveTables = new Map(liveSnapshot.tables.map(t => [`${t.schema}.${t.name}`, t]));
|
|
148
|
+
const liveViews = new Map(liveSnapshot.views.map(v => [`${v.schema}.${v.name}`, v]));
|
|
149
|
+
const liveFunctions = new Map(liveSnapshot.functions.map(f => [`${f.schema}.${f.name}`, f]));
|
|
150
|
+
const liveEnums = new Map(liveSnapshot.enums.map(e => [`${e.schema}.${e.name}`, e]));
|
|
151
|
+
const liveExtNames = new Set(liveSnapshot.extensions.map(e => e.name));
|
|
152
|
+
for (const file of sorted) {
|
|
153
|
+
const key = `${file.schemaName}.${file.objectName}`;
|
|
154
|
+
switch (file.category) {
|
|
155
|
+
case 'extension': {
|
|
156
|
+
const sql = stripHeader(file.content).trim();
|
|
157
|
+
if (!sql || sql.startsWith('-- No')) {
|
|
158
|
+
steps.push(makeStep(++stepNum, file, 'SKIP', '', false, []));
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
// Check if all extensions in the file already exist
|
|
162
|
+
const extNames = [...sql.matchAll(/CREATE EXTENSION[^"]*"([^"]+)"/gi)].map(m => m[1]);
|
|
163
|
+
const newExts = extNames.filter(name => !liveExtNames.has(name));
|
|
164
|
+
if (newExts.length === 0) {
|
|
165
|
+
steps.push(makeStep(++stepNum, file, 'SKIP', '', false, []));
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
// Only CREATE the missing extensions
|
|
169
|
+
const newSql = newExts
|
|
170
|
+
.map(name => `CREATE EXTENSION IF NOT EXISTS "${name}";`)
|
|
171
|
+
.join('\n');
|
|
172
|
+
steps.push(makeStep(++stepNum, file, 'CREATE', newSql, false, []));
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
case 'enum': {
|
|
178
|
+
const liveEnum = liveEnums.get(key);
|
|
179
|
+
const diskValues = parseEnumValuesFromDisk(file.content);
|
|
180
|
+
if (!liveEnum) {
|
|
181
|
+
steps.push(makeStep(++stepNum, file, 'CREATE', stripHeader(file.content).trim(), false, []));
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
// Existing enum: add new values only (PG cannot remove enum values)
|
|
185
|
+
const newValues = diskValues.filter(v => !liveEnum.values.includes(v));
|
|
186
|
+
if (newValues.length === 0) {
|
|
187
|
+
steps.push(makeStep(++stepNum, file, 'SKIP', '', false, []));
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
const sql = newValues
|
|
191
|
+
.map(v => `ALTER TYPE "${file.schemaName}"."${file.objectName}" ADD VALUE IF NOT EXISTS '${v}';`)
|
|
192
|
+
.join('\n');
|
|
193
|
+
steps.push(makeStep(++stepNum, file, 'ALTER', sql, false, []));
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
break;
|
|
197
|
+
}
|
|
198
|
+
case 'table-def': {
|
|
199
|
+
const liveTable = liveTables.get(key);
|
|
200
|
+
if (!liveTable) {
|
|
201
|
+
steps.push(makeStep(++stepNum, file, 'CREATE', stripHeader(file.content).trim(), false, []));
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
const result = diffTableColumns(file, liveTable, renames);
|
|
205
|
+
renameCandidates.push(...result.renames);
|
|
206
|
+
if (result.sql.trim()) {
|
|
207
|
+
steps.push(makeStep(++stepNum, file, 'ALTER', result.sql, result.destructive, result.warnings));
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
steps.push(makeStep(++stepNum, file, 'SKIP', '', false, []));
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
break;
|
|
214
|
+
}
|
|
215
|
+
case 'table-indexes': {
|
|
216
|
+
const liveTable = liveTables.get(key);
|
|
217
|
+
if (!liveTable) {
|
|
218
|
+
const sql = stripHeader(file.content).trim();
|
|
219
|
+
if (sql && !sql.startsWith('-- No')) {
|
|
220
|
+
steps.push(makeStep(++stepNum, file, 'CREATE', sql, false, []));
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
steps.push(makeStep(++stepNum, file, 'SKIP', '', false, []));
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
else {
|
|
227
|
+
const result = diffIndexes(file, liveSnapshot.indexes, file.schemaName, file.objectName);
|
|
228
|
+
if (result.sql.trim()) {
|
|
229
|
+
steps.push(makeStep(++stepNum, file, result.operation, result.sql, result.destructive, result.warnings));
|
|
230
|
+
}
|
|
231
|
+
else {
|
|
232
|
+
steps.push(makeStep(++stepNum, file, 'SKIP', '', false, []));
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
break;
|
|
236
|
+
}
|
|
237
|
+
case 'view': {
|
|
238
|
+
const liveView = liveViews.get(key);
|
|
239
|
+
if (!liveView) {
|
|
240
|
+
steps.push(makeStep(++stepNum, file, 'CREATE', stripHeader(file.content).trim(), false, []));
|
|
241
|
+
}
|
|
242
|
+
else {
|
|
243
|
+
const liveNorm = normalizeForComparison(liveView.definition);
|
|
244
|
+
const diskBody = stripHeader(file.content).trim();
|
|
245
|
+
const diskDefMatch = diskBody.match(/AS\s+([\s\S]+)/i);
|
|
246
|
+
const diskDef = diskDefMatch ? diskDefMatch[1].trim() : diskBody;
|
|
247
|
+
const diskNorm = normalizeForComparison(diskDef);
|
|
248
|
+
if (md5(liveNorm) === md5(diskNorm)) {
|
|
249
|
+
steps.push(makeStep(++stepNum, file, 'SKIP', '', false, []));
|
|
250
|
+
}
|
|
251
|
+
else {
|
|
252
|
+
steps.push(makeStep(++stepNum, file, 'REPLACE', diskBody, false, []));
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
break;
|
|
256
|
+
}
|
|
257
|
+
case 'function': {
|
|
258
|
+
const liveFunc = liveFunctions.get(key);
|
|
259
|
+
const diskBody = stripHeader(file.content).trim();
|
|
260
|
+
// Skip extension-owned functions (C/internal) — cannot be deployed via SQL
|
|
261
|
+
if (liveFunc && EXTENSION_LANGUAGES.has(liveFunc.language)) {
|
|
262
|
+
steps.push(makeStep(++stepNum, file, 'SKIP', '', false, []));
|
|
263
|
+
break;
|
|
264
|
+
}
|
|
265
|
+
if (!liveFunc) {
|
|
266
|
+
steps.push(makeStep(++stepNum, file, 'CREATE', diskBody, false, []));
|
|
267
|
+
}
|
|
268
|
+
else {
|
|
269
|
+
const liveNorm = liveFunc.body ? normalizeForComparison(liveFunc.body) : '';
|
|
270
|
+
const diskNorm = normalizeForComparison(diskBody);
|
|
271
|
+
if (md5(liveNorm) === md5(diskNorm)) {
|
|
272
|
+
steps.push(makeStep(++stepNum, file, 'SKIP', '', false, []));
|
|
273
|
+
}
|
|
274
|
+
else {
|
|
275
|
+
steps.push(makeStep(++stepNum, file, 'REPLACE', diskBody, false, []));
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
break;
|
|
279
|
+
}
|
|
280
|
+
case 'table-triggers': {
|
|
281
|
+
const body = stripHeader(file.content).trim();
|
|
282
|
+
if (!body || body.startsWith('-- No')) {
|
|
283
|
+
steps.push(makeStep(++stepNum, file, 'SKIP', '', false, []));
|
|
284
|
+
break;
|
|
285
|
+
}
|
|
286
|
+
const liveTable = liveTables.get(key);
|
|
287
|
+
if (!liveTable) {
|
|
288
|
+
steps.push(makeStep(++stepNum, file, 'CREATE', body, false, []));
|
|
289
|
+
}
|
|
290
|
+
else {
|
|
291
|
+
// Extract CREATE TRIGGER statements from disk and compare against live
|
|
292
|
+
const liveTriggers = liveSnapshot.triggers.filter(t => t.schema === file.schemaName && t.table === file.objectName);
|
|
293
|
+
const liveSet = new Set(liveTriggers.map(t => normalizeForComparison(t.body)));
|
|
294
|
+
const diskTrigDefs = body.match(/CREATE TRIGGER[\s\S]*?(?=DROP TRIGGER|CREATE TRIGGER|$)/gi) || [];
|
|
295
|
+
const diskSet = new Set(diskTrigDefs.map(d => normalizeForComparison(d)));
|
|
296
|
+
// Compare: same triggers if same set of normalized CREATE TRIGGER statements
|
|
297
|
+
const setsEqual = liveSet.size === diskSet.size && [...liveSet].every(t => diskSet.has(t));
|
|
298
|
+
if (setsEqual) {
|
|
299
|
+
steps.push(makeStep(++stepNum, file, 'SKIP', '', false, []));
|
|
300
|
+
}
|
|
301
|
+
else {
|
|
302
|
+
steps.push(makeStep(++stepNum, file, 'REPLACE', body, false, []));
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
break;
|
|
306
|
+
}
|
|
307
|
+
case 'table-policies': {
|
|
308
|
+
const liveTable = liveTables.get(key);
|
|
309
|
+
if (!liveTable) {
|
|
310
|
+
const body = stripHeader(file.content).trim();
|
|
311
|
+
if (body && !body.startsWith('-- No')) {
|
|
312
|
+
steps.push(makeStep(++stepNum, file, 'CREATE', body, false, []));
|
|
313
|
+
}
|
|
314
|
+
else {
|
|
315
|
+
steps.push(makeStep(++stepNum, file, 'SKIP', '', false, []));
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
else {
|
|
319
|
+
const result = diffPolicies(file, liveSnapshot.policies, file.schemaName, file.objectName);
|
|
320
|
+
if (result.sql.trim()) {
|
|
321
|
+
steps.push(makeStep(++stepNum, file, result.operation, result.sql, result.destructive, result.warnings));
|
|
322
|
+
}
|
|
323
|
+
else {
|
|
324
|
+
steps.push(makeStep(++stepNum, file, 'SKIP', '', false, []));
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
break;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
return {
|
|
332
|
+
steps,
|
|
333
|
+
renames: renameCandidates,
|
|
334
|
+
hasDestructive: steps.some(s => s.destructive),
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
function diffTableColumns(file, liveTable, confirmedRenames) {
|
|
338
|
+
const diskCols = parseColumnsFromDisk(file.content);
|
|
339
|
+
const liveCols = new Map(liveTable.columns.map(c => [c.name, c]));
|
|
340
|
+
const sqls = [];
|
|
341
|
+
const warnings = [];
|
|
342
|
+
const renames = [];
|
|
343
|
+
let destructive = false;
|
|
344
|
+
const tbl = `"${file.schemaName}"."${file.objectName}"`;
|
|
345
|
+
// Columns on disk but not live: ADD COLUMN
|
|
346
|
+
const added = [];
|
|
347
|
+
for (const [colName, col] of diskCols) {
|
|
348
|
+
if (!liveCols.has(colName)) {
|
|
349
|
+
// Check if this is a confirmed rename
|
|
350
|
+
let isRename = false;
|
|
351
|
+
for (const [rk, newName] of confirmedRenames) {
|
|
352
|
+
if (newName === colName && rk.startsWith(`${file.objectName}.`)) {
|
|
353
|
+
const oldCol = rk.split('.')[1];
|
|
354
|
+
sqls.push(`ALTER TABLE ${tbl} RENAME COLUMN "${oldCol}" TO "${colName}";`);
|
|
355
|
+
isRename = true;
|
|
356
|
+
break;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
if (!isRename) {
|
|
360
|
+
added.push(colName);
|
|
361
|
+
const parts = [`ALTER TABLE ${tbl} ADD COLUMN "${colName}" ${col.type}`];
|
|
362
|
+
if (!col.nullable)
|
|
363
|
+
parts.push('NOT NULL');
|
|
364
|
+
if (col.defaultVal)
|
|
365
|
+
parts.push(`DEFAULT ${col.defaultVal}`);
|
|
366
|
+
sqls.push(parts.join(' ') + ';');
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
// Columns live but not on disk: DROP COLUMN
|
|
371
|
+
const removed = [];
|
|
372
|
+
for (const [colName] of liveCols) {
|
|
373
|
+
if (!diskCols.has(colName)) {
|
|
374
|
+
const renameKey = `${file.objectName}.${colName}`;
|
|
375
|
+
if (confirmedRenames.has(renameKey))
|
|
376
|
+
continue;
|
|
377
|
+
removed.push(colName);
|
|
378
|
+
sqls.push(`ALTER TABLE ${tbl} DROP COLUMN "${colName}";`);
|
|
379
|
+
warnings.push(`DROP COLUMN "${colName}" on ${tbl}`);
|
|
380
|
+
destructive = true;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
// Detect possible renames (removed + added with compatible types)
|
|
384
|
+
for (const oldCol of removed) {
|
|
385
|
+
const liveCol = liveCols.get(oldCol);
|
|
386
|
+
if (!liveCol)
|
|
387
|
+
continue;
|
|
388
|
+
for (const newCol of added) {
|
|
389
|
+
const diskCol = diskCols.get(newCol);
|
|
390
|
+
if (!diskCol)
|
|
391
|
+
continue;
|
|
392
|
+
if (typesCompatible(liveCol.type, diskCol.type)) {
|
|
393
|
+
renames.push({
|
|
394
|
+
table: file.objectName,
|
|
395
|
+
schema: file.schemaName,
|
|
396
|
+
oldColumn: oldCol,
|
|
397
|
+
newColumn: newCol,
|
|
398
|
+
type: liveCol.type,
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
// Columns in both: check for type or nullability changes
|
|
404
|
+
for (const [colName, diskCol] of diskCols) {
|
|
405
|
+
const liveCol = liveCols.get(colName);
|
|
406
|
+
if (!liveCol)
|
|
407
|
+
continue;
|
|
408
|
+
if (liveCol.type !== diskCol.type) {
|
|
409
|
+
sqls.push(`ALTER TABLE ${tbl} ALTER COLUMN "${colName}" TYPE ${diskCol.type};`);
|
|
410
|
+
}
|
|
411
|
+
if (liveCol.nullable && !diskCol.nullable) {
|
|
412
|
+
sqls.push(`ALTER TABLE ${tbl} ALTER COLUMN "${colName}" SET NOT NULL;`);
|
|
413
|
+
}
|
|
414
|
+
else if (!liveCol.nullable && diskCol.nullable) {
|
|
415
|
+
sqls.push(`ALTER TABLE ${tbl} ALTER COLUMN "${colName}" DROP NOT NULL;`);
|
|
416
|
+
}
|
|
417
|
+
if (diskCol.defaultVal && diskCol.defaultVal !== liveCol.default) {
|
|
418
|
+
sqls.push(`ALTER TABLE ${tbl} ALTER COLUMN "${colName}" SET DEFAULT ${diskCol.defaultVal};`);
|
|
419
|
+
}
|
|
420
|
+
else if (!diskCol.defaultVal && liveCol.default) {
|
|
421
|
+
sqls.push(`ALTER TABLE ${tbl} ALTER COLUMN "${colName}" DROP DEFAULT;`);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
return { sql: sqls.join('\n'), destructive, warnings, renames };
|
|
425
|
+
}
|
|
426
|
+
function diffIndexes(file, liveIndexes, schemaName, tableName) {
|
|
427
|
+
const diskIndexes = parseIndexNamesFromDisk(file.content);
|
|
428
|
+
const liveTableIndexes = liveIndexes.filter(i => i.schema === schemaName && i.table === tableName && !i.isPrimary);
|
|
429
|
+
const liveNames = new Set(liveTableIndexes.map(i => i.name));
|
|
430
|
+
const sqls = [];
|
|
431
|
+
const warnings = [];
|
|
432
|
+
let destructive = false;
|
|
433
|
+
for (const [name, stmt] of diskIndexes) {
|
|
434
|
+
if (!liveNames.has(name)) {
|
|
435
|
+
sqls.push(stmt.endsWith(';') ? stmt : stmt + ';');
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
for (const idx of liveTableIndexes) {
|
|
439
|
+
if (!diskIndexes.has(idx.name)) {
|
|
440
|
+
sqls.push(`DROP INDEX IF EXISTS "${schemaName}"."${idx.name}";`);
|
|
441
|
+
warnings.push(`DROP INDEX "${idx.name}" on ${schemaName}.${tableName}`);
|
|
442
|
+
destructive = true;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
return {
|
|
446
|
+
sql: sqls.join('\n'),
|
|
447
|
+
operation: sqls.length > 0 ? 'ALTER' : 'SKIP',
|
|
448
|
+
destructive,
|
|
449
|
+
warnings,
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
// ---------------------------------------------------------------------------
|
|
453
|
+
// Policy diff
|
|
454
|
+
// ---------------------------------------------------------------------------
|
|
455
|
+
function diffPolicies(file, livePolicies, schemaName, tableName) {
|
|
456
|
+
const diskPolicies = parsePolicyNamesFromDisk(file.content);
|
|
457
|
+
const liveTablePolicies = livePolicies.filter(p => p.schema === schemaName && p.table === tableName);
|
|
458
|
+
const liveNames = new Set(liveTablePolicies.map(p => p.name));
|
|
459
|
+
const sqls = [];
|
|
460
|
+
const warnings = [];
|
|
461
|
+
let destructive = false;
|
|
462
|
+
const addedPolicies = [...diskPolicies].filter(n => !liveNames.has(n));
|
|
463
|
+
const removedPolicies = [...liveNames].filter(n => !diskPolicies.has(n));
|
|
464
|
+
if (addedPolicies.length > 0 || removedPolicies.length > 0) {
|
|
465
|
+
const body = stripHeader(file.content).trim();
|
|
466
|
+
sqls.push(body);
|
|
467
|
+
for (const name of removedPolicies) {
|
|
468
|
+
sqls.unshift(`DROP POLICY IF EXISTS "${name}" ON "${schemaName}"."${tableName}";`);
|
|
469
|
+
warnings.push(`DROP POLICY "${name}" on ${schemaName}.${tableName}`);
|
|
470
|
+
destructive = true;
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
else {
|
|
474
|
+
// Same policy names — if the policy set is identical, skip.
|
|
475
|
+
// Since we can't reliably parse policy bodies from the SQL file,
|
|
476
|
+
// and the file was generated by `pull` from the same DB, if the
|
|
477
|
+
// policy names match we consider them unchanged.
|
|
478
|
+
}
|
|
479
|
+
return {
|
|
480
|
+
sql: sqls.join('\n'),
|
|
481
|
+
operation: sqls.length > 0 ? 'REPLACE' : 'SKIP',
|
|
482
|
+
destructive,
|
|
483
|
+
warnings,
|
|
484
|
+
};
|
|
485
|
+
}
|
|
486
|
+
// ---------------------------------------------------------------------------
|
|
487
|
+
// Step builder
|
|
488
|
+
// ---------------------------------------------------------------------------
|
|
489
|
+
function makeStep(step, file, operation, sql, destructive, warnings) {
|
|
490
|
+
return {
|
|
491
|
+
step,
|
|
492
|
+
filePath: file.filePath,
|
|
493
|
+
objectType: file.category,
|
|
494
|
+
objectName: `${file.schemaName}.${file.objectName}`,
|
|
495
|
+
operation,
|
|
496
|
+
sql,
|
|
497
|
+
destructive,
|
|
498
|
+
warnings,
|
|
499
|
+
};
|
|
500
|
+
}
|
|
501
|
+
//# sourceMappingURL=planner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"planner.js","sourceRoot":"","sources":["../../src/lib/planner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface DiskFile {
|
|
2
|
+
/** Relative path from project root, e.g. schema/tables/users/definition.sql */
|
|
3
|
+
filePath: string;
|
|
4
|
+
/** Category derived from path: extension | enum | table-def | table-indexes | table-policies | table-triggers | view | function */
|
|
5
|
+
category: DiskFileCategory;
|
|
6
|
+
/** Object name (table name, function name, etc.) */
|
|
7
|
+
objectName: string;
|
|
8
|
+
/** Schema name parsed from header, defaults to 'public' */
|
|
9
|
+
schemaName: string;
|
|
10
|
+
/** Raw file content */
|
|
11
|
+
content: string;
|
|
12
|
+
/** MD5 hash of content body (excluding the 2-line header) */
|
|
13
|
+
bodyHash: string;
|
|
14
|
+
}
|
|
15
|
+
export type DiskFileCategory = 'extension' | 'enum' | 'table-def' | 'table-indexes' | 'table-policies' | 'table-triggers' | 'view' | 'function';
|
|
16
|
+
/**
|
|
17
|
+
* Read all schema SQL files from disk into structured DiskFile objects.
|
|
18
|
+
*/
|
|
19
|
+
export declare function readSchemaFiles(env: string): DiskFile[];
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.readSchemaFiles = readSchemaFiles;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
10
|
+
const SCHEMA_DIR = 'schema';
|
|
11
|
+
function md5(content) {
|
|
12
|
+
return crypto_1.default.createHash('md5').update(content).digest('hex');
|
|
13
|
+
}
|
|
14
|
+
function stripHeader(content) {
|
|
15
|
+
return content.split('\n').slice(2).join('\n');
|
|
16
|
+
}
|
|
17
|
+
function parseHeader(content) {
|
|
18
|
+
// Header format: -- object: <type> · <schema>.<name>
|
|
19
|
+
const firstLine = content.split('\n')[0] || '';
|
|
20
|
+
const match = firstLine.match(/--\s*object:\s*\S+\s*·\s*(\S+)\.(\S+)/);
|
|
21
|
+
if (match) {
|
|
22
|
+
return { schemaName: match[1], objectName: match[2] };
|
|
23
|
+
}
|
|
24
|
+
return { schemaName: 'public', objectName: '' };
|
|
25
|
+
}
|
|
26
|
+
function categorizeFile(relPath) {
|
|
27
|
+
const parts = relPath.split(path_1.default.sep);
|
|
28
|
+
// schema/<env>/extensions/enabled.sql
|
|
29
|
+
if (parts[2] === 'extensions') {
|
|
30
|
+
return { category: 'extension', fallbackName: 'enabled' };
|
|
31
|
+
}
|
|
32
|
+
// schema/<env>/enums/<name>.sql
|
|
33
|
+
if (parts[2] === 'enums' && parts[3]) {
|
|
34
|
+
return { category: 'enum', fallbackName: parts[3].replace(/\.sql$/, '') };
|
|
35
|
+
}
|
|
36
|
+
// schema/<env>/tables/<name>/definition.sql | indexes.sql | policies.sql | triggers.sql
|
|
37
|
+
if (parts[2] === 'tables' && parts[3] && parts[4]) {
|
|
38
|
+
const tableName = parts[3];
|
|
39
|
+
const fileName = parts[4].replace(/\.sql$/, '');
|
|
40
|
+
const categoryMap = {
|
|
41
|
+
definition: 'table-def',
|
|
42
|
+
indexes: 'table-indexes',
|
|
43
|
+
policies: 'table-policies',
|
|
44
|
+
triggers: 'table-triggers',
|
|
45
|
+
};
|
|
46
|
+
const cat = categoryMap[fileName];
|
|
47
|
+
if (cat)
|
|
48
|
+
return { category: cat, fallbackName: tableName };
|
|
49
|
+
}
|
|
50
|
+
// schema/<env>/views/<name>.sql
|
|
51
|
+
if (parts[2] === 'views' && parts[3]) {
|
|
52
|
+
return { category: 'view', fallbackName: parts[3].replace(/\.sql$/, '') };
|
|
53
|
+
}
|
|
54
|
+
// schema/<env>/functions/<name>.sql
|
|
55
|
+
if (parts[2] === 'functions' && parts[3]) {
|
|
56
|
+
return { category: 'function', fallbackName: parts[3].replace(/\.sql$/, '') };
|
|
57
|
+
}
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Recursively collect all .sql files under a directory.
|
|
62
|
+
*/
|
|
63
|
+
function collectSqlFiles(dir, base) {
|
|
64
|
+
const absDir = path_1.default.resolve(dir);
|
|
65
|
+
if (!fs_1.default.existsSync(absDir))
|
|
66
|
+
return [];
|
|
67
|
+
const results = [];
|
|
68
|
+
for (const entry of fs_1.default.readdirSync(absDir, { withFileTypes: true })) {
|
|
69
|
+
if (entry.name.startsWith('.'))
|
|
70
|
+
continue;
|
|
71
|
+
const fullPath = path_1.default.join(dir, entry.name);
|
|
72
|
+
if (entry.isDirectory()) {
|
|
73
|
+
results.push(...collectSqlFiles(fullPath, base));
|
|
74
|
+
}
|
|
75
|
+
else if (entry.name.endsWith('.sql')) {
|
|
76
|
+
results.push(fullPath);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return results;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Read all schema SQL files from disk into structured DiskFile objects.
|
|
83
|
+
*/
|
|
84
|
+
function readSchemaFiles(env) {
|
|
85
|
+
const envDir = path_1.default.join(SCHEMA_DIR, env);
|
|
86
|
+
const files = collectSqlFiles(envDir, envDir);
|
|
87
|
+
const result = [];
|
|
88
|
+
for (const filePath of files) {
|
|
89
|
+
const relPath = path_1.default.relative('.', filePath);
|
|
90
|
+
const info = categorizeFile(relPath);
|
|
91
|
+
if (!info)
|
|
92
|
+
continue;
|
|
93
|
+
const content = fs_1.default.readFileSync(filePath, 'utf-8');
|
|
94
|
+
const header = parseHeader(content);
|
|
95
|
+
result.push({
|
|
96
|
+
filePath: relPath,
|
|
97
|
+
category: info.category,
|
|
98
|
+
objectName: header.objectName || info.fallbackName,
|
|
99
|
+
schemaName: header.schemaName,
|
|
100
|
+
content,
|
|
101
|
+
bodyHash: md5(stripHeader(content)),
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
return result;
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=reader.js.map
|