Skip to content

Commit

Permalink
Merge 80045e1 into aedba5e
Browse files Browse the repository at this point in the history
  • Loading branch information
langovoi committed Apr 6, 2024
2 parents aedba5e + 80045e1 commit 671ed73
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 4 deletions.
4 changes: 2 additions & 2 deletions docs/src/guide/schema-builder.md
Original file line number Diff line number Diff line change
Expand Up @@ -747,9 +747,9 @@ If you want to chain primary() while creating new column you can use [primary](#

### unique

**table.unique(columns, options={[indexName: string], [deferrable:'not deferrable'|'immediate'|'deferred'], [storageEngineIndexType:'btree'|'hash'], [useConstraint:true|false], [predicate: QueryBuilder]})**
**table.unique(columns, options={[indexName: string], [deferrable:'not deferrable'|'immediate'|'deferred'], [storageEngineIndexType:'btree'|'hash'], [useConstraint:true|false], [predicate: QueryBuilder], [nullsNotDistinct: true|false]})**

Adds an unique index to a table over the given `columns`. In MySQL, the storage engine index type may be 'btree' or 'hash' index types, more info in Index Options section : [https://dev.mysql.com/doc/refman/8.0/en/create-index.html](https://dev.mysql.com/doc/refman/8.0/en/create-index.html). A default index name using the columns is used unless indexName is specified. If you need to create a composite index, pass an array of column to `columns`. Deferrable unique constraint are supported on Postgres and Oracle and can be set by passing deferrable option to options object. In MSSQL and Postgres, you can set the `useConstraint` option to true to create a unique constraint instead of a unique index (defaults to false for MSSQL, true for Postgres without `predicate`, false for Postgres with `predicate`). In PostgreSQL, SQLite and MSSQL a partial unique index can be specified by setting a 'where' predicate.
Adds an unique index to a table over the given `columns`. In MySQL, the storage engine index type may be 'btree' or 'hash' index types, more info in Index Options section : [https://dev.mysql.com/doc/refman/8.0/en/create-index.html](https://dev.mysql.com/doc/refman/8.0/en/create-index.html). A default index name using the columns is used unless indexName is specified. If you need to create a composite index, pass an array of column to `columns`. Deferrable unique constraint are supported on Postgres and Oracle and can be set by passing deferrable option to options object. In MSSQL and Postgres, you can set the `useConstraint` option to true to create a unique constraint instead of a unique index (defaults to false for MSSQL, true for Postgres without `predicate`, false for Postgres with `predicate`). In PostgreSQL, SQLite and MSSQL a partial unique index can be specified by setting a 'where' predicate. In Postgres 15+ specifying `nullsNotDistinct: true` on unique index will cause `NULL` to be treated as not distinct, or in other words, equivalently.

```js
knex.schema.alterTable('users', function (t) {
Expand Down
11 changes: 9 additions & 2 deletions lib/dialects/postgres/schema/pg-tablecompiler.js
Original file line number Diff line number Diff line change
Expand Up @@ -191,8 +191,9 @@ class TableCompiler_PG extends TableCompiler {
let deferrable;
let useConstraint = true;
let predicate;
let nullsNotDistinct;
if (isObject(indexName)) {
({ indexName, deferrable, useConstraint, predicate } = indexName);
({ indexName, deferrable, useConstraint, predicate, nullsNotDistinct } = indexName);
if (useConstraint === undefined) {
useConstraint = !!deferrable || !predicate;
}
Expand All @@ -204,6 +205,11 @@ class TableCompiler_PG extends TableCompiler {
throw new Error('postgres cannot create constraint with predicate');
}
deferrable = deferrable ? ` deferrable initially ${deferrable}` : '';
if(nullsNotDistinct !== undefined) {
nullsNotDistinct = nullsNotDistinct ? ' nulls not distinct' : ' nulls distinct';
} else {
nullsNotDistinct = '';
}
indexName = indexName
? this.formatter.wrap(indexName)
: this._indexCommand('unique', this.tableNameRaw, columns);
Expand All @@ -214,6 +220,7 @@ class TableCompiler_PG extends TableCompiler {
' unique (' +
this.formatter.columnize(columns) +
')' +
nullsNotDistinct +
deferrable
);
} else {
Expand All @@ -224,7 +231,7 @@ class TableCompiler_PG extends TableCompiler {
this.pushQuery(
`create unique index ${indexName} on ${this.tableName()} (${this.formatter.columnize(
columns
)})${predicateQuery}`
)})${nullsNotDistinct}${predicateQuery}`
);
}
}
Expand Down
64 changes: 64 additions & 0 deletions test/unit/schema-builder/postgres.js
Original file line number Diff line number Diff line change
Expand Up @@ -740,6 +740,36 @@ describe('PostgreSQL SchemaBuilder', function () {
);
});

it('adds unique constraint with nulls not distinct', function () {
tableSql = client
.schemaBuilder()
.createTable('person', function (table) {
table
.integer('user_id')
.unique({ indexName: 'user_id_index', nullsNotDistinct: true });
})
.toSQL();
equal(2, tableSql.length);
expect(tableSql[1].sql).to.equal(
'alter table "person" add constraint "user_id_index" unique ("user_id") nulls not distinct'
);
});

it('adds unique constraint with nulls distinct', function () {
tableSql = client
.schemaBuilder()
.createTable('person', function (table) {
table
.integer('user_id')
.unique({ indexName: 'user_id_index', nullsNotDistinct: false });
})
.toSQL();
equal(2, tableSql.length);
expect(tableSql[1].sql).to.equal(
'alter table "person" add constraint "user_id_index" unique ("user_id") nulls distinct'
);
});

it('adds primary constraint with deferrable initially immediate', function () {
tableSql = client
.schemaBuilder()
Expand Down Expand Up @@ -1079,6 +1109,40 @@ describe('PostgreSQL SchemaBuilder', function () {
);
});

it('adding unique index with nulls not distinct', function () {
tableSql = client
.schemaBuilder()
.table('users', function (table) {
table.unique('foo', {
indexName: 'bar',
useConstraint: false,
nullsNotDistinct: true,
});
})
.toSQL();
equal(1, tableSql.length);
expect(tableSql[0].sql).to.equal(
'create unique index "bar" on "users" ("foo") nulls not distinct'
);
});

it('adding unique index with nulls distinct', function () {
tableSql = client
.schemaBuilder()
.table('users', function (table) {
table.unique('foo', {
indexName: 'bar',
useConstraint: false,
nullsNotDistinct: false,
});
})
.toSQL();
equal(1, tableSql.length);
expect(tableSql[0].sql).to.equal(
'create unique index "bar" on "users" ("foo") nulls distinct'
);
});

it('adding unique index with a predicate', function () {
tableSql = client
.schemaBuilder()
Expand Down
1 change: 1 addition & 0 deletions types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2543,6 +2543,7 @@ declare namespace Knex {
deferrable?: deferrableType;
useConstraint?: boolean;
predicate?: QueryBuilder;
nullsNotDistinct?: boolean;
}>
): TableBuilder;
/** @deprecated */
Expand Down

0 comments on commit 671ed73

Please sign in to comment.