mirror of
https://github.com/knex/knex.git
synced 2025-12-27 15:08:47 +00:00
mssql: Support table.primary, table.unique variant with options object (#4710)
This commit is contained in:
parent
126b84639e
commit
99e6726df9
@ -4,6 +4,7 @@
|
||||
// -------
|
||||
const TableCompiler = require('../../../schema/tablecompiler');
|
||||
const helpers = require('../../../util/helpers');
|
||||
const { isObject } = require('../../../util/is');
|
||||
|
||||
// Table Compiler
|
||||
// ------
|
||||
@ -223,7 +224,22 @@ class TableCompiler_MSSQL extends TableCompiler {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a primary key.
|
||||
*
|
||||
* @param {undefined | string | string[]} columns
|
||||
* @param {string | {constraintName: string, deferrable?: 'not deferrable'|'deferred'|'immediate' }} constraintName
|
||||
*/
|
||||
primary(columns, constraintName) {
|
||||
let deferrable;
|
||||
if (isObject(constraintName)) {
|
||||
({ constraintName, deferrable } = constraintName);
|
||||
}
|
||||
if (deferrable && deferrable !== 'not deferrable') {
|
||||
this.client.logger.warn(
|
||||
`mssql: primary key constraint [${constraintName}] will not be deferrable ${deferrable} because mssql does not support deferred constraints.`
|
||||
);
|
||||
}
|
||||
constraintName = constraintName
|
||||
? this.formatter.wrap(constraintName)
|
||||
: this.formatter.wrap(`${this.tableNameRaw}_pkey`);
|
||||
@ -242,7 +258,23 @@ class TableCompiler_MSSQL extends TableCompiler {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a unique index.
|
||||
*
|
||||
* @param {string | string[]} columns
|
||||
* @param {string | {indexName: undefined | string, deferrable?: 'not deferrable'|'deferred'|'immediate' }} indexName
|
||||
*/
|
||||
unique(columns, indexName) {
|
||||
/** @type {string | undefined} */
|
||||
let deferrable;
|
||||
if (isObject(indexName)) {
|
||||
({ indexName, deferrable } = indexName);
|
||||
}
|
||||
if (deferrable && deferrable !== 'not deferrable') {
|
||||
this.client.logger.warn(
|
||||
`mssql: unique index [${indexName}] will not be deferrable ${deferrable} because mssql does not support deferred constraints.`
|
||||
);
|
||||
}
|
||||
indexName = indexName
|
||||
? this.formatter.wrap(indexName)
|
||||
: this._indexCommand('unique', this.tableNameRaw, columns);
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
// MySQL Table Builder & Compiler
|
||||
// -------
|
||||
const TableCompiler = require('../../../schema/tablecompiler');
|
||||
const { isObject } = require('../../../util/is');
|
||||
|
||||
// Table Compiler
|
||||
// ------
|
||||
@ -218,6 +219,15 @@ class TableCompiler_MySQL extends TableCompiler {
|
||||
}
|
||||
|
||||
primary(columns, constraintName) {
|
||||
let deferrable;
|
||||
if (isObject(constraintName)) {
|
||||
({ constraintName, deferrable } = constraintName);
|
||||
}
|
||||
if (deferrable && deferrable !== 'not deferrable') {
|
||||
this.client.logger.warn(
|
||||
`mysql: primary key constraint \`${constraintName}\` will not be deferrable ${deferrable} because mysql does not support deferred constraints.`
|
||||
);
|
||||
}
|
||||
constraintName = constraintName
|
||||
? this.formatter.wrap(constraintName)
|
||||
: this.formatter.wrap(`${this.tableNameRaw}_pkey`);
|
||||
@ -229,6 +239,15 @@ class TableCompiler_MySQL extends TableCompiler {
|
||||
}
|
||||
|
||||
unique(columns, indexName) {
|
||||
let deferrable;
|
||||
if (isObject(indexName)) {
|
||||
({ indexName, deferrable } = indexName);
|
||||
}
|
||||
if (deferrable && deferrable !== 'not deferrable') {
|
||||
this.client.logger.warn(
|
||||
`mysql: unique index \`${indexName}\` will not be deferrable ${deferrable} because mysql does not support deferred constraints.`
|
||||
);
|
||||
}
|
||||
indexName = indexName
|
||||
? this.formatter.wrap(indexName)
|
||||
: this._indexCommand('unique', this.tableNameRaw, columns);
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
const filter = require('lodash/filter');
|
||||
const values = require('lodash/values');
|
||||
const identity = require('lodash/identity');
|
||||
const { isObject } = require('../../../util/is');
|
||||
|
||||
const TableCompiler = require('../../../schema/tablecompiler');
|
||||
const { formatDefault } = require('../../../formatter/formatterUtils');
|
||||
@ -122,6 +123,15 @@ class TableCompiler_SQLite3 extends TableCompiler {
|
||||
|
||||
// Compile a unique key command.
|
||||
unique(columns, indexName) {
|
||||
let deferrable;
|
||||
if (isObject(indexName)) {
|
||||
({ indexName, deferrable } = indexName);
|
||||
}
|
||||
if (deferrable && deferrable !== 'not deferrable') {
|
||||
this.client.logger.warn(
|
||||
`sqlite3: unique index \`${indexName}\` will not be deferrable ${deferrable} because sqlite3 does not support deferred constraints.`
|
||||
);
|
||||
}
|
||||
indexName = indexName
|
||||
? this.formatter.wrap(indexName)
|
||||
: this._indexCommand('unique', this.tableNameRaw, columns);
|
||||
@ -158,6 +168,16 @@ class TableCompiler_SQLite3 extends TableCompiler {
|
||||
columns = columns.map((column) =>
|
||||
this.client.customWrapIdentifier(column, identity)
|
||||
);
|
||||
|
||||
let deferrable;
|
||||
if (isObject(constraintName)) {
|
||||
({ constraintName, deferrable } = constraintName);
|
||||
}
|
||||
if (deferrable && deferrable !== 'not deferrable') {
|
||||
this.client.logger.warn(
|
||||
`sqlite3: primary key constraint \`${constraintName}\` will not be deferrable ${deferrable} because sqlite3 does not support deferred constraints.`
|
||||
);
|
||||
}
|
||||
constraintName = this.client.customWrapIdentifier(constraintName, identity);
|
||||
|
||||
if (this.method !== 'create' && this.method !== 'createIfNot') {
|
||||
|
||||
@ -170,6 +170,35 @@ describe('MSSQL dialect', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('unique table constraint with options object', () => {
|
||||
const tableName = 'test_unique_index_options';
|
||||
before(async () => {
|
||||
await knex.schema.createTable(tableName, function () {
|
||||
this.integer('x').notNull();
|
||||
this.integer('y').notNull();
|
||||
});
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await knex.schema.dropTable(tableName);
|
||||
});
|
||||
|
||||
it('accepts indexName in options object', async () => {
|
||||
const indexName = `AK_${tableName}_x_y`;
|
||||
await knex.schema.alterTable(tableName, function () {
|
||||
this.unique(['x', 'y'], { indexName });
|
||||
});
|
||||
expect(
|
||||
knex
|
||||
.insert([
|
||||
{ x: 1, y: 1 },
|
||||
{ x: 1, y: 1 },
|
||||
])
|
||||
.into(tableName)
|
||||
).to.eventually.be.rejectedWith(new RegExp(indexName));
|
||||
});
|
||||
});
|
||||
|
||||
describe('comment support', () => {
|
||||
const schemaName = 'dbo';
|
||||
const tableName = 'test_attaches_comments';
|
||||
|
||||
@ -15,9 +15,6 @@ describe('Schema', () => {
|
||||
|
||||
before(function () {
|
||||
knex = getKnexForDb(db);
|
||||
if (isMssql(knex)) {
|
||||
return this.skip();
|
||||
}
|
||||
});
|
||||
|
||||
after(() => {
|
||||
@ -100,8 +97,8 @@ describe('Schema', () => {
|
||||
|
||||
it('creates a compound primary key', async () => {
|
||||
await knex.schema.alterTable('primary_table', (table) => {
|
||||
// CockroachDB does not support nullable primary keys
|
||||
if (isCockroachDB(knex)) {
|
||||
// CockroachDB and mssql do not support nullable primary keys
|
||||
if (isCockroachDB(knex) || isMssql(knex)) {
|
||||
table.dropNullable('id_two');
|
||||
table.dropNullable('id_three');
|
||||
}
|
||||
@ -128,49 +125,54 @@ describe('Schema', () => {
|
||||
}
|
||||
});
|
||||
|
||||
it('creates a compound primary key with a custom constraint name', async function () {
|
||||
// CockroachDB currently does not support dropping primary key without creating new one in the same transaction
|
||||
if (isCockroachDB(knex)) {
|
||||
return this.skip();
|
||||
}
|
||||
|
||||
await knex.schema.alterTable('primary_table', (table) => {
|
||||
// CockroachDB does not support nullable primary keys
|
||||
if (isCockroachDB()) {
|
||||
table.dropNullable('id_two');
|
||||
table.dropNullable('id_three');
|
||||
for (const [flavor, customConstraintName] of [
|
||||
['provided directly as a string', 'my_custom_constraint_name'],
|
||||
[
|
||||
'provided in the options object',
|
||||
{ constraintName: 'my_custom_constraint_name' },
|
||||
],
|
||||
]) {
|
||||
it(`creates a compound primary key with a custom constraint name ${flavor}`, async function () {
|
||||
// As of 2021-10-02, CockroachDB does not support dropping a primary key without creating a new one in the same transaction.
|
||||
if (isCockroachDB(knex)) {
|
||||
return this.skip();
|
||||
}
|
||||
table.primary(
|
||||
['id_two', 'id_three'],
|
||||
'my_custom_constraint_name'
|
||||
);
|
||||
});
|
||||
|
||||
await knex('primary_table').insert({ id_two: 1, id_three: 1 });
|
||||
await knex('primary_table').insert({ id_two: 2, id_three: 1 });
|
||||
await knex('primary_table').insert({ id_two: 1, id_three: 2 });
|
||||
await knex.schema.alterTable('primary_table', (table) => {
|
||||
// CockroachDB and mssql do not support nullable primary keys
|
||||
if (isCockroachDB(knex) || isMssql(knex)) {
|
||||
table.dropNullable('id_two');
|
||||
table.dropNullable('id_three');
|
||||
}
|
||||
table.primary(['id_two', 'id_three'], customConstraintName);
|
||||
});
|
||||
|
||||
try {
|
||||
await knex('primary_table').insert({ id_two: 1, id_three: 1 });
|
||||
} catch (err) {
|
||||
if (isSQLite(knex)) {
|
||||
expect(err.message).to.equal(
|
||||
'insert into `primary_table` (`id_three`, `id_two`) values (1, 1) - SQLITE_CONSTRAINT: UNIQUE constraint failed: primary_table.id_two, primary_table.id_three'
|
||||
);
|
||||
}
|
||||
if (isPgBased(knex)) {
|
||||
expect(err.message).to.equal(
|
||||
'insert into "primary_table" ("id_three", "id_two") values ($1, $2) - duplicate key value violates unique constraint "my_custom_constraint_name"'
|
||||
);
|
||||
}
|
||||
}
|
||||
await knex('primary_table').insert({ id_two: 2, id_three: 1 });
|
||||
await knex('primary_table').insert({ id_two: 1, id_three: 2 });
|
||||
|
||||
await knex.schema.alterTable('primary_table', (table) => {
|
||||
table.dropPrimary('my_custom_constraint_name');
|
||||
try {
|
||||
await knex('primary_table').insert({ id_two: 1, id_three: 1 });
|
||||
} catch (err) {
|
||||
if (isSQLite(knex)) {
|
||||
expect(err.message).to.equal(
|
||||
'insert into `primary_table` (`id_three`, `id_two`) values (1, 1) - SQLITE_CONSTRAINT: UNIQUE constraint failed: primary_table.id_two, primary_table.id_three'
|
||||
);
|
||||
}
|
||||
if (isPgBased(knex)) {
|
||||
expect(err.message).to.equal(
|
||||
'insert into "primary_table" ("id_three", "id_two") values ($1, $2) - duplicate key value violates unique constraint "my_custom_constraint_name"'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
await knex.schema.alterTable('primary_table', (table) => {
|
||||
table.dropPrimary('my_custom_constraint_name');
|
||||
});
|
||||
|
||||
await knex('primary_table').insert({ id_two: 1, id_three: 1 });
|
||||
});
|
||||
|
||||
await knex('primary_table').insert({ id_two: 1, id_three: 1 });
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user