diff --git a/packages/bolt-connection/src/bolt/bolt-protocol-v6x0.transformer.js b/packages/bolt-connection/src/bolt/bolt-protocol-v6x0.transformer.js index c9ccd8578..573a14114 100644 --- a/packages/bolt-connection/src/bolt/bolt-protocol-v6x0.transformer.js +++ b/packages/bolt-connection/src/bolt/bolt-protocol-v6x0.transformer.js @@ -18,7 +18,7 @@ import v5x8 from './bolt-protocol-v5x8.transformer' import { TypeTransformer } from './transformer' import { structure } from '../packstream' -import { Vector, newError } from 'neo4j-driver-core' +import { Vector, UnknownType, newError } from 'neo4j-driver-core' const VECTOR = 0x56 const FLOAT_32 = 0xc6 const FLOAT_64 = 0xc1 @@ -26,6 +26,7 @@ const INT_8 = 0xc8 const INT_16 = 0xc9 const INT_32 = 0xca const INT_64 = 0xcb +const UNKNOWN = 0x3F const typeToTypeMarker = { INT8: INT_8, @@ -132,7 +133,21 @@ function checkLittleEndian () { return typeArray[0] === 1000 } +function createUnknownTypeTransformer () { + return new TypeTransformer({ + signature: UNKNOWN, + isTypeInstance: object => object instanceof UnknownType, + toStructure: _ => { + throw newError('Unknown Type object can not be transmitted') + }, + fromStructure: structure => { + return new UnknownType(structure.fields[0], structure.fields[1], structure.fields[2], structure.fields[3].message) + } + }) +} + export default { ...v5x8, - createVectorTransformer + createVectorTransformer, + createUnknownTypeTransformer } diff --git a/packages/bolt-connection/src/bolt/transformer.js b/packages/bolt-connection/src/bolt/transformer.js index ab273bec8..341d4a6d2 100644 --- a/packages/bolt-connection/src/bolt/transformer.js +++ b/packages/bolt-connection/src/bolt/transformer.js @@ -114,7 +114,7 @@ export class TypeTransformer { * @param {isTypeInstanceFunction} [param.isTypeInstance] The function which checks if object is * instance of the type described by the TypeTransformer * @param {toStructureFunction} [param.toStructure] The function which gets the object and converts to structure - * @param {fromStructureFunction} pparam.fromStructure] The function which get the structure and covnverts to object + * @param {fromStructureFunction} [param.fromStructure] The function which get the structure and covnverts to object * @returns {TypeTransformer} A new type transform extends with new methods */ extendsWith ({ signature, fromStructure, toStructure, isTypeInstance }) { diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 83fc1400b..96094c4b6 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -103,6 +103,7 @@ import resultTransformers, { ResultTransformer } from './result-transformers' import ClientCertificate, { clientCertificateProviders, ClientCertificateProvider, ClientCertificateProviders, RotatingClientCertificateProvider, resolveCertificateProvider } from './client-certificate' import * as internal from './internal' // todo: removed afterwards import Vector, { VectorType, vector } from './vector' +import UnknownType from './unknown-type' /** * Object containing string constants representing predefined {@link Neo4jError} codes. @@ -189,7 +190,8 @@ const forExport = { notificationFilterDisabledClassification, notificationFilterMinimumSeverityLevel, clientCertificateProviders, - resolveCertificateProvider + resolveCertificateProvider, + UnknownType } export { @@ -269,6 +271,7 @@ export { clientCertificateProviders, resolveCertificateProvider, Vector, + UnknownType, vector } diff --git a/packages/core/src/unknown-type.ts b/packages/core/src/unknown-type.ts new file mode 100644 index 000000000..cc6ca0d09 --- /dev/null +++ b/packages/core/src/unknown-type.ts @@ -0,0 +1,67 @@ +/** + * Copyright (c) "Neo4j" + * Neo4j Sweden AB [https://neo4j.com] + * + * 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. + */ + +/** + * A representation of a value that could not be transmitted over the wire due to an outdated protocol version. + * @access public + * @exports UnknownType + */ +export default class UnknownType { + name: string + _minimumProtocolMajor: number + _minimumProtocolMinor: number + message: string | undefined + constructor (name: string, minimumProtocolMajor: number, minimumProtocolMinor: number, message: string | undefined) { + /** + * The name of the type that could not be transmitted. + * + * @type {string} + */ + this.name = name + /** + * The major version of the protocol needed to transmit the value. + * + * @type {number} + * @access private + */ + this._minimumProtocolMajor = minimumProtocolMajor + /** + * The minor version of the protocol needed to transmit the value. + * + * @type {number} + * @access private + */ + this._minimumProtocolMinor = minimumProtocolMinor + /** + * An optional message, including additional information regarding the untransmittable value. + * + * @type {string | undefined} + */ + this.message = message + } + + /** + * @returns {string} The minimum version of the protocol needed to transmit this value. + */ + minimumProtocolVersion (): string { + return `${this._minimumProtocolMajor}.${this._minimumProtocolMinor}` + } + + toString (): string { + return `UnknownType<${this.name}>` + } +} diff --git a/packages/core/test/unknown-type.test.ts b/packages/core/test/unknown-type.test.ts new file mode 100644 index 000000000..36f3598c3 --- /dev/null +++ b/packages/core/test/unknown-type.test.ts @@ -0,0 +1,30 @@ +/** + * Copyright (c) "Neo4j" + * Neo4j Sweden AB [https://neo4j.com] + * + * 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 { UnknownType } from '../src' + +describe('UnknownTppe', () => { + it.each([ + ['with message', ['QuantumInteger', 76, 87, 'Quantum computing is from the future.'], '76.87', 'UnknownType'], + ['without message', ['CuniformInteger', 1, 1], '1.1', 'UnknownType'] + ])('should create UnknownType (%s)', (_, parameters: [string, number, number, string], protocolString, representation) => { + const unknownType = new UnknownType(...parameters) + expect(unknownType.minimumProtocolVersion()).toBe(protocolString) + expect(unknownType.toString()).toBe(representation) + expect(unknownType.message).toBe(parameters[3]) + }) +}) diff --git a/packages/neo4j-driver-deno/lib/bolt-connection/bolt/bolt-protocol-v6x0.transformer.js b/packages/neo4j-driver-deno/lib/bolt-connection/bolt/bolt-protocol-v6x0.transformer.js index c0e0d16b2..3564ddb0c 100644 --- a/packages/neo4j-driver-deno/lib/bolt-connection/bolt/bolt-protocol-v6x0.transformer.js +++ b/packages/neo4j-driver-deno/lib/bolt-connection/bolt/bolt-protocol-v6x0.transformer.js @@ -18,7 +18,7 @@ import v5x8 from './bolt-protocol-v5x8.transformer.js' import { TypeTransformer } from './transformer.js' import { structure } from '../packstream/index.js' -import { Vector, newError } from '../../core/index.ts' +import { Vector, UnknownType, newError } from '../../core/index.ts' const VECTOR = 0x56 const FLOAT_32 = 0xc6 const FLOAT_64 = 0xc1 @@ -26,6 +26,7 @@ const INT_8 = 0xc8 const INT_16 = 0xc9 const INT_32 = 0xca const INT_64 = 0xcb +const UNKNOWN = 0x3F const typeToTypeMarker = { INT8: INT_8, @@ -132,7 +133,21 @@ function checkLittleEndian () { return typeArray[0] === 1000 } +function createUnknownTypeTransformer () { + return new TypeTransformer({ + signature: UNKNOWN, + isTypeInstance: object => object instanceof UnknownType, + toStructure: _ => { + throw newError('Unknown Type object can not be transmitted') + }, + fromStructure: structure => { + return new UnknownType(structure.fields[0], structure.fields[1], structure.fields[2], structure.fields[3].message) + } + }) +} + export default { ...v5x8, - createVectorTransformer + createVectorTransformer, + createUnknownTypeTransformer } diff --git a/packages/neo4j-driver-deno/lib/bolt-connection/bolt/transformer.js b/packages/neo4j-driver-deno/lib/bolt-connection/bolt/transformer.js index 63013e612..8ea27491f 100644 --- a/packages/neo4j-driver-deno/lib/bolt-connection/bolt/transformer.js +++ b/packages/neo4j-driver-deno/lib/bolt-connection/bolt/transformer.js @@ -114,7 +114,7 @@ export class TypeTransformer { * @param {isTypeInstanceFunction} [param.isTypeInstance] The function which checks if object is * instance of the type described by the TypeTransformer * @param {toStructureFunction} [param.toStructure] The function which gets the object and converts to structure - * @param {fromStructureFunction} pparam.fromStructure] The function which get the structure and covnverts to object + * @param {fromStructureFunction} [param.fromStructure] The function which get the structure and covnverts to object * @returns {TypeTransformer} A new type transform extends with new methods */ extendsWith ({ signature, fromStructure, toStructure, isTypeInstance }) { diff --git a/packages/neo4j-driver-deno/lib/core/index.ts b/packages/neo4j-driver-deno/lib/core/index.ts index b22a6600b..a7c78aa37 100644 --- a/packages/neo4j-driver-deno/lib/core/index.ts +++ b/packages/neo4j-driver-deno/lib/core/index.ts @@ -103,6 +103,7 @@ import resultTransformers, { ResultTransformer } from './result-transformers.ts' import ClientCertificate, { clientCertificateProviders, ClientCertificateProvider, ClientCertificateProviders, RotatingClientCertificateProvider, resolveCertificateProvider } from './client-certificate.ts' import * as internal from './internal/index.ts' import Vector, { VectorType, vector } from './vector.ts' +import UnknownType from './unknown-type.ts' /** * Object containing string constants representing predefined {@link Neo4jError} codes. @@ -189,7 +190,8 @@ const forExport = { notificationFilterDisabledClassification, notificationFilterMinimumSeverityLevel, clientCertificateProviders, - resolveCertificateProvider + resolveCertificateProvider, + UnknownType } export { @@ -269,6 +271,7 @@ export { clientCertificateProviders, resolveCertificateProvider, Vector, + UnknownType, vector } diff --git a/packages/neo4j-driver-deno/lib/core/unknown-type.ts b/packages/neo4j-driver-deno/lib/core/unknown-type.ts new file mode 100644 index 000000000..cc6ca0d09 --- /dev/null +++ b/packages/neo4j-driver-deno/lib/core/unknown-type.ts @@ -0,0 +1,67 @@ +/** + * Copyright (c) "Neo4j" + * Neo4j Sweden AB [https://neo4j.com] + * + * 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. + */ + +/** + * A representation of a value that could not be transmitted over the wire due to an outdated protocol version. + * @access public + * @exports UnknownType + */ +export default class UnknownType { + name: string + _minimumProtocolMajor: number + _minimumProtocolMinor: number + message: string | undefined + constructor (name: string, minimumProtocolMajor: number, minimumProtocolMinor: number, message: string | undefined) { + /** + * The name of the type that could not be transmitted. + * + * @type {string} + */ + this.name = name + /** + * The major version of the protocol needed to transmit the value. + * + * @type {number} + * @access private + */ + this._minimumProtocolMajor = minimumProtocolMajor + /** + * The minor version of the protocol needed to transmit the value. + * + * @type {number} + * @access private + */ + this._minimumProtocolMinor = minimumProtocolMinor + /** + * An optional message, including additional information regarding the untransmittable value. + * + * @type {string | undefined} + */ + this.message = message + } + + /** + * @returns {string} The minimum version of the protocol needed to transmit this value. + */ + minimumProtocolVersion (): string { + return `${this._minimumProtocolMajor}.${this._minimumProtocolMinor}` + } + + toString (): string { + return `UnknownType<${this.name}>` + } +} diff --git a/packages/testkit-backend/src/cypher-native-binders.js b/packages/testkit-backend/src/cypher-native-binders.js index 22272007b..ad302edd9 100644 --- a/packages/testkit-backend/src/cypher-native-binders.js +++ b/packages/testkit-backend/src/cypher-native-binders.js @@ -183,6 +183,14 @@ export default function CypherNativeBinders (neo4j) { return structResponse('CypherVector', { dtype, data }) } + if (x._minimumProtocolMajor != null) { + const name = x.name + const minimumProtocolMajor = x._minimumProtocolMajor + const minimumProtocolMinor = x._minimumProtocolMinor + const message = x.message + return structResponse('CypherUnknownType', { name, minimumProtocolMajor, minimumProtocolMinor, message }) + } + // If all failed, interpret as a map const map = {} for (const [key, value] of Object.entries(x)) { diff --git a/packages/testkit-backend/src/feature/common.js b/packages/testkit-backend/src/feature/common.js index a619d6531..984af3f21 100644 --- a/packages/testkit-backend/src/feature/common.js +++ b/packages/testkit-backend/src/feature/common.js @@ -44,6 +44,7 @@ const features = [ 'Feature:API:Summary:GqlStatusObjects', 'Feature:API:Liveness.Check', 'Feature:API:Type.Vector', + 'Feature:API:Type.UnknownType', 'Optimization:AuthPipelining', 'Optimization:EagerTransactionBegin', 'Optimization:ExecuteQueryPipelining', diff --git a/testkit/testkit.json b/testkit/testkit.json index 0b9944108..fdc8cf1d9 100644 --- a/testkit/testkit.json +++ b/testkit/testkit.json @@ -1,6 +1,6 @@ { "testkit": { "uri": "https://github.com/neo4j-drivers/testkit.git", - "ref": "6.x" + "ref": "unknown-type-stub-tests" } }