Skip to content

Commit

Permalink
Implement mapBinding mssql dialect option (#5292)
Browse files Browse the repository at this point in the history
  • Loading branch information
kellyrbourg committed Aug 31, 2022
1 parent 29283a1 commit e0c0fa9
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 14 deletions.
34 changes: 20 additions & 14 deletions lib/dialects/mssql/index.js
Expand Up @@ -333,14 +333,24 @@ class Client_MSSQL extends Client {
_typeForBinding(binding) {
const Driver = this._driver();

if (
this.connectionSettings.options &&
this.connectionSettings.options.mapBinding
) {
const result = this.connectionSettings.options.mapBinding(binding);
if (result) {
return [result.value, result.type];
}
}

switch (typeof binding) {
case 'string':
return Driver.TYPES.NVarChar;
return [binding, Driver.TYPES.NVarChar];
case 'boolean':
return Driver.TYPES.Bit;
return [binding, Driver.TYPES.Bit];
case 'number': {
if (binding % 1 !== 0) {
return Driver.TYPES.Float;
return [binding, Driver.TYPES.Float];
}

if (binding < SQL_INT4.MIN || binding > SQL_INT4.MAX) {
Expand All @@ -350,25 +360,21 @@ class Client_MSSQL extends Client {
);
}

return Driver.TYPES.BigInt;
return [binding, Driver.TYPES.BigInt];
}

return Driver.TYPES.Int;
return [binding, Driver.TYPES.Int];
}
default: {
// if (binding === null || typeof binding === 'undefined') {
// return tedious.TYPES.Null;
// }

if (binding instanceof Date) {
return Driver.TYPES.DateTime;
return [binding, Driver.TYPES.DateTime];
}

if (binding instanceof Buffer) {
return Driver.TYPES.VarBinary;
return [binding, Driver.TYPES.VarBinary];
}

return Driver.TYPES.NVarChar;
return [binding, Driver.TYPES.NVarChar];
}
}
}
Expand Down Expand Up @@ -401,8 +407,8 @@ class Client_MSSQL extends Client {
}

// sets a request input parameter. Detects bigints and decimals and sets type appropriately.
_setReqInput(req, i, binding) {
const tediousType = this._typeForBinding(binding);
_setReqInput(req, i, inputBinding) {
const [binding, tediousType] = this._typeForBinding(inputBinding);
const bindingName = 'p'.concat(i);
let options;

Expand Down
28 changes: 28 additions & 0 deletions test/integration2/dialects/mssql.spec.js
@@ -1,4 +1,5 @@
const { expect } = require('chai');
const { TYPES } = require('tedious');
const { getAllDbs, getKnexForDb } = require('../util/knex-instance-provider');

async function fetchDefaultConstraint(knex, table, column) {
Expand Down Expand Up @@ -31,6 +32,8 @@ describe('MSSQL dialect', () => {
beforeEach(async () => {
await knex.schema.createTable('test', function () {
this.increments('id').primary();
this.specificType('varchar', 'varchar(100)');
this.string('nvarchar');
});
});

Expand Down Expand Up @@ -362,6 +365,31 @@ describe('MSSQL dialect', () => {
return result ? result.comment : undefined;
}
});

describe('supports mapBinding config', async () => {
it('can remap types', async () => {
const query = knex('test')
.where('varchar', { value: 'testing', type: TYPES.VarChar })
.select('id');
const { bindings } = query.toSQL().toNative();
expect(bindings[0].type, TYPES.VarChar);
expect(bindings[0].value, 'testing');

// verify the query runs successfully
await query;
});
it('undefined mapBinding result falls back to default implementation', async () => {
const query = knex('test')
.where('nvarchar', 'testing')
.select('id');

const { bindings } = query.toSQL().toNative();
expect(bindings[0], 'testing');

// verify the query runs successfully
await query;
});
});
});
});
});
Expand Down
7 changes: 7 additions & 0 deletions test/integration2/util/knex-instance-provider.js
Expand Up @@ -173,6 +173,13 @@ const testConfigs = {
server: 'localhost',
port: 21433,
database: 'knex_test',
options: {
mapBinding(value) {
if (value && value.type) {
return { value: value.value, type: value.type };
}
},
},
},
pool: pool,
migrations,
Expand Down
1 change: 1 addition & 0 deletions types/index.d.ts
Expand Up @@ -2887,6 +2887,7 @@ export declare namespace Knex {
multiSubnetFailover?: boolean;
packetSize?: number;
trustServerCertificate?: boolean;
mapBinding?: (value: any) => ({ value: any, type: any } | undefined);
}>;
pool?: Readonly<{
min?: number;
Expand Down

0 comments on commit e0c0fa9

Please sign in to comment.