diff --git a/README.md b/README.md index cd5807e731..2ca803e505 100644 --- a/README.md +++ b/README.md @@ -30,27 +30,36 @@ npm install redisgraph.js # Example: Using the JavaScript Client ```javascript -const RedisGraph = require("redisgraph.js").RedisGraph; - -let graph = new RedisGraph('social'); -graph -.query("CREATE (:person{name:'roi',age:32})") -.then( () => { - return graph.query("CREATE (:person{name:'amit',age:30})"); -}) -.then( () => { - return graph.query("MATCH (a:person), (b:person) WHERE (a.name = 'roi' AND b.name='amit') CREATE (a)-[:knows]->(b)") -}) -.then( () => { - return graph.query("MATCH (a:person)-[:knows]->(:person) RETURN a") -}) -.then( (res) => { - while(res.hasNext()){ - let record = res.next(); - console.log(record.getString('a.name')); - } - console.log(res.getStatistics().queryExecutionTime()); -}); +const RedisGraph = require("redisgraph.js").Graph; + +let graph = new RedisGraph("social"); + +graph.query("CREATE (:person{name:'roi',age:32})").then(() => { + graph.query("CREATE (:person{name:'amit',age:30})").then(()=>{ + graph.query("MATCH (a:person), (b:person) WHERE (a.name = 'roi' AND b.name='amit') CREATE (a)-[:knows]->(b)").then(()=>{ + graph.query("MATCH (a:person)-[:knows]->(:person) RETURN a.name").then(res=>{ + while (res.hasNext()) { + let record = res.next(); + console.log(record.get("a.name")); + } + console.log(res.getStatistics().queryExecutionTime()); + graph.query("MATCH p = (a:person)-[:knows]->(:person) RETURN p").then(res=>{ + while (res.hasNext()) { + let record = res.next(); + // See path.js for more path API. + console.log(record.get("p").nodeCount); + graph.deleteGraph(); + process.exit(); + } + }) + }) + }) + }) + }) + .catch(err => { + console.log(err); + }); + ``` diff --git a/examples/redisGraphExample.js b/examples/redisGraphExample.js index 7097923bba..00c92d8042 100644 --- a/examples/redisGraphExample.js +++ b/examples/redisGraphExample.js @@ -1,26 +1,28 @@ -const RedisGraph = require("redisgraph.js").RedisGraph; +const RedisGraph = require("redisgraph.js").Graph; let graph = new RedisGraph("social"); -graph - .query("CREATE (:person{name:'roi',age:32})") - .then(() => { - return graph.query("CREATE (:person{name:'amit',age:30})"); - }) - .then(() => { - return graph.query( - "MATCH (a:person), (b:person) WHERE (a.name = 'roi' AND b.name='amit') CREATE (a)-[:knows]->(a)" - ); - }) - .then(() => { - return graph.query("MATCH (a:person)-[:knows]->(:person) RETURN a"); - }) - .then(res => { - while (res.hasNext()) { - let record = res.next(); - console.log(record.getString("a.name")); - } - console.log(res.getStatistics().queryExecutionTime()); +graph.query("CREATE (:person{name:'roi',age:32})").then(() => { + graph.query("CREATE (:person{name:'amit',age:30})").then(()=>{ + graph.query("MATCH (a:person), (b:person) WHERE (a.name = 'roi' AND b.name='amit') CREATE (a)-[:knows]->(b)").then(()=>{ + graph.query("MATCH (a:person)-[:knows]->(:person) RETURN a.name").then(res=>{ + while (res.hasNext()) { + let record = res.next(); + console.log(record.get("a.name")); + } + console.log(res.getStatistics().queryExecutionTime()); + graph.query("MATCH p = (a:person)-[:knows]->(:person) RETURN p").then(res=>{ + while (res.hasNext()) { + let record = res.next(); + // See path.js for more path API. + console.log(record.get("p").nodeCount); + graph.deleteGraph(); + process.exit(); + } + }) + }) + }) + }) }) .catch(err => { console.log(err); diff --git a/package.json b/package.json index c06f53815d..f987a0ba4a 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "url": "git://github.com/redislabs/redisgraph.js.git" }, "dependencies": { + "deep-equal": "^1.1.0", "redis": "^2.8.0" }, "devDependencies": { diff --git a/src/edge.js b/src/edge.js index f907295868..d671e4b35b 100644 --- a/src/edge.js +++ b/src/edge.js @@ -1,3 +1,4 @@ +"use strict"; /** * An edge connecting two nodes. */ diff --git a/src/graph.js b/src/graph.js index befc6c5157..4b75506d34 100644 --- a/src/graph.js +++ b/src/graph.js @@ -1,3 +1,4 @@ +"use strict"; const redis = require("redis"), util = require("util"), ResultSet = require("./resultSet"); diff --git a/src/label.js b/src/label.js index 33e1565dc2..39f7d2de4f 100644 --- a/src/label.js +++ b/src/label.js @@ -1,3 +1,4 @@ +"use strict"; /** * Different Statistics labels */ diff --git a/src/node.js b/src/node.js index 1b242a9b9e..3018abb8ae 100644 --- a/src/node.js +++ b/src/node.js @@ -1,3 +1,4 @@ +"use strict"; /** * A node within the garph. */ diff --git a/src/path.js b/src/path.js new file mode 100644 index 0000000000..83f0bab15d --- /dev/null +++ b/src/path.js @@ -0,0 +1,46 @@ +"use strict"; +class Path { + constructor(nodes, edges){ + this.nodes = nodes; + this.edges = edges; + } + + get Nodes(){ + return this.nodes; + } + + get Edges(){ + return this.edges; + } + + getNode(index){ + return this.nodes[index]; + } + + getEdge(index){ + return this.edges[index]; + } + + get firstNode(){ + return this.nodes[0]; + } + + get lastNode(){ + return this.nodes[this.nodes.length -1]; + } + + get nodeCount(){ + return this.nodes.length; + } + + get edgeCount(){ + return this.edges.length; + } + + toString() { + return JSON.stringify(this); + } + +} + +module.exports = Path; diff --git a/src/record.js b/src/record.js index 17826fc308..afd1ede43e 100644 --- a/src/record.js +++ b/src/record.js @@ -1,3 +1,4 @@ +"use strict"; /** * Hold a query record */ diff --git a/src/resultSet.js b/src/resultSet.js index b954f9c07b..3afea4a353 100644 --- a/src/resultSet.js +++ b/src/resultSet.js @@ -1,8 +1,10 @@ +"use strict"; const Statistics = require("./statistics"), - Record = require("./record"); - Node = require("./node"); - Edge = require("./edge"); - ReplyError = require("redis").ReplyError + Record = require("./record"), + Node = require("./node"), + Edge = require("./edge"), + Path = require("./path"), + ReplyError = require("redis").ReplyError; const ResultSetColumnTypes = { COLUMN_UNKNOWN: 0, @@ -20,7 +22,8 @@ const ResultSetValueTypes = { VALUE_DOUBLE: 5, VALUE_ARRAY: 6, VALUE_EDGE: 7, - VALUE_NODE: 8 + VALUE_NODE: 8, + VALUE_PATH: 9 } /** @@ -190,6 +193,12 @@ class ResultSet { return rawArray; } + async parsePath(rawPath) { + let nodes = await this.parseScalar(rawPath[0]); + let edges = await this.parseScalar(rawPath[1]); + return new Path(nodes, edges); + } + async parseScalar(cell) { let scalar_type = cell[0]; let value = cell[1]; @@ -224,6 +233,9 @@ class ResultSet { case ResultSetValueTypes.VALUE_EDGE: scalar = await this.parseEdge(value); break; + case ResultSetValueTypes.VALUE_PATH: + scalar = await this.parsePath(value); + break; case ResultSetValueTypes.VALUE_UNKNOWN: console.log("Unknown scalar type\n"); break; diff --git a/src/statistics.js b/src/statistics.js index 711ee7d36f..0618a0aa9d 100644 --- a/src/statistics.js +++ b/src/statistics.js @@ -1,3 +1,4 @@ +"use strict"; const Label = require("./label"); class Statistics { diff --git a/test/pathBuilder.js b/test/pathBuilder.js new file mode 100644 index 0000000000..74eb46a0d8 --- /dev/null +++ b/test/pathBuilder.js @@ -0,0 +1,36 @@ +"use strict"; +const Node = require("../src/node"), + Edge = require("../src/edge"), + Path = require("../src/path"); + +class PathBuilder { + constructor(nodeCount){ + this.nodes = new Array(); + this.edges = new Array(); + this.currentAppendClass = Node; + } + + append(obj){ + if(! obj instanceof this.currentAppendClass) throw "Error in path build insertion order and types." + if(obj instanceof Node) return this._appendNode(obj); + else return this._appendEdge(obj); + } + + build(){ + return new Path(this.nodes, this.edges); + } + + _appendNode(node){ + this.nodes.push(node); + this.currentAppendClass = Edge; + return this; + } + + _appendEdge(edge){ + this.edges.push(edge); + this.currentAppendClass = Node; + return this; + } +} + +module.exports = PathBuilder; diff --git a/test/redisGraphAPITest.js b/test/redisGraphAPITest.js index f5ee8f4562..687cedde76 100644 --- a/test/redisGraphAPITest.js +++ b/test/redisGraphAPITest.js @@ -1,7 +1,13 @@ +"use strict"; const assert = require("assert"), redis = require("redis"), Label = require("../src/label"), - RedisGraph = require("../src/graph"); + RedisGraph = require("../src/graph"), + Node = require("../src/node"), + Edge = require("../src/edge"), + Path = require("../src/path"), + PathBuilder = require("./pathBuilder"), + deepEqual = require('deep-equal'); describe('RedisGraphAPI Test', function () { const api = new RedisGraph("social"); @@ -288,4 +294,68 @@ describe('RedisGraphAPI Test', function () { }) }) + it('unitTestPath', ()=>{ + let node0 = new Node("L1", {}); + node0.setId(0); + let node1 = new Node("L1", {}); + node1.setId(1); + + let edge01 = new Edge(0, "R1", 1, {}); + edge01.setId(0); + + let path01 = new PathBuilder().append(node0).append(edge01).append(node1).build(); + + assert.equal(1, path01.edgeCount); + assert.equal(2, path01.nodeCount); + assert.deepEqual(node0, path01.firstNode); + assert.deepEqual(node0, path01.getNode(0)); + assert.deepEqual(node1, path01.lastNode); + assert.deepEqual(node1, path01.getNode(1)); + assert.deepEqual(edge01, path01.getEdge(0)); + assert.deepEqual([node0, node1], path01.nodes); + assert.deepEqual([edge01], path01.edges); + + }) + + it('testPath', (done)=>{ + api.query("CREATE (:L1)-[:R1]->(:L1)-[:R1]->(:L1)").then(response => { + api.query("MATCH p = (:L1)-[:R1*]->(:L1) RETURN p").then(response =>{ + let node0 = new Node("L1", {}); + node0.setId(0); + let node1 = new Node("L1", {}); + node1.setId(1); + let node2 = new Node("L1", {}); + node2.setId(2); + let edge01 = new Edge(0, "R1", 1, {}); + edge01.setId(0); + let edge12 = new Edge(1, "R1", 2, {}); + edge12.setId(1); + + let path01 = new PathBuilder().append(node0).append(edge01).append(node1).build(); + let path12 = new PathBuilder().append(node1).append(edge12).append(node2).build(); + let path02 = new PathBuilder().append(node0).append(edge01).append(node1).append(edge12).append(node2).build(); + + let paths = new Set([path01, path12, path02]); + while(response.hasNext()){ + let p = response.next().get("p"); + let pInPaths = false; + let path = null; + let pathsIterator = paths.values(); + for( pathsIterator; path = pathsIterator.next().value;){ + if(deepEqual(p ,path)){ + pInPaths = true; + break; + } + } + assert(pInPaths); + paths.delete(path); + } + assert.equal(0, paths.size); + done(); + }) + }).catch(error => { + console.log(error); + }) + }) + });