Skip to content

Commit

Permalink
mssql: schema builder - add predictable constraint names for default …
Browse files Browse the repository at this point in the history
…values (#4319)
  • Loading branch information
dhensby committed Feb 27, 2021
1 parent 5ec76f5 commit c0d8c5c
Show file tree
Hide file tree
Showing 5 changed files with 318 additions and 162 deletions.
17 changes: 17 additions & 0 deletions lib/dialects/mssql/schema/mssql-columncompiler.js
Expand Up @@ -2,6 +2,7 @@
// -------
const ColumnCompiler = require('../../../schema/columncompiler');
const { toNumber } = require('../../../util/helpers');
const { formatDefault } = require('../../../formatter/formatterUtils');

class ColumnCompiler_MSSQL extends ColumnCompiler {
constructor(client, tableCompiler, columnBuilder) {
Expand Down Expand Up @@ -63,6 +64,22 @@ class ColumnCompiler_MSSQL extends ColumnCompiler {
return '';
}

defaultTo(value, { constraintName } = {}) {
const formatedValue = formatDefault(value, this.type, this.client);
constraintName =
typeof constraintName !== 'undefined'
? constraintName
: `${
this.tableCompiler.tableNameRaw
}_${this.getColumnName()}_default`.toLowerCase();
if (!constraintName) {
return `DEFAULT ${formatedValue}`;
}
return `CONSTRAINT ${this.formatter.wrap(
constraintName
)} DEFAULT ${formatedValue}`;
}

comment(comment) {
if (comment && comment.length > 255) {
this.client.logger.warn(
Expand Down
6 changes: 3 additions & 3 deletions test/integration/schema/index.js
Expand Up @@ -473,7 +473,7 @@ module.exports = (knex) => {
'create index "test_table_one_logins_index" on "test_table_one" ("logins")',
]);
tester('mssql', [
"CREATE TABLE [test_table_one] ([id] bigint identity(1,1) not null primary key, [first_name] nvarchar(255), [last_name] nvarchar(255), [email] nvarchar(255) null, [logins] int default '1', [balance] float default '0', [about] nvarchar(max), [created_at] datetime2, [updated_at] datetime2)",
"CREATE TABLE [test_table_one] ([id] bigint identity(1,1) not null primary key, [first_name] nvarchar(255), [last_name] nvarchar(255), [email] nvarchar(255) null, [logins] int CONSTRAINT [test_table_one_logins_default] DEFAULT '1', [balance] float CONSTRAINT [test_table_one_balance_default] DEFAULT '0', [about] nvarchar(max), [created_at] datetime2, [updated_at] datetime2)",
'CREATE INDEX [test_table_one_first_name_index] ON [test_table_one] ([first_name])',
'CREATE UNIQUE INDEX [test_table_one_email_unique] ON [test_table_one] ([email]) WHERE [email] IS NOT NULL',
'CREATE INDEX [test_table_one_logins_index] ON [test_table_one] ([logins])',
Expand Down Expand Up @@ -539,7 +539,7 @@ module.exports = (knex) => {
'alter table "test_table_three" add constraint "test_table_three_pkey" primary key ("main")',
]);
tester('mssql', [
"CREATE TABLE [test_table_three] ([main] int not null, [paragraph] nvarchar(max) default 'Lorem ipsum Qui quis qui in.', [metadata] nvarchar(max) default '{\"a\":10}', CONSTRAINT [test_table_three_pkey] PRIMARY KEY ([main]))",
"CREATE TABLE [test_table_three] ([main] int not null, [paragraph] nvarchar(max) CONSTRAINT [test_table_three_paragraph_default] DEFAULT 'Lorem ipsum Qui quis qui in.', [metadata] nvarchar(max) CONSTRAINT [test_table_three_metadata_default] DEFAULT '{\"a\":10}', CONSTRAINT [test_table_three_pkey] PRIMARY KEY ([main]))",
]);
})
.then(() =>
Expand Down Expand Up @@ -827,7 +827,7 @@ module.exports = (knex) => {
"create table \"bool_test\" (\"one\" number(1, 0) check (\"one\" in ('0', '1')), \"two\" number(1, 0) default '0' check (\"two\" in ('0', '1')), \"three\" number(1, 0) default '1' check (\"three\" in ('0', '1')), \"four\" number(1, 0) default '1' check (\"four\" in ('0', '1')), \"five\" number(1, 0) default '0' check (\"five\" in ('0', '1')))",
]);
tester('mssql', [
"CREATE TABLE [bool_test] ([one] bit, [two] bit default '0', [three] bit default '1', [four] bit default '1', [five] bit default '0')",
"CREATE TABLE [bool_test] ([one] bit, [two] bit CONSTRAINT [bool_test_two_default] DEFAULT '0', [three] bit CONSTRAINT [bool_test_three_default] DEFAULT '1', [four] bit CONSTRAINT [bool_test_four_default] DEFAULT '1', [five] bit CONSTRAINT [bool_test_five_default] DEFAULT '0')",
]);
})
.then(() => knex.insert({ one: false }).into('bool_test')));
Expand Down
85 changes: 85 additions & 0 deletions test/integration2/dialects/mssql.js
@@ -0,0 +1,85 @@
const { expect } = require('chai');
const { getAllDbs, getKnexForDb } = require('../util/knex-instance-provider');

async function fetchDefaultConstraintName(knex, table, column) {
const [result] = await knex.schema.raw(`
SELECT default_constraints.name
FROM sys.all_columns
INNER JOIN sys.tables
ON all_columns.object_id = tables.object_id
INNER JOIN sys.schemas
ON tables.schema_id = schemas.schema_id
INNER JOIN sys.default_constraints
ON all_columns.default_object_id = default_constraints.object_id
WHERE schemas.name = 'dbo'
AND tables.name = '${table}'
AND all_columns.name = '${column}'
`);
return result ? result.name : null;
}

describe('MSSQL dialect', () => {
describe('Connection configuration', () => {
getAllDbs()
.filter((db) => db.startsWith('mssql'))
.forEach((db) => {
describe(db, () => {
let knex;
before(async () => {
knex = getKnexForDb(db);
});

beforeEach(async () => {
await knex.schema.createTable('test', function () {
this.increments('id').primary();
});
});

after(async () => {
await knex.destroy();
});

afterEach(async () => {
await knex.schema.dropTable('test');
});

it('names default constraint', async () => {
await knex.schema.alterTable('test', function () {
this.string('name').defaultTo('knex');
});
const result = await fetchDefaultConstraintName(
knex,
'test',
'name'
);
expect(result).to.equal('test_name_default');
});
it('names default constraint with supplied name', async () => {
const constraintName = 'DF_test_name';
await knex.schema.alterTable('test', function () {
this.string('name').defaultTo('knex', { constraintName });
});
const result = await fetchDefaultConstraintName(
knex,
'test',
'name'
);
expect(result).to.equal('DF_test_name');
});
it("doesn't name default constraint", async () => {
const constraintName = '';
await knex.schema.alterTable('test', function () {
this.string('name').defaultTo('knex', { constraintName });
});
const result = await fetchDefaultConstraintName(
knex,
'test',
'name'
);
// this is the default patten used by mssql if no constraint is defined
expect(result).to.match(/^DF__test__name__[0-9A-Z]+$/);
});
});
});
});
});

0 comments on commit c0d8c5c

Please sign in to comment.