Skip to content

Commit

Permalink
Add binary uuid option (#4836)
Browse files Browse the repository at this point in the history
  • Loading branch information
OlivierCavadenti committed Dec 7, 2021
1 parent 84bc2d9 commit d813edf
Show file tree
Hide file tree
Showing 13 changed files with 233 additions and 4 deletions.
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 @@ -2052,7 +2052,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

0 comments on commit d813edf

Please sign in to comment.