Implement mapBinding mssql dialect option (#5292)

This commit is contained in:
Kelly Bourg 2022-08-31 13:25:25 -05:00 committed by GitHub
parent 29283a1560
commit e0c0fa9358
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 56 additions and 14 deletions

View File

@ -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) {
@ -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];
}
}
}
@ -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;

View File

@ -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) {
@ -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');
});
});
@ -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;
});
});
});
});
});

View File

@ -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,

1
types/index.d.ts vendored
View File

@ -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;