Skip to content

Commit

Permalink
Add the concept of valueHandlers for processing returned rows from qu…
Browse files Browse the repository at this point in the history
…eries with user provided code
  • Loading branch information
dhensby committed Jan 29, 2022
1 parent 09441db commit b56ee39
Show file tree
Hide file tree
Showing 10 changed files with 92 additions and 3 deletions.
7 changes: 7 additions & 0 deletions lib/base/index.js
Expand Up @@ -54,6 +54,13 @@ Object.defineProperty(module.exports, 'Promise', {
}
})

Object.defineProperty(module.exports, 'valueHandler', {
enumerable: true,
value: shared.valueHandler,
writable: false,
configurable: false
})

for (const key in TYPES) {
const value = TYPES[key]
module.exports.exports[key] = value
Expand Down
7 changes: 7 additions & 0 deletions lib/msnodesqlv8/index.js
Expand Up @@ -22,6 +22,13 @@ Object.defineProperty(module.exports, 'Promise', {
}
})

Object.defineProperty(module.exports, 'valueHandler', {
enumerable: true,
value: base.valueHandler,
writable: false,
configurable: false
})

base.driver.name = 'msnodesqlv8'
base.driver.ConnectionPool = ConnectionPool
base.driver.Transaction = Transaction
Expand Down
8 changes: 7 additions & 1 deletion lib/msnodesqlv8/request.js
Expand Up @@ -8,6 +8,7 @@ const { IDS, objectHasProperty } = require('../utils')
const { TYPES, DECLARATIONS, declare } = require('../datatypes')
const { PARSERS: UDT } = require('../udt')
const Table = require('../table')
const { valueHandler } = require('../shared')

const JSON_COLUMN_ID = 'JSON_F52E2B61-18A1-11d1-B105-00805F49916B'
const XML_COLUMN_ID = 'XML_F52E2B61-18A1-11d1-B105-00805F49916B'
Expand Down Expand Up @@ -122,7 +123,12 @@ const createColumns = function (metadata, arrayRowMode) {
}

const valueCorrection = function (value, metadata) {
if ((metadata.sqlType === 'time') && (value != null)) {
const type = metadata && objectHasProperty(metadata, 'sqlType') && objectHasProperty(DECLARATIONS, metadata.sqlType)
? DECLARATIONS[metadata.sqlType]
: null
if (type && valueHandler.has(type)) {
return valueHandler.get(type)(value)
} else if ((metadata.sqlType === 'time') && (value != null)) {
value.setFullYear(1970)
return value
} else if ((metadata.sqlType === 'udt') && (value != null)) {
Expand Down
7 changes: 7 additions & 0 deletions lib/shared.js
Expand Up @@ -105,3 +105,10 @@ Object.defineProperty(module.exports, 'Promise', {
PromiseLibrary = value
}
})

Object.defineProperty(module.exports, 'valueHandler', {
enumerable: true,
value: new Map(),
writable: false,
configurable: false
})
7 changes: 7 additions & 0 deletions lib/tedious/index.js
Expand Up @@ -22,6 +22,13 @@ Object.defineProperty(module.exports, 'Promise', {
}
})

Object.defineProperty(module.exports, 'valueHandler', {
enumerable: true,
value: base.valueHandler,
writable: false,
configurable: false
})

base.driver.name = 'tedious'
base.driver.ConnectionPool = ConnectionPool
base.driver.Transaction = Transaction
Expand Down
6 changes: 5 additions & 1 deletion lib/tedious/request.js
Expand Up @@ -8,6 +8,7 @@ const { IDS, objectHasProperty } = require('../utils')
const { TYPES, DECLARATIONS, declare, cast } = require('../datatypes')
const Table = require('../table')
const { PARSERS: UDT } = require('../udt')
const { valueHandler } = require('../shared')

const JSON_COLUMN_ID = 'JSON_F52E2B61-18A1-11d1-B105-00805F49916B'
const XML_COLUMN_ID = 'XML_F52E2B61-18A1-11d1-B105-00805F49916B'
Expand Down Expand Up @@ -159,7 +160,10 @@ const createColumns = function (metadata, arrayRowMode) {
}

const valueCorrection = function (value, metadata) {
if ((metadata.type === tds.TYPES.UDT) && (value != null)) {
const type = getMssqlType(metadata.type)
if (valueHandler.has(type)) {
return valueHandler.get(type)(value)
} else if ((metadata.type === tds.TYPES.UDT) && (value != null)) {
if (UDT[metadata.udtInfo.typeName]) {
return UDT[metadata.udtInfo.typeName](value)
} else {
Expand Down
13 changes: 13 additions & 0 deletions test/common/tests.js
Expand Up @@ -123,6 +123,19 @@ module.exports = (sql, driver) => {
}

return {
'value handler' (done) {
let callCount = 0
const callArgs = []
// assign a "spy" to the valuehandler for varchar
sql.valueHandler.set(sql.TYPES.VarChar, function () { callCount++; callArgs.push(arguments); return arguments[0].toUpperCase() })
sql.query('SELECT TOP 1 * FROM [streaming] ').then((result) => {
assert.strictEqual(callCount, 1)
assert.strictEqual(result.recordset.length, 1)
assert.notStrictEqual(result.recordset[0], callArgs[0])
assert.notStrictEqual(result.recordset[0], callArgs[0][0].toUpperCase())
done()
}).catch(done)
},
'stored procedure' (mode, done) {
const req = new TestRequest()
req.input('in', sql.Int, null)
Expand Down
36 changes: 35 additions & 1 deletion test/common/unit.js
@@ -1,6 +1,6 @@
'use strict'

/* globals describe, it */
/* globals describe, it, afterEach */

const sql = require('../../')
const assert = require('assert')
Expand Down Expand Up @@ -352,3 +352,37 @@ describe('config cloning', () => {
assert.notDeepStrictEqual(options, pool.config.options)
})
})

describe('value handlers', () => {
afterEach('reset valueHandler', () => {
sql.valueHandler.clear()
})
it('can set a value handler', () => {
assert.strictEqual(sql.valueHandler instanceof Map, true)
assert.strictEqual(sql.valueHandler.size, 0)
sql.valueHandler.set(sql.TYPES.Int, (value) => value.toUpperCase())
assert.strictEqual(sql.valueHandler.size, 1)
assert.strictEqual(sql.valueHandler.has(sql.TYPES.Int), true)
})
it('can delete a value handler', () => {
assert.strictEqual(sql.valueHandler instanceof Map, true)
assert.strictEqual(sql.valueHandler.size, 0)
sql.valueHandler.set(sql.TYPES.Int, (value) => value.toUpperCase())
assert.strictEqual(sql.valueHandler.size, 1)
assert.strictEqual(sql.valueHandler.has(sql.TYPES.Int), true)
sql.valueHandler.delete(sql.TYPES.Int)
assert.strictEqual(sql.valueHandler.has(sql.TYPES.Int), false)
assert.strictEqual(sql.valueHandler.size, 0)
})
it('can reset all value handlers', () => {
assert.strictEqual(sql.valueHandler instanceof Map, true)
assert.strictEqual(sql.valueHandler.size, 0)
sql.valueHandler.set(sql.TYPES.Int, (value) => value.toUpperCase())
sql.valueHandler.set(sql.TYPES.BigInt, (value) => value.toUpperCase())
assert.strictEqual(sql.valueHandler.size, 2)
assert.strictEqual(sql.valueHandler.has(sql.TYPES.Int), true)
assert.strictEqual(sql.valueHandler.has(sql.TYPES.BigInt), true)
sql.valueHandler.clear()
assert.strictEqual(sql.valueHandler.size, 0)
})
})
2 changes: 2 additions & 0 deletions test/msnodesqlv8/msnodesqlv8.js
Expand Up @@ -36,13 +36,15 @@ describe('msnodesqlv8', function () {
})
})
)
afterEach(() => sql.valueHandler.clear())

describe('basic test suite', function () {
before(function (done) {
const cfg = config()
sql.connect(cfg, done)
})

it('value handler', done => TESTS['value handler'](done))
it('stored procedure (exec)', done => TESTS['stored procedure']('execute', done))
it('stored procedure (batch)', done => TESTS['stored procedure']('batch', done))
it('user defined types', done => TESTS['user defined types'](done))
Expand Down
2 changes: 2 additions & 0 deletions test/tedious/tedious.js
Expand Up @@ -42,6 +42,7 @@ describe('tedious', () => {
})
})
)
afterEach(() => sql.valueHandler.clear())

describe('basic test suite', () => {
before((done) => {
Expand All @@ -50,6 +51,7 @@ describe('tedious', () => {
sql.connect(cfg, done)
})

it('value handler', done => TESTS['value handler'](done))
it('stored procedure (exec)', done => TESTS['stored procedure']('execute', done))
it('stored procedure (batch)', done => TESTS['stored procedure']('batch', done))
it('user defined types', done => TESTS['user defined types'](done))
Expand Down

0 comments on commit b56ee39

Please sign in to comment.