Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: neo4j/neo4j-javascript-driver
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 4.4.7
Choose a base ref
...
head repository: neo4j/neo4j-javascript-driver
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 4.4
Choose a head ref
  • 13 commits
  • 30 files changed
  • 6 contributors

Commits on Sep 6, 2022

  1. Fix serialization of broken objects in the driver logs (#983)

    * Fix serialization of broken objects in the driver logs
    
    Trying to logging broken objects was causing the driver fails in unexpected moments.
    This broken behaviour makes the driver fail different when the `debug` log is enabled.
    
    Co-authored-by: Robsdedude <[email protected]>
    bigmontz and robsdedude authored Sep 6, 2022

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    99a58d2 View commit details
  2. Fix Zoned DateTime support for dates before common era (#986)

    Years previous the common era were being treated as positive numbers causing the dates appear
    as positive numbers and breaking the auto-zone offset detection for zoned date times which were
    not created with the offset.
    bigmontz committed Sep 6, 2022
    Copy the full SHA
    7525da3 View commit details
  3. Add stricter string validation to neo4j.int (#985)

    `neo4j.int` could have some surprising result when used with string. For avoiding this problem,
    a configuration option called `strictStringValidation` was added. When enable, `strictStringValidation` will trigger a deeper validation of the string. This option could slow down the conversion.
    
    Co-authored-by: Oskar Damkjaer <[email protected]>
    bigmontz and OskarDamkjaer committed Sep 6, 2022
    Copy the full SHA
    29a1b2f View commit details

Commits on Sep 9, 2022

  1. Fix DateTime with ZoneId for years between 00-99 #992 (#991)

    The error was happening because Date.UTC factory doesn't treats dates between 00-99 as 1900-1999.
    
    Removing the usage of this factory makes the code slightly faster while resolves the issue.
    bigmontz authored Sep 9, 2022

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    8a55f99 View commit details

Commits on Sep 12, 2022

  1. Improve purge address of the Pool routine (#994)

    In Browser environments, the WebSocket release can take seconds to finish.
    This behaviour can make LDAP authentication expired take more time then usual.
    
    Purging the connection in parallel speeds up this process.
    bigmontz authored Sep 12, 2022

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    c82c716 View commit details

Commits on Sep 14, 2022

  1. Fix TestKit backend startup for nodejs >10 (#996)

    Co-authored-by: Antonio Barcelos <[email protected]>
    robsdedude and bigmontz authored Sep 14, 2022

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    4bdeed2 View commit details

Commits on Sep 21, 2022

  1. Add property-based testing to temporal-types conversion (#997)

    Add this type of testing to `.toString()` ('should be serialize string which can be loaded by new Date') helps to cover corner cases and solve special cases such:
    
    * Negative date time not being serialised correctly in the iso standard. Years should always have 6 digits and the signal in front for working correctly with negative years and high numbers. This also avoids the year 2000 problem. See, https://en.wikipedia.org/wiki/ISO_8601
    * `Date.fromStandardDate` factory was not taking in consideration the `seconds` contribution in the timezone offset. This is not a quite common scenario, but there are dates with timezone offset of for example `50 minutes` and `20 seconds`.
    * Fix `Date.toString` for dates with offsets of seconds. Javascript Date constructor doesn't create dates from iso strings with seconds in the offset. For instance, `new Date("2010-01-12T14:44:53+00:00:10")`. So, this tests should be skipped.
    
    Co-authored-by: Robsdedude <[email protected]>
    bigmontz and robsdedude authored Sep 21, 2022

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    fdd043c View commit details

Commits on Apr 14, 2023

  1. Fix chown command in Testkit docker file (#1078)

    Signed-off-by: Conor Watson <[email protected]>
    robsdedude authored Apr 14, 2023

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    6fb7fff View commit details

Commits on Jun 16, 2023

  1. Fix DateTime with ZoneId unpacking (#1098)

    The timezone offset was miss-calculated because of an error on extracting timezone information when the hour equals to `0`.
    The problems happens because `Intl.DateTimeFormat` when configured with `hour12: false` returns `0` hour as `24`.
    
    The solution for this is convert `24` to `0` before calculate the `offset`.
    
    NOTE:
    Other valid solution would be change `hourCycle` to `h23`.
    However, this solution is not supported by all javascript environment.
    bigmontz authored Jun 16, 2023

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    0436752 View commit details

Commits on Aug 4, 2023

  1. Reduce number of ROUTE requests when routing table is stale (#1119)

    The driver was starting a rediscovery process of each acquireConnection causing more load than needed in the cluster. Keeping track of the ongoing requests and use it when possible reduces the load in the process and speeds up the connection acquisition.
    
    Co-authored-by: Robsdedude <[email protected]>
    bigmontz and robsdedude committed Aug 4, 2023
    Copy the full SHA
    6b8a899 View commit details

Commits on Apr 7, 2025

  1. fix: upgrade @babel/runtime from 7.13.10 to 7.26.10 (#1267)

    Snyk has created this PR to upgrade @babel/runtime from 7.13.10 to 7.26.10.
    
    See this package in npm:
    @babel/runtime
    
    See this project in Snyk:
    https://app.snyk.io/org/drivers-b9e/project/b4e2b50b-e8e2-44d8-b08e-f95ea565bc28?utm_source=github&utm_medium=referral&page=upgrade-pr
    
    Co-authored-by: snyk-bot <[email protected]>
    robsdedude and snyk-bot authored Apr 7, 2025

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    d6d78c0 View commit details

Commits on Apr 15, 2025

  1. Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    a931816 View commit details

Commits on May 12, 2025

  1. Fix logging of driver errors containing bigints in testkit backend (#…

    …1280)
    
    The JavaScript driver testkit backend handles all ints as bigints, when these end up in some errors (as in syntax errors on 2025.x servers) they cause the backend to crash. This commit solves the issue by using a replacer function.
    MaxAake authored May 12, 2025

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    12eef00 View commit details
Showing with 1,077 additions and 172 deletions.
  1. +35 −37 packages/bolt-connection/src/connection-provider/connection-provider-routing.js
  2. +58 −0 packages/bolt-connection/src/lang/functional.js
  3. +19 −0 packages/bolt-connection/src/lang/index.js
  4. +16 −11 packages/bolt-connection/src/packstream/packstream-utc.js
  5. +2 −2 packages/bolt-connection/src/packstream/packstream-v1.js
  6. +3 −1 packages/bolt-connection/src/pool/pool.js
  7. +170 −0 packages/bolt-connection/test/lang/functional.test.js
  8. +16 −0 packages/bolt-connection/test/packstream/packstream-v2.test.js
  9. +37 −0 packages/bolt-connection/test/pool/pool.test.js
  10. +15 −0 packages/core/package-lock.json
  11. +1 −0 packages/core/package.json
  12. +6 −0 packages/core/src/driver.ts
  13. +46 −6 packages/core/src/integer.ts
  14. +3 −1 packages/core/src/internal/index.ts
  15. +87 −0 packages/core/src/internal/object-util.ts
  16. +58 −14 packages/core/src/internal/temporal-util.ts
  17. +1 −32 packages/core/src/internal/util.ts
  18. +15 −4 packages/core/src/json.ts
  19. +13 −0 packages/core/test/__snapshots__/json.test.ts.snap
  20. +122 −0 packages/core/test/integer.test.ts
  21. +67 −0 packages/core/test/internal/object-util.test.ts
  22. +69 −0 packages/core/test/json.test.ts
  23. +96 −0 packages/core/test/temporal-types.test.ts
  24. +68 −46 packages/neo4j-driver/package-lock.json
  25. +1 −1 packages/neo4j-driver/package.json
  26. +4 −4 packages/neo4j-driver/test/internal/temporal-util.test.js
  27. +44 −9 packages/neo4j-driver/test/temporal-types.test.js
  28. +1 −1 packages/testkit-backend/package.json
  29. +3 −2 packages/testkit-backend/src/request-handlers.js
  30. +1 −1 testkit/Dockerfile
Original file line number Diff line number Diff line change
@@ -28,6 +28,7 @@ import {
ConnectionErrorHandler,
DelegateConnection
} from '../connection'
import { functional } from '../lang'

const { SERVICE_UNAVAILABLE, SESSION_EXPIRED } = error
const {
@@ -85,6 +86,8 @@ export default class RoutingConnectionProvider extends PooledConnectionProvider
? int(routingTablePurgeDelay)
: DEFAULT_ROUTING_TABLE_PURGE_DELAY
)

this._refreshRoutingTable = functional.reuseOngoingRequest(this._refreshRoutingTable, this)
}

_createConnectionErrorHandler () {
@@ -140,7 +143,7 @@ export default class RoutingConnectionProvider extends PooledConnectionProvider
const routingTable = await this._freshRoutingTable({
accessMode,
database: context.database,
bookmark: bookmarks,
bookmarks,
impersonatedUser,
onDatabaseNameResolved: (databaseName) => {
context.database = context.database || databaseName
@@ -259,7 +262,7 @@ export default class RoutingConnectionProvider extends PooledConnectionProvider
return this._connectionPool.acquire(address)
}

_freshRoutingTable ({ accessMode, database, bookmark, impersonatedUser, onDatabaseNameResolved } = {}) {
_freshRoutingTable ({ accessMode, database, bookmarks, impersonatedUser, onDatabaseNameResolved } = {}) {
const currentRoutingTable = this._routingTableRegistry.get(
database,
() => new RoutingTable({ database })
@@ -271,44 +274,45 @@ export default class RoutingConnectionProvider extends PooledConnectionProvider
this._log.info(
`Routing table is stale for database: "${database}" and access mode: "${accessMode}": ${currentRoutingTable}`
)
return this._refreshRoutingTable(currentRoutingTable, bookmark, impersonatedUser, onDatabaseNameResolved)
return this._refreshRoutingTable(currentRoutingTable, bookmarks, impersonatedUser)
.then(newRoutingTable => {
onDatabaseNameResolved(newRoutingTable.database)
return newRoutingTable
})
}

_refreshRoutingTable (currentRoutingTable, bookmark, impersonatedUser, onDatabaseNameResolved) {
_refreshRoutingTable (currentRoutingTable, bookmarks, impersonatedUser) {
const knownRouters = currentRoutingTable.routers

if (this._useSeedRouter) {
return this._fetchRoutingTableFromSeedRouterFallbackToKnownRouters(
knownRouters,
currentRoutingTable,
bookmark,
impersonatedUser,
onDatabaseNameResolved
bookmarks,
impersonatedUser
)
}
return this._fetchRoutingTableFromKnownRoutersFallbackToSeedRouter(
knownRouters,
currentRoutingTable,
bookmark,
impersonatedUser,
onDatabaseNameResolved
bookmarks,
impersonatedUser
)
}

async _fetchRoutingTableFromSeedRouterFallbackToKnownRouters (
knownRouters,
currentRoutingTable,
bookmark,
impersonatedUser,
onDatabaseNameResolved
bookmarks,
impersonatedUser
) {
// we start with seed router, no routers were probed before
const seenRouters = []
let newRoutingTable = await this._fetchRoutingTableUsingSeedRouter(
seenRouters,
this._seedRouter,
currentRoutingTable,
bookmark,
bookmarks,
impersonatedUser
)

@@ -319,29 +323,27 @@ export default class RoutingConnectionProvider extends PooledConnectionProvider
newRoutingTable = await this._fetchRoutingTableUsingKnownRouters(
knownRouters,
currentRoutingTable,
bookmark,
bookmarks,
impersonatedUser
)
}

return await this._applyRoutingTableIfPossible(
currentRoutingTable,
newRoutingTable,
onDatabaseNameResolved
newRoutingTable
)
}

async _fetchRoutingTableFromKnownRoutersFallbackToSeedRouter (
knownRouters,
currentRoutingTable,
bookmark,
bookmarks,
impersonatedUser,
onDatabaseNameResolved
) {
let newRoutingTable = await this._fetchRoutingTableUsingKnownRouters(
knownRouters,
currentRoutingTable,
bookmark,
bookmarks,
impersonatedUser
)

@@ -351,28 +353,27 @@ export default class RoutingConnectionProvider extends PooledConnectionProvider
knownRouters,
this._seedRouter,
currentRoutingTable,
bookmark,
bookmarks,
impersonatedUser
)
}

return await this._applyRoutingTableIfPossible(
currentRoutingTable,
newRoutingTable,
onDatabaseNameResolved
newRoutingTable
)
}

async _fetchRoutingTableUsingKnownRouters (
knownRouters,
currentRoutingTable,
bookmark,
bookmarks,
impersonatedUser
) {
const newRoutingTable = await this._fetchRoutingTable(
knownRouters,
currentRoutingTable,
bookmark,
bookmarks,
impersonatedUser
)

@@ -397,7 +398,7 @@ export default class RoutingConnectionProvider extends PooledConnectionProvider
seenRouters,
seedRouter,
routingTable,
bookmark,
bookmarks,
impersonatedUser
) {
const resolvedAddresses = await this._resolveSeedRouter(seedRouter)
@@ -407,7 +408,7 @@ export default class RoutingConnectionProvider extends PooledConnectionProvider
address => seenRouters.indexOf(address) < 0
)

return await this._fetchRoutingTable(newAddresses, routingTable, bookmark, impersonatedUser)
return await this._fetchRoutingTable(newAddresses, routingTable, bookmarks, impersonatedUser)
}

async _resolveSeedRouter (seedRouter) {
@@ -419,7 +420,7 @@ export default class RoutingConnectionProvider extends PooledConnectionProvider
return [].concat.apply([], dnsResolvedAddresses)
}

_fetchRoutingTable (routerAddresses, routingTable, bookmark, impersonatedUser) {
_fetchRoutingTable (routerAddresses, routingTable, bookmarks, impersonatedUser) {
return routerAddresses.reduce(
async (refreshedTablePromise, currentRouter, currentIndex) => {
const newRoutingTable = await refreshedTablePromise
@@ -441,7 +442,7 @@ export default class RoutingConnectionProvider extends PooledConnectionProvider
// try next router
const session = await this._createSessionForRediscovery(
currentRouter,
bookmark,
bookmarks,
impersonatedUser
)
if (session) {
@@ -474,7 +475,7 @@ export default class RoutingConnectionProvider extends PooledConnectionProvider
)
}

async _createSessionForRediscovery (routerAddress, bookmark, impersonatedUser) {
async _createSessionForRediscovery (routerAddress, bookmarks, impersonatedUser) {
try {
const connection = await this._connectionPool.acquire(routerAddress)

@@ -498,7 +499,7 @@ export default class RoutingConnectionProvider extends PooledConnectionProvider
return new Session({
mode: READ,
database: SYSTEM_DB_NAME,
bookmark,
bookmark: bookmarks,
connectionProvider,
impersonatedUser
})
@@ -513,7 +514,7 @@ export default class RoutingConnectionProvider extends PooledConnectionProvider
}
}

async _applyRoutingTableIfPossible (currentRoutingTable, newRoutingTable, onDatabaseNameResolved) {
async _applyRoutingTableIfPossible (currentRoutingTable, newRoutingTable) {
if (!newRoutingTable) {
// none of routing servers returned valid routing table, throw exception
throw newError(
@@ -528,21 +529,18 @@ export default class RoutingConnectionProvider extends PooledConnectionProvider
this._useSeedRouter = true
}

await this._updateRoutingTable(newRoutingTable, onDatabaseNameResolved)
await this._updateRoutingTable(newRoutingTable)

return newRoutingTable
}

async _updateRoutingTable (newRoutingTable, onDatabaseNameResolved) {
async _updateRoutingTable (newRoutingTable) {
// close old connections to servers not present in the new routing table
await this._connectionPool.keepAll(newRoutingTable.allServers())
this._routingTableRegistry.removeExpired()
this._routingTableRegistry.register(
newRoutingTable
)

onDatabaseNameResolved(newRoutingTable.database)

this._log.info(`Updated routing table ${newRoutingTable}`)
}

58 changes: 58 additions & 0 deletions packages/bolt-connection/src/lang/functional.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/**
* Copyright (c) "Neo4j"
* Neo4j Sweden AB [http://neo4j.com]
*
* This file is part of Neo4j.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { json } from 'neo4j-driver-core'

/**
* Identity function.
*
* Identity functions are function which returns the input as output.
*
* @param {any} x
* @returns {any} the x
*/
export function identity (x) {
return x
}

/**
* Makes the function able to share ongoing requests
*
* @param {function(...args): Promise} func The function to be decorated
* @param {any} thisArg The `this` which should be used in the function call
* @return {function(...args): Promise} The decorated function
*/
export function reuseOngoingRequest (func, thisArg = null) {
const ongoingRequests = new Map()

return function (...args) {
const key = json.stringify(args)
if (ongoingRequests.has(key)) {
return ongoingRequests.get(key)
}

const promise = func.apply(thisArg, args)

ongoingRequests.set(key, promise)

return promise.finally(() => {
ongoingRequests.delete(key)
})
}
}
19 changes: 19 additions & 0 deletions packages/bolt-connection/src/lang/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/**
* Copyright (c) "Neo4j"
* Neo4j Sweden AB [http://neo4j.com]
*
* This file is part of Neo4j.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export * as functional from './functional'
27 changes: 16 additions & 11 deletions packages/bolt-connection/src/packstream/packstream-utc.js
Original file line number Diff line number Diff line change
@@ -262,28 +262,33 @@ export function packDateTime (value, packer) {
hour: 'numeric',
minute: 'numeric',
second: 'numeric',
hour12: false
hour12: false,
era: 'narrow'
})

const l = epochSecondAndNanoToLocalDateTime(epochSecond, nano)
const utc = Date.UTC(
int(l.year).toNumber(),
int(l.month).toNumber() - 1,
int(l.day).toNumber(),
int(l.hour).toNumber(),
int(l.minute).toNumber(),
int(l.second).toNumber()
)
const utc = int(epochSecond)
.multiply(1000)
.add(int(nano).div(1_000_000))
.toNumber()

const formattedUtcParts = formatter.formatToParts(utc)

const localDateTime = formattedUtcParts.reduce((obj, currentValue) => {
if (currentValue.type !== 'literal') {
if (currentValue.type === 'era') {
obj.adjustEra =
currentValue.value.toUpperCase() === 'B'
? year => year.subtract(1).negate() // 1BC equals to year 0 in astronomical year numbering
: year => year
} else if (currentValue.type === 'hour') {
obj.hour = int(currentValue.value).modulo(24)
} else if (currentValue.type !== 'literal') {
obj[currentValue.type] = int(currentValue.value)
}
return obj
}, {})

localDateTime.year = localDateTime.adjustEra(localDateTime.year)

const epochInTimeZone = localDateTimeToEpochSecond(
localDateTime.year,
localDateTime.month,
4 changes: 2 additions & 2 deletions packages/bolt-connection/src/packstream/packstream-v1.js
Original file line number Diff line number Diff line change
@@ -32,7 +32,7 @@ import {
internal
} from 'neo4j-driver-core'

const { util } = internal
const { objectUtil } = internal
const { PROTOCOL_ERROR } = error

const TINY_STRING = 0x80
@@ -575,7 +575,7 @@ class Unpacker {
return null
}
} catch (error) {
return util.createBrokenObject(error)
return objectUtil.createBrokenObject(error)
}

}
Loading