rake-db 2.2.6 → 2.3.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/CHANGELOG.md +13 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.esm.js +82 -64
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +82 -64
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/ast.ts +3 -3
- package/src/migration/changeTable.test.ts +10 -15
- package/src/migration/changeTable.ts +90 -77
- package/src/migration/createTable.test.ts +2 -3
- package/src/migration/migrationUtils.ts +28 -22
- package/src/pull/dbStructure.test.ts +14 -6
- package/src/pull/dbStructure.ts +167 -47
- package/src/pull/structureToAst.test.ts +203 -35
- package/src/pull/structureToAst.ts +69 -18
|
@@ -78,9 +78,8 @@ describe('changeTable', () => {
|
|
|
78
78
|
name: 'indexName',
|
|
79
79
|
unique: true,
|
|
80
80
|
using: 'gin',
|
|
81
|
-
expression: 10,
|
|
82
81
|
collate: 'utf-8',
|
|
83
|
-
|
|
82
|
+
opclass: 'opclass',
|
|
84
83
|
order: 'ASC',
|
|
85
84
|
include: 'id',
|
|
86
85
|
with: 'fillfactor = 70',
|
|
@@ -133,7 +132,7 @@ describe('changeTable', () => {
|
|
|
133
132
|
CREATE UNIQUE INDEX "indexName"
|
|
134
133
|
ON "table"
|
|
135
134
|
USING gin
|
|
136
|
-
("withIndex"
|
|
135
|
+
("withIndex" COLLATE 'utf-8' opclass ASC)
|
|
137
136
|
INCLUDE ("id")
|
|
138
137
|
WITH (fillfactor = 70)
|
|
139
138
|
TABLESPACE tablespace
|
|
@@ -604,9 +603,8 @@ describe('changeTable', () => {
|
|
|
604
603
|
addIndexWithOptions: t.change(
|
|
605
604
|
t.integer(),
|
|
606
605
|
t.integer().index({
|
|
607
|
-
expression: 'expression',
|
|
608
606
|
collate: 'collate',
|
|
609
|
-
|
|
607
|
+
opclass: 'opclass',
|
|
610
608
|
order: 'order',
|
|
611
609
|
unique: true,
|
|
612
610
|
using: 'using',
|
|
@@ -620,9 +618,8 @@ describe('changeTable', () => {
|
|
|
620
618
|
removeIndex: t.change(t.integer().index(), t.integer()),
|
|
621
619
|
removeIndexWithOptions: t.change(
|
|
622
620
|
t.integer().index({
|
|
623
|
-
expression: 'expression',
|
|
624
621
|
collate: 'collate',
|
|
625
|
-
|
|
622
|
+
opclass: 'opclass',
|
|
626
623
|
order: 'order',
|
|
627
624
|
unique: true,
|
|
628
625
|
using: 'using',
|
|
@@ -637,9 +634,8 @@ describe('changeTable', () => {
|
|
|
637
634
|
changeIndex: t.change(
|
|
638
635
|
t.integer().index({
|
|
639
636
|
name: 'from',
|
|
640
|
-
expression: 'from',
|
|
641
637
|
collate: 'from',
|
|
642
|
-
|
|
638
|
+
opclass: 'from',
|
|
643
639
|
order: 'from',
|
|
644
640
|
unique: false,
|
|
645
641
|
using: 'from',
|
|
@@ -651,9 +647,8 @@ describe('changeTable', () => {
|
|
|
651
647
|
}),
|
|
652
648
|
t.integer().index({
|
|
653
649
|
name: 'to',
|
|
654
|
-
expression: 'to',
|
|
655
650
|
collate: 'to',
|
|
656
|
-
|
|
651
|
+
opclass: 'to',
|
|
657
652
|
order: 'to',
|
|
658
653
|
unique: true,
|
|
659
654
|
using: 'to',
|
|
@@ -673,8 +668,8 @@ describe('changeTable', () => {
|
|
|
673
668
|
`DROP INDEX "tableRemoveIndexWithOptionsIndex" CASCADE`,
|
|
674
669
|
`DROP INDEX "from" CASCADE`,
|
|
675
670
|
`CREATE INDEX "tableAddIndexIndex" ON "table" ("addIndex")`,
|
|
676
|
-
`CREATE UNIQUE INDEX "tableAddIndexWithOptionsIndex" ON "table" USING using ("addIndexWithOptions"
|
|
677
|
-
`CREATE UNIQUE INDEX "to" ON "table" USING to ("changeIndex"
|
|
671
|
+
`CREATE UNIQUE INDEX "tableAddIndexWithOptionsIndex" ON "table" USING using ("addIndexWithOptions" COLLATE 'collate' opclass order) INCLUDE ("a", "b") WITH (with) TABLESPACE tablespace WHERE where`,
|
|
672
|
+
`CREATE UNIQUE INDEX "to" ON "table" USING to ("changeIndex" COLLATE 'to' to to) INCLUDE ("c", "d") WITH (to) TABLESPACE to WHERE to`,
|
|
678
673
|
]);
|
|
679
674
|
|
|
680
675
|
queryMock.mockClear();
|
|
@@ -685,8 +680,8 @@ describe('changeTable', () => {
|
|
|
685
680
|
`DROP INDEX "tableAddIndexWithOptionsIndex" CASCADE`,
|
|
686
681
|
`DROP INDEX "to" RESTRICT`,
|
|
687
682
|
`CREATE INDEX "tableRemoveIndexIndex" ON "table" ("removeIndex")`,
|
|
688
|
-
`CREATE UNIQUE INDEX "tableRemoveIndexWithOptionsIndex" ON "table" USING using ("removeIndexWithOptions"
|
|
689
|
-
`CREATE INDEX "from" ON "table" USING from ("changeIndex"
|
|
683
|
+
`CREATE UNIQUE INDEX "tableRemoveIndexWithOptionsIndex" ON "table" USING using ("removeIndexWithOptions" COLLATE 'collate' opclass order) INCLUDE ("a", "b") WITH (with) TABLESPACE tablespace WHERE where`,
|
|
684
|
+
`CREATE INDEX "from" ON "table" USING from ("changeIndex" COLLATE 'from' from from) INCLUDE ("a", "b") WITH (from) TABLESPACE from WHERE from`,
|
|
690
685
|
]);
|
|
691
686
|
});
|
|
692
687
|
|
|
@@ -127,8 +127,8 @@ const columnTypeToColumnChange = (
|
|
|
127
127
|
item: ColumnType | Change,
|
|
128
128
|
): RakeDbAst.ColumnChange => {
|
|
129
129
|
if (item instanceof ColumnType) {
|
|
130
|
-
const
|
|
131
|
-
if (
|
|
130
|
+
const foreignKeys = item.data.foreignKeys;
|
|
131
|
+
if (foreignKeys?.some((it) => 'fn' in it)) {
|
|
132
132
|
throw new Error('Callback in foreignKey is not allowed in migration');
|
|
133
133
|
}
|
|
134
134
|
|
|
@@ -138,7 +138,7 @@ const columnTypeToColumnChange = (
|
|
|
138
138
|
nullable: item.data.isNullable,
|
|
139
139
|
primaryKey: item.isPrimaryKey,
|
|
140
140
|
...item.data,
|
|
141
|
-
|
|
141
|
+
foreignKeys: foreignKeys as RakeDbAst.ColumnChange['foreignKeys'],
|
|
142
142
|
};
|
|
143
143
|
}
|
|
144
144
|
|
|
@@ -395,83 +395,96 @@ const astToQueries = (ast: RakeDbAst.ChangeTable): Sql[] => {
|
|
|
395
395
|
);
|
|
396
396
|
}
|
|
397
397
|
|
|
398
|
-
const
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
fromFkey
|
|
408
|
-
fromFkey
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
398
|
+
const foreignKeysLen = Math.max(
|
|
399
|
+
from.foreignKeys?.length || 0,
|
|
400
|
+
to.foreignKeys?.length || 0,
|
|
401
|
+
);
|
|
402
|
+
for (let i = 0; i < foreignKeysLen; i++) {
|
|
403
|
+
const fromFkey = from.foreignKeys?.[i];
|
|
404
|
+
const toFkey = to.foreignKeys?.[i];
|
|
405
|
+
|
|
406
|
+
if (
|
|
407
|
+
(fromFkey || toFkey) &&
|
|
408
|
+
(!fromFkey ||
|
|
409
|
+
!toFkey ||
|
|
410
|
+
fromFkey.name !== toFkey.name ||
|
|
411
|
+
fromFkey.match !== toFkey.match ||
|
|
412
|
+
fromFkey.onUpdate !== toFkey.onUpdate ||
|
|
413
|
+
fromFkey.onDelete !== toFkey.onDelete ||
|
|
414
|
+
fromFkey.dropMode !== toFkey.dropMode ||
|
|
415
|
+
fromFkey.table !== toFkey.table ||
|
|
416
|
+
fromFkey.columns.join(',') !== toFkey.columns.join(','))
|
|
417
|
+
) {
|
|
418
|
+
if (fromFkey) {
|
|
419
|
+
dropForeignKeys.push({
|
|
420
|
+
columns: [key],
|
|
421
|
+
fnOrTable: fromFkey.table,
|
|
422
|
+
foreignColumns: fromFkey.columns,
|
|
423
|
+
options: fromFkey,
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
if (toFkey) {
|
|
428
|
+
addForeignKeys.push({
|
|
429
|
+
columns: [key],
|
|
430
|
+
fnOrTable: toFkey.table,
|
|
431
|
+
foreignColumns: toFkey.columns,
|
|
432
|
+
options: toFkey,
|
|
433
|
+
});
|
|
434
|
+
}
|
|
428
435
|
}
|
|
429
436
|
}
|
|
430
437
|
|
|
431
|
-
const
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
fromIndex
|
|
441
|
-
fromIndex
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
fromIndex.
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
438
|
+
const indexesLen = Math.max(
|
|
439
|
+
from.indexes?.length || 0,
|
|
440
|
+
to.indexes?.length || 0,
|
|
441
|
+
);
|
|
442
|
+
for (let i = 0; i < indexesLen; i++) {
|
|
443
|
+
const fromIndex = from.indexes?.[i];
|
|
444
|
+
const toIndex = to.indexes?.[i];
|
|
445
|
+
|
|
446
|
+
if (
|
|
447
|
+
(fromIndex || toIndex) &&
|
|
448
|
+
(!fromIndex ||
|
|
449
|
+
!toIndex ||
|
|
450
|
+
fromIndex.collate !== toIndex.collate ||
|
|
451
|
+
fromIndex.opclass !== toIndex.opclass ||
|
|
452
|
+
fromIndex.order !== toIndex.order ||
|
|
453
|
+
fromIndex.name !== toIndex.name ||
|
|
454
|
+
fromIndex.unique !== toIndex.unique ||
|
|
455
|
+
fromIndex.using !== toIndex.using ||
|
|
456
|
+
fromIndex.include !== toIndex.include ||
|
|
457
|
+
(Array.isArray(fromIndex.include) &&
|
|
458
|
+
Array.isArray(toIndex.include) &&
|
|
459
|
+
fromIndex.include.join(',') !== toIndex.include.join(',')) ||
|
|
460
|
+
fromIndex.with !== toIndex.with ||
|
|
461
|
+
fromIndex.tablespace !== toIndex.tablespace ||
|
|
462
|
+
fromIndex.where !== toIndex.where ||
|
|
463
|
+
fromIndex.dropMode !== toIndex.dropMode)
|
|
464
|
+
) {
|
|
465
|
+
if (fromIndex) {
|
|
466
|
+
dropIndexes.push({
|
|
467
|
+
columns: [
|
|
468
|
+
{
|
|
469
|
+
column: key,
|
|
470
|
+
...fromIndex,
|
|
471
|
+
},
|
|
472
|
+
],
|
|
473
|
+
options: fromIndex,
|
|
474
|
+
});
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
if (toIndex) {
|
|
478
|
+
addIndexes.push({
|
|
479
|
+
columns: [
|
|
480
|
+
{
|
|
481
|
+
column: key,
|
|
482
|
+
...toIndex,
|
|
483
|
+
},
|
|
484
|
+
],
|
|
485
|
+
options: toIndex,
|
|
486
|
+
});
|
|
487
|
+
}
|
|
475
488
|
}
|
|
476
489
|
}
|
|
477
490
|
|
|
@@ -63,9 +63,8 @@ const db = getDb();
|
|
|
63
63
|
name: 'indexName',
|
|
64
64
|
unique: true,
|
|
65
65
|
using: 'gin',
|
|
66
|
-
expression: 10,
|
|
67
66
|
collate: 'utf-8',
|
|
68
|
-
|
|
67
|
+
opclass: 'opclass',
|
|
69
68
|
order: 'ASC',
|
|
70
69
|
include: 'id',
|
|
71
70
|
with: 'fillfactor = 70',
|
|
@@ -113,7 +112,7 @@ const db = getDb();
|
|
|
113
112
|
CREATE UNIQUE INDEX "indexName"
|
|
114
113
|
ON "table"
|
|
115
114
|
USING gin
|
|
116
|
-
("withIndex"
|
|
115
|
+
("withIndex" COLLATE 'utf-8' opclass ASC)
|
|
117
116
|
INCLUDE ("id")
|
|
118
117
|
WITH (fillfactor = 70)
|
|
119
118
|
TABLESPACE tablespace
|
|
@@ -51,17 +51,19 @@ export const columnToSql = (
|
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
const {
|
|
55
|
-
if (
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
|
|
54
|
+
const { foreignKeys } = item.data;
|
|
55
|
+
if (foreignKeys) {
|
|
56
|
+
for (const foreignKey of foreignKeys) {
|
|
57
|
+
const [schema, table] = getForeignKeyTable(
|
|
58
|
+
'fn' in foreignKey ? foreignKey.fn : foreignKey.table,
|
|
59
|
+
);
|
|
59
60
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
61
|
+
if (foreignKey.name) {
|
|
62
|
+
line.push(`CONSTRAINT "${foreignKey.name}"`);
|
|
63
|
+
}
|
|
63
64
|
|
|
64
|
-
|
|
65
|
+
line.push(referencesToSql(schema, table, foreignKey.columns, foreignKey));
|
|
66
|
+
}
|
|
65
67
|
}
|
|
66
68
|
|
|
67
69
|
return line.join(' ');
|
|
@@ -72,13 +74,13 @@ export const addColumnIndex = (
|
|
|
72
74
|
key: string,
|
|
73
75
|
item: ColumnType,
|
|
74
76
|
) => {
|
|
75
|
-
if (item.data) {
|
|
76
|
-
|
|
77
|
-
indexes.
|
|
78
|
-
columns: [{ ...
|
|
79
|
-
options:
|
|
80
|
-
})
|
|
81
|
-
|
|
77
|
+
if (item.data.indexes) {
|
|
78
|
+
indexes.push(
|
|
79
|
+
...item.data.indexes.map((index) => ({
|
|
80
|
+
columns: [{ ...index, column: key }],
|
|
81
|
+
options: index,
|
|
82
|
+
})),
|
|
83
|
+
);
|
|
82
84
|
}
|
|
83
85
|
};
|
|
84
86
|
|
|
@@ -162,7 +164,13 @@ export const indexesToQuery = (
|
|
|
162
164
|
return indexes.map(({ columns, options }) => {
|
|
163
165
|
const indexName =
|
|
164
166
|
options.name ||
|
|
165
|
-
joinWords(
|
|
167
|
+
joinWords(
|
|
168
|
+
name,
|
|
169
|
+
...columns
|
|
170
|
+
.filter((it): it is { column: string } => 'column' in it)
|
|
171
|
+
.map((it) => it.column),
|
|
172
|
+
'index',
|
|
173
|
+
);
|
|
166
174
|
|
|
167
175
|
if (!up) {
|
|
168
176
|
return {
|
|
@@ -191,17 +199,15 @@ export const indexesToQuery = (
|
|
|
191
199
|
|
|
192
200
|
columns.forEach((column) => {
|
|
193
201
|
const columnSql: string[] = [
|
|
194
|
-
`"${column.column}"${
|
|
195
|
-
column.expression ? `(${column.expression})` : ''
|
|
196
|
-
}`,
|
|
202
|
+
'column' in column ? `"${column.column}"` : `(${column.expression})`,
|
|
197
203
|
];
|
|
198
204
|
|
|
199
205
|
if (column.collate) {
|
|
200
206
|
columnSql.push(`COLLATE '${column.collate}'`);
|
|
201
207
|
}
|
|
202
208
|
|
|
203
|
-
if (column.
|
|
204
|
-
columnSql.push(column.
|
|
209
|
+
if (column.opclass) {
|
|
210
|
+
columnSql.push(column.opclass);
|
|
205
211
|
}
|
|
206
212
|
|
|
207
213
|
if (column.order) {
|
|
@@ -20,7 +20,7 @@ describe('dbStructure', () => {
|
|
|
20
20
|
|
|
21
21
|
describe('getTables', () => {
|
|
22
22
|
it('should return tables', async () => {
|
|
23
|
-
rows = [{ schemaName: 'schema', name: 'table' }];
|
|
23
|
+
rows = [{ schemaName: 'schema', name: 'table', comment: 'comment' }];
|
|
24
24
|
const result = await db.getTables();
|
|
25
25
|
expect(result).toEqual(rows);
|
|
26
26
|
});
|
|
@@ -65,6 +65,9 @@ describe('dbStructure', () => {
|
|
|
65
65
|
type: 'int4',
|
|
66
66
|
default: '123',
|
|
67
67
|
isNullable: false,
|
|
68
|
+
collation: 'en_US',
|
|
69
|
+
compression: 'p',
|
|
70
|
+
comment: 'column comment',
|
|
68
71
|
},
|
|
69
72
|
];
|
|
70
73
|
const result = await db.getColumns();
|
|
@@ -78,10 +81,13 @@ describe('dbStructure', () => {
|
|
|
78
81
|
{
|
|
79
82
|
schemaName: 'public',
|
|
80
83
|
tableName: 'table',
|
|
81
|
-
columnNames: ['column'],
|
|
82
84
|
name: 'indexName',
|
|
83
85
|
isUnique: true,
|
|
84
|
-
|
|
86
|
+
columns: [{ column: 'column' }],
|
|
87
|
+
include: null,
|
|
88
|
+
with: null,
|
|
89
|
+
tablespace: null,
|
|
90
|
+
where: null,
|
|
85
91
|
},
|
|
86
92
|
];
|
|
87
93
|
const result = await db.getIndexes();
|
|
@@ -100,6 +106,9 @@ describe('dbStructure', () => {
|
|
|
100
106
|
name: 'name',
|
|
101
107
|
columnNames: ['column'],
|
|
102
108
|
foreignColumnNames: ['foreignColumn'],
|
|
109
|
+
match: 's',
|
|
110
|
+
onUpdate: 'a',
|
|
111
|
+
onDelete: 'a',
|
|
103
112
|
},
|
|
104
113
|
];
|
|
105
114
|
const result = await db.getForeignKeys();
|
|
@@ -107,18 +116,17 @@ describe('dbStructure', () => {
|
|
|
107
116
|
});
|
|
108
117
|
});
|
|
109
118
|
|
|
110
|
-
describe('
|
|
119
|
+
describe('getPrimaryKeys', () => {
|
|
111
120
|
it('should return constraints', async () => {
|
|
112
121
|
rows = [
|
|
113
122
|
{
|
|
114
123
|
schemaName: 'public',
|
|
115
124
|
tableName: 'table',
|
|
116
125
|
name: 'name',
|
|
117
|
-
type: 'PRIMARY KEY',
|
|
118
126
|
columnNames: ['id'],
|
|
119
127
|
},
|
|
120
128
|
];
|
|
121
|
-
const result = await db.
|
|
129
|
+
const result = await db.getPrimaryKeys();
|
|
122
130
|
expect(result).toEqual(rows);
|
|
123
131
|
});
|
|
124
132
|
});
|