Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add binary uuid option #1778 #4836

Merged
merged 3 commits into from Dec 7, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 3 additions & 1 deletion lib/dialects/mssql/schema/mssql-columncompiler.js
Expand Up @@ -143,7 +143,9 @@ ColumnCompiler_MSSQL.prototype.json = 'nvarchar(max)';
// TODO: mssql supports check constraints as of SQL Server 2008
// so make enu here more like postgres
ColumnCompiler_MSSQL.prototype.enu = 'nvarchar(100)';
ColumnCompiler_MSSQL.prototype.uuid = 'uniqueidentifier';
ColumnCompiler_MSSQL.prototype.uuid = ({ useBinaryUuid = false } = {}) =>
useBinaryUuid ? 'binary(16)' : 'uniqueidentifier';

ColumnCompiler_MSSQL.prototype.datetime = 'datetime2';
ColumnCompiler_MSSQL.prototype.bool = 'bit';

Expand Down
3 changes: 2 additions & 1 deletion lib/dialects/redshift/schema/redshift-columncompiler.js
Expand Up @@ -2,6 +2,7 @@
// -------

const ColumnCompiler_PG = require('../../postgres/schema/pg-columncompiler');
const ColumnCompiler = require('../../../schema/columncompiler');

class ColumnCompiler_Redshift extends ColumnCompiler_PG {
constructor() {
Expand Down Expand Up @@ -54,7 +55,7 @@ ColumnCompiler_Redshift.prototype.mediumblob = 'varchar(16777218)';
ColumnCompiler_Redshift.prototype.set = 'text';
ColumnCompiler_Redshift.prototype.text = 'varchar(max)';
ColumnCompiler_Redshift.prototype.tinyblob = 'varchar(256)';
ColumnCompiler_Redshift.prototype.uuid = 'char(36)';
ColumnCompiler_Redshift.prototype.uuid = ColumnCompiler.prototype.uuid;
ColumnCompiler_Redshift.prototype.varbinary = 'varchar(max)';
ColumnCompiler_Redshift.prototype.bigint = 'bigint';
ColumnCompiler_Redshift.prototype.bool = 'boolean';
Expand Down
21 changes: 21 additions & 0 deletions lib/knex-builder/FunctionHelper.js
Expand Up @@ -13,6 +13,27 @@ class FunctionHelper {
}
return this.client.raw('CURRENT_TIMESTAMP');
}

uuidToBin(uuid) {
const buf = Buffer.from(uuid.replace(/-/g, ''), 'hex');
return Buffer.concat([
buf.slice(6, 8),
buf.slice(4, 6),
buf.slice(0, 4),
buf.slice(8, 16),
]);
}

binToUuid(bin) {
const buf = new Buffer(bin, 'hex');
return [
buf.toString('hex', 4, 8),
buf.toString('hex', 2, 4),
buf.toString('hex', 0, 2),
buf.toString('hex', 8, 10),
buf.toString('hex', 10, 16),
].join('-');
}
}

module.exports = FunctionHelper;
3 changes: 2 additions & 1 deletion lib/schema/columncompiler.js
Expand Up @@ -147,7 +147,8 @@ ColumnCompiler.prototype.geography = 'geography';
ColumnCompiler.prototype.point = 'point';
ColumnCompiler.prototype.enu = 'varchar';
ColumnCompiler.prototype.bit = ColumnCompiler.prototype.json = 'text';
ColumnCompiler.prototype.uuid = 'char(36)';
ColumnCompiler.prototype.uuid = ({ useBinaryUuid = false } = {}) =>
useBinaryUuid ? 'binary(16)' : 'char(36)';
ColumnCompiler.prototype.increments = ({ primaryKey = true } = {}) =>
'integer not null' + (primaryKey ? ' primary key' : '') + ' autoincrement';
ColumnCompiler.prototype.bigincrements = ({ primaryKey = true } = {}) =>
Expand Down
3 changes: 3 additions & 0 deletions package.json
Expand Up @@ -180,6 +180,9 @@
{
"name": "Brian Lauber",
"web": "https://briandamaged.org"
},
{
"name": "Olivier Cavadenti"
}
],
"browser": {
Expand Down
37 changes: 37 additions & 0 deletions test/integration2/query/misc/additional.spec.js
Expand Up @@ -375,6 +375,43 @@ describe('Additional', function () {
expect(knex.fn.now(6).toQuery()).to.equal('CURRENT_TIMESTAMP(6)');
});

it('should allow using .fn-methods to convert uuid to binary', function () {
const originalUuid = '6c825dc9-c98f-37ab-b01b-416294811a84';
const binary = knex.fn.uuidToBin(originalUuid);
const uuid = knex.fn.binToUuid(binary);
expect(uuid).to.equal(originalUuid);
});

it('should insert binary uuid and retreive it', async () => {
await knex.schema.dropTableIfExists('uuid_table');
await knex.schema.createTable('uuid_table', (t) => {
t.uuid('uuid_col_binary', { useBinaryUuid: true });
});
const originalUuid = '3f06af63-a93c-11e4-9797-00505690773f';

let uuidToInsert;

if (isPostgreSQL(knex) || isCockroachDB(knex)) {
uuidToInsert = originalUuid;
} else {
uuidToInsert = knex.fn.uuidToBin(originalUuid);
}

await knex('uuid_table').insert({
uuid_col_binary: uuidToInsert,
});
const uuid = await knex('uuid_table').select('uuid_col_binary');

let expectedUuid;
if (isPostgreSQL(knex) || isCockroachDB(knex)) {
expectedUuid = uuid[0].uuid_col_binary;
} else {
expectedUuid = knex.fn.binToUuid(uuid[0].uuid_col_binary);
}

expect(expectedUuid).to.equal(originalUuid);
});

it('#2184 - should properly escape table name for SQLite columnInfo', function () {
if (!isSQLite(knex)) {
return this.skip();
Expand Down
26 changes: 26 additions & 0 deletions test/unit/schema-builder/mssql.js
Expand Up @@ -1167,6 +1167,32 @@ describe('MSSQL SchemaBuilder', function () {
);
});

it('adding uuid', function () {
tableSql = client
.schemaBuilder()
.table('users', function (table) {
table.uuid('foo');
})
.toSQL();

expect(tableSql.length).to.equal(1);
expect(tableSql[0].sql).to.equal(
'ALTER TABLE [users] ADD [foo] uniqueidentifier'
);
});

it('adding binary uuid', function () {
tableSql = client
.schemaBuilder()
.table('users', function (table) {
table.uuid('foo', { useBinaryUuid: true });
})
.toSQL();

equal(1, tableSql.length);
equal(tableSql[0].sql, 'ALTER TABLE [users] ADD [foo] binary(16)');
});

it('is possible to set raw statements in defaultTo, #146', function () {
tableSql = client
.schemaBuilder()
Expand Down
28 changes: 28 additions & 0 deletions test/unit/schema-builder/mysql.js
Expand Up @@ -1115,6 +1115,34 @@ module.exports = function (dialect) {
);
});

it('adding uuid', function () {
tableSql = client
.schemaBuilder()
.table('users', function (table) {
table.uuid('foo');
})
.toSQL();

expect(tableSql.length).to.equal(1);
expect(tableSql[0].sql).to.equal(
'alter table `users` add `foo` char(36)'
);
});

it('adding binary uuid', function () {
tableSql = client
.schemaBuilder()
.table('users', function (table) {
table.uuid('foo', { useBinaryUuid: true });
})
.toSQL();

expect(tableSql.length).to.equal(1);
expect(tableSql[0].sql).to.equal(
'alter table `users` add `foo` binary(16)'
);
});

it('test set comment', function () {
tableSql = client
.schemaBuilder()
Expand Down
26 changes: 26 additions & 0 deletions test/unit/schema-builder/oracledb.js
Expand Up @@ -1011,6 +1011,32 @@ describe('OracleDb SchemaBuilder', function () {
);
});

it('adding uuid', function () {
tableSql = client
.schemaBuilder()
.table('users', function (table) {
table.uuid('foo');
})
.toSQL();

expect(tableSql.length).to.equal(1);
expect(tableSql[0].sql).to.equal('alter table "users" add "foo" char(36)');
});

it('adding binary uuid', function () {
tableSql = client
.schemaBuilder()
.table('users', function (table) {
table.uuid('foo', { useBinaryUuid: true });
})
.toSQL();

expect(tableSql.length).to.equal(1);
expect(tableSql[0].sql).to.equal(
'alter table "users" add "foo" binary(16)'
);
});

it('test set comment', function () {
tableSql = client
.schemaBuilder()
Expand Down
28 changes: 28 additions & 0 deletions test/unit/schema-builder/postgres.js
Expand Up @@ -1671,6 +1671,34 @@ describe('PostgreSQL SchemaBuilder', function () {
);
});

it('adding uuid', function () {
tableSql = client
.schemaBuilder()
.table('users', function (table) {
table.uuid('foo');
})
.toSQL();

expect(tableSql.length).to.equal(1);
expect(tableSql[0].sql).to.equal(
'alter table "users" add column "foo" uuid'
);
});

it('adding binary uuid', function () {
tableSql = client
.schemaBuilder()
.table('users', function (table) {
table.uuid('foo', { useBinaryUuid: true });
})
.toSQL();

expect(tableSql.length).to.equal(1);
expect(tableSql[0].sql).to.equal(
'alter table "users" add column "foo" uuid'
);
});

it('set comment', function () {
tableSql = client
.schemaBuilder()
Expand Down
28 changes: 28 additions & 0 deletions test/unit/schema-builder/redshift.js
Expand Up @@ -850,6 +850,34 @@ describe('Redshift SchemaBuilder', function () {
);
});

it('adding uuid', function () {
tableSql = client
.schemaBuilder()
.table('users', function (table) {
table.uuid('foo');
})
.toSQL();

expect(tableSql.length).to.equal(1);
expect(tableSql[0].sql).to.equal(
'alter table "users" add column "foo" char(36)'
);
});

it('adding binary uuid', function () {
tableSql = client
.schemaBuilder()
.table('users', function (table) {
table.uuid('foo', { useBinaryUuid: true });
})
.toSQL();

expect(tableSql.length).to.equal(1);
expect(tableSql[0].sql).to.equal(
'alter table "users" add column "foo" binary(16)'
);
});

it('allows adding default json objects when the column is json', function () {
tableSql = client
.schemaBuilder()
Expand Down
28 changes: 28 additions & 0 deletions test/unit/schema-builder/sqlite3.js
Expand Up @@ -894,6 +894,34 @@ describe('SQLite SchemaBuilder', function () {
equal(tableSql[0].sql, 'alter table `users` add column `foo` blob');
});

it('adding uuid', function () {
tableSql = client
.schemaBuilder()
.table('users', function (table) {
table.uuid('foo');
})
.toSQL();

expect(tableSql.length).to.equal(1);
expect(tableSql[0].sql).to.equal(
'alter table `users` add column `foo` char(36)'
);
});

it('adding binary uuid', function () {
tableSql = client
.schemaBuilder()
.table('users', function (table) {
table.uuid('foo', { useBinaryUuid: true });
})
.toSQL();

expect(tableSql.length).to.equal(1);
expect(tableSql[0].sql).to.equal(
'alter table `users` add column `foo` binary(16)'
);
});

it('allows for on delete cascade with foreign keys, #166', function () {
tableSql = client
.schemaBuilder()
Expand Down
2 changes: 1 addition & 1 deletion types/index.d.ts
Expand Up @@ -2049,7 +2049,7 @@ export declare namespace Knex {
): ColumnBuilder;
json(columnName: string): ColumnBuilder;
jsonb(columnName: string): ColumnBuilder;
uuid(columnName: string): ColumnBuilder;
uuid(columnName: string, options?: Readonly<{useBinaryUuid?: boolean}>): ColumnBuilder;
comment(val: string): void;
specificType(columnName: string, type: string): ColumnBuilder;
primary(columnNames: readonly string[], options?: Readonly<{constraintName?: string, deferrable?: deferrableType}>): TableBuilder;
Expand Down