module neo4j
import curl_json
+import error
# Handles Neo4j server start and stop command
#
self.cypher_url = root["cypher"].to_s
end
- fun service_root: Jsonable do return get("{base_url}/db/data")
+ fun service_root: Jsonable do return get(base_url / "db/data")
# Is the connection with the Neo4j server ok?
fun is_ok: Bool do return service_root isa JsonObject
# assert nodes.has(andres)
# assert nodes.has(kate)
fun nodes_with_label(lbl: String): Array[NeoNode] do
- var res = get("{base_url}/db/data/label/{lbl}/nodes")
+ var res = get(base_url / "db/data/label/{lbl.to_percent_encoding}/nodes")
var nodes = new Array[NeoNode]
for json in res.as(JsonArray) do
var obj = json.as(JsonObject)
# assert not nodes.has(kate)
fun nodes_with_labels(labels: Array[String]): Array[NeoNode] do
assert not labels.is_empty
- var res = cypher(new CypherQuery.from_string("MATCH (n:{labels.join(":")}) RETURN n"))
+
+ # Build the query.
+ var buffer = new RopeBuffer
+ buffer.append "match n where \{label_0\} in labels(n)"
+ for i in [1..labels.length[ do
+ buffer.append " and \{label_{i}\} in labels(n)"
+ end
+ buffer.append " return n"
+ var query = new CypherQuery.from_string(buffer.write_to_string)
+ for i in [0..labels.length[ do
+ query.params["label_{i}"] = labels[i]
+ end
+
+ # Retrieve the answer.
+ var res = cypher(query)
var nodes = new Array[NeoNode]
for json in res.as(JsonObject)["data"].as(JsonArray) do
var obj = json.as(JsonArray).first.as(JsonObject)
# Perform a `CypherQuery`
# see: CypherQuery
fun cypher(query: CypherQuery): Jsonable do
- return post("{cypher_url}", query.to_json)
+ return post("{cypher_url}", query.to_rest)
end
# GET JSON data from `url`
# Parse the cURL `response` as a JSON string
private fun parse_response(response: CurlResponse): Jsonable do
if response isa CurlResponseSuccess then
- if response.body_str.is_empty then
+ var str = response.body_str
+ if str.is_empty then return new JsonObject
+ var res = str.parse_json
+ if res isa JsonParseError then
+ var e = new NeoError(res.to_s, "JsonParseError")
+ e.cause = res
+ return e
+ end
+ if res == null then
+ # empty response wrap it in empty object
return new JsonObject
- else
- var str = response.body_str
- var res = str.to_jsonable
- if res == null then
- # empty response wrap it in empty object
- return new JsonObject
- else if res isa JsonObject and res.has_key("exception") then
- var error = "Neo4jError::{res["exception"] or else "null"}"
- var msg = ""
- if res.has_key("message") then
- msg = res["message"].to_s
- end
- return new JsonError(error, msg.to_json)
- else
- return res
+ else if res isa JsonObject and res.has_key("exception") then
+ var error = "Neo4jError::{res["exception"] or else "null"}"
+ var msg = ""
+ if res.has_key("message") then
+ msg = res["message"].to_s
end
+ return new NeoError(msg, error)
+ else
+ return res
end
else if response isa CurlResponseFailed then
- return new JsonError("Curl error", "{response.error_msg} ({response.error_code})")
+ return new NeoError("{response.error_msg} ({response.error_code})", "CurlError")
else
- return new JsonError("Curl error", "Unexpected response '{response}'")
+ return new NeoError("Unexpected response \"{response}\".", "CurlError")
end
end
end
# `params` to embed in the query like in prepared statements
var params = new JsonObject
- init do end
-
# init the query from a query string
init from_string(query: String) do
self.query = query
return self
end
- # Translate the query to JSON
- fun to_json: JsonObject do
+ # Translate the query to the body of a corresponding Neo4j REST request.
+ fun to_rest: JsonObject do
var obj = new JsonObject
obj["query"] = query
if not params.is_empty then
return obj
end
- redef fun to_s do return to_json.to_s
+ redef fun to_s do return to_rest.to_s
end
# The fundamental units that form a graph are nodes and relationships.
private var internal_properties: nullable JsonObject = null
private fun load_properties: JsonObject do
- var obj = neo.get("{url.to_s}/properties").as(JsonObject)
+ var obj = neo.get(url.to_s / "properties").as(JsonObject)
internal_properties = obj
return obj
end
# Is the property `key` set?
fun has_key(key: String): Bool do return properties.has_key(key)
-
- # Translate `self` to JSON
- fun to_json: JsonObject do return properties
end
# Nodes are used to represent entities stored in base.
var tpl = new FlatBuffer
tpl.append "\{"
tpl.append "labels: [{labels.join(", ")}],"
- tpl.append "data: {to_json}"
+ tpl.append "data: {properties.to_json}"
tpl.append "\}"
return tpl.write_to_string
end
private fun load_labels: Array[String] do
var labels = new Array[String]
- var res = neo.get("{url.to_s}/labels")
+ var res = neo.get(url.to_s / "labels")
if res isa JsonArray then
for val in res do labels.add val.to_s
end
private fun load_in_edges: List[NeoEdge] do
var edges = new List[NeoEdge]
- var res = neo.get("{url.to_s}/relationships/in").as(JsonArray)
+ var res = neo.get(url.to_s / "relationships/in").as(JsonArray)
for obj in res do
edges.add(new NeoEdge.from_json(neo, obj.as(JsonObject)))
end
private fun load_out_edges: List[NeoEdge] do
var edges = new List[NeoEdge]
- var res = neo.get("{url.to_s}/relationships/out")
+ var res = neo.get(url.to_s / "relationships/out")
for obj in res.as(JsonArray) do
edges.add(new NeoEdge.from_json(neo, obj.as(JsonObject)))
end
# Get edge type
fun rel_type: nullable String do return internal_type
- redef fun to_json do
+ # Get the JSON body of a REST request that create the relationship.
+ private fun to_rest: JsonObject do
var obj = new JsonObject
if to.is_linked then
obj["to"] = to.url
else
job.to = "\{{edge.from.batch_id.to_s}\}/relationships"
end
- job.body = edge.to_json
+ job.body = edge.to_rest
end
# Create multiple edges
fun save_edges(edges: Collection[NeoEdge]) do for edge in edges do save_edge(edge)
# Execute the batch and update local nodes
- fun execute: List[JsonError] do
+ fun execute: List[NeoError] do
var request = new JsonPOST(client.batch_url, client.curl)
# request.headers["X-Stream"] = "true"
var json_jobs = new JsonArray
- for job in jobs.values do json_jobs.add job.to_json
+ for job in jobs.values do json_jobs.add job.to_rest
request.data = json_jobs
var response = request.execute
var res = client.parse_response(response)
end
# Associate data from response in original nodes and edges
- private fun finalize_batch(response: Jsonable): List[JsonError] do
- var errors = new List[JsonError]
+ private fun finalize_batch(response: Jsonable): List[NeoError] do
+ var errors = new List[NeoError]
if not response isa JsonArray then
- errors.add(new JsonError("Neo4jError", "Unexpected batch response format"))
+ errors.add(new NeoError("Unexpected batch response format.", "Neo4jError"))
return errors
end
# print " {res.length} jobs executed"
for res in response do
if not res isa JsonObject then
- errors.add(new JsonError("Neo4jError", "Unexpected job format in batch response"))
+ errors.add(new NeoError("Unexpected job format in batch response.", "Neo4jError"))
continue
end
var id = res["id"].as(Int)
var body: nullable Jsonable = null
# JSON formated job
- fun to_json: JsonObject do
+ fun to_rest: JsonObject do
var job = new JsonObject
job["id"] = id
job["method"] = method