rake-db 2.3.1 → 2.3.2
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 +8 -0
- package/dist/index.esm.js +26 -8
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +25 -7
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/pull/astToMigration.test.ts +35 -0
- package/src/pull/astToMigration.ts +29 -1
- package/src/pull/pull.test.ts +19 -0
- package/src/pull/pull.ts +5 -1
- package/src/pull/structureToAst.test.ts +36 -7
- package/src/pull/structureToAst.ts +8 -5
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rake-db",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.2",
|
|
4
4
|
"description": "Migrations tool for Postgresql DB",
|
|
5
5
|
"homepage": "https://orchid-orm.netlify.app/guide/migration-setup-and-overview.html",
|
|
6
6
|
"repository": {
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"dependencies": {
|
|
43
43
|
"enquirer": "^2.3.6",
|
|
44
44
|
"pluralize": "^8.0.0",
|
|
45
|
-
"pqb": "0.9.
|
|
45
|
+
"pqb": "0.9.2"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
48
|
"@swc/core": "^1.2.210",
|
|
@@ -59,6 +59,41 @@ describe('astToMigration', () => {
|
|
|
59
59
|
);
|
|
60
60
|
});
|
|
61
61
|
|
|
62
|
+
it('should add columns with indexes and foreignKeys', () => {
|
|
63
|
+
const result = astToMigration([
|
|
64
|
+
{
|
|
65
|
+
...tableAst,
|
|
66
|
+
shape: {
|
|
67
|
+
someId: columnTypes
|
|
68
|
+
.integer()
|
|
69
|
+
.unique({ name: 'indexName' })
|
|
70
|
+
.foreignKey('otherTable', 'otherId', {
|
|
71
|
+
name: 'fkey',
|
|
72
|
+
match: 'FULL',
|
|
73
|
+
onUpdate: 'CASCADE',
|
|
74
|
+
onDelete: 'CASCADE',
|
|
75
|
+
}),
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
]);
|
|
79
|
+
|
|
80
|
+
expect(result).toBe(`import { change } from 'rake-db';
|
|
81
|
+
|
|
82
|
+
change(async (db) => {
|
|
83
|
+
await db.createTable('schema.table', (t) => ({
|
|
84
|
+
someId: t.integer().foreignKey('otherTable', 'otherId', {
|
|
85
|
+
name: 'fkey',
|
|
86
|
+
match: 'FULL',
|
|
87
|
+
onUpdate: 'CASCADE',
|
|
88
|
+
onDelete: 'CASCADE',
|
|
89
|
+
}).unique({
|
|
90
|
+
name: 'indexName',
|
|
91
|
+
}),
|
|
92
|
+
}));
|
|
93
|
+
});
|
|
94
|
+
`);
|
|
95
|
+
});
|
|
96
|
+
|
|
62
97
|
it('should add composite primaryKeys, indexes, foreignKeys', () => {
|
|
63
98
|
const result = astToMigration([
|
|
64
99
|
{
|
|
@@ -3,11 +3,14 @@ import {
|
|
|
3
3
|
addCode,
|
|
4
4
|
Code,
|
|
5
5
|
codeToString,
|
|
6
|
+
ColumnType,
|
|
6
7
|
foreignKeyToCode,
|
|
7
8
|
indexToCode,
|
|
9
|
+
isRaw,
|
|
8
10
|
primaryKeyToCode,
|
|
9
11
|
quoteObjectKey,
|
|
10
12
|
singleQuote,
|
|
13
|
+
TimestampColumn,
|
|
11
14
|
} from 'pqb';
|
|
12
15
|
import { quoteSchemaTable } from '../common';
|
|
13
16
|
|
|
@@ -40,13 +43,24 @@ const createTable = (ast: RakeDbAst.Table) => {
|
|
|
40
43
|
const code: Code[] = [];
|
|
41
44
|
addCode(code, `await db.createTable(${quoteSchemaTable(ast)}, (t) => ({`);
|
|
42
45
|
|
|
46
|
+
const hasTimestamps =
|
|
47
|
+
isTimestamp(ast.shape.createdAt) && isTimestamp(ast.shape.updatedAt);
|
|
48
|
+
|
|
43
49
|
for (const key in ast.shape) {
|
|
50
|
+
if (hasTimestamps && (key === 'createdAt' || key === 'updatedAt')) continue;
|
|
51
|
+
|
|
44
52
|
const line: Code[] = [`${quoteObjectKey(key)}: `];
|
|
45
|
-
|
|
53
|
+
for (const part of ast.shape[key].toCode('t')) {
|
|
54
|
+
addCode(line, part);
|
|
55
|
+
}
|
|
46
56
|
addCode(line, ',');
|
|
47
57
|
code.push(line);
|
|
48
58
|
}
|
|
49
59
|
|
|
60
|
+
if (hasTimestamps) {
|
|
61
|
+
code.push(['...t.timestamps(),']);
|
|
62
|
+
}
|
|
63
|
+
|
|
50
64
|
if (ast.primaryKey) {
|
|
51
65
|
code.push([primaryKeyToCode(ast.primaryKey, 't')]);
|
|
52
66
|
}
|
|
@@ -63,3 +77,17 @@ const createTable = (ast: RakeDbAst.Table) => {
|
|
|
63
77
|
|
|
64
78
|
return code;
|
|
65
79
|
};
|
|
80
|
+
|
|
81
|
+
const isTimestamp = (column?: ColumnType) => {
|
|
82
|
+
if (!column) return false;
|
|
83
|
+
|
|
84
|
+
const { default: def } = column.data;
|
|
85
|
+
return (
|
|
86
|
+
column instanceof TimestampColumn &&
|
|
87
|
+
!column.data.isNullable &&
|
|
88
|
+
def &&
|
|
89
|
+
typeof def === 'object' &&
|
|
90
|
+
isRaw(def) &&
|
|
91
|
+
def.__raw === 'now()'
|
|
92
|
+
);
|
|
93
|
+
};
|
package/src/pull/pull.test.ts
CHANGED
|
@@ -56,6 +56,24 @@ describe('pull', () => {
|
|
|
56
56
|
type: 'text',
|
|
57
57
|
isNullable: false,
|
|
58
58
|
},
|
|
59
|
+
{
|
|
60
|
+
schemaName: 'public',
|
|
61
|
+
tableName: 'table2',
|
|
62
|
+
name: 'createdAt',
|
|
63
|
+
type: 'timestamp',
|
|
64
|
+
dateTimePrecision: 6,
|
|
65
|
+
isNullable: false,
|
|
66
|
+
default: 'now()',
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
schemaName: 'public',
|
|
70
|
+
tableName: 'table2',
|
|
71
|
+
name: 'updatedAt',
|
|
72
|
+
type: 'timestamp',
|
|
73
|
+
dateTimePrecision: 6,
|
|
74
|
+
isNullable: false,
|
|
75
|
+
default: 'now()',
|
|
76
|
+
},
|
|
59
77
|
];
|
|
60
78
|
|
|
61
79
|
const config = getMigrationConfigWithDefaults({
|
|
@@ -84,6 +102,7 @@ change(async (db) => {
|
|
|
84
102
|
|
|
85
103
|
await db.createTable('table2', (t) => ({
|
|
86
104
|
text: t.text(),
|
|
105
|
+
...t.timestamps(),
|
|
87
106
|
}));
|
|
88
107
|
});
|
|
89
108
|
`,
|
package/src/pull/pull.ts
CHANGED
|
@@ -9,8 +9,12 @@ export const pullDbStructure = async (
|
|
|
9
9
|
options: AdapterOptions,
|
|
10
10
|
config: RakeDbConfig,
|
|
11
11
|
) => {
|
|
12
|
-
const
|
|
12
|
+
const adapter = new Adapter(options);
|
|
13
|
+
const db = new DbStructure(adapter);
|
|
13
14
|
const ast = await structureToAst(db);
|
|
15
|
+
|
|
16
|
+
await adapter.close();
|
|
17
|
+
|
|
14
18
|
const result = astToMigration(ast);
|
|
15
19
|
if (!result) return;
|
|
16
20
|
|
|
@@ -4,6 +4,8 @@ import {
|
|
|
4
4
|
BigSerialColumn,
|
|
5
5
|
DecimalColumn,
|
|
6
6
|
IntegerColumn,
|
|
7
|
+
isRaw,
|
|
8
|
+
RawExpression,
|
|
7
9
|
SerialColumn,
|
|
8
10
|
SmallSerialColumn,
|
|
9
11
|
TextColumn,
|
|
@@ -121,7 +123,9 @@ describe('structureToAst', () => {
|
|
|
121
123
|
db.getTables = async () => [
|
|
122
124
|
{ schemaName: 'public', name: 'table', comment: 'comment' },
|
|
123
125
|
];
|
|
126
|
+
|
|
124
127
|
const ast = await structureToAst(db);
|
|
128
|
+
|
|
125
129
|
expect(ast).toEqual([
|
|
126
130
|
{
|
|
127
131
|
type: 'table',
|
|
@@ -139,7 +143,9 @@ describe('structureToAst', () => {
|
|
|
139
143
|
it('should add table with schema', async () => {
|
|
140
144
|
const db = new DbStructure(adapter);
|
|
141
145
|
db.getTables = async () => [{ schemaName: 'custom', name: 'table' }];
|
|
146
|
+
|
|
142
147
|
const ast = await structureToAst(db);
|
|
148
|
+
|
|
143
149
|
expect(ast).toEqual([
|
|
144
150
|
{
|
|
145
151
|
type: 'table',
|
|
@@ -154,9 +160,20 @@ describe('structureToAst', () => {
|
|
|
154
160
|
]);
|
|
155
161
|
});
|
|
156
162
|
|
|
163
|
+
it('should ignore schemaMigrations table', async () => {
|
|
164
|
+
const db = new DbStructure(adapter);
|
|
165
|
+
db.getTables = async () => [
|
|
166
|
+
{ schemaName: 'public', name: 'schemaMigrations' },
|
|
167
|
+
];
|
|
168
|
+
|
|
169
|
+
const ast = await structureToAst(db);
|
|
170
|
+
|
|
171
|
+
expect(ast).toEqual([]);
|
|
172
|
+
});
|
|
173
|
+
|
|
157
174
|
it('should add columns', async () => {
|
|
158
175
|
const db = new DbStructure(adapter);
|
|
159
|
-
db.getTables = async () => [
|
|
176
|
+
db.getTables = async () => [table];
|
|
160
177
|
db.getColumns = async () => columns;
|
|
161
178
|
|
|
162
179
|
const [ast] = (await structureToAst(db)) as [RakeDbAst.Table];
|
|
@@ -167,6 +184,18 @@ describe('structureToAst', () => {
|
|
|
167
184
|
expect(ast.shape.name).toBeInstanceOf(TextColumn);
|
|
168
185
|
});
|
|
169
186
|
|
|
187
|
+
it('should wrap column default into raw', async () => {
|
|
188
|
+
const db = new DbStructure(adapter);
|
|
189
|
+
db.getTables = async () => [table];
|
|
190
|
+
db.getColumns = async () => [{ ...timestampColumn, default: 'now()' }];
|
|
191
|
+
|
|
192
|
+
const [ast] = (await structureToAst(db)) as [RakeDbAst.Table];
|
|
193
|
+
|
|
194
|
+
const { default: def } = ast.shape.timestamp.data;
|
|
195
|
+
expect(def && typeof def === 'object' && isRaw(def)).toBe(true);
|
|
196
|
+
expect((def as RawExpression).__raw).toBe('now()');
|
|
197
|
+
});
|
|
198
|
+
|
|
170
199
|
describe('serial column', () => {
|
|
171
200
|
it('should add serial column based on various default values', async () => {
|
|
172
201
|
const db = new DbStructure(adapter);
|
|
@@ -231,7 +260,7 @@ describe('structureToAst', () => {
|
|
|
231
260
|
|
|
232
261
|
it('should set maxChars to char column', async () => {
|
|
233
262
|
const db = new DbStructure(adapter);
|
|
234
|
-
db.getTables = async () => [
|
|
263
|
+
db.getTables = async () => [table];
|
|
235
264
|
db.getColumns = async () => [varCharColumn];
|
|
236
265
|
|
|
237
266
|
const [ast] = (await structureToAst(db)) as [RakeDbAst.Table];
|
|
@@ -243,7 +272,7 @@ describe('structureToAst', () => {
|
|
|
243
272
|
|
|
244
273
|
it('should set numericPrecision and numericScale to decimal column', async () => {
|
|
245
274
|
const db = new DbStructure(adapter);
|
|
246
|
-
db.getTables = async () => [
|
|
275
|
+
db.getTables = async () => [table];
|
|
247
276
|
db.getColumns = async () => [decimalColumn];
|
|
248
277
|
|
|
249
278
|
const [ast] = (await structureToAst(db)) as [RakeDbAst.Table];
|
|
@@ -256,7 +285,7 @@ describe('structureToAst', () => {
|
|
|
256
285
|
|
|
257
286
|
it('should set dateTimePrecision to timestamp column', async () => {
|
|
258
287
|
const db = new DbStructure(adapter);
|
|
259
|
-
db.getTables = async () => [
|
|
288
|
+
db.getTables = async () => [table];
|
|
260
289
|
db.getColumns = async () => [timestampColumn];
|
|
261
290
|
|
|
262
291
|
const [ast] = (await structureToAst(db)) as [RakeDbAst.Table];
|
|
@@ -270,7 +299,7 @@ describe('structureToAst', () => {
|
|
|
270
299
|
|
|
271
300
|
it('should set primaryKey to column', async () => {
|
|
272
301
|
const db = new DbStructure(adapter);
|
|
273
|
-
db.getTables = async () => [
|
|
302
|
+
db.getTables = async () => [table];
|
|
274
303
|
db.getColumns = async () => columns;
|
|
275
304
|
db.getPrimaryKeys = async () => [primaryKey];
|
|
276
305
|
|
|
@@ -283,7 +312,7 @@ describe('structureToAst', () => {
|
|
|
283
312
|
|
|
284
313
|
it('should add composite primary key', async () => {
|
|
285
314
|
const db = new DbStructure(adapter);
|
|
286
|
-
db.getTables = async () => [
|
|
315
|
+
db.getTables = async () => [table];
|
|
287
316
|
db.getColumns = async () => columns;
|
|
288
317
|
db.getPrimaryKeys = async () => [
|
|
289
318
|
{ ...primaryKey, columnNames: ['id', 'name'] },
|
|
@@ -301,7 +330,7 @@ describe('structureToAst', () => {
|
|
|
301
330
|
|
|
302
331
|
it('should ignore primary key name if it is standard', async () => {
|
|
303
332
|
const db = new DbStructure(adapter);
|
|
304
|
-
db.getTables = async () => [
|
|
333
|
+
db.getTables = async () => [table];
|
|
305
334
|
db.getColumns = async () => columns;
|
|
306
335
|
db.getPrimaryKeys = async () => [
|
|
307
336
|
{ ...primaryKey, columnNames: ['id', 'name'], name: 'table_pkey' },
|
|
@@ -15,8 +15,8 @@ const matchMap = {
|
|
|
15
15
|
};
|
|
16
16
|
|
|
17
17
|
const fkeyActionMap = {
|
|
18
|
-
a:
|
|
19
|
-
r:
|
|
18
|
+
a: undefined, // default
|
|
19
|
+
r: 'RESTRICT',
|
|
20
20
|
c: 'CASCADE',
|
|
21
21
|
n: 'SET NULL',
|
|
22
22
|
d: 'SET DEFAULT',
|
|
@@ -56,6 +56,8 @@ export const structureToAst = async (db: DbStructure): Promise<RakeDbAst[]> => {
|
|
|
56
56
|
for (const table of tables) {
|
|
57
57
|
const { schemaName, name } = table;
|
|
58
58
|
|
|
59
|
+
if (name === 'schemaMigrations') continue;
|
|
60
|
+
|
|
59
61
|
const belongsToTable = makeBelongsToTable(schemaName, name);
|
|
60
62
|
|
|
61
63
|
const columns = allColumns.filter(belongsToTable);
|
|
@@ -66,13 +68,14 @@ export const structureToAst = async (db: DbStructure): Promise<RakeDbAst[]> => {
|
|
|
66
68
|
const shape: ColumnsShape = {};
|
|
67
69
|
for (let item of columns) {
|
|
68
70
|
const isSerial = getIsSerial(item);
|
|
71
|
+
if (isSerial) {
|
|
72
|
+
item = { ...item, default: undefined };
|
|
73
|
+
}
|
|
74
|
+
|
|
69
75
|
const klass = columnsByType[getColumnType(item, isSerial)];
|
|
70
76
|
if (!klass) {
|
|
71
77
|
throw new Error(`Column type \`${item.type}\` is not supported`);
|
|
72
78
|
}
|
|
73
|
-
if (isSerial) {
|
|
74
|
-
item = { ...item, default: undefined };
|
|
75
|
-
}
|
|
76
79
|
|
|
77
80
|
let column = instantiateColumn(klass, item);
|
|
78
81
|
|