rake-db 2.3.26 → 2.3.28
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 +6 -0
- package/dist/index.d.ts +9 -6
- package/dist/index.js +224 -112
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +224 -114
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/commands/migrateOrRollback.test.ts +43 -1
- package/src/commands/migrateOrRollback.ts +13 -15
- package/src/common.ts +16 -0
- package/src/errors.ts +3 -0
- package/src/migration/change.test.ts +16 -0
- package/src/migration/change.ts +5 -16
- package/src/migration/changeTable.test.ts +236 -58
- package/src/migration/changeTable.ts +34 -14
- package/src/migration/createTable.test.ts +31 -7
- package/src/migration/createTable.ts +44 -25
- package/src/migration/migration.test.ts +1 -1
- package/src/migration/migration.ts +6 -8
- package/src/migration/tableMethods.ts +8 -0
- package/src/pull/astToMigration.test.ts +97 -28
- package/src/pull/astToMigration.ts +55 -12
- package/src/pull/dbStructure.test.ts +14 -0
- package/src/pull/dbStructure.ts +21 -0
- package/src/pull/pull.test.ts +4 -0
- package/src/pull/structureToAst.test.ts +37 -0
- package/src/pull/structureToAst.ts +24 -10
- package/src/rakeDb.test.ts +20 -0
- package/src/rakeDb.ts +27 -18
- package/src/test-utils.ts +1 -0
|
@@ -6,12 +6,11 @@ import {
|
|
|
6
6
|
emptyObject,
|
|
7
7
|
TableData,
|
|
8
8
|
RawExpression,
|
|
9
|
-
raw,
|
|
10
9
|
columnTypes,
|
|
11
|
-
Sql,
|
|
12
10
|
quote,
|
|
13
11
|
getRaw,
|
|
14
12
|
isRaw,
|
|
13
|
+
EnumColumn,
|
|
15
14
|
} from 'pqb';
|
|
16
15
|
import {
|
|
17
16
|
ChangeTableCallback,
|
|
@@ -23,7 +22,11 @@ import {
|
|
|
23
22
|
runCodeUpdater,
|
|
24
23
|
} from './migration';
|
|
25
24
|
import { RakeDbAst } from '../ast';
|
|
26
|
-
import {
|
|
25
|
+
import {
|
|
26
|
+
getSchemaAndTableFromName,
|
|
27
|
+
makePopulateEnumQuery,
|
|
28
|
+
quoteWithSchema,
|
|
29
|
+
} from '../common';
|
|
27
30
|
import {
|
|
28
31
|
addColumnComment,
|
|
29
32
|
addColumnIndex,
|
|
@@ -33,6 +36,8 @@ import {
|
|
|
33
36
|
indexesToQuery,
|
|
34
37
|
primaryKeyToSql,
|
|
35
38
|
} from './migrationUtils';
|
|
39
|
+
import { tableMethods } from './tableMethods';
|
|
40
|
+
import { TableQuery } from './createTable';
|
|
36
41
|
|
|
37
42
|
type ChangeTableData = { add: TableData; drop: TableData };
|
|
38
43
|
const newChangeTableData = (): ChangeTableData => ({
|
|
@@ -147,7 +152,7 @@ const columnTypeToColumnChange = (
|
|
|
147
152
|
|
|
148
153
|
type TableChangeMethods = typeof tableChangeMethods;
|
|
149
154
|
const tableChangeMethods = {
|
|
150
|
-
|
|
155
|
+
...tableMethods,
|
|
151
156
|
add,
|
|
152
157
|
drop,
|
|
153
158
|
change(
|
|
@@ -216,7 +221,8 @@ export const changeTable = async (
|
|
|
216
221
|
|
|
217
222
|
const queries = astToQueries(ast);
|
|
218
223
|
for (const query of queries) {
|
|
219
|
-
await migration.adapter.
|
|
224
|
+
const result = await migration.adapter.arrays(query);
|
|
225
|
+
query.then?.(result);
|
|
220
226
|
}
|
|
221
227
|
|
|
222
228
|
await runCodeUpdater(migration, ast);
|
|
@@ -285,13 +291,12 @@ type PrimaryKeys = {
|
|
|
285
291
|
options?: { name?: string };
|
|
286
292
|
};
|
|
287
293
|
|
|
288
|
-
const astToQueries = (ast: RakeDbAst.ChangeTable):
|
|
289
|
-
const
|
|
294
|
+
const astToQueries = (ast: RakeDbAst.ChangeTable): TableQuery[] => {
|
|
295
|
+
const queries: TableQuery[] = [];
|
|
290
296
|
|
|
291
297
|
if (ast.comment !== undefined) {
|
|
292
|
-
|
|
298
|
+
queries.push({
|
|
293
299
|
text: `COMMENT ON TABLE ${quoteWithSchema(ast)} IS ${quote(ast.comment)}`,
|
|
294
|
-
values: [],
|
|
295
300
|
});
|
|
296
301
|
}
|
|
297
302
|
|
|
@@ -309,6 +314,13 @@ const astToQueries = (ast: RakeDbAst.ChangeTable): Sql[] => {
|
|
|
309
314
|
for (const key in ast.shape) {
|
|
310
315
|
const item = ast.shape[key];
|
|
311
316
|
|
|
317
|
+
if ('item' in item) {
|
|
318
|
+
const { item: column } = item;
|
|
319
|
+
if (column instanceof EnumColumn) {
|
|
320
|
+
queries.push(makePopulateEnumQuery(column));
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
312
324
|
if (item.type === 'add') {
|
|
313
325
|
if (item.item.isPrimaryKey) {
|
|
314
326
|
addPrimaryKeys.columns.push(key);
|
|
@@ -318,6 +330,14 @@ const astToQueries = (ast: RakeDbAst.ChangeTable): Sql[] => {
|
|
|
318
330
|
dropPrimaryKeys.columns.push(key);
|
|
319
331
|
}
|
|
320
332
|
} else if (item.type === 'change') {
|
|
333
|
+
if (item.from.column instanceof EnumColumn) {
|
|
334
|
+
queries.push(makePopulateEnumQuery(item.from.column));
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
if (item.to.column instanceof EnumColumn) {
|
|
338
|
+
queries.push(makePopulateEnumQuery(item.to.column));
|
|
339
|
+
}
|
|
340
|
+
|
|
321
341
|
if (item.from.primaryKey) {
|
|
322
342
|
dropPrimaryKeys.columns.push(key);
|
|
323
343
|
dropPrimaryKeys.change = true;
|
|
@@ -530,7 +550,7 @@ const astToQueries = (ast: RakeDbAst.ChangeTable): Sql[] => {
|
|
|
530
550
|
);
|
|
531
551
|
|
|
532
552
|
if (alterTable.length) {
|
|
533
|
-
|
|
553
|
+
queries.push({
|
|
534
554
|
text:
|
|
535
555
|
`ALTER TABLE ${quoteWithSchema(ast)}` +
|
|
536
556
|
`\n ${alterTable.join(',\n ')}`,
|
|
@@ -538,9 +558,9 @@ const astToQueries = (ast: RakeDbAst.ChangeTable): Sql[] => {
|
|
|
538
558
|
});
|
|
539
559
|
}
|
|
540
560
|
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
561
|
+
queries.push(...indexesToQuery(false, ast, dropIndexes));
|
|
562
|
+
queries.push(...indexesToQuery(true, ast, addIndexes));
|
|
563
|
+
queries.push(...commentsToQuery(ast, comments));
|
|
544
564
|
|
|
545
|
-
return
|
|
565
|
+
return queries;
|
|
546
566
|
};
|
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
asMock,
|
|
3
|
+
expectSql,
|
|
4
|
+
getDb,
|
|
5
|
+
queryMock,
|
|
6
|
+
resetDb,
|
|
7
|
+
toLine,
|
|
8
|
+
} from '../test-utils';
|
|
2
9
|
|
|
3
10
|
const db = getDb();
|
|
4
11
|
|
|
@@ -90,6 +97,7 @@ const db = getDb();
|
|
|
90
97
|
|
|
91
98
|
const expectCreateTable = () => {
|
|
92
99
|
expectSql([
|
|
100
|
+
'SELECT unnest(enum_range(NULL::"mood"))::text',
|
|
93
101
|
`
|
|
94
102
|
CREATE TABLE "table" (
|
|
95
103
|
"id" serial PRIMARY KEY,
|
|
@@ -130,18 +138,32 @@ const db = getDb();
|
|
|
130
138
|
};
|
|
131
139
|
|
|
132
140
|
const expectDropTable = () => {
|
|
133
|
-
expectSql(
|
|
134
|
-
|
|
135
|
-
|
|
141
|
+
expectSql([
|
|
142
|
+
'SELECT unnest(enum_range(NULL::"mood"))::text',
|
|
143
|
+
`
|
|
144
|
+
DROP TABLE "table" CASCADE
|
|
145
|
+
`,
|
|
146
|
+
]);
|
|
136
147
|
};
|
|
137
148
|
|
|
149
|
+
const enumRows = [['one'], ['two']];
|
|
150
|
+
asMock(db.adapter.arrays).mockResolvedValueOnce({ rows: enumRows });
|
|
151
|
+
|
|
138
152
|
await fn();
|
|
139
153
|
(action === 'createTable' ? expectCreateTable : expectDropTable)();
|
|
140
154
|
|
|
155
|
+
const [{ ast: ast1 }] = asMock(db.options.appCodeUpdater).mock.calls[0];
|
|
156
|
+
expect(ast1.shape.enum.options).toEqual(['one', 'two']);
|
|
157
|
+
|
|
141
158
|
db.up = false;
|
|
142
159
|
queryMock.mockClear();
|
|
160
|
+
asMock(db.options.appCodeUpdater).mockClear();
|
|
161
|
+
asMock(db.adapter.arrays).mockResolvedValueOnce({ rows: enumRows });
|
|
143
162
|
await fn();
|
|
144
163
|
(action === 'createTable' ? expectDropTable : expectCreateTable)();
|
|
164
|
+
|
|
165
|
+
const [{ ast: ast2 }] = asMock(db.options.appCodeUpdater).mock.calls[0];
|
|
166
|
+
expect(ast2.shape.enum.options).toEqual(['one', 'two']);
|
|
145
167
|
});
|
|
146
168
|
|
|
147
169
|
it('should support composite primary key defined on multiple columns', async () => {
|
|
@@ -321,7 +343,7 @@ const db = getDb();
|
|
|
321
343
|
|
|
322
344
|
it('should throw by default when no primary key', async () => {
|
|
323
345
|
await expect(() => db[action]('table', () => ({}))).rejects.toThrow(
|
|
324
|
-
'Table table has no primary key',
|
|
346
|
+
'Table table has no primary key.\nYou can suppress this error by setting { noPrimaryKey: true } after a table name.',
|
|
325
347
|
);
|
|
326
348
|
});
|
|
327
349
|
|
|
@@ -329,7 +351,7 @@ const db = getDb();
|
|
|
329
351
|
db.options.noPrimaryKey = 'error';
|
|
330
352
|
|
|
331
353
|
await expect(() => db[action]('table', () => ({}))).rejects.toThrow(
|
|
332
|
-
'Table table has no primary key',
|
|
354
|
+
'Table table has no primary key.\nYou can suppress this error by setting { noPrimaryKey: true } after a table name.',
|
|
333
355
|
);
|
|
334
356
|
});
|
|
335
357
|
|
|
@@ -339,7 +361,9 @@ const db = getDb();
|
|
|
339
361
|
|
|
340
362
|
db[action]('table', () => ({}));
|
|
341
363
|
|
|
342
|
-
expect(console.warn).toBeCalledWith(
|
|
364
|
+
expect(console.warn).toBeCalledWith(
|
|
365
|
+
'Table table has no primary key.\nYou can suppress this error by setting { noPrimaryKey: true } after a table name.',
|
|
366
|
+
);
|
|
343
367
|
});
|
|
344
368
|
|
|
345
369
|
it('should not throw when no primary key and noPrimaryKey is set to `ignore`', async () => {
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ColumnsShape,
|
|
3
3
|
columnTypes,
|
|
4
|
+
EnumColumn,
|
|
4
5
|
getColumnTypes,
|
|
5
6
|
getTableData,
|
|
6
7
|
NoPrimaryKeyOption,
|
|
8
|
+
QueryArraysResult,
|
|
7
9
|
quote,
|
|
8
|
-
raw,
|
|
9
|
-
Sql,
|
|
10
10
|
TableData,
|
|
11
11
|
} from 'pqb';
|
|
12
12
|
import {
|
|
@@ -25,12 +25,22 @@ import {
|
|
|
25
25
|
indexesToQuery,
|
|
26
26
|
primaryKeyToSql,
|
|
27
27
|
} from './migrationUtils';
|
|
28
|
-
import {
|
|
28
|
+
import {
|
|
29
|
+
getSchemaAndTableFromName,
|
|
30
|
+
makePopulateEnumQuery,
|
|
31
|
+
quoteWithSchema,
|
|
32
|
+
} from '../common';
|
|
29
33
|
import { RakeDbAst } from '../ast';
|
|
34
|
+
import { tableMethods } from './tableMethods';
|
|
35
|
+
import { NoPrimaryKey } from '../errors';
|
|
36
|
+
|
|
37
|
+
const types = Object.assign(Object.create(columnTypes), tableMethods);
|
|
30
38
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
39
|
+
export type TableQuery = {
|
|
40
|
+
text: string;
|
|
41
|
+
values?: unknown[];
|
|
42
|
+
then?(result: QueryArraysResult): void;
|
|
43
|
+
};
|
|
34
44
|
|
|
35
45
|
export const createTable = async (
|
|
36
46
|
migration: MigrationBase,
|
|
@@ -53,8 +63,9 @@ export const createTable = async (
|
|
|
53
63
|
validatePrimaryKey(ast);
|
|
54
64
|
|
|
55
65
|
const queries = astToQueries(ast);
|
|
56
|
-
for (const query of queries) {
|
|
57
|
-
await migration.adapter.
|
|
66
|
+
for (const { then, ...query } of queries) {
|
|
67
|
+
const result = await migration.adapter.arrays(query);
|
|
68
|
+
then?.(result);
|
|
58
69
|
}
|
|
59
70
|
|
|
60
71
|
await runCodeUpdater(migration, ast);
|
|
@@ -110,26 +121,35 @@ const validatePrimaryKey = (ast: RakeDbAst.Table) => {
|
|
|
110
121
|
}
|
|
111
122
|
|
|
112
123
|
if (!hasPrimaryKey) {
|
|
113
|
-
const
|
|
124
|
+
const error = new NoPrimaryKey(
|
|
125
|
+
`Table ${ast.name} has no primary key.\nYou can suppress this error by setting { noPrimaryKey: true } after a table name.`,
|
|
126
|
+
);
|
|
114
127
|
if (ast.noPrimaryKey === 'error') {
|
|
115
|
-
throw
|
|
128
|
+
throw error;
|
|
116
129
|
} else {
|
|
117
|
-
console.warn(message);
|
|
130
|
+
console.warn(error.message);
|
|
118
131
|
}
|
|
119
132
|
}
|
|
120
133
|
}
|
|
121
134
|
};
|
|
122
135
|
|
|
123
|
-
const astToQueries = (ast: RakeDbAst.Table):
|
|
136
|
+
const astToQueries = (ast: RakeDbAst.Table): TableQuery[] => {
|
|
137
|
+
const queries: TableQuery[] = [];
|
|
138
|
+
|
|
139
|
+
for (const key in ast.shape) {
|
|
140
|
+
const item = ast.shape[key];
|
|
141
|
+
if (!(item instanceof EnumColumn)) continue;
|
|
142
|
+
|
|
143
|
+
queries.push(makePopulateEnumQuery(item));
|
|
144
|
+
}
|
|
145
|
+
|
|
124
146
|
if (ast.action === 'drop') {
|
|
125
|
-
|
|
126
|
-
{
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
},
|
|
132
|
-
];
|
|
147
|
+
queries.push({
|
|
148
|
+
text: `DROP TABLE ${quoteWithSchema(ast)}${
|
|
149
|
+
ast.dropMode ? ` ${ast.dropMode}` : ''
|
|
150
|
+
}`,
|
|
151
|
+
});
|
|
152
|
+
return queries;
|
|
133
153
|
}
|
|
134
154
|
|
|
135
155
|
const lines: string[] = [];
|
|
@@ -154,21 +174,20 @@ const astToQueries = (ast: RakeDbAst.Table): Sql[] => {
|
|
|
154
174
|
|
|
155
175
|
indexes.push(...ast.indexes);
|
|
156
176
|
|
|
157
|
-
|
|
177
|
+
queries.push(
|
|
158
178
|
{
|
|
159
179
|
text: `CREATE TABLE ${quoteWithSchema(ast)} (${lines.join(',')}\n)`,
|
|
160
180
|
values,
|
|
161
181
|
},
|
|
162
182
|
...indexesToQuery(true, ast, indexes),
|
|
163
183
|
...commentsToQuery(ast, comments),
|
|
164
|
-
|
|
184
|
+
);
|
|
165
185
|
|
|
166
186
|
if (ast.comment) {
|
|
167
|
-
|
|
187
|
+
queries.push({
|
|
168
188
|
text: `COMMENT ON TABLE ${quoteWithSchema(ast)} IS ${quote(ast.comment)}`,
|
|
169
|
-
values: [],
|
|
170
189
|
});
|
|
171
190
|
}
|
|
172
191
|
|
|
173
|
-
return
|
|
192
|
+
return queries;
|
|
174
193
|
};
|
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
DbResult,
|
|
19
19
|
DefaultColumnTypes,
|
|
20
20
|
EnumColumn,
|
|
21
|
+
quote,
|
|
21
22
|
} from 'pqb';
|
|
22
23
|
import { createTable } from './createTable';
|
|
23
24
|
import { changeTable, TableChangeData, TableChanger } from './changeTable';
|
|
@@ -483,22 +484,19 @@ const createEnum = async (
|
|
|
483
484
|
...options,
|
|
484
485
|
};
|
|
485
486
|
|
|
486
|
-
let
|
|
487
|
+
let query;
|
|
487
488
|
const quotedName = quoteWithSchema(ast);
|
|
488
489
|
if (ast.action === 'create') {
|
|
489
|
-
|
|
490
|
-
.map(
|
|
490
|
+
query = `CREATE TYPE ${quotedName} AS ENUM (${values
|
|
491
|
+
.map(quote)
|
|
491
492
|
.join(', ')})`;
|
|
492
493
|
} else {
|
|
493
|
-
|
|
494
|
+
query = `DROP TYPE${ast.dropIfExists ? ' IF EXISTS' : ''} ${quotedName}${
|
|
494
495
|
ast.cascade ? ' CASCADE' : ''
|
|
495
496
|
}`;
|
|
496
497
|
}
|
|
497
498
|
|
|
498
|
-
await migration.adapter.query(
|
|
499
|
-
text,
|
|
500
|
-
values,
|
|
501
|
-
});
|
|
499
|
+
await migration.adapter.query(query);
|
|
502
500
|
|
|
503
501
|
await runCodeUpdater(migration, ast);
|
|
504
502
|
};
|
|
@@ -9,15 +9,46 @@ ${content}
|
|
|
9
9
|
});
|
|
10
10
|
`;
|
|
11
11
|
|
|
12
|
-
const
|
|
12
|
+
const schema: RakeDbAst.Schema = {
|
|
13
|
+
type: 'schema',
|
|
14
|
+
action: 'create',
|
|
15
|
+
name: 'schemaName',
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const extension: RakeDbAst.Extension = {
|
|
19
|
+
type: 'extension',
|
|
20
|
+
action: 'create',
|
|
21
|
+
name: 'extensionName',
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const enumType: RakeDbAst.Enum = {
|
|
25
|
+
type: 'enum',
|
|
26
|
+
action: 'create',
|
|
27
|
+
name: 'mood',
|
|
28
|
+
values: ['sad', 'ok', 'happy'],
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const table: RakeDbAst.Table = {
|
|
13
32
|
type: 'table',
|
|
14
33
|
action: 'create',
|
|
15
34
|
schema: 'schema',
|
|
16
35
|
name: 'table',
|
|
17
|
-
shape: {},
|
|
18
36
|
noPrimaryKey: 'ignore',
|
|
19
37
|
indexes: [],
|
|
20
38
|
foreignKeys: [],
|
|
39
|
+
shape: {
|
|
40
|
+
id: columnTypes.serial().primaryKey(),
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const foreignKey: RakeDbAst.ForeignKey = {
|
|
45
|
+
type: 'foreignKey',
|
|
46
|
+
action: 'create',
|
|
47
|
+
tableName: 'table',
|
|
48
|
+
columns: ['otherId'],
|
|
49
|
+
fnOrTable: 'otherTable',
|
|
50
|
+
foreignColumns: ['id'],
|
|
51
|
+
options: {},
|
|
21
52
|
};
|
|
22
53
|
|
|
23
54
|
describe('astToMigration', () => {
|
|
@@ -29,24 +60,59 @@ describe('astToMigration', () => {
|
|
|
29
60
|
expect(result).toBe(undefined);
|
|
30
61
|
});
|
|
31
62
|
|
|
32
|
-
it('should
|
|
63
|
+
it('should put schema, extension, enum to first change, tables to separate changes, foreignKeys in last change', () => {
|
|
33
64
|
const result = astToMigration([
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
},
|
|
65
|
+
schema,
|
|
66
|
+
extension,
|
|
67
|
+
enumType,
|
|
68
|
+
table,
|
|
69
|
+
{ ...table, name: 'other' },
|
|
70
|
+
foreignKey,
|
|
39
71
|
]);
|
|
40
72
|
|
|
73
|
+
expect(result).toBe(`import { change } from 'rake-db';
|
|
74
|
+
|
|
75
|
+
change(async (db) => {
|
|
76
|
+
await db.createSchema('schemaName');
|
|
77
|
+
|
|
78
|
+
await db.createExtension('extensionName');
|
|
79
|
+
|
|
80
|
+
await db.createEnum('mood', ['sad', 'ok', 'happy']);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
change(async (db) => {
|
|
84
|
+
await db.createTable('schema.table', (t) => ({
|
|
85
|
+
id: t.serial().primaryKey(),
|
|
86
|
+
}));
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
change(async (db) => {
|
|
90
|
+
await db.createTable('schema.other', (t) => ({
|
|
91
|
+
id: t.serial().primaryKey(),
|
|
92
|
+
}));
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
change(async (db) => {
|
|
96
|
+
await db.addForeignKey(
|
|
97
|
+
'table',
|
|
98
|
+
['otherId'],
|
|
99
|
+
'otherTable',
|
|
100
|
+
['id'],
|
|
101
|
+
);
|
|
102
|
+
});
|
|
103
|
+
`);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('should create schema', () => {
|
|
107
|
+
const result = astToMigration([schema]);
|
|
108
|
+
|
|
41
109
|
expect(result).toBe(template(` await db.createSchema('schemaName');`));
|
|
42
110
|
});
|
|
43
111
|
|
|
44
112
|
it('should create extension', () => {
|
|
45
113
|
const result = astToMigration([
|
|
46
114
|
{
|
|
47
|
-
|
|
48
|
-
action: 'create',
|
|
49
|
-
name: 'extensionName',
|
|
115
|
+
...extension,
|
|
50
116
|
schema: 'schema',
|
|
51
117
|
version: '123',
|
|
52
118
|
},
|
|
@@ -56,20 +122,28 @@ describe('astToMigration', () => {
|
|
|
56
122
|
template(` await db.createExtension('extensionName', {
|
|
57
123
|
schema: 'schema',
|
|
58
124
|
version: '123',
|
|
59
|
-
})
|
|
125
|
+
});`),
|
|
126
|
+
);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it('should create enum', () => {
|
|
130
|
+
const result = astToMigration([
|
|
131
|
+
{
|
|
132
|
+
...enumType,
|
|
133
|
+
schema: 'schema',
|
|
134
|
+
},
|
|
135
|
+
]);
|
|
136
|
+
|
|
137
|
+
expect(result).toBe(
|
|
138
|
+
template(` await db.createEnum('mood', ['sad', 'ok', 'happy'], {
|
|
139
|
+
schema: 'schema',
|
|
140
|
+
});`),
|
|
60
141
|
);
|
|
61
142
|
});
|
|
62
143
|
|
|
63
144
|
describe('table', () => {
|
|
64
145
|
it('should create table', () => {
|
|
65
|
-
const result = astToMigration([
|
|
66
|
-
{
|
|
67
|
-
...tableAst,
|
|
68
|
-
shape: {
|
|
69
|
-
id: columnTypes.serial().primaryKey(),
|
|
70
|
-
},
|
|
71
|
-
},
|
|
72
|
-
]);
|
|
146
|
+
const result = astToMigration([table]);
|
|
73
147
|
|
|
74
148
|
expect(result).toBe(
|
|
75
149
|
template(` await db.createTable('schema.table', (t) => ({
|
|
@@ -81,7 +155,7 @@ describe('astToMigration', () => {
|
|
|
81
155
|
it('should add columns with indexes and foreignKeys', () => {
|
|
82
156
|
const result = astToMigration([
|
|
83
157
|
{
|
|
84
|
-
...
|
|
158
|
+
...table,
|
|
85
159
|
shape: {
|
|
86
160
|
someId: columnTypes
|
|
87
161
|
.integer()
|
|
@@ -116,7 +190,7 @@ change(async (db) => {
|
|
|
116
190
|
it('should add composite primaryKeys, indexes, foreignKeys', () => {
|
|
117
191
|
const result = astToMigration([
|
|
118
192
|
{
|
|
119
|
-
...
|
|
193
|
+
...table,
|
|
120
194
|
shape: {
|
|
121
195
|
id: columnTypes.serial().primaryKey(),
|
|
122
196
|
},
|
|
@@ -171,13 +245,8 @@ change(async (db) => {
|
|
|
171
245
|
it('should add standalone foreignKey', () => {
|
|
172
246
|
const result = astToMigration([
|
|
173
247
|
{
|
|
174
|
-
|
|
175
|
-
action: 'create',
|
|
248
|
+
...foreignKey,
|
|
176
249
|
tableSchema: 'custom',
|
|
177
|
-
tableName: 'table',
|
|
178
|
-
columns: ['otherId'],
|
|
179
|
-
fnOrTable: 'otherTable',
|
|
180
|
-
foreignColumns: ['id'],
|
|
181
250
|
options: {
|
|
182
251
|
name: 'fkey',
|
|
183
252
|
match: 'FULL',
|
|
@@ -16,30 +16,58 @@ import {
|
|
|
16
16
|
import { quoteSchemaTable } from '../common';
|
|
17
17
|
|
|
18
18
|
export const astToMigration = (ast: RakeDbAst[]): string | undefined => {
|
|
19
|
-
const
|
|
19
|
+
const first: Code[] = [];
|
|
20
|
+
const tables: Code[] = [];
|
|
21
|
+
const foreignKeys: Code[] = [];
|
|
20
22
|
for (const item of ast) {
|
|
21
23
|
if (item.type === 'schema' && item.action === 'create') {
|
|
22
|
-
|
|
24
|
+
first.push(createSchema(item));
|
|
23
25
|
} else if (item.type === 'extension' && item.action === 'create') {
|
|
24
|
-
if (
|
|
25
|
-
|
|
26
|
+
if (first.length) first.push([]);
|
|
27
|
+
first.push(...createExtension(item));
|
|
28
|
+
} else if (item.type === 'enum' && item.action === 'create') {
|
|
29
|
+
if (first.length) first.push([]);
|
|
30
|
+
first.push(...createEnum(item));
|
|
26
31
|
} else if (item.type === 'table' && item.action === 'create') {
|
|
27
|
-
|
|
28
|
-
code.push(...createTable(item));
|
|
32
|
+
tables.push(createTable(item));
|
|
29
33
|
} else if (item.type === 'foreignKey') {
|
|
30
|
-
if (
|
|
31
|
-
|
|
34
|
+
if (foreignKeys.length) foreignKeys.push([]);
|
|
35
|
+
foreignKeys.push(...createForeignKey(item));
|
|
32
36
|
}
|
|
33
37
|
}
|
|
34
38
|
|
|
35
|
-
if (!
|
|
39
|
+
if (!first.length && !tables.length && !foreignKeys.length) return;
|
|
40
|
+
|
|
41
|
+
let code = `import { change } from 'rake-db';
|
|
42
|
+
`;
|
|
36
43
|
|
|
37
|
-
|
|
44
|
+
if (first.length) {
|
|
45
|
+
code += `
|
|
46
|
+
change(async (db) => {
|
|
47
|
+
${codeToString(first, ' ', ' ')}
|
|
48
|
+
});
|
|
49
|
+
`;
|
|
50
|
+
}
|
|
38
51
|
|
|
52
|
+
if (tables.length) {
|
|
53
|
+
for (const table of tables) {
|
|
54
|
+
code += `
|
|
39
55
|
change(async (db) => {
|
|
40
|
-
${codeToString(
|
|
56
|
+
${codeToString(table, ' ', ' ')}
|
|
41
57
|
});
|
|
42
58
|
`;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (foreignKeys.length) {
|
|
63
|
+
code += `
|
|
64
|
+
change(async (db) => {
|
|
65
|
+
${codeToString(foreignKeys, ' ', ' ')}
|
|
66
|
+
});
|
|
67
|
+
`;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return code;
|
|
43
71
|
};
|
|
44
72
|
|
|
45
73
|
const createSchema = (ast: RakeDbAst.Schema) => {
|
|
@@ -58,7 +86,22 @@ const createExtension = (ast: RakeDbAst.Extension): Code[] => {
|
|
|
58
86
|
}
|
|
59
87
|
addCode(code, '}');
|
|
60
88
|
}
|
|
61
|
-
addCode(code, ')');
|
|
89
|
+
addCode(code, ');');
|
|
90
|
+
return code;
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const createEnum = (ast: RakeDbAst.Enum) => {
|
|
94
|
+
const code: Code[] = [
|
|
95
|
+
`await db.createEnum(${singleQuote(ast.name)}, [${ast.values
|
|
96
|
+
.map(singleQuote)
|
|
97
|
+
.join(', ')}]`,
|
|
98
|
+
];
|
|
99
|
+
if (ast.schema) {
|
|
100
|
+
addCode(code, ', {');
|
|
101
|
+
code.push([`schema: ${singleQuote(ast.schema)},`]);
|
|
102
|
+
addCode(code, '}');
|
|
103
|
+
}
|
|
104
|
+
addCode(code, ');');
|
|
62
105
|
return code;
|
|
63
106
|
};
|
|
64
107
|
|
|
@@ -163,4 +163,18 @@ describe('dbStructure', () => {
|
|
|
163
163
|
expect(result).toEqual(rows);
|
|
164
164
|
});
|
|
165
165
|
});
|
|
166
|
+
|
|
167
|
+
describe('getEnums', () => {
|
|
168
|
+
it('should return enums', async () => {
|
|
169
|
+
rows = [
|
|
170
|
+
{
|
|
171
|
+
schemaName: 'public',
|
|
172
|
+
name: 'mood',
|
|
173
|
+
values: ['sad', 'ok', 'happy'],
|
|
174
|
+
},
|
|
175
|
+
];
|
|
176
|
+
const result = await db.getEnums();
|
|
177
|
+
expect(result).toEqual(rows);
|
|
178
|
+
});
|
|
179
|
+
});
|
|
166
180
|
});
|