rake-db 2.3.29 → 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-test.log +0 -22
- package/.turbo/turbo-test:ci.log +0 -22
- package/CHANGELOG.md +0 -388
- 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,841 +0,0 @@
|
|
|
1
|
-
import { DbStructure } from './dbStructure';
|
|
2
|
-
import {
|
|
3
|
-
Adapter,
|
|
4
|
-
BigSerialColumn,
|
|
5
|
-
DecimalColumn,
|
|
6
|
-
IntegerColumn,
|
|
7
|
-
isRaw,
|
|
8
|
-
RawExpression,
|
|
9
|
-
SerialColumn,
|
|
10
|
-
SmallSerialColumn,
|
|
11
|
-
TextColumn,
|
|
12
|
-
TimestampColumn,
|
|
13
|
-
VarCharColumn,
|
|
14
|
-
} from 'pqb';
|
|
15
|
-
import { structureToAst } from './structureToAst';
|
|
16
|
-
import { RakeDbAst } from '../ast';
|
|
17
|
-
import { getIndexName } from '../migration/migrationUtils';
|
|
18
|
-
|
|
19
|
-
const adapter = new Adapter({ databaseURL: 'file:path' });
|
|
20
|
-
const query = jest.fn().mockImplementation(() => ({ rows: [] }));
|
|
21
|
-
adapter.query = query;
|
|
22
|
-
adapter.arrays = query;
|
|
23
|
-
|
|
24
|
-
const intColumn: DbStructure.Column = {
|
|
25
|
-
schemaName: 'public',
|
|
26
|
-
tableName: 'table',
|
|
27
|
-
name: 'column',
|
|
28
|
-
type: 'int4',
|
|
29
|
-
default: '123',
|
|
30
|
-
isNullable: false,
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
const varCharColumn: DbStructure.Column = {
|
|
34
|
-
...intColumn,
|
|
35
|
-
name: 'varchar',
|
|
36
|
-
type: 'character varying',
|
|
37
|
-
collation: 'en_US',
|
|
38
|
-
maxChars: 10,
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
const decimalColumn: DbStructure.Column = {
|
|
42
|
-
...intColumn,
|
|
43
|
-
name: 'decimal',
|
|
44
|
-
type: 'decimal',
|
|
45
|
-
numericPrecision: 10,
|
|
46
|
-
numericScale: 2,
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
const timestampColumn: DbStructure.Column = {
|
|
50
|
-
...intColumn,
|
|
51
|
-
name: 'timestamp',
|
|
52
|
-
type: 'timestamp',
|
|
53
|
-
dateTimePrecision: 10,
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
const tableColumns = [
|
|
57
|
-
{ ...intColumn, name: 'id' },
|
|
58
|
-
{ ...intColumn, name: 'name', type: 'text' },
|
|
59
|
-
];
|
|
60
|
-
|
|
61
|
-
const otherTableColumn = { ...intColumn, tableName: 'otherTable' };
|
|
62
|
-
|
|
63
|
-
const table = { schemaName: 'public', name: 'table' };
|
|
64
|
-
|
|
65
|
-
const columns = [...tableColumns, otherTableColumn];
|
|
66
|
-
|
|
67
|
-
const primaryKey: DbStructure.PrimaryKey = {
|
|
68
|
-
schemaName: 'public',
|
|
69
|
-
tableName: 'table',
|
|
70
|
-
name: 'pkey',
|
|
71
|
-
columnNames: ['id'],
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
const index: DbStructure.Index = {
|
|
75
|
-
schemaName: 'public',
|
|
76
|
-
tableName: 'table',
|
|
77
|
-
name: 'index',
|
|
78
|
-
using: 'btree',
|
|
79
|
-
isUnique: false,
|
|
80
|
-
columns: [{ column: 'name' }],
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
const foreignKey: DbStructure.ForeignKey = {
|
|
84
|
-
schemaName: 'public',
|
|
85
|
-
tableName: 'table',
|
|
86
|
-
foreignTableSchemaName: 'public',
|
|
87
|
-
foreignTableName: 'otherTable',
|
|
88
|
-
name: 'fkey',
|
|
89
|
-
columnNames: ['otherId'],
|
|
90
|
-
foreignColumnNames: ['id'],
|
|
91
|
-
match: 'f',
|
|
92
|
-
onUpdate: 'c',
|
|
93
|
-
onDelete: 'c',
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
const extension: DbStructure.Extension = {
|
|
97
|
-
schemaName: 'public',
|
|
98
|
-
name: 'name',
|
|
99
|
-
version: '123',
|
|
100
|
-
};
|
|
101
|
-
|
|
102
|
-
const enumType: DbStructure.Enum = {
|
|
103
|
-
schemaName: 'public',
|
|
104
|
-
name: 'mood',
|
|
105
|
-
values: ['sad', 'ok', 'happy'],
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
describe('structureToAst', () => {
|
|
109
|
-
it('should add schema except public', async () => {
|
|
110
|
-
const db = new DbStructure(adapter);
|
|
111
|
-
db.getSchemas = async () => ['public', 'one', 'two'];
|
|
112
|
-
const ast = await structureToAst(db);
|
|
113
|
-
expect(ast).toEqual([
|
|
114
|
-
{
|
|
115
|
-
type: 'schema',
|
|
116
|
-
action: 'create',
|
|
117
|
-
name: 'one',
|
|
118
|
-
},
|
|
119
|
-
{
|
|
120
|
-
type: 'schema',
|
|
121
|
-
action: 'create',
|
|
122
|
-
name: 'two',
|
|
123
|
-
},
|
|
124
|
-
]);
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
describe('table', () => {
|
|
128
|
-
it('should add table', async () => {
|
|
129
|
-
const db = new DbStructure(adapter);
|
|
130
|
-
db.getTables = async () => [
|
|
131
|
-
{ schemaName: 'public', name: 'table', comment: 'comment' },
|
|
132
|
-
];
|
|
133
|
-
|
|
134
|
-
const ast = await structureToAst(db);
|
|
135
|
-
|
|
136
|
-
expect(ast).toEqual([
|
|
137
|
-
{
|
|
138
|
-
type: 'table',
|
|
139
|
-
action: 'create',
|
|
140
|
-
name: 'table',
|
|
141
|
-
comment: 'comment',
|
|
142
|
-
shape: {},
|
|
143
|
-
noPrimaryKey: 'ignore',
|
|
144
|
-
indexes: [],
|
|
145
|
-
foreignKeys: [],
|
|
146
|
-
},
|
|
147
|
-
]);
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
it('should add table with schema', async () => {
|
|
151
|
-
const db = new DbStructure(adapter);
|
|
152
|
-
db.getTables = async () => [{ schemaName: 'custom', name: 'table' }];
|
|
153
|
-
|
|
154
|
-
const ast = await structureToAst(db);
|
|
155
|
-
|
|
156
|
-
expect(ast).toEqual([
|
|
157
|
-
{
|
|
158
|
-
type: 'table',
|
|
159
|
-
action: 'create',
|
|
160
|
-
schema: 'custom',
|
|
161
|
-
name: 'table',
|
|
162
|
-
shape: {},
|
|
163
|
-
noPrimaryKey: 'ignore',
|
|
164
|
-
indexes: [],
|
|
165
|
-
foreignKeys: [],
|
|
166
|
-
},
|
|
167
|
-
]);
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
it('should ignore schemaMigrations table', async () => {
|
|
171
|
-
const db = new DbStructure(adapter);
|
|
172
|
-
db.getTables = async () => [
|
|
173
|
-
{ schemaName: 'public', name: 'schemaMigrations' },
|
|
174
|
-
];
|
|
175
|
-
|
|
176
|
-
const ast = await structureToAst(db);
|
|
177
|
-
|
|
178
|
-
expect(ast).toEqual([]);
|
|
179
|
-
});
|
|
180
|
-
|
|
181
|
-
it('should add columns', async () => {
|
|
182
|
-
const db = new DbStructure(adapter);
|
|
183
|
-
db.getTables = async () => [table];
|
|
184
|
-
db.getColumns = async () => columns;
|
|
185
|
-
|
|
186
|
-
const [ast] = (await structureToAst(db)) as [RakeDbAst.Table];
|
|
187
|
-
|
|
188
|
-
expect(Object.keys(ast.shape).length).toBe(tableColumns.length);
|
|
189
|
-
expect(ast.noPrimaryKey).toBe('ignore');
|
|
190
|
-
expect(ast.shape.id).toBeInstanceOf(IntegerColumn);
|
|
191
|
-
expect(ast.shape.name).toBeInstanceOf(TextColumn);
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
it('should wrap column default into raw', async () => {
|
|
195
|
-
const db = new DbStructure(adapter);
|
|
196
|
-
db.getTables = async () => [table];
|
|
197
|
-
db.getColumns = async () => [{ ...timestampColumn, default: 'now()' }];
|
|
198
|
-
|
|
199
|
-
const [ast] = (await structureToAst(db)) as [RakeDbAst.Table];
|
|
200
|
-
|
|
201
|
-
const { default: def } = ast.shape.timestamp.data;
|
|
202
|
-
expect(def && typeof def === 'object' && isRaw(def)).toBe(true);
|
|
203
|
-
expect((def as RawExpression).__raw).toBe('now()');
|
|
204
|
-
});
|
|
205
|
-
|
|
206
|
-
describe('serial column', () => {
|
|
207
|
-
it('should add serial column based on various default values', async () => {
|
|
208
|
-
const db = new DbStructure(adapter);
|
|
209
|
-
db.getTables = async () => [{ schemaName: 'schema', name: 'table' }];
|
|
210
|
-
|
|
211
|
-
const defaults = [
|
|
212
|
-
`nextval('table_id_seq'::regclass)`,
|
|
213
|
-
`nextval('"table_id_seq"'::regclass)`,
|
|
214
|
-
`nextval('schema.table_id_seq'::regclass)`,
|
|
215
|
-
`nextval('schema."table_id_seq"'::regclass)`,
|
|
216
|
-
`nextval('"schema".table_id_seq'::regclass)`,
|
|
217
|
-
`nextval('"schema"."table_id_seq"'::regclass)`,
|
|
218
|
-
];
|
|
219
|
-
|
|
220
|
-
for (const def of defaults) {
|
|
221
|
-
db.getColumns = async () => [
|
|
222
|
-
{
|
|
223
|
-
...intColumn,
|
|
224
|
-
name: 'id',
|
|
225
|
-
schemaName: 'schema',
|
|
226
|
-
tableName: 'table',
|
|
227
|
-
default: def,
|
|
228
|
-
},
|
|
229
|
-
];
|
|
230
|
-
|
|
231
|
-
const [ast] = (await structureToAst(db)) as [RakeDbAst.Table];
|
|
232
|
-
|
|
233
|
-
expect(ast.shape.id).toBeInstanceOf(SerialColumn);
|
|
234
|
-
expect(ast.shape.id.data.default).toBe(undefined);
|
|
235
|
-
}
|
|
236
|
-
});
|
|
237
|
-
|
|
238
|
-
it('should support smallserial, serial, and bigserial', async () => {
|
|
239
|
-
const db = new DbStructure(adapter);
|
|
240
|
-
db.getTables = async () => [{ schemaName: 'schema', name: 'table' }];
|
|
241
|
-
|
|
242
|
-
const types = [
|
|
243
|
-
['int2', SmallSerialColumn],
|
|
244
|
-
['int4', SerialColumn],
|
|
245
|
-
['int8', BigSerialColumn],
|
|
246
|
-
] as const;
|
|
247
|
-
|
|
248
|
-
for (const [type, Column] of types) {
|
|
249
|
-
db.getColumns = async () => [
|
|
250
|
-
{
|
|
251
|
-
...intColumn,
|
|
252
|
-
type,
|
|
253
|
-
name: 'id',
|
|
254
|
-
schemaName: 'schema',
|
|
255
|
-
tableName: 'table',
|
|
256
|
-
default: `nextval('table_id_seq'::regclass)`,
|
|
257
|
-
},
|
|
258
|
-
];
|
|
259
|
-
|
|
260
|
-
const [ast] = (await structureToAst(db)) as [RakeDbAst.Table];
|
|
261
|
-
|
|
262
|
-
expect(ast.shape.id).toBeInstanceOf(Column);
|
|
263
|
-
expect(ast.shape.id.data.default).toBe(undefined);
|
|
264
|
-
}
|
|
265
|
-
});
|
|
266
|
-
});
|
|
267
|
-
|
|
268
|
-
it('should set maxChars to char column', async () => {
|
|
269
|
-
const db = new DbStructure(adapter);
|
|
270
|
-
db.getTables = async () => [table];
|
|
271
|
-
db.getColumns = async () => [varCharColumn];
|
|
272
|
-
|
|
273
|
-
const [ast] = (await structureToAst(db)) as [RakeDbAst.Table];
|
|
274
|
-
|
|
275
|
-
const column = ast.shape[varCharColumn.name];
|
|
276
|
-
expect(column).toBeInstanceOf(VarCharColumn);
|
|
277
|
-
expect(column.data.maxChars).toBe(varCharColumn.maxChars);
|
|
278
|
-
});
|
|
279
|
-
|
|
280
|
-
it('should set numericPrecision and numericScale to decimal column', async () => {
|
|
281
|
-
const db = new DbStructure(adapter);
|
|
282
|
-
db.getTables = async () => [table];
|
|
283
|
-
db.getColumns = async () => [decimalColumn];
|
|
284
|
-
|
|
285
|
-
const [ast] = (await structureToAst(db)) as [RakeDbAst.Table];
|
|
286
|
-
|
|
287
|
-
const column = ast.shape[decimalColumn.name];
|
|
288
|
-
expect(column).toBeInstanceOf(DecimalColumn);
|
|
289
|
-
expect(column.data.numericPrecision).toBe(decimalColumn.numericPrecision);
|
|
290
|
-
expect(column.data.numericScale).toBe(decimalColumn.numericScale);
|
|
291
|
-
});
|
|
292
|
-
|
|
293
|
-
it('should set dateTimePrecision to timestamp column', async () => {
|
|
294
|
-
const db = new DbStructure(adapter);
|
|
295
|
-
db.getTables = async () => [table];
|
|
296
|
-
db.getColumns = async () => [timestampColumn];
|
|
297
|
-
|
|
298
|
-
const [ast] = (await structureToAst(db)) as [RakeDbAst.Table];
|
|
299
|
-
|
|
300
|
-
const column = ast.shape[timestampColumn.name];
|
|
301
|
-
expect(column).toBeInstanceOf(TimestampColumn);
|
|
302
|
-
expect(column.data.dateTimePrecision).toBe(
|
|
303
|
-
timestampColumn.dateTimePrecision,
|
|
304
|
-
);
|
|
305
|
-
});
|
|
306
|
-
|
|
307
|
-
it('should set primaryKey to column', async () => {
|
|
308
|
-
const db = new DbStructure(adapter);
|
|
309
|
-
db.getTables = async () => [table];
|
|
310
|
-
db.getColumns = async () => columns;
|
|
311
|
-
db.getPrimaryKeys = async () => [primaryKey];
|
|
312
|
-
|
|
313
|
-
const [ast] = (await structureToAst(db)) as [RakeDbAst.Table];
|
|
314
|
-
|
|
315
|
-
expect(ast.noPrimaryKey).toBe('error');
|
|
316
|
-
expect(ast.shape.id.isPrimaryKey).toBe(true);
|
|
317
|
-
expect(ast.primaryKey).toBe(undefined);
|
|
318
|
-
});
|
|
319
|
-
|
|
320
|
-
it('should add composite primary key', async () => {
|
|
321
|
-
const db = new DbStructure(adapter);
|
|
322
|
-
db.getTables = async () => [table];
|
|
323
|
-
db.getColumns = async () => columns;
|
|
324
|
-
db.getPrimaryKeys = async () => [
|
|
325
|
-
{ ...primaryKey, columnNames: ['id', 'name'] },
|
|
326
|
-
];
|
|
327
|
-
|
|
328
|
-
const [ast] = (await structureToAst(db)) as [RakeDbAst.Table];
|
|
329
|
-
|
|
330
|
-
expect(ast.noPrimaryKey).toBe('error');
|
|
331
|
-
expect(ast.shape.id.isPrimaryKey).toBe(false);
|
|
332
|
-
expect(ast.primaryKey).toEqual({
|
|
333
|
-
columns: ['id', 'name'],
|
|
334
|
-
options: { name: 'pkey' },
|
|
335
|
-
});
|
|
336
|
-
});
|
|
337
|
-
|
|
338
|
-
it('should ignore primary key name if it is standard', async () => {
|
|
339
|
-
const db = new DbStructure(adapter);
|
|
340
|
-
db.getTables = async () => [table];
|
|
341
|
-
db.getColumns = async () => columns;
|
|
342
|
-
db.getPrimaryKeys = async () => [
|
|
343
|
-
{ ...primaryKey, columnNames: ['id', 'name'], name: 'table_pkey' },
|
|
344
|
-
];
|
|
345
|
-
|
|
346
|
-
const [ast] = (await structureToAst(db)) as [RakeDbAst.Table];
|
|
347
|
-
|
|
348
|
-
expect(ast.noPrimaryKey).toBe('error');
|
|
349
|
-
expect(ast.shape.id.isPrimaryKey).toBe(false);
|
|
350
|
-
expect(ast.primaryKey).toEqual({
|
|
351
|
-
columns: ['id', 'name'],
|
|
352
|
-
});
|
|
353
|
-
});
|
|
354
|
-
|
|
355
|
-
it('should add index to column', async () => {
|
|
356
|
-
const db = new DbStructure(adapter);
|
|
357
|
-
db.getTables = async () => [table];
|
|
358
|
-
db.getColumns = async () => columns;
|
|
359
|
-
db.getIndexes = async () => [index];
|
|
360
|
-
|
|
361
|
-
const [ast] = (await structureToAst(db)) as [RakeDbAst.Table];
|
|
362
|
-
expect(ast.shape.name.data.indexes).toEqual([
|
|
363
|
-
{
|
|
364
|
-
name: 'index',
|
|
365
|
-
unique: false,
|
|
366
|
-
},
|
|
367
|
-
]);
|
|
368
|
-
expect(ast.indexes).toHaveLength(0);
|
|
369
|
-
});
|
|
370
|
-
|
|
371
|
-
it('should ignore standard index name', async () => {
|
|
372
|
-
const db = new DbStructure(adapter);
|
|
373
|
-
db.getTables = async () => [table];
|
|
374
|
-
db.getColumns = async () => columns;
|
|
375
|
-
db.getIndexes = async () => [
|
|
376
|
-
{ ...index, name: getIndexName(table.name, index.columns) },
|
|
377
|
-
];
|
|
378
|
-
|
|
379
|
-
const [ast] = (await structureToAst(db)) as [RakeDbAst.Table];
|
|
380
|
-
expect(ast.shape.name.data.indexes).toEqual([
|
|
381
|
-
{
|
|
382
|
-
unique: false,
|
|
383
|
-
},
|
|
384
|
-
]);
|
|
385
|
-
expect(ast.indexes).toHaveLength(0);
|
|
386
|
-
});
|
|
387
|
-
|
|
388
|
-
it('should set index options to column index', async () => {
|
|
389
|
-
const db = new DbStructure(adapter);
|
|
390
|
-
db.getTables = async () => [table];
|
|
391
|
-
db.getColumns = async () => columns;
|
|
392
|
-
db.getIndexes = async () => [
|
|
393
|
-
{
|
|
394
|
-
...index,
|
|
395
|
-
using: 'gist',
|
|
396
|
-
isUnique: true,
|
|
397
|
-
columns: [
|
|
398
|
-
{
|
|
399
|
-
column: 'name',
|
|
400
|
-
collate: 'en_US',
|
|
401
|
-
opclass: 'varchar_ops',
|
|
402
|
-
order: 'DESC',
|
|
403
|
-
},
|
|
404
|
-
],
|
|
405
|
-
include: ['id'],
|
|
406
|
-
with: 'fillfactor=80',
|
|
407
|
-
tablespace: 'tablespace',
|
|
408
|
-
where: 'condition',
|
|
409
|
-
},
|
|
410
|
-
];
|
|
411
|
-
|
|
412
|
-
const [ast] = (await structureToAst(db)) as [RakeDbAst.Table];
|
|
413
|
-
expect(ast.shape.name.data.indexes).toEqual([
|
|
414
|
-
{
|
|
415
|
-
name: 'index',
|
|
416
|
-
using: 'gist',
|
|
417
|
-
unique: true,
|
|
418
|
-
collate: 'en_US',
|
|
419
|
-
opclass: 'varchar_ops',
|
|
420
|
-
order: 'DESC',
|
|
421
|
-
include: ['id'],
|
|
422
|
-
with: 'fillfactor=80',
|
|
423
|
-
tablespace: 'tablespace',
|
|
424
|
-
where: 'condition',
|
|
425
|
-
},
|
|
426
|
-
]);
|
|
427
|
-
expect(ast.indexes).toHaveLength(0);
|
|
428
|
-
});
|
|
429
|
-
|
|
430
|
-
it('should add composite indexes to the table', async () => {
|
|
431
|
-
const db = new DbStructure(adapter);
|
|
432
|
-
db.getTables = async () => [table];
|
|
433
|
-
db.getColumns = async () => columns;
|
|
434
|
-
db.getIndexes = async () => [
|
|
435
|
-
{ ...index, columns: [{ column: 'id' }, { column: 'name' }] },
|
|
436
|
-
{
|
|
437
|
-
...index,
|
|
438
|
-
columns: [{ column: 'id' }, { column: 'name' }],
|
|
439
|
-
isUnique: true,
|
|
440
|
-
},
|
|
441
|
-
];
|
|
442
|
-
|
|
443
|
-
const [ast] = (await structureToAst(db)) as [RakeDbAst.Table];
|
|
444
|
-
expect(ast.shape.name.data.indexes).toBe(undefined);
|
|
445
|
-
expect(ast.indexes).toEqual([
|
|
446
|
-
{
|
|
447
|
-
columns: [{ column: 'id' }, { column: 'name' }],
|
|
448
|
-
options: { name: 'index', unique: false },
|
|
449
|
-
},
|
|
450
|
-
{
|
|
451
|
-
columns: [{ column: 'id' }, { column: 'name' }],
|
|
452
|
-
options: { name: 'index', unique: true },
|
|
453
|
-
},
|
|
454
|
-
]);
|
|
455
|
-
});
|
|
456
|
-
|
|
457
|
-
it('should ignore standard index name in composite index', async () => {
|
|
458
|
-
const db = new DbStructure(adapter);
|
|
459
|
-
db.getTables = async () => [table];
|
|
460
|
-
db.getColumns = async () => columns;
|
|
461
|
-
|
|
462
|
-
const indexColumns = [{ column: 'id' }, { column: 'name' }];
|
|
463
|
-
db.getIndexes = async () => [
|
|
464
|
-
{
|
|
465
|
-
...index,
|
|
466
|
-
columns: indexColumns,
|
|
467
|
-
name: getIndexName(table.name, indexColumns),
|
|
468
|
-
},
|
|
469
|
-
];
|
|
470
|
-
|
|
471
|
-
const [ast] = (await structureToAst(db)) as [RakeDbAst.Table];
|
|
472
|
-
expect(ast.shape.name.data.indexes).toBe(undefined);
|
|
473
|
-
expect(ast.indexes).toEqual([
|
|
474
|
-
{
|
|
475
|
-
columns: indexColumns,
|
|
476
|
-
options: { unique: false },
|
|
477
|
-
},
|
|
478
|
-
]);
|
|
479
|
-
});
|
|
480
|
-
|
|
481
|
-
it('should add index with expression and options to the table', async () => {
|
|
482
|
-
const db = new DbStructure(adapter);
|
|
483
|
-
db.getTables = async () => [table];
|
|
484
|
-
db.getColumns = async () => columns;
|
|
485
|
-
db.getIndexes = async () => [
|
|
486
|
-
{
|
|
487
|
-
...index,
|
|
488
|
-
using: 'gist',
|
|
489
|
-
isUnique: true,
|
|
490
|
-
columns: [
|
|
491
|
-
{
|
|
492
|
-
expression: 'lower(name)',
|
|
493
|
-
collate: 'en_US',
|
|
494
|
-
opclass: 'varchar_ops',
|
|
495
|
-
order: 'DESC',
|
|
496
|
-
},
|
|
497
|
-
],
|
|
498
|
-
include: ['id'],
|
|
499
|
-
with: 'fillfactor=80',
|
|
500
|
-
tablespace: 'tablespace',
|
|
501
|
-
where: 'condition',
|
|
502
|
-
},
|
|
503
|
-
];
|
|
504
|
-
|
|
505
|
-
const [ast] = (await structureToAst(db)) as [RakeDbAst.Table];
|
|
506
|
-
expect(ast.shape.name.data.indexes).toBe(undefined);
|
|
507
|
-
expect(ast.indexes).toEqual([
|
|
508
|
-
{
|
|
509
|
-
columns: [
|
|
510
|
-
{
|
|
511
|
-
expression: 'lower(name)',
|
|
512
|
-
collate: 'en_US',
|
|
513
|
-
opclass: 'varchar_ops',
|
|
514
|
-
order: 'DESC',
|
|
515
|
-
},
|
|
516
|
-
],
|
|
517
|
-
options: {
|
|
518
|
-
name: 'index',
|
|
519
|
-
using: 'gist',
|
|
520
|
-
unique: true,
|
|
521
|
-
include: ['id'],
|
|
522
|
-
with: 'fillfactor=80',
|
|
523
|
-
tablespace: 'tablespace',
|
|
524
|
-
where: 'condition',
|
|
525
|
-
},
|
|
526
|
-
},
|
|
527
|
-
]);
|
|
528
|
-
});
|
|
529
|
-
|
|
530
|
-
it('should add foreign key to the column', async () => {
|
|
531
|
-
const db = new DbStructure(adapter);
|
|
532
|
-
db.getTables = async () => [
|
|
533
|
-
{ ...table, name: 'table1' },
|
|
534
|
-
{ ...table, name: 'table2' },
|
|
535
|
-
];
|
|
536
|
-
db.getColumns = async () => [
|
|
537
|
-
...columns,
|
|
538
|
-
{ ...intColumn, name: 'otherId', tableName: 'table2' },
|
|
539
|
-
];
|
|
540
|
-
db.getForeignKeys = async () => [
|
|
541
|
-
{ ...foreignKey, tableName: 'table2', foreignTableName: 'table1' },
|
|
542
|
-
];
|
|
543
|
-
|
|
544
|
-
const [, ast] = (await structureToAst(db)) as RakeDbAst.Table[];
|
|
545
|
-
|
|
546
|
-
expect(ast.shape.otherId.data.foreignKeys).toEqual([
|
|
547
|
-
{
|
|
548
|
-
columns: ['id'],
|
|
549
|
-
name: 'fkey',
|
|
550
|
-
table: 'table1',
|
|
551
|
-
match: 'FULL',
|
|
552
|
-
onUpdate: 'CASCADE',
|
|
553
|
-
onDelete: 'CASCADE',
|
|
554
|
-
},
|
|
555
|
-
]);
|
|
556
|
-
expect(ast.foreignKeys).toHaveLength(0);
|
|
557
|
-
});
|
|
558
|
-
|
|
559
|
-
it('should ignore standard foreign key name', async () => {
|
|
560
|
-
const db = new DbStructure(adapter);
|
|
561
|
-
db.getTables = async () => [
|
|
562
|
-
{ ...table, name: 'table1' },
|
|
563
|
-
{ ...table, name: 'table2' },
|
|
564
|
-
];
|
|
565
|
-
db.getColumns = async () => [
|
|
566
|
-
{ ...intColumn, name: 'otherId', tableName: 'table2' },
|
|
567
|
-
];
|
|
568
|
-
db.getForeignKeys = async () => [
|
|
569
|
-
{
|
|
570
|
-
...foreignKey,
|
|
571
|
-
name: `table2_otherId_fkey`,
|
|
572
|
-
tableName: 'table2',
|
|
573
|
-
foreignTableName: 'table1',
|
|
574
|
-
},
|
|
575
|
-
];
|
|
576
|
-
|
|
577
|
-
const [, ast] = (await structureToAst(db)) as RakeDbAst.Table[];
|
|
578
|
-
|
|
579
|
-
expect(ast.shape.otherId.data.foreignKeys).toEqual([
|
|
580
|
-
{
|
|
581
|
-
columns: ['id'],
|
|
582
|
-
table: 'table1',
|
|
583
|
-
match: 'FULL',
|
|
584
|
-
onUpdate: 'CASCADE',
|
|
585
|
-
onDelete: 'CASCADE',
|
|
586
|
-
},
|
|
587
|
-
]);
|
|
588
|
-
expect(ast.foreignKeys).toHaveLength(0);
|
|
589
|
-
});
|
|
590
|
-
|
|
591
|
-
it('should add composite foreign key', async () => {
|
|
592
|
-
const db = new DbStructure(adapter);
|
|
593
|
-
db.getTables = async () => [
|
|
594
|
-
{ ...table, name: 'table1' },
|
|
595
|
-
{ ...table, name: 'table2' },
|
|
596
|
-
];
|
|
597
|
-
db.getColumns = async () => [
|
|
598
|
-
{ ...intColumn, name: 'otherId', tableName: 'table2' },
|
|
599
|
-
];
|
|
600
|
-
db.getForeignKeys = async () => [
|
|
601
|
-
{
|
|
602
|
-
...foreignKey,
|
|
603
|
-
tableName: 'table2',
|
|
604
|
-
columnNames: ['name', 'otherId'],
|
|
605
|
-
foreignTableName: 'table1',
|
|
606
|
-
foreignColumnNames: ['name', 'id'],
|
|
607
|
-
},
|
|
608
|
-
];
|
|
609
|
-
|
|
610
|
-
const [, ast] = (await structureToAst(db)) as RakeDbAst.Table[];
|
|
611
|
-
|
|
612
|
-
expect(ast.shape.otherId.data.foreignKeys).toBe(undefined);
|
|
613
|
-
expect(ast.foreignKeys).toEqual([
|
|
614
|
-
{
|
|
615
|
-
columns: ['name', 'otherId'],
|
|
616
|
-
fnOrTable: 'table1',
|
|
617
|
-
foreignColumns: ['name', 'id'],
|
|
618
|
-
options: {
|
|
619
|
-
name: 'fkey',
|
|
620
|
-
match: 'FULL',
|
|
621
|
-
onUpdate: 'CASCADE',
|
|
622
|
-
onDelete: 'CASCADE',
|
|
623
|
-
},
|
|
624
|
-
},
|
|
625
|
-
]);
|
|
626
|
-
});
|
|
627
|
-
|
|
628
|
-
it('should ignore standard foreign key name in a composite foreign key', async () => {
|
|
629
|
-
const db = new DbStructure(adapter);
|
|
630
|
-
db.getTables = async () => [
|
|
631
|
-
{ ...table, name: 'table1' },
|
|
632
|
-
{ ...table, name: 'table2' },
|
|
633
|
-
];
|
|
634
|
-
db.getColumns = async () => [
|
|
635
|
-
{ ...intColumn, name: 'otherId', tableName: 'table2' },
|
|
636
|
-
];
|
|
637
|
-
db.getForeignKeys = async () => [
|
|
638
|
-
{
|
|
639
|
-
...foreignKey,
|
|
640
|
-
tableName: 'table2',
|
|
641
|
-
foreignTableName: 'table1',
|
|
642
|
-
columnNames: ['name', 'otherId'],
|
|
643
|
-
foreignColumnNames: ['name', 'id'],
|
|
644
|
-
name: 'table2_name_otherId_fkey',
|
|
645
|
-
},
|
|
646
|
-
];
|
|
647
|
-
|
|
648
|
-
const [, ast] = (await structureToAst(db)) as RakeDbAst.Table[];
|
|
649
|
-
|
|
650
|
-
expect(ast.shape.otherId.data.foreignKeys).toBe(undefined);
|
|
651
|
-
expect(ast.foreignKeys).toEqual([
|
|
652
|
-
{
|
|
653
|
-
columns: ['name', 'otherId'],
|
|
654
|
-
fnOrTable: 'table1',
|
|
655
|
-
foreignColumns: ['name', 'id'],
|
|
656
|
-
options: {
|
|
657
|
-
match: 'FULL',
|
|
658
|
-
onUpdate: 'CASCADE',
|
|
659
|
-
onDelete: 'CASCADE',
|
|
660
|
-
},
|
|
661
|
-
},
|
|
662
|
-
]);
|
|
663
|
-
});
|
|
664
|
-
|
|
665
|
-
it('should have referenced table before the table with foreign key', async () => {
|
|
666
|
-
const db = new DbStructure(adapter);
|
|
667
|
-
db.getTables = async () => [
|
|
668
|
-
{ ...table, name: 'fkTable' },
|
|
669
|
-
{ ...table, name: 'table1' },
|
|
670
|
-
{ ...table, name: 'table2' },
|
|
671
|
-
{ ...table, name: 'otherTable' },
|
|
672
|
-
];
|
|
673
|
-
db.getColumns = async () => [
|
|
674
|
-
{ ...intColumn, name: 'table1Id', tableName: 'fkTable' },
|
|
675
|
-
{ ...intColumn, name: 'table2Id', tableName: 'fkTable' },
|
|
676
|
-
];
|
|
677
|
-
db.getForeignKeys = async () => [
|
|
678
|
-
{
|
|
679
|
-
...foreignKey,
|
|
680
|
-
tableName: 'fkTable',
|
|
681
|
-
columnNames: ['table1Id'],
|
|
682
|
-
foreignTableName: 'table1',
|
|
683
|
-
},
|
|
684
|
-
{
|
|
685
|
-
...foreignKey,
|
|
686
|
-
tableName: 'fkTable',
|
|
687
|
-
columnNames: ['table2Id'],
|
|
688
|
-
foreignTableName: 'table2',
|
|
689
|
-
},
|
|
690
|
-
];
|
|
691
|
-
|
|
692
|
-
const [table1, table2, fkTable, otherTable] = (await structureToAst(
|
|
693
|
-
db,
|
|
694
|
-
)) as RakeDbAst.Table[];
|
|
695
|
-
|
|
696
|
-
expect(table1.name).toBe('table1');
|
|
697
|
-
expect(table2.name).toBe('table2');
|
|
698
|
-
expect(fkTable.name).toBe('fkTable');
|
|
699
|
-
expect(otherTable.name).toBe('otherTable');
|
|
700
|
-
});
|
|
701
|
-
|
|
702
|
-
it('should add foreign key to a same table', async () => {
|
|
703
|
-
const db = new DbStructure(adapter);
|
|
704
|
-
db.getTables = async () => [table];
|
|
705
|
-
db.getColumns = async () => [intColumn];
|
|
706
|
-
db.getForeignKeys = async () => [
|
|
707
|
-
{
|
|
708
|
-
...foreignKey,
|
|
709
|
-
tableName: table.name,
|
|
710
|
-
columnNames: [intColumn.name],
|
|
711
|
-
foreignTableName: table.name,
|
|
712
|
-
},
|
|
713
|
-
];
|
|
714
|
-
|
|
715
|
-
const [ast] = (await structureToAst(db)) as RakeDbAst.Table[];
|
|
716
|
-
|
|
717
|
-
expect(ast.name).toBe(table.name);
|
|
718
|
-
});
|
|
719
|
-
|
|
720
|
-
it('should add standalone foreign key when it is recursive', async () => {
|
|
721
|
-
const db = new DbStructure(adapter);
|
|
722
|
-
db.getTables = async () => [
|
|
723
|
-
{ ...table, name: 'table1' },
|
|
724
|
-
{ ...table, name: 'table2' },
|
|
725
|
-
];
|
|
726
|
-
db.getColumns = async () => [
|
|
727
|
-
{ ...intColumn, tableName: 'table1' },
|
|
728
|
-
{ ...intColumn, tableName: 'table2' },
|
|
729
|
-
];
|
|
730
|
-
db.getForeignKeys = async () => [
|
|
731
|
-
{
|
|
732
|
-
...foreignKey,
|
|
733
|
-
tableName: 'table1',
|
|
734
|
-
columnNames: [intColumn.name],
|
|
735
|
-
foreignTableName: 'table2',
|
|
736
|
-
},
|
|
737
|
-
{
|
|
738
|
-
...foreignKey,
|
|
739
|
-
tableName: 'table2',
|
|
740
|
-
columnNames: [intColumn.name],
|
|
741
|
-
foreignTableName: 'table1',
|
|
742
|
-
},
|
|
743
|
-
];
|
|
744
|
-
|
|
745
|
-
const [table1, table2, fkey] = (await structureToAst(
|
|
746
|
-
db,
|
|
747
|
-
)) as RakeDbAst.Table[];
|
|
748
|
-
|
|
749
|
-
expect(table1.name).toBe('table1');
|
|
750
|
-
expect(table1.shape[intColumn.name].data.foreignKeys).toBe(undefined);
|
|
751
|
-
expect(table2.name).toBe('table2');
|
|
752
|
-
expect(table2.shape[intColumn.name].data.foreignKeys).toEqual([
|
|
753
|
-
{
|
|
754
|
-
table: 'table1',
|
|
755
|
-
columns: ['id'],
|
|
756
|
-
match: 'FULL',
|
|
757
|
-
name: 'fkey',
|
|
758
|
-
onUpdate: 'CASCADE',
|
|
759
|
-
onDelete: 'CASCADE',
|
|
760
|
-
},
|
|
761
|
-
]);
|
|
762
|
-
|
|
763
|
-
expect(fkey).toEqual({
|
|
764
|
-
type: 'foreignKey',
|
|
765
|
-
action: 'create',
|
|
766
|
-
tableName: 'table1',
|
|
767
|
-
columns: ['column'],
|
|
768
|
-
fnOrTable: 'table2',
|
|
769
|
-
foreignColumns: ['id'],
|
|
770
|
-
options: {
|
|
771
|
-
match: 'FULL',
|
|
772
|
-
name: 'fkey',
|
|
773
|
-
onDelete: 'CASCADE',
|
|
774
|
-
onUpdate: 'CASCADE',
|
|
775
|
-
},
|
|
776
|
-
});
|
|
777
|
-
});
|
|
778
|
-
});
|
|
779
|
-
|
|
780
|
-
describe('extension', () => {
|
|
781
|
-
it('should add extension', async () => {
|
|
782
|
-
const db = new DbStructure(adapter);
|
|
783
|
-
db.getExtensions = async () => [{ ...extension, schemaName: 'custom' }];
|
|
784
|
-
|
|
785
|
-
const [ast] = (await structureToAst(db)) as [RakeDbAst.Extension];
|
|
786
|
-
|
|
787
|
-
expect(ast).toEqual({
|
|
788
|
-
type: 'extension',
|
|
789
|
-
action: 'create',
|
|
790
|
-
name: 'name',
|
|
791
|
-
schema: 'custom',
|
|
792
|
-
version: '123',
|
|
793
|
-
});
|
|
794
|
-
});
|
|
795
|
-
|
|
796
|
-
it('should ignore schema if it is `public`', async () => {
|
|
797
|
-
const db = new DbStructure(adapter);
|
|
798
|
-
db.getExtensions = async () => [extension];
|
|
799
|
-
|
|
800
|
-
const [ast] = (await structureToAst(db)) as [RakeDbAst.Extension];
|
|
801
|
-
|
|
802
|
-
expect(ast).toEqual({
|
|
803
|
-
type: 'extension',
|
|
804
|
-
action: 'create',
|
|
805
|
-
name: 'name',
|
|
806
|
-
version: '123',
|
|
807
|
-
});
|
|
808
|
-
});
|
|
809
|
-
});
|
|
810
|
-
|
|
811
|
-
describe('enum', () => {
|
|
812
|
-
it('should add enum', async () => {
|
|
813
|
-
const db = new DbStructure(adapter);
|
|
814
|
-
db.getEnums = async () => [{ ...enumType, schemaName: 'custom' }];
|
|
815
|
-
|
|
816
|
-
const [ast] = (await structureToAst(db)) as [RakeDbAst.Enum];
|
|
817
|
-
|
|
818
|
-
expect(ast).toEqual({
|
|
819
|
-
type: 'enum',
|
|
820
|
-
action: 'create',
|
|
821
|
-
name: 'mood',
|
|
822
|
-
schema: 'custom',
|
|
823
|
-
values: enumType.values,
|
|
824
|
-
});
|
|
825
|
-
});
|
|
826
|
-
|
|
827
|
-
it('should ignore schema if it is `public`', async () => {
|
|
828
|
-
const db = new DbStructure(adapter);
|
|
829
|
-
db.getEnums = async () => [enumType];
|
|
830
|
-
|
|
831
|
-
const [ast] = (await structureToAst(db)) as [RakeDbAst.Enum];
|
|
832
|
-
|
|
833
|
-
expect(ast).toEqual({
|
|
834
|
-
type: 'enum',
|
|
835
|
-
action: 'create',
|
|
836
|
-
name: 'mood',
|
|
837
|
-
values: enumType.values,
|
|
838
|
-
});
|
|
839
|
-
});
|
|
840
|
-
});
|
|
841
|
-
});
|