Skip to content
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

TINKERPOP-1489 JavaScript GLV #695

Merged
merged 37 commits into from
Jan 25, 2018
Merged

TINKERPOP-1489 JavaScript GLV #695

merged 37 commits into from
Jan 25, 2018

Conversation

jorgebay
Copy link
Contributor

https://issues.apache.org/jira/browse/TINKERPOP-1489

Submitting the JavaScript for review to merge into tp32 after 3.2.6 code freeze and release.

Changes since #626:

@jorgebay
Copy link
Contributor Author

VOTE +1

mvn clean install -DskipIntegrationTests=false passes.

API summary:

  • All methods are generated using groovy template files.
  • Naming conventions for js are very similar to java, so no significant changes there from the java one (except in() and from()` which are reserved keywords).
  • toList() and next() are used, in the same way as the rest of the GLVs, except that it causes async execution (no blocking API is provided, as it won't be usable in Node.js): next() returns an async iterator and toList() a promise that gets fulfilled with an Array.

Usage samples:

const vertices = await g.V().toList();
for await (const vertex of g.V()) {
  console.log(vertex.label);
}

@spmallette
Copy link
Contributor

Hi @jorgebay - sorry - i just haven't had time to focus on this yet. I'll try to dig into it next week. Thanks for jamming on this and getting it ready for merging.

@spmallette
Copy link
Contributor

I rebased this today and added the nashorn scriptengine implementation for GremlinScriptEngine. I'd like to get us running tests with js the way we do with python since it's jsr223 compliant. I guess I'll keep working toward that goal this week - i'd propose to hold-off on merging this until that is done.

@jorgebay
Copy link
Contributor Author

jorgebay commented Sep 6, 2017

Great! It would be really nice to have a working GremlinJavaScriptScriptEngine!

@spmallette
Copy link
Contributor

I think the need to figure out the language agnostic way to test GLVs is becoming more important. I was pretty close to getting nashorn to execute gremlin-javascript natively, but there's weird pathing issue and npm integration issues that just aren't making it easy (possible). I tried to hack my way around the pathing problems and while i was making progress it was just getting ugly. I'll need to think about the language agnostic approach a bit before I worry about trying to go any further in this direction.

@jorgebay
Copy link
Contributor Author

jorgebay commented Sep 8, 2017

I've removed support for Nashorn as part of #626 (see first comment). JavaScript engines don't provide a standard way to deal with and import modules, so supporting with multiple runtimes is usually a pain (unlike other languages like Python that has the import system built-in).

If to support GremlinJavaScriptScriptEngine we need to support Nashorn on the GLV, we should try to split the GLV and the JS script engine in 2 separate tickets and try to tackle those separately.

Having a JavaScript GLV would enable users to write their traversals in js, making it easier for users from the js community to use Gremlin. On the other side, supporting js lambdas is a more marginal use case.

I think the need to figure out the language agnostic way to test GLVs is becoming more important

I think testing a GLV (bytecode generation, websocket connection, type mapping, ...) can't be implemented in a runtime agnostic way because the whole concepts are defined by the runtime. I think we can define a set of behaviours that the GLV must adhere. We can define a set of given-when-then statements (in doc), which we can make sure each GLV implements in actual tests.

On the other hand, I think testing a script engine can be generalized into a common suite (like ScriptEngineLambdaTest) plus specialized behaviour tests per language.

@spmallette
Copy link
Contributor

I mostly cared about nashorn to achieve testing as we did in python. I sense that most folks won't want to run on nashorn itself, so perhaps direct support of nashorn doesn't really matter especially if we come up with a better way to test. I'd rather not complicate gremlin-javascript with multiple runtimes - GLVs require enough effort to support as it is.

btw, i felt like this lib got me pretty far in making npm work on nashorn:

https://github.com/nodyn/jvm-npm

wasn't too bad, but got tripped up on the pathing as it didn't seem to want to run in a context that didn't have the js files in the same root directory as where you were running the scriptengine from. I couldn't quite figure out how to make that work. Again, it probably doesn't make sense to chase that angle anymore though. I'd rather just get testing figured out for GLVs in general.

We can define a set of given-when-then statements (in doc), which we can make sure each GLV implements in actual tests.

if we can write them in a doc, then it would seem we could write them as cucumber tests ( https://cucumber.io/ ) that could actually be executed somehow. that's been the general plan i've had anyway. if you have any other ideas, please let me know - i'll probably start playing around with this idea today or get started on it fresh next week.

@spmallette
Copy link
Contributor

Just a note for those following this ticket's progress. I'm in the process of doing TINKERPOP-1784 which will add a language agnostic test suite using gherkin defined feature files. That should allow us to test all GLVs in a nice way.

@jorgebay
Copy link
Contributor Author

I've implemented the support files for the gherkin test suite.
Thanks to the test suite, I've found and fixed some bugs that were part of the original implementation.

mvn clean install -pl :gremlin-javascript -DskipIntegrationTests=false run the mocha based tests and the cucumber-based tests. I've included it on TravisCI also.

328 scenarios (22 skipped, 306 passed)

It's ready to be reviewed!

I would like the JavaScript GLV to be part of the next release cycle (3.2.8 / 3.3.2). This GLV have been sidelined several times since the original pull request #450 (Oct 2016!)...

@spmallette
Copy link
Contributor

this is excellent. i agree that we should look to merge this for 3.2.8/3.3.2. as we hopefully release 3.2.7/3.3.1 we should see gremlin-js come into an official state in the first few months of 2018.

@jorgebay
Copy link
Contributor Author

jorgebay commented Jan 4, 2018

What a great time of the year to review this pr! 😄

@@ -0,0 +1,39 @@
{
"name": "gremlin-javascript",
"version": "3.2.7-alpha1",
Copy link
Contributor

Choose a reason for hiding this comment

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

should be 3.2.8-alpha1 - at this point. though, we've been using "release candidate" suffix for other GLVs as in "3.2.8-rc1" - perhaps we should continue in that vein?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've used alpha to avoid messing up in case it was accidentally pushed while testing the pull request.
The version suffix is added in the determineVersion() method of the generation.groovy file.

<parent>
<groupId>org.apache.tinkerpop</groupId>
<artifactId>tinkerpop</artifactId>
<version>3.2.7-SNAPSHOT</version>
Copy link
Contributor

Choose a reason for hiding this comment

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

should be 3.2.8-SNAPSHOT at this point

</goals>
<configuration>
<scripts>
<script><![CDATA[
Copy link
Contributor

Choose a reason for hiding this comment

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

can you please move embedded scripts to files as we did with the other GLVs?

https://github.com/apache/tinkerpop/blob/tp32/gremlin-python/pom.xml#L483

Makes the pom a bit easier to read.

<activeByDefault>false</activeByDefault>
</activation>
<build>
<plugins>
Copy link
Contributor

Choose a reason for hiding this comment

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

is there any special configuration required in the release manager's local environment for this to work? Either way, It would be a massive help if you could provide a "Javascript Environment" section in the dev docs here:

http://tinkerpop.apache.org/docs/current/dev/developer/#system-configuration

@jorgebay
Copy link
Contributor Author

jorgebay commented Jan 8, 2018

I've addressed the comments made by @spmallette:

  • I've included sections on the development-environment.asciidoc file for js environment and info for the release managers.
  • Moved generation to a groovy file.

@spmallette
Copy link
Contributor

gremlin-javascript seems to build ok for me locally, but not on docker. claims it needs a maven upgrade to 3.1.0 for the npm plugin to work. do you see the same thing @jorgebay ?

@jorgebay
Copy link
Contributor Author

I'm getting the same failure, but I don't understand where the requirement to a newer maven is coming from within frontend-maven-plugin.

@jbmusso
Copy link
Contributor

jbmusso commented Jan 11, 2018

Quick update - I plan to check this PR this weekend.

@jorgebay
Copy link
Contributor Author

I've just noticed that there isn't a g:T deserializer, I'll add it in the next days.

@jorgebay
Copy link
Contributor Author

Thanks @dkuppitz for looking into the maven issue!

I'll rebase it and add a g:T deserializer.

@jbmusso
Copy link
Contributor

jbmusso commented Jan 17, 2018

Finally found some time. Wew.

Well, this PR is very well crafted - well done! My comments are only minor:

  • About utils.toPromise - if I understand you well, you want a dual callback/promise API for most async functions?
  • In graph-traversal.js, most methods of GraphTraversalSource and GraphTraversal and function attached to statics could maybe be dynamically created from an array of method names and dynamically added to these classes/object. I don’t know what would be the performance implication of this, but I don’t think there should be any unless V8 really can’t figure out what’s going on when parsing that file. Hopefully it's smart and figures out that the class is not changing. That’d lower the file size and help maintainability a lot.
  • ES6, most likely friendlier for more recent versions of V8 and supported by Node.js v4+ (see Node green):
    • arguments is deprecated and is replaced by ...args for variadic functions
    • most function keywords could be replaced by arrow functions (lexical scoping and/or concise syntax). I tend to keep function for top-level functions, and use fat arrows everywhere even when this binding isn't needed (ie. callback w/o this)
    • array.splice(0) could be replaced by const copy = [...original]
    • func.apply(null, arguments) could be replaced by func(...args) when first argument this value is indeed meant to be null
  • package.json: ./node_modules/.bin is added to the $PATH by npm or yarn, so we could just use "test": "mocha test/unit test/integration -t 5000". Yay npm!

I can fork and push 4 distinct commits for this if you want, so this can be cherry-picked.

A more major update would be to author in ES6/7/8 and add a transpilation step, so all runtime could use code that they can optimize best. Using babel with babel-preset-env combined with postinstall-build is an option. This will ensure that latest versions of Node.js use mostly non-transpiled code, while older versions automatically transpile what is strictly needed. That would make things more performant for latest versions of Node.js, since V8 optimizes a lot for new syntax, while still making the GLV compatible for older versions of Node.js. The nice thing is that the build step is automatically handled at install time by npm, so no extra maven coding should be required. I think such approach could be added in future releases and is out of scope today.

Also, I'm ok to transfer/donate the "gremlin" package name to Apache TinkerPop so this can be published under this name.

@jorgebay
Copy link
Contributor Author

About utils.toPromise - if I understand you well, you want a dual callback/promise API for most async functions?

Just promise-based API, no callback-based API. utils.toPromise() its a way to support different "promise factories", the way promises are created in the driver. It's an idea to support any Promise API (like bluebird), but it's not really needed... maybe adds unnecessary complexity to the code? Do you think it makes more sense to remove it?

In graph-traversal.js, most methods of GraphTraversalSource and GraphTraversal and function attached to statics [...]

I like the idea of having the methods defined in code to support code completion on IDEs like VS Code and WebStorm, given that it's hard to remember all the traversal methods by heart. Maybe we can reduce the size and complexity of the generated code by using something like:

Instead of (current):

const statics = {};
statics.V = function (args) {
  const g = new GraphTraversal(null, null, new Bytecode());
  return g.V.apply(g, arguments);
};
statics.addE = function (args) {
  const g = new GraphTraversal(null, null, new Bytecode());
  return g.addE.apply(g, arguments);
};

Use:

const statics = {
  V: (...args) => callOnEmptyTraversal('V', args),
  addE: (...args) => callOnEmptyTraversal('addE', args),
  // ...
};

wdyt?

I'll start working on the other suggestions (ES6).

@spmallette
Copy link
Contributor

I'm posting this to all open PRs of current relevance - this PR needs to be rebased against the branch it is targeted against given a broken python dependency that was published to pypi a day or so ago. I've pushed a fix on tp32 and master at this point and David Brown is working on getting an issue raised with the project that initiated the problem.

@jorgebay
Copy link
Contributor Author

Rebased.

@jbmusso
Copy link
Contributor

jbmusso commented Jan 19, 2018

According to petkaantonov/bluebird#1026, users should be able to just patch the global Promise object in their application with:

global.Promise = require("bluebird");

I am unsure about other Promise libraries but I believe this approach should work as long as they're Promise/A+ standard compliant. Maybe we could also give it more thoughts and see for other ways to handle this in a future release, but I think it's worth making the code simpler at this point. I also feel it can/should be done at the application level.

For Traversal methods, I didn't think about IDEs and you're absolutely right about code completion. I think your proposed approach with callOnEmptyTraversal works best. This makes me think that I'm pretty sure people will want typed traversals with TypeScript or FlowType soon (thinking about https://github.com/DefinitelyTyped/DefinitelyTyped here for example).

- Use rest parameters
- Use a more compact declaration for methods on statics
- Bump engine to Node.js >= 6
@jorgebay
Copy link
Contributor Author

I've pushed 2 commits to address the issues highlighted in the review.

I got rid of the promise factory and I'm using rest parameters and spread syntax (instead of parseArgs()) for GraphTraversal and GraphTraversalSource methods.

In order to ease up maintenance of the GLV, I've bumped the min version supported of the runtime to Node.js 6, as Node.js 4 is reaching EOL in April and it didn't support several ES2015 features (rest parameters being one of them).

@jorgebay
Copy link
Contributor Author

I've updated the travis commands to include a mvn clean install -DskipTests before running GLV tests, GLV jobs take now 7 and 5 minutes respectively which is still not much.

@jbmusso
Copy link
Contributor

jbmusso commented Jan 23, 2018

All good to me!

VOTE +1

@spmallette
Copy link
Contributor

All tests pass with docker/build.sh -t -n -i

VOTE +1

@asfgit asfgit merged commit 328c936 into tp32 Jan 25, 2018
@asfgit asfgit deleted the TINKERPOP-1489 branch January 25, 2018 13:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants