From 9d091c8e1b2fc3caa0fbeeeb9a0ceb0dd32145ae Mon Sep 17 00:00:00 2001
From: Denis Carriere <carriere.denis@gmail.com>
Date: Tue, 19 Feb 2019 16:50:29 -0500
Subject: [PATCH] Convert redisgraph.js to Typescript

---
 .gitignore                                    |  1 +
 index.js                                      | 13 ----------
 index.ts                                      |  5 ++++
 package.json                                  | 11 ++++++---
 src/{label.js => label.ts}                    |  4 +---
 src/{record.js => record.ts}                  | 21 +++++++++-------
 src/{redisGraph.js => redisGraph.ts}          | 18 +++++++-------
 src/{resultSet.js => resultSet.ts}            | 19 ++++++++++-----
 src/{statistics.js => statistics.ts}          | 16 ++++++-------
 ...isGraphAPITest.js => redisGraphAPITest.ts} | 24 +++++++++----------
 tsconfig.json                                 | 17 +++++++++++++
 11 files changed, 87 insertions(+), 62 deletions(-)
 delete mode 100644 index.js
 create mode 100644 index.ts
 rename src/{label.js => label.ts} (86%)
 rename src/{record.js => record.ts} (51%)
 rename src/{redisGraph.js => redisGraph.ts} (69%)
 rename src/{resultSet.js => resultSet.ts} (71%)
 rename src/{statistics.js => statistics.ts} (82%)
 rename test/{redisGraphAPITest.js => redisGraphAPITest.ts} (92%)
 create mode 100644 tsconfig.json

diff --git a/.gitignore b/.gitignore
index e171686cee..5d42caa5fd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,3 +4,4 @@
 package-lock.json
 yarn.lock
 /examples/node_modules
+dist
\ No newline at end of file
diff --git a/index.js b/index.js
deleted file mode 100644
index 95cad74544..0000000000
--- a/index.js
+++ /dev/null
@@ -1,13 +0,0 @@
-const Record = require("./src/record"),
-	RedisGraph = require("./src/redisGraph"),
-	ResultSet = require("./src/resultSet"),
-	Statistics = require("./src/statistics"),
-	Label = require("./src/label");
-
-module.exports = {
-	Record: Record,
-	RedisGraph: RedisGraph,
-	ResultSet: ResultSet,
-	Statistics: Statistics,
-	Label: Label
-};
diff --git a/index.ts b/index.ts
new file mode 100644
index 0000000000..828ff42a7f
--- /dev/null
+++ b/index.ts
@@ -0,0 +1,5 @@
+export * from "./src/record"
+export * from "./src/redisGraph"
+export * from "./src/resultSet"
+export * from "./src/statistics"
+export * from "./src/label"
diff --git a/package.json b/package.json
index 7e368b6371..c66a7fe890 100644
--- a/package.json
+++ b/package.json
@@ -12,10 +12,15 @@
 		"redis": "^2.8.0"
 	},
 	"devDependencies": {
-		"mocha": "^5.2.0"
+		"@types/mocha": "^5.2.6",
+		"@types/redis": "^2.8.10",
+		"mocha": "^5.2.0",
+		"ts-mocha": "^2.0.0",
+		"typescript": "^3.3.3"
 	},
 	"scripts": {
-		"test": "mocha --exit"
+		"test": "ts-mocha test/*.ts --exit"
 	},
-	"main": "index.js"
+	"main": "dist/index.js",
+	"types": "dist/index.d.js"
 }
diff --git a/src/label.js b/src/label.ts
similarity index 86%
rename from src/label.js
rename to src/label.ts
index 33e1565dc2..c3fe7fa81c 100644
--- a/src/label.js
+++ b/src/label.ts
@@ -1,7 +1,7 @@
 /**
  * Different Statistics labels
  */
-var Label = Object.freeze({
+export const Label = Object.freeze({
 	LABELS_ADDED: "Labels added",
 	NODES_CREATED: "Nodes created",
 	NODES_DELETED: "Nodes deleted",
@@ -10,5 +10,3 @@ var Label = Object.freeze({
 	RELATIONSHIPS_CREATED: "Relationships created",
 	QUERY_INTERNAL_EXECUTION_TIME: "Query internal execution time"
 });
-
-module.exports = Label;
diff --git a/src/record.js b/src/record.ts
similarity index 51%
rename from src/record.js
rename to src/record.ts
index d661e7e708..d9565828dc 100644
--- a/src/record.js
+++ b/src/record.ts
@@ -1,18 +1,25 @@
+type Header = string[]
+type Values = string[]
+
+
 /**
  * Hold a query record
  */
-class Record {
-	constructor(header, values) {
+export class Record {
+	private _header: Header;
+	private _values: Values;
+
+	constructor(header: Header, values: Values) {
 		this._header = header;
 		this._values = values;
 	}
 
-	getString(key) {
-		let index = key;
+	getString(key: string|number) {
+		let index: string|number = key;
 		if (typeof key === "string") {
 			index = this._header.indexOf(key);
 		}
-		return this._values[index];
+		return this._values[Number(index)];
 	}
 
 	keys() {
@@ -23,7 +30,7 @@ class Record {
 		return this._values;
 	}
 
-	containsKey(key) {
+	containsKey(key: string) {
 		return this._header.includes(key);
 	}
 
@@ -31,5 +38,3 @@ class Record {
 		return this._header.length;
 	}
 }
-
-module.exports = Record;
diff --git a/src/redisGraph.js b/src/redisGraph.ts
similarity index 69%
rename from src/redisGraph.js
rename to src/redisGraph.ts
index 4dbab581c4..79e34465be 100644
--- a/src/redisGraph.js
+++ b/src/redisGraph.ts
@@ -1,11 +1,13 @@
-const redis = require("redis"),
-	util = require("util"),
-	ResultSet = require("./resultSet");
+import redis, { ClientOpts, RedisClient } from "redis";
+import util from "util";
+import { ResultSet } from "./resultSet";
 
 /**
  * RedisGraph client
  */
-class RedisGraph {
+export class RedisGraph {
+	private _graphId: string;
+	private _sendCommand: (arg1: string, options: any) => Promise<void>;
 	/**
 	 * Creates a client to a specific graph running on the specific host/post
 	 * See: node_redis for more options on createClient
@@ -15,12 +17,12 @@ class RedisGraph {
 	 * @param port Redis port
 	 * @param options node_redis options
 	 */
-	constructor(graphId, host, port, options) {
+	constructor(graphId: string, host?: string | RedisClient, port=6379, options?: ClientOpts) {
 		this._graphId = graphId;
 		let client =
 			host instanceof redis.RedisClient
 				? host
-				: redis.createClient.apply(redis, [].slice.call(arguments, 1));
+				: redis.createClient(port, host, options);
 		this._sendCommand = util.promisify(client.send_command).bind(client);
 	}
 
@@ -30,7 +32,7 @@ class RedisGraph {
 	 * @param query Cypher query
 	 * @return a result set
 	 */
-	query(query) {
+	query(query: string) {
 		return this._sendCommand("graph.QUERY", [this._graphId, query]).then(
 			res => {
 				return new ResultSet(res);
@@ -49,5 +51,3 @@ class RedisGraph {
 		});
 	}
 }
-
-module.exports = RedisGraph;
diff --git a/src/resultSet.js b/src/resultSet.ts
similarity index 71%
rename from src/resultSet.js
rename to src/resultSet.ts
index f496a9c871..0bb8f6111b 100644
--- a/src/resultSet.js
+++ b/src/resultSet.ts
@@ -1,11 +1,19 @@
-const Statistics = require("./statistics"),
-	Record = require("./record");
+import { Statistics } from "./statistics"
+import { Record } from "./record";
+
+type Header = string[]
 
 /**
  * Hold a query result
  */
-class ResultSet {
-	constructor(resp) {
+export class ResultSet {
+	private _position: number
+	private _header: Header
+	private _totalResults: number
+	private _results: Record[]
+	private _statistics: Statistics
+
+	constructor(resp: any) {
 		this._position = 0;
 		this._statistics = new Statistics(resp[1]);
 
@@ -20,6 +28,7 @@ class ResultSet {
 			this._header = result[0];
 			this._totalResults = result.length - 1;
 			this._results = new Array(this._totalResults);
+
 			for (let i = 0; i < this._totalResults; ++i) {
 				this._results[i] = new Record(this._header, result[i + 1]);
 			}
@@ -42,5 +51,3 @@ class ResultSet {
 		return this._statistics;
 	}
 }
-
-module.exports = ResultSet;
diff --git a/src/statistics.js b/src/statistics.ts
similarity index 82%
rename from src/statistics.js
rename to src/statistics.ts
index 711ee7d36f..f49ab1f2b9 100644
--- a/src/statistics.js
+++ b/src/statistics.ts
@@ -1,11 +1,13 @@
-const Label = require("./label");
+import { Label } from "./label";
 
-class Statistics {
-	constructor(raw) {
+export class Statistics {
+	private _raw: any
+	private _statistics: any
+	constructor(raw: any) {
 		this._raw = raw;
 	}
 
-	getStringValue(label) {
+	getStringValue(label: string) {
 		return this.getStatistics()[label];
 	}
 
@@ -25,13 +27,13 @@ class Statistics {
 		return this._statistics;
 	}
 
-	getIntValue(label) {
+	getIntValue(label: string) {
 		let value = this.getStringValue(label);
 		return value ? parseInt(value) : 0;
 	}
 
 
-	getFloatValue(label) {
+	getFloatValue(label: string) {
 		let value = this.getStringValue(label);
 		return value ? parseFloat(value) : 0;
 	}
@@ -64,5 +66,3 @@ class Statistics {
 		return this.getFloatValue(Label.QUERY_INTERNAL_EXECUTION_TIME);
 	}
 }
-
-module.exports = Statistics;
diff --git a/test/redisGraphAPITest.js b/test/redisGraphAPITest.ts
similarity index 92%
rename from test/redisGraphAPITest.js
rename to test/redisGraphAPITest.ts
index 40c346021e..9077f738e3 100644
--- a/test/redisGraphAPITest.js
+++ b/test/redisGraphAPITest.ts
@@ -1,11 +1,11 @@
-const assert = require("assert"),
-	redis = require("redis"),
-	Label = require("../src/label"),
-	RedisGraph = require("../src/redisGraph");
+import assert from "assert";
+import redis from "redis";
+import { Label } from "../src/label";
+import { RedisGraph } from "../src/redisGraph";
 
 describe('RedisGraphAPI Test', () =>{
 	const api = new RedisGraph("social");
-	
+
 	beforeEach( () => {
 		return api.deleteGraph().catch(()=>{});
 	});
@@ -30,7 +30,7 @@ describe('RedisGraphAPI Test', () =>{
 			);
 			assert.equal(2, result.getStatistics().propertiesSet());
 			assert.ok( result.getStatistics().queryExecutionTime()); // not 0
-			assert.ok(result.getStatistics().getStringValue(Label.QUERY_INTERNAL_EXECUTION_TIME)); // exsits   
+			assert.ok(result.getStatistics().getStringValue(Label.QUERY_INTERNAL_EXECUTION_TIME)); // exsits
 		});
 	});
 
@@ -83,9 +83,9 @@ describe('RedisGraphAPI Test', () =>{
 	});
 
 	it('test Query', () => {
-		// Create both source and destination nodes    	
+		// Create both source and destination nodes
 		return api.query("CREATE (:qhuman{name:'roi',age:32})")
-		.then( (create1Result) => {	
+		.then( (create1Result) => {
 			return api.query("CREATE (:qhuman{name:'amit',age:30})");
 		})
 		.then( (create2Result) => {
@@ -96,7 +96,7 @@ describe('RedisGraphAPI Test', () =>{
 			// Query
 			return api.query("MATCH (a:qhuman)-[knows]->(:qhuman) RETURN a");
 		})
-		.then( (resultSet) => {	
+		.then( (resultSet) => {
 			assert.ok(resultSet.hasNext());
 			assert.equal(0, resultSet.getStatistics().nodesCreated());
 			assert.equal(0, resultSet.getStatistics().nodesDeleted());
@@ -104,15 +104,15 @@ describe('RedisGraphAPI Test', () =>{
 			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.ok(resultSet.getStatistics().getStringValue(Label.QUERY_INTERNAL_EXECUTION_TIME));
 
 			assert.deepStrictEqual( [ 'a.age', 'a.name' ], resultSet.getHeader());
-			
+
 			let record = resultSet.next();
 			assert.equal( "roi", record.getString(1));
 			assert.equal( "roi", record.getString("a.name"));
 			assert.equal( "32.000000", record.getString(0));
-			
+
 			assert.deepStrictEqual( [ 'a.age', 'a.name' ], record.keys());
 			assert.deepStrictEqual( [ '32.000000', 'roi' ], record.values());
 			assert.equal( false, record.containsKey("aa"));
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000000..0131b88c96
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,17 @@
+{
+  "compilerOptions": {
+    /* Basic Options */
+    "target": "es5",                          /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */
+    "module": "commonjs",                     /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
+    "declaration": true,                      /* Generates corresponding '.d.ts' file. */
+    "sourceMap": true,                        /* Generates corresponding '.map' file. */
+    "outDir": "./dist",                       /* Redirect output structure to the directory. */
+
+    /* Strict Type-Checking Options */
+    "strict": true,                           /* Enable all strict type-checking options. */
+
+    /* Module Resolution Options */
+    "esModuleInterop": true                   /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
+  },
+  "files": ["index.ts"]
+}