diff --git a/packages/core/src/error.ts b/packages/core/src/error.ts index c6cc2d7d7..dfe6aff2d 100644 --- a/packages/core/src/error.ts +++ b/packages/core/src/error.ts @@ -150,6 +150,34 @@ class GQLError extends Error { this.name = 'GQLError' } + /** + * Returns whether a given GqlStatus code can be found in the cause chain of the error (including the error itself). + * + * @param {string} gqlStatus the GqlStatus code to find + * @returns {boolean} + */ + containsGqlCause (gqlStatus: string): boolean { + return this.findByGqlStatus(gqlStatus) !== undefined + } + + /** + * Returns the first error in the cause chain (including the error itself) with a given GqlStatus code. + * Returns undefined if the GqlStatus code is not present anywhere in the chain. + * + * @param {string} gqlStatus the GqlStatus code to find + * @returns {GQLError | Neo4jError | undefined} + */ + findByGqlStatus (gqlStatus: string): GQLError | Neo4jError | undefined { + if (this.gqlStatus === gqlStatus) { + return this + } + if (this.cause !== undefined && (this.cause instanceof GQLError || this.cause instanceof Neo4jError)) { + return this.cause.findByGqlStatus(gqlStatus) + } + + return undefined + } + /** * The json string representation of the diagnostic record. * The goal of this method is provide a serialized object for human inspection. diff --git a/packages/core/test/error.test.ts b/packages/core/test/error.test.ts index 770ef9e05..b4d7f71cb 100644 --- a/packages/core/test/error.test.ts +++ b/packages/core/test/error.test.ts @@ -16,6 +16,7 @@ */ import { Neo4jError, + GQLError, isRetryableError, newError, newGQLError, @@ -201,8 +202,41 @@ describe('Neo4jError', () => { expect(Neo4jError.isRetryable(error)).toBe(false) }) }) + + describe('.containsGqlCause()', () => { + it.each([ + [createNestedErrors(0), 'cause0', false], + [createNestedErrors(0), 'root', true], + [createNestedErrors(10), 'cause8', true], + [createNestedErrors(10), 'cause11', false] + ])('should correctly identify if GQLStatus is present in cause chain', (error, status, expectedResult) => { + expect(error.containsGqlCause(status)).toBe(expectedResult) + }) + }) + + describe('.findByGqlStatus()', () => { + it.each([ + [createNestedErrors(0), 'cause0', undefined], + [createNestedErrors(0), 'root', 'root'], + [createNestedErrors(10), 'cause8', '8cause'], + [createNestedErrors(10), 'cause11', undefined] + ])('should correctly find error in cause chain', (error, status, expectedMessage) => { + expect(error.findByGqlStatus(status)?.message).toBe(expectedMessage) + }) + }) }) +function createNestedErrors (causes: number): Neo4jError { + const error = new Neo4jError('root', '', 'root', '') + let current: Neo4jError | GQLError = error + for (let i = 0; i < causes; i++) { + const cause = new GQLError(i.toString() + 'cause', 'cause' + i.toString(), '') + current.cause = cause + current = cause + } + return error +} + function getRetryableErrorsFixture (): Array<[Neo4jError]> { return getRetryableCodes().map(code => [newError('message', code)]) } diff --git a/packages/neo4j-driver-deno/lib/core/error.ts b/packages/neo4j-driver-deno/lib/core/error.ts index c23104842..6ef3afcb3 100644 --- a/packages/neo4j-driver-deno/lib/core/error.ts +++ b/packages/neo4j-driver-deno/lib/core/error.ts @@ -150,6 +150,34 @@ class GQLError extends Error { this.name = 'GQLError' } + /** + * Returns whether a given GqlStatus code can be found in the cause chain of the error (including the error itself). + * + * @param {string} gqlStatus the GqlStatus code to find + * @returns {boolean} + */ + containsGqlCause (gqlStatus: string): boolean { + return this.findByGqlStatus(gqlStatus) !== undefined + } + + /** + * Returns the first error in the cause chain (including the error itself) with a given GqlStatus code. + * Returns undefined if the GqlStatus code is not present anywhere in the chain. + * + * @param {string} gqlStatus the GqlStatus code to find + * @returns {GQLError | Neo4jError | undefined} + */ + findByGqlStatus (gqlStatus: string): GQLError | Neo4jError | undefined { + if (this.gqlStatus === gqlStatus) { + return this + } + if (this.cause !== undefined && (this.cause instanceof GQLError || this.cause instanceof Neo4jError)) { + return this.cause.findByGqlStatus(gqlStatus) + } + + return undefined + } + /** * The json string representation of the diagnostic record. * The goal of this method is provide a serialized object for human inspection.