Skip to content

Converted to typescript #61

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

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
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
1 change: 1 addition & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ jobs:

# run tests!
- run: sudo npm install -g istanbul codecov
- run: npx tsc
- run: istanbul cover ./node_modules/mocha/bin/_mocha -- -R spec --exit
- early_return_for_forked_pull_requests
- run: codecov -t ${CODECOV_TOKEN}
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ yarn.lock
examples/node_modules
coverage/
.DS_Store
dist/
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const RedisGraph = require("redisgraph.js").Graph;

import {Graph as RedisGraph} from 'redisgraph.js';

let graph = new RedisGraph("social");

Expand All @@ -18,7 +19,7 @@ try {
let record = res.next();
console.log(record.get("a.name"));
}
console.log(res.getStatistics().queryExecutionTime());
console.log(res.getStatistics()?.queryExecutionTime());

// Match with parameters.
let param = { age: 30 };
Expand Down
20 changes: 20 additions & 0 deletions examples/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"compilerOptions": {
"target": "es5",
"module": "UMD",
"lib": ["es5"],
"strict": true,
"allowJs": true,
"inlineSourceMap": true,
"inlineSources": true,
"outDir": "./dist",
"moduleResolution": "node",
"downlevelIteration": true,
"rootDir": "./",
"baseUrl": "./",
"declaration": true,

},
"include": ["./"],
"exclude": ["dist"]
}
13 changes: 0 additions & 13 deletions index.js

This file was deleted.

9 changes: 6 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,13 @@
"redis": "^3.0.2"
},
"devDependencies": {
"mocha": "^7.0.1"
"@types/deep-equal": "^1.0.1",
"@types/redis": "^2.8.28",
"mocha": "^7.0.1",
"typescript": "^4.1.3"
},
"scripts": {
"test": "mocha --exit"
"test": "npx tsc && mocha --exit"
},
"main": "index.js"
"main": "dist/index.js"
}
11 changes: 6 additions & 5 deletions src/edge.js → src/edge.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
"use strict";
import {Node} from "./node";
/**
* An edge connecting two nodes.
*/
class Edge {
export class Edge {

private id?: number;
/**
* Builds an Edge object.
* @constructor
Expand All @@ -11,7 +13,7 @@ class Edge {
* @param {Node} destNode - Destination node of the edge.
* @param {Map} properties - Properties map of the edge.
*/
constructor(srcNode, relation, destNode, properties) {
constructor(private srcNode: Node, private relation: string, private destNode: Node, private properties: Map<string, any>) {
this.id = undefined; //edge's id - set by RedisGraph
this.relation = relation; //edge's relationship type
this.srcNode = srcNode; //edge's source node
Expand All @@ -23,7 +25,7 @@ class Edge {
* Sets the edge ID.
* @param {int} id
*/
setId(id) {
setId(id:number) {
this.id = id;
}

Expand All @@ -35,4 +37,3 @@ class Edge {
}
}

module.exports = Edge;
279 changes: 279 additions & 0 deletions src/graph.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,279 @@
import * as redis from "redis";
import { ClientOpts, RedisClient } from "redis";
import * as util from "util";
import { ResultSet } from "./resultSet";

function isString(value: any): value is string {
return typeof value === "string";
}

/**
* RedisGraph client
*/
export class Graph {
private _labels: string[] = []; // List of node labels.
private _relationshipTypes: string[] = []; // List of relation types.
private _properties: string[] = []; // List of properties.

private _labelsPromise: Promise<string[]> | undefined; // used as a synchronization mechanizom for labels retrival
private _propertyPromise: Promise<string[]> | undefined; // used as a synchronization mechanizom for property names retrival
private _relationshipPromise: Promise<string[]> | undefined; // used as a synchronization mechanizom for relationship types retrival
private _client: RedisClient;
private _sendCommand:
| ((command: string) => Promise<any>)
| ((command: string, args?: any[]) => Promise<any>);
/**
* Creates a client to a specific graph running on the specific host/post
* See: node_redis for more options on createClient
*
* @param {string} graphId the graph id
* @param {string | RedisClient} [host] Redis host or node_redis client
* @param {string | int} [port] Redis port
* @param {ClientOpts} [options] node_redis options
*/
constructor(
private _graphId: string,
host?: string | RedisClient,
port?: number,
options?: ClientOpts
) {
this._labels = []; // List of node labels.
this._relationshipTypes = []; // List of relation types.
this._properties = []; // List of properties.

this._labelsPromise = undefined; // used as a synchronization mechanizom for labels retrival
this._propertyPromise = undefined; // used as a synchronization mechanizom for property names retrival
this._relationshipPromise = undefined; // used as a synchronization mechanizom for relationship types retrival

this._client =
host instanceof redis.RedisClient
? host
: port
? redis.createClient(port, host, options)
: redis.createClient();
this._sendCommand = util
.promisify<string, any>(this._client.send_command)
.bind(this._client);
}
/**
* Closes the client.
*/
close() {
this._client.quit();
}

/**
* Auxiliary function to extract string(s) data from procedures such as:
* db.labels, db.propertyKeys and db.relationshipTypes
* @param {ResultSet} resultSet - a procedure result set
* @returns {string[]} strings array.
*/
_extractStrings(resultSet: ResultSet): string[] {
var strings = [];
while (resultSet.hasNext()) {
strings.push(resultSet.next().getString(0));
}
return strings;
}

/**
* Transforms a parameter value to string.
* @param {object} paramValue
* @returns {string} the string representation of paramValue.
*/
paramToString(paramValue: null | string | any[]): string {
if (paramValue == null) return "null";
if (isString(paramValue)) {
let strValue = "";
paramValue = paramValue.replace(/[\\"']/g, "\\$&");
if (paramValue[0] != '"') strValue += '"';
strValue += paramValue;
if (!paramValue.endsWith('"') || paramValue.endsWith('\\"'))
strValue += '"';
return strValue;
}
if (Array.isArray(paramValue)) {
let stringsArr = new Array(paramValue.length);
for (var i = 0; i < paramValue.length; i++) {
stringsArr[i] = this.paramToString(paramValue[i]);
}
return ["[", stringsArr.join(", "), "]"].join("");
}
return paramValue;
}

/**
* Extracts parameters from dictionary into cypher parameters string.
* @param {Map} params parameters dictionary.
* @return {string} a cypher parameters string.
*/
buildParamsHeader(params: any) {
let paramsArray = ["CYPHER"];

for (var key in params) {
let value = this.paramToString(params[key]);
paramsArray.push(`${key}=${value}`);
}
paramsArray.push(" ");
return paramsArray.join(" ");
}

/**
* Execute a Cypher query
* @async
* @param {string} query Cypher query
* @param {Map} [params] Parameters map
* @returns {ResultSet} a promise contains a result set
*/
async query(query: string, params?: object) {
if (params) {
query = this.buildParamsHeader(params) + query;
}
var res = await this._sendCommand("graph.QUERY", [
this._graphId,
query,
"--compact",
]);
var resultSet = new ResultSet(this);
return resultSet.parseResponse(res);
}

/**
* Deletes the entire graph
* @async
* @returns {ResultSet} a promise contains the delete operation running time statistics
*/
async deleteGraph() {
var res = await this._sendCommand("graph.DELETE", [this._graphId]);
//clear internal graph state
this._labels = [];
this._relationshipTypes = [];
this._properties = [];
var resultSet = new ResultSet(this);
return resultSet.parseResponse(res);
}

/**
* Calls procedure
* @param {string} procedure Procedure to call
* @param {string[]} [args] Arguments to pass
* @param {string[]} [y] Yield outputs
* @returns {ResultSet} a promise contains the procedure result set data
*/
callProcedure(procedure: string, args = new Array(), y = new Array()) {
let q = "CALL " + procedure + "(" + args.join(",") + ")" + y.join(" ");
return this.query(q);
}

/**
* Retrieves all labels in graph.
* @async
*/
async labels() {
if (this._labelsPromise == undefined) {
this._labelsPromise = this.callProcedure("db.labels").then((response) => {
return this._extractStrings(response);
});
this._labels = await this._labelsPromise;
this._labelsPromise = undefined;
} else {
await this._labelsPromise;
}
}

/**
* Retrieves all relationship types in graph.
* @async
*/
async relationshipTypes() {
if (this._relationshipPromise == undefined) {
this._relationshipPromise = this.callProcedure(
"db.relationshipTypes"
).then((response) => {
return this._extractStrings(response);
});
this._relationshipTypes = await this._relationshipPromise;
this._relationshipPromise = undefined;
} else {
await this._relationshipPromise;
}
}

/**
* Retrieves all properties in graph.
* @async
*/
async propertyKeys() {
if (this._propertyPromise == undefined) {
this._propertyPromise = this.callProcedure("db.propertyKeys").then(
(response) => {
return this._extractStrings(response);
}
);
this._properties = await this._propertyPromise;
this._propertyPromise = undefined;
} else {
await this._propertyPromise;
}
}

/**
* Retrieves label by ID.
* @param {int} id internal ID of label.
* @returns {string} String label.
*/
getLabel(id: number): string {
return this._labels[id];
}

/**
* Retrieve all the labels from the graph and returns the wanted label
* @async
* @param {int} id internal ID of label.
* @returns {string} String label.
*/
async fetchAndGetLabel(id: number) {
await this.labels();
return this._labels[id];
}

/**
* Retrieves relationship type by ID.
* @param {int} id internal ID of relationship type.
* @return String relationship type.
*/
getRelationship(id: number) {
return this._relationshipTypes[id];
}

/**
* Retrieves al the relationships types from the graph, and returns the wanted type
* @async
* @param {int} id internal ID of relationship type.
* @returns {string} String relationship type.
*/
async fetchAndGetRelationship(id: number): Promise<string> {
await this.relationshipTypes();
return this._relationshipTypes[id];
}

/**
* Retrieves property name by ID.
* @param {int} id internal ID of property.
* @returns {string} String property.
*/
getProperty(id: number): string {
return this._properties[id];
}

/**
* Retrieves al the properties from the graph, and returns the wanted property
* @async
* @param {int} id internal ID of property.
* @returns {string} String property.
*/
async fetchAndGetProperty(id: number): Promise<string> {
await this.propertyKeys();
return this._properties[id];
}
}
Loading