You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by sp...@apache.org on 2018/10/08 19:02:09 UTC

[tinkerpop] 05/12: Client and Translator classes for better handling of scripts

This is an automated email from the ASF dual-hosted git repository.

spmallette pushed a commit to branch TINKERPOP-1959-tp33
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git

commit a72c6fb8e939b31b2a779aa743daad762d0e5fe6
Author: Matthew Allen <ma...@runbox.com>
AuthorDate: Sat Sep 1 07:53:13 2018 +0100

    Client and Translator classes for better handling of scripts
---
 .../glv/GraphTraversalSource.template              |  11 ---
 gremlin-javascript/glv/TraversalSource.template    |  11 ---
 .../main/javascript/gremlin-javascript/index.js    |   6 +-
 .../gremlin-javascript/lib/driver/client.js        |  65 +++++++++++++
 .../lib/driver/driver-remote-connection.js         |  17 +---
 .../lib/driver/remote-connection.js                |  21 +----
 .../gremlin-javascript/lib/process/bytecode.js     |  67 -------------
 .../lib/process/graph-traversal.js                 |  11 ---
 .../gremlin-javascript/lib/process/translator.js   |  91 ++++++++++++++++++
 .../gremlin-javascript/lib/process/traversal.js    |  11 ---
 .../javascript/gremlin-javascript/test/helper.js   |   5 +
 .../test/integration/client-tests.js               |  65 +++++++++++++
 .../test/integration/traversal-test.js             |  18 ----
 .../gremlin-javascript/test/unit/eval-test.js      | 104 ---------------------
 .../test/unit/translator-test.js                   |  61 ++++++++++++
 15 files changed, 297 insertions(+), 267 deletions(-)

diff --git a/gremlin-javascript/glv/GraphTraversalSource.template b/gremlin-javascript/glv/GraphTraversalSource.template
index 1d3dd5d..58be16c 100644
--- a/gremlin-javascript/glv/GraphTraversalSource.template
+++ b/gremlin-javascript/glv/GraphTraversalSource.template
@@ -84,17 +84,6 @@ class GraphTraversalSource {
     return new GraphTraversal(this.graph, new TraversalStrategies(this.traversalStrategies), b);
   }
   <% } %>
-
-
-  /**
-   * Send a Gremlin-Groovy script to the server. If a script is not passed in 
-   * then the bytecode instructions will be converted to a script and sent.
-   * @param {string} script The script to send to server
-   * @param {array} bindings Map of bindings
-   */
-  eval(script, bindings) {
-    return (new GraphTraversal(this.graph, new TraversalStrategies(this.traversalStrategies), new Bytecode(this.bytecode))).eval(script, bindings);
-  }
 }
 
 /**
diff --git a/gremlin-javascript/glv/TraversalSource.template b/gremlin-javascript/glv/TraversalSource.template
index 9824273..f3c7795 100644
--- a/gremlin-javascript/glv/TraversalSource.template
+++ b/gremlin-javascript/glv/TraversalSource.template
@@ -79,17 +79,6 @@ class Traversal {
   }
 
   /**
-   * Send a Gremlin-Groovy script to the server. If a script is not passed in 
-   * then the bytecode instructions will be converted to a script and sent.
-   * @param {string} script The script to send to server
-   * @param {array} bindings Map of bindings
-   */
-  eval(script, bindings) {
-    this.bytecode.addStep('eval', [ script, bindings ]);
-    return this._applyStrategies().then(() => this._getNext());
-  }
-
-  /**
    * Synchronous iterator of traversers including
    * @private
    */
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/index.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/index.js
index c2e810d..ffc7f0c 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/index.js
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/index.js
@@ -29,8 +29,10 @@ const graph = require('./lib/structure/graph');
 const gs = require('./lib/structure/io/graph-serializer');
 const rc = require('./lib/driver/remote-connection');
 const Bytecode = require('./lib/process/bytecode');
+const Translator = require('./lib/process/translator');
 const utils = require('./lib/utils');
 const DriverRemoteConnection = require('./lib/driver/driver-remote-connection');
+const Client = require('./lib/driver/client');
 const Authenticator = require('./lib/driver/auth/authenticator');
 const PlainTextSaslAuthenticator = require('./lib/driver/auth/plain-text-sasl-authenticator');
 
@@ -40,6 +42,7 @@ module.exports = {
     RemoteStrategy: rc.RemoteStrategy,
     RemoteTraversal: rc.RemoteTraversal,
     DriverRemoteConnection: DriverRemoteConnection,
+    Client: Client,
     auth: {
       Authenticator: Authenticator,
       PlainTextSaslAuthenticator: PlainTextSaslAuthenticator
@@ -66,7 +69,8 @@ module.exports = {
     t: t.t,
     GraphTraversal: gt.GraphTraversal,
     GraphTraversalSource: gt.GraphTraversalSource,
-    statics: gt.statics
+    statics: gt.statics,
+    Translator: Translator
   },
   structure: {
     io: {
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/client.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/client.js
new file mode 100644
index 0000000..89d9347
--- /dev/null
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/client.js
@@ -0,0 +1,65 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+'use strict';
+
+const DriverRemoteConnection = require('./driver-remote-connection');
+const Bytecode = require('../process/bytecode');
+
+class Client extends DriverRemoteConnection {
+  /**
+   * Creates a new instance of DriverRemoteConnection.
+   * @param {String} url The resource uri.
+   * @param {Object} [options] The connection options.
+   * @param {Array} [options.ca] Trusted certificates.
+   * @param {String|Array|Buffer} [options.cert] The certificate key.
+   * @param {String} [options.mimeType] The mime type to use.
+   * @param {String|Buffer} [options.pfx] The private key, certificate, and CA certs.
+   * @param {GraphSONReader} [options.reader] The reader to use.
+   * @param {Boolean} [options.rejectUnauthorized] Determines whether to verify or not the server certificate.
+   * @param {String} [options.traversalSource] The traversal source. Defaults to: 'g'.
+   * @param {GraphSONWriter} [options.writer] The writer to use.
+   * @param {Authenticator} [options.authenticator] The authentication handler to use.
+   * @constructor
+   */
+  constructor(url, options) {
+    super(url, options);
+  }
+
+  /** override */
+  submit(message, bindings) {
+    if (typeof message === 'string' || message instanceof String) {
+      const args = {
+        'gremlin': message,
+        'bindings': bindings,
+        'language': 'gremlin-groovy',
+        'accept': 'application/json',
+        'aliases': { 'g': this.traversalSource }
+      };
+
+      return super.submit(null, 'eval', args, null, '');
+    }
+
+    if (message instanceof Bytecode) {
+      return super.submit(message);
+    }
+  }
+  
+}
+
+module.exports = Client;
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/driver-remote-connection.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/driver-remote-connection.js
index fb66aae..81d5124 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/driver-remote-connection.js
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/driver-remote-connection.js
@@ -132,22 +132,13 @@ class DriverRemoteConnection extends RemoteConnection {
       'op': op || 'bytecode',
       // if using op eval need to ensure processor stays unset if caller didn't set it.
       'processor': (!processor && op !== 'eval') ? 'traversal' : processor,
-      'args': this._getArgs(args || {
-          'gremlin': this._writer.adaptObject(bytecode)
-        },
-        op
-      )
+      'args': args || {
+          'gremlin': this._writer.adaptObject(bytecode),
+          'aliases': { 'g': this.traversalSource }
+        }
     });
   }
 
-  _getArgs(args, op) {
-    if (args.aliases === undefined) {
-      args.aliases = { 'g': this.traversalSource };
-    }
-
-    return args;
-  }
-
   _handleMessage(data) {
     const response = this._reader.read(JSON.parse(data.toString()));
     if (response.requestId === null || response.requestId === undefined) {
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/remote-connection.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/remote-connection.js
index 96db161..c675c42 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/remote-connection.js
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/remote-connection.js
@@ -68,26 +68,7 @@ class RemoteStrategy extends TraversalStrategy {
       return Promise.resolve();
     }
 
-    let instructions = traversal.getBytecode();
-    let op = 'bytecode';
-    let processor = 'traversal';
-    let args = null;
-
-    // check if the last instruction is an eval statement
-    if (instructions.stepInstructions.length && instructions.stepInstructions[instructions.stepInstructions.length-1][0] === 'eval') {
-      const script = instructions.toScript();
-      op = 'eval';
-      processor = '';
-      args = {
-        'gremlin': script.script,
-        'bindings': script.bindings,
-        'language': 'gremlin-groovy',
-        'accept': 'application/json',
-      };
-      instructions = null;
-    }
-
-    return this.connection.submit(instructions, op, args, null, processor).then(function (remoteTraversal) {
+    return this.connection.submit(traversal.getBytecode()).then(function (remoteTraversal) {
       traversal.sideEffects = remoteTraversal.sideEffects;
       traversal.traversers = remoteTraversal.traversers;
     });
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/bytecode.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/bytecode.js
index fe96568..e7fdd40 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/bytecode.js
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/bytecode.js
@@ -91,73 +91,6 @@ class Bytecode {
       (this.stepInstructions.length   > 0 ? JSON.stringify(this.stepInstructions) : '')
     );
   }
-
-  /**
-   * Returns a script representations of the step instructions that can be used by standard eval operation.
-   * @returns {Object} An object containing a script string and bindings map.
-   */
-  toScript() {
-    let bindings = {};
-    let script = 'g';
-    let length = this.stepInstructions.length;
-
-    // if eval was passed a script then simply execute the given script.
-    if (this.stepInstructions[length - 1][0] === 'eval'
-      && this.stepInstructions[length - 1][1] !== undefined
-      && this.stepInstructions[length - 1][1] !== null
-    ) {
-      return {
-        script: this.stepInstructions[length - 1][1],
-        bindings: this.stepInstructions[length - 1][2]
-      }
-    }
-
-    if (this.stepInstructions[length - 1][0] === 'eval') {
-      this.stepInstructions.pop();
-      length = this.stepInstructions.length;
-    }
-
-    // build the script from the glv instructions.
-    let paramIdx = 1;
-    for (let i = 0; i < length; i++) {
-      const params = this.stepInstructions[i].slice(1);
-      script = script + '.' + this.stepInstructions[i][0] + '(';
-
-      if (params.length) {
-        for (let k = 0; k < params.length; k++) {
-          if (k > 0) {
-            script = script + ', ';
-          }
-
-          if (Object(params[k]) === params[k]) {
-            script = script + params[k].toString();
-          } else {
-            const prop = `p${paramIdx++}`;
-            script = script + prop;
-            
-            if (typeof params[k] === 'number') {
-              if (Number.isInteger(params[k])) {
-                bindings[prop] = Number.parseInt(params[k]);
-              } else {
-                bindings[prop] = Number.parseFloat(params[k]);
-              }
-            } else if (params[k] === undefined) {
-              bindings[prop] = null;
-            } else {
-              bindings[prop] = params[k];
-            }
-          }
-        }
-      }
-
-      script = script + ')';
-    }
-    
-    return {
-      script,
-      bindings
-    };
-  }
 }
 
 module.exports = Bytecode;
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/graph-traversal.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/graph-traversal.js
index c73405e..edeb2cb 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/graph-traversal.js
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/graph-traversal.js
@@ -172,17 +172,6 @@ class GraphTraversalSource {
     return new GraphTraversal(this.graph, new TraversalStrategies(this.traversalStrategies), b);
   }
   
-
-
-  /**
-   * Send a Gremlin-Groovy script to the server. If a script is not passed in 
-   * then the bytecode instructions will be converted to a script and sent.
-   * @param {string} script The script to send to server
-   * @param {array} bindings Map of bindings
-   */
-  eval(script, bindings) {
-    return (new GraphTraversal(this.graph, new TraversalStrategies(this.traversalStrategies), new Bytecode(this.bytecode))).eval(script, bindings);
-  }
 }
 
 /**
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/translator.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/translator.js
new file mode 100644
index 0000000..dfd4b69
--- /dev/null
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/translator.js
@@ -0,0 +1,91 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+'use strict';
+
+/**
+ * Class to translate glv bytecode steps into executable Gremlin-Groovy script
+ */
+class Translator {
+  constructor(traversalSource) {
+    this._traversalSource = traversalSource;
+  }
+
+  getTraversalSource() {
+    return this._traversalSource;
+  }
+
+  getTargetLanguage() {
+    return "gremlin-groovy";
+  }
+
+  of(traversalSource) {
+    this._traversalSource = traversalSource;
+  }
+
+  /**
+   * Returns a script representation of the given bytecode instructions.
+   * @param {Object} bytecode The bytecode object containing step instructions.
+   * @returns {string} Gremlin-Groovy script
+   */
+  translate(bytecode) {
+    let script = this._traversalSource;
+    let instructions = bytecode.stepInstructions;
+
+    // build the script from the glv instructions.
+    for (let i = 0; i < instructions.length; i++) {
+      const params = instructions[i].slice(1);
+      script += '.' + instructions[i][0] + '(';
+
+      if (params.length) {
+        for (let k = 0; k < params.length; k++) {
+          if (k > 0) {
+            script += ', ';
+          }
+
+          if (Object(params[k]) === params[k]) {
+            if (params[k].toString() === '[object Object]') {
+              Object.keys(params[k]).forEach(function(key, index) {
+                if (index > 0) script += ', ';
+                script += '(\'' + key + '\', ';
+                if (params[k][key] instanceof String || typeof params[k][key] === 'string') {
+                  script += '\'' + params[k][key] + '\'';
+                } else {
+                  script += params[k][key];
+                }
+                script += ')';
+              });
+            } else {
+              script += params[k].toString();
+            }
+          } else if (params[k] === undefined) {
+            script += '';
+          } else {
+            script += '\'' + params[k] + '\'';
+          }
+        }
+      }
+
+      script += ')';
+    }
+    
+    return script;
+  }
+}
+
+module.exports = Translator;
\ No newline at end of file
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/traversal.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/traversal.js
index 9b88232..5ec2db5 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/traversal.js
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/traversal.js
@@ -79,17 +79,6 @@ class Traversal {
   }
 
   /**
-   * Send a Gremlin-Groovy script to the server. If a script is not passed in 
-   * then the bytecode instructions will be converted to a script and sent.
-   * @param {string} script The script to send to server
-   * @param {array} bindings Map of bindings
-   */
-  eval(script, bindings) {
-    this.bytecode.addStep('eval', [ script, bindings ]);
-    return this._applyStrategies().then(() => this._getNext());
-  }
-
-  /**
    * Synchronous iterator of traversers including
    * @private
    */
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/helper.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/helper.js
index 899a8ad..b2a61d2 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/helper.js
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/helper.js
@@ -24,6 +24,7 @@
 const os = require('os');
 
 const DriverRemoteConnection = require('../lib/driver/driver-remote-connection');
+const Client = require('../lib/driver/client');
 const PlainTextSaslAuthenticator = require('../lib/driver/auth/plain-text-sasl-authenticator');
 
 exports.getConnection = function getConnection(traversalSource) {
@@ -37,4 +38,8 @@ exports.getSecureConnectionWithPlainTextSaslAuthenticator = function getConnecti
     authenticator: authenticator, 
     rejectUnauthorized: false 
   });
+};
+
+exports.getClient = function getClient(traversalSource) {
+  return new Client('ws://localhost:45940/gremlin', { traversalSource: traversalSource });
 };
\ No newline at end of file
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/integration/client-tests.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/integration/client-tests.js
new file mode 100644
index 0000000..83f4baa
--- /dev/null
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/integration/client-tests.js
@@ -0,0 +1,65 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+'use strict';
+
+const assert = require('assert');
+const Bytecode = require('../../lib/process/bytecode');
+const graphModule = require('../../lib/structure/graph');
+const helper = require('../helper');
+
+let connection;
+
+describe('Client', function () {
+  before(function () {
+    connection = helper.getClient('gmodern');
+    return connection.open();
+  });
+  after(function () {
+    return connection.close();
+  });
+  describe('#submit()', function () {
+    it('should send bytecode', function () {
+      return connection.submit(new Bytecode().addStep('V', []).addStep('tail', []))
+        .then(function (response) {
+          assert.ok(response);
+          assert.ok(response.traversers);
+          assert.strictEqual(response.traversers.length, 1);
+          assert.ok(response.traversers[0].object instanceof graphModule.Vertex);
+        });
+    });
+    it('should send and parse a script', function () {
+      return connection.submit('g.V().tail()')
+        .then(function (response) {
+          assert.ok(response);
+          assert.ok(response.traversers);
+          assert.strictEqual(response.traversers.length, 1);
+          assert.ok(response.traversers[0] instanceof graphModule.Vertex);
+        });
+    });
+    it('should send and parse a script with bindings', function () {
+      return connection.submit('x + x', {x: 3})
+        .then(function (response) {
+          assert.ok(response);
+          assert.ok(response.traversers);
+          assert.strictEqual(response.traversers[0], 6);
+        });
+    });
+  });
+});
\ No newline at end of file
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/integration/traversal-test.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/integration/traversal-test.js
index cfdc4f0..920d998 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/integration/traversal-test.js
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/integration/traversal-test.js
@@ -66,22 +66,4 @@ describe('Traversal', function () {
         });
     });
   });
-  describe('#eval()', function() {
-    it('should submit the traversal as a script and return a result', function() {
-      var g = new Graph().traversal().withRemote(connection);
-      return g.V().count().eval().then(function (item) {
-        assert.ok(item);
-        assert.strictEqual(item.done, true);
-        assert.strictEqual(typeof item.value, 'number');
-      });
-    });
-
-    it('should submit a script and bindings and return a result', function() {
-      var g = new Graph().traversal().withRemote(connection);
-      return g.eval('g.V(v1)', { v1: 1 }).then(function (item) {
-        assert.ok(item);
-        assert.ok(item.value instanceof Vertex);
-      });
-    });
-  });
 });
\ No newline at end of file
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/eval-test.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/eval-test.js
deleted file mode 100644
index c3c87fb..0000000
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/eval-test.js
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-
-'use strict';
-
-const assert = require('assert');
-const expect = require('chai').expect;
-const graph = require('../../lib/structure/graph');
-const t = require('../../lib/process/traversal');
-const TraversalStrategies = require('../../lib/process/traversal-strategy').TraversalStrategies;
-const Bytecode = require('../../lib/process/bytecode');
-
-describe('Traversal', function () {
-
-  describe('#getBytecode#toScript()', function () {
-    it('should add steps and produce valid script representation', function () {
-      const g = new graph.Graph().traversal();
-      const script = g.V().out('created').getBytecode().toScript();
-      assert.ok(script);
-      assert.strictEqual(script.script, 'g.V().out(p1)');
-    });
-
-    it('should add steps and produce valid script representation with parameter bindings', function () {
-      const g = new graph.Graph().traversal();
-      const script = g.addV('name', 'Lilac').getBytecode().toScript();
-      assert.ok(script);
-      assert.strictEqual(script.script, 'g.addV(p1, p2)');
-      assert.ok(script.bindings);
-      assert.deepStrictEqual(script.bindings, { p1: 'name', p2: 'Lilac' });
-    });
-
-    it('should add steps containing enum and produce valid script representation', function () {
-      const g = new graph.Graph().traversal();
-      const script = g.V().order().by('age', t.order.decr).getBytecode().toScript();
-      assert.ok(script);
-      assert.strictEqual(script.script, 'g.V().order().by(p1, decr)');
-    });
-
-    it('should add steps containing a predicate and produce valid script representation', function () {
-      const g = new graph.Graph().traversal();
-      const script = g.V().hasLabel('person').has('age', t.P.gt(30)).getBytecode().toScript();
-      assert.ok(script);
-      assert.strictEqual(script.script, 'g.V().hasLabel(p1).has(p2, gt(30))');
-    });
-
-    it('should take a script and return that script along with passed in bindings', function () {
-      const g = new graph.Graph().traversal();
-      const bytecode = g.addV('name', 'Lilac').getBytecode();
-      const script = bytecode.addStep('eval', [ 
-        'g.addV(\'name\', name).property(\'created\', date)',
-        { name: 'Lilac', created: '2018-01-01T00:00:00.000z' }
-      ]).toScript();
-      assert.ok(script);
-      assert.strictEqual(script.script, 'g.addV(\'name\', name).property(\'created\', date)');
-      assert.deepStrictEqual(script.bindings, { name: 'Lilac', created: '2018-01-01T00:00:00.000z' });
-    });
-  });
-
-  describe('#eval()', function () {
-    it('should apply the strategies and return a Promise with the iterator item', function () {
-      const strategyMock = {
-        apply: function (traversal) {
-          traversal.traversers = [ new t.Traverser(1, 1), new t.Traverser(2, 1) ];
-          return Promise.resolve();
-        }
-      };
-      const strategies = new TraversalStrategies();
-      strategies.addStrategy(strategyMock);
-      const traversal = new t.Traversal(null, strategies, new Bytecode());
-      return traversal.eval(null, null, null)
-        .then(function (item) {
-          assert.strictEqual(item.value, 1);
-          assert.strictEqual(item.done, false);
-          return traversal.eval(null, null, null);
-        })
-        .then(function (item) {
-          assert.strictEqual(item.value, 2);
-          assert.strictEqual(item.done, false);
-          return traversal.eval(null, null, null);
-        })
-        .then(function (item) {
-          assert.strictEqual(item.value, null);
-          assert.strictEqual(item.done, true);
-          return traversal.eval(null, null, null);
-        });
-    });
-  });
-});
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/translator-test.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/translator-test.js
new file mode 100644
index 0000000..b5310bf
--- /dev/null
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/translator-test.js
@@ -0,0 +1,61 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+'use strict';
+
+const assert = require('assert');
+const expect = require('chai').expect;
+const graph = require('../../lib/structure/graph');
+const t = require('../../lib/process/traversal');
+const TraversalStrategies = require('../../lib/process/traversal-strategy').TraversalStrategies;
+const Bytecode = require('../../lib/process/bytecode');
+const Translator = require('../../lib/process/translator');
+
+describe('Translator', function () {
+
+  describe('#translate()', function () {
+    it('should produce valid script representation from bytecode glv steps', function () {
+      const g = new graph.Graph().traversal();
+      const script = new Translator('g').translate(g.V().out('created').getBytecode());
+      assert.ok(script);
+      assert.strictEqual(script, 'g.V().out(\'created\')');
+    });
+
+    it('should produce valid script representation from bytecode glv steps containing parameter bindings', function () {
+      const g = new graph.Graph().traversal();
+      const script = new Translator('g').translate(g.addV({'name': 'Lilac'}).getBytecode());
+      assert.ok(script);
+      assert.strictEqual(script, 'g.addV((\'name\', \'Lilac\'))');
+    });
+
+    it('should produce valid script representation from bytecode glv steps containing enum', function () {
+      const g = new graph.Graph().traversal();
+      const script = new Translator('g').translate(g.V().order().by('age', t.order.decr).getBytecode());
+      assert.ok(script);
+      assert.strictEqual(script, 'g.V().order().by(\'age\', decr)');
+    });
+
+    it('should produce valid script representation from bytecode glv steps containing a predicate', function () {
+      const g = new graph.Graph().traversal();
+      const script = new Translator('g').translate(g.V().hasLabel('person').has('age', t.P.gt(30)).getBytecode());
+      assert.ok(script);
+      assert.strictEqual(script, 'g.V().hasLabel(\'person\').has(\'age\', gt(30))');
+    });
+  });
+});