Skip to content

Add support for multi-labeled nodes #82

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/node.js
Original file line number Diff line number Diff line change
@@ -7,12 +7,12 @@ class Node {
/**
* Builds a node object.
*
* @param {string} label - node label.
* @param {string|string[]} label - node label(s).
* @param {Map} properties - properties map.
*/
constructor(label, properties) {
this.id = undefined; //node's id - set by RedisGraph
this.label = label; //node's label
this.label = label; //node's label(s)
this.properties = properties; //node's list of properties (list of Key:Value)
}

42 changes: 29 additions & 13 deletions src/resultSet.js
Original file line number Diff line number Diff line change
@@ -174,31 +174,47 @@ class ResultSet {
}

/**
* Parse raw node representation into a Node object.
* Parse label index into a label string.
* @async
* @param {object[]} cell raw node representation.
* @returns {Promise<Node>} Node object.
* @param {number} label_idx index of label.
* @returns {Promise<string>} string representation of label.
*/
async parseNode(cell) {
// Node ID (integer),
// [label string offset (integer)],
// [[name, value, value type] X N]

let node_id = cell[0];
let label = this._graph.getLabel(cell[1][0]);
async parseNodeLabel(label_idx) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Class properties must be methods. Expected '(' but instead saw 'parseNodeLabel'.
Duplicate class method 'async'.

let label = this._graph.getLabel(label_idx);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'let' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).

// will try to get the right label for at most 10 times
var tries = 0;
while (label == undefined && tries < 10) {
label = await this._graph.fetchAndGetLabel(cell[1][0]);
label = await this._graph.fetchAndGetLabel(label_idx);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing semicolon.

tries++;
}
if (label == undefined) {
console.warn(
"unable to retrive label value for label index " + cell[1][0]
"unable to retrieve label value for label index " + label_idx
);
}
return label;
}

/**
* Parse raw node representation into a Node object.
* @async
* @param {object[]} cell raw node representation.
* @returns {Promise<Node>} Node object.
*/
async parseNode(cell) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Class properties must be methods. Expected '(' but instead saw 'parseNode'.
Duplicate class method 'async'.

// Node ID (integer),
// [label string offset (integer) X N],
// [[name, value, value type] X N]

let node_id = cell[0];
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'let' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).

var labels = undefined;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not necessary to initialize 'labels' to 'undefined'.

if (cell[1].length == 1) {
labels = await this.parseNodeLabel(cell[1][0]);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing semicolon.

} else {
labels = await Promise.all(cell[1].map(x => this.parseNodeLabel(x)));
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'arrow function syntax (=>)' is only available in ES6 (use 'esversion: 6').
Missing semicolon.

}
let properties = await this.parseEntityProperties(cell[2]);
let node = new Node(label, properties);
let node = new Node(labels, properties);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'let' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).

node.setId(node_id);
return node;
}
48 changes: 48 additions & 0 deletions test/redisGraphAPITest.js
Original file line number Diff line number Diff line change
@@ -95,6 +95,54 @@ describe("RedisGraphAPI Test", () => {
);
});

it("test Create Multi-Labeled Node", async () => {
// Create a node with 2 labels
let result = await api.query("CREATE (:human:male {name:'danny', age:12})");
assert.equal(result.size(), 0);
assert.ok(!result.hasNext());
assert.equal(
"1",
result.getStatistics().getStringValue(Label.NODES_CREATED)
);
assert.equal(
"2",
result.getStatistics().getStringValue(Label.PROPERTIES_SET)
);
assert.ok(
result
.getStatistics()
.getStringValue(Label.QUERY_INTERNAL_EXECUTION_TIME)
);

// Retrieve the node
let resultSet = await api.query(
"MATCH (a:human:male) RETURN a"
);
assert.equal(resultSet.size(), 1);
assert.ok(resultSet.hasNext());
assert.equal(0, resultSet.getStatistics().nodesCreated());
assert.equal(0, resultSet.getStatistics().nodesDeleted());
assert.equal(0, resultSet.getStatistics().labelsAdded());
assert.equal(0, resultSet.getStatistics().propertiesSet());
assert.equal(0, resultSet.getStatistics().relationshipsCreated());
assert.equal(0, resultSet.getStatistics().relationshipsDeleted());
assert.ok(
resultSet
.getStatistics()
.getStringValue(Label.QUERY_INTERNAL_EXECUTION_TIME)
);

assert.deepStrictEqual(["a"], resultSet.getHeader());

let record = resultSet.next();
let n = record.get(0);
assert.equal(12, n.properties["age"]);
assert.equal("danny", n.properties["name"]);
assert.deepEqual(["human", "male"], n.label);
assert.equal(0, n.id);

});

it("test Connect Nodes", async () => {
// Create both source and destination nodes
await api.query("CREATE (:person {name:'roi', age:34})");
2 changes: 1 addition & 1 deletion types/src/edge.d.ts
Original file line number Diff line number Diff line change
@@ -32,4 +32,4 @@ declare class Edge {
declare namespace Edge {
export { Node };
}
type Node = import("./node");
type Node = import('./node');
31 changes: 29 additions & 2 deletions types/src/graph.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
export = Graph;
/**
* @typedef {import('ioredis') | redis.RedisClient} RedisClient
*/
/**
* RedisGraph client
*/
@@ -8,11 +11,11 @@ declare class Graph {
* See: node_redis for more options on createClient
*
* @param {string} graphId the graph id
* @param {string | redis.RedisClient} [host] Redis host or node_redis client
* @param {string | RedisClient} [host] Redis host or node_redis client or ioredis client
* @param {string | number} [port] Redis port (integer)
* @param {Object} [options] node_redis options
*/
constructor(graphId: string, host?: string | any, port?: string | number, options?: any);
constructor(graphId: string, host?: string | RedisClient, port?: string | number, options?: any);
_graphId: string;
_labels: any[];
_relationshipTypes: any[];
@@ -53,6 +56,26 @@ declare class Graph {
* @returns {Promise<ResultSet>} a promise contains a result set
*/
query(query: string, params?: Map<any, any>): Promise<ResultSet>;
/**
* Execute a Cypher readonly query
* @async
* @param {string} query Cypher query
* @param {Map} [params] Parameters map
*
* @returns {Promise<ResultSet>} a promise contains a result set
*/
readonlyQuery(query: string, params?: Map<any, any>): Promise<ResultSet>;
/**
* Execute a Cypher query
* @private
* @async
* @param {'graph.QUERY'|'graph.RO_QUERY'} command
* @param {string} query Cypher query
* @param {Map} [params] Parameters map
*
* @returns {Promise<ResultSet>} a promise contains a result set
*/
private _query;
/**
* Deletes the entire graph
* @async
@@ -122,4 +145,8 @@ declare class Graph {
*/
fetchAndGetProperty(id: number): Promise<string>;
}
declare namespace Graph {
export { RedisClient };
}
import ResultSet = require("./resultSet");
type RedisClient = any | any;
6 changes: 3 additions & 3 deletions types/src/node.d.ts
Original file line number Diff line number Diff line change
@@ -6,12 +6,12 @@ declare class Node {
/**
* Builds a node object.
*
* @param {string} label - node label.
* @param {string|string[]} label - node label(s).
* @param {Map} properties - properties map.
*/
constructor(label: string, properties: Map<any, any>);
constructor(label: string | string[], properties: Map<any, any>);
id: number;
label: string;
label: string | string[];
properties: Map<any, any>;
/**
* Sets the node id.
4 changes: 2 additions & 2 deletions types/src/path.d.ts
Original file line number Diff line number Diff line change
@@ -64,5 +64,5 @@ declare class Path {
declare namespace Path {
export { Node, Edge };
}
type Node = import("./node");
type Edge = import("./edge");
type Node = import('./node');
type Edge = import('./edge');
18 changes: 17 additions & 1 deletion types/src/resultSet.d.ts
Original file line number Diff line number Diff line change
@@ -50,6 +50,13 @@ declare class ResultSet {
* @returns {Promise<object>} Map with the parsed properties.
*/
parseEntityProperties(props: object[]): Promise<object>;
/**
* Parse label index into a label string
* @async
* @param {number} label_idx index of label
* @returns {Promise<string>} string representation of label.
*/
parseNodeLabel(label_idx: number): Promise<string>;
/**
* Parse raw node representation into a Node object.
* @async
@@ -85,6 +92,15 @@ declare class ResultSet {
* @returns {Promise<object>} Map object.
*/
parseMap(rawMap: object[]): Promise<object>;
/**
* Parse a raw Point representation into a lat-lon Map object.
* @param {object[]} rawPoint 2-valued lat-lon array representation
* @returns {{ latitude: number, longitude: number }} Map object with latitude and longitude keys.
*/
parsePoint(rawPoint: object[]): {
latitude: number;
longitude: number;
};
/**
* Parse a raw value into its actual value.
* @async
@@ -121,4 +137,4 @@ import Node = require("./node");
import Edge = require("./edge");
import Path = require("./path");
import Record = require("./record");
type Graph = import("./graph");
type Graph = import('./graph');