-
Notifications
You must be signed in to change notification settings - Fork 135
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
Gremlin Base Functionality #47
Changes from all commits
4824654
50056af
7f2db67
7c2af53
812e013
3e374b7
318d68e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -241,6 +241,45 @@ module.exports = class GraphDatabase | |
catch error | ||
throw adjustError error | ||
|
||
# wrapper around the Gremlin plugin to execute scripts bundled with | ||
# Neo4j. Pass in the Gremlin script as a string, and optionally script | ||
# parameters as a map -- recommended for both perf and security! | ||
# http://docs.neo4j.org/chunked/snapshot/gremlin-plugin.html | ||
# returns... | ||
execute: (script, params, _) -> | ||
try | ||
services = @getServices _ | ||
endpoint = services.gremlin or | ||
services.extensions?.GremlinPlugin?['execute_script'] | ||
|
||
if not endpoint | ||
throw new Error 'Gremlin plugin not installed' | ||
|
||
response = @_request.post | ||
uri: endpoint | ||
json: if params then {script, params} else {script} | ||
, _ | ||
|
||
# XXX workaround for neo4j silent failures for invalid queries: | ||
if response.statusCode is status.NO_CONTENT | ||
throw new Error """ | ||
Unknown Neo4j error for Gremlin script: | ||
|
||
#{script} | ||
|
||
""" | ||
|
||
if response.statusCode isnt status.OK | ||
# Database error | ||
throw response | ||
|
||
# Success: transform nodes/relationships | ||
results = util.transform response.body, this | ||
return results | ||
|
||
catch error | ||
throw adjustError error | ||
|
||
# XXX temporary backwards compatibility shim for query() argument order: | ||
do (actual = @::query) => | ||
@::query = (query, params, callback) -> | ||
|
@@ -259,6 +298,16 @@ module.exports = class GraphDatabase | |
|
||
actual.call @, query, params, callback | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Minor note: the overload helper for |
||
|
||
# | ||
do (actual = @::execute) => | ||
@::execute = (script, params, callback) -> | ||
if typeof params is 'function' | ||
callback = params | ||
params = null | ||
|
||
actual.call @, script, params, callback | ||
|
||
# executes a query against the given node index. lucene syntax reference: | ||
# http://lucene.apache.org/java/3_1_0/queryparsersyntax.html | ||
queryNodeIndex: (index, query, _) -> | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,7 +24,8 @@ | |
"clean": "rm lib/*.js", | ||
"postinstall": "npm run build", | ||
"profile": "_coffee test/profile", | ||
"test": "_coffee test" | ||
"test": "_coffee test", | ||
"gremlin": "_coffee test/gremlin" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I assume this was for testing during development. =) I'll go ahead remove this, but I'd really like to port our tests to Mocha, which among other things will let you |
||
}, | ||
"keywords": [ | ||
"neo4j", "graph", "database", "driver", "rest", "api", "client" | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
# will be used for testing gremlin script executions | ||
# as well as validating the return results are as expected | ||
|
||
assert = require('assert') | ||
neo4j = require('..') | ||
|
||
db = new neo4j.GraphDatabase 'http://localhost:7474' | ||
|
||
# convenience wrapper | ||
createNode = (name) -> | ||
node = db.createNode {name} | ||
node.name = name | ||
node.toString = -> name | ||
node | ||
|
||
#create some nodes | ||
users = for i in [0..6] | ||
createNode "gremlinTest#{i}" | ||
|
||
# save in parallel | ||
futures = (user.save() for user in users) | ||
future _ for future in futures | ||
|
||
# convenience aliases | ||
user0 = users[0] | ||
user1 = users[1] | ||
user2 = users[2] | ||
user3 = users[3] | ||
user4 = users[4] | ||
user5 = users[5] | ||
user6 = users[6] | ||
|
||
# test: can query a single user | ||
results = db.execute """ | ||
g.v(#{user0.id}) | ||
""", {}, _ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Given that you already test no params at the end, I'll change this to test params support since it doesn't seem like any other case tests that. |
||
|
||
assert.ok typeof results, 'object' | ||
assert.ok typeof results.data.name, 'string' # dislike this because it will throw for the wrong reasons possibly | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But in this case, you don't need to check the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh also, watch out -- if you're checking |
||
assert.equal results.data.name, user0.name | ||
|
||
# test: create relationships between users (same as cypher tests), then query by relationships | ||
createFollowRelationships = (i, _) -> | ||
user = users[i] | ||
i1 = (i + 1) % users.length | ||
i2 = (i + 2) % users.length | ||
i3 = (i + 3) % users.length | ||
f1 = user.createRelationshipTo users[i1], 'gremlin_follows', {} | ||
f2 = user.createRelationshipTo users[i2], 'gremlin_follows', {} | ||
f3 = user.createRelationshipTo users[i3], 'gremlin_follows', {} | ||
f1 _ | ||
f2 _ | ||
f3 _ | ||
|
||
# create follow relationships for each user in parallel | ||
futures = (createFollowRelationships(i) for user, i in users) | ||
future _ for future in futures | ||
|
||
relationships = db.execute """ | ||
g.v(#{user0.id}).in('gremlin_follows') | ||
""", {} , _ | ||
|
||
# above is working, but lib should support returning instances of Node and Relationship if possible | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It does now! ;) |
||
|
||
|
||
# handle multiple types of data return | ||
traversals = db.execute """ | ||
g.v(#{user0.id}).transform{ [it, it.out.toList(), it.in.count()] } | ||
""", {}, _ | ||
|
||
assert.ok traversals instanceof Array | ||
assert.equal traversals.length, 1 | ||
|
||
assert.ok traversals[0] instanceof Array | ||
assert.equal traversals[0].length, 3 | ||
|
||
assert.ok typeof traversals[0][0], 'object' | ||
assert.ok traversals[0][1] instanceof Array | ||
assert.ok typeof traversals[0][2], 'number' | ||
|
||
console.log 'Multiple data types appear to have worked with .execute() and util.transform()' | ||
|
||
# ensure you can call without params | ||
|
||
params_test = db.execute """ | ||
g.v(#{user0.id}) | ||
""", _ | ||
|
||
assert.ok typeof params_test, 'object' | ||
assert.equal params_test.data.name, user0.name | ||
|
||
# Should be relatively clear at this point the .execute() function is working with gremlin on some level | ||
console.log 'Passed initial Gremlin tests' |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
require './crud' | ||
require './cypher' | ||
require './gremlin' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no official
gremlin
endpoint baked in, so simplifying this to only check the plugin endpoint.