rake-db 1.3.2 → 2.0.0

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.
Files changed (72) hide show
  1. package/.env +3 -0
  2. package/.env.local +1 -0
  3. package/README.md +1 -545
  4. package/db.ts +16 -0
  5. package/dist/index.d.ts +94 -0
  6. package/dist/index.esm.js +190 -0
  7. package/dist/index.esm.js.map +1 -0
  8. package/dist/index.js +201 -0
  9. package/dist/index.js.map +1 -0
  10. package/jest-setup.ts +3 -0
  11. package/migrations/20221009210157_first.ts +8 -0
  12. package/migrations/20221009210200_second.ts +5 -0
  13. package/package.json +55 -41
  14. package/rollup.config.js +3 -0
  15. package/src/commands/createOrDrop.test.ts +145 -0
  16. package/src/commands/createOrDrop.ts +107 -0
  17. package/src/commands/generate.test.ts +133 -0
  18. package/src/commands/generate.ts +85 -0
  19. package/src/commands/migrateOrRollback.test.ts +118 -0
  20. package/src/commands/migrateOrRollback.ts +108 -0
  21. package/src/common.test.ts +281 -0
  22. package/src/common.ts +224 -0
  23. package/src/index.ts +2 -0
  24. package/src/migration/change.ts +20 -0
  25. package/src/migration/changeTable.test.ts +417 -0
  26. package/src/migration/changeTable.ts +375 -0
  27. package/src/migration/createTable.test.ts +269 -0
  28. package/src/migration/createTable.ts +169 -0
  29. package/src/migration/migration.test.ts +341 -0
  30. package/src/migration/migration.ts +296 -0
  31. package/src/migration/migrationUtils.ts +281 -0
  32. package/src/rakeDb.ts +29 -0
  33. package/src/test-utils.ts +45 -0
  34. package/tsconfig.json +12 -0
  35. package/dist/lib/createAndDrop.d.ts +0 -2
  36. package/dist/lib/createAndDrop.js +0 -63
  37. package/dist/lib/defaults.d.ts +0 -2
  38. package/dist/lib/defaults.js +0 -5
  39. package/dist/lib/errorCodes.d.ts +0 -4
  40. package/dist/lib/errorCodes.js +0 -7
  41. package/dist/lib/generate.d.ts +0 -1
  42. package/dist/lib/generate.js +0 -99
  43. package/dist/lib/help.d.ts +0 -2
  44. package/dist/lib/help.js +0 -24
  45. package/dist/lib/init.d.ts +0 -2
  46. package/dist/lib/init.js +0 -276
  47. package/dist/lib/migrate.d.ts +0 -4
  48. package/dist/lib/migrate.js +0 -189
  49. package/dist/lib/migration.d.ts +0 -37
  50. package/dist/lib/migration.js +0 -159
  51. package/dist/lib/schema/changeTable.d.ts +0 -23
  52. package/dist/lib/schema/changeTable.js +0 -109
  53. package/dist/lib/schema/column.d.ts +0 -31
  54. package/dist/lib/schema/column.js +0 -201
  55. package/dist/lib/schema/createTable.d.ts +0 -10
  56. package/dist/lib/schema/createTable.js +0 -53
  57. package/dist/lib/schema/foreignKey.d.ts +0 -11
  58. package/dist/lib/schema/foreignKey.js +0 -53
  59. package/dist/lib/schema/index.d.ts +0 -3
  60. package/dist/lib/schema/index.js +0 -54
  61. package/dist/lib/schema/primaryKey.d.ts +0 -9
  62. package/dist/lib/schema/primaryKey.js +0 -24
  63. package/dist/lib/schema/table.d.ts +0 -43
  64. package/dist/lib/schema/table.js +0 -110
  65. package/dist/lib/schema/timestamps.d.ts +0 -3
  66. package/dist/lib/schema/timestamps.js +0 -9
  67. package/dist/lib/utils.d.ts +0 -26
  68. package/dist/lib/utils.js +0 -114
  69. package/dist/rake-db.d.ts +0 -2
  70. package/dist/rake-db.js +0 -34
  71. package/dist/types.d.ts +0 -94
  72. package/dist/types.js +0 -40
@@ -0,0 +1,417 @@
1
+ import {
2
+ expectSql,
3
+ getDb,
4
+ queryMock,
5
+ resetDb,
6
+ setDbDown,
7
+ toLine,
8
+ } from '../test-utils';
9
+ import { raw } from 'pqb';
10
+
11
+ const db = getDb();
12
+
13
+ describe('changeTable', () => {
14
+ beforeEach(resetDb);
15
+
16
+ it('should set comment', async () => {
17
+ const fn = () => {
18
+ return db.changeTable('table', { comment: 'comment' });
19
+ };
20
+
21
+ await fn();
22
+ expectSql(`COMMENT ON TABLE "table" IS 'comment'`);
23
+
24
+ setDbDown();
25
+ await fn();
26
+ expectSql(`COMMENT ON TABLE "table" IS NULL`);
27
+ });
28
+
29
+ it('should change comment', async () => {
30
+ const fn = () => {
31
+ return db.changeTable('table', { comment: ['old', 'new'] });
32
+ };
33
+
34
+ await fn();
35
+ expectSql(`COMMENT ON TABLE "table" IS 'new'`);
36
+
37
+ setDbDown();
38
+ await fn();
39
+ expectSql(`COMMENT ON TABLE "table" IS 'old'`);
40
+ });
41
+
42
+ (['add', 'drop'] as const).forEach((action) => {
43
+ it(`should ${action} columns ${
44
+ action === 'add' ? 'to' : 'from'
45
+ } table`, async () => {
46
+ const fn = () => {
47
+ return db.changeTable('table', (t) => ({
48
+ id: t[action](t.serial().primaryKey()),
49
+ dropCascade: t[action](t.text(), { dropMode: 'CASCADE' }),
50
+ nullable: t[action](t.text().nullable()),
51
+ nonNullable: t[action](t.text()),
52
+ withDefault: t[action](t.boolean().default(false)),
53
+ withDefaultRaw: t[action](t.date().default(raw(`now()`))),
54
+ withIndex: t[action](
55
+ t.text().index({
56
+ name: 'indexName',
57
+ unique: true,
58
+ using: 'gin',
59
+ expression: 10,
60
+ collate: 'utf-8',
61
+ operator: 'operator',
62
+ order: 'ASC',
63
+ include: 'id',
64
+ with: 'fillfactor = 70',
65
+ tablespace: 'tablespace',
66
+ where: 'column = 123',
67
+ }),
68
+ ),
69
+ uniqueColumn: t[action](t.text().unique({ dropMode: 'CASCADE' })),
70
+ columnWithComment: t[action](
71
+ t.text().comment('this is a column comment'),
72
+ ),
73
+ varcharWithLength: t[action](t.varchar(20)),
74
+ decimalWithPrecisionAndScale: t[action](t.decimal(10, 5)),
75
+ columnWithCompression: t[action](t.text().compression('compression')),
76
+ columnWithCollate: t[action](t.text().collate('utf-8')),
77
+ columnWithForeignKey: t[action](
78
+ t.integer().foreignKey('table', 'column', {
79
+ name: 'fkeyConstraint',
80
+ match: 'FULL',
81
+ onUpdate: 'CASCADE',
82
+ onDelete: 'CASCADE',
83
+ }),
84
+ ),
85
+ ...t[action](t.timestamps()),
86
+ }));
87
+ };
88
+
89
+ const expectAddColumns = () => {
90
+ expectSql([
91
+ `
92
+ ALTER TABLE "table"
93
+ ADD COLUMN "id" serial PRIMARY KEY,
94
+ ADD COLUMN "dropCascade" text NOT NULL,
95
+ ADD COLUMN "nullable" text,
96
+ ADD COLUMN "nonNullable" text NOT NULL,
97
+ ADD COLUMN "withDefault" boolean NOT NULL DEFAULT false,
98
+ ADD COLUMN "withDefaultRaw" date NOT NULL DEFAULT now(),
99
+ ADD COLUMN "withIndex" text NOT NULL,
100
+ ADD COLUMN "uniqueColumn" text NOT NULL,
101
+ ADD COLUMN "columnWithComment" text NOT NULL,
102
+ ADD COLUMN "varcharWithLength" varchar(20) NOT NULL,
103
+ ADD COLUMN "decimalWithPrecisionAndScale" decimal(10, 5) NOT NULL,
104
+ ADD COLUMN "columnWithCompression" text COMPRESSION compression NOT NULL,
105
+ ADD COLUMN "columnWithCollate" text COLLATE 'utf-8' NOT NULL,
106
+ ADD COLUMN "columnWithForeignKey" integer NOT NULL CONSTRAINT "fkeyConstraint" REFERENCES "table"("column") MATCH FULL ON DELETE CASCADE ON UPDATE CASCADE,
107
+ ADD COLUMN "createdAt" timestamp NOT NULL DEFAULT now(),
108
+ ADD COLUMN "updatedAt" timestamp NOT NULL DEFAULT now()
109
+ `,
110
+ toLine(`
111
+ CREATE UNIQUE INDEX "indexName"
112
+ ON "table"
113
+ USING gin
114
+ ("withIndex"(10) COLLATE 'utf-8' operator ASC)
115
+ INCLUDE ("id")
116
+ WITH (fillfactor = 70)
117
+ TABLESPACE tablespace
118
+ WHERE column = 123
119
+ `),
120
+ toLine(`
121
+ CREATE UNIQUE INDEX "tableUniqueColumnIndex"
122
+ ON "table"
123
+ ("uniqueColumn")
124
+ `),
125
+ `COMMENT ON COLUMN "table"."columnWithComment" IS 'this is a column comment'`,
126
+ ]);
127
+ };
128
+
129
+ const expectRemoveColumns = () => {
130
+ expectSql([
131
+ `
132
+ ALTER TABLE "table"
133
+ DROP COLUMN "id",
134
+ DROP COLUMN "dropCascade" CASCADE,
135
+ DROP COLUMN "nullable",
136
+ DROP COLUMN "nonNullable",
137
+ DROP COLUMN "withDefault",
138
+ DROP COLUMN "withDefaultRaw",
139
+ DROP COLUMN "withIndex",
140
+ DROP COLUMN "uniqueColumn",
141
+ DROP COLUMN "columnWithComment",
142
+ DROP COLUMN "varcharWithLength",
143
+ DROP COLUMN "decimalWithPrecisionAndScale",
144
+ DROP COLUMN "columnWithCompression",
145
+ DROP COLUMN "columnWithCollate",
146
+ DROP COLUMN "columnWithForeignKey",
147
+ DROP COLUMN "createdAt",
148
+ DROP COLUMN "updatedAt"
149
+ `,
150
+ toLine(`DROP INDEX "indexName"`),
151
+ toLine(`DROP INDEX "tableUniqueColumnIndex" CASCADE`),
152
+ ]);
153
+ };
154
+
155
+ await fn();
156
+ (action === 'add' ? expectAddColumns : expectRemoveColumns)();
157
+
158
+ queryMock.mockClear();
159
+ db.up = false;
160
+ await fn();
161
+ (action === 'add' ? expectRemoveColumns : expectAddColumns)();
162
+ });
163
+
164
+ it(`should ${action} composite primary key`, async () => {
165
+ const fn = () => {
166
+ return db.changeTable('table', (t) => ({
167
+ ...t[action](t.primaryKey(['id', 'name'])),
168
+ }));
169
+ };
170
+
171
+ const expectAddPrimaryKey = () => {
172
+ expectSql(`
173
+ ALTER TABLE "table"
174
+ ADD PRIMARY KEY ("id", "name")
175
+ `);
176
+ };
177
+
178
+ const expectDropPrimaryKey = () => {
179
+ expectSql(`
180
+ ALTER TABLE "table"
181
+ DROP CONSTRAINT "table_pkey"
182
+ `);
183
+ };
184
+
185
+ await fn();
186
+ (action === 'add' ? expectAddPrimaryKey : expectDropPrimaryKey)();
187
+
188
+ db.up = false;
189
+ queryMock.mockClear();
190
+ await fn();
191
+ (action === 'add' ? expectDropPrimaryKey : expectAddPrimaryKey)();
192
+ });
193
+
194
+ it(`should ${action} composite primary key with constraint name`, async () => {
195
+ const fn = () => {
196
+ return db.changeTable('table', (t) => ({
197
+ ...t[action](
198
+ t.primaryKey(['id', 'name'], { name: 'primaryKeyName' }),
199
+ ),
200
+ }));
201
+ };
202
+
203
+ const expectAddPrimaryKey = () => {
204
+ expectSql(`
205
+ ALTER TABLE "table"
206
+ ADD CONSTRAINT "primaryKeyName" PRIMARY KEY ("id", "name")
207
+ `);
208
+ };
209
+
210
+ const expectDropPrimaryKey = () => {
211
+ expectSql(`
212
+ ALTER TABLE "table"
213
+ DROP CONSTRAINT "primaryKeyName"
214
+ `);
215
+ };
216
+
217
+ await fn();
218
+ (action === 'add' ? expectAddPrimaryKey : expectDropPrimaryKey)();
219
+
220
+ db.up = false;
221
+ queryMock.mockClear();
222
+ await fn();
223
+ (action === 'add' ? expectDropPrimaryKey : expectAddPrimaryKey)();
224
+ });
225
+
226
+ it(`should ${action} composite index`, async () => {
227
+ const fn = () => {
228
+ return db.changeTable('table', (t) => ({
229
+ ...t[action](
230
+ t.index(['id', { column: 'name', order: 'DESC' }], {
231
+ name: 'compositeIndexOnTable',
232
+ dropMode: 'CASCADE',
233
+ }),
234
+ ),
235
+ }));
236
+ };
237
+
238
+ const expectCreateIndex = () => {
239
+ expectSql(`
240
+ CREATE INDEX "compositeIndexOnTable" ON "table" ("id", "name" DESC)
241
+ `);
242
+ };
243
+
244
+ const expectDropIndex = () => {
245
+ expectSql(`
246
+ DROP INDEX "compositeIndexOnTable" CASCADE
247
+ `);
248
+ };
249
+
250
+ await fn();
251
+ (action === 'add' ? expectCreateIndex : expectDropIndex)();
252
+
253
+ db.up = false;
254
+ queryMock.mockClear();
255
+ await fn();
256
+ (action === 'add' ? expectDropIndex : expectCreateIndex)();
257
+ });
258
+
259
+ it(`should ${action} composite unique index`, async () => {
260
+ const fn = () => {
261
+ return db.changeTable('table', (t) => ({
262
+ ...t[action](
263
+ t.unique(['id', { column: 'name', order: 'DESC' }], {
264
+ name: 'compositeIndexOnTable',
265
+ dropMode: 'CASCADE',
266
+ }),
267
+ ),
268
+ }));
269
+ };
270
+
271
+ const expectCreateIndex = () => {
272
+ expectSql(`
273
+ CREATE UNIQUE INDEX "compositeIndexOnTable" ON "table" ("id", "name" DESC)
274
+ `);
275
+ };
276
+
277
+ const expectDropIndex = () => {
278
+ expectSql(`
279
+ DROP INDEX "compositeIndexOnTable" CASCADE
280
+ `);
281
+ };
282
+
283
+ await fn();
284
+ (action === 'add' ? expectCreateIndex : expectDropIndex)();
285
+
286
+ db.up = false;
287
+ queryMock.mockClear();
288
+ await fn();
289
+ (action === 'add' ? expectDropIndex : expectCreateIndex)();
290
+ });
291
+
292
+ it(`should ${action} composite foreign key`, async () => {
293
+ const fn = () => {
294
+ return db.changeTable('table', (t) => ({
295
+ ...t[action](
296
+ t.foreignKey(
297
+ ['id', 'name'],
298
+ 'otherTable',
299
+ ['foreignId', 'foreignName'],
300
+ {
301
+ name: 'constraintName',
302
+ match: 'FULL',
303
+ onUpdate: 'CASCADE',
304
+ onDelete: 'CASCADE',
305
+ dropMode: 'CASCADE',
306
+ },
307
+ ),
308
+ ),
309
+ }));
310
+ };
311
+
312
+ const expectedConstraint = toLine(`
313
+ ADD CONSTRAINT "constraintName"
314
+ FOREIGN KEY ("id", "name")
315
+ REFERENCES "otherTable"("foreignId", "foreignName")
316
+ MATCH FULL
317
+ ON DELETE CASCADE
318
+ ON UPDATE CASCADE
319
+ `);
320
+
321
+ const expectAddConstraint = () => {
322
+ expectSql(`
323
+ ALTER TABLE "table"
324
+ ${expectedConstraint}
325
+ `);
326
+ };
327
+
328
+ const expectDropConstraint = () => {
329
+ expectSql(`
330
+ ALTER TABLE "table"
331
+ DROP CONSTRAINT "constraintName" CASCADE
332
+ `);
333
+ };
334
+
335
+ await fn();
336
+ (action === 'add' ? expectAddConstraint : expectDropConstraint)();
337
+
338
+ db.up = false;
339
+ queryMock.mockClear();
340
+ await fn();
341
+ (action === 'add' ? expectDropConstraint : expectAddConstraint)();
342
+ });
343
+ });
344
+
345
+ it('should change column', async () => {
346
+ const fn = () => {
347
+ return db.changeTable('table', (t) => ({
348
+ changeType: t.change(t.integer(), t.text()),
349
+ changeTypeUsing: t.change(t.integer(), t.text(), {
350
+ usingUp: raw('b::text'),
351
+ usingDown: raw('b::int'),
352
+ }),
353
+ changeCollate: t.change(
354
+ t.text().collate('de_DE'),
355
+ t.text().collate('fr_FR'),
356
+ ),
357
+ changeDefault: t.change(t.default('from'), t.default(raw("'to'"))),
358
+ changeNull: t.change(t.nonNullable(), t.nullable()),
359
+ changeComment: t.change(t.comment('comment 1'), t.comment('comment 2')),
360
+ }));
361
+ };
362
+
363
+ await fn();
364
+ expectSql([
365
+ `
366
+ ALTER TABLE "table"
367
+ ALTER COLUMN "changeType" TYPE text,
368
+ ALTER COLUMN "changeTypeUsing" TYPE text USING b::text,
369
+ ALTER COLUMN "changeCollate" TYPE text COLLATE 'fr_FR',
370
+ ALTER COLUMN "changeDefault" SET DEFAULT 'to',
371
+ ALTER COLUMN "changeNull" DROP NOT NULL
372
+ `,
373
+ `COMMENT ON COLUMN "table"."changeComment" IS 'comment 2'`,
374
+ ]);
375
+
376
+ queryMock.mockClear();
377
+ db.up = false;
378
+ await fn();
379
+ expectSql([
380
+ `
381
+ ALTER TABLE "table"
382
+ ALTER COLUMN "changeType" TYPE integer,
383
+ ALTER COLUMN "changeTypeUsing" TYPE integer USING b::int,
384
+ ALTER COLUMN "changeCollate" TYPE text COLLATE 'de_DE',
385
+ ALTER COLUMN "changeDefault" SET DEFAULT 'from',
386
+ ALTER COLUMN "changeNull" SET NOT NULL
387
+ `,
388
+ `COMMENT ON COLUMN "table"."changeComment" IS 'comment 1'`,
389
+ ]);
390
+ });
391
+
392
+ it('should rename a column', async () => {
393
+ const fn = () => {
394
+ return db.changeTable('table', (t) => ({
395
+ a: t.rename('b'),
396
+ }));
397
+ };
398
+
399
+ await fn();
400
+ expectSql(
401
+ `
402
+ ALTER TABLE "table"
403
+ RENAME COLUMN "a" TO "b"
404
+ `,
405
+ );
406
+
407
+ queryMock.mockClear();
408
+ db.up = false;
409
+ await fn();
410
+ expectSql(
411
+ `
412
+ ALTER TABLE "table"
413
+ RENAME COLUMN "b" TO "a"
414
+ `,
415
+ );
416
+ });
417
+ });