Skip to content

Commit

Permalink
feat: inline primary key creation for postgres flavours (#5233)
Browse files Browse the repository at this point in the history
  • Loading branch information
hairmare committed Jun 30, 2022
1 parent d371c04 commit 8b0dd49
Show file tree
Hide file tree
Showing 3 changed files with 157 additions and 27 deletions.
39 changes: 33 additions & 6 deletions lib/dialects/postgres/schema/pg-tablecompiler.js
Expand Up @@ -44,7 +44,10 @@ class TableCompiler_PG extends TableCompiler {
const createStatement = ifNot
? 'create table if not exists '
: 'create table ';
const columnsSql = ' (' + columns.sql.join(', ') + this._addChecks() + ')';
const columnsSql = ` (${columns.sql.join(', ')}${
this.primaryKeys() || ''
}${this._addChecks()})`;

let sql =
createStatement +
this.tableName() +
Expand All @@ -65,6 +68,28 @@ class TableCompiler_PG extends TableCompiler {
if (hasComment) this.comment(this.single.comment);
}

primaryKeys() {
const pks = (this.grouped.alterTable || []).filter(
(k) => k.method === 'primary'
);
if (pks.length > 0 && pks[0].args.length > 0) {
const columns = pks[0].args[0];
let constraintName = pks[0].args[1] || '';
let deferrable;
if (isObject(constraintName)) {
({ constraintName, deferrable } = constraintName);
}
deferrable = deferrable ? ` deferrable initially ${deferrable}` : '';
constraintName = constraintName
? this.formatter.wrap(constraintName)
: this.formatter.wrap(`${this.tableNameRaw}_pkey`);

return `, constraint ${constraintName} primary key (${this.formatter.columnize(
columns
)})${deferrable}`;
}
}

addColumns(columns, prefix, colCompilers) {
if (prefix === this.alterColumnsPrefix) {
// alter columns
Expand Down Expand Up @@ -153,11 +178,13 @@ class TableCompiler_PG extends TableCompiler {
constraintName = constraintName
? this.formatter.wrap(constraintName)
: this.formatter.wrap(`${this.tableNameRaw}_pkey`);
this.pushQuery(
`alter table ${this.tableName()} add constraint ${constraintName} primary key (${this.formatter.columnize(
columns
)})${deferrable}`
);
if (this.method !== 'create' && this.method !== 'createIfNot') {
this.pushQuery(
`alter table ${this.tableName()} add constraint ${constraintName} primary key (${this.formatter.columnize(
columns
)})${deferrable}`
);
}
}

unique(columns, indexName) {
Expand Down
46 changes: 37 additions & 9 deletions test/integration2/schema/misc.spec.js
Expand Up @@ -483,25 +483,54 @@ describe('Schema (misc)', () => {
});

describe('uuid types - postgres', () => {
before(async () => {
await knex.schema.createTable('uuid_column_test', (table) => {
table.uuid('id', { primaryKey: true });
});
after(async () => {
if (isPgBased(knex)) {
await knex.schema.dropTable('uuid_column_test');
}
});

after(async () => {
await knex.schema.dropTable('uuid_column_test');
it('creates a uuid column as primary using fluid syntax', async function () {
if (!isPgBased(knex)) {
return this.skip();
}
const table_name = 'uuid_column_test';
const expected_column = 'id';
const expected_type = 'uuid';

await knex.schema.dropTableIfExists(table_name);
await knex.schema.createTable(table_name, (table) => {
table.uuid('id').primary();
});

const cols = await knex.raw(
`select c.column_name, c.data_type
from INFORMATION_SCHEMA.COLUMNS c
join INFORMATION_SCHEMA.KEY_COLUMN_USAGE cu
on (c.table_name = cu.table_name and c.column_name = cu.column_name)
where c.table_name = ?
and (cu.constraint_name like '%_pkey' or cu.constraint_name = 'primary')`,
table_name
);
const column_name = cols.rows[0].column_name;
const column_type = cols.rows[0].data_type;

expect(column_name).to.equal(expected_column);
expect(column_type).to.equal(expected_type);
});

it('#5211 - creates an uuid column as primary key', async function () {
if (!isPgBased(knex)) {
return this.skip();
}

const table_name = 'uuid_column_test';
const expected_column = 'id';
const expected_type = 'uuid';

await knex.schema.dropTableIfExists(table_name);
await knex.schema.createTable(table_name, (table) => {
table.uuid('id', { primaryKey: true });
});

const cols = await knex.raw(
`select c.column_name, c.data_type
from INFORMATION_SCHEMA.COLUMNS c
Expand Down Expand Up @@ -862,8 +891,7 @@ describe('Schema (misc)', () => {
tester(
['pg', 'cockroachdb'],
[
'create table "test_table_three" ("main" integer not null, "paragraph" text default \'Lorem ipsum Qui quis qui in.\', "metadata" json default \'{"a":10}\', "details" jsonb default \'{"b":{"d":20}}\')',
'alter table "test_table_three" add constraint "test_table_three_pkey" primary key ("main")',
'create table "test_table_three" ("main" integer not null, "paragraph" text default \'Lorem ipsum Qui quis qui in.\', "metadata" json default \'{"a":10}\', "details" jsonb default \'{"b":{"d":20}}\', constraint "test_table_three_pkey" primary key ("main"))',
]
);
tester('pg-redshift', [
Expand Down
99 changes: 87 additions & 12 deletions test/unit/schema-builder/postgres.js
Expand Up @@ -150,6 +150,20 @@ describe('PostgreSQL SchemaBuilder', function () {
);
});

it('should create a table with inline uuid primary key creation', function () {
tableSql = client
.schemaBuilder()
.createTable('uuids', function (table) {
table.uuid('id').primary();
})
.toSQL();

equal(1, tableSql.length);
expect(tableSql[0].sql).to.equal(
'create table "uuids" ("id" uuid, constraint "uuids_pkey" primary key ("id"))'
);
});

it('basic alter table', function () {
tableSql = client
.schemaBuilder()
Expand Down Expand Up @@ -547,6 +561,19 @@ describe('PostgreSQL SchemaBuilder', function () {
);
});

it('drop primary takes constraint name', function () {
tableSql = client
.schemaBuilder()
.table('users', function (table) {
table.dropPrimary('testconstraintname');
})
.toSQL();
equal(1, tableSql.length);
expect(tableSql[0].sql).to.equal(
'alter table "users" drop constraint "testconstraintname"'
);
});

it('drop unique', function () {
tableSql = client
.schemaBuilder()
Expand Down Expand Up @@ -688,9 +715,9 @@ describe('PostgreSQL SchemaBuilder', function () {
});
})
.toSQL();
equal(2, tableSql.length);
expect(tableSql[1].sql).to.equal(
'alter table "person" add constraint "user_id_primary" primary key ("user_id") deferrable initially immediate'
equal(1, tableSql.length);
expect(tableSql[0].sql).to.equal(
'create table "person" ("user_id" integer, constraint "user_id_primary" primary key ("user_id") deferrable initially immediate)'
);
});

Expand Down Expand Up @@ -733,12 +760,9 @@ describe('PostgreSQL SchemaBuilder', function () {
table.string('name').primary();
})
.toSQL();
equal(2, tableSql.length);
equal(1, tableSql.length);
expect(tableSql[0].sql).to.equal(
'create table "users" ("name" varchar(255))'
);
expect(tableSql[1].sql).to.equal(
'alter table "users" add constraint "users_pkey" primary key ("name")'
'create table "users" ("name" varchar(255), constraint "users_pkey" primary key ("name"))'
);
});

Expand Down Expand Up @@ -1992,12 +2016,15 @@ describe('PostgreSQL SchemaBuilder', function () {
it('#1430 - .primary & .dropPrimary takes columns and constraintName', function () {
tableSql = client
.schemaBuilder()
.table('users', function (t) {
.createTable('users', function (t) {
t.string('test1');
t.string('test2');
t.primary(['test1', 'test2'], 'testconstraintname');
})
.toSQL();
equal(1, tableSql.length);
expect(tableSql[0].sql).to.equal(
'alter table "users" add constraint "testconstraintname" primary key ("test1", "test2")'
'create table "users" ("test1" varchar(255), "test2" varchar(255), constraint "testconstraintname" primary key ("test1", "test2"))'
);

tableSql = client
Expand All @@ -2007,11 +2034,59 @@ describe('PostgreSQL SchemaBuilder', function () {
})
.toSQL();

expect(tableSql[1].sql).to.equal(
'alter table "users" add constraint "testconstraintname" primary key ("test")'
expect(tableSql[0].sql).to.equal(
'create table "users" ("test" varchar(255), constraint "testconstraintname" primary key ("test"))'
);
});

describe('alter with primary', function () {
it('liquid argument', function () {
tableSql = client
.schemaBuilder()
.alterTable('users', function (t) {
t.string('test').primary();
})
.toSQL();

equal(2, tableSql.length);
expect(tableSql[0].sql).to.equal(
'alter table "users" add column "test" varchar(255)'
);
expect(tableSql[1].sql).to.equal(
'alter table "users" add constraint "users_pkey" primary key ("test")'
);
});
it('liquid argument with name', function () {
tableSql = client
.schemaBuilder()
.alterTable('users', function (t) {
t.string('test').primary('testname');
})
.toSQL();

equal(2, tableSql.length);
expect(tableSql[0].sql).to.equal(
'alter table "users" add column "test" varchar(255)'
);
expect(tableSql[1].sql).to.equal(
'alter table "users" add constraint "testname" primary key ("test")'
);
});
it('call on table with columns and name', function () {
tableSql = client
.schemaBuilder()
.alterTable('users', function (t) {
t.primary(['test1', 'test2'], 'testconstraintname');
})
.toSQL();

equal(1, tableSql.length);
expect(tableSql[0].sql).to.equal(
'alter table "users" add constraint "testconstraintname" primary key ("test1", "test2")'
);
});
});

describe('queryContext', function () {
let spy;
let originalWrapIdentifier;
Expand Down

0 comments on commit 8b0dd49

Please sign in to comment.