diff --git a/__mocks__/neo4j.js b/__mocks__/neo4j.js
deleted file mode 100644
index 9bde1c7e084..00000000000
--- a/__mocks__/neo4j.js
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (c) 2002-2018 "Neo4j, Inc"
- * Network Engine for Objects in Lund AB [http://neotechnology.com]
- *
- * This file is part of Neo4j.
- *
- * Neo4j is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-function integerFn (val) {
- this.val = val
-}
-integerFn.prototype.toString = function () {
- return this.val.toString()
-}
-
-var out = {
- v1: {
- isInt: function (val) {
- return val instanceof out.v1.Integer
- },
- types: {
- Node: function Node (id, labels, properties) {
- this.identity = id
- this.labels = labels
- this.properties = properties
- },
- Relationship: function Relationship (id, start, end, type, properties) {
- this.identity = id
- this.start = start
- this.end = end
- this.type = type
- this.properties = properties
- },
- Path: function Path (start, end, segments) {
- this.start = start
- this.end = end
- this.segments = segments
- this.length = segments.length
- },
- PathSegment: function PathSegment (start, relationship, end) {
- this.start = start
- this.relationship = relationship
- this.end = end
- }
- },
- Integer: function Integer (low, high) {
- this.low = low
- this.high = high
- }
- }
-}
-
-out.v1.types.Node.prototype.toString = function () {
- return 'node'
-}
-out.v1.types.Relationship.prototype.toString = function () {
- return 'rel'
-}
-out.v1.types.Path.prototype.toString = function () {
- return 'path'
-}
-out.v1.types.PathSegment.prototype.toString = function () {
- return 'pathsegment'
-}
-out.v1.Integer.prototype.toInt = function () {
- return this.low
-}
-out.v1.Integer.prototype.toString = function () {
- return this.low
-}
-out.v1.Int = out.v1.Integer
-out.v1.int = val => {
- if (val /* is compatible */ instanceof out.v1.Integer) return val
- if (typeof val === 'number') return new out.v1.Integer(val)
- if (typeof val === 'string') return new out.v1.Integer(val)
- // Throws for non-objects, converts non-instanceof Integer:
- return new out.v1.Integer(val.low, val.high)
-}
-
-module.exports = out
diff --git a/e2e_tests/integration/types.spec.js b/e2e_tests/integration/types.spec.js
new file mode 100644
index 00000000000..e033f41f3e5
--- /dev/null
+++ b/e2e_tests/integration/types.spec.js
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2002-2018 "Neo4j, Inc"
+ * Network Engine for Objects in Lund AB [http://neotechnology.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+/* global Cypress, cy, test, expect */
+
+describe('Types in Browser', () => {
+ it('can connect', () => {
+ cy.executeCommand(':server disconnect')
+ cy.executeCommand(':clear')
+ cy.executeCommand(':server connect')
+ const password = Cypress.env('BROWSER_NEW_PASSWORD') || 'newpassword'
+ cy.connect(password)
+ })
+ it('presents the point type correctly', () => {
+ cy.executeCommand(':clear')
+ const query =
+ "WITH point({{}crs: 'wgs-84', longitude: 12.78, latitude: 56.7}) as p1 RETURN p1"
+ cy.executeCommand(query)
+ cy.waitForCommandResult()
+
+ cy
+ .get('[data-test-id="frameContents"]', { timeout: 10000 })
+ .then(contents => {
+ // Check for point type support
+ if (contents.find('.table-row').length > 0) {
+ cy.resultContains('point({srid:4326, x:12.78, y:56.7})')
+
+ // Go to ascii view
+ cy
+ .get('[data-test-id="cypherFrameSidebarAscii"')
+ .first()
+ .click()
+ cy.resultContains('│point({srid:4326, x:12.78, y:56.7})')
+ } else {
+ cy.resultContains('ERROR')
+ }
+ })
+ })
+ it('presents datetime type correctly', () => {
+ cy.executeCommand(':clear')
+ const query =
+ 'RETURN datetime({{}year:2015, month:7, day:20, hour:15, minute:11, second:42, timezone:"Europe/Stockholm"}) AS t1'
+ cy.executeCommand(query)
+ cy.waitForCommandResult()
+ cy
+ .get('[data-test-id="frameContents"]', { timeout: 10000 })
+ .then(contents => {
+ // Check for type support
+ if (contents.find('.table-row').length > 0) {
+ cy.resultContains('"2015-07-20T15:11:42.000000000[Europe/Stockholm]"')
+ // Go to ascii view
+ cy
+ .get('[data-test-id="cypherFrameSidebarAscii"')
+ .first()
+ .click()
+ cy.resultContains(
+ '│"2015-07-20T15:11:42.000000000[Europe/Stockholm]"'
+ )
+ } else {
+ cy.resultContains('ERROR')
+ }
+ })
+ })
+ it('presents local datetime type correctly', () => {
+ cy.executeCommand(':clear')
+ const query =
+ 'RETURN localdatetime({{}year:2015, month:7, day:20, hour:15, minute:11, second:42}) AS t1'
+ cy.executeCommand(query)
+ cy.waitForCommandResult()
+ cy
+ .get('[data-test-id="frameContents"]', { timeout: 10000 })
+ .then(contents => {
+ // Check for type support
+ if (contents.find('.table-row').length > 0) {
+ cy.resultContains('"2015-07-20T15:11:42.000000000"')
+ // Go to ascii view
+ cy
+ .get('[data-test-id="cypherFrameSidebarAscii"')
+ .first()
+ .click()
+ cy.resultContains('│"2015-07-20T15:11:42.000000000"')
+ } else {
+ cy.resultContains('ERROR')
+ }
+ })
+ })
+ it('presents date type correctly', () => {
+ cy.executeCommand(':clear')
+ const query = 'RETURN date({{}year:2015, month:7, day:20}) AS t1'
+ cy.executeCommand(query)
+ cy.waitForCommandResult()
+ cy
+ .get('[data-test-id="frameContents"]', { timeout: 10000 })
+ .then(contents => {
+ // Check for type support
+ if (contents.find('.table-row').length > 0) {
+ cy.resultContains('"2015-07-20"')
+ // Go to ascii view
+ cy
+ .get('[data-test-id="cypherFrameSidebarAscii"')
+ .first()
+ .click()
+ cy.resultContains('│"2015-07-20"')
+ } else {
+ cy.resultContains('ERROR')
+ }
+ })
+ })
+ it('presents duration type correctly', () => {
+ cy.executeCommand(':clear')
+ const query =
+ 'RETURN duration({{}months:14, days:3, seconds:14706, nanoseconds:0}) AS t1'
+ cy.executeCommand(query)
+ cy.waitForCommandResult()
+ cy
+ .get('[data-test-id="frameContents"]', { timeout: 10000 })
+ .then(contents => {
+ // Check for type support
+ if (contents.find('.table-row').length > 0) {
+ cy.resultContains('"P14M3DT14706.000000000S"')
+ // Go to ascii view
+ cy
+ .get('[data-test-id="cypherFrameSidebarAscii"')
+ .first()
+ .click()
+ cy.resultContains('│"P14M3DT14706.000000000S"')
+ } else {
+ cy.resultContains('ERROR')
+ }
+ })
+ })
+ it('presents time type correctly', () => {
+ cy.executeCommand(':clear')
+ const query =
+ 'RETURN time({{}hour:14, minute:3, second:4, timezone: "Europe/Stockholm"}) AS t1'
+ cy.executeCommand(query)
+ cy.waitForCommandResult()
+ cy
+ .get('[data-test-id="frameContents"]', { timeout: 10000 })
+ .then(contents => {
+ // Check for type support
+ if (contents.find('.table-row').length > 0) {
+ cy.resultContains('"14:03:04.000000000+02:00"')
+ // Go to ascii view
+ cy
+ .get('[data-test-id="cypherFrameSidebarAscii"')
+ .first()
+ .click()
+ cy.resultContains('│"14:03:04.000000000+02:00"')
+ } else {
+ cy.resultContains('ERROR')
+ }
+ })
+ })
+ it('presents localtime type correctly', () => {
+ cy.executeCommand(':clear')
+ const query = 'RETURN localtime({{}hour:14, minute:3, second:4}) AS t1'
+ cy.executeCommand(query)
+ cy.waitForCommandResult()
+ cy
+ .get('[data-test-id="frameContents"]', { timeout: 10000 })
+ .then(contents => {
+ // Check for type support
+ if (contents.find('.table-row').length > 0) {
+ cy.resultContains('"14:03:04.000000000"')
+ // Go to ascii view
+ cy
+ .get('[data-test-id="cypherFrameSidebarAscii"')
+ .first()
+ .click()
+ cy.resultContains('│"14:03:04.000000000"')
+ } else {
+ cy.resultContains('ERROR')
+ }
+ })
+ })
+})
diff --git a/e2e_tests/support/commands.js b/e2e_tests/support/commands.js
index 0613021c6a5..935bb45f4e4 100644
--- a/e2e_tests/support/commands.js
+++ b/e2e_tests/support/commands.js
@@ -74,7 +74,6 @@ Cypress.Commands.add('disconnect', () => {
Cypress.Commands.add('executeCommand', query => {
cy.get(ClearEditorButton).click()
cy.get(Editor).type(query, { force: true })
- cy.get(Editor).should('have.value', query)
cy.get(SubmitQueryButton).click()
})
Cypress.Commands.add('waitForCommandResult', () => {
@@ -82,3 +81,9 @@ Cypress.Commands.add('waitForCommandResult', () => {
.get('[data-test-id="frame-loaded-contents"]', { timeout: 40000 })
.should('be.visible')
})
+Cypress.Commands.add('resultContains', str => {
+ cy
+ .get('[data-test-id="frameContents"]', { timeout: 10000 })
+ .first()
+ .should('contain', str)
+})
diff --git a/package.json b/package.json
index a110472f831..7e838c50162 100644
--- a/package.json
+++ b/package.json
@@ -15,10 +15,8 @@
"apiVersion": "^1.2.0"
},
"scripts": {
- "start":
- "webpack-dashboard -t 'Neo4j Browser' -- webpack-dev-server --colors --no-info",
- "starts":
- "webpack-dashboard -t 'Neo4j Browser' -- webpack-dev-server --https --colors --no-info",
+ "start": "webpack-dashboard -t 'Neo4j Browser' -- webpack-dev-server --colors --no-info",
+ "starts": "webpack-dashboard -t 'Neo4j Browser' -- webpack-dev-server --https --colors --no-info",
"startnodash": "webpack-dev-server --colors --no-info",
"precommit": "lint-staged",
"format": "prettier-eslint 'src/**/!(*.min).js' 'src/**/*.jsx' --write",
@@ -31,23 +29,27 @@
"build": "rm -rf ./dist && NODE_ENV=\"production\" webpack",
"prepare-jar": "node ./scripts/prepare-mvn-package.js",
"jar": "yarn build && mvn package",
- "version-pom":
- "node ./scripts/set-pom-version.js -f ./pom.xml -v $npm_package_version",
+ "version-pom": "node ./scripts/set-pom-version.js -f ./pom.xml -v $npm_package_version",
"version": "npm run version-pom && git add ./pom.xml",
"update-licenses": "sh ./scripts/generate_licenses.sh"
},
"lint-staged": {
"linters": {
- "*.{js,jsx}": ["prettier-eslint --write", "git add"]
+ "*.{js,jsx}": [
+ "prettier-eslint --write",
+ "git add"
+ ]
}
},
"jest": {
- "testPathIgnorePatterns": [".jsx$", "/e2e_tests/"],
+ "testPathIgnorePatterns": [
+ ".jsx$",
+ "/e2e_tests/"
+ ],
"moduleNameMapper": {
- "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga|html)$":
- "/__mocks__/fileMock.js",
+ "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga|html)$": "/__mocks__/fileMock.js",
"\\.(css|less)$": "/__mocks__/styleMock.js",
- "neo4j": "/__mocks__/neo4j.js",
+ "^neo4j-driver-alias$": "neo4j-driver",
"^react-dom/server$": "preact-render-to-string",
"^react-addons-test-utils$": "preact-test-utils",
"^react-addons-transition-group$": "preact-transition-group",
@@ -57,7 +59,10 @@
"^browser-components(.*)$": "/src/browser/components$1",
"worker-loader": "/__mocks__/workerLoaderMock.js"
},
- "modulePaths": ["/src", "/src/shared"]
+ "modulePaths": [
+ "/src",
+ "/src/shared"
+ ]
},
"devDependencies": {
"autoprefixer": "^7.1.4",
@@ -136,7 +141,7 @@
"isomorphic-fetch": "^2.2.1",
"jsonic": "^0.3.0",
"lodash.debounce": "^4.0.8",
- "neo4j-driver": "^1.5.3",
+ "neo4j-driver": "1.6.0-rc1",
"node-noop": "^1.0.0",
"preact": "^8.2.5",
"preact-compat": "^3.17.0",
diff --git a/src/browser/modules/Stream/CypherFrame/TableView.jsx b/src/browser/modules/Stream/CypherFrame/TableView.jsx
index dcf5bbfad6e..1ad509e06bb 100644
--- a/src/browser/modules/Stream/CypherFrame/TableView.jsx
+++ b/src/browser/modules/Stream/CypherFrame/TableView.jsx
@@ -20,6 +20,7 @@
import { Component } from 'preact'
import { v4 } from 'uuid'
+import { v1 as neo4j } from 'neo4j-driver-alias'
import {
StyledStatsBar,
PaddedTableViewDiv,
@@ -34,16 +35,12 @@ import {
StyledJsonPre
} from 'browser-components/DataTables'
import { deepEquals, shallowEquals, stringifyMod } from 'services/utils'
-import { v1 as neo4j } from 'neo4j-driver-alias'
import {
getBodyAndStatusBarMessages,
getRecordsToDisplayInTable,
transformResultRecordsToResultArray
} from './helpers'
-
-const intToString = val => {
- if (neo4j.isInt(val)) return val.toString()
-}
+import { stringFormat } from 'services/bolt/cypherTypesFormatting'
const renderCell = entry => {
if (Array.isArray(entry)) {
@@ -57,13 +54,15 @@ const renderCell = entry => {
} else if (typeof entry === 'object') {
return renderObject(entry)
} else {
- return stringifyMod(entry, intToString, true)
+ return stringifyMod(entry, stringFormat, true)
}
}
export const renderObject = entry => {
if (neo4j.isInt(entry)) return entry.toString()
if (entry === null) return null
- return {stringifyMod(entry, intToString, true)}
+ return (
+ {stringifyMod(entry, stringFormat, true)}
+ )
}
const buildData = entries => {
return entries.map(entry => {
diff --git a/src/browser/modules/Stream/CypherFrame/__snapshots__/TableView.test.js.snap b/src/browser/modules/Stream/CypherFrame/__snapshots__/TableView.test.js.snap
index 9bda28d30e8..4c498f72751 100644
--- a/src/browser/modules/Stream/CypherFrame/__snapshots__/TableView.test.js.snap
+++ b/src/browser/modules/Stream/CypherFrame/__snapshots__/TableView.test.js.snap
@@ -3,7 +3,7 @@
exports[`TableViews TableView renderObject handles null values 1`] = `
{
- "x": 1
+ "x": 1.0
}
`;
diff --git a/src/browser/modules/Stream/CypherFrame/helpers.js b/src/browser/modules/Stream/CypherFrame/helpers.js
index c7001270e24..e09cc10b493 100644
--- a/src/browser/modules/Stream/CypherFrame/helpers.js
+++ b/src/browser/modules/Stream/CypherFrame/helpers.js
@@ -26,6 +26,7 @@ import {
flattenArray
} from 'services/bolt/boltMappings'
import { stringifyMod } from 'services/utils'
+import { stringFormat } from 'services/bolt/cypherTypesFormatting'
export function getBodyAndStatusBarMessages (result, maxRows) {
if (!result || !result.summary || !result.summary.resultAvailableAfter) {
@@ -167,9 +168,7 @@ export const stringifyResultArray = (intChecker = neo4j.isInt, arr = []) => {
return arr.map(col => {
if (!col) return col
return col.map(fVal => {
- return stringifyMod(fVal, val => {
- if (intChecker(val)) return val.toString()
- })
+ return stringifyMod(fVal, stringFormat)
})
})
}
@@ -247,7 +246,14 @@ export const isGraphItem = (types = neo4j.types, item) => {
item instanceof types.Node ||
item instanceof types.Relationship ||
item instanceof types.Path ||
- item instanceof types.PathSegment
+ item instanceof types.PathSegment ||
+ item instanceof neo4j.types.Date ||
+ item instanceof neo4j.types.DateTime ||
+ item instanceof neo4j.types.Duration ||
+ item instanceof neo4j.types.LocalDateTime ||
+ item instanceof neo4j.types.LocalTime ||
+ item instanceof neo4j.types.Time ||
+ item instanceof neo4j.types.Point
)
}
diff --git a/src/browser/modules/Stream/CypherFrame/helpers.test.js b/src/browser/modules/Stream/CypherFrame/helpers.test.js
index 659776cf95d..37f7f4313a4 100644
--- a/src/browser/modules/Stream/CypherFrame/helpers.test.js
+++ b/src/browser/modules/Stream/CypherFrame/helpers.test.js
@@ -19,6 +19,7 @@
*/
/* global describe, test, expect */
+/* eslint-disable new-cap */
import { v1 as neo4j } from 'neo4j-driver-alias'
import * as viewTypes from 'shared/modules/stream/frameViewTypes'
import {
@@ -517,7 +518,7 @@ describe('helpers', () => {
test('extractRecordsToResultArray handles regular records', () => {
// Given
const start = new neo4j.types.Node(1, ['X'], { x: 1 })
- const end = new neo4j.types.Node(2, ['Y'], { y: new neo4j.Int(1) })
+ const end = new neo4j.types.Node(2, ['Y'], { y: new neo4j.int(1) })
const rel = new neo4j.types.Relationship(3, 1, 2, 'REL', { rel: 1 })
const segments = [new neo4j.types.PathSegment(start, rel, end)]
const path = new neo4j.types.Path(start, end, segments)
@@ -590,11 +591,11 @@ describe('helpers', () => {
const records = [
{
keys: ['"neoInt"', '"int"', '"any"', '"backslash"'],
- _fields: [new neo4j.Int('882573709873217509'), 100, 0.5, '"\\"']
+ _fields: [new neo4j.int('882573709873217509'), 100, 0.5, '"\\"']
},
{
keys: ['"neoInt"', '"int"', '"any"'],
- _fields: [new neo4j.Int(300), 100, 'string']
+ _fields: [new neo4j.int(300), 100, 'string']
}
]
@@ -609,15 +610,17 @@ describe('helpers', () => {
// Then
expect(res).toEqual([
['""neoInt""', '""int""', '""any""', '""backslash""'],
- ['882573709873217509', '100', '0.5', '""\\""'],
- ['300', '100', '"string"']
+ ['882573709873217509', '100.0', '0.5', '""\\""'],
+ ['300', '100.0', '"string"']
])
})
test('stringifyResultArray handles neo4j integers nested within graph items', () => {
// Given
- const start = new neo4j.types.Node(1, ['X'], { x: 1 })
- const end = new neo4j.types.Node(2, ['Y'], { y: new neo4j.Int(2) }) // <-- Neo4j integer
- const rel = new neo4j.types.Relationship(3, 1, 2, 'REL', { rel: 1 })
+ const start = new neo4j.types.Node(1, ['X'], { x: new neo4j.int(1) })
+ const end = new neo4j.types.Node(2, ['Y'], { y: new neo4j.int(2) })
+ const rel = new neo4j.types.Relationship(3, 1, 2, 'REL', {
+ rel: new neo4j.int(1)
+ })
const segments = [new neo4j.types.PathSegment(start, rel, end)]
const path = new neo4j.types.Path(start, end, segments)
diff --git a/src/browser/modules/Stream/CypherFrame/index.jsx b/src/browser/modules/Stream/CypherFrame/index.jsx
index 25d4e5d92a0..627903a8b3f 100644
--- a/src/browser/modules/Stream/CypherFrame/index.jsx
+++ b/src/browser/modules/Stream/CypherFrame/index.jsx
@@ -157,6 +157,7 @@ export class CypherFrame extends Component {
{
this.changeView(viewTypes.TABLE)
@@ -172,6 +173,7 @@ export class CypherFrame extends Component {
}
>
{
this.changeView(viewTypes.TEXT)
diff --git a/src/shared/services/bolt/applyGraphTypes.test.js b/src/shared/services/bolt/applyGraphTypes.test.js
index 20c95350bb0..ad583e1e76f 100644
--- a/src/shared/services/bolt/applyGraphTypes.test.js
+++ b/src/shared/services/bolt/applyGraphTypes.test.js
@@ -125,7 +125,7 @@ describe('applyGraphTypes', () => {
test('should apply integer type', () => {
const rawNumber = nativeTypesToCustom(neo4j.int(5))
const typedNumber = applyGraphTypes(rawNumber)
- expect(typedNumber).toBeInstanceOf(neo4j.Integer)
+ expect(neo4j.isInt(typedNumber)).toBeTruthy()
})
test('should apply node type', () => {
@@ -134,7 +134,7 @@ describe('applyGraphTypes', () => {
const typedNode = applyGraphTypes(rawNode)
expect(typedNode).toBeInstanceOf(neo4j.types.Node)
- expect(typedNode.identity).toBeInstanceOf(neo4j.Integer)
+ expect(neo4j.isInt(typedNode.identity)).toBeTruthy()
})
test('should not false positive on fake node object type', () => {
@@ -148,7 +148,8 @@ describe('applyGraphTypes', () => {
const obj = applyGraphTypes(rawObject)
expect(obj).toBeInstanceOf(Object)
- expect(obj.identity).toBeInstanceOf(neo4j.Integer)
+ expect(neo4j.isInt(obj.identity)).toBeTruthy()
+ expect(neo4j.isInt(obj.identity2)).toBeFalsy()
expect(obj.identity2).toBeInstanceOf(Object)
expect(obj[reservedTypePropertyName]).toEqual('Node')
})
@@ -180,7 +181,7 @@ describe('applyGraphTypes', () => {
const typedNode = applyGraphTypes(rawNode)
expect(typedNode).toBeInstanceOf(neo4j.types.Node)
- expect(typedNode.identity).toBeInstanceOf(neo4j.Integer)
+ expect(neo4j.isInt(typedNode.identity)).toBeTruthy()
expect(typedNode.properties.prop1).toBeNull()
expect(typedNode.properties.prop2).toEqual(33)
@@ -191,7 +192,7 @@ describe('applyGraphTypes', () => {
expect(typedNode.properties.prop6.prop1).toEqual(1)
expect(typedNode.properties.prop6.prop2).toEqual('test')
- expect(typedNode.properties.prop7.prop1).toBeInstanceOf(neo4j.Integer)
+ expect(neo4j.isInt(typedNode.properties.prop7.prop1)).toBeTruthy()
expect(typedNode.properties.prop7.prop1.toInt()).toEqual(3)
expect(typedNode.properties.prop7.prop2).toEqual('test')
@@ -223,9 +224,9 @@ describe('applyGraphTypes', () => {
const typedNodes = applyGraphTypes(rawNodes, neo4j.types)
expect(typedNodes.length).toEqual(2)
expect(typedNodes[0]).toBeInstanceOf(neo4j.types.Node)
- expect(typedNodes[0].identity).toBeInstanceOf(neo4j.Integer)
+ expect(neo4j.isInt(typedNodes[0].identity)).toBeTruthy()
expect(typedNodes[1]).toBeInstanceOf(neo4j.types.Node)
- expect(typedNodes[1].identity).toBeInstanceOf(neo4j.Integer)
+ expect(neo4j.isInt(typedNodes[1].identity)).toBeTruthy()
})
test('should apply relationship type', () => {
@@ -241,7 +242,7 @@ describe('applyGraphTypes', () => {
const typedRelationship = applyGraphTypes(rawRelationship)
expect(typedRelationship).toBeInstanceOf(neo4j.types.Relationship)
- expect(typedRelationship.identity).toBeInstanceOf(neo4j.Integer)
+ expect(neo4j.isInt(typedRelationship.identity)).toBeTruthy()
expect(typedRelationship.type).toEqual('TESTED_WITH')
})
@@ -268,13 +269,13 @@ describe('applyGraphTypes', () => {
const typedRelationships = applyGraphTypes(rawRelationships)
expect(typedRelationships.length).toEqual(2)
expect(typedRelationships[0]).toBeInstanceOf(neo4j.types.Relationship)
- expect(typedRelationships[0].identity).toBeInstanceOf(neo4j.Integer)
- expect(typedRelationships[0].start).toBeInstanceOf(neo4j.Integer)
- expect(typedRelationships[0].end).toBeInstanceOf(neo4j.Integer)
+ expect(neo4j.isInt(typedRelationships[0].identity)).toBeTruthy()
+ expect(neo4j.isInt(typedRelationships[0].start)).toBeTruthy()
+ expect(neo4j.isInt(typedRelationships[0].end)).toBeTruthy()
expect(typedRelationships[1]).toBeInstanceOf(neo4j.types.Relationship)
- expect(typedRelationships[1].identity).toBeInstanceOf(neo4j.Integer)
- expect(typedRelationships[1].start).toBeInstanceOf(neo4j.Integer)
- expect(typedRelationships[1].end).toBeInstanceOf(neo4j.Integer)
+ expect(neo4j.isInt(typedRelationships[1].identity)).toBeTruthy()
+ expect(neo4j.isInt(typedRelationships[1].start)).toBeTruthy()
+ expect(neo4j.isInt(typedRelationships[1].end)).toBeTruthy()
})
test('should apply to custom object properties', () => {
@@ -286,7 +287,7 @@ describe('applyGraphTypes', () => {
const typedObject = applyGraphTypes(rawData)
expect(typedObject.node).toBeInstanceOf(neo4j.types.Node)
- expect(typedObject.num).toBeInstanceOf(neo4j.Integer)
+ expect(neo4j.isInt(typedObject.num)).toBeTruthy()
})
test('should apply to array of custom object properties', () => {
@@ -304,9 +305,9 @@ describe('applyGraphTypes', () => {
const typedObjects = applyGraphTypes(rawObj)
expect(typedObjects.length).toEqual(2)
expect(typedObjects[0].node).toBeInstanceOf(neo4j.types.Node)
- expect(typedObjects[0].num).toBeInstanceOf(neo4j.Integer)
+ expect(neo4j.isInt(typedObjects[0].num)).toBeTruthy()
expect(typedObjects[1].node).toBeInstanceOf(neo4j.types.Node)
- expect(typedObjects[1].num).toBeInstanceOf(neo4j.Integer)
+ expect(neo4j.isInt(typedObjects[1].num)).toBeTruthy()
})
test('should apply PathSegment type', () => {
@@ -315,7 +316,7 @@ describe('applyGraphTypes', () => {
expect(typedPathSegment).toBeTruthy()
expect(typedPathSegment).toBeInstanceOf(neo4j.types.PathSegment)
expect(typedPathSegment.start).toBeInstanceOf(neo4j.types.Node)
- expect(typedPathSegment.start.identity).toBeInstanceOf(neo4j.Integer)
+ expect(neo4j.isInt(typedPathSegment.start.identity)).toBeTruthy()
expect(typedPathSegment.end).toBeInstanceOf(neo4j.types.Node)
expect(typedPathSegment.relationship).toBeInstanceOf(
neo4j.types.Relationship
@@ -388,7 +389,7 @@ describe('applyGraphTypes', () => {
})
const typedObject = applyGraphTypes(complexObj)
expect(typedObject).toBeTruthy()
- expect(typedObject.rawNum).toBeInstanceOf(neo4j.Integer)
+ expect(neo4j.isInt(typedObject.rawNum)).toBeTruthy()
expect(typedObject.rawNode).toBeInstanceOf(neo4j.types.Node)
expect(typedObject.rawRelationship).toBeInstanceOf(neo4j.types.Relationship)
expect(typedObject.rawPath).toBeInstanceOf(neo4j.types.Path)
@@ -400,6 +401,65 @@ describe('applyGraphTypes', () => {
neo4j.types.PathSegment
)
})
+ test('should apply Point type', () => {
+ const point = new neo4j.types.Point('test-ref', 57.734588, 12.908685)
+ const rawPoint = nativeTypesToCustom(point)
+
+ const typedPoint = applyGraphTypes(rawPoint)
+ expect(typedPoint).toBeInstanceOf(neo4j.types.Point)
+ })
+ test('should apply Date type', () => {
+ const date = new neo4j.types.Date(2012, 5, 11)
+ const rawDate = nativeTypesToCustom(date)
+
+ const typedDate = applyGraphTypes(rawDate)
+ expect(typedDate).toBeInstanceOf(neo4j.types.Date)
+ })
+ test('should apply DateTime type', () => {
+ const dateTime = new neo4j.types.DateTime(
+ 2012,
+ 5,
+ 11,
+ 9,
+ 12,
+ 44,
+ 0,
+ null,
+ 'Europe/Stockholm'
+ )
+ const rawDateTime = nativeTypesToCustom(dateTime)
+
+ const typedDateTime = applyGraphTypes(rawDateTime)
+ expect(typedDateTime).toBeInstanceOf(neo4j.types.DateTime)
+ })
+ test('should apply Duration type', () => {
+ const date = new neo4j.types.Duration(1, 2, 0, 0)
+ const rawDate = nativeTypesToCustom(date)
+
+ const typedDate = applyGraphTypes(rawDate)
+ expect(typedDate).toBeInstanceOf(neo4j.types.Duration)
+ })
+ test('should apply LocalDateTime type', () => {
+ const date = new neo4j.types.LocalDateTime(2012, 5, 11, 1, 12, 2)
+ const rawDate = nativeTypesToCustom(date)
+
+ const typedDate = applyGraphTypes(rawDate)
+ expect(typedDate).toBeInstanceOf(neo4j.types.LocalDateTime)
+ })
+ test('should apply LocalTime type', () => {
+ const date = new neo4j.types.LocalTime(11, 1, 12, 2)
+ const rawDate = nativeTypesToCustom(date)
+
+ const typedDate = applyGraphTypes(rawDate)
+ expect(typedDate).toBeInstanceOf(neo4j.types.LocalTime)
+ })
+ test('should apply Time type', () => {
+ const date = new neo4j.types.Time(11, 1, 12, 3600)
+ const rawDate = nativeTypesToCustom(date)
+
+ const typedDate = applyGraphTypes(rawDate)
+ expect(typedDate).toBeInstanceOf(neo4j.types.Time)
+ })
})
const nativeTypesToCustom = x => {
diff --git a/src/shared/services/bolt/boltMappings.js b/src/shared/services/bolt/boltMappings.js
index 10a57108e3f..7e3aa88b649 100644
--- a/src/shared/services/bolt/boltMappings.js
+++ b/src/shared/services/bolt/boltMappings.js
@@ -323,6 +323,63 @@ export const applyGraphTypes = (item, types = neo4j.types) => {
applyGraphTypes(item.end, types),
item.segments.map(x => applyGraphTypes(x, types))
)
+ case 'Point':
+ return new types[className](
+ applyGraphTypes(item.srid),
+ applyGraphTypes(item.x),
+ applyGraphTypes(item.y),
+ applyGraphTypes(item.z)
+ )
+ case 'Date':
+ return new types[className](
+ applyGraphTypes(item.year),
+ applyGraphTypes(item.month),
+ applyGraphTypes(item.day)
+ )
+ case 'DateTime':
+ return new types[className](
+ applyGraphTypes(item.year),
+ applyGraphTypes(item.month),
+ applyGraphTypes(item.day),
+ applyGraphTypes(item.hour),
+ applyGraphTypes(item.minute),
+ applyGraphTypes(item.second),
+ applyGraphTypes(item.nanosecond),
+ applyGraphTypes(item.timeZoneOffsetSeconds),
+ applyGraphTypes(item.timeZoneId)
+ )
+ case 'Duration':
+ return new types[className](
+ applyGraphTypes(item.months),
+ applyGraphTypes(item.days),
+ applyGraphTypes(item.seconds),
+ applyGraphTypes(item.nanoseconds)
+ )
+ case 'LocalDateTime':
+ return new types[className](
+ applyGraphTypes(item.year),
+ applyGraphTypes(item.month),
+ applyGraphTypes(item.day),
+ applyGraphTypes(item.hour),
+ applyGraphTypes(item.minute),
+ applyGraphTypes(item.second),
+ applyGraphTypes(item.nanosecond)
+ )
+ case 'LocalTime':
+ return new types[className](
+ applyGraphTypes(item.hour),
+ applyGraphTypes(item.minute),
+ applyGraphTypes(item.second),
+ applyGraphTypes(item.nanosecond)
+ )
+ case 'Time':
+ return new types[className](
+ applyGraphTypes(item.hour),
+ applyGraphTypes(item.minute),
+ applyGraphTypes(item.second),
+ applyGraphTypes(item.nanosecond),
+ applyGraphTypes(item.timeZoneOffsetSeconds)
+ )
case 'Integer':
return neo4j.int(tmpItem)
default:
@@ -396,6 +453,69 @@ export const recursivelyTypeGraphItems = (item, types = neo4j.types) => {
item.properties = props
return item
}
+ if (item instanceof types.Point) {
+ const keys = Object.keys(item)
+ let tmp = {}
+ keys.forEach(
+ key => (tmp[key] = recursivelyTypeGraphItems(item[key], types))
+ )
+ safetlyAddObjectProp(tmp, reservedTypePropertyName, 'Point')
+ return tmp
+ }
+ if (item instanceof types.Date) {
+ const keys = Object.keys(item)
+ let tmp = {}
+ keys.forEach(
+ key => (tmp[key] = recursivelyTypeGraphItems(item[key], types))
+ )
+ safetlyAddObjectProp(tmp, reservedTypePropertyName, 'Date')
+ return tmp
+ }
+ if (item instanceof types.DateTime) {
+ const keys = Object.keys(item)
+ let tmp = {}
+ keys.forEach(
+ key => (tmp[key] = recursivelyTypeGraphItems(item[key], types))
+ )
+ safetlyAddObjectProp(tmp, reservedTypePropertyName, 'DateTime')
+ return tmp
+ }
+ if (item instanceof types.Duration) {
+ const keys = Object.keys(item)
+ let tmp = {}
+ keys.forEach(
+ key => (tmp[key] = recursivelyTypeGraphItems(item[key], types))
+ )
+ safetlyAddObjectProp(tmp, reservedTypePropertyName, 'Duration')
+ return tmp
+ }
+ if (item instanceof types.LocalDateTime) {
+ const keys = Object.keys(item)
+ let tmp = {}
+ keys.forEach(
+ key => (tmp[key] = recursivelyTypeGraphItems(item[key], types))
+ )
+ safetlyAddObjectProp(tmp, reservedTypePropertyName, 'LocalDateTime')
+ return tmp
+ }
+ if (item instanceof types.LocalTime) {
+ const keys = Object.keys(item)
+ let tmp = {}
+ keys.forEach(
+ key => (tmp[key] = recursivelyTypeGraphItems(item[key], types))
+ )
+ safetlyAddObjectProp(tmp, reservedTypePropertyName, 'LocalTime')
+ return tmp
+ }
+ if (item instanceof types.Time) {
+ const keys = Object.keys(item)
+ let tmp = {}
+ keys.forEach(
+ key => (tmp[key] = recursivelyTypeGraphItems(item[key], types))
+ )
+ safetlyAddObjectProp(tmp, reservedTypePropertyName, 'Time')
+ return tmp
+ }
if (neo4j.isInt(item)) {
return safetlyAddObjectProp(item, reservedTypePropertyName, 'Integer')
}
diff --git a/src/shared/services/bolt/cypherTypesFormatting.js b/src/shared/services/bolt/cypherTypesFormatting.js
new file mode 100644
index 00000000000..cc469341e25
--- /dev/null
+++ b/src/shared/services/bolt/cypherTypesFormatting.js
@@ -0,0 +1,28 @@
+import { v1 as neo4j } from 'neo4j-driver-alias'
+
+export const stringFormat = anything => {
+ if (typeof anything === 'number') {
+ if (Math.floor(anything) === anything) {
+ return `${anything}.0`
+ }
+ return undefined
+ }
+ if (neo4j.isInt(anything)) {
+ return anything.toString()
+ }
+ if (anything instanceof neo4j.types.Point) {
+ const zString = anything.z ? `, z:${anything.z}` : ''
+ return `point({srid:${anything.srid}, x:${anything.x}, y:${anything.y}${zString}})`
+ }
+ if (
+ anything instanceof neo4j.types.Date ||
+ anything instanceof neo4j.types.DateTime ||
+ anything instanceof neo4j.types.Duration ||
+ anything instanceof neo4j.types.LocalDateTime ||
+ anything instanceof neo4j.types.LocalTime ||
+ anything instanceof neo4j.types.Time
+ ) {
+ return `"${anything.toString()}"`
+ }
+ return undefined
+}
diff --git a/yarn.lock b/yarn.lock
index de64864ea7d..ee4297b1ab4 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -5660,9 +5660,9 @@ negotiator@0.6.1:
version "0.6.1"
resolved "https://neo.jfrog.io/neo/api/npm/npm/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9"
-neo4j-driver@^1.5.3:
- version "1.5.3"
- resolved "https://neo.jfrog.io/neo/api/npm/npm/neo4j-driver/-/neo4j-driver-1.5.3.tgz#aa7cec63ed793dd5a51c98ab0477edc35c293248"
+neo4j-driver@1.6.0-rc1:
+ version "1.6.0-rc1"
+ resolved "https://neo.jfrog.io/neo/api/npm/npm/neo4j-driver/-/neo4j-driver-1.6.0-rc1.tgz?dl=https://registry.npmjs.org/neo4j-driver/-/neo4j-driver-1.6.0-rc1.tgz#8590f05a5e23d2057e898c4209f2f1b4ccc77ae0"
dependencies:
babel-runtime "^6.18.0"
url-parse "^1.2.0"