From ed92bb552257ca1b34e6c5d9126b9c47f1e24843 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dirk=20von=20Gr=C3=BCnigen?= Date: Mon, 22 Jan 2024 00:16:54 +0100 Subject: [PATCH 1/4] Add bash version of the run tests script --- runTests.sh | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100755 runTests.sh diff --git a/runTests.sh b/runTests.sh new file mode 100755 index 000000000..0c7562163 --- /dev/null +++ b/runTests.sh @@ -0,0 +1,26 @@ +npm install -g gulp typescript jest + +npm ci +npm run build -- --no-private + +if [ -n "$2" ]; then + export NEOCTRL_ARGS="$2" +fi + +trap "npm run stop-neo4j" EXIT + +npm run start-neo4j + +if [ $? -ne 0 ]; then + echo "Unable to start neo4j" + exit 1 +fi + +npm test -- --no-private + +if [ $? -eq 0 ]; then + echo "Exit with code 0" +else + echo "Exit with code 1" + exit 1 +fi From e3bf7d0eaeb61b96b0269df77b21f5e34952ac82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dirk=20von=20Gr=C3=BCnigen?= Date: Mon, 22 Jan 2024 00:18:53 +0100 Subject: [PATCH 2/4] Use a map to cache certain objects created via the Intl API to prevent performance degradation for results with lots of datetime values --- .../bolt-protocol-v5x0.utc.transformer.js | 34 +++++++++++++------ packages/core/src/internal/temporal-util.ts | 13 +++++-- .../bolt-protocol-v5x0.utc.transformer.js | 34 +++++++++++++------ .../lib/core/internal/temporal-util.ts | 13 +++++-- 4 files changed, 66 insertions(+), 28 deletions(-) diff --git a/packages/bolt-connection/src/bolt/bolt-protocol-v5x0.utc.transformer.js b/packages/bolt-connection/src/bolt/bolt-protocol-v5x0.utc.transformer.js index b080273ef..f40b05ab5 100644 --- a/packages/bolt-connection/src/bolt/bolt-protocol-v5x0.utc.transformer.js +++ b/packages/bolt-connection/src/bolt/bolt-protocol-v5x0.utc.transformer.js @@ -157,18 +157,30 @@ function getOffsetFromZoneId (timeZoneId, epochSecond, nanosecond) { return offset } +const dateTimeFormatCache = new Map(); + +function getDateTimeFormatForZoneId(timeZoneId) { + if (!dateTimeFormatCache.has(timeZoneId)) { + const formatter = new Intl.DateTimeFormat('en-US', { + timeZone: timeZoneId, + year: 'numeric', + month: 'numeric', + day: 'numeric', + hour: 'numeric', + minute: 'numeric', + second: 'numeric', + hour12: false, + era: 'narrow' + }) + + dateTimeFormatCache.set(timeZoneId, formatter) + } + + return dateTimeFormatCache.get(timeZoneId) +} + function getTimeInZoneId (timeZoneId, epochSecond, nano) { - const formatter = new Intl.DateTimeFormat('en-US', { - timeZone: timeZoneId, - year: 'numeric', - month: 'numeric', - day: 'numeric', - hour: 'numeric', - minute: 'numeric', - second: 'numeric', - hour12: false, - era: 'narrow' - }) + const formatter = getDateTimeFormatForZoneId(timeZoneId) const utc = int(epochSecond) .multiply(1000) diff --git a/packages/core/src/internal/temporal-util.ts b/packages/core/src/internal/temporal-util.ts index 34416c4e0..494ca40ee 100644 --- a/packages/core/src/internal/temporal-util.ts +++ b/packages/core/src/internal/temporal-util.ts @@ -428,13 +428,20 @@ export function assertValidNanosecond ( ) } -export function assertValidZoneId (fieldName: string, zoneId: string): void { +const timeZoneValidityCache = new Map(); + +export function assertValidZoneId(fieldName: string, zoneId: string): void { + let result = false; + try { - Intl.DateTimeFormat(undefined, { timeZone: zoneId }) + if (timeZoneValidityCache.get(zoneId)) return; + result = !!Intl.DateTimeFormat(undefined, { timeZone: zoneId }); } catch (e) { throw newError( `${fieldName} is expected to be a valid ZoneId but was: "${zoneId}"` - ) + ); + } finally { + timeZoneValidityCache.set(zoneId, result) } } diff --git a/packages/neo4j-driver-deno/lib/bolt-connection/bolt/bolt-protocol-v5x0.utc.transformer.js b/packages/neo4j-driver-deno/lib/bolt-connection/bolt/bolt-protocol-v5x0.utc.transformer.js index b76c9ca30..595c66a21 100644 --- a/packages/neo4j-driver-deno/lib/bolt-connection/bolt/bolt-protocol-v5x0.utc.transformer.js +++ b/packages/neo4j-driver-deno/lib/bolt-connection/bolt/bolt-protocol-v5x0.utc.transformer.js @@ -157,18 +157,30 @@ function getOffsetFromZoneId (timeZoneId, epochSecond, nanosecond) { return offset } +const dateTimeFormatCache = new Map(); + +function getDateTimeFormatForZoneId(timeZoneId) { + if (!dateTimeFormatCache.has(timeZoneId)) { + const formatter = new Intl.DateTimeFormat('en-US', { + timeZone: timeZoneId, + year: 'numeric', + month: 'numeric', + day: 'numeric', + hour: 'numeric', + minute: 'numeric', + second: 'numeric', + hour12: false, + era: 'narrow' + }) + + dateTimeFormatCache.set(timeZoneId, formatter) + } + + return dateTimeFormatCache.get(timeZoneId) +} + function getTimeInZoneId (timeZoneId, epochSecond, nano) { - const formatter = new Intl.DateTimeFormat('en-US', { - timeZone: timeZoneId, - year: 'numeric', - month: 'numeric', - day: 'numeric', - hour: 'numeric', - minute: 'numeric', - second: 'numeric', - hour12: false, - era: 'narrow' - }) + const formatter = getDateTimeFormatForZoneId(timeZoneId) const utc = int(epochSecond) .multiply(1000) diff --git a/packages/neo4j-driver-deno/lib/core/internal/temporal-util.ts b/packages/neo4j-driver-deno/lib/core/internal/temporal-util.ts index 95cfb531d..d79b24de5 100644 --- a/packages/neo4j-driver-deno/lib/core/internal/temporal-util.ts +++ b/packages/neo4j-driver-deno/lib/core/internal/temporal-util.ts @@ -428,13 +428,20 @@ export function assertValidNanosecond ( ) } -export function assertValidZoneId (fieldName: string, zoneId: string): void { +const timeZoneValidityCache = new Map(); + +export function assertValidZoneId(fieldName: string, zoneId: string): void { + let result = false + try { - Intl.DateTimeFormat(undefined, { timeZone: zoneId }) + if (timeZoneValidityCache.get(zoneId)) return + result = !!Intl.DateTimeFormat(undefined, { timeZone: zoneId }) } catch (e) { throw newError( `${fieldName} is expected to be a valid ZoneId but was: "${zoneId}"` - ) + ); + } finally { + timeZoneValidityCache.set(zoneId, result) } } From 5a87885469fa243a9de1e4cd04c23b071b320858 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dirk=20von=20Gr=C3=BCnigen?= Date: Sat, 27 Jan 2024 22:07:28 +0100 Subject: [PATCH 3/4] Simplify `assertValidZoneId` and and fix linter errors --- .../bolt-protocol-v5x0.utc.transformer.js | 4 +-- packages/core/src/internal/temporal-util.ts | 30 ++++++++++++------- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/packages/bolt-connection/src/bolt/bolt-protocol-v5x0.utc.transformer.js b/packages/bolt-connection/src/bolt/bolt-protocol-v5x0.utc.transformer.js index f40b05ab5..bd2a72ed7 100644 --- a/packages/bolt-connection/src/bolt/bolt-protocol-v5x0.utc.transformer.js +++ b/packages/bolt-connection/src/bolt/bolt-protocol-v5x0.utc.transformer.js @@ -157,9 +157,9 @@ function getOffsetFromZoneId (timeZoneId, epochSecond, nanosecond) { return offset } -const dateTimeFormatCache = new Map(); +const dateTimeFormatCache = new Map() -function getDateTimeFormatForZoneId(timeZoneId) { +function getDateTimeFormatForZoneId (timeZoneId) { if (!dateTimeFormatCache.has(timeZoneId)) { const formatter = new Intl.DateTimeFormat('en-US', { timeZone: timeZoneId, diff --git a/packages/core/src/internal/temporal-util.ts b/packages/core/src/internal/temporal-util.ts index 494ca40ee..2951d5ac5 100644 --- a/packages/core/src/internal/temporal-util.ts +++ b/packages/core/src/internal/temporal-util.ts @@ -16,7 +16,7 @@ */ import Integer, { int, isInt } from '../integer' -import { newError } from '../error' +import { Neo4jError, newError } from '../error' import { assertNumberOrInteger } from './util' import { NumberOrInteger } from '../graph-types' @@ -428,20 +428,28 @@ export function assertValidNanosecond ( ) } -const timeZoneValidityCache = new Map(); +const timeZoneValidityCache = new Map() +const newInvalidZoneIdError = (zoneId: string, fieldName: string): Neo4jError => newError( + `${fieldName} is expected to be a valid ZoneId but was: "${zoneId}"` +) -export function assertValidZoneId(fieldName: string, zoneId: string): void { - let result = false; +export function assertValidZoneId (fieldName: string, zoneId: string): void { + const cachedResult = timeZoneValidityCache.get(zoneId) + + if (cachedResult === true) { + return + } + + if (cachedResult === false) { + throw newInvalidZoneIdError(zoneId, fieldName) + } try { - if (timeZoneValidityCache.get(zoneId)) return; - result = !!Intl.DateTimeFormat(undefined, { timeZone: zoneId }); + Intl.DateTimeFormat(undefined, { timeZone: zoneId }) + timeZoneValidityCache.set(zoneId, true) } catch (e) { - throw newError( - `${fieldName} is expected to be a valid ZoneId but was: "${zoneId}"` - ); - } finally { - timeZoneValidityCache.set(zoneId, result) + timeZoneValidityCache.set(zoneId, false) + throw newInvalidZoneIdError(zoneId, fieldName) } } From 2d6db6e484f1d6c312fb3f29f5b3313b086f9f0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dirk=20von=20Gr=C3=BCnigen?= Date: Sun, 28 Jan 2024 00:27:39 +0100 Subject: [PATCH 4/4] Run build to sync deno driver --- .../bolt-protocol-v5x0.utc.transformer.js | 4 +-- .../lib/core/internal/temporal-util.ts | 30 ++++++++++++------- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/packages/neo4j-driver-deno/lib/bolt-connection/bolt/bolt-protocol-v5x0.utc.transformer.js b/packages/neo4j-driver-deno/lib/bolt-connection/bolt/bolt-protocol-v5x0.utc.transformer.js index 595c66a21..dec7863ab 100644 --- a/packages/neo4j-driver-deno/lib/bolt-connection/bolt/bolt-protocol-v5x0.utc.transformer.js +++ b/packages/neo4j-driver-deno/lib/bolt-connection/bolt/bolt-protocol-v5x0.utc.transformer.js @@ -157,9 +157,9 @@ function getOffsetFromZoneId (timeZoneId, epochSecond, nanosecond) { return offset } -const dateTimeFormatCache = new Map(); +const dateTimeFormatCache = new Map() -function getDateTimeFormatForZoneId(timeZoneId) { +function getDateTimeFormatForZoneId (timeZoneId) { if (!dateTimeFormatCache.has(timeZoneId)) { const formatter = new Intl.DateTimeFormat('en-US', { timeZone: timeZoneId, diff --git a/packages/neo4j-driver-deno/lib/core/internal/temporal-util.ts b/packages/neo4j-driver-deno/lib/core/internal/temporal-util.ts index d79b24de5..be1961ec8 100644 --- a/packages/neo4j-driver-deno/lib/core/internal/temporal-util.ts +++ b/packages/neo4j-driver-deno/lib/core/internal/temporal-util.ts @@ -16,7 +16,7 @@ */ import Integer, { int, isInt } from '../integer.ts' -import { newError } from '../error.ts' +import { Neo4jError, newError } from '../error.ts' import { assertNumberOrInteger } from './util.ts' import { NumberOrInteger } from '../graph-types.ts' @@ -428,20 +428,28 @@ export function assertValidNanosecond ( ) } -const timeZoneValidityCache = new Map(); +const timeZoneValidityCache = new Map() +const newInvalidZoneIdError = (zoneId: string, fieldName: string): Neo4jError => newError( + `${fieldName} is expected to be a valid ZoneId but was: "${zoneId}"` +) -export function assertValidZoneId(fieldName: string, zoneId: string): void { - let result = false +export function assertValidZoneId (fieldName: string, zoneId: string): void { + const cachedResult = timeZoneValidityCache.get(zoneId) + + if (cachedResult === true) { + return + } + + if (cachedResult === false) { + throw newInvalidZoneIdError(zoneId, fieldName) + } try { - if (timeZoneValidityCache.get(zoneId)) return - result = !!Intl.DateTimeFormat(undefined, { timeZone: zoneId }) + Intl.DateTimeFormat(undefined, { timeZone: zoneId }) + timeZoneValidityCache.set(zoneId, true) } catch (e) { - throw newError( - `${fieldName} is expected to be a valid ZoneId but was: "${zoneId}"` - ); - } finally { - timeZoneValidityCache.set(zoneId, result) + timeZoneValidityCache.set(zoneId, false) + throw newInvalidZoneIdError(zoneId, fieldName) } }