rake-db 2.3.1 → 2.3.2

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rake-db",
3
- "version": "2.3.1",
3
+ "version": "2.3.2",
4
4
  "description": "Migrations tool for Postgresql DB",
5
5
  "homepage": "https://orchid-orm.netlify.app/guide/migration-setup-and-overview.html",
6
6
  "repository": {
@@ -42,7 +42,7 @@
42
42
  "dependencies": {
43
43
  "enquirer": "^2.3.6",
44
44
  "pluralize": "^8.0.0",
45
- "pqb": "0.9.1"
45
+ "pqb": "0.9.2"
46
46
  },
47
47
  "devDependencies": {
48
48
  "@swc/core": "^1.2.210",
@@ -59,6 +59,41 @@ describe('astToMigration', () => {
59
59
  );
60
60
  });
61
61
 
62
+ it('should add columns with indexes and foreignKeys', () => {
63
+ const result = astToMigration([
64
+ {
65
+ ...tableAst,
66
+ shape: {
67
+ someId: columnTypes
68
+ .integer()
69
+ .unique({ name: 'indexName' })
70
+ .foreignKey('otherTable', 'otherId', {
71
+ name: 'fkey',
72
+ match: 'FULL',
73
+ onUpdate: 'CASCADE',
74
+ onDelete: 'CASCADE',
75
+ }),
76
+ },
77
+ },
78
+ ]);
79
+
80
+ expect(result).toBe(`import { change } from 'rake-db';
81
+
82
+ change(async (db) => {
83
+ await db.createTable('schema.table', (t) => ({
84
+ someId: t.integer().foreignKey('otherTable', 'otherId', {
85
+ name: 'fkey',
86
+ match: 'FULL',
87
+ onUpdate: 'CASCADE',
88
+ onDelete: 'CASCADE',
89
+ }).unique({
90
+ name: 'indexName',
91
+ }),
92
+ }));
93
+ });
94
+ `);
95
+ });
96
+
62
97
  it('should add composite primaryKeys, indexes, foreignKeys', () => {
63
98
  const result = astToMigration([
64
99
  {
@@ -3,11 +3,14 @@ import {
3
3
  addCode,
4
4
  Code,
5
5
  codeToString,
6
+ ColumnType,
6
7
  foreignKeyToCode,
7
8
  indexToCode,
9
+ isRaw,
8
10
  primaryKeyToCode,
9
11
  quoteObjectKey,
10
12
  singleQuote,
13
+ TimestampColumn,
11
14
  } from 'pqb';
12
15
  import { quoteSchemaTable } from '../common';
13
16
 
@@ -40,13 +43,24 @@ const createTable = (ast: RakeDbAst.Table) => {
40
43
  const code: Code[] = [];
41
44
  addCode(code, `await db.createTable(${quoteSchemaTable(ast)}, (t) => ({`);
42
45
 
46
+ const hasTimestamps =
47
+ isTimestamp(ast.shape.createdAt) && isTimestamp(ast.shape.updatedAt);
48
+
43
49
  for (const key in ast.shape) {
50
+ if (hasTimestamps && (key === 'createdAt' || key === 'updatedAt')) continue;
51
+
44
52
  const line: Code[] = [`${quoteObjectKey(key)}: `];
45
- addCode(line, ast.shape[key].toCode('t'));
53
+ for (const part of ast.shape[key].toCode('t')) {
54
+ addCode(line, part);
55
+ }
46
56
  addCode(line, ',');
47
57
  code.push(line);
48
58
  }
49
59
 
60
+ if (hasTimestamps) {
61
+ code.push(['...t.timestamps(),']);
62
+ }
63
+
50
64
  if (ast.primaryKey) {
51
65
  code.push([primaryKeyToCode(ast.primaryKey, 't')]);
52
66
  }
@@ -63,3 +77,17 @@ const createTable = (ast: RakeDbAst.Table) => {
63
77
 
64
78
  return code;
65
79
  };
80
+
81
+ const isTimestamp = (column?: ColumnType) => {
82
+ if (!column) return false;
83
+
84
+ const { default: def } = column.data;
85
+ return (
86
+ column instanceof TimestampColumn &&
87
+ !column.data.isNullable &&
88
+ def &&
89
+ typeof def === 'object' &&
90
+ isRaw(def) &&
91
+ def.__raw === 'now()'
92
+ );
93
+ };
@@ -56,6 +56,24 @@ describe('pull', () => {
56
56
  type: 'text',
57
57
  isNullable: false,
58
58
  },
59
+ {
60
+ schemaName: 'public',
61
+ tableName: 'table2',
62
+ name: 'createdAt',
63
+ type: 'timestamp',
64
+ dateTimePrecision: 6,
65
+ isNullable: false,
66
+ default: 'now()',
67
+ },
68
+ {
69
+ schemaName: 'public',
70
+ tableName: 'table2',
71
+ name: 'updatedAt',
72
+ type: 'timestamp',
73
+ dateTimePrecision: 6,
74
+ isNullable: false,
75
+ default: 'now()',
76
+ },
59
77
  ];
60
78
 
61
79
  const config = getMigrationConfigWithDefaults({
@@ -84,6 +102,7 @@ change(async (db) => {
84
102
 
85
103
  await db.createTable('table2', (t) => ({
86
104
  text: t.text(),
105
+ ...t.timestamps(),
87
106
  }));
88
107
  });
89
108
  `,
package/src/pull/pull.ts CHANGED
@@ -9,8 +9,12 @@ export const pullDbStructure = async (
9
9
  options: AdapterOptions,
10
10
  config: RakeDbConfig,
11
11
  ) => {
12
- const db = new DbStructure(new Adapter(options));
12
+ const adapter = new Adapter(options);
13
+ const db = new DbStructure(adapter);
13
14
  const ast = await structureToAst(db);
15
+
16
+ await adapter.close();
17
+
14
18
  const result = astToMigration(ast);
15
19
  if (!result) return;
16
20
 
@@ -4,6 +4,8 @@ import {
4
4
  BigSerialColumn,
5
5
  DecimalColumn,
6
6
  IntegerColumn,
7
+ isRaw,
8
+ RawExpression,
7
9
  SerialColumn,
8
10
  SmallSerialColumn,
9
11
  TextColumn,
@@ -121,7 +123,9 @@ describe('structureToAst', () => {
121
123
  db.getTables = async () => [
122
124
  { schemaName: 'public', name: 'table', comment: 'comment' },
123
125
  ];
126
+
124
127
  const ast = await structureToAst(db);
128
+
125
129
  expect(ast).toEqual([
126
130
  {
127
131
  type: 'table',
@@ -139,7 +143,9 @@ describe('structureToAst', () => {
139
143
  it('should add table with schema', async () => {
140
144
  const db = new DbStructure(adapter);
141
145
  db.getTables = async () => [{ schemaName: 'custom', name: 'table' }];
146
+
142
147
  const ast = await structureToAst(db);
148
+
143
149
  expect(ast).toEqual([
144
150
  {
145
151
  type: 'table',
@@ -154,9 +160,20 @@ describe('structureToAst', () => {
154
160
  ]);
155
161
  });
156
162
 
163
+ it('should ignore schemaMigrations table', async () => {
164
+ const db = new DbStructure(adapter);
165
+ db.getTables = async () => [
166
+ { schemaName: 'public', name: 'schemaMigrations' },
167
+ ];
168
+
169
+ const ast = await structureToAst(db);
170
+
171
+ expect(ast).toEqual([]);
172
+ });
173
+
157
174
  it('should add columns', async () => {
158
175
  const db = new DbStructure(adapter);
159
- db.getTables = async () => [{ schemaName: 'public', name: 'table' }];
176
+ db.getTables = async () => [table];
160
177
  db.getColumns = async () => columns;
161
178
 
162
179
  const [ast] = (await structureToAst(db)) as [RakeDbAst.Table];
@@ -167,6 +184,18 @@ describe('structureToAst', () => {
167
184
  expect(ast.shape.name).toBeInstanceOf(TextColumn);
168
185
  });
169
186
 
187
+ it('should wrap column default into raw', async () => {
188
+ const db = new DbStructure(adapter);
189
+ db.getTables = async () => [table];
190
+ db.getColumns = async () => [{ ...timestampColumn, default: 'now()' }];
191
+
192
+ const [ast] = (await structureToAst(db)) as [RakeDbAst.Table];
193
+
194
+ const { default: def } = ast.shape.timestamp.data;
195
+ expect(def && typeof def === 'object' && isRaw(def)).toBe(true);
196
+ expect((def as RawExpression).__raw).toBe('now()');
197
+ });
198
+
170
199
  describe('serial column', () => {
171
200
  it('should add serial column based on various default values', async () => {
172
201
  const db = new DbStructure(adapter);
@@ -231,7 +260,7 @@ describe('structureToAst', () => {
231
260
 
232
261
  it('should set maxChars to char column', async () => {
233
262
  const db = new DbStructure(adapter);
234
- db.getTables = async () => [{ schemaName: 'public', name: 'table' }];
263
+ db.getTables = async () => [table];
235
264
  db.getColumns = async () => [varCharColumn];
236
265
 
237
266
  const [ast] = (await structureToAst(db)) as [RakeDbAst.Table];
@@ -243,7 +272,7 @@ describe('structureToAst', () => {
243
272
 
244
273
  it('should set numericPrecision and numericScale to decimal column', async () => {
245
274
  const db = new DbStructure(adapter);
246
- db.getTables = async () => [{ schemaName: 'public', name: 'table' }];
275
+ db.getTables = async () => [table];
247
276
  db.getColumns = async () => [decimalColumn];
248
277
 
249
278
  const [ast] = (await structureToAst(db)) as [RakeDbAst.Table];
@@ -256,7 +285,7 @@ describe('structureToAst', () => {
256
285
 
257
286
  it('should set dateTimePrecision to timestamp column', async () => {
258
287
  const db = new DbStructure(adapter);
259
- db.getTables = async () => [{ schemaName: 'public', name: 'table' }];
288
+ db.getTables = async () => [table];
260
289
  db.getColumns = async () => [timestampColumn];
261
290
 
262
291
  const [ast] = (await structureToAst(db)) as [RakeDbAst.Table];
@@ -270,7 +299,7 @@ describe('structureToAst', () => {
270
299
 
271
300
  it('should set primaryKey to column', async () => {
272
301
  const db = new DbStructure(adapter);
273
- db.getTables = async () => [{ schemaName: 'public', name: 'table' }];
302
+ db.getTables = async () => [table];
274
303
  db.getColumns = async () => columns;
275
304
  db.getPrimaryKeys = async () => [primaryKey];
276
305
 
@@ -283,7 +312,7 @@ describe('structureToAst', () => {
283
312
 
284
313
  it('should add composite primary key', async () => {
285
314
  const db = new DbStructure(adapter);
286
- db.getTables = async () => [{ schemaName: 'public', name: 'table' }];
315
+ db.getTables = async () => [table];
287
316
  db.getColumns = async () => columns;
288
317
  db.getPrimaryKeys = async () => [
289
318
  { ...primaryKey, columnNames: ['id', 'name'] },
@@ -301,7 +330,7 @@ describe('structureToAst', () => {
301
330
 
302
331
  it('should ignore primary key name if it is standard', async () => {
303
332
  const db = new DbStructure(adapter);
304
- db.getTables = async () => [{ schemaName: 'public', name: 'table' }];
333
+ db.getTables = async () => [table];
305
334
  db.getColumns = async () => columns;
306
335
  db.getPrimaryKeys = async () => [
307
336
  { ...primaryKey, columnNames: ['id', 'name'], name: 'table_pkey' },
@@ -15,8 +15,8 @@ const matchMap = {
15
15
  };
16
16
 
17
17
  const fkeyActionMap = {
18
- a: 'NO ACTION',
19
- r: undefined, // default
18
+ a: undefined, // default
19
+ r: 'RESTRICT',
20
20
  c: 'CASCADE',
21
21
  n: 'SET NULL',
22
22
  d: 'SET DEFAULT',
@@ -56,6 +56,8 @@ export const structureToAst = async (db: DbStructure): Promise<RakeDbAst[]> => {
56
56
  for (const table of tables) {
57
57
  const { schemaName, name } = table;
58
58
 
59
+ if (name === 'schemaMigrations') continue;
60
+
59
61
  const belongsToTable = makeBelongsToTable(schemaName, name);
60
62
 
61
63
  const columns = allColumns.filter(belongsToTable);
@@ -66,13 +68,14 @@ export const structureToAst = async (db: DbStructure): Promise<RakeDbAst[]> => {
66
68
  const shape: ColumnsShape = {};
67
69
  for (let item of columns) {
68
70
  const isSerial = getIsSerial(item);
71
+ if (isSerial) {
72
+ item = { ...item, default: undefined };
73
+ }
74
+
69
75
  const klass = columnsByType[getColumnType(item, isSerial)];
70
76
  if (!klass) {
71
77
  throw new Error(`Column type \`${item.type}\` is not supported`);
72
78
  }
73
- if (isSerial) {
74
- item = { ...item, default: undefined };
75
- }
76
79
 
77
80
  let column = instantiateColumn(klass, item);
78
81