From 7d8656ae0cf9e959fddfebc2b0a042eea47bbd5b Mon Sep 17 00:00:00 2001 From: Jacek Tomaszewski Date: Thu, 15 Feb 2024 14:55:46 +0100 Subject: [PATCH 01/12] feat: provide better error messages when input param is invalid --- src/data-types/tvp.ts | 7 ++++++- src/errors.ts | 8 ++++++++ src/rpcrequest-payload.ts | 7 ++++++- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/data-types/tvp.ts b/src/data-types/tvp.ts index 118157bf4..6e7e11bc9 100644 --- a/src/data-types/tvp.ts +++ b/src/data-types/tvp.ts @@ -1,4 +1,5 @@ import { type DataType } from '../data-type'; +import { InputError } from '../errors'; import WritableTrackingBuffer from '../tracking-buffer/writable-tracking-buffer'; const TVP_ROW_TOKEN = Buffer.from([0x01]); @@ -92,7 +93,11 @@ const TVP: DataType = { // TvpColumnData yield column.type.generateParameterLength(param, options); - yield * column.type.generateParameterData(param, options); + try { + yield * column.type.generateParameterData(param, options); + } catch (error) { + throw new InputError(`TVP column i=${k} has invalid data at row j=${i}`, error); + } } } diff --git a/src/errors.ts b/src/errors.ts index 097d7c91e..a97926e06 100644 --- a/src/errors.ts +++ b/src/errors.ts @@ -26,3 +26,11 @@ export class RequestError extends Error { this.code = code; } } + +export class InputError extends TypeError { + constructor(message: string, readonly cause: unknown) { + super( + message + (cause instanceof Error ? `. Details: ${cause.message}` : '') + ); + } +} diff --git a/src/rpcrequest-payload.ts b/src/rpcrequest-payload.ts index 20aff27a9..cd49fedfd 100644 --- a/src/rpcrequest-payload.ts +++ b/src/rpcrequest-payload.ts @@ -3,6 +3,7 @@ import { writeToTrackingBuffer } from './all-headers'; import { type Parameter, type ParameterData } from './data-type'; import { type InternalConnectionOptions } from './connection'; import { Collation } from './collation'; +import { InputError } from './errors'; // const OPTION = { // WITH_RECOMPILE: 0x01, @@ -113,7 +114,11 @@ class RpcRequestPayload implements Iterable { yield type.generateTypeInfo(param, this.options); yield type.generateParameterLength(param, this.options); - yield * type.generateParameterData(param, this.options); + try { + yield * type.generateParameterData(param, this.options); + } catch (error) { + throw new InputError(`Input parameter with name=${parameter.name} has invalid data`, error); + } } } From e86a9a0d59063fff828a2351980bb0f0b3fc224f Mon Sep 17 00:00:00 2001 From: Michael Sun <47126816+MichaelSun90@users.noreply.github.com> Date: Wed, 24 Jul 2024 13:42:55 -0700 Subject: [PATCH 02/12] chore: update input error --- src/errors.ts | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/errors.ts b/src/errors.ts index a97926e06..049826d9e 100644 --- a/src/errors.ts +++ b/src/errors.ts @@ -27,10 +27,4 @@ export class RequestError extends Error { } } -export class InputError extends TypeError { - constructor(message: string, readonly cause: unknown) { - super( - message + (cause instanceof Error ? `. Details: ${cause.message}` : '') - ); - } -} +export class InputError extends TypeError {} From b25c41b4e5fe4a01e3b7d5a9410c6b4c9d12c715 Mon Sep 17 00:00:00 2001 From: Michael Sun <47126816+MichaelSun90@users.noreply.github.com> Date: Wed, 24 Jul 2024 13:43:57 -0700 Subject: [PATCH 03/12] chore: update the rpc error message --- src/rpcrequest-payload.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rpcrequest-payload.ts b/src/rpcrequest-payload.ts index cd49fedfd..d2d15e2ae 100644 --- a/src/rpcrequest-payload.ts +++ b/src/rpcrequest-payload.ts @@ -117,7 +117,7 @@ class RpcRequestPayload implements Iterable { try { yield * type.generateParameterData(param, this.options); } catch (error) { - throw new InputError(`Input parameter with name=${parameter.name} has invalid data`, error); + throw new InputError(`Input parameter '${parameter.name}' could not be validated`, { cause: error }); } } } From 135425ecec2f10ba4b98e9182b553a6ff52f9057 Mon Sep 17 00:00:00 2001 From: Michael Sun <47126816+MichaelSun90@users.noreply.github.com> Date: Wed, 24 Jul 2024 13:45:25 -0700 Subject: [PATCH 04/12] chore: update tvp type message --- src/data-types/tvp.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data-types/tvp.ts b/src/data-types/tvp.ts index 6e7e11bc9..bbef12b52 100644 --- a/src/data-types/tvp.ts +++ b/src/data-types/tvp.ts @@ -96,7 +96,7 @@ const TVP: DataType = { try { yield * column.type.generateParameterData(param, options); } catch (error) { - throw new InputError(`TVP column i=${k} has invalid data at row j=${i}`, error); + throw new InputError(`TVP column '${column.name}' has invalid data at row index ${i}`, { cause: error }); } } } From a368b70cc15702182e48aee8f950eb8fd8ed1268 Mon Sep 17 00:00:00 2001 From: Michael Sun <47126816+MichaelSun90@users.noreply.github.com> Date: Wed, 24 Jul 2024 13:47:31 -0700 Subject: [PATCH 05/12] chore: modify the tvp test --- test/integration/tvp-test.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/test/integration/tvp-test.js b/test/integration/tvp-test.js index a9dd0c0c6..3967c1df3 100644 --- a/test/integration/tvp-test.js +++ b/test/integration/tvp-test.js @@ -180,9 +180,15 @@ describe('calling a procedure that takes and returns a TVP', function() { }); it('correctly handles validation errors', function(done) { - const request = new Request('__tediousTvpTest', (err) => { - assert.instanceOf(err, TypeError); - assert.strictEqual(err?.message, 'Value must be between 0 and 255, inclusive.'); + const request = new Request('__tediousTvpTest', (err) => { + assert.instanceOf(err, InputError); + assert.strictEqual(err?.message, 'Input parameter \'tvp\' could not be validated'); + + assert.instanceOf(err?.cause, InputError); + assert.strictEqual(/** @type {InputError} */(err?.cause).message, 'TVP column \'b\' has invalid data at row index 0'); + + assert.instanceOf(/** @type {InputError} */(err?.cause).cause, TypeError); + assert.strictEqual(/** @type {TypeError} */(/** @type {InputError} */(err?.cause).cause).message, 'Value must be between 0 and 255, inclusive.'); const request = new Request('SELECT 1', done); connection.execSql(request); From 3e6b3a0106679f5cd9378ad7efabc9c3c73742bb Mon Sep 17 00:00:00 2001 From: Michael Sun <47126816+MichaelSun90@users.noreply.github.com> Date: Wed, 24 Jul 2024 13:48:41 -0700 Subject: [PATCH 06/12] chore: add import for input error --- test/integration/tvp-test.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/integration/tvp-test.js b/test/integration/tvp-test.js index 3967c1df3..33c663aac 100644 --- a/test/integration/tvp-test.js +++ b/test/integration/tvp-test.js @@ -9,6 +9,7 @@ import Request from '../../src/request'; import { debugOptionsFromEnv } from '../helpers/debug-options-from-env'; import defaultConfig from '../config'; +import { InputError } from '../../src/errors'; function getConfig() { const config = { From cc5b951790b3930cdf25464c3c2e6628ff3724e0 Mon Sep 17 00:00:00 2001 From: Michael Sun <47126816+MichaelSun90@users.noreply.github.com> Date: Wed, 24 Jul 2024 14:13:43 -0700 Subject: [PATCH 07/12] chore: fix test file --- test/integration/tvp-test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/integration/tvp-test.js b/test/integration/tvp-test.js index 33c663aac..add8d51d2 100644 --- a/test/integration/tvp-test.js +++ b/test/integration/tvp-test.js @@ -181,7 +181,7 @@ describe('calling a procedure that takes and returns a TVP', function() { }); it('correctly handles validation errors', function(done) { - const request = new Request('__tediousTvpTest', (err) => { + const request = new Request('__tediousTvpTest', (err) => { assert.instanceOf(err, InputError); assert.strictEqual(err?.message, 'Input parameter \'tvp\' could not be validated'); @@ -194,7 +194,7 @@ describe('calling a procedure that takes and returns a TVP', function() { const request = new Request('SELECT 1', done); connection.execSql(request); }); - + const table = { columns: [ { From 0291bff46d37d1739d18227b18b3632764321f60 Mon Sep 17 00:00:00 2001 From: Michael Sun <47126816+MichaelSun90@users.noreply.github.com> Date: Wed, 24 Jul 2024 14:15:24 -0700 Subject: [PATCH 08/12] chore: change the try catch location --- src/data-types/tvp.ts | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/data-types/tvp.ts b/src/data-types/tvp.ts index bbef12b52..8b0cda8d9 100644 --- a/src/data-types/tvp.ts +++ b/src/data-types/tvp.ts @@ -84,8 +84,15 @@ const TVP: DataType = { const column = columns[k]; const value = row[k]; + let paramValue; + try { + paramValue = column.type.validate(value, parameter.collation); + } catch (error) { + throw new InputError(`TVP column '${column.name}' has invalid data at row index ${i}`, { cause: error }); + } + const param = { - value: column.type.validate(value, parameter.collation), + value: paramValue, length: column.length, scale: column.scale, precision: column.precision @@ -93,11 +100,7 @@ const TVP: DataType = { // TvpColumnData yield column.type.generateParameterLength(param, options); - try { - yield * column.type.generateParameterData(param, options); - } catch (error) { - throw new InputError(`TVP column '${column.name}' has invalid data at row index ${i}`, { cause: error }); - } + yield * column.type.generateParameterData(param, options); } } From ee9fd288d557b4e5ec524bf2829beca8e2d9b89e Mon Sep 17 00:00:00 2001 From: Michael Sun <47126816+MichaelSun90@users.noreply.github.com> Date: Wed, 24 Jul 2024 14:19:43 -0700 Subject: [PATCH 09/12] chore: remove tailing spaces From 35c546304dc2d1f0bf3544274915b5f73e0d6a15 Mon Sep 17 00:00:00 2001 From: Michael Sun <47126816+MichaelSun90@users.noreply.github.com> Date: Wed, 24 Jul 2024 14:20:36 -0700 Subject: [PATCH 10/12] chore: remove tailing space from test file From 68d420fb482f6306f60e4b35c0e43610a86dbee2 Mon Sep 17 00:00:00 2001 From: Michael Sun <47126816+MichaelSun90@users.noreply.github.com> Date: Wed, 24 Jul 2024 14:55:32 -0700 Subject: [PATCH 11/12] chore: remove tailing spaces --- src/data-types/tvp.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data-types/tvp.ts b/src/data-types/tvp.ts index 8b0cda8d9..aba75940d 100644 --- a/src/data-types/tvp.ts +++ b/src/data-types/tvp.ts @@ -90,7 +90,7 @@ const TVP: DataType = { } catch (error) { throw new InputError(`TVP column '${column.name}' has invalid data at row index ${i}`, { cause: error }); } - + const param = { value: paramValue, length: column.length, From 87dbc1a56535ddf8ef535792dfa46d610eb5060a Mon Sep 17 00:00:00 2001 From: Michael Sun <47126816+MichaelSun90@users.noreply.github.com> Date: Wed, 24 Jul 2024 14:56:23 -0700 Subject: [PATCH 12/12] chore: remove tailing spaces test --- test/integration/tvp-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration/tvp-test.js b/test/integration/tvp-test.js index add8d51d2..955895bb3 100644 --- a/test/integration/tvp-test.js +++ b/test/integration/tvp-test.js @@ -194,7 +194,7 @@ describe('calling a procedure that takes and returns a TVP', function() { const request = new Request('SELECT 1', done); connection.execSql(request); }); - + const table = { columns: [ {