rake-db 2.3.30 → 2.3.31
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/package.json +11 -21
- package/.env +0 -1
- package/.env.local +0 -2
- package/.turbo/turbo-check.log +0 -23
- package/.turbo/turbo-test.log +0 -22
- package/.turbo/turbo-test:ci.log +0 -22
- package/CHANGELOG.md +0 -395
- package/app/dbScript.ts +0 -33
- package/app/migrations/20221017181504_createUser.ts +0 -14
- package/app/migrations/20221017200111_createProfile.ts +0 -10
- package/app/migrations/20221017200252_createChat.ts +0 -9
- package/app/migrations/20221017200326_createChatUser.ts +0 -10
- package/app/migrations/20221017200900_createMessage.ts +0 -12
- package/app/migrations/20221017201235_createGeoSchema.ts +0 -5
- package/app/migrations/20221017210011_createCountry.ts +0 -8
- package/app/migrations/20221017210133_createCity.ts +0 -9
- package/app/migrations/20221105202843_createUniqueTable.ts +0 -12
- package/jest-setup.ts +0 -3
- package/rollup.config.js +0 -3
- package/src/ast.ts +0 -130
- package/src/commands/createOrDrop.test.ts +0 -214
- package/src/commands/createOrDrop.ts +0 -151
- package/src/commands/generate.test.ts +0 -136
- package/src/commands/generate.ts +0 -93
- package/src/commands/migrateOrRollback.test.ts +0 -267
- package/src/commands/migrateOrRollback.ts +0 -190
- package/src/common.test.ts +0 -295
- package/src/common.ts +0 -353
- package/src/errors.ts +0 -3
- package/src/index.ts +0 -8
- package/src/migration/change.test.ts +0 -16
- package/src/migration/change.ts +0 -15
- package/src/migration/changeTable.test.ts +0 -897
- package/src/migration/changeTable.ts +0 -566
- package/src/migration/createTable.test.ts +0 -384
- package/src/migration/createTable.ts +0 -193
- package/src/migration/migration.test.ts +0 -430
- package/src/migration/migration.ts +0 -518
- package/src/migration/migrationUtils.ts +0 -307
- package/src/migration/tableMethods.ts +0 -8
- package/src/pull/astToMigration.test.ts +0 -275
- package/src/pull/astToMigration.ts +0 -173
- package/src/pull/dbStructure.test.ts +0 -180
- package/src/pull/dbStructure.ts +0 -413
- package/src/pull/pull.test.ts +0 -115
- package/src/pull/pull.ts +0 -22
- package/src/pull/structureToAst.test.ts +0 -841
- package/src/pull/structureToAst.ts +0 -372
- package/src/rakeDb.test.ts +0 -131
- package/src/rakeDb.ts +0 -84
- package/src/test-utils.ts +0 -64
- package/tsconfig.json +0 -12
|
@@ -1,372 +0,0 @@
|
|
|
1
|
-
import { DbStructure } from './dbStructure';
|
|
2
|
-
import { RakeDbAst } from '../ast';
|
|
3
|
-
import {
|
|
4
|
-
columnsByType,
|
|
5
|
-
ColumnsShape,
|
|
6
|
-
ForeignKeyOptions,
|
|
7
|
-
instantiateColumn,
|
|
8
|
-
singleQuote,
|
|
9
|
-
TableData,
|
|
10
|
-
} from 'pqb';
|
|
11
|
-
import { getForeignKeyName, getIndexName } from '../migration/migrationUtils';
|
|
12
|
-
|
|
13
|
-
const matchMap = {
|
|
14
|
-
s: undefined,
|
|
15
|
-
f: 'FULL',
|
|
16
|
-
p: 'PARTIAL',
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
const fkeyActionMap = {
|
|
20
|
-
a: undefined, // default
|
|
21
|
-
r: 'RESTRICT',
|
|
22
|
-
c: 'CASCADE',
|
|
23
|
-
n: 'SET NULL',
|
|
24
|
-
d: 'SET DEFAULT',
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
type Data = {
|
|
28
|
-
schemas: string[];
|
|
29
|
-
tables: DbStructure.Table[];
|
|
30
|
-
columns: DbStructure.Column[];
|
|
31
|
-
primaryKeys: DbStructure.PrimaryKey[];
|
|
32
|
-
indexes: DbStructure.Index[];
|
|
33
|
-
foreignKeys: DbStructure.ForeignKey[];
|
|
34
|
-
extensions: DbStructure.Extension[];
|
|
35
|
-
enums: DbStructure.Enum[];
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
type PendingTables = Record<
|
|
39
|
-
string,
|
|
40
|
-
{ table: DbStructure.Table; dependsOn: Set<string> }
|
|
41
|
-
>;
|
|
42
|
-
|
|
43
|
-
export const structureToAst = async (db: DbStructure): Promise<RakeDbAst[]> => {
|
|
44
|
-
const ast: RakeDbAst[] = [];
|
|
45
|
-
|
|
46
|
-
const data = await getData(db);
|
|
47
|
-
|
|
48
|
-
for (const name of data.schemas) {
|
|
49
|
-
if (name === 'public') continue;
|
|
50
|
-
|
|
51
|
-
ast.push({
|
|
52
|
-
type: 'schema',
|
|
53
|
-
action: 'create',
|
|
54
|
-
name,
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const pendingTables: PendingTables = {};
|
|
59
|
-
for (const table of data.tables) {
|
|
60
|
-
const key = `${table.schemaName}.${table.name}`;
|
|
61
|
-
const dependsOn = new Set<string>();
|
|
62
|
-
|
|
63
|
-
for (const fk of data.foreignKeys) {
|
|
64
|
-
if (fk.schemaName !== table.schemaName || fk.tableName !== table.name)
|
|
65
|
-
continue;
|
|
66
|
-
|
|
67
|
-
const otherKey = `${fk.foreignTableSchemaName}.${fk.foreignTableName}`;
|
|
68
|
-
if (otherKey !== key) {
|
|
69
|
-
dependsOn.add(otherKey);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
pendingTables[key] = { table, dependsOn };
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
for (const key in pendingTables) {
|
|
77
|
-
const { table, dependsOn } = pendingTables[key];
|
|
78
|
-
if (!dependsOn.size) {
|
|
79
|
-
pushTableAst(ast, data, table, pendingTables);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const outerFKeys: [DbStructure.ForeignKey, DbStructure.Table][] = [];
|
|
84
|
-
|
|
85
|
-
for (const it of data.extensions) {
|
|
86
|
-
ast.push({
|
|
87
|
-
type: 'extension',
|
|
88
|
-
action: 'create',
|
|
89
|
-
name: it.name,
|
|
90
|
-
schema: it.schemaName === 'public' ? undefined : it.schemaName,
|
|
91
|
-
version: it.version,
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
for (const it of data.enums) {
|
|
96
|
-
ast.push({
|
|
97
|
-
type: 'enum',
|
|
98
|
-
action: 'create',
|
|
99
|
-
name: it.name,
|
|
100
|
-
schema: it.schemaName === 'public' ? undefined : it.schemaName,
|
|
101
|
-
values: it.values,
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
for (const key in pendingTables) {
|
|
106
|
-
const innerFKeys: DbStructure.ForeignKey[] = [];
|
|
107
|
-
const { table } = pendingTables[key];
|
|
108
|
-
|
|
109
|
-
for (const fkey of data.foreignKeys) {
|
|
110
|
-
if (fkey.schemaName !== table.schemaName || fkey.tableName !== table.name)
|
|
111
|
-
continue;
|
|
112
|
-
|
|
113
|
-
const otherKey = `${fkey.foreignTableSchemaName}.${fkey.foreignTableName}`;
|
|
114
|
-
if (!pendingTables[otherKey] || otherKey === key) {
|
|
115
|
-
innerFKeys.push(fkey);
|
|
116
|
-
} else {
|
|
117
|
-
outerFKeys.push([fkey, table]);
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
pushTableAst(ast, data, table, pendingTables, innerFKeys);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
for (const [fkey, table] of outerFKeys) {
|
|
125
|
-
ast.push({
|
|
126
|
-
...foreignKeyToAst(fkey),
|
|
127
|
-
type: 'foreignKey',
|
|
128
|
-
action: 'create',
|
|
129
|
-
tableSchema: table.schemaName === 'public' ? undefined : table.schemaName,
|
|
130
|
-
tableName: fkey.tableName,
|
|
131
|
-
});
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
return ast;
|
|
135
|
-
};
|
|
136
|
-
|
|
137
|
-
const getData = async (db: DbStructure): Promise<Data> => {
|
|
138
|
-
const [
|
|
139
|
-
schemas,
|
|
140
|
-
tables,
|
|
141
|
-
columns,
|
|
142
|
-
primaryKeys,
|
|
143
|
-
indexes,
|
|
144
|
-
foreignKeys,
|
|
145
|
-
extensions,
|
|
146
|
-
enums,
|
|
147
|
-
] = await Promise.all([
|
|
148
|
-
db.getSchemas(),
|
|
149
|
-
db.getTables(),
|
|
150
|
-
db.getColumns(),
|
|
151
|
-
db.getPrimaryKeys(),
|
|
152
|
-
db.getIndexes(),
|
|
153
|
-
db.getForeignKeys(),
|
|
154
|
-
db.getExtensions(),
|
|
155
|
-
db.getEnums(),
|
|
156
|
-
]);
|
|
157
|
-
|
|
158
|
-
return {
|
|
159
|
-
schemas,
|
|
160
|
-
tables,
|
|
161
|
-
columns,
|
|
162
|
-
primaryKeys,
|
|
163
|
-
indexes,
|
|
164
|
-
foreignKeys,
|
|
165
|
-
extensions,
|
|
166
|
-
enums,
|
|
167
|
-
};
|
|
168
|
-
};
|
|
169
|
-
|
|
170
|
-
const makeBelongsToTable =
|
|
171
|
-
(schema: string | undefined, table: string) =>
|
|
172
|
-
(item: { schemaName: string; tableName: string }) =>
|
|
173
|
-
item.schemaName === schema && item.tableName === table;
|
|
174
|
-
|
|
175
|
-
const getIsSerial = (item: DbStructure.Column) => {
|
|
176
|
-
if (item.type === 'int2' || item.type === 'int4' || item.type === 'int8') {
|
|
177
|
-
const { default: def, schemaName, tableName, name } = item;
|
|
178
|
-
const seq = `${tableName}_${name}_seq`;
|
|
179
|
-
if (
|
|
180
|
-
def &&
|
|
181
|
-
(def === `nextval(${singleQuote(`${seq}`)}::regclass)` ||
|
|
182
|
-
def === `nextval(${singleQuote(`"${seq}"`)}::regclass)` ||
|
|
183
|
-
def === `nextval(${singleQuote(`${schemaName}.${seq}`)}::regclass)` ||
|
|
184
|
-
def === `nextval(${singleQuote(`"${schemaName}".${seq}`)}::regclass)` ||
|
|
185
|
-
def === `nextval(${singleQuote(`${schemaName}."${seq}"`)}::regclass)` ||
|
|
186
|
-
def === `nextval(${singleQuote(`"${schemaName}"."${seq}"`)}::regclass)`)
|
|
187
|
-
) {
|
|
188
|
-
return true;
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
return false;
|
|
193
|
-
};
|
|
194
|
-
|
|
195
|
-
const getColumnType = (item: DbStructure.Column, isSerial: boolean) => {
|
|
196
|
-
if (isSerial) {
|
|
197
|
-
return item.type === 'int2'
|
|
198
|
-
? 'smallserial'
|
|
199
|
-
: item.type === 'int4'
|
|
200
|
-
? 'serial'
|
|
201
|
-
: 'bigserial';
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
return item.type;
|
|
205
|
-
};
|
|
206
|
-
|
|
207
|
-
const pushTableAst = (
|
|
208
|
-
ast: RakeDbAst[],
|
|
209
|
-
data: Data,
|
|
210
|
-
table: DbStructure.Table,
|
|
211
|
-
pendingTables: PendingTables,
|
|
212
|
-
innerFKeys = data.foreignKeys,
|
|
213
|
-
) => {
|
|
214
|
-
const { schemaName, name } = table;
|
|
215
|
-
|
|
216
|
-
const key = `${schemaName}.${table.name}`;
|
|
217
|
-
delete pendingTables[key];
|
|
218
|
-
|
|
219
|
-
if (name === 'schemaMigrations') return;
|
|
220
|
-
|
|
221
|
-
const belongsToTable = makeBelongsToTable(schemaName, name);
|
|
222
|
-
|
|
223
|
-
const columns = data.columns.filter(belongsToTable);
|
|
224
|
-
const primaryKey = data.primaryKeys.find(belongsToTable);
|
|
225
|
-
const tableIndexes = data.indexes.filter(belongsToTable);
|
|
226
|
-
const tableForeignKeys = innerFKeys.filter(belongsToTable);
|
|
227
|
-
|
|
228
|
-
const shape: ColumnsShape = {};
|
|
229
|
-
for (let item of columns) {
|
|
230
|
-
const isSerial = getIsSerial(item);
|
|
231
|
-
if (isSerial) {
|
|
232
|
-
item = { ...item, default: undefined };
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
const klass = columnsByType[getColumnType(item, isSerial)];
|
|
236
|
-
if (!klass) {
|
|
237
|
-
throw new Error(`Column type \`${item.type}\` is not supported`);
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
let column = instantiateColumn(klass, item);
|
|
241
|
-
|
|
242
|
-
if (
|
|
243
|
-
primaryKey?.columnNames.length === 1 &&
|
|
244
|
-
primaryKey?.columnNames[0] === item.name
|
|
245
|
-
) {
|
|
246
|
-
column = column.primaryKey();
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
const indexes = tableIndexes.filter(
|
|
250
|
-
(it) =>
|
|
251
|
-
it.columns.length === 1 &&
|
|
252
|
-
'column' in it.columns[0] &&
|
|
253
|
-
it.columns[0].column === item.name,
|
|
254
|
-
);
|
|
255
|
-
for (const index of indexes) {
|
|
256
|
-
const options = index.columns[0];
|
|
257
|
-
column = column.index({
|
|
258
|
-
collate: options.collate,
|
|
259
|
-
opclass: options.opclass,
|
|
260
|
-
order: options.order,
|
|
261
|
-
name:
|
|
262
|
-
index.name !== getIndexName(name, index.columns)
|
|
263
|
-
? index.name
|
|
264
|
-
: undefined,
|
|
265
|
-
using: index.using === 'btree' ? undefined : index.using,
|
|
266
|
-
unique: index.isUnique,
|
|
267
|
-
include: index.include,
|
|
268
|
-
with: index.with,
|
|
269
|
-
tablespace: index.tablespace,
|
|
270
|
-
where: index.where,
|
|
271
|
-
});
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
const foreignKeys = tableForeignKeys.filter(
|
|
275
|
-
(it) => it.columnNames.length === 1 && it.columnNames[0] === item.name,
|
|
276
|
-
);
|
|
277
|
-
for (const foreignKey of foreignKeys) {
|
|
278
|
-
column = column.foreignKey(
|
|
279
|
-
foreignKey.foreignTableName,
|
|
280
|
-
foreignKey.foreignColumnNames[0],
|
|
281
|
-
{
|
|
282
|
-
name:
|
|
283
|
-
foreignKey.name &&
|
|
284
|
-
foreignKey.name !== getForeignKeyName(name, foreignKey.columnNames)
|
|
285
|
-
? foreignKey.name
|
|
286
|
-
: undefined,
|
|
287
|
-
match: matchMap[foreignKey.match],
|
|
288
|
-
onUpdate: fkeyActionMap[foreignKey.onUpdate],
|
|
289
|
-
onDelete: fkeyActionMap[foreignKey.onDelete],
|
|
290
|
-
} as ForeignKeyOptions,
|
|
291
|
-
);
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
shape[item.name] = column;
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
ast.push({
|
|
298
|
-
type: 'table',
|
|
299
|
-
action: 'create',
|
|
300
|
-
schema: schemaName === 'public' ? undefined : schemaName,
|
|
301
|
-
comment: table.comment,
|
|
302
|
-
name: name,
|
|
303
|
-
shape,
|
|
304
|
-
noPrimaryKey: primaryKey ? 'error' : 'ignore',
|
|
305
|
-
primaryKey:
|
|
306
|
-
primaryKey && primaryKey.columnNames.length > 1
|
|
307
|
-
? {
|
|
308
|
-
columns: primaryKey.columnNames,
|
|
309
|
-
options:
|
|
310
|
-
primaryKey.name === `${name}_pkey`
|
|
311
|
-
? undefined
|
|
312
|
-
: { name: primaryKey.name },
|
|
313
|
-
}
|
|
314
|
-
: undefined,
|
|
315
|
-
indexes: tableIndexes
|
|
316
|
-
.filter(
|
|
317
|
-
(index) =>
|
|
318
|
-
index.columns.length > 1 ||
|
|
319
|
-
index.columns.some((it) => 'expression' in it),
|
|
320
|
-
)
|
|
321
|
-
.map((index) => ({
|
|
322
|
-
columns: index.columns.map((it) => ({
|
|
323
|
-
...('column' in it
|
|
324
|
-
? { column: it.column }
|
|
325
|
-
: { expression: it.expression }),
|
|
326
|
-
collate: it.collate,
|
|
327
|
-
opclass: it.opclass,
|
|
328
|
-
order: it.order,
|
|
329
|
-
})),
|
|
330
|
-
options: {
|
|
331
|
-
name:
|
|
332
|
-
index.name !== getIndexName(name, index.columns)
|
|
333
|
-
? index.name
|
|
334
|
-
: undefined,
|
|
335
|
-
using: index.using === 'btree' ? undefined : index.using,
|
|
336
|
-
unique: index.isUnique,
|
|
337
|
-
include: index.include,
|
|
338
|
-
with: index.with,
|
|
339
|
-
tablespace: index.tablespace,
|
|
340
|
-
where: index.where,
|
|
341
|
-
},
|
|
342
|
-
})),
|
|
343
|
-
foreignKeys: tableForeignKeys
|
|
344
|
-
.filter((it) => it.columnNames.length > 1)
|
|
345
|
-
.map(foreignKeyToAst),
|
|
346
|
-
});
|
|
347
|
-
|
|
348
|
-
for (const otherKey in pendingTables) {
|
|
349
|
-
const item = pendingTables[otherKey];
|
|
350
|
-
if (item.dependsOn.delete(key) && item.dependsOn.size === 0) {
|
|
351
|
-
pushTableAst(ast, data, item.table, pendingTables);
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
};
|
|
355
|
-
|
|
356
|
-
const foreignKeyToAst = (
|
|
357
|
-
fkey: DbStructure.ForeignKey,
|
|
358
|
-
): TableData.ForeignKey => ({
|
|
359
|
-
columns: fkey.columnNames,
|
|
360
|
-
fnOrTable: fkey.foreignTableName,
|
|
361
|
-
foreignColumns: fkey.foreignColumnNames,
|
|
362
|
-
options: {
|
|
363
|
-
name:
|
|
364
|
-
fkey.name &&
|
|
365
|
-
fkey.name !== getForeignKeyName(fkey.tableName, fkey.columnNames)
|
|
366
|
-
? fkey.name
|
|
367
|
-
: undefined,
|
|
368
|
-
match: matchMap[fkey.match],
|
|
369
|
-
onUpdate: fkeyActionMap[fkey.onUpdate],
|
|
370
|
-
onDelete: fkeyActionMap[fkey.onDelete],
|
|
371
|
-
} as ForeignKeyOptions,
|
|
372
|
-
});
|
package/src/rakeDb.test.ts
DELETED
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
import { rakeDb } from './rakeDb';
|
|
2
|
-
import { createDb, dropDb, resetDb } from './commands/createOrDrop';
|
|
3
|
-
import { migrate, rollback } from './commands/migrateOrRollback';
|
|
4
|
-
import { generate } from './commands/generate';
|
|
5
|
-
import { pullDbStructure } from './pull/pull';
|
|
6
|
-
import { RakeDbError } from './errors';
|
|
7
|
-
|
|
8
|
-
jest.mock('./common', () => ({
|
|
9
|
-
processRakeDbConfig: (config: unknown) => config,
|
|
10
|
-
}));
|
|
11
|
-
|
|
12
|
-
jest.mock('./commands/createOrDrop', () => ({
|
|
13
|
-
createDb: jest.fn(),
|
|
14
|
-
dropDb: jest.fn(),
|
|
15
|
-
resetDb: jest.fn(),
|
|
16
|
-
}));
|
|
17
|
-
|
|
18
|
-
jest.mock('./commands/migrateOrRollback', () => ({
|
|
19
|
-
migrate: jest.fn(),
|
|
20
|
-
rollback: jest.fn(),
|
|
21
|
-
}));
|
|
22
|
-
|
|
23
|
-
jest.mock('./commands/generate', () => ({
|
|
24
|
-
generate: jest.fn(),
|
|
25
|
-
}));
|
|
26
|
-
|
|
27
|
-
jest.mock('./pull/pull', () => ({
|
|
28
|
-
pullDbStructure: jest.fn(),
|
|
29
|
-
}));
|
|
30
|
-
|
|
31
|
-
const options = [
|
|
32
|
-
{
|
|
33
|
-
databaseURL: 'one',
|
|
34
|
-
},
|
|
35
|
-
{
|
|
36
|
-
databaseURL: 'two',
|
|
37
|
-
},
|
|
38
|
-
];
|
|
39
|
-
|
|
40
|
-
const config = {
|
|
41
|
-
migrationsPath: 'migrations',
|
|
42
|
-
commands: {},
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
describe('rakeDb', () => {
|
|
46
|
-
test('create', async () => {
|
|
47
|
-
await rakeDb(options, config, ['create']);
|
|
48
|
-
|
|
49
|
-
expect(createDb).toBeCalledWith(options, config);
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
test('drop', async () => {
|
|
53
|
-
await rakeDb(options, config, ['drop']);
|
|
54
|
-
|
|
55
|
-
expect(dropDb).toBeCalledWith(options);
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
test('reset', async () => {
|
|
59
|
-
await rakeDb(options, config, ['reset']);
|
|
60
|
-
|
|
61
|
-
expect(resetDb).toBeCalledWith(options, config);
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
test('migrate', async () => {
|
|
65
|
-
await rakeDb(options, config, ['migrate', 'arg']);
|
|
66
|
-
|
|
67
|
-
expect(migrate).toBeCalledWith(options, config, ['arg']);
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
test('rollback', async () => {
|
|
71
|
-
await rakeDb(options, config, ['rollback', 'arg']);
|
|
72
|
-
|
|
73
|
-
expect(rollback).toBeCalledWith(options, config, ['arg']);
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
test('generate', async () => {
|
|
77
|
-
await rakeDb(options, config, ['g', 'arg']);
|
|
78
|
-
|
|
79
|
-
expect(generate).toBeCalledWith(config, ['arg']);
|
|
80
|
-
|
|
81
|
-
jest.clearAllMocks();
|
|
82
|
-
|
|
83
|
-
await rakeDb(options, config, ['generate', 'arg']);
|
|
84
|
-
|
|
85
|
-
expect(generate).toBeCalledWith(config, ['arg']);
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
test('pull', async () => {
|
|
89
|
-
await rakeDb(options, config, ['pull']);
|
|
90
|
-
|
|
91
|
-
expect(pullDbStructure).toBeCalledWith(options[0], config);
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
test('custom command', async () => {
|
|
95
|
-
const custom = jest.fn();
|
|
96
|
-
|
|
97
|
-
const conf = { ...config, commands: { custom } };
|
|
98
|
-
|
|
99
|
-
await rakeDb(options, conf, ['custom', 'arg']);
|
|
100
|
-
|
|
101
|
-
expect(custom).toBeCalledWith(options, conf, ['arg']);
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
test('other', async () => {
|
|
105
|
-
const log = jest.fn();
|
|
106
|
-
console.log = log;
|
|
107
|
-
|
|
108
|
-
await rakeDb(options, config, ['other']);
|
|
109
|
-
|
|
110
|
-
expect(log).toBeCalled();
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
it('should log error and exit process with 1 when RakeDbError thrown', async () => {
|
|
114
|
-
const errorLog = jest.fn();
|
|
115
|
-
const exit = jest.fn(() => undefined as never);
|
|
116
|
-
console.error = errorLog;
|
|
117
|
-
process.exit = exit;
|
|
118
|
-
|
|
119
|
-
const err = new RakeDbError('message');
|
|
120
|
-
const custom = () => {
|
|
121
|
-
throw err;
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
const conf = { ...config, commands: { custom } };
|
|
125
|
-
|
|
126
|
-
await expect(() => rakeDb(options, conf, ['custom'])).rejects.toThrow(err);
|
|
127
|
-
|
|
128
|
-
expect(errorLog).toBeCalledWith('message');
|
|
129
|
-
expect(exit).toBeCalledWith(1);
|
|
130
|
-
});
|
|
131
|
-
});
|
package/src/rakeDb.ts
DELETED
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
import { AdapterOptions, MaybeArray, toArray } from 'pqb';
|
|
2
|
-
import { createDb, dropDb, resetDb } from './commands/createOrDrop';
|
|
3
|
-
import { migrate, rollback } from './commands/migrateOrRollback';
|
|
4
|
-
import { processRakeDbConfig, RakeDbConfig } from './common';
|
|
5
|
-
import { generate } from './commands/generate';
|
|
6
|
-
import { pullDbStructure } from './pull/pull';
|
|
7
|
-
import { RakeDbError } from './errors';
|
|
8
|
-
|
|
9
|
-
export const rakeDb = async (
|
|
10
|
-
options: MaybeArray<AdapterOptions>,
|
|
11
|
-
partialConfig: Partial<RakeDbConfig> = {},
|
|
12
|
-
args: string[] = process.argv.slice(2),
|
|
13
|
-
) => {
|
|
14
|
-
const config = processRakeDbConfig(partialConfig);
|
|
15
|
-
|
|
16
|
-
const command = args[0]?.split(':')[0];
|
|
17
|
-
|
|
18
|
-
try {
|
|
19
|
-
if (command === 'create') {
|
|
20
|
-
await createDb(options, config);
|
|
21
|
-
} else if (command === 'drop') {
|
|
22
|
-
await dropDb(options);
|
|
23
|
-
} else if (command === 'reset') {
|
|
24
|
-
await resetDb(options, config);
|
|
25
|
-
} else if (command === 'migrate') {
|
|
26
|
-
await migrate(options, config, args.slice(1));
|
|
27
|
-
} else if (command === 'rollback') {
|
|
28
|
-
await rollback(options, config, args.slice(1));
|
|
29
|
-
} else if (command === 'g' || command === 'generate') {
|
|
30
|
-
await generate(config, args.slice(1));
|
|
31
|
-
} else if (command === 'pull') {
|
|
32
|
-
await pullDbStructure(toArray(options)[0], config);
|
|
33
|
-
} else if (config.commands[command]) {
|
|
34
|
-
await config.commands[command](toArray(options), config, args.slice(1));
|
|
35
|
-
} else {
|
|
36
|
-
printHelp();
|
|
37
|
-
}
|
|
38
|
-
} catch (err) {
|
|
39
|
-
if (err instanceof RakeDbError) {
|
|
40
|
-
console.error(err.message);
|
|
41
|
-
process.exit(1);
|
|
42
|
-
}
|
|
43
|
-
throw err;
|
|
44
|
-
}
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
const printHelp = () =>
|
|
48
|
-
console.log(
|
|
49
|
-
`Usage: rake-db [command] [arguments]
|
|
50
|
-
|
|
51
|
-
Commands:
|
|
52
|
-
create create databases
|
|
53
|
-
drop drop databases
|
|
54
|
-
reset drop, create and migrate databases
|
|
55
|
-
g, generate generate migration file, see below
|
|
56
|
-
migrate migrate pending migrations
|
|
57
|
-
rollback rollback the last migrated
|
|
58
|
-
no or unknown command prints this message
|
|
59
|
-
|
|
60
|
-
Migrate arguments:
|
|
61
|
-
no arguments run all pending migrations
|
|
62
|
-
number run specific number of pending migrations
|
|
63
|
-
|
|
64
|
-
Rollback arguments:
|
|
65
|
-
no arguments rollback one last applied migration
|
|
66
|
-
number rollback specific number of applied migrations
|
|
67
|
-
all rollback all applied migrations
|
|
68
|
-
|
|
69
|
-
Migrate and rollback common arguments:
|
|
70
|
-
--code run code updater, overrides \`useCodeUpdater\` option
|
|
71
|
-
--code false do not run code updater
|
|
72
|
-
|
|
73
|
-
Generate arguments:
|
|
74
|
-
- (required) first argument is migration name
|
|
75
|
-
* create* template for create table
|
|
76
|
-
* change* template for change table
|
|
77
|
-
* add*To* template for add columns
|
|
78
|
-
* remove*From* template for remove columns
|
|
79
|
-
* drop* template for drop table
|
|
80
|
-
|
|
81
|
-
- other arguments considered as columns with types and optional methods:
|
|
82
|
-
rake-db g createTable id:serial.primaryKey name:text.nullable
|
|
83
|
-
`,
|
|
84
|
-
);
|
package/src/test-utils.ts
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import { createMigrationInterface, Migration } from './migration/migration';
|
|
2
|
-
import { MaybeArray, toArray, TransactionAdapter } from 'pqb';
|
|
3
|
-
|
|
4
|
-
export const asMock = (fn: unknown) => fn as jest.Mock;
|
|
5
|
-
|
|
6
|
-
let db: Migration | undefined;
|
|
7
|
-
|
|
8
|
-
export const getDb = () => {
|
|
9
|
-
if (db) return db;
|
|
10
|
-
|
|
11
|
-
db = createMigrationInterface(
|
|
12
|
-
{} as unknown as TransactionAdapter,
|
|
13
|
-
true,
|
|
14
|
-
{
|
|
15
|
-
basePath: __dirname,
|
|
16
|
-
log: false,
|
|
17
|
-
migrationsPath: 'migrations-path',
|
|
18
|
-
migrationsTable: 'schemaMigrations',
|
|
19
|
-
import: require,
|
|
20
|
-
appCodeUpdater: appCodeUpdaterMock,
|
|
21
|
-
commands: {},
|
|
22
|
-
},
|
|
23
|
-
{},
|
|
24
|
-
{},
|
|
25
|
-
);
|
|
26
|
-
db.adapter.query = queryMock;
|
|
27
|
-
db.adapter.arrays = queryMock;
|
|
28
|
-
return db;
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
export const queryMock = jest.fn();
|
|
32
|
-
const appCodeUpdaterMock = jest.fn();
|
|
33
|
-
|
|
34
|
-
export const resetDb = () => {
|
|
35
|
-
queryMock.mockClear();
|
|
36
|
-
queryMock.mockResolvedValue(undefined);
|
|
37
|
-
appCodeUpdaterMock.mockClear();
|
|
38
|
-
getDb().up = true;
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
export const setDbDown = () => {
|
|
42
|
-
getDb().up = false;
|
|
43
|
-
queryMock.mockClear();
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
export const trim = (s: string) => {
|
|
47
|
-
return s.trim().replace(/\n\s+/g, '\n');
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
export const toLine = (s: string) => {
|
|
51
|
-
return s.trim().replace(/\n\s*/g, ' ');
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
export const expectSql = (sql: MaybeArray<string>) => {
|
|
55
|
-
expect(
|
|
56
|
-
queryMock.mock.calls.map((call) =>
|
|
57
|
-
trim(
|
|
58
|
-
typeof call[0] === 'string'
|
|
59
|
-
? call[0]
|
|
60
|
-
: (call[0] as { text: string }).text,
|
|
61
|
-
),
|
|
62
|
-
),
|
|
63
|
-
).toEqual(toArray(sql).map(trim));
|
|
64
|
-
};
|