relq 1.0.5 → 1.0.7
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/cjs/cli/commands/add.cjs +257 -17
- package/dist/cjs/cli/commands/commit.cjs +13 -2
- package/dist/cjs/cli/commands/export.cjs +25 -19
- package/dist/cjs/cli/commands/import.cjs +219 -100
- package/dist/cjs/cli/commands/init.cjs +86 -14
- package/dist/cjs/cli/commands/pull.cjs +104 -23
- package/dist/cjs/cli/commands/push.cjs +38 -3
- package/dist/cjs/cli/index.cjs +9 -1
- package/dist/cjs/cli/utils/ast/codegen/builder.cjs +297 -0
- package/dist/cjs/cli/utils/ast/codegen/constraints.cjs +185 -0
- package/dist/cjs/cli/utils/ast/codegen/defaults.cjs +311 -0
- package/dist/cjs/cli/utils/ast/codegen/index.cjs +24 -0
- package/dist/cjs/cli/utils/ast/codegen/type-map.cjs +116 -0
- package/dist/cjs/cli/utils/ast/codegen/utils.cjs +69 -0
- package/dist/cjs/cli/utils/ast/index.cjs +19 -0
- package/dist/cjs/cli/utils/ast/transformer/helpers.cjs +154 -0
- package/dist/cjs/cli/utils/ast/transformer/index.cjs +25 -0
- package/dist/cjs/cli/utils/ast/types.cjs +2 -0
- package/dist/cjs/cli/utils/ast-codegen.cjs +949 -0
- package/dist/cjs/cli/utils/ast-transformer.cjs +916 -0
- package/dist/cjs/cli/utils/change-tracker.cjs +50 -1
- package/dist/cjs/cli/utils/cli-utils.cjs +151 -0
- package/dist/cjs/cli/utils/fast-introspect.cjs +149 -23
- package/dist/cjs/cli/utils/pg-parser.cjs +1 -0
- package/dist/cjs/cli/utils/repo-manager.cjs +121 -4
- package/dist/cjs/cli/utils/schema-comparator.cjs +98 -14
- package/dist/cjs/cli/utils/schema-introspect.cjs +56 -19
- package/dist/cjs/cli/utils/snapshot-manager.cjs +0 -1
- package/dist/cjs/cli/utils/sql-generator.cjs +353 -64
- package/dist/cjs/cli/utils/type-generator.cjs +114 -15
- package/dist/cjs/config/config.cjs +29 -10
- package/dist/cjs/core/relq-client.cjs +22 -6
- package/dist/cjs/schema-definition/column-types.cjs +149 -13
- package/dist/cjs/schema-definition/defaults.cjs +72 -0
- package/dist/cjs/schema-definition/index.cjs +15 -1
- package/dist/cjs/schema-definition/introspection.cjs +7 -3
- package/dist/cjs/schema-definition/pg-relations.cjs +169 -0
- package/dist/cjs/schema-definition/pg-view.cjs +30 -0
- package/dist/cjs/schema-definition/table-definition.cjs +110 -4
- package/dist/cjs/types/config-types.cjs +13 -4
- package/dist/cjs/utils/aws-dsql.cjs +177 -0
- package/dist/config.d.ts +147 -2
- package/dist/esm/cli/commands/add.js +255 -18
- package/dist/esm/cli/commands/commit.js +13 -2
- package/dist/esm/cli/commands/export.js +25 -19
- package/dist/esm/cli/commands/import.js +221 -102
- package/dist/esm/cli/commands/init.js +86 -14
- package/dist/esm/cli/commands/pull.js +106 -25
- package/dist/esm/cli/commands/push.js +39 -4
- package/dist/esm/cli/index.js +9 -1
- package/dist/esm/cli/utils/ast/codegen/builder.js +291 -0
- package/dist/esm/cli/utils/ast/codegen/constraints.js +176 -0
- package/dist/esm/cli/utils/ast/codegen/defaults.js +305 -0
- package/dist/esm/cli/utils/ast/codegen/index.js +6 -0
- package/dist/esm/cli/utils/ast/codegen/type-map.js +111 -0
- package/dist/esm/cli/utils/ast/codegen/utils.js +60 -0
- package/dist/esm/cli/utils/ast/index.js +3 -0
- package/dist/esm/cli/utils/ast/transformer/helpers.js +141 -0
- package/dist/esm/cli/utils/ast/transformer/index.js +2 -0
- package/dist/esm/cli/utils/ast/types.js +1 -0
- package/dist/esm/cli/utils/ast-codegen.js +945 -0
- package/dist/esm/cli/utils/ast-transformer.js +907 -0
- package/dist/esm/cli/utils/change-tracker.js +50 -1
- package/dist/esm/cli/utils/cli-utils.js +147 -0
- package/dist/esm/cli/utils/fast-introspect.js +149 -23
- package/dist/esm/cli/utils/pg-parser.js +1 -0
- package/dist/esm/cli/utils/repo-manager.js +114 -4
- package/dist/esm/cli/utils/schema-comparator.js +98 -14
- package/dist/esm/cli/utils/schema-introspect.js +56 -19
- package/dist/esm/cli/utils/snapshot-manager.js +0 -1
- package/dist/esm/cli/utils/sql-generator.js +353 -64
- package/dist/esm/cli/utils/type-generator.js +114 -15
- package/dist/esm/config/config.js +29 -10
- package/dist/esm/core/relq-client.js +23 -7
- package/dist/esm/schema-definition/column-types.js +146 -12
- package/dist/esm/schema-definition/defaults.js +69 -0
- package/dist/esm/schema-definition/index.js +3 -0
- package/dist/esm/schema-definition/introspection.js +7 -3
- package/dist/esm/schema-definition/pg-relations.js +161 -0
- package/dist/esm/schema-definition/pg-view.js +24 -0
- package/dist/esm/schema-definition/table-definition.js +110 -4
- package/dist/esm/types/config-types.js +12 -4
- package/dist/esm/utils/aws-dsql.js +139 -0
- package/dist/index.d.ts +159 -1
- package/dist/schema-builder.d.ts +1314 -32
- package/package.json +1 -1
|
@@ -37,7 +37,8 @@ exports.importCommand = importCommand;
|
|
|
37
37
|
const fs = __importStar(require("fs"));
|
|
38
38
|
const path = __importStar(require("path"));
|
|
39
39
|
const sql_parser_1 = require("../utils/sql-parser.cjs");
|
|
40
|
-
const
|
|
40
|
+
const ast_codegen_1 = require("../utils/ast-codegen.cjs");
|
|
41
|
+
const ast_transformer_1 = require("../utils/ast-transformer.cjs");
|
|
41
42
|
const repo_manager_1 = require("../utils/repo-manager.cjs");
|
|
42
43
|
const schema_comparator_1 = require("../utils/schema-comparator.cjs");
|
|
43
44
|
const change_tracker_1 = require("../utils/change-tracker.cjs");
|
|
@@ -102,7 +103,7 @@ async function importCommand(sqlFilePath, options = {}, projectRoot = process.cw
|
|
|
102
103
|
}
|
|
103
104
|
}
|
|
104
105
|
spinner.start('Parsing SQL schema');
|
|
105
|
-
const parsedSchema = (0,
|
|
106
|
+
const parsedSchema = await (0, ast_transformer_1.parseSQL)(sqlContent);
|
|
106
107
|
const functions = includeFunctions ? (0, sql_parser_1.parseFunctions)(sqlContent) : [];
|
|
107
108
|
const triggers = includeTriggers ? (0, sql_parser_1.parseTriggers)(sqlContent) : [];
|
|
108
109
|
const comments = (0, sql_parser_1.parseComments)(sqlContent);
|
|
@@ -190,13 +191,6 @@ async function importCommand(sqlFilePath, options = {}, projectRoot = process.cw
|
|
|
190
191
|
}
|
|
191
192
|
return true;
|
|
192
193
|
});
|
|
193
|
-
const filteredCompositeTypes = parsedSchema.compositeTypes.filter(c => {
|
|
194
|
-
if ((0, relqignore_1.isCompositeTypeIgnored)(c.name, ignorePatterns).ignored) {
|
|
195
|
-
ignoredCount++;
|
|
196
|
-
return false;
|
|
197
|
-
}
|
|
198
|
-
return true;
|
|
199
|
-
});
|
|
200
194
|
const filteredSequences = parsedSchema.sequences.filter(s => {
|
|
201
195
|
if ((0, relqignore_1.isSequenceIgnored)(s.name, ignorePatterns).ignored) {
|
|
202
196
|
ignoredCount++;
|
|
@@ -215,15 +209,11 @@ async function importCommand(sqlFilePath, options = {}, projectRoot = process.cw
|
|
|
215
209
|
tables: filteredTables,
|
|
216
210
|
enums: filteredEnums,
|
|
217
211
|
domains: filteredDomains,
|
|
218
|
-
compositeTypes: filteredCompositeTypes,
|
|
219
212
|
sequences: filteredSequences,
|
|
220
|
-
collations: parsedSchema.collations,
|
|
221
|
-
foreignTables: parsedSchema.foreignTables,
|
|
222
213
|
views: parsedSchema.views,
|
|
223
|
-
|
|
224
|
-
|
|
214
|
+
functions: parsedSchema.functions,
|
|
215
|
+
triggers: parsedSchema.triggers,
|
|
225
216
|
extensions: parsedSchema.extensions,
|
|
226
|
-
partitions: parsedSchema.partitions,
|
|
227
217
|
};
|
|
228
218
|
if (ignoredCount > 0) {
|
|
229
219
|
console.log(`${ignoredCount} object(s) ignored by .relqignore`);
|
|
@@ -233,14 +223,14 @@ async function importCommand(sqlFilePath, options = {}, projectRoot = process.cw
|
|
|
233
223
|
name: t.name,
|
|
234
224
|
columns: t.columns.map(c => ({
|
|
235
225
|
name: c.name,
|
|
236
|
-
type: c.
|
|
226
|
+
type: c.type,
|
|
237
227
|
default: c.defaultValue,
|
|
238
228
|
})),
|
|
239
229
|
})),
|
|
240
230
|
enums: parsedSchema.enums,
|
|
241
231
|
domains: parsedSchema.domains,
|
|
242
232
|
sequences: parsedSchema.sequences,
|
|
243
|
-
compositeTypes:
|
|
233
|
+
compositeTypes: [],
|
|
244
234
|
}, ignorePatterns);
|
|
245
235
|
if (dependencyErrors.length > 0) {
|
|
246
236
|
spinner.stop();
|
|
@@ -249,12 +239,6 @@ async function importCommand(sqlFilePath, options = {}, projectRoot = process.cw
|
|
|
249
239
|
return;
|
|
250
240
|
}
|
|
251
241
|
spinner.start('Generating TypeScript schema');
|
|
252
|
-
const dbSchema = convertToDbSchema(filteredSchema, filteredFunctions, triggers, comments);
|
|
253
|
-
const typescriptContent = (0, type_generator_1.generateTypeScript)(dbSchema, {
|
|
254
|
-
camelCase: true,
|
|
255
|
-
includeFunctions,
|
|
256
|
-
includeTriggers,
|
|
257
|
-
});
|
|
258
242
|
spinner.succeed('Generated TypeScript schema');
|
|
259
243
|
const incomingSchema = convertToNormalizedSchema(filteredSchema, filteredFunctions, triggers);
|
|
260
244
|
const existingSnapshot = (0, repo_manager_1.loadSnapshot)(projectRoot);
|
|
@@ -318,8 +302,91 @@ async function importCommand(sqlFilePath, options = {}, projectRoot = process.cw
|
|
|
318
302
|
changes = [];
|
|
319
303
|
console.log(`${git_utils_1.colors.cyan('First import')} - creating initial snapshot`);
|
|
320
304
|
}
|
|
321
|
-
const
|
|
322
|
-
|
|
305
|
+
const astSchema = (0, ast_transformer_1.normalizedToParsedSchema)({
|
|
306
|
+
tables: mergedSchema.tables.map(t => ({
|
|
307
|
+
name: t.name,
|
|
308
|
+
schema: t.schema,
|
|
309
|
+
columns: t.columns.map(c => ({
|
|
310
|
+
name: c.name,
|
|
311
|
+
type: c.type,
|
|
312
|
+
nullable: c.nullable,
|
|
313
|
+
default: c.default,
|
|
314
|
+
primaryKey: c.primaryKey,
|
|
315
|
+
unique: c.unique,
|
|
316
|
+
check: c.check,
|
|
317
|
+
checkName: c.checkName,
|
|
318
|
+
references: c.references,
|
|
319
|
+
comment: c.comment,
|
|
320
|
+
isGenerated: c.isGenerated,
|
|
321
|
+
generatedExpression: c.generationExpression,
|
|
322
|
+
generatedExpressionAst: c.generatedExpressionAst,
|
|
323
|
+
})),
|
|
324
|
+
indexes: t.indexes.map(i => ({
|
|
325
|
+
name: i.name,
|
|
326
|
+
columns: i.columns,
|
|
327
|
+
unique: i.unique,
|
|
328
|
+
type: i.type,
|
|
329
|
+
definition: i.definition,
|
|
330
|
+
whereClause: i.whereClause,
|
|
331
|
+
whereClauseAst: i.whereClauseAst,
|
|
332
|
+
})),
|
|
333
|
+
constraints: t.constraints?.map(c => ({
|
|
334
|
+
name: c.name,
|
|
335
|
+
type: c.type,
|
|
336
|
+
columns: c.columns,
|
|
337
|
+
definition: c.definition,
|
|
338
|
+
references: c.references,
|
|
339
|
+
})),
|
|
340
|
+
isPartitioned: t.isPartitioned,
|
|
341
|
+
partitionType: t.partitionType,
|
|
342
|
+
partitionKey: t.partitionKey,
|
|
343
|
+
comment: t.comment,
|
|
344
|
+
})),
|
|
345
|
+
enums: mergedSchema.enums.map(e => ({
|
|
346
|
+
name: e.name,
|
|
347
|
+
schema: e.schema,
|
|
348
|
+
values: e.values,
|
|
349
|
+
})),
|
|
350
|
+
domains: mergedSchema.domains?.map(d => ({
|
|
351
|
+
name: d.name,
|
|
352
|
+
baseType: d.baseType,
|
|
353
|
+
notNull: d.notNull,
|
|
354
|
+
default: d.default ?? undefined,
|
|
355
|
+
check: d.check ?? undefined,
|
|
356
|
+
checkName: d.checkName,
|
|
357
|
+
})),
|
|
358
|
+
sequences: mergedSchema.sequences?.map(s => ({
|
|
359
|
+
name: s.name,
|
|
360
|
+
start: s.start,
|
|
361
|
+
increment: s.increment,
|
|
362
|
+
minValue: s.minValue,
|
|
363
|
+
maxValue: s.maxValue,
|
|
364
|
+
cache: s.cache,
|
|
365
|
+
cycle: s.cycle,
|
|
366
|
+
})),
|
|
367
|
+
extensions: mergedSchema.extensions?.map(e => e.name),
|
|
368
|
+
functions: includeFunctions ? mergedSchema.functions?.map(f => ({
|
|
369
|
+
name: f.name,
|
|
370
|
+
schema: f.schema,
|
|
371
|
+
args: f.args || [],
|
|
372
|
+
returnType: f.returnType,
|
|
373
|
+
language: f.language,
|
|
374
|
+
body: f.body,
|
|
375
|
+
volatility: f.volatility,
|
|
376
|
+
isStrict: f.isStrict,
|
|
377
|
+
securityDefiner: f.securityDefiner,
|
|
378
|
+
})) : [],
|
|
379
|
+
triggers: includeTriggers ? mergedSchema.triggers?.map(t => ({
|
|
380
|
+
name: t.name,
|
|
381
|
+
table: t.table,
|
|
382
|
+
timing: t.timing,
|
|
383
|
+
events: t.events,
|
|
384
|
+
level: t.level,
|
|
385
|
+
functionName: t.functionName,
|
|
386
|
+
when: t.when,
|
|
387
|
+
})) : [],
|
|
388
|
+
});
|
|
389
|
+
const finalTypescriptContent = (0, ast_codegen_1.generateTypeScriptFromAST)(astSchema, {
|
|
323
390
|
camelCase: true,
|
|
324
391
|
includeFunctions,
|
|
325
392
|
includeTriggers,
|
|
@@ -347,6 +414,7 @@ async function importCommand(sqlFilePath, options = {}, projectRoot = process.cw
|
|
|
347
414
|
}
|
|
348
415
|
fs.writeFileSync(absoluteOutputPath, finalTypescriptContent, 'utf-8');
|
|
349
416
|
console.log(`Written ${git_utils_1.colors.cyan(absoluteOutputPath)} ${git_utils_1.colors.gray(`(${(0, git_utils_1.formatBytes)(finalTypescriptContent.length)})`)}`);
|
|
417
|
+
applyTrackingIdsToSnapshot(finalTypescriptContent, mergedSchema);
|
|
350
418
|
(0, repo_manager_1.saveSnapshot)(mergedSchema, projectRoot);
|
|
351
419
|
if (changes.length > 0) {
|
|
352
420
|
(0, repo_manager_1.addUnstagedChanges)(changes, projectRoot);
|
|
@@ -395,36 +463,50 @@ function convertToDbSchema(parsed, functions = [], triggers = [], comments = [])
|
|
|
395
463
|
return {
|
|
396
464
|
tables: parsed.tables.map(t => ({
|
|
397
465
|
name: t.name,
|
|
398
|
-
schema: t.schema,
|
|
466
|
+
schema: t.schema || 'public',
|
|
399
467
|
comment: tableComments.get(t.name) || null,
|
|
400
|
-
columns: t.columns
|
|
468
|
+
columns: t.columns
|
|
469
|
+
.filter(c => {
|
|
470
|
+
if (!c.type) {
|
|
471
|
+
console.warn(`Warning: Skipping column ${t.name}.${c.name} (no type)`);
|
|
472
|
+
return false;
|
|
473
|
+
}
|
|
474
|
+
return true;
|
|
475
|
+
})
|
|
476
|
+
.map(c => ({
|
|
401
477
|
name: c.name,
|
|
402
|
-
dataType: c.
|
|
403
|
-
udtName: c.
|
|
478
|
+
dataType: c.type,
|
|
479
|
+
udtName: c.type,
|
|
404
480
|
isNullable: c.isNullable,
|
|
405
|
-
defaultValue: c.defaultValue,
|
|
481
|
+
defaultValue: c.defaultValue ?? null,
|
|
406
482
|
isPrimaryKey: c.isPrimaryKey,
|
|
407
483
|
isUnique: c.isUnique,
|
|
408
|
-
maxLength: c.
|
|
409
|
-
precision: c.precision,
|
|
410
|
-
scale: c.scale,
|
|
484
|
+
maxLength: c.typeParams?.length ?? null,
|
|
485
|
+
precision: c.typeParams?.precision ?? null,
|
|
486
|
+
scale: c.typeParams?.scale ?? null,
|
|
411
487
|
references: c.references ? `${c.references.table}.${c.references.column}` : null,
|
|
412
488
|
comment: columnComments.get(`${t.name}.${c.name}`) || c.comment || null,
|
|
413
489
|
isGenerated: c.isGenerated || false,
|
|
414
|
-
generationExpression: c.
|
|
490
|
+
generationExpression: c.generatedExpression || null,
|
|
415
491
|
})),
|
|
416
492
|
indexes: t.indexes.map(idx => ({
|
|
417
493
|
name: idx.name,
|
|
418
494
|
columns: idx.columns,
|
|
419
495
|
isUnique: idx.isUnique,
|
|
420
|
-
isPrimary:
|
|
421
|
-
type: idx.
|
|
422
|
-
definition: idx.
|
|
496
|
+
isPrimary: false,
|
|
497
|
+
type: idx.method || 'btree',
|
|
498
|
+
definition: idx.expressions?.join(', ') || idx.columns.join(', '),
|
|
423
499
|
whereClause: idx.whereClause,
|
|
424
|
-
|
|
500
|
+
whereClauseAst: idx.whereClauseAst,
|
|
501
|
+
expression: idx.expressions?.[0],
|
|
425
502
|
comment: indexComments.get(idx.name) || null,
|
|
426
503
|
})),
|
|
427
|
-
constraints: t.constraints
|
|
504
|
+
constraints: t.constraints.map(c => ({
|
|
505
|
+
name: c.name,
|
|
506
|
+
type: c.type,
|
|
507
|
+
columns: c.columns,
|
|
508
|
+
definition: c.expression || c.columns.join(', '),
|
|
509
|
+
})),
|
|
428
510
|
rowCount: 0,
|
|
429
511
|
isPartitioned: t.isPartitioned,
|
|
430
512
|
partitionType: t.partitionType,
|
|
@@ -434,34 +516,31 @@ function convertToDbSchema(parsed, functions = [], triggers = [], comments = [])
|
|
|
434
516
|
name: e.name,
|
|
435
517
|
values: e.values,
|
|
436
518
|
})),
|
|
437
|
-
domains: parsed.domains
|
|
519
|
+
domains: parsed.domains.map(d => ({
|
|
438
520
|
name: d.name,
|
|
439
521
|
baseType: d.baseType,
|
|
440
522
|
isNotNull: d.notNull || false,
|
|
441
|
-
defaultValue: d.
|
|
442
|
-
checkExpression: d.
|
|
443
|
-
check: d.
|
|
444
|
-
default: d.
|
|
523
|
+
defaultValue: d.defaultValue || null,
|
|
524
|
+
checkExpression: d.checkExpression || null,
|
|
525
|
+
check: d.checkExpression,
|
|
526
|
+
default: d.defaultValue,
|
|
445
527
|
notNull: d.notNull,
|
|
446
|
-
}))
|
|
447
|
-
compositeTypes:
|
|
448
|
-
|
|
449
|
-
attributes: c.attributes || [],
|
|
450
|
-
})) || [],
|
|
451
|
-
sequences: parsed.sequences?.map((s) => ({
|
|
528
|
+
})),
|
|
529
|
+
compositeTypes: [],
|
|
530
|
+
sequences: parsed.sequences.map(s => ({
|
|
452
531
|
name: s.name,
|
|
453
|
-
dataType:
|
|
454
|
-
start: s.
|
|
532
|
+
dataType: 'bigint',
|
|
533
|
+
start: s.startValue,
|
|
455
534
|
increment: s.increment,
|
|
456
535
|
minValue: s.minValue,
|
|
457
536
|
maxValue: s.maxValue,
|
|
458
537
|
cache: s.cache,
|
|
459
538
|
cycle: s.cycle,
|
|
460
|
-
ownedBy: s.ownedBy,
|
|
461
|
-
}))
|
|
539
|
+
ownedBy: s.ownedBy ? `${s.ownedBy.table}.${s.ownedBy.column}` : undefined,
|
|
540
|
+
})),
|
|
462
541
|
collations: [],
|
|
463
542
|
extensions: parsed.extensions,
|
|
464
|
-
partitions:
|
|
543
|
+
partitions: [],
|
|
465
544
|
functions: functions.map(f => ({
|
|
466
545
|
...f,
|
|
467
546
|
comment: functionComments.get(f.name) || null,
|
|
@@ -476,79 +555,95 @@ function convertToDbSchema(parsed, functions = [], triggers = [], comments = [])
|
|
|
476
555
|
};
|
|
477
556
|
}
|
|
478
557
|
function convertToNormalizedSchema(parsed, functions = [], triggers = []) {
|
|
558
|
+
const regularViews = parsed.views.filter(v => !v.isMaterialized);
|
|
559
|
+
const materializedViews = parsed.views.filter(v => v.isMaterialized);
|
|
479
560
|
return {
|
|
480
561
|
extensions: parsed.extensions.map(ext => ({ name: ext })),
|
|
481
562
|
enums: parsed.enums.map(e => ({
|
|
482
563
|
name: e.name,
|
|
483
|
-
schema: 'public',
|
|
564
|
+
schema: e.schema || 'public',
|
|
484
565
|
values: e.values,
|
|
485
566
|
})),
|
|
486
567
|
domains: parsed.domains.map(d => ({
|
|
487
568
|
name: d.name,
|
|
488
|
-
schema: 'public',
|
|
569
|
+
schema: d.schema || 'public',
|
|
489
570
|
baseType: d.baseType,
|
|
490
571
|
notNull: d.notNull || false,
|
|
491
|
-
default: d.
|
|
492
|
-
check: d.
|
|
493
|
-
})),
|
|
494
|
-
compositeTypes: parsed.compositeTypes.map(c => ({
|
|
495
|
-
name: c.name,
|
|
496
|
-
schema: 'public',
|
|
497
|
-
attributes: c.attributes,
|
|
572
|
+
default: d.defaultValue || null,
|
|
573
|
+
check: d.checkExpression || null,
|
|
498
574
|
})),
|
|
575
|
+
compositeTypes: [],
|
|
499
576
|
sequences: parsed.sequences.map(s => ({
|
|
500
577
|
name: s.name,
|
|
501
|
-
schema: 'public',
|
|
578
|
+
schema: s.schema || 'public',
|
|
502
579
|
dataType: 'bigint',
|
|
503
|
-
startValue: s.
|
|
580
|
+
startValue: s.startValue || 1,
|
|
504
581
|
increment: s.increment || 1,
|
|
505
582
|
minValue: s.minValue || null,
|
|
506
583
|
maxValue: s.maxValue || null,
|
|
507
|
-
cache: 1,
|
|
508
|
-
cycle: false,
|
|
509
|
-
ownedBy: null,
|
|
584
|
+
cache: s.cache || 1,
|
|
585
|
+
cycle: s.cycle || false,
|
|
586
|
+
ownedBy: s.ownedBy ? `${s.ownedBy.table}.${s.ownedBy.column}` : null,
|
|
510
587
|
})),
|
|
511
588
|
collations: [],
|
|
512
589
|
tables: parsed.tables.map(t => {
|
|
513
|
-
const childPartitions = parsed.partitions.filter(p => p.parentTable === t.name);
|
|
514
590
|
return {
|
|
515
591
|
name: t.name,
|
|
516
|
-
schema: t.schema,
|
|
517
|
-
columns: t.columns.map(c =>
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
592
|
+
schema: t.schema || 'public',
|
|
593
|
+
columns: t.columns.map(c => {
|
|
594
|
+
const col = {
|
|
595
|
+
name: c.name,
|
|
596
|
+
tsName: toCamelCase(c.name),
|
|
597
|
+
type: c.type,
|
|
598
|
+
nullable: c.isNullable,
|
|
599
|
+
default: c.defaultValue,
|
|
600
|
+
primaryKey: c.isPrimaryKey,
|
|
601
|
+
unique: c.isUnique,
|
|
602
|
+
isGenerated: c.isGenerated,
|
|
603
|
+
generationExpression: c.generatedExpression,
|
|
604
|
+
generatedExpressionAst: c.generatedExpressionAst,
|
|
605
|
+
};
|
|
606
|
+
return col;
|
|
607
|
+
}),
|
|
531
608
|
indexes: t.indexes.map(idx => ({
|
|
532
609
|
name: idx.name,
|
|
533
610
|
columns: idx.columns,
|
|
534
611
|
unique: idx.isUnique,
|
|
535
|
-
type: idx.
|
|
536
|
-
definition: idx.
|
|
612
|
+
type: idx.method || 'btree',
|
|
613
|
+
definition: idx.expressions?.join(', ') || idx.columns.join(', '),
|
|
537
614
|
whereClause: idx.whereClause,
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
constraints: t.constraints.map(c => ({
|
|
541
|
-
name: c.name,
|
|
542
|
-
type: c.type,
|
|
543
|
-
definition: c.definition,
|
|
615
|
+
whereClauseAst: idx.whereClauseAst,
|
|
616
|
+
expression: idx.expressions?.[0],
|
|
544
617
|
})),
|
|
618
|
+
constraints: t.constraints.map(c => {
|
|
619
|
+
const base = {
|
|
620
|
+
name: c.name,
|
|
621
|
+
type: c.type,
|
|
622
|
+
definition: c.expression || c.columns.join(', '),
|
|
623
|
+
columns: c.columns,
|
|
624
|
+
};
|
|
625
|
+
if (c.type === 'FOREIGN KEY' && c.references) {
|
|
626
|
+
base.referencedTable = c.references.table;
|
|
627
|
+
base.referencedColumns = c.references.columns;
|
|
628
|
+
if (c.references.onDelete)
|
|
629
|
+
base.onDelete = c.references.onDelete;
|
|
630
|
+
if (c.references.onUpdate)
|
|
631
|
+
base.onUpdate = c.references.onUpdate;
|
|
632
|
+
if (c.references.match)
|
|
633
|
+
base.matchType = c.references.match;
|
|
634
|
+
if (c.references.deferrable)
|
|
635
|
+
base.deferrable = c.references.deferrable;
|
|
636
|
+
if (c.references.initiallyDeferred)
|
|
637
|
+
base.initiallyDeferred = c.references.initiallyDeferred;
|
|
638
|
+
}
|
|
639
|
+
if (c.type === 'CHECK' && c.expression) {
|
|
640
|
+
base.checkExpression = c.expression;
|
|
641
|
+
}
|
|
642
|
+
return base;
|
|
643
|
+
}),
|
|
545
644
|
isPartitioned: t.isPartitioned,
|
|
546
645
|
partitionType: t.partitionType,
|
|
547
646
|
partitionKey: t.partitionKey,
|
|
548
|
-
partitions: childPartitions.length > 0 ? childPartitions.map(p => ({
|
|
549
|
-
name: p.name,
|
|
550
|
-
bound: p.partitionBound || '',
|
|
551
|
-
})) : undefined,
|
|
552
647
|
};
|
|
553
648
|
}),
|
|
554
649
|
functions: functions.map(f => ({
|
|
@@ -565,16 +660,16 @@ function convertToNormalizedSchema(parsed, functions = [], triggers = []) {
|
|
|
565
660
|
forEach: 'STATEMENT',
|
|
566
661
|
functionName: t.functionName || '',
|
|
567
662
|
})),
|
|
568
|
-
views:
|
|
663
|
+
views: regularViews.map(v => ({
|
|
569
664
|
name: v.name,
|
|
570
665
|
schema: v.schema || 'public',
|
|
571
666
|
definition: v.definition,
|
|
572
667
|
})),
|
|
573
|
-
materializedViews:
|
|
668
|
+
materializedViews: materializedViews.map(mv => ({
|
|
574
669
|
name: mv.name,
|
|
575
670
|
schema: mv.schema || 'public',
|
|
576
671
|
definition: mv.definition,
|
|
577
|
-
withData:
|
|
672
|
+
withData: true,
|
|
578
673
|
})),
|
|
579
674
|
};
|
|
580
675
|
}
|
|
@@ -686,6 +781,7 @@ function snapshotToDbSchemaForGeneration(snapshot) {
|
|
|
686
781
|
type: i.type || 'btree',
|
|
687
782
|
definition: i.definition,
|
|
688
783
|
whereClause: i.whereClause,
|
|
784
|
+
whereClauseAst: i.whereClauseAst,
|
|
689
785
|
comment: null,
|
|
690
786
|
})),
|
|
691
787
|
constraints: t.constraints?.map(c => ({
|
|
@@ -785,4 +881,27 @@ function mergeSchemas(existing, incoming, replaceAll = false) {
|
|
|
785
881
|
foreignTables: mergeByName(existing.foreignTables || [], incoming.foreignTables || []),
|
|
786
882
|
};
|
|
787
883
|
}
|
|
884
|
+
function applyTrackingIdsToSnapshot(typescript, snapshot) {
|
|
885
|
+
for (const table of snapshot.tables) {
|
|
886
|
+
const tablePattern = new RegExp(`defineTable\\s*\\(\\s*['"]${table.name}['"]\\s*,\\s*\\{[^}]+\\}\\s*,\\s*\\{[^}]*\\$trackingId:\\s*['"]([^'"]+)['"]`, 's');
|
|
887
|
+
const tableMatch = typescript.match(tablePattern);
|
|
888
|
+
if (tableMatch) {
|
|
889
|
+
table.trackingId = tableMatch[1];
|
|
890
|
+
}
|
|
891
|
+
for (const col of table.columns) {
|
|
892
|
+
const colPattern = new RegExp(`(?:${col.tsName}|${col.name}):\\s*\\w+\\([^)]*\\)[^\\n]*\\.\\\$id\\(['"]([^'"]+)['"]\\)`);
|
|
893
|
+
const colMatch = typescript.match(colPattern);
|
|
894
|
+
if (colMatch) {
|
|
895
|
+
col.trackingId = colMatch[1];
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
for (const idx of table.indexes) {
|
|
899
|
+
const idxPattern = new RegExp(`index\\s*\\(\\s*['"]${idx.name}['"]\\s*\\)[^\\n]*\\.\\\$id\\(['"]([^'"]+)['"]\\)`);
|
|
900
|
+
const idxMatch = typescript.match(idxPattern);
|
|
901
|
+
if (idxMatch) {
|
|
902
|
+
idx.trackingId = idxMatch[1];
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
}
|
|
788
907
|
exports.default = importCommand;
|
|
@@ -84,21 +84,69 @@ function checkEnvVars() {
|
|
|
84
84
|
DATABASE_NAME: process.env.DATABASE_NAME,
|
|
85
85
|
DATABASE_USER: process.env.DATABASE_USER,
|
|
86
86
|
DATABASE_PASSWORD: process.env.DATABASE_PASSWORD,
|
|
87
|
+
DATABASE_REGION: process.env.DATABASE_REGION,
|
|
88
|
+
AWS_DATABASE_HOST: process.env.AWS_DATABASE_HOST,
|
|
89
|
+
AWS_ACCESS_KEY_ID: process.env.AWS_ACCESS_KEY_ID,
|
|
90
|
+
AWS_DATABASE_USER: process.env.AWS_DATABASE_USER,
|
|
91
|
+
AWS_DATABASE_NAME: process.env.AWS_DATABASE_NAME,
|
|
92
|
+
AWS_DATABASE_PORT: process.env.AWS_DATABASE_PORT,
|
|
93
|
+
AWS_SECRET_ACCESS_KEY: process.env.AWS_SECRET_ACCESS_KEY,
|
|
87
94
|
RELQ_PG_CONN_URL: process.env.RELQ_PG_CONN_URL,
|
|
88
95
|
};
|
|
89
96
|
const hasConnUrl = !!vars.RELQ_PG_CONN_URL;
|
|
90
|
-
const hasIndividual = !!(vars.DATABASE_HOST && vars.DATABASE_NAME);
|
|
97
|
+
const hasIndividual = !!(vars.DATABASE_HOST && vars.DATABASE_NAME && vars.DATABASE_USER && vars.DATABASE_PASSWORD);
|
|
98
|
+
const hasAws = !!(vars.AWS_ACCESS_KEY_ID && vars.AWS_SECRET_ACCESS_KEY && vars.DATABASE_REGION && vars.AWS_DATABASE_NAME && vars.AWS_DATABASE_HOST);
|
|
91
99
|
return {
|
|
92
|
-
found: hasConnUrl || hasIndividual,
|
|
100
|
+
found: hasConnUrl || hasIndividual || hasAws,
|
|
101
|
+
hasConnUrl,
|
|
102
|
+
hasIndividual,
|
|
103
|
+
hasAws,
|
|
93
104
|
vars,
|
|
94
105
|
};
|
|
95
106
|
}
|
|
107
|
+
async function askConnectionType(rl, options) {
|
|
108
|
+
const choices = [];
|
|
109
|
+
if (options.hasConnUrl) {
|
|
110
|
+
choices.push({ key: String(choices.length + 1), label: 'Connection URL (RELQ_PG_CONN_URL)', value: 'url' });
|
|
111
|
+
}
|
|
112
|
+
if (options.hasIndividual) {
|
|
113
|
+
choices.push({ key: String(choices.length + 1), label: 'Individual Config (DATABASE_HOST, DATABASE_NAME, ...)', value: 'individual' });
|
|
114
|
+
}
|
|
115
|
+
if (options.hasAws) {
|
|
116
|
+
choices.push({ key: String(choices.length + 1), label: 'AWS DSQL (AWS_ACCESS_KEY_ID, DATABASE_REGION, ...)', value: 'aws' });
|
|
117
|
+
}
|
|
118
|
+
if (choices.length === 1) {
|
|
119
|
+
return choices[0].value;
|
|
120
|
+
}
|
|
121
|
+
console.log('Multiple connection options found:');
|
|
122
|
+
console.log('');
|
|
123
|
+
for (const choice of choices) {
|
|
124
|
+
console.log(` ${cli_utils_1.colors.cyan(choice.key)}. ${choice.label}`);
|
|
125
|
+
}
|
|
126
|
+
console.log('');
|
|
127
|
+
const answer = await ask(rl, `Which connection type? [${choices.map(c => c.key).join('/')}]`, '1');
|
|
128
|
+
const selected = choices.find(c => c.key === answer);
|
|
129
|
+
return selected?.value ?? choices[0].value;
|
|
130
|
+
}
|
|
96
131
|
function generateConfig(options) {
|
|
97
132
|
let connectionBlock;
|
|
98
133
|
if (options.useEnv) {
|
|
99
|
-
if (
|
|
134
|
+
if (options.connectionType === 'url') {
|
|
100
135
|
connectionBlock = ` connection: {
|
|
101
136
|
url: process.env.RELQ_PG_CONN_URL,
|
|
137
|
+
},`;
|
|
138
|
+
}
|
|
139
|
+
else if (options.connectionType === 'aws') {
|
|
140
|
+
connectionBlock = ` connection: {
|
|
141
|
+
database: process.env.AWS_DATABASE_NAME,
|
|
142
|
+
aws: {
|
|
143
|
+
hostname: process.env.AWS_DATABASE_HOST!,
|
|
144
|
+
region: process.env.DATABASE_REGION!,
|
|
145
|
+
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
|
|
146
|
+
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
|
|
147
|
+
user: process.env.AWS_DATABASE_USER || 'admin',
|
|
148
|
+
port: parseInt(process.env.AWS_DATABASE_PORT || '5432'),
|
|
149
|
+
},
|
|
102
150
|
},`;
|
|
103
151
|
}
|
|
104
152
|
else {
|
|
@@ -323,30 +371,53 @@ async function initCommand(context) {
|
|
|
323
371
|
console.log('');
|
|
324
372
|
const envCheck = checkEnvVars();
|
|
325
373
|
let useEnv = false;
|
|
374
|
+
let connectionType = 'individual';
|
|
326
375
|
let host = 'localhost';
|
|
327
376
|
let port = '5432';
|
|
328
377
|
let database = '';
|
|
329
378
|
let user = 'postgres';
|
|
330
379
|
let password = '';
|
|
331
380
|
if (envCheck.found) {
|
|
332
|
-
console.log('Found database
|
|
333
|
-
|
|
334
|
-
|
|
381
|
+
console.log('Found database connection options:');
|
|
382
|
+
console.log('');
|
|
383
|
+
if (envCheck.hasConnUrl) {
|
|
384
|
+
console.log(` ${cli_utils_1.colors.cyan('Connection URL')}`);
|
|
385
|
+
console.log(` RELQ_PG_CONN_URL: ${envCheck.vars.RELQ_PG_CONN_URL?.substring(0, 40)}...`);
|
|
335
386
|
}
|
|
336
|
-
|
|
387
|
+
if (envCheck.hasIndividual) {
|
|
388
|
+
console.log(` ${cli_utils_1.colors.cyan('Individual Config')}`);
|
|
337
389
|
if (envCheck.vars.DATABASE_HOST)
|
|
338
|
-
console.log(`
|
|
339
|
-
if (envCheck.vars.DATABASE_PORT)
|
|
340
|
-
console.log(` DATABASE_PORT: ${envCheck.vars.DATABASE_PORT}`);
|
|
390
|
+
console.log(` DATABASE_HOST: ${envCheck.vars.DATABASE_HOST}`);
|
|
341
391
|
if (envCheck.vars.DATABASE_NAME)
|
|
342
|
-
console.log(`
|
|
392
|
+
console.log(` DATABASE_NAME: ${envCheck.vars.DATABASE_NAME}`);
|
|
343
393
|
if (envCheck.vars.DATABASE_USER)
|
|
344
|
-
console.log(`
|
|
394
|
+
console.log(` DATABASE_USER: ${envCheck.vars.DATABASE_USER}`);
|
|
345
395
|
if (envCheck.vars.DATABASE_PASSWORD)
|
|
346
|
-
console.log('
|
|
396
|
+
console.log(' DATABASE_PASSWORD: ***');
|
|
397
|
+
}
|
|
398
|
+
if (envCheck.hasAws) {
|
|
399
|
+
console.log(` ${cli_utils_1.colors.cyan('AWS DSQL')}`);
|
|
400
|
+
if (envCheck.vars.AWS_DATABASE_HOST)
|
|
401
|
+
console.log(` AWS_DATABASE_HOST: ${envCheck.vars.AWS_DATABASE_HOST}`);
|
|
402
|
+
if (envCheck.vars.DATABASE_REGION)
|
|
403
|
+
console.log(` DATABASE_REGION: ${envCheck.vars.DATABASE_REGION}`);
|
|
404
|
+
if (envCheck.vars.AWS_DATABASE_NAME)
|
|
405
|
+
console.log(` AWS_DATABASE_NAME: ${envCheck.vars.AWS_DATABASE_NAME}`);
|
|
406
|
+
if (envCheck.vars.AWS_ACCESS_KEY_ID)
|
|
407
|
+
console.log(` AWS_ACCESS_KEY_ID: ${envCheck.vars.AWS_ACCESS_KEY_ID?.substring(0, 8)}...`);
|
|
408
|
+
console.log(' AWS_SECRET_ACCESS_KEY: ***');
|
|
347
409
|
}
|
|
348
410
|
console.log('');
|
|
349
|
-
|
|
411
|
+
const optionCount = [envCheck.hasConnUrl, envCheck.hasIndividual, envCheck.hasAws].filter(Boolean).length;
|
|
412
|
+
if (optionCount > 1) {
|
|
413
|
+
connectionType = await askConnectionType(rl, envCheck);
|
|
414
|
+
console.log('');
|
|
415
|
+
useEnv = await askYesNo(rl, `Use ${connectionType === 'aws' ? 'AWS DSQL' : connectionType === 'url' ? 'Connection URL' : 'Individual Config'} from environment?`, true);
|
|
416
|
+
}
|
|
417
|
+
else {
|
|
418
|
+
connectionType = envCheck.hasConnUrl ? 'url' : envCheck.hasAws ? 'aws' : 'individual';
|
|
419
|
+
useEnv = await askYesNo(rl, 'Use these environment variables?', true);
|
|
420
|
+
}
|
|
350
421
|
console.log('');
|
|
351
422
|
}
|
|
352
423
|
if (!useEnv) {
|
|
@@ -380,6 +451,7 @@ async function initCommand(context) {
|
|
|
380
451
|
if (!fs.existsSync(configPath)) {
|
|
381
452
|
const configContent = generateConfig({
|
|
382
453
|
useEnv,
|
|
454
|
+
connectionType,
|
|
383
455
|
host,
|
|
384
456
|
port,
|
|
385
457
|
database,
|