rake-db 2.2.5 → 2.3.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.
@@ -4,7 +4,7 @@ import {
4
4
  getMigrationFiles,
5
5
  RakeDbConfig,
6
6
  MigrationFile,
7
- quoteTable,
7
+ quoteWithSchema,
8
8
  } from '../common';
9
9
  import {
10
10
  getCurrentPromise,
@@ -105,7 +105,9 @@ const saveMigratedVersion = async (
105
105
  config: RakeDbConfig,
106
106
  ) => {
107
107
  await db.query(
108
- `INSERT INTO ${quoteTable(config.migrationsTable)} VALUES ('${version}')`,
108
+ `INSERT INTO ${quoteWithSchema({
109
+ name: config.migrationsTable,
110
+ })} VALUES ('${version}')`,
109
111
  );
110
112
  };
111
113
 
@@ -115,9 +117,9 @@ const removeMigratedVersion = async (
115
117
  config: RakeDbConfig,
116
118
  ) => {
117
119
  await db.query(
118
- `DELETE FROM ${quoteTable(
119
- config.migrationsTable,
120
- )} WHERE version = '${version}'`,
120
+ `DELETE FROM ${quoteWithSchema({
121
+ name: config.migrationsTable,
122
+ })} WHERE version = '${version}'`,
121
123
  );
122
124
  };
123
125
 
@@ -127,7 +129,7 @@ const getMigratedVersionsMap = async (
127
129
  ): Promise<Record<string, boolean>> => {
128
130
  try {
129
131
  const result = await db.arrays<[string]>(
130
- `SELECT * FROM ${quoteTable(config.migrationsTable)}`,
132
+ `SELECT * FROM ${quoteWithSchema({ name: config.migrationsTable })}`,
131
133
  );
132
134
  return Object.fromEntries(result.rows.map((row) => [row[0], true]));
133
135
  } catch (err) {
@@ -8,7 +8,7 @@ import {
8
8
  joinColumns,
9
9
  joinWords,
10
10
  migrationConfigDefaults,
11
- quoteTable,
11
+ quoteWithSchema,
12
12
  setAdapterOptions,
13
13
  setAdminCredentialsToOptions,
14
14
  sortAsc,
@@ -285,13 +285,15 @@ describe('common', () => {
285
285
  });
286
286
  });
287
287
 
288
- describe('quoteTable', () => {
289
- it('should quote a table', () => {
290
- expect(quoteTable('table')).toBe('"table"');
288
+ describe('quoteWithSchema', () => {
289
+ it('should quote a name', () => {
290
+ expect(quoteWithSchema({ name: 'table' })).toBe('"table"');
291
291
  });
292
292
 
293
- it('should quote a table with schema', () => {
294
- expect(quoteTable('schema.table')).toBe('"schema"."table"');
293
+ it('should quote a name with schema', () => {
294
+ expect(quoteWithSchema({ schema: 'schema', name: 'table' })).toBe(
295
+ '"schema"."table"',
296
+ );
295
297
  });
296
298
  });
297
299
  });
package/src/common.ts CHANGED
@@ -126,9 +126,9 @@ export const createSchemaMigrations = async (
126
126
  ) => {
127
127
  try {
128
128
  await db.query(
129
- `CREATE TABLE ${quoteTable(
130
- config.migrationsTable,
131
- )} ( version TEXT NOT NULL )`,
129
+ `CREATE TABLE ${quoteWithSchema({
130
+ name: config.migrationsTable,
131
+ })} ( version TEXT NOT NULL )`,
132
132
  );
133
133
  console.log('Created versions table');
134
134
  } catch (err) {
@@ -235,11 +235,21 @@ export const joinColumns = (columns: string[]) => {
235
235
  return columns.map((column) => `"${column}"`).join(', ');
236
236
  };
237
237
 
238
- export const quoteTable = (table: string) => {
239
- const index = table.indexOf('.');
240
- if (index !== -1) {
241
- return `"${table.slice(0, index)}"."${table.slice(index + 1)}"`;
242
- } else {
243
- return `"${table}"`;
244
- }
238
+ export const quoteWithSchema = ({
239
+ schema,
240
+ name,
241
+ }: {
242
+ schema?: string;
243
+ name: string;
244
+ }) => {
245
+ return schema ? `"${schema}"."${name}"` : `"${name}"`;
246
+ };
247
+
248
+ export const getSchemaAndTableFromName = (
249
+ name: string,
250
+ ): [string | undefined, string] => {
251
+ const index = name.indexOf('.');
252
+ return index !== -1
253
+ ? [name.slice(0, index), name.slice(index + 1)]
254
+ : [undefined, name];
245
255
  };
@@ -18,6 +18,23 @@ describe('changeTable', () => {
18
18
  expect(db.options.appCodeUpdater).toHaveBeenCalled();
19
19
  });
20
20
 
21
+ it('should work for table with schema', async () => {
22
+ const fn = () => {
23
+ return db.changeTable('schema.table', (t) => ({
24
+ column: t.add(t.text()),
25
+ }));
26
+ };
27
+
28
+ await fn();
29
+ expectSql(
30
+ `ALTER TABLE "schema"."table"\nADD COLUMN "column" text NOT NULL`,
31
+ );
32
+
33
+ setDbDown();
34
+ await fn();
35
+ expectSql(`ALTER TABLE "schema"."table"\nDROP COLUMN "column"`);
36
+ });
37
+
21
38
  it('should set comment', async () => {
22
39
  const fn = () => {
23
40
  return db.changeTable('table', { comment: 'comment' });
@@ -61,9 +78,8 @@ describe('changeTable', () => {
61
78
  name: 'indexName',
62
79
  unique: true,
63
80
  using: 'gin',
64
- expression: 10,
65
81
  collate: 'utf-8',
66
- operator: 'operator',
82
+ opclass: 'opclass',
67
83
  order: 'ASC',
68
84
  include: 'id',
69
85
  with: 'fillfactor = 70',
@@ -116,7 +132,7 @@ describe('changeTable', () => {
116
132
  CREATE UNIQUE INDEX "indexName"
117
133
  ON "table"
118
134
  USING gin
119
- ("withIndex"(10) COLLATE 'utf-8' operator ASC)
135
+ ("withIndex" COLLATE 'utf-8' opclass ASC)
120
136
  INCLUDE ("id")
121
137
  WITH (fillfactor = 70)
122
138
  TABLESPACE tablespace
@@ -587,9 +603,8 @@ describe('changeTable', () => {
587
603
  addIndexWithOptions: t.change(
588
604
  t.integer(),
589
605
  t.integer().index({
590
- expression: 'expression',
591
606
  collate: 'collate',
592
- operator: 'operator',
607
+ opclass: 'opclass',
593
608
  order: 'order',
594
609
  unique: true,
595
610
  using: 'using',
@@ -603,9 +618,8 @@ describe('changeTable', () => {
603
618
  removeIndex: t.change(t.integer().index(), t.integer()),
604
619
  removeIndexWithOptions: t.change(
605
620
  t.integer().index({
606
- expression: 'expression',
607
621
  collate: 'collate',
608
- operator: 'operator',
622
+ opclass: 'opclass',
609
623
  order: 'order',
610
624
  unique: true,
611
625
  using: 'using',
@@ -620,9 +634,8 @@ describe('changeTable', () => {
620
634
  changeIndex: t.change(
621
635
  t.integer().index({
622
636
  name: 'from',
623
- expression: 'from',
624
637
  collate: 'from',
625
- operator: 'from',
638
+ opclass: 'from',
626
639
  order: 'from',
627
640
  unique: false,
628
641
  using: 'from',
@@ -634,9 +647,8 @@ describe('changeTable', () => {
634
647
  }),
635
648
  t.integer().index({
636
649
  name: 'to',
637
- expression: 'to',
638
650
  collate: 'to',
639
- operator: 'to',
651
+ opclass: 'to',
640
652
  order: 'to',
641
653
  unique: true,
642
654
  using: 'to',
@@ -656,8 +668,8 @@ describe('changeTable', () => {
656
668
  `DROP INDEX "tableRemoveIndexWithOptionsIndex" CASCADE`,
657
669
  `DROP INDEX "from" CASCADE`,
658
670
  `CREATE INDEX "tableAddIndexIndex" ON "table" ("addIndex")`,
659
- `CREATE UNIQUE INDEX "tableAddIndexWithOptionsIndex" ON "table" USING using ("addIndexWithOptions"(expression) COLLATE 'collate' operator order) INCLUDE ("a", "b") WITH (with) TABLESPACE tablespace WHERE where`,
660
- `CREATE UNIQUE INDEX "to" ON "table" USING to ("changeIndex"(to) COLLATE 'to' to to) INCLUDE ("c", "d") WITH (to) TABLESPACE to WHERE to`,
671
+ `CREATE UNIQUE INDEX "tableAddIndexWithOptionsIndex" ON "table" USING using ("addIndexWithOptions" COLLATE 'collate' opclass order) INCLUDE ("a", "b") WITH (with) TABLESPACE tablespace WHERE where`,
672
+ `CREATE UNIQUE INDEX "to" ON "table" USING to ("changeIndex" COLLATE 'to' to to) INCLUDE ("c", "d") WITH (to) TABLESPACE to WHERE to`,
661
673
  ]);
662
674
 
663
675
  queryMock.mockClear();
@@ -668,8 +680,8 @@ describe('changeTable', () => {
668
680
  `DROP INDEX "tableAddIndexWithOptionsIndex" CASCADE`,
669
681
  `DROP INDEX "to" RESTRICT`,
670
682
  `CREATE INDEX "tableRemoveIndexIndex" ON "table" ("removeIndex")`,
671
- `CREATE UNIQUE INDEX "tableRemoveIndexWithOptionsIndex" ON "table" USING using ("removeIndexWithOptions"(expression) COLLATE 'collate' operator order) INCLUDE ("a", "b") WITH (with) TABLESPACE tablespace WHERE where`,
672
- `CREATE INDEX "from" ON "table" USING from ("changeIndex"(from) COLLATE 'from' from from) INCLUDE ("a", "b") WITH (from) TABLESPACE from WHERE from`,
683
+ `CREATE UNIQUE INDEX "tableRemoveIndexWithOptionsIndex" ON "table" USING using ("removeIndexWithOptions" COLLATE 'collate' opclass order) INCLUDE ("a", "b") WITH (with) TABLESPACE tablespace WHERE where`,
684
+ `CREATE INDEX "from" ON "table" USING from ("changeIndex" COLLATE 'from' from from) INCLUDE ("a", "b") WITH (from) TABLESPACE from WHERE from`,
673
685
  ]);
674
686
  });
675
687
 
@@ -23,7 +23,7 @@ import {
23
23
  runCodeUpdater,
24
24
  } from './migration';
25
25
  import { RakeDbAst } from '../ast';
26
- import { quoteTable } from '../common';
26
+ import { getSchemaAndTableFromName, quoteWithSchema } from '../common';
27
27
  import {
28
28
  addColumnComment,
29
29
  addColumnIndex,
@@ -127,18 +127,18 @@ const columnTypeToColumnChange = (
127
127
  item: ColumnType | Change,
128
128
  ): RakeDbAst.ColumnChange => {
129
129
  if (item instanceof ColumnType) {
130
- const foreignKey = item.data.foreignKey;
131
- if (foreignKey && 'fn' in foreignKey) {
130
+ const foreignKeys = item.data.foreignKeys;
131
+ if (foreignKeys?.some((it) => 'fn' in it)) {
132
132
  throw new Error('Callback in foreignKey is not allowed in migration');
133
133
  }
134
134
 
135
135
  return {
136
136
  column: item,
137
137
  type: item.toSQL(),
138
- nullable: item.isNullable,
138
+ nullable: item.data.isNullable,
139
139
  primaryKey: item.isPrimaryKey,
140
140
  ...item.data,
141
- foreignKey,
141
+ foreignKeys: foreignKeys as RakeDbAst.ColumnChange['foreignKeys'],
142
142
  };
143
143
  }
144
144
 
@@ -257,9 +257,12 @@ const makeAst = (
257
257
  }
258
258
  }
259
259
 
260
+ const [schema, table] = getSchemaAndTableFromName(name);
261
+
260
262
  return {
261
263
  type: 'changeTable',
262
- name,
264
+ schema,
265
+ name: table,
263
266
  comment: comment
264
267
  ? up
265
268
  ? Array.isArray(comment)
@@ -287,7 +290,7 @@ const astToQueries = (ast: RakeDbAst.ChangeTable): Sql[] => {
287
290
 
288
291
  if (ast.comment !== undefined) {
289
292
  result.push({
290
- text: `COMMENT ON TABLE ${quoteTable(ast.name)} IS ${quote(ast.comment)}`,
293
+ text: `COMMENT ON TABLE ${quoteWithSchema(ast)} IS ${quote(ast.comment)}`,
291
294
  values: [],
292
295
  });
293
296
  }
@@ -392,83 +395,96 @@ const astToQueries = (ast: RakeDbAst.ChangeTable): Sql[] => {
392
395
  );
393
396
  }
394
397
 
395
- const fromFkey = from.foreignKey;
396
- const toFkey = to.foreignKey;
397
- if (
398
- (fromFkey || toFkey) &&
399
- (!fromFkey ||
400
- !toFkey ||
401
- fromFkey.name !== toFkey.name ||
402
- fromFkey.match !== toFkey.match ||
403
- fromFkey.onUpdate !== toFkey.onUpdate ||
404
- fromFkey.onDelete !== toFkey.onDelete ||
405
- fromFkey.dropMode !== toFkey.dropMode ||
406
- fromFkey.table !== toFkey.table ||
407
- fromFkey.columns.join(',') !== toFkey.columns.join(','))
408
- ) {
409
- if (fromFkey) {
410
- dropForeignKeys.push({
411
- columns: [key],
412
- fnOrTable: fromFkey.table,
413
- foreignColumns: fromFkey.columns,
414
- options: fromFkey,
415
- });
416
- }
417
-
418
- if (toFkey) {
419
- addForeignKeys.push({
420
- columns: [key],
421
- fnOrTable: toFkey.table,
422
- foreignColumns: toFkey.columns,
423
- options: toFkey,
424
- });
398
+ const foreignKeysLen = Math.max(
399
+ from.foreignKeys?.length || 0,
400
+ to.foreignKeys?.length || 0,
401
+ );
402
+ for (let i = 0; i < foreignKeysLen; i++) {
403
+ const fromFkey = from.foreignKeys?.[i];
404
+ const toFkey = to.foreignKeys?.[i];
405
+
406
+ if (
407
+ (fromFkey || toFkey) &&
408
+ (!fromFkey ||
409
+ !toFkey ||
410
+ fromFkey.name !== toFkey.name ||
411
+ fromFkey.match !== toFkey.match ||
412
+ fromFkey.onUpdate !== toFkey.onUpdate ||
413
+ fromFkey.onDelete !== toFkey.onDelete ||
414
+ fromFkey.dropMode !== toFkey.dropMode ||
415
+ fromFkey.table !== toFkey.table ||
416
+ fromFkey.columns.join(',') !== toFkey.columns.join(','))
417
+ ) {
418
+ if (fromFkey) {
419
+ dropForeignKeys.push({
420
+ columns: [key],
421
+ fnOrTable: fromFkey.table,
422
+ foreignColumns: fromFkey.columns,
423
+ options: fromFkey,
424
+ });
425
+ }
426
+
427
+ if (toFkey) {
428
+ addForeignKeys.push({
429
+ columns: [key],
430
+ fnOrTable: toFkey.table,
431
+ foreignColumns: toFkey.columns,
432
+ options: toFkey,
433
+ });
434
+ }
425
435
  }
426
436
  }
427
437
 
428
- const fromIndex = from.index;
429
- const toIndex = to.index;
430
- if (
431
- (fromIndex || toIndex) &&
432
- (!fromIndex ||
433
- !toIndex ||
434
- fromIndex.expression !== toIndex.expression ||
435
- fromIndex.collate !== toIndex.collate ||
436
- fromIndex.operator !== toIndex.operator ||
437
- fromIndex.order !== toIndex.order ||
438
- fromIndex.name !== toIndex.name ||
439
- fromIndex.unique !== toIndex.unique ||
440
- fromIndex.using !== toIndex.using ||
441
- fromIndex.include !== toIndex.include ||
442
- (Array.isArray(fromIndex.include) &&
443
- Array.isArray(toIndex.include) &&
444
- fromIndex.include.join(',') !== toIndex.include.join(',')) ||
445
- fromIndex.with !== toIndex.with ||
446
- fromIndex.tablespace !== toIndex.tablespace ||
447
- fromIndex.where !== toIndex.where ||
448
- fromIndex.dropMode !== toIndex.dropMode)
449
- ) {
450
- if (fromIndex) {
451
- dropIndexes.push({
452
- columns: [
453
- {
454
- column: key,
455
- ...fromIndex,
456
- },
457
- ],
458
- options: fromIndex,
459
- });
460
- }
461
-
462
- if (toIndex) {
463
- addIndexes.push({
464
- columns: [
465
- {
466
- column: key,
467
- ...toIndex,
468
- },
469
- ],
470
- options: toIndex,
471
- });
438
+ const indexesLen = Math.max(
439
+ from.indexes?.length || 0,
440
+ to.indexes?.length || 0,
441
+ );
442
+ for (let i = 0; i < indexesLen; i++) {
443
+ const fromIndex = from.indexes?.[i];
444
+ const toIndex = to.indexes?.[i];
445
+
446
+ if (
447
+ (fromIndex || toIndex) &&
448
+ (!fromIndex ||
449
+ !toIndex ||
450
+ fromIndex.collate !== toIndex.collate ||
451
+ fromIndex.opclass !== toIndex.opclass ||
452
+ fromIndex.order !== toIndex.order ||
453
+ fromIndex.name !== toIndex.name ||
454
+ fromIndex.unique !== toIndex.unique ||
455
+ fromIndex.using !== toIndex.using ||
456
+ fromIndex.include !== toIndex.include ||
457
+ (Array.isArray(fromIndex.include) &&
458
+ Array.isArray(toIndex.include) &&
459
+ fromIndex.include.join(',') !== toIndex.include.join(',')) ||
460
+ fromIndex.with !== toIndex.with ||
461
+ fromIndex.tablespace !== toIndex.tablespace ||
462
+ fromIndex.where !== toIndex.where ||
463
+ fromIndex.dropMode !== toIndex.dropMode)
464
+ ) {
465
+ if (fromIndex) {
466
+ dropIndexes.push({
467
+ columns: [
468
+ {
469
+ column: key,
470
+ ...fromIndex,
471
+ },
472
+ ],
473
+ options: fromIndex,
474
+ });
475
+ }
476
+
477
+ if (toIndex) {
478
+ addIndexes.push({
479
+ columns: [
480
+ {
481
+ column: key,
482
+ ...toIndex,
483
+ },
484
+ ],
485
+ options: toIndex,
486
+ });
487
+ }
472
488
  }
473
489
  }
474
490
 
@@ -493,7 +509,7 @@ const astToQueries = (ast: RakeDbAst.ChangeTable): Sql[] => {
493
509
 
494
510
  prependAlterTable.push(
495
511
  ...dropForeignKeys.map(
496
- (foreignKey) => `\n DROP ${constraintToSql(ast.name, false, foreignKey)}`,
512
+ (foreignKey) => `\n DROP ${constraintToSql(ast, false, foreignKey)}`,
497
513
  ),
498
514
  );
499
515
 
@@ -509,22 +525,22 @@ const astToQueries = (ast: RakeDbAst.ChangeTable): Sql[] => {
509
525
 
510
526
  alterTable.push(
511
527
  ...addForeignKeys.map(
512
- (foreignKey) => `\n ADD ${constraintToSql(ast.name, true, foreignKey)}`,
528
+ (foreignKey) => `\n ADD ${constraintToSql(ast, true, foreignKey)}`,
513
529
  ),
514
530
  );
515
531
 
516
532
  if (alterTable.length) {
517
533
  result.push({
518
534
  text:
519
- `ALTER TABLE ${quoteTable(ast.name)}` +
535
+ `ALTER TABLE ${quoteWithSchema(ast)}` +
520
536
  `\n ${alterTable.join(',\n ')}`,
521
537
  values,
522
538
  });
523
539
  }
524
540
 
525
- result.push(...indexesToQuery(false, ast.name, dropIndexes));
526
- result.push(...indexesToQuery(true, ast.name, addIndexes));
527
- result.push(...commentsToQuery(ast.name, comments));
541
+ result.push(...indexesToQuery(false, ast, dropIndexes));
542
+ result.push(...indexesToQuery(true, ast, addIndexes));
543
+ result.push(...commentsToQuery(ast, comments));
528
544
 
529
545
  return result;
530
546
  };
@@ -0,0 +1,96 @@
1
+ import { getPrimaryKeysOfTable } from './migrationUtils';
2
+ import { expectSql, getDb, queryMock, resetDb } from '../test-utils';
3
+
4
+ const db = getDb();
5
+
6
+ jest.mock('./migrationUtils', () => ({
7
+ ...jest.requireActual('./migrationUtils'),
8
+ getPrimaryKeysOfTable: jest.fn(),
9
+ }));
10
+
11
+ describe('join table', () => {
12
+ beforeEach(resetDb);
13
+
14
+ (['createJoinTable', 'dropJoinTable'] as const).forEach((action) => {
15
+ describe(action, () => {
16
+ it(`should ${
17
+ action === 'createJoinTable' ? 'create' : 'drop'
18
+ } a join table`, async () => {
19
+ const fn = () => {
20
+ return db[action](['posts', 'comments'], (t) => ({
21
+ ...t.timestamps(),
22
+ }));
23
+ };
24
+
25
+ const expectCreateTable = async () => {
26
+ (getPrimaryKeysOfTable as jest.Mock)
27
+ .mockResolvedValueOnce([
28
+ {
29
+ name: 'uuid',
30
+ type: 'uuid',
31
+ },
32
+ ])
33
+ .mockResolvedValueOnce([
34
+ {
35
+ name: 'id',
36
+ type: 'integer',
37
+ },
38
+ {
39
+ name: 'authorName',
40
+ type: 'text',
41
+ },
42
+ ]);
43
+
44
+ await fn();
45
+
46
+ expectSql(`
47
+ CREATE TABLE "postsComments" (
48
+ "postUuid" uuid NOT NULL REFERENCES "posts"("uuid"),
49
+ "commentId" integer NOT NULL,
50
+ "commentAuthorName" text NOT NULL,
51
+ "createdAt" timestamp NOT NULL DEFAULT now(),
52
+ "updatedAt" timestamp NOT NULL DEFAULT now(),
53
+ PRIMARY KEY ("postUuid", "commentId", "commentAuthorName"),
54
+ CONSTRAINT "postsComments_commentId_commentAuthorName_fkey" FOREIGN KEY ("commentId", "commentAuthorName") REFERENCES "comments"("id", "authorName")
55
+ )
56
+ `);
57
+ };
58
+
59
+ const expectDropTable = async () => {
60
+ await fn();
61
+
62
+ expectSql(`
63
+ DROP TABLE "postsComments"
64
+ `);
65
+ };
66
+
67
+ await (action === 'createJoinTable'
68
+ ? expectCreateTable
69
+ : expectDropTable)();
70
+
71
+ db.up = false;
72
+ queryMock.mockClear();
73
+ await (action === 'createJoinTable'
74
+ ? expectDropTable
75
+ : expectCreateTable)();
76
+ });
77
+
78
+ it('should throw error if table has no primary key', async () => {
79
+ db.up = action !== 'dropJoinTable';
80
+
81
+ (getPrimaryKeysOfTable as jest.Mock)
82
+ .mockResolvedValueOnce([
83
+ {
84
+ name: 'id',
85
+ type: 'integer',
86
+ },
87
+ ])
88
+ .mockResolvedValueOnce([]);
89
+
90
+ await expect(db[action](['posts', 'comments'])).rejects.toThrow(
91
+ 'Primary key for table "comments" is not defined',
92
+ );
93
+ });
94
+ });
95
+ });
96
+ });
@@ -1,6 +1,10 @@
1
1
  import { ColumnType, Operators } from 'pqb';
2
2
  import { ColumnsShapeCallback, JoinTableOptions, Migration } from './migration';
3
- import { joinWords, quoteTable } from '../common';
3
+ import {
4
+ getSchemaAndTableFromName,
5
+ joinWords,
6
+ quoteWithSchema,
7
+ } from '../common';
4
8
  import { getPrimaryKeysOfTable } from './migrationUtils';
5
9
  import { singular } from 'pluralize';
6
10
  import { createTable } from './createTable';
@@ -46,26 +50,33 @@ export const createJoinTable = async (
46
50
  })),
47
51
  );
48
52
 
53
+ const [schema, name] = getSchemaAndTableFromName(table);
49
54
  if (!primaryKeys.length) {
50
55
  throw new Error(
51
- `Primary key for table ${quoteTable(table)} is not defined`,
56
+ `Primary key for table ${quoteWithSchema({
57
+ schema,
58
+ name,
59
+ })} is not defined`,
52
60
  );
53
61
  }
54
62
 
55
- return [table, primaryKeys] as const;
63
+ return [schema, table, primaryKeys] as const;
56
64
  }),
57
65
  );
58
66
 
59
67
  return createTable(migration, up, tableName, options, (t) => {
60
68
  const result: Record<string, ColumnType> = {};
61
69
 
62
- tablesWithPrimaryKeys.forEach(([table, primaryKeys]) => {
70
+ tablesWithPrimaryKeys.forEach(([schema, table, primaryKeys]) => {
63
71
  if (primaryKeys.length === 1) {
64
72
  const [{ type, joinedName, name }] = primaryKeys;
65
73
 
66
74
  const column = new UnknownColumn(type);
67
75
 
68
- result[joinedName] = column.foreignKey(table, name);
76
+ result[joinedName] = column.foreignKey(
77
+ schema ? `${schema}.${table}` : table,
78
+ name,
79
+ );
69
80
 
70
81
  return;
71
82
  }
@@ -86,7 +97,7 @@ export const createJoinTable = async (
86
97
  }
87
98
 
88
99
  t.primaryKey(
89
- tablesWithPrimaryKeys.flatMap(([, primaryKeys]) =>
100
+ tablesWithPrimaryKeys.flatMap(([, , primaryKeys]) =>
90
101
  primaryKeys.map((item) => item.joinedName),
91
102
  ),
92
103
  );