rake-db 2.2.3 → 2.2.4
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 +10 -0
- package/db.ts +8 -0
- package/dist/index.d.ts +12 -4
- package/dist/index.esm.js +169 -120
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +169 -119
- package/dist/index.js.map +1 -1
- package/migrations/20221017200326_createChatUser.ts +3 -0
- package/package.json +2 -2
- package/src/commands/migrateOrRollback.test.ts +86 -12
- package/src/commands/migrateOrRollback.ts +23 -4
- package/src/common.ts +7 -1
- package/src/migration/changeTable.ts +2 -1
- package/src/migration/createTable.ts +2 -1
- package/src/migration/migration.ts +14 -3
- package/src/rakeDb.ts +19 -6
- package/src/test-utils.ts +15 -7
|
@@ -3,6 +3,8 @@ import { createSchemaMigrations, migrationConfigDefaults } from '../common';
|
|
|
3
3
|
import { getMigrationFiles } from '../common';
|
|
4
4
|
import { Adapter, noop, TransactionAdapter } from 'pqb';
|
|
5
5
|
import { Migration } from '../migration/migration';
|
|
6
|
+
import { change } from '../migration/change';
|
|
7
|
+
import { asMock } from '../test-utils';
|
|
6
8
|
|
|
7
9
|
jest.mock('../common', () => ({
|
|
8
10
|
...jest.requireActual('../common'),
|
|
@@ -23,6 +25,7 @@ Adapter.prototype.arrays = getMigratedVersionsArrayMock;
|
|
|
23
25
|
|
|
24
26
|
const queryMock = jest.fn();
|
|
25
27
|
Adapter.prototype.query = queryMock;
|
|
28
|
+
queryMock.mockImplementation(() => undefined);
|
|
26
29
|
|
|
27
30
|
Adapter.prototype.transaction = (cb) => {
|
|
28
31
|
return cb({} as unknown as TransactionAdapter);
|
|
@@ -43,17 +46,32 @@ const config = {
|
|
|
43
46
|
},
|
|
44
47
|
};
|
|
45
48
|
|
|
49
|
+
const createTableCallback = () => {
|
|
50
|
+
change(async (db) => {
|
|
51
|
+
await db.createTable('table', (t) => ({
|
|
52
|
+
id: t.serial().primaryKey(),
|
|
53
|
+
}));
|
|
54
|
+
});
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
let migrationFiles: { path: string; version: string }[] = [];
|
|
58
|
+
asMock(getMigrationFiles).mockImplementation(() => migrationFiles);
|
|
59
|
+
|
|
60
|
+
let migratedVersions: string[] = [];
|
|
61
|
+
getMigratedVersionsArrayMock.mockImplementation(() => ({
|
|
62
|
+
rows: migratedVersions.map((version) => [version]),
|
|
63
|
+
}));
|
|
64
|
+
|
|
46
65
|
describe('migrateOrRollback', () => {
|
|
47
66
|
beforeEach(() => {
|
|
48
67
|
jest.clearAllMocks();
|
|
68
|
+
requireTsMock.mockImplementation(() => undefined);
|
|
49
69
|
});
|
|
50
70
|
|
|
51
71
|
describe('migrate', () => {
|
|
52
72
|
it('should work properly', async () => {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
queryMock.mockReturnValueOnce(undefined);
|
|
56
|
-
requireTsMock.mockResolvedValue(undefined);
|
|
73
|
+
migrationFiles = files;
|
|
74
|
+
migratedVersions = ['1'];
|
|
57
75
|
|
|
58
76
|
await migrate(options, config, []);
|
|
59
77
|
|
|
@@ -74,7 +92,7 @@ describe('migrateOrRollback', () => {
|
|
|
74
92
|
});
|
|
75
93
|
|
|
76
94
|
it('should create migrations table if it not exist', async () => {
|
|
77
|
-
|
|
95
|
+
migrationFiles = [];
|
|
78
96
|
getMigratedVersionsArrayMock.mockRejectedValueOnce({ code: '42P01' });
|
|
79
97
|
(createSchemaMigrations as jest.Mock).mockResolvedValueOnce(undefined);
|
|
80
98
|
|
|
@@ -86,16 +104,72 @@ describe('migrateOrRollback', () => {
|
|
|
86
104
|
expect(transactionQueryMock).not.toBeCalled();
|
|
87
105
|
expect(config.logger.log).not.toBeCalled();
|
|
88
106
|
});
|
|
107
|
+
|
|
108
|
+
it('should call appCodeUpdater only on the first run', async () => {
|
|
109
|
+
migrationFiles = [files[0]];
|
|
110
|
+
migratedVersions = [];
|
|
111
|
+
requireTsMock.mockImplementationOnce(createTableCallback);
|
|
112
|
+
const appCodeUpdater = jest.fn();
|
|
113
|
+
|
|
114
|
+
await migrate(
|
|
115
|
+
[options, options],
|
|
116
|
+
{ ...config, appCodeUpdater, useCodeUpdater: true },
|
|
117
|
+
[],
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
expect(appCodeUpdater).toBeCalledTimes(1);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it('should not call appCodeUpdater when useCodeUpdater is set to false in config', async () => {
|
|
124
|
+
migrationFiles = [files[0]];
|
|
125
|
+
migratedVersions = [];
|
|
126
|
+
requireTsMock.mockImplementation(createTableCallback);
|
|
127
|
+
const appCodeUpdater = jest.fn();
|
|
128
|
+
|
|
129
|
+
await migrate(
|
|
130
|
+
options,
|
|
131
|
+
{ ...config, appCodeUpdater, useCodeUpdater: false },
|
|
132
|
+
[],
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
expect(appCodeUpdater).not.toBeCalled();
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it('should not call appCodeUpdater when having argument --code false', async () => {
|
|
139
|
+
migrationFiles = [files[0]];
|
|
140
|
+
migratedVersions = [];
|
|
141
|
+
requireTsMock.mockImplementation(createTableCallback);
|
|
142
|
+
const appCodeUpdater = jest.fn();
|
|
143
|
+
|
|
144
|
+
await migrate(
|
|
145
|
+
options,
|
|
146
|
+
{ ...config, appCodeUpdater, useCodeUpdater: true },
|
|
147
|
+
['--code', 'false'],
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
expect(appCodeUpdater).not.toBeCalled();
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it('should call appCodeUpdater when having argument --code', async () => {
|
|
154
|
+
migrationFiles = [files[0]];
|
|
155
|
+
migratedVersions = [];
|
|
156
|
+
requireTsMock.mockImplementation(createTableCallback);
|
|
157
|
+
const appCodeUpdater = jest.fn();
|
|
158
|
+
|
|
159
|
+
await migrate(
|
|
160
|
+
options,
|
|
161
|
+
{ ...config, appCodeUpdater, useCodeUpdater: false },
|
|
162
|
+
['--code'],
|
|
163
|
+
);
|
|
164
|
+
|
|
165
|
+
expect(appCodeUpdater).toBeCalled();
|
|
166
|
+
});
|
|
89
167
|
});
|
|
90
168
|
|
|
91
169
|
describe('rollback', () => {
|
|
92
170
|
it('should work properly', async () => {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
rows: [['1'], ['2']],
|
|
96
|
-
});
|
|
97
|
-
queryMock.mockReturnValueOnce(undefined);
|
|
98
|
-
requireTsMock.mockResolvedValue(undefined);
|
|
171
|
+
migrationFiles = files.reverse();
|
|
172
|
+
migratedVersions = ['1', '2'];
|
|
99
173
|
|
|
100
174
|
await rollback(options, config, []);
|
|
101
175
|
|
|
@@ -114,7 +188,7 @@ describe('migrateOrRollback', () => {
|
|
|
114
188
|
});
|
|
115
189
|
|
|
116
190
|
it('should create migrations table if it not exist', async () => {
|
|
117
|
-
|
|
191
|
+
migrationFiles = [];
|
|
118
192
|
getMigratedVersionsArrayMock.mockRejectedValueOnce({ code: '42P01' });
|
|
119
193
|
(createSchemaMigrations as jest.Mock).mockResolvedValueOnce(undefined);
|
|
120
194
|
|
|
@@ -22,10 +22,25 @@ const migrateOrRollback = async (
|
|
|
22
22
|
args: string[],
|
|
23
23
|
up: boolean,
|
|
24
24
|
) => {
|
|
25
|
+
config = { ...config };
|
|
25
26
|
const files = await getMigrationFiles(config, up);
|
|
26
27
|
|
|
27
|
-
|
|
28
|
-
let
|
|
28
|
+
let count = up ? Infinity : 1;
|
|
29
|
+
let argI = 0;
|
|
30
|
+
const num = args[0] === 'all' ? Infinity : parseInt(args[0]);
|
|
31
|
+
if (!isNaN(num)) {
|
|
32
|
+
argI++;
|
|
33
|
+
count = num;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const arg = args[argI];
|
|
37
|
+
if (arg === '--code') {
|
|
38
|
+
config.useCodeUpdater = args[argI + 1] !== 'false';
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (!config.useCodeUpdater) delete config.appCodeUpdater;
|
|
42
|
+
|
|
43
|
+
const appCodeUpdaterCache = {};
|
|
29
44
|
|
|
30
45
|
for (const opts of toArray(options)) {
|
|
31
46
|
const db = new Adapter(opts);
|
|
@@ -41,12 +56,14 @@ const migrateOrRollback = async (
|
|
|
41
56
|
|
|
42
57
|
if (count-- <= 0) break;
|
|
43
58
|
|
|
44
|
-
await processMigration(db, up, file, config);
|
|
59
|
+
await processMigration(db, up, file, config, opts, appCodeUpdaterCache);
|
|
45
60
|
config.logger?.log(`${file.path} ${up ? 'migrated' : 'rolled back'}`);
|
|
46
61
|
}
|
|
47
62
|
} finally {
|
|
48
63
|
await db.close();
|
|
49
64
|
}
|
|
65
|
+
// use appCodeUpdater only for the first provided options
|
|
66
|
+
delete config.appCodeUpdater;
|
|
50
67
|
}
|
|
51
68
|
};
|
|
52
69
|
|
|
@@ -57,9 +74,11 @@ const processMigration = async (
|
|
|
57
74
|
up: boolean,
|
|
58
75
|
file: MigrationFile,
|
|
59
76
|
config: RakeDbConfig,
|
|
77
|
+
options: AdapterOptions,
|
|
78
|
+
appCodeUpdaterCache: object,
|
|
60
79
|
) => {
|
|
61
80
|
await db.transaction(async (tx) => {
|
|
62
|
-
const db = new Migration(tx, up, config);
|
|
81
|
+
const db = new Migration(tx, up, config, options, appCodeUpdaterCache);
|
|
63
82
|
setCurrentMigration(db);
|
|
64
83
|
setCurrentMigrationUp(up);
|
|
65
84
|
|
package/src/common.ts
CHANGED
|
@@ -15,9 +15,14 @@ export type RakeDbConfig = {
|
|
|
15
15
|
requireTs(path: string): void;
|
|
16
16
|
noPrimaryKey?: NoPrimaryKeyOption;
|
|
17
17
|
appCodeUpdater?: AppCodeUpdater;
|
|
18
|
+
useCodeUpdater?: boolean;
|
|
18
19
|
} & QueryLogOptions;
|
|
19
20
|
|
|
20
|
-
export type AppCodeUpdater = (
|
|
21
|
+
export type AppCodeUpdater = (params: {
|
|
22
|
+
ast: RakeDbAst;
|
|
23
|
+
options: AdapterOptions;
|
|
24
|
+
cache: object;
|
|
25
|
+
}) => Promise<void>;
|
|
21
26
|
|
|
22
27
|
export const migrationConfigDefaults = {
|
|
23
28
|
migrationsPath: path.resolve(process.cwd(), 'src', 'migrations'),
|
|
@@ -25,6 +30,7 @@ export const migrationConfigDefaults = {
|
|
|
25
30
|
requireTs: require,
|
|
26
31
|
log: true,
|
|
27
32
|
logger: console,
|
|
33
|
+
useCodeUpdaterByDefault: true,
|
|
28
34
|
};
|
|
29
35
|
|
|
30
36
|
export const getMigrationConfigWithDefaults = (
|
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
DropMode,
|
|
21
21
|
Migration,
|
|
22
22
|
MigrationColumnTypes,
|
|
23
|
+
runCodeUpdater,
|
|
23
24
|
} from './migration';
|
|
24
25
|
import { RakeDbAst } from '../ast';
|
|
25
26
|
import { quoteTable } from '../common';
|
|
@@ -218,7 +219,7 @@ export const changeTable = async (
|
|
|
218
219
|
await migration.query(query);
|
|
219
220
|
}
|
|
220
221
|
|
|
221
|
-
await migration
|
|
222
|
+
await runCodeUpdater(migration, ast);
|
|
222
223
|
};
|
|
223
224
|
|
|
224
225
|
const makeAst = (
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
ColumnComment,
|
|
14
14
|
ColumnsShapeCallback,
|
|
15
15
|
Migration,
|
|
16
|
+
runCodeUpdater,
|
|
16
17
|
TableOptions,
|
|
17
18
|
} from './migration';
|
|
18
19
|
import {
|
|
@@ -56,7 +57,7 @@ export const createTable = async (
|
|
|
56
57
|
await migration.query(query);
|
|
57
58
|
}
|
|
58
59
|
|
|
59
|
-
await migration
|
|
60
|
+
await runCodeUpdater(migration, ast);
|
|
60
61
|
};
|
|
61
62
|
|
|
62
63
|
const makeAst = (
|
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
TypeParsers,
|
|
18
18
|
raw,
|
|
19
19
|
TextColumn,
|
|
20
|
+
AdapterOptions,
|
|
20
21
|
} from 'pqb';
|
|
21
22
|
import { createTable } from './createTable';
|
|
22
23
|
import { changeTable, TableChangeData, TableChanger } from './changeTable';
|
|
@@ -67,6 +68,8 @@ export class Migration extends TransactionAdapter {
|
|
|
67
68
|
tx: TransactionAdapter,
|
|
68
69
|
public up: boolean,
|
|
69
70
|
public options: RakeDbConfig,
|
|
71
|
+
public adapterOptions: AdapterOptions,
|
|
72
|
+
public appCodeUpdaterCache: object,
|
|
70
73
|
) {
|
|
71
74
|
super(tx, tx.client, tx.types);
|
|
72
75
|
this.log = logParamToLogObject(options.logger || console, options.log);
|
|
@@ -186,7 +189,7 @@ export class Migration extends TransactionAdapter {
|
|
|
186
189
|
`ALTER TABLE ${quoteTable(ast.from)} RENAME TO "${ast.to}"`,
|
|
187
190
|
);
|
|
188
191
|
|
|
189
|
-
await this
|
|
192
|
+
await runCodeUpdater(this, ast);
|
|
190
193
|
}
|
|
191
194
|
|
|
192
195
|
addColumn(
|
|
@@ -417,7 +420,7 @@ const createSchema = async (
|
|
|
417
420
|
`${ast.action === 'create' ? 'CREATE' : 'DROP'} SCHEMA "${name}"`,
|
|
418
421
|
);
|
|
419
422
|
|
|
420
|
-
await migration
|
|
423
|
+
await runCodeUpdater(migration, ast);
|
|
421
424
|
};
|
|
422
425
|
|
|
423
426
|
const createExtension = async (
|
|
@@ -450,7 +453,7 @@ const createExtension = async (
|
|
|
450
453
|
|
|
451
454
|
await migration.query(query);
|
|
452
455
|
|
|
453
|
-
await migration
|
|
456
|
+
await runCodeUpdater(migration, ast);
|
|
454
457
|
};
|
|
455
458
|
|
|
456
459
|
const queryExists = (
|
|
@@ -459,3 +462,11 @@ const queryExists = (
|
|
|
459
462
|
) => {
|
|
460
463
|
return db.query(sql).then(({ rowCount }) => rowCount > 0);
|
|
461
464
|
};
|
|
465
|
+
|
|
466
|
+
export const runCodeUpdater = (migration: Migration, ast: RakeDbAst) => {
|
|
467
|
+
return migration.options.appCodeUpdater?.({
|
|
468
|
+
ast,
|
|
469
|
+
options: migration.adapterOptions,
|
|
470
|
+
cache: migration.appCodeUpdaterCache,
|
|
471
|
+
});
|
|
472
|
+
};
|
package/src/rakeDb.ts
CHANGED
|
@@ -39,17 +39,30 @@ Commands:
|
|
|
39
39
|
drop drop databases
|
|
40
40
|
reset drop, create and migrate databases
|
|
41
41
|
g, generate generate migration file, see below
|
|
42
|
-
migrate migrate
|
|
42
|
+
migrate migrate pending migrations
|
|
43
43
|
rollback rollback the last migrated
|
|
44
44
|
no or unknown command prints this message
|
|
45
45
|
|
|
46
|
+
Migrate arguments:
|
|
47
|
+
no arguments run all pending migrations
|
|
48
|
+
number run specific number of pending migrations
|
|
49
|
+
|
|
50
|
+
Rollback arguments:
|
|
51
|
+
no arguments rollback one last applied migration
|
|
52
|
+
number rollback specific number of applied migrations
|
|
53
|
+
all rollback all applied migrations
|
|
54
|
+
|
|
55
|
+
Migrate and rollback common arguments:
|
|
56
|
+
--code run code updater, overrides \`useCodeUpdater\` option
|
|
57
|
+
--code false do not run code updater
|
|
58
|
+
|
|
46
59
|
Generate arguments:
|
|
47
60
|
- (required) first argument is migration name
|
|
48
|
-
* create*
|
|
49
|
-
* change*
|
|
50
|
-
* add*To*
|
|
51
|
-
* remove*From*
|
|
52
|
-
* drop*
|
|
61
|
+
* create* template for create table
|
|
62
|
+
* change* template for change table
|
|
63
|
+
* add*To* template for add columns
|
|
64
|
+
* remove*From* template for remove columns
|
|
65
|
+
* drop* template for drop table
|
|
53
66
|
|
|
54
67
|
- other arguments considered as columns with types and optional methods:
|
|
55
68
|
rake-db g createTable id:serial.primaryKey name:text.nullable
|
package/src/test-utils.ts
CHANGED
|
@@ -1,18 +1,26 @@
|
|
|
1
1
|
import { Migration } from './migration/migration';
|
|
2
2
|
import { MaybeArray, toArray, TransactionAdapter } from 'pqb';
|
|
3
3
|
|
|
4
|
+
export const asMock = (fn: unknown) => fn as jest.Mock;
|
|
5
|
+
|
|
4
6
|
let db: Migration | undefined;
|
|
5
7
|
|
|
6
8
|
export const getDb = () => {
|
|
7
9
|
if (db) return db;
|
|
8
10
|
|
|
9
|
-
db = new Migration(
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
db = new Migration(
|
|
12
|
+
{} as unknown as TransactionAdapter,
|
|
13
|
+
true,
|
|
14
|
+
{
|
|
15
|
+
log: false,
|
|
16
|
+
migrationsPath: 'migrations-path',
|
|
17
|
+
migrationsTable: 'schemaMigrations',
|
|
18
|
+
requireTs: require,
|
|
19
|
+
appCodeUpdater: appCodeUpdaterMock,
|
|
20
|
+
},
|
|
21
|
+
{},
|
|
22
|
+
{},
|
|
23
|
+
);
|
|
16
24
|
db.query = queryMock;
|
|
17
25
|
return db;
|
|
18
26
|
};
|