neo4j-http 1.0.0 → 1.0.2.ben
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +30 -8
- data/lib/neo4j/http/configuration.rb +4 -0
- data/lib/neo4j/http/cypher_client.rb +24 -8
- data/lib/neo4j/http/errors.rb +1 -0
- data/lib/neo4j/http/node_client.rb +3 -2
- data/lib/neo4j/http/relationship_client.rb +7 -1
- data/lib/neo4j/http/results.rb +4 -1
- data/lib/neo4j/http/version.rb +1 -1
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5d96303c02ea752544432e28e5510fbe6c88adc8478068cab9924f523dec5c3d
|
4
|
+
data.tar.gz: c905e048958cfd2dd2a4b22c03b2a0cc7d015389689198124a02566242f47a20
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 82acf63f31d626badac509a0018aec7777165caf8507253f7ce88f145f8c235255da55d6277a340d971ec3740202e7ed4dbed4671ffec0d22e76f5b53fc909d9
|
7
|
+
data.tar.gz: d8abb8918f0ee93487928ea09d8983fa7ee8e9be62fa0f5f59f4ab8213282157ddaa2146b600992edbe3f9d12f3b281e2a3d254dd31e02d2ae1414d6fc95663d
|
data/README.md
CHANGED
@@ -27,21 +27,43 @@ Or install it yourself as:
|
|
27
27
|
|
28
28
|
The client is configured by default via a set of environment variables from [Neo4j::Http::Configuration](https://github.com/doximity/neo4j-http/blob/master/lib/neo4j/http/configuration.rb):
|
29
29
|
|
30
|
-
* `NEO4J_URL` - The base URL to connect to Neo4j at
|
31
|
-
* `NEO4J_USER` - The user name to use when authenticating to neo4j
|
32
|
-
* `NEO4J_PASSWORD` - The password of the user to be used for authentication
|
33
|
-
* `NEO4J_DATABASE` - The database name to be used when connecting. By default this will be nil
|
34
|
-
* `NEO4J_HTTP_USER_AGENT` - The user agent name provided in the request - defaults to `Ruby Neo4j Http Client`
|
35
|
-
* `NEO4J_REQUEST_TIMEOUT_IN_SECONDS` - The number of seconds for the http request to time out if provided
|
30
|
+
* `NEO4J_URL` - The base URL to connect to Neo4j at - defaults to `"http://localhost:7474"`
|
31
|
+
* `NEO4J_USER` - The user name to use when authenticating to neo4j - defaults to `""`
|
32
|
+
* `NEO4J_PASSWORD` - The password of the user to be used for authentication - defaults to `""`
|
33
|
+
* `NEO4J_DATABASE` - The database name to be used when connecting. By default this will be `nil`.
|
34
|
+
* `NEO4J_HTTP_USER_AGENT` - The user agent name provided in the request - defaults to `"Ruby Neo4j Http Client"`
|
35
|
+
* `NEO4J_REQUEST_TIMEOUT_IN_SECONDS` - The number of seconds for the http request to time out if provided - defaults to `nil`
|
36
|
+
* `ACCESS_MODE` - "WRITE", or "READ" for read only instances of Neo4j clients - defaults to `"WRITE"`
|
36
37
|
|
37
|
-
These configuration values can also be set during initalization
|
38
|
+
These configuration values can also be set during initalization, and take precedence over the environment variables:
|
38
39
|
|
39
40
|
```ruby
|
40
41
|
Neo4j::Http.configure do |config|
|
41
|
-
config.
|
42
|
+
config.uri = "http://localhost:7474"
|
43
|
+
config.user = ""
|
44
|
+
config.password = ""
|
45
|
+
config.database_name = nil
|
46
|
+
config.user_agent = "Ruby Neo4j Http Client"
|
47
|
+
config.request_timeout_in_seconds = nil
|
48
|
+
config.access_mode = "WRITE"
|
42
49
|
end
|
43
50
|
```
|
44
51
|
|
52
|
+
### Multiple databases
|
53
|
+
|
54
|
+
The HTTP API endpoints [follow the pattern](https://neo4j.com/docs/upgrade-migration-guide/current/migration/surface-changes/http-api/) `/db/<NEO4J_DATABASE>/tx`
|
55
|
+
|
56
|
+
To route to a different database, set a value for `NEO4J_DATABASE`. If no value is supplied, or this ENV is unset, the URI defaults to `/db/data/transaction/commit`
|
57
|
+
|
58
|
+
This can be used for testing by setting up a test environment only variable using a gem like [dotenv-rails](https://github.com/bkeepers/dotenv):
|
59
|
+
|
60
|
+
```
|
61
|
+
# .env.testing
|
62
|
+
NEO4J_DATABASE=test
|
63
|
+
```
|
64
|
+
|
65
|
+
All testing operations are now routed to the URI `/db/test/tx/commit`.
|
66
|
+
|
45
67
|
## Usage
|
46
68
|
|
47
69
|
The core interface can be directly accessed on `Neo4::Http::Client` -
|
@@ -9,6 +9,7 @@ module Neo4j
|
|
9
9
|
attr_accessor :uri
|
10
10
|
attr_accessor :user
|
11
11
|
attr_accessor :user_agent
|
12
|
+
attr_accessor :access_mode
|
12
13
|
|
13
14
|
def initialize(options = ENV)
|
14
15
|
@uri = options.fetch("NEO4J_URL", "http://localhost:7474")
|
@@ -17,8 +18,11 @@ module Neo4j
|
|
17
18
|
@database_name = options.fetch("NEO4J_DATABASE", nil)
|
18
19
|
@user_agent = options.fetch("NEO4J_HTTP_USER_AGENT", "Ruby Neo4j Http Client")
|
19
20
|
@request_timeout_in_seconds = options.fetch("NEO4J_REQUEST_TIMEOUT_IN_SECONDS", nil)
|
21
|
+
@access_mode = options.fetch("NEO4J_ACCESS_MODE", "WRITE")
|
20
22
|
end
|
21
23
|
|
24
|
+
# https://neo4j.com/developer/manage-multiple-databases/
|
25
|
+
# https://neo4j.com/docs/upgrade-migration-guide/current/migration/surface-changes/http-api/
|
22
26
|
def transaction_path
|
23
27
|
# v3.5 - /db/data/transaction/commit
|
24
28
|
# v4.x - /db/#{database_name}/tx/commit
|
@@ -12,26 +12,36 @@ module Neo4j
|
|
12
12
|
@default ||= new(Neo4j::Http.config)
|
13
13
|
end
|
14
14
|
|
15
|
-
def initialize(configuration)
|
15
|
+
def initialize(configuration, injected_connection = nil)
|
16
16
|
@configuration = configuration
|
17
|
+
@injected_connection = injected_connection
|
17
18
|
end
|
18
19
|
|
20
|
+
# Executes a cypher query, passing in the cypher statement, with parameters as an optional hash
|
21
|
+
# e.g. Neo4j::Http::Cypherclient.execute_cypher("MATCH (n { foo: $foo }) LIMIT 1 RETURN n", { foo: "bar" })
|
19
22
|
def execute_cypher(cypher, parameters = {})
|
23
|
+
# By default the access mode is set to "WRITE", but can be set to "READ"
|
24
|
+
# for improved routing performance on read only queries
|
25
|
+
access_mode = parameters.delete(:access_mode) || @configuration.access_mode
|
26
|
+
|
20
27
|
request_body = {
|
21
28
|
statements: [
|
22
|
-
{
|
23
|
-
|
29
|
+
{
|
30
|
+
statement: cypher,
|
31
|
+
parameters: parameters.as_json
|
32
|
+
}
|
24
33
|
]
|
25
34
|
}
|
26
35
|
|
27
|
-
|
36
|
+
@connection = @injected_connection || connection(access_mode)
|
37
|
+
response = @connection.post(transaction_path, request_body)
|
28
38
|
results = check_errors!(cypher, response, parameters)
|
29
39
|
|
30
40
|
Neo4j::Http::Results.parse(results&.first || {})
|
31
41
|
end
|
32
42
|
|
33
|
-
def connection
|
34
|
-
build_connection
|
43
|
+
def connection(access_mode)
|
44
|
+
build_connection(access_mode)
|
35
45
|
end
|
36
46
|
|
37
47
|
protected
|
@@ -39,6 +49,10 @@ module Neo4j
|
|
39
49
|
delegate :auth_token, :transaction_path, to: :@configuration
|
40
50
|
def check_errors!(cypher, response, parameters)
|
41
51
|
raise Neo4j::Http::Errors::InvalidConnectionUrl, response.status if response.status == 404
|
52
|
+
if response.body["errors"].any? { |error| error["message"][/Routing WRITE queries is not supported/] }
|
53
|
+
raise Neo4j::Http::Errors::ReadOnlyError
|
54
|
+
end
|
55
|
+
|
42
56
|
body = response.body || {}
|
43
57
|
errors = body.fetch("errors", [])
|
44
58
|
return body.fetch("results", {}) unless errors.present?
|
@@ -61,8 +75,10 @@ module Neo4j
|
|
61
75
|
Neo4j::Http::Errors::Neo4jCodedError
|
62
76
|
end
|
63
77
|
|
64
|
-
def build_connection
|
65
|
-
|
78
|
+
def build_connection(access_mode)
|
79
|
+
# https://neo4j.com/docs/http-api/current/actions/transaction-configuration/
|
80
|
+
headers = build_http_headers.merge({"access-mode" => access_mode})
|
81
|
+
Faraday.new(url: @configuration.uri, headers: headers, request: build_request_options) do |f|
|
66
82
|
f.request :json # encode req bodies as JSON
|
67
83
|
f.request :retry # retry transient failures
|
68
84
|
f.response :json # decode response bodies as JSON
|
data/lib/neo4j/http/errors.rb
CHANGED
@@ -41,15 +41,16 @@ module Neo4j
|
|
41
41
|
def find_node_by(label:, **attributes)
|
42
42
|
selectors = attributes.map { |key, value| "#{key}: $attributes.#{key}" }.join(", ")
|
43
43
|
cypher = "MATCH (node:#{label} { #{selectors} }) RETURN node LIMIT 1"
|
44
|
-
results = @cypher_client.execute_cypher(cypher, attributes: attributes)
|
44
|
+
results = @cypher_client.execute_cypher(cypher, attributes: attributes.merge(access_mode: "READ"))
|
45
45
|
return if results.empty?
|
46
|
+
|
46
47
|
results.first&.fetch("node")
|
47
48
|
end
|
48
49
|
|
49
50
|
def find_nodes_by(label:, attributes:, limit: 100)
|
50
51
|
selectors = build_selectors(attributes)
|
51
52
|
cypher = "MATCH (node:#{label}) where #{selectors} RETURN node LIMIT #{limit}"
|
52
|
-
results = @cypher_client.execute_cypher(cypher, attributes: attributes)
|
53
|
+
results = @cypher_client.execute_cypher(cypher, attributes: attributes.merge(access_mode: "READ"))
|
53
54
|
results.map { |result| result["node"] }
|
54
55
|
end
|
55
56
|
|
@@ -52,7 +52,13 @@ module Neo4j
|
|
52
52
|
RETURN from, to, relationship
|
53
53
|
CYPHER
|
54
54
|
|
55
|
-
results = @cypher_client.execute_cypher(
|
55
|
+
results = @cypher_client.execute_cypher(
|
56
|
+
cypher,
|
57
|
+
from: from,
|
58
|
+
to: to,
|
59
|
+
relationship: relationship,
|
60
|
+
access_mode: "READ"
|
61
|
+
)
|
56
62
|
results&.first
|
57
63
|
end
|
58
64
|
|
data/lib/neo4j/http/results.rb
CHANGED
@@ -4,7 +4,10 @@ module Neo4j
|
|
4
4
|
module Http
|
5
5
|
class Results
|
6
6
|
# Example result set:
|
7
|
-
# [{"columns"=>["n"],
|
7
|
+
# [{"columns"=>["n"],
|
8
|
+
# "data"=>
|
9
|
+
# [{"row"=>[{"name"=>"Foo", "uuid"=>"8c7dcfda-d848-4937-a91a-2e6debad2dd6"}],
|
10
|
+
# "meta"=>[{"id"=>242, "type"=>"node", "deleted"=>false}]}]}]
|
8
11
|
#
|
9
12
|
def self.parse(results)
|
10
13
|
columns = results["columns"]
|
data/lib/neo4j/http/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: neo4j-http
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.2.ben
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ryan Stawarz
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-07-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -73,7 +73,7 @@ dependencies:
|
|
73
73
|
- - ">="
|
74
74
|
- !ruby/object:Gem::Version
|
75
75
|
version: '0'
|
76
|
-
type: :
|
76
|
+
type: :runtime
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
@@ -121,9 +121,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
121
121
|
version: 2.3.0
|
122
122
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
123
123
|
requirements:
|
124
|
-
- - "
|
124
|
+
- - ">"
|
125
125
|
- !ruby/object:Gem::Version
|
126
|
-
version:
|
126
|
+
version: 1.3.1
|
127
127
|
requirements: []
|
128
128
|
rubygems_version: 3.3.11
|
129
129
|
signing_key:
|