-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This client inherits from the default client but overrides the actions associated with node and relationship manipulation To run commands in batch you can now instantiate a transaction like: Neo4j::Http::Client.in_batch do |tx| [ tx.upsert_node(node), tx.upsert_node(node2), tx.upsert_relationship(relationship: relationship, from: from, to: to) ] end The array of statements will be passed into a batch client that will prepare the statements and the parameters and issue a single request to the Neo4j HTTP API. Note that the size of the batch is determined by the caller's array length.
- Loading branch information
Showing
16 changed files
with
562 additions
and
116 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
# frozen_string_literal: true | ||
|
||
module Neo4j | ||
module Http | ||
class BatchClient < Client | ||
class << self | ||
def default | ||
cypher_client = Http::BatchCypherClient.new(Neo4j::Http.config) | ||
node_client = Http::BatchNodeClient.new(cypher_client) | ||
relationship_client = Http::BatchRelationshipClient.new(cypher_client) | ||
@default ||= new(cypher_client, node_client, relationship_client) | ||
end | ||
end | ||
|
||
attr_accessor :cypher_client, :node_client, :relationship_client | ||
|
||
def initialize(cypher_client, node_client, relationship_client) | ||
@cypher_client = cypher_client | ||
@node_client = node_client | ||
@relationship_client = relationship_client | ||
end | ||
|
||
delegate(*CYPHER_CLIENT_METHODS, to: :cypher_client) | ||
delegate(*NODE_CLIENT_METHODS, to: :node_client) | ||
delegate(*RELATIONSHIP_CLIENT_METHODS, to: :relationship_client) | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
# frozen_string_literal: true | ||
|
||
require "forwardable" | ||
require "faraday" | ||
require "faraday/retry" | ||
require "faraday_middleware" | ||
|
||
module Neo4j | ||
module Http | ||
class BatchCypherClient < CypherClient | ||
# Each statement should be Hash with statement and parameters keys e.g. | ||
# { | ||
# statement: "MATCH (n:User { name: $name }) RETURN n", | ||
# parameters: { name: "Ben" } | ||
# } | ||
# https://neo4j.com/docs/http-api/current/actions/execute-multiple-statements/ | ||
def execute_cypher(statements = []) | ||
statements = [statements] if statements.is_a?(Hash) # equivalent to Array.wrap | ||
|
||
request_body = { | ||
statements: statements.map do |statement| | ||
{ | ||
statement: statement[:statement], | ||
parameters: statement[:parameters].as_json | ||
} | ||
end | ||
} | ||
|
||
@connection = @injected_connection || connection("WRITE") | ||
response = @connection.post(transaction_path, request_body) | ||
results = check_errors!(statements, response) | ||
|
||
results.map do |result| | ||
Neo4j::Http::Results.parse(result || {}) | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
# frozen_string_literal: true | ||
|
||
module Neo4j | ||
module Http | ||
class BatchNodeClient < NodeClient | ||
def upsert_node(node) | ||
raise "#{node.key_name} value cannot be blank - (node keys: #{node.to_h.keys})" if node.key_value.blank? | ||
|
||
cypher = <<-CYPHER | ||
MERGE (node:#{node.label} {#{node.key_name}: $key_value}) | ||
ON CREATE SET node += $attributes | ||
ON MATCH SET node += $attributes | ||
return node | ||
CYPHER | ||
|
||
{ | ||
statement: cypher, | ||
parameters: { key_value: node.key_value, attributes: node.attributes } | ||
} | ||
end | ||
|
||
def delete_node(node) | ||
cypher = <<-CYPHER | ||
MATCH (node:#{node.label} {#{node.key_name}: $key_value}) | ||
WITH node | ||
DETACH DELETE node | ||
RETURN node | ||
CYPHER | ||
|
||
{ | ||
statement: cypher, | ||
parameters: { key_value: node.key_value } | ||
} | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
# frozen_string_literal: true | ||
|
||
module Neo4j | ||
module Http | ||
class BatchRelationshipClient < RelationshipClient | ||
def upsert_relationship(relationship:, from:, to:, create_nodes: false) | ||
match_or_merge = create_nodes ? "MERGE" : "MATCH" | ||
from_selector = build_match_selector(:from, from) | ||
to_selector = build_match_selector(:to, to) | ||
relationship_selector = build_match_selector(:relationship, relationship) | ||
|
||
on_match = "" | ||
if relationship.attributes.present? | ||
on_match = <<-CYPHER | ||
ON CREATE SET relationship += $relationship_attributes | ||
ON MATCH SET relationship += $relationship_attributes | ||
CYPHER | ||
end | ||
|
||
cypher = +<<-CYPHER | ||
#{match_or_merge} (#{from_selector}) | ||
#{match_or_merge} (#{to_selector}) | ||
MERGE (from) - [#{relationship_selector}] - (to) | ||
#{on_match} | ||
RETURN from, to, relationship | ||
CYPHER | ||
|
||
{ | ||
statement: cypher, | ||
parameters: { | ||
from: from, | ||
to: to, | ||
relationship: relationship, | ||
relationship_attributes: relationship.attributes | ||
} | ||
} | ||
end | ||
|
||
def delete_relationship(relationship:, from:, to:) | ||
from_selector = build_match_selector(:from, from) | ||
to_selector = build_match_selector(:to, to) | ||
relationship_selector = build_match_selector(:relationship, relationship) | ||
|
||
cypher = <<-CYPHER | ||
MATCH (#{from_selector}) - [#{relationship_selector}] - (#{to_selector}) | ||
WITH from, to, relationship | ||
DELETE relationship | ||
RETURN from, to | ||
CYPHER | ||
|
||
{ | ||
statement: cypher, | ||
parameters: { | ||
from: from, | ||
to: to | ||
} | ||
} | ||
end | ||
|
||
def delete_relationship_on_primary_key(relationship:) | ||
# protection against mass deletion of relationships | ||
return if relationship.key_name.nil? | ||
|
||
relationship_selector = build_match_selector(:relationship, relationship) | ||
|
||
cypher = <<-CYPHER | ||
MATCH () - [#{relationship_selector}] - () | ||
WITH relationship | ||
DELETE relationship | ||
RETURN relationship | ||
CYPHER | ||
|
||
{ | ||
statement: cypher, | ||
parameters: { | ||
relationship: relationship | ||
} | ||
} | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.