rake-db 2.2.4 → 2.2.6
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 +14 -0
- package/db.ts +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.esm.js +92 -60
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +92 -60
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/ast.ts +4 -0
- package/src/commands/migrateOrRollback.ts +8 -6
- package/src/common.test.ts +9 -6
- package/src/common.ts +21 -11
- package/src/migration/changeTable.test.ts +17 -0
- package/src/migration/changeTable.ts +13 -10
- package/src/migration/createJoinTable.test.ts +96 -0
- package/src/migration/createJoinTable.ts +17 -6
- package/src/migration/createTable.test.ts +16 -0
- package/src/migration/createTable.ts +11 -8
- package/src/migration/migration.test.ts +18 -86
- package/src/migration/migration.ts +18 -4
- package/src/migration/migrationUtils.ts +33 -21
- package/src/pull/dbStructure.test.ts +158 -0
- package/src/pull/dbStructure.ts +272 -0
- package/src/pull/getColumnByType.ts +15 -0
- package/src/pull/structureToAst.test.ts +308 -0
- package/src/pull/structureToAst.ts +145 -0
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
getMigrationFiles,
|
|
5
5
|
RakeDbConfig,
|
|
6
6
|
MigrationFile,
|
|
7
|
-
|
|
7
|
+
quoteWithSchema,
|
|
8
8
|
} from '../common';
|
|
9
9
|
import {
|
|
10
10
|
getCurrentPromise,
|
|
@@ -105,7 +105,9 @@ const saveMigratedVersion = async (
|
|
|
105
105
|
config: RakeDbConfig,
|
|
106
106
|
) => {
|
|
107
107
|
await db.query(
|
|
108
|
-
`INSERT INTO ${
|
|
108
|
+
`INSERT INTO ${quoteWithSchema({
|
|
109
|
+
name: config.migrationsTable,
|
|
110
|
+
})} VALUES ('${version}')`,
|
|
109
111
|
);
|
|
110
112
|
};
|
|
111
113
|
|
|
@@ -115,9 +117,9 @@ const removeMigratedVersion = async (
|
|
|
115
117
|
config: RakeDbConfig,
|
|
116
118
|
) => {
|
|
117
119
|
await db.query(
|
|
118
|
-
`DELETE FROM ${
|
|
119
|
-
config.migrationsTable,
|
|
120
|
-
)} WHERE version = '${version}'`,
|
|
120
|
+
`DELETE FROM ${quoteWithSchema({
|
|
121
|
+
name: config.migrationsTable,
|
|
122
|
+
})} WHERE version = '${version}'`,
|
|
121
123
|
);
|
|
122
124
|
};
|
|
123
125
|
|
|
@@ -127,7 +129,7 @@ const getMigratedVersionsMap = async (
|
|
|
127
129
|
): Promise<Record<string, boolean>> => {
|
|
128
130
|
try {
|
|
129
131
|
const result = await db.arrays<[string]>(
|
|
130
|
-
`SELECT * FROM ${
|
|
132
|
+
`SELECT * FROM ${quoteWithSchema({ name: config.migrationsTable })}`,
|
|
131
133
|
);
|
|
132
134
|
return Object.fromEntries(result.rows.map((row) => [row[0], true]));
|
|
133
135
|
} catch (err) {
|
package/src/common.test.ts
CHANGED
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
joinColumns,
|
|
9
9
|
joinWords,
|
|
10
10
|
migrationConfigDefaults,
|
|
11
|
-
|
|
11
|
+
quoteWithSchema,
|
|
12
12
|
setAdapterOptions,
|
|
13
13
|
setAdminCredentialsToOptions,
|
|
14
14
|
sortAsc,
|
|
@@ -48,6 +48,7 @@ describe('common', () => {
|
|
|
48
48
|
requireTs: expect.any(Function),
|
|
49
49
|
log: true,
|
|
50
50
|
logger: console,
|
|
51
|
+
useCodeUpdater: true,
|
|
51
52
|
});
|
|
52
53
|
});
|
|
53
54
|
});
|
|
@@ -284,13 +285,15 @@ describe('common', () => {
|
|
|
284
285
|
});
|
|
285
286
|
});
|
|
286
287
|
|
|
287
|
-
describe('
|
|
288
|
-
it('should quote a
|
|
289
|
-
expect(
|
|
288
|
+
describe('quoteWithSchema', () => {
|
|
289
|
+
it('should quote a name', () => {
|
|
290
|
+
expect(quoteWithSchema({ name: 'table' })).toBe('"table"');
|
|
290
291
|
});
|
|
291
292
|
|
|
292
|
-
it('should quote a
|
|
293
|
-
expect(
|
|
293
|
+
it('should quote a name with schema', () => {
|
|
294
|
+
expect(quoteWithSchema({ schema: 'schema', name: 'table' })).toBe(
|
|
295
|
+
'"schema"."table"',
|
|
296
|
+
);
|
|
294
297
|
});
|
|
295
298
|
});
|
|
296
299
|
});
|
package/src/common.ts
CHANGED
|
@@ -30,7 +30,7 @@ export const migrationConfigDefaults = {
|
|
|
30
30
|
requireTs: require,
|
|
31
31
|
log: true,
|
|
32
32
|
logger: console,
|
|
33
|
-
|
|
33
|
+
useCodeUpdater: true,
|
|
34
34
|
};
|
|
35
35
|
|
|
36
36
|
export const getMigrationConfigWithDefaults = (
|
|
@@ -126,9 +126,9 @@ export const createSchemaMigrations = async (
|
|
|
126
126
|
) => {
|
|
127
127
|
try {
|
|
128
128
|
await db.query(
|
|
129
|
-
`CREATE TABLE ${
|
|
130
|
-
config.migrationsTable,
|
|
131
|
-
)} ( version TEXT NOT NULL )`,
|
|
129
|
+
`CREATE TABLE ${quoteWithSchema({
|
|
130
|
+
name: config.migrationsTable,
|
|
131
|
+
})} ( version TEXT NOT NULL )`,
|
|
132
132
|
);
|
|
133
133
|
console.log('Created versions table');
|
|
134
134
|
} catch (err) {
|
|
@@ -235,11 +235,21 @@ export const joinColumns = (columns: string[]) => {
|
|
|
235
235
|
return columns.map((column) => `"${column}"`).join(', ');
|
|
236
236
|
};
|
|
237
237
|
|
|
238
|
-
export const
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
238
|
+
export const quoteWithSchema = ({
|
|
239
|
+
schema,
|
|
240
|
+
name,
|
|
241
|
+
}: {
|
|
242
|
+
schema?: string;
|
|
243
|
+
name: string;
|
|
244
|
+
}) => {
|
|
245
|
+
return schema ? `"${schema}"."${name}"` : `"${name}"`;
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
export const getSchemaAndTableFromName = (
|
|
249
|
+
name: string,
|
|
250
|
+
): [string | undefined, string] => {
|
|
251
|
+
const index = name.indexOf('.');
|
|
252
|
+
return index !== -1
|
|
253
|
+
? [name.slice(0, index), name.slice(index + 1)]
|
|
254
|
+
: [undefined, name];
|
|
245
255
|
};
|
|
@@ -18,6 +18,23 @@ describe('changeTable', () => {
|
|
|
18
18
|
expect(db.options.appCodeUpdater).toHaveBeenCalled();
|
|
19
19
|
});
|
|
20
20
|
|
|
21
|
+
it('should work for table with schema', async () => {
|
|
22
|
+
const fn = () => {
|
|
23
|
+
return db.changeTable('schema.table', (t) => ({
|
|
24
|
+
column: t.add(t.text()),
|
|
25
|
+
}));
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
await fn();
|
|
29
|
+
expectSql(
|
|
30
|
+
`ALTER TABLE "schema"."table"\nADD COLUMN "column" text NOT NULL`,
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
setDbDown();
|
|
34
|
+
await fn();
|
|
35
|
+
expectSql(`ALTER TABLE "schema"."table"\nDROP COLUMN "column"`);
|
|
36
|
+
});
|
|
37
|
+
|
|
21
38
|
it('should set comment', async () => {
|
|
22
39
|
const fn = () => {
|
|
23
40
|
return db.changeTable('table', { comment: 'comment' });
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
runCodeUpdater,
|
|
24
24
|
} from './migration';
|
|
25
25
|
import { RakeDbAst } from '../ast';
|
|
26
|
-
import {
|
|
26
|
+
import { getSchemaAndTableFromName, quoteWithSchema } from '../common';
|
|
27
27
|
import {
|
|
28
28
|
addColumnComment,
|
|
29
29
|
addColumnIndex,
|
|
@@ -135,7 +135,7 @@ const columnTypeToColumnChange = (
|
|
|
135
135
|
return {
|
|
136
136
|
column: item,
|
|
137
137
|
type: item.toSQL(),
|
|
138
|
-
nullable: item.isNullable,
|
|
138
|
+
nullable: item.data.isNullable,
|
|
139
139
|
primaryKey: item.isPrimaryKey,
|
|
140
140
|
...item.data,
|
|
141
141
|
foreignKey,
|
|
@@ -257,9 +257,12 @@ const makeAst = (
|
|
|
257
257
|
}
|
|
258
258
|
}
|
|
259
259
|
|
|
260
|
+
const [schema, table] = getSchemaAndTableFromName(name);
|
|
261
|
+
|
|
260
262
|
return {
|
|
261
263
|
type: 'changeTable',
|
|
262
|
-
|
|
264
|
+
schema,
|
|
265
|
+
name: table,
|
|
263
266
|
comment: comment
|
|
264
267
|
? up
|
|
265
268
|
? Array.isArray(comment)
|
|
@@ -287,7 +290,7 @@ const astToQueries = (ast: RakeDbAst.ChangeTable): Sql[] => {
|
|
|
287
290
|
|
|
288
291
|
if (ast.comment !== undefined) {
|
|
289
292
|
result.push({
|
|
290
|
-
text: `COMMENT ON TABLE ${
|
|
293
|
+
text: `COMMENT ON TABLE ${quoteWithSchema(ast)} IS ${quote(ast.comment)}`,
|
|
291
294
|
values: [],
|
|
292
295
|
});
|
|
293
296
|
}
|
|
@@ -493,7 +496,7 @@ const astToQueries = (ast: RakeDbAst.ChangeTable): Sql[] => {
|
|
|
493
496
|
|
|
494
497
|
prependAlterTable.push(
|
|
495
498
|
...dropForeignKeys.map(
|
|
496
|
-
(foreignKey) => `\n DROP ${constraintToSql(ast
|
|
499
|
+
(foreignKey) => `\n DROP ${constraintToSql(ast, false, foreignKey)}`,
|
|
497
500
|
),
|
|
498
501
|
);
|
|
499
502
|
|
|
@@ -509,22 +512,22 @@ const astToQueries = (ast: RakeDbAst.ChangeTable): Sql[] => {
|
|
|
509
512
|
|
|
510
513
|
alterTable.push(
|
|
511
514
|
...addForeignKeys.map(
|
|
512
|
-
(foreignKey) => `\n ADD ${constraintToSql(ast
|
|
515
|
+
(foreignKey) => `\n ADD ${constraintToSql(ast, true, foreignKey)}`,
|
|
513
516
|
),
|
|
514
517
|
);
|
|
515
518
|
|
|
516
519
|
if (alterTable.length) {
|
|
517
520
|
result.push({
|
|
518
521
|
text:
|
|
519
|
-
`ALTER TABLE ${
|
|
522
|
+
`ALTER TABLE ${quoteWithSchema(ast)}` +
|
|
520
523
|
`\n ${alterTable.join(',\n ')}`,
|
|
521
524
|
values,
|
|
522
525
|
});
|
|
523
526
|
}
|
|
524
527
|
|
|
525
|
-
result.push(...indexesToQuery(false, ast
|
|
526
|
-
result.push(...indexesToQuery(true, ast
|
|
527
|
-
result.push(...commentsToQuery(ast
|
|
528
|
+
result.push(...indexesToQuery(false, ast, dropIndexes));
|
|
529
|
+
result.push(...indexesToQuery(true, ast, addIndexes));
|
|
530
|
+
result.push(...commentsToQuery(ast, comments));
|
|
528
531
|
|
|
529
532
|
return result;
|
|
530
533
|
};
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { getPrimaryKeysOfTable } from './migrationUtils';
|
|
2
|
+
import { expectSql, getDb, queryMock, resetDb } from '../test-utils';
|
|
3
|
+
|
|
4
|
+
const db = getDb();
|
|
5
|
+
|
|
6
|
+
jest.mock('./migrationUtils', () => ({
|
|
7
|
+
...jest.requireActual('./migrationUtils'),
|
|
8
|
+
getPrimaryKeysOfTable: jest.fn(),
|
|
9
|
+
}));
|
|
10
|
+
|
|
11
|
+
describe('join table', () => {
|
|
12
|
+
beforeEach(resetDb);
|
|
13
|
+
|
|
14
|
+
(['createJoinTable', 'dropJoinTable'] as const).forEach((action) => {
|
|
15
|
+
describe(action, () => {
|
|
16
|
+
it(`should ${
|
|
17
|
+
action === 'createJoinTable' ? 'create' : 'drop'
|
|
18
|
+
} a join table`, async () => {
|
|
19
|
+
const fn = () => {
|
|
20
|
+
return db[action](['posts', 'comments'], (t) => ({
|
|
21
|
+
...t.timestamps(),
|
|
22
|
+
}));
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const expectCreateTable = async () => {
|
|
26
|
+
(getPrimaryKeysOfTable as jest.Mock)
|
|
27
|
+
.mockResolvedValueOnce([
|
|
28
|
+
{
|
|
29
|
+
name: 'uuid',
|
|
30
|
+
type: 'uuid',
|
|
31
|
+
},
|
|
32
|
+
])
|
|
33
|
+
.mockResolvedValueOnce([
|
|
34
|
+
{
|
|
35
|
+
name: 'id',
|
|
36
|
+
type: 'integer',
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
name: 'authorName',
|
|
40
|
+
type: 'text',
|
|
41
|
+
},
|
|
42
|
+
]);
|
|
43
|
+
|
|
44
|
+
await fn();
|
|
45
|
+
|
|
46
|
+
expectSql(`
|
|
47
|
+
CREATE TABLE "postsComments" (
|
|
48
|
+
"postUuid" uuid NOT NULL REFERENCES "posts"("uuid"),
|
|
49
|
+
"commentId" integer NOT NULL,
|
|
50
|
+
"commentAuthorName" text NOT NULL,
|
|
51
|
+
"createdAt" timestamp NOT NULL DEFAULT now(),
|
|
52
|
+
"updatedAt" timestamp NOT NULL DEFAULT now(),
|
|
53
|
+
PRIMARY KEY ("postUuid", "commentId", "commentAuthorName"),
|
|
54
|
+
CONSTRAINT "postsComments_commentId_commentAuthorName_fkey" FOREIGN KEY ("commentId", "commentAuthorName") REFERENCES "comments"("id", "authorName")
|
|
55
|
+
)
|
|
56
|
+
`);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const expectDropTable = async () => {
|
|
60
|
+
await fn();
|
|
61
|
+
|
|
62
|
+
expectSql(`
|
|
63
|
+
DROP TABLE "postsComments"
|
|
64
|
+
`);
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
await (action === 'createJoinTable'
|
|
68
|
+
? expectCreateTable
|
|
69
|
+
: expectDropTable)();
|
|
70
|
+
|
|
71
|
+
db.up = false;
|
|
72
|
+
queryMock.mockClear();
|
|
73
|
+
await (action === 'createJoinTable'
|
|
74
|
+
? expectDropTable
|
|
75
|
+
: expectCreateTable)();
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('should throw error if table has no primary key', async () => {
|
|
79
|
+
db.up = action !== 'dropJoinTable';
|
|
80
|
+
|
|
81
|
+
(getPrimaryKeysOfTable as jest.Mock)
|
|
82
|
+
.mockResolvedValueOnce([
|
|
83
|
+
{
|
|
84
|
+
name: 'id',
|
|
85
|
+
type: 'integer',
|
|
86
|
+
},
|
|
87
|
+
])
|
|
88
|
+
.mockResolvedValueOnce([]);
|
|
89
|
+
|
|
90
|
+
await expect(db[action](['posts', 'comments'])).rejects.toThrow(
|
|
91
|
+
'Primary key for table "comments" is not defined',
|
|
92
|
+
);
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
});
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { ColumnType, Operators } from 'pqb';
|
|
2
2
|
import { ColumnsShapeCallback, JoinTableOptions, Migration } from './migration';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
getSchemaAndTableFromName,
|
|
5
|
+
joinWords,
|
|
6
|
+
quoteWithSchema,
|
|
7
|
+
} from '../common';
|
|
4
8
|
import { getPrimaryKeysOfTable } from './migrationUtils';
|
|
5
9
|
import { singular } from 'pluralize';
|
|
6
10
|
import { createTable } from './createTable';
|
|
@@ -46,26 +50,33 @@ export const createJoinTable = async (
|
|
|
46
50
|
})),
|
|
47
51
|
);
|
|
48
52
|
|
|
53
|
+
const [schema, name] = getSchemaAndTableFromName(table);
|
|
49
54
|
if (!primaryKeys.length) {
|
|
50
55
|
throw new Error(
|
|
51
|
-
`Primary key for table ${
|
|
56
|
+
`Primary key for table ${quoteWithSchema({
|
|
57
|
+
schema,
|
|
58
|
+
name,
|
|
59
|
+
})} is not defined`,
|
|
52
60
|
);
|
|
53
61
|
}
|
|
54
62
|
|
|
55
|
-
return [table, primaryKeys] as const;
|
|
63
|
+
return [schema, table, primaryKeys] as const;
|
|
56
64
|
}),
|
|
57
65
|
);
|
|
58
66
|
|
|
59
67
|
return createTable(migration, up, tableName, options, (t) => {
|
|
60
68
|
const result: Record<string, ColumnType> = {};
|
|
61
69
|
|
|
62
|
-
tablesWithPrimaryKeys.forEach(([table, primaryKeys]) => {
|
|
70
|
+
tablesWithPrimaryKeys.forEach(([schema, table, primaryKeys]) => {
|
|
63
71
|
if (primaryKeys.length === 1) {
|
|
64
72
|
const [{ type, joinedName, name }] = primaryKeys;
|
|
65
73
|
|
|
66
74
|
const column = new UnknownColumn(type);
|
|
67
75
|
|
|
68
|
-
result[joinedName] = column.foreignKey(
|
|
76
|
+
result[joinedName] = column.foreignKey(
|
|
77
|
+
schema ? `${schema}.${table}` : table,
|
|
78
|
+
name,
|
|
79
|
+
);
|
|
69
80
|
|
|
70
81
|
return;
|
|
71
82
|
}
|
|
@@ -86,7 +97,7 @@ export const createJoinTable = async (
|
|
|
86
97
|
}
|
|
87
98
|
|
|
88
99
|
t.primaryKey(
|
|
89
|
-
tablesWithPrimaryKeys.flatMap(([, primaryKeys]) =>
|
|
100
|
+
tablesWithPrimaryKeys.flatMap(([, , primaryKeys]) =>
|
|
90
101
|
primaryKeys.map((item) => item.joinedName),
|
|
91
102
|
),
|
|
92
103
|
);
|
|
@@ -14,6 +14,22 @@ const db = getDb();
|
|
|
14
14
|
expect(db.options.appCodeUpdater).toHaveBeenCalled();
|
|
15
15
|
});
|
|
16
16
|
|
|
17
|
+
it(`should ${action} with schema`, async () => {
|
|
18
|
+
await db[action]('schema.name', (t) => ({ id: t.serial().primaryKey() }));
|
|
19
|
+
|
|
20
|
+
if (action === 'createTable') {
|
|
21
|
+
expectSql(`
|
|
22
|
+
CREATE TABLE "schema"."name" (
|
|
23
|
+
"id" serial PRIMARY KEY
|
|
24
|
+
)
|
|
25
|
+
`);
|
|
26
|
+
} else {
|
|
27
|
+
expectSql(`
|
|
28
|
+
DROP TABLE "schema"."name"
|
|
29
|
+
`);
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
|
|
17
33
|
it(`should ${action} with comment`, async () => {
|
|
18
34
|
await db[action]('name', { comment: 'this is a table comment' }, (t) => ({
|
|
19
35
|
id: t.serial().primaryKey(),
|
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
indexesToQuery,
|
|
26
26
|
primaryKeyToSql,
|
|
27
27
|
} from './migrationUtils';
|
|
28
|
-
import {
|
|
28
|
+
import { getSchemaAndTableFromName, quoteWithSchema } from '../common';
|
|
29
29
|
import { RakeDbAst } from '../ast';
|
|
30
30
|
|
|
31
31
|
const types = Object.assign(Object.create(columnTypes), {
|
|
@@ -77,10 +77,13 @@ const makeAst = (
|
|
|
77
77
|
|
|
78
78
|
const primaryKey = tableData.primaryKey;
|
|
79
79
|
|
|
80
|
+
const [schema, table] = getSchemaAndTableFromName(tableName);
|
|
81
|
+
|
|
80
82
|
return {
|
|
81
83
|
type: 'table',
|
|
82
84
|
action: up ? 'create' : 'drop',
|
|
83
|
-
|
|
85
|
+
schema,
|
|
86
|
+
name: table,
|
|
84
87
|
shape,
|
|
85
88
|
...tableData,
|
|
86
89
|
primaryKey:
|
|
@@ -121,7 +124,7 @@ const astToQueries = (ast: RakeDbAst.Table): Sql[] => {
|
|
|
121
124
|
if (ast.action === 'drop') {
|
|
122
125
|
return [
|
|
123
126
|
{
|
|
124
|
-
text: `DROP TABLE ${
|
|
127
|
+
text: `DROP TABLE ${quoteWithSchema(ast)}${
|
|
125
128
|
ast.dropMode ? ` ${ast.dropMode}` : ''
|
|
126
129
|
}`,
|
|
127
130
|
values: [],
|
|
@@ -146,23 +149,23 @@ const astToQueries = (ast: RakeDbAst.Table): Sql[] => {
|
|
|
146
149
|
}
|
|
147
150
|
|
|
148
151
|
ast.foreignKeys.forEach((foreignKey) => {
|
|
149
|
-
lines.push(`\n ${constraintToSql(ast
|
|
152
|
+
lines.push(`\n ${constraintToSql(ast, true, foreignKey)}`);
|
|
150
153
|
});
|
|
151
154
|
|
|
152
155
|
indexes.push(...ast.indexes);
|
|
153
156
|
|
|
154
157
|
const result: Sql[] = [
|
|
155
158
|
{
|
|
156
|
-
text: `CREATE TABLE ${
|
|
159
|
+
text: `CREATE TABLE ${quoteWithSchema(ast)} (${lines.join(',')}\n)`,
|
|
157
160
|
values,
|
|
158
161
|
},
|
|
159
|
-
...indexesToQuery(true, ast
|
|
160
|
-
...commentsToQuery(ast
|
|
162
|
+
...indexesToQuery(true, ast, indexes),
|
|
163
|
+
...commentsToQuery(ast, comments),
|
|
161
164
|
];
|
|
162
165
|
|
|
163
166
|
if (ast.comment) {
|
|
164
167
|
result.push({
|
|
165
|
-
text: `COMMENT ON TABLE ${
|
|
168
|
+
text: `COMMENT ON TABLE ${quoteWithSchema(ast)} IS ${quote(ast.comment)}`,
|
|
166
169
|
values: [],
|
|
167
170
|
});
|
|
168
171
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { expectSql, getDb, queryMock, resetDb, toLine } from '../test-utils';
|
|
2
|
-
import { getPrimaryKeysOfTable } from './migrationUtils';
|
|
3
2
|
|
|
4
3
|
const db = getDb();
|
|
5
4
|
|
|
@@ -37,6 +36,24 @@ describe('migration', () => {
|
|
|
37
36
|
});
|
|
38
37
|
});
|
|
39
38
|
|
|
39
|
+
it('should rename table with schema', async () => {
|
|
40
|
+
const fn = () => {
|
|
41
|
+
return db.renameTable('one.from', 'two.to');
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
await fn();
|
|
45
|
+
expectSql(`
|
|
46
|
+
ALTER TABLE "one"."from" RENAME TO "two"."to"
|
|
47
|
+
`);
|
|
48
|
+
|
|
49
|
+
db.up = false;
|
|
50
|
+
queryMock.mockClear();
|
|
51
|
+
await fn();
|
|
52
|
+
expectSql(`
|
|
53
|
+
ALTER TABLE "two"."to" RENAME TO "one"."from"
|
|
54
|
+
`);
|
|
55
|
+
});
|
|
56
|
+
|
|
40
57
|
(['addColumn', 'dropColumn'] as const).forEach((action) => {
|
|
41
58
|
describe(action, () => {
|
|
42
59
|
it(`should use changeTable to ${
|
|
@@ -249,91 +266,6 @@ describe('migration', () => {
|
|
|
249
266
|
});
|
|
250
267
|
});
|
|
251
268
|
|
|
252
|
-
(['createJoinTable', 'dropJoinTable'] as const).forEach((action) => {
|
|
253
|
-
describe(action, () => {
|
|
254
|
-
it(`should ${
|
|
255
|
-
action === 'createJoinTable' ? 'create' : 'drop'
|
|
256
|
-
} a join table`, async () => {
|
|
257
|
-
const fn = () => {
|
|
258
|
-
return db[action](['posts', 'comments'], (t) => ({
|
|
259
|
-
...t.timestamps(),
|
|
260
|
-
}));
|
|
261
|
-
};
|
|
262
|
-
|
|
263
|
-
const expectCreateTable = async () => {
|
|
264
|
-
(getPrimaryKeysOfTable as jest.Mock)
|
|
265
|
-
.mockResolvedValueOnce([
|
|
266
|
-
{
|
|
267
|
-
name: 'uuid',
|
|
268
|
-
type: 'uuid',
|
|
269
|
-
},
|
|
270
|
-
])
|
|
271
|
-
.mockResolvedValueOnce([
|
|
272
|
-
{
|
|
273
|
-
name: 'id',
|
|
274
|
-
type: 'integer',
|
|
275
|
-
},
|
|
276
|
-
{
|
|
277
|
-
name: 'authorName',
|
|
278
|
-
type: 'text',
|
|
279
|
-
},
|
|
280
|
-
]);
|
|
281
|
-
|
|
282
|
-
await fn();
|
|
283
|
-
|
|
284
|
-
expectSql(`
|
|
285
|
-
CREATE TABLE "postsComments" (
|
|
286
|
-
"postUuid" uuid NOT NULL REFERENCES "posts"("uuid"),
|
|
287
|
-
"commentId" integer NOT NULL,
|
|
288
|
-
"commentAuthorName" text NOT NULL,
|
|
289
|
-
"createdAt" timestamp NOT NULL DEFAULT now(),
|
|
290
|
-
"updatedAt" timestamp NOT NULL DEFAULT now(),
|
|
291
|
-
PRIMARY KEY ("postUuid", "commentId", "commentAuthorName"),
|
|
292
|
-
CONSTRAINT "postsComments_commentId_commentAuthorName_fkey" FOREIGN KEY ("commentId", "commentAuthorName") REFERENCES "comments"("id", "authorName")
|
|
293
|
-
)
|
|
294
|
-
`);
|
|
295
|
-
};
|
|
296
|
-
|
|
297
|
-
const expectDropTable = async () => {
|
|
298
|
-
await fn();
|
|
299
|
-
|
|
300
|
-
expectSql(`
|
|
301
|
-
DROP TABLE "postsComments"
|
|
302
|
-
`);
|
|
303
|
-
};
|
|
304
|
-
|
|
305
|
-
await (action === 'createJoinTable'
|
|
306
|
-
? expectCreateTable
|
|
307
|
-
: expectDropTable)();
|
|
308
|
-
|
|
309
|
-
db.up = false;
|
|
310
|
-
queryMock.mockClear();
|
|
311
|
-
await (action === 'createJoinTable'
|
|
312
|
-
? expectDropTable
|
|
313
|
-
: expectCreateTable)();
|
|
314
|
-
});
|
|
315
|
-
|
|
316
|
-
it('should throw error if table has no primary key', async () => {
|
|
317
|
-
if (action === 'dropJoinTable') {
|
|
318
|
-
db.up = false;
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
(getPrimaryKeysOfTable as jest.Mock)
|
|
322
|
-
.mockResolvedValueOnce([
|
|
323
|
-
{
|
|
324
|
-
name: 'id',
|
|
325
|
-
type: 'integer',
|
|
326
|
-
},
|
|
327
|
-
])
|
|
328
|
-
.mockResolvedValueOnce([]);
|
|
329
|
-
|
|
330
|
-
await expect(db[action](['posts', 'comments'])).rejects.toThrow(
|
|
331
|
-
'Primary key for table "comments" is not defined',
|
|
332
|
-
);
|
|
333
|
-
});
|
|
334
|
-
});
|
|
335
|
-
});
|
|
336
|
-
|
|
337
269
|
(['createSchema', 'dropSchema'] as const).forEach((action) => {
|
|
338
270
|
describe(action, () => {
|
|
339
271
|
it('should call appCodeUpdater', async () => {
|
|
@@ -21,7 +21,11 @@ import {
|
|
|
21
21
|
} from 'pqb';
|
|
22
22
|
import { createTable } from './createTable';
|
|
23
23
|
import { changeTable, TableChangeData, TableChanger } from './changeTable';
|
|
24
|
-
import {
|
|
24
|
+
import {
|
|
25
|
+
RakeDbConfig,
|
|
26
|
+
quoteWithSchema,
|
|
27
|
+
getSchemaAndTableFromName,
|
|
28
|
+
} from '../common';
|
|
25
29
|
import { createJoinTable } from './createJoinTable';
|
|
26
30
|
import { RakeDbAst } from '../ast';
|
|
27
31
|
|
|
@@ -179,14 +183,24 @@ export class Migration extends TransactionAdapter {
|
|
|
179
183
|
}
|
|
180
184
|
|
|
181
185
|
async renameTable(from: string, to: string): Promise<void> {
|
|
186
|
+
const [fromSchema, f] = getSchemaAndTableFromName(this.up ? from : to);
|
|
187
|
+
const [toSchema, t] = getSchemaAndTableFromName(this.up ? to : from);
|
|
182
188
|
const ast: RakeDbAst.RenameTable = {
|
|
183
189
|
type: 'renameTable',
|
|
184
|
-
|
|
185
|
-
|
|
190
|
+
fromSchema,
|
|
191
|
+
from: f,
|
|
192
|
+
toSchema,
|
|
193
|
+
to: t,
|
|
186
194
|
};
|
|
187
195
|
|
|
188
196
|
await this.query(
|
|
189
|
-
`ALTER TABLE ${
|
|
197
|
+
`ALTER TABLE ${quoteWithSchema({
|
|
198
|
+
schema: ast.fromSchema,
|
|
199
|
+
name: ast.from,
|
|
200
|
+
})} RENAME TO ${quoteWithSchema({
|
|
201
|
+
schema: ast.toSchema,
|
|
202
|
+
name: ast.to,
|
|
203
|
+
})}`,
|
|
190
204
|
);
|
|
191
205
|
|
|
192
206
|
await runCodeUpdater(this, ast);
|