diff --git a/lib/dialects/mssql/query.js b/lib/dialects/mssql/query.js index b14c80391591..35e9a02847bc 100644 --- a/lib/dialects/mssql/query.js +++ b/lib/dialects/mssql/query.js @@ -9,6 +9,13 @@ const { logger } = require('../../utils/logger'); const debug = logger.debugContext('sql:mssql'); +function getScale(aNum) { + if (!Number.isFinite(aNum)) return 0; + let e = 1; + while (Math.round(aNum * e) / e !== aNum) e *= 10; + return Math.log10(e); +} + class Query extends AbstractQuery { getInsertIdField() { return 'id'; @@ -27,7 +34,7 @@ class Query extends AbstractQuery { } else { paramType.type = TYPES.Numeric; //Default to a reasonable numeric precision/scale pending more sophisticated logic - paramType.typeOptions = { precision: 30, scale: 15 }; + paramType.typeOptions = { precision: 30, scale: getScale(value) }; } } if (Buffer.isBuffer(value)) { diff --git a/test/unit/dialects/mssql/query.test.js b/test/unit/dialects/mssql/query.test.js index ef151977fb05..90ef90479155 100644 --- a/test/unit/dialects/mssql/query.test.js +++ b/test/unit/dialects/mssql/query.test.js @@ -15,18 +15,22 @@ let sandbox, query; if (dialect === 'mssql') { describe('[MSSQL Specific] Query', () => { - describe('beginTransaction', () => { - beforeEach(() => { - sandbox = sinon.createSandbox(); - const options = { - transaction: { name: 'transactionName' }, - isolationLevel: 'REPEATABLE_READ', - logging: false - }; - sandbox.stub(connectionStub, 'beginTransaction').callsArg(0); - query = new Query(connectionStub, sequelize, options); - }); + beforeEach(() => { + sandbox = sinon.createSandbox(); + const options = { + transaction: { name: 'transactionName' }, + isolationLevel: 'REPEATABLE_READ', + logging: false + }; + sandbox.stub(connectionStub, 'beginTransaction').callsArg(0); + query = new Query(connectionStub, sequelize, options); + }); + + afterEach(() => { + sandbox.restore(); + }); + describe('beginTransaction', () => { it('should call beginTransaction with correct arguments', () => { return query._run(connectionStub, 'BEGIN TRANSACTION') .then(() => { @@ -35,10 +39,6 @@ if (dialect === 'mssql') { expect(connectionStub.beginTransaction.args[0][2]).to.equal(tediousIsolationLevel.REPEATABLE_READ); }); }); - - afterEach(() => { - sandbox.restore(); - }); }); describe('formatBindParameters', () => { @@ -64,5 +64,25 @@ if (dialect === 'mssql') { expect(result[0]).to.equal(expected); }); }); + + describe('getSQLTypeFromJsType', () => { + const TYPES = tedious.TYPES; + it('should return correct parameter type', () => { + expect(query.getSQLTypeFromJsType(2147483647, TYPES)).to.eql({ type: TYPES.Int, typeOptions: {} }); + expect(query.getSQLTypeFromJsType(-2147483648, TYPES)).to.eql({ type: TYPES.Int, typeOptions: {} }); + + expect(query.getSQLTypeFromJsType(2147483648, TYPES)).to.eql({ type: TYPES.BigInt, typeOptions: {} }); + expect(query.getSQLTypeFromJsType(-2147483649, TYPES)).to.eql({ type: TYPES.BigInt, typeOptions: {} }); + + expect(query.getSQLTypeFromJsType(Buffer.from('abc'), TYPES)).to.eql({ type: TYPES.VarBinary, typeOptions: {} }); + }); + + it('should return parameter type correct scale for float', () => { + expect(query.getSQLTypeFromJsType(1.23, TYPES)).to.eql({ type: TYPES.Numeric, typeOptions: { precision: 30, scale: 2 } }); + expect(query.getSQLTypeFromJsType(0.30000000000000004, TYPES)).to.eql({ type: TYPES.Numeric, typeOptions: { precision: 30, scale: 17 } }); + expect(query.getSQLTypeFromJsType(2.5e-15, TYPES)).to.eql({ type: TYPES.Numeric, typeOptions: { precision: 30, scale: 16 } }); + }); + }); + }); }