Skip to content

Commit 17cb5ed

Browse files
authored
update to node 16, FIX HASHER BUG (#84)
Problem ======= We need to update to Node16+ as 15.* is @ end-of-life. Closes #62, Fixes #85, a hasher bug Solution ======== Update to nodejs 16.15.1, update some packages and fix anything broken. **Important:** This revealed a bug in the Xxhasher code that was not converting to hex-encoded strings as the [bloom filter expects](https://github.com/LibertyDSNP/parquetjs/blob/2c733b5c7a647b9a8ebe9a13d300f41537ef60e2/lib/bloom/sbbf.ts#L357)
1 parent b5698e4 commit 17cb5ed

13 files changed

+1286
-1688
lines changed

.github/workflows/main.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ jobs:
1414
- name: Use Node.js
1515
uses: actions/setup-node@v2
1616
with:
17-
node-version: '14.16.0'
17+
node-version: '16.15.1'
1818

1919
- uses: actions/cache@v2
2020
with:

.github/workflows/publish-next.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ jobs:
1212
- name: Use Node.js
1313
uses: actions/setup-node@v2
1414
with:
15-
node-version: '14.16.0'
15+
node-version: '16.15.1'
1616
registry-url: 'https://registry.npmjs.org'
1717

1818
- uses: actions/cache@v2

.github/workflows/release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ jobs:
1212
- name: Use Node.js
1313
uses: actions/setup-node@v2
1414
with:
15-
node-version: '14.16.0'
15+
node-version: '16.15.1'
1616
registry-url: 'https://registry.npmjs.org'
1717

1818
- uses: actions/cache@v2

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
.DS_STORE
12
node_modules
23
*.parquet
34
npm-debug.log

.tool-versions

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
nodejs 15.12.0
1+
nodejs 16.15.1

lib/bloom/xxhasher.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,27 +14,28 @@ type HasherFunc = (input: string, seedHigh?: number, seedLow?: number) => string
1414
* [xxHash spec](https://github.com/Cyan4973/xxHash/blob/v0.7.0/doc/xxhash_spec.md)
1515
*/
1616
export default class XxHasher {
17-
private static h64 = xxhash().then(x => x.h64)
17+
private static h64 = xxhash().then(x => x.h64ToString)
1818

19-
private async hashit(value: string): Promise<string> {
19+
private async hashIt(value: string): Promise<string> {
2020
return (await XxHasher.h64)(value)
2121
}
2222

2323
/**
2424
* @function hash64
25-
* @description creates a hash for certain data types.
26-
* @return the 64 big XXHash as a string
27-
* @param value one of n, throw an error.
25+
* @description creates a hash for certain data types. All data is converted using toString()
26+
* prior to hashing.
27+
* @return the 64 big XXHash as a hex-encoded string.
28+
* @param value, must be of type string, Buffer, Uint8Array, Long, boolean, number, or bigint
2829
*/
2930
async hash64(value: any): Promise<string> {
30-
if (typeof value === 'string') return this.hashit(value)
31+
if (typeof value === 'string') return this.hashIt(value)
3132
if (value instanceof Buffer ||
3233
value instanceof Uint8Array ||
3334
value instanceof Long ||
3435
typeof value === 'boolean' ||
3536
typeof value === 'number' ||
3637
typeof value === 'bigint') {
37-
return this.hashit(value.toString())
38+
return this.hashIt(value.toString())
3839
}
3940
throw new Error("unsupported type: " + value)
4041
}

lib/types.ts

Lines changed: 22 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -386,25 +386,34 @@ function fromPrimitive_BSON(value: Buffer) {
386386
return BSON.deserialize(value);
387387
}
388388

389-
function toPrimitive_TIME_MILLIS(value: string | number) {
390-
let v = value
391-
if (typeof value === `string`) {
392-
v = parseInt(value, 10);
389+
function toNumberInternal(typeName: string, value: string | number): number {
390+
let numberValue = 0;
391+
switch (typeof value) {
392+
case "string":
393+
numberValue = parseInt(value, 10);
394+
break;
395+
case "number":
396+
numberValue = value;
397+
break;
398+
default:
399+
throw `${typeName} has an invalid type: ${typeof value}`;
393400
}
394401
// Year 2255 bug. Should eventually switch to bigint
395-
if (v < 0 || v > (Number.MAX_SAFE_INTEGER - 1) || typeof v !== 'number') {
396-
throw 'invalid value for TIME_MILLIS: ' + value;
402+
if (numberValue < 0 || numberValue >= Number.MAX_SAFE_INTEGER) {
403+
throw `${typeName} value is out of bounds: ${numberValue}`;
397404
}
405+
return numberValue
406+
}
398407

399-
return v;
408+
function toPrimitive_TIME_MILLIS(value: string | number) {
409+
return toNumberInternal("TIME_MILLIS", value);
400410
}
401411

402412
function toPrimitive_TIME_MICROS(value: string | number | bigint) {
403413
const v = BigInt(value);
404414
if (v < 0n ) {
405-
throw 'invalid value for TIME_MICROS: ' + value;
415+
throw 'TIME_MICROS value is out of bounds: ' + value;
406416
}
407-
408417
return v;
409418
}
410419

@@ -415,19 +424,7 @@ function toPrimitive_DATE(value: string | Date | number) {
415424
if (value instanceof Date) {
416425
return value.getTime() / kMillisPerDay;
417426
}
418-
419-
/* convert from integer */
420-
let v = value
421-
if (typeof value === 'string') {
422-
v = parseInt(value, 10);
423-
}
424-
425-
if (v < 0 || typeof v !== 'number') {
426-
throw 'invalid value for DATE: ' + value;
427-
}
428-
429-
return v;
430-
427+
return toNumberInternal("DATE", value )
431428
}
432429

433430
function fromPrimitive_DATE(value: number ) {
@@ -440,20 +437,7 @@ function toPrimitive_TIMESTAMP_MILLIS(value: string | Date | number) {
440437
if (value instanceof Date) {
441438
return value.getTime();
442439
}
443-
444-
/* convert from integer */
445-
446-
let v = value
447-
if (typeof value === 'string' ) {
448-
v = parseInt(value, 10);
449-
}
450-
451-
if (v < 0 || typeof v !== 'number') {
452-
throw 'invalid value for TIMESTAMP_MILLIS: ' + value;
453-
}
454-
455-
return v;
456-
440+
return toNumberInternal("TIMESTAMP_MILLIS", value);
457441
}
458442

459443
function fromPrimitive_TIMESTAMP_MILLIS(value: number | string | bigint) {
@@ -471,12 +455,12 @@ function toPrimitive_TIMESTAMP_MICROS(value: Date | string | number | bigint) {
471455
// Will throw if NaN
472456
const v = BigInt(value);
473457
if (v < 0n) {
474-
throw 'Cannot be less than zero';
458+
throw 'out of bounds';
475459
}
476460

477461
return v;
478462
} catch (e) {
479-
throw 'invalid value for TIMESTAMP_MICROS: ' + value;
463+
throw 'TIMESTAMP_MICROS value is out of bounds: ' + value;
480464
}
481465
}
482466

lib/util.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ export const osend = function(os: WriteStreamMinimal) {
174174
});
175175
}
176176

177-
export const osopen = function(path: string | Buffer | URL, opts?: string | WriterOptions): Promise<WriteStream> {
177+
export const osopen = function(path: string | Buffer | URL, opts?: WriterOptions): Promise<WriteStream> {
178178
return new Promise((resolve, reject) => {
179179
let outputStream = fs.createWriteStream(path, opts);
180180

0 commit comments

Comments
 (0)