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..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,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..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,13 +428,28 @@ export function assertValidNanosecond ( ) } +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 { + const cachedResult = timeZoneValidityCache.get(zoneId) + + if (cachedResult === true) { + return + } + + if (cachedResult === false) { + throw newInvalidZoneIdError(zoneId, fieldName) + } + try { Intl.DateTimeFormat(undefined, { timeZone: zoneId }) + timeZoneValidityCache.set(zoneId, true) } catch (e) { - throw newError( - `${fieldName} is expected to be a valid ZoneId but was: "${zoneId}"` - ) + timeZoneValidityCache.set(zoneId, false) + throw newInvalidZoneIdError(zoneId, fieldName) } } 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..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,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..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,13 +428,28 @@ export function assertValidNanosecond ( ) } +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 { + const cachedResult = timeZoneValidityCache.get(zoneId) + + if (cachedResult === true) { + return + } + + if (cachedResult === false) { + throw newInvalidZoneIdError(zoneId, fieldName) + } + try { Intl.DateTimeFormat(undefined, { timeZone: zoneId }) + timeZoneValidityCache.set(zoneId, true) } catch (e) { - throw newError( - `${fieldName} is expected to be a valid ZoneId but was: "${zoneId}"` - ) + timeZoneValidityCache.set(zoneId, false) + throw newInvalidZoneIdError(zoneId, fieldName) } } 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