Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: Improved Data Type validation/conversion. #677

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 19 additions & 0 deletions src/bulk-load.ts
Original file line number Diff line number Diff line change
Expand Up @@ -233,10 +233,29 @@ class BulkLoad extends EventEmitter {

// write each column
if (Array.isArray(row)) {
this.columns.map((column, index) => {
const data = row[index];
try {
column.type.validate(data, column.length);
} catch (e) {
console.log(e);
console.debug(e);
}

return null;
});
this.rowToPacketTransform.write(row);
} else {
const object = row;
this.rowToPacketTransform.write(this.columns.map((column) => {
const data = object[column.objName];
try {
column.type.validate(data, column.length);
} catch (e) {
console.log(e);
console.debug(e);
}

return object[column.objName];
}));
}
Expand Down
2 changes: 1 addition & 1 deletion src/data-type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export interface DataType {
declaration(parameter: Parameter): string;
generateTypeInfo(parameter: ParameterData, options: InternalConnectionOptions): Buffer;
generateParameterData(parameter: ParameterData, options: InternalConnectionOptions): Generator<Buffer, void>;
validate(value: any): any; // TODO: Refactor 'any' and replace with more specific type.
validate(value: any, length?: number): any; // TODO: Refactor 'any' and replace with more specific type.

hasTableName?: boolean;

Expand Down
9 changes: 7 additions & 2 deletions src/data-types/bigint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const BigInt: DataType = {
},

validate: function(value): null | number | TypeError {
if (value == null) {
if (value == null || value === undefined) {
return null;
}

Expand All @@ -43,7 +43,12 @@ const BigInt: DataType = {
return new TypeError(`Value must be between ${Number.MIN_SAFE_INTEGER} and ${Number.MAX_SAFE_INTEGER}, inclusive. For smaller or bigger numbers, use VarChar type.`);
}

return value;
const numberValue = typeof value === 'number' ? value : parseInt(value);
if (!Number.isSafeInteger(numberValue)) {
return new TypeError(`The given value could not be converted to ${this.name}`);
}

return numberValue;
}
};

Expand Down
10 changes: 8 additions & 2 deletions src/data-types/binary.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,15 +57,21 @@ const Binary: { maximumLength: number } & DataType = {
}
},

validate: function(value): Buffer | null | TypeError {
if (value == null) {
validate: function(value, length): Buffer | null | TypeError {
if (value === undefined || value === null) {
return null;
}

if (!Buffer.isBuffer(value)) {
return new TypeError('Invalid buffer.');
}

if (length) {
if (value.length > length) {
return new TypeError(`The given value could not be converted to ${this.name}`);
}
}

return value;
}
};
Expand Down
8 changes: 2 additions & 6 deletions src/data-types/bit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,10 @@ const Bit: DataType = {
},

validate: function(value): null | boolean {
if (value == null) {
if (value == null || value === undefined) {
return null;
}
if (value) {
return true;
} else {
return false;
}
return !!value;
}
};

Expand Down
16 changes: 8 additions & 8 deletions src/data-types/char.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,17 +72,17 @@ const Char: { maximumLength: number } & DataType = {
}
},

validate: function(value): null | string | TypeError {
if (value == null) {
validate: function(value, length): null | string | TypeError {
if (value === undefined || value === null) {
return null;
}
if (typeof value !== 'string') {
if (typeof value.toString !== 'function') {
return TypeError('Invalid string.');
}
value = value.toString();

const stringValue = typeof value !== 'string' && typeof value.toString === 'function' ? value.toString() : value;
if (typeof stringValue !== 'string' || (length && stringValue.length > length) || stringValue.length > this.maximumLength) {
return new TypeError(`The given value could not be converted to ${this.name}`);
}
return value;

return stringValue;
}
};

Expand Down
15 changes: 9 additions & 6 deletions src/data-types/date.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,19 +43,22 @@ const Date: DataType = {

// TODO: value is techincally of type 'unknown'.
validate: function(value): null | Date | TypeError {
if (value == null) {
if (value === undefined || value === null) {
return null;
}

if (!(value instanceof globalDate)) {
value = new globalDate(globalDate.parse(value));
let dateValue: any;
if (value instanceof globalDate) {
dateValue = value;
} else {
dateValue = new globalDate(globalDate.parse(value));
}

if (isNaN(value)) {
return new TypeError('Invalid date.');
if (isNaN(dateValue)) {
return new TypeError(`The given value could not be converted to ${this.name}`);
}

return value;
return dateValue;
}
};

Expand Down
15 changes: 9 additions & 6 deletions src/data-types/datetime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,19 +64,22 @@ const DateTime: DataType = {

// TODO: type 'any' needs to be revisited.
validate: function(value): null | number | TypeError {
if (value == null) {
if (value === undefined || value === null) {
return null;
}

if (!(value instanceof Date)) {
value = new Date(Date.parse(value));
let dateValue: any;
if (value instanceof Date) {
dateValue = value;
} else {
dateValue = new Date(Date.parse(value));
}

if (isNaN(value)) {
return new TypeError('Invalid date.');
if (isNaN(dateValue)) {
return new TypeError(`The given value could not be converted to ${this.name}`);
}

return value;
return dateValue;
}
};

Expand Down
15 changes: 9 additions & 6 deletions src/data-types/datetime2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,19 +82,22 @@ const DateTime2: DataType & { resolveScale: NonNullable<DataType['resolveScale']
},

validate: function(value): null | number | TypeError {
if (value == null) {
if (value === undefined || value === null) {
return null;
}

if (!(value instanceof Date)) {
value = new Date(Date.parse(value));
let dateValue: any;
if (value instanceof Date) {
dateValue = value;
} else {
dateValue = new Date(Date.parse(value));
}

if (isNaN(value)) {
return new TypeError('Invalid date.');
if (isNaN(dateValue)) {
return new TypeError(`The given value could not be converted to ${this.name}`);
}

return value;
return dateValue;
}
};

Expand Down
15 changes: 9 additions & 6 deletions src/data-types/datetimeoffset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,19 +72,22 @@ const DateTimeOffset: DataType & { resolveScale: NonNullable<DataType['resolveSc
}
},
validate: function(value): null | number | TypeError {
if (value == null) {
if (value === undefined || value === null) {
return null;
}

if (!(value instanceof Date)) {
value = new Date(Date.parse(value));
let dateValue: any;
if (value instanceof Date) {
dateValue = value;
} else {
dateValue = new Date(Date.parse(value));
}

if (isNaN(value)) {
return new TypeError('Invalid date.');
if (isNaN(dateValue)) {
return new TypeError(`The given value could not be converted to ${this.name}`);
}

return value;
return dateValue;
}
};

Expand Down
17 changes: 12 additions & 5 deletions src/data-types/decimal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,14 +83,21 @@ const Decimal: DataType & { resolvePrecision: NonNullable<DataType['resolvePreci
},

validate: function(value): number | null | TypeError {
if (value == null) {
if (value === undefined || value === null) {
return null;
}
value = parseFloat(value);
if (isNaN(value)) {
return new TypeError('Invalid number.');
let numberValue;
if (typeof value === 'number') {
numberValue = value;
} else {
numberValue = parseFloat(value);
}

if (!Number.isFinite(numberValue) || (typeof value === 'string' && value !== numberValue.toString())) {
return new TypeError(`The given value could not be converted to ${this.name}`);
}
return value;

return numberValue;
}
};

Expand Down
17 changes: 12 additions & 5 deletions src/data-types/float.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,21 @@ const Float: DataType = {
},

validate: function(value): number | null | TypeError {
if (value == null) {
if (value === undefined || value === null) {
return null;
}
value = parseFloat(value);
if (isNaN(value)) {
return new TypeError('Invalid number.');
let numberValue;
if (typeof value === 'number') {
numberValue = value;
} else {
numberValue = parseFloat(value);
}

if (!Number.isFinite(numberValue) || (typeof value === 'string' && value !== numberValue.toString())) {
return new TypeError(`The given value could not be converted to ${this.name}`);
}
return value;

return numberValue;
}
};

Expand Down
16 changes: 12 additions & 4 deletions src/data-types/image.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { DataType } from '../data-type';
const MAX = 2147483647;
const NULL = -1;

const Image: DataType = {
id: 0x22,
Expand All @@ -20,9 +22,14 @@ const Image: DataType = {
},

generateTypeInfo(parameter) {
const value = parameter.value;
const buffer = Buffer.alloc(5);
buffer.writeUInt8(this.id, 0);
buffer.writeInt32LE(parameter.length!, 1);
if (value === null) {
buffer.writeInt32LE(NULL, 1);
} else {
buffer.writeInt32LE(parameter.length!, 1);
}
return buffer;
},

Expand All @@ -41,11 +48,12 @@ const Image: DataType = {
},

validate: function(value): null | TypeError | Buffer {
if (value == null) {
if (value === undefined || value === null) {
return null;
}
if (!Buffer.isBuffer(value)) {
return new TypeError('Invalid buffer.');

if (!Buffer.isBuffer(value) || value.length > MAX) {
return new TypeError(`The given value could not be converted to ${this.name}`);
}
return value;
}
Expand Down
17 changes: 5 additions & 12 deletions src/data-types/int.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,23 +29,16 @@ const Int: DataType = {
},

validate: function(value): number | null | TypeError {
if (value == null) {
if (value === null || value === undefined) {
return null;
}

if (typeof value !== 'number') {
value = Number(value);
const numberValue = typeof value === 'number' ? value : parseInt(value);
if (!Number.isSafeInteger(numberValue) || value < -2147483648 || value > 2147483647) {
return new TypeError(`The given value could not be converted to ${this.name}`);
}

if (isNaN(value)) {
return new TypeError('Invalid number.');
}

if (value < -2147483648 || value > 2147483647) {
return new TypeError('Value must be between -2147483648 and 2147483647, inclusive.');
}

return value | 0;
return numberValue;
}
};

Expand Down