Skip to content

Commit e720d1a

Browse files
MichaelSun90arthurschreiber
authored andcommitted
feat: allow returning lowercase GUIDs
According to [RFC 4122](https://tools.ietf.org/html/rfc4122) section 3, UUIDs should be generated with lower case characters. Unfortunately, GUIDs returned by `tedious` were generated with upper case characters. To be more compliant with RFC 4122, a new connection option `lowerCaseGuids` is introduced, which allows specifying whether upper or lower case characters should be used for GUIDs. To preserve backwards-compatibility, this option defaults to `false`. This will be changed to `true` in a future release.
1 parent 6a80598 commit e720d1a

File tree

6 files changed

+161
-37
lines changed

6 files changed

+161
-37
lines changed

src/connection.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,8 @@ class Connection extends EventEmitter {
244244
textsize: DEFAULT_TEXTSIZE,
245245
trustServerCertificate: true,
246246
useColumnNames: false,
247-
useUTC: true
247+
useUTC: true,
248+
lowerCaseGuids: false
248249
}
249250
};
250251

@@ -638,6 +639,14 @@ class Connection extends EventEmitter {
638639

639640
this.config.options.useUTC = config.options.useUTC;
640641
}
642+
643+
if (config.options.lowerCaseGuids !== undefined) {
644+
if (typeof config.options.lowerCaseGuids !== 'boolean') {
645+
throw new TypeError('The "config.options.lowerCaseGuids" property must be of type boolean.');
646+
}
647+
648+
this.config.options.lowerCaseGuids = config.options.lowerCaseGuids;
649+
}
641650
}
642651

643652
let credentialsDetails = this.config.options.cryptoCredentialsDetails;

src/guid-parser.ts

Lines changed: 62 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const MAP = [
1+
const UPPER_CASE_MAP = [
22
'00', '01', '02', '03', '04', '05', '06', '07', '08', '09', '0A', '0B', '0C', '0D', '0E', '0F',
33
'10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '1A', '1B', '1C', '1D', '1E', '1F',
44
'20', '21', '22', '23', '24', '25', '26', '27', '28', '29', '2A', '2B', '2C', '2D', '2E', '2F',
@@ -17,28 +17,72 @@ const MAP = [
1717
'F0', 'F1', 'F2', 'F3', 'F4', 'F5', 'F6', 'F7', 'F8', 'F9', 'FA', 'FB', 'FC', 'FD', 'FE', 'FF'
1818
];
1919

20-
export function arrayToGuid(array: Array<number>) {
20+
const LOWER_CASE_MAP = [
21+
'00', '01', '02', '03', '04', '05', '06', '07', '08', '09', '0a', '0b', '0c', '0d', '0e', '0f',
22+
'10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '1a', '1b', '1c', '1d', '1e', '1f',
23+
'20', '21', '22', '23', '24', '25', '26', '27', '28', '29', '2a', '2b', '2c', '2d', '2e', '2f',
24+
'30', '31', '32', '33', '34', '35', '36', '37', '38', '39', '3a', '3b', '3c', '3d', '3e', '3f',
25+
'40', '41', '42', '43', '44', '45', '46', '47', '48', '49', '4a', '4b', '4c', '4d', '4e', '4f',
26+
'50', '51', '52', '53', '54', '55', '56', '57', '58', '59', '5a', '5b', '5c', '5d', '5e', '5f',
27+
'60', '61', '62', '63', '64', '65', '66', '67', '68', '69', '6a', '6b', '6c', '6d', '6e', '6f',
28+
'70', '71', '72', '73', '74', '75', '76', '77', '78', '79', '7a', '7b', '7c', '7d', '7e', '7f',
29+
'80', '81', '82', '83', '84', '85', '86', '87', '88', '89', '8a', '8b', '8c', '8d', '8e', '8f',
30+
'90', '91', '92', '93', '94', '95', '96', '97', '98', '99', '9a', '9b', '9c', '9d', '9e', '9f',
31+
'a0', 'a1', 'a2', 'a3', 'a4', 'a5', 'a6', 'a7', 'a8', 'a9', 'aa', 'ab', 'ac', 'ad', 'ae', 'af',
32+
'b0', 'b1', 'b2', 'b3', 'b4', 'b5', 'b6', 'b7', 'b8', 'b9', 'ba', 'bb', 'bc', 'bd', 'be', 'bf',
33+
'c0', 'c1', 'c2', 'c3', 'c4', 'c5', 'c6', 'c7', 'c8', 'c9', 'ca', 'cb', 'cc', 'cd', 'ce', 'cf',
34+
'd0', 'd1', 'd2', 'd3', 'd4', 'd5', 'd6', 'd7', 'd8', 'd9', 'da', 'db', 'dc', 'dd', 'de', 'df',
35+
'e0', 'e1', 'e2', 'e3', 'e4', 'e5', 'e6', 'e7', 'e8', 'e9', 'ea', 'eb', 'ec', 'ed', 'ee', 'ef',
36+
'f0', 'f1', 'f2', 'f3', 'f4', 'f5', 'f6', 'f7', 'f8', 'f9', 'fa', 'fb', 'fc', 'fd', 'fe', 'ff'
37+
];
38+
39+
export function arrayToUpperCaseGuid(array: Array<number>) {
40+
return (
41+
UPPER_CASE_MAP[array[3]] +
42+
UPPER_CASE_MAP[array[2]] +
43+
UPPER_CASE_MAP[array[1]] +
44+
UPPER_CASE_MAP[array[0]] +
45+
'-' +
46+
UPPER_CASE_MAP[array[5]] +
47+
UPPER_CASE_MAP[array[4]] +
48+
'-' +
49+
UPPER_CASE_MAP[array[7]] +
50+
UPPER_CASE_MAP[array[6]] +
51+
'-' +
52+
UPPER_CASE_MAP[array[8]] +
53+
UPPER_CASE_MAP[array[9]] +
54+
'-' +
55+
UPPER_CASE_MAP[array[10]] +
56+
UPPER_CASE_MAP[array[11]] +
57+
UPPER_CASE_MAP[array[12]] +
58+
UPPER_CASE_MAP[array[13]] +
59+
UPPER_CASE_MAP[array[14]] +
60+
UPPER_CASE_MAP[array[15]]
61+
);
62+
}
63+
64+
export function arrayToLowerCaseGuid(array: Array<number>) {
2165
return (
22-
MAP[array[3]] +
23-
MAP[array[2]] +
24-
MAP[array[1]] +
25-
MAP[array[0]] +
66+
LOWER_CASE_MAP[array[3]] +
67+
LOWER_CASE_MAP[array[2]] +
68+
LOWER_CASE_MAP[array[1]] +
69+
LOWER_CASE_MAP[array[0]] +
2670
'-' +
27-
MAP[array[5]] +
28-
MAP[array[4]] +
71+
LOWER_CASE_MAP[array[5]] +
72+
LOWER_CASE_MAP[array[4]] +
2973
'-' +
30-
MAP[array[7]] +
31-
MAP[array[6]] +
74+
LOWER_CASE_MAP[array[7]] +
75+
LOWER_CASE_MAP[array[6]] +
3276
'-' +
33-
MAP[array[8]] +
34-
MAP[array[9]] +
77+
LOWER_CASE_MAP[array[8]] +
78+
LOWER_CASE_MAP[array[9]] +
3579
'-' +
36-
MAP[array[10]] +
37-
MAP[array[11]] +
38-
MAP[array[12]] +
39-
MAP[array[13]] +
40-
MAP[array[14]] +
41-
MAP[array[15]]
80+
LOWER_CASE_MAP[array[10]] +
81+
LOWER_CASE_MAP[array[11]] +
82+
LOWER_CASE_MAP[array[12]] +
83+
LOWER_CASE_MAP[array[13]] +
84+
LOWER_CASE_MAP[array[14]] +
85+
LOWER_CASE_MAP[array[15]]
4286
);
4387
}
4488

src/value-parser.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,7 @@ function valueParse(parser, metaData, options, callback) {
310310
return callback(null);
311311
case 0x10:
312312
return parser.readBuffer(0x10, (data) => {
313-
callback(guidParser.arrayToGuid(data));
313+
callback(options.lowerCaseGuids ? guidParser.arrayToLowerCaseGuid(data) : guidParser.arrayToUpperCaseGuid(data));
314314
});
315315

316316
default:

test/integration/parameterised-statements-test.js

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ function getConfig() {
2323
}
2424

2525

26-
function execSql(done, type, value, tdsVersion, options, expectedValue, cast) {
26+
function execSql(done, type, value, tdsVersion, options, expectedValue, cast, connectionOptions) {
2727
var config = getConfig();
2828
// config.options.packetSize = 32768
2929

@@ -65,7 +65,8 @@ function execSql(done, type, value, tdsVersion, options, expectedValue, cast) {
6565
}
6666
});
6767

68-
var connection = new Connection(config);
68+
const connectionConfig = Object.assign({}, config, { options: Object.assign({}, config.options, connectionOptions) });
69+
var connection = new Connection(connectionConfig);
6970

7071
connection.on('connect', function(err) {
7172
assert.ifError(err);
@@ -85,7 +86,7 @@ function execSql(done, type, value, tdsVersion, options, expectedValue, cast) {
8586
});
8687
}
8788

88-
function execSqlOutput(done, type, value, expectedValue) {
89+
function execSqlOutput(done, type, value, expectedValue, connectionOptions) {
8990
var config = getConfig();
9091

9192
var request = new Request('set @paramOut = @paramIn', function(err) {
@@ -122,7 +123,8 @@ function execSqlOutput(done, type, value, expectedValue) {
122123
assert.ok(metadata);
123124
});
124125

125-
var connection = new Connection(config);
126+
const connectionConfig = Object.assign({}, config, { options: Object.assign({}, config.options, connectionOptions) });
127+
var connection = new Connection(connectionConfig);
126128

127129
connection.on('connect', function(err) {
128130
assert.ifError(err);
@@ -253,11 +255,29 @@ describe('Parameterised Statements Test', function() {
253255
execSql(done, TYPES.Money, 956455842.4566);
254256
});
255257

256-
it('should test unique identifier', function(done) {
258+
it('UniqueIdentifier when `lowerCaseGuids` option is `false`', function(done) {
257259
execSql(
258260
done,
259261
TYPES.UniqueIdentifier,
260-
'01234567-89AB-CDEF-0123-456789ABCDEF'
262+
'01234567-89AB-CDEF-0123-456789ABCDEF',
263+
undefined,
264+
undefined,
265+
undefined,
266+
undefined,
267+
{ lowerCaseGuids: false }
268+
);
269+
});
270+
271+
it('UniqueIdentifier when `lowerCaseGuids` option is `true`', function(done) {
272+
execSql(
273+
done,
274+
TYPES.UniqueIdentifier,
275+
'01234567-89ab-cdef-0123-456789abcdef',
276+
undefined,
277+
undefined,
278+
undefined,
279+
undefined,
280+
{ lowerCaseGuids: true }
261281
);
262282
});
263283

@@ -662,12 +682,12 @@ describe('Parameterised Statements Test', function() {
662682
execSqlOutput(done, TYPES.Float, 9654.2546456567565767644);
663683
});
664684

665-
it('should test output unique identifier', function(done) {
666-
execSqlOutput(
667-
done,
668-
TYPES.UniqueIdentifier,
669-
'01234567-89AB-CDEF-0123-456789ABCDEF'
670-
);
685+
it('UniqueIdentifier as output parameter when `lowerCaseGuids` option is `false`', function(done) {
686+
execSqlOutput(done, TYPES.UniqueIdentifier, '01234567-89AB-CDEF-0123-456789ABCDEF', undefined, { lowerCaseGuids: false });
687+
});
688+
689+
it('UniqueIdentifier as output parameter when `lowerCaseGuids` option is `true`', function(done) {
690+
execSqlOutput(done, TYPES.UniqueIdentifier, '01234567-89ab-cdef-0123-456789abcdef', undefined, { lowerCaseGuids: true });
671691
});
672692

673693
it('should output int null', function(done) {

test/unit/guid-parser-test.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,10 +167,17 @@ describe('Guid Parser Test', function() {
167167
}
168168
});
169169

170-
it('arrayToGuid', () => {
170+
it('arrayToLowerCaseGuid', () => {
171171
for (let i = 0; i < arrays.length; i++) {
172172
const array = arrays[i];
173-
assert.strictEqual(guidParser.arrayToGuid(array), upperGuids[i]);
173+
assert.strictEqual(guidParser.arrayToLowerCaseGuid(array), lowerGuids[i]);
174+
}
175+
});
176+
177+
it('arrayToUpperCaseGuid', () => {
178+
for (let i = 0; i < arrays.length; i++) {
179+
const array = arrays[i];
180+
assert.strictEqual(guidParser.arrayToUpperCaseGuid(array), upperGuids[i]);
174181
}
175182
});
176183
});

test/unit/token/row-token-parser-test.js

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -601,7 +601,7 @@ describe('Row Token Parser', () => {
601601
assert.strictEqual('10000', token.columns[11].value);
602602
});
603603

604-
it('should write guidN', () => {
604+
it('parsing a UniqueIdentifier value when `lowerCaseGuids` option is `false`', () => {
605605
const colMetaData = [
606606
{ type: dataTypeByName.UniqueIdentifier },
607607
{ type: dataTypeByName.UniqueIdentifier }
@@ -633,9 +633,9 @@ describe('Row Token Parser', () => {
633633
);
634634
// console.log(buffer.data)
635635

636-
const parser = new Parser({ token() { } }, colMetaData, options);
636+
const parser = new Parser({ token() {} }, colMetaData, Object.assign({ lowerCaseGuids: false }, options));
637637
parser.write(buffer.data);
638-
const token = parser.read();
638+
var token = parser.read();
639639
// console.log(token)
640640

641641
assert.strictEqual(token.columns.length, 2);
@@ -646,6 +646,50 @@ describe('Row Token Parser', () => {
646646
);
647647
});
648648

649+
it('parsing a UniqueIdentifier value when `lowerCaseGuids` option is `true`', () => {
650+
var colMetaData = [
651+
{ type: dataTypeByName.UniqueIdentifier },
652+
{ type: dataTypeByName.UniqueIdentifier }
653+
];
654+
655+
var buffer = new WritableTrackingBuffer(0, 'ucs2');
656+
buffer.writeUInt8(0xd1);
657+
buffer.writeBuffer(
658+
Buffer.from([
659+
0,
660+
16,
661+
0x01,
662+
0x23,
663+
0x45,
664+
0x67,
665+
0x89,
666+
0xab,
667+
0xcd,
668+
0xef,
669+
0x01,
670+
0x23,
671+
0x45,
672+
0x67,
673+
0x89,
674+
0xab,
675+
0xcd,
676+
0xef
677+
])
678+
);
679+
// console.log(buffer.data)
680+
const parser = new Parser({ token() {} }, colMetaData, Object.assign({ lowerCaseGuids: true }, options));
681+
parser.write(buffer.data);
682+
const token = parser.read();
683+
// console.log(token)
684+
685+
assert.strictEqual(token.columns.length, 2);
686+
assert.strictEqual(token.columns[0].value, null);
687+
assert.deepEqual(
688+
'67452301-ab89-efcd-0123-456789abcdef',
689+
token.columns[1].value
690+
);
691+
});
692+
649693
it('should write floatN', () => {
650694
const colMetaData = [
651695
{ type: FloatN },

0 commit comments

Comments
 (0)