neo4j-core 3.0.0.alpha.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +22 -0
- data/README.md +332 -0
- data/lib/neo4j-core.rb +27 -0
- data/lib/neo4j-core/cypher_translator.rb +34 -0
- data/lib/neo4j-core/hash_with_indifferent_access.rb +165 -0
- data/lib/neo4j-core/helpers.rb +25 -0
- data/lib/neo4j-core/label.rb +8 -0
- data/lib/neo4j-core/version.rb +5 -0
- data/lib/neo4j-embedded.rb +18 -0
- data/lib/neo4j-embedded/embedded_database.rb +29 -0
- data/lib/neo4j-embedded/embedded_label.rb +80 -0
- data/lib/neo4j-embedded/embedded_node.rb +163 -0
- data/lib/neo4j-embedded/embedded_relationship.rb +44 -0
- data/lib/neo4j-embedded/embedded_session.rb +151 -0
- data/lib/neo4j-embedded/property.rb +43 -0
- data/lib/neo4j-embedded/to_java.rb +49 -0
- data/lib/neo4j-server.rb +10 -0
- data/lib/neo4j-server/cypher_label.rb +28 -0
- data/lib/neo4j-server/cypher_node.rb +140 -0
- data/lib/neo4j-server/cypher_node_uncommited.rb +12 -0
- data/lib/neo4j-server/cypher_relationship.rb +82 -0
- data/lib/neo4j-server/cypher_response.rb +113 -0
- data/lib/neo4j-server/cypher_session.rb +156 -0
- data/lib/neo4j-server/cypher_transaction.rb +81 -0
- data/lib/neo4j-server/resource.rb +73 -0
- data/lib/neo4j/entity_equality.rb +9 -0
- data/lib/neo4j/jars/concurrentlinkedhashmap-lru-1.3.1.jar +0 -0
- data/lib/neo4j/jars/geronimo-jta_1.1_spec-1.1.1.jar +0 -0
- data/lib/neo4j/jars/lucene-core-3.6.2.jar +0 -0
- data/lib/neo4j/jars/neo4j-cypher-2.0.0-M06.jar +0 -0
- data/lib/neo4j/jars/neo4j-kernel-2.0-SNAPSHOT-tests.jar +0 -0
- data/lib/neo4j/jars/neo4j-kernel-2.0.0-M06.jar +0 -0
- data/lib/neo4j/jars/neo4j-lucene-index-2.0.0-M06.jar +0 -0
- data/lib/neo4j/jars/neo4j-management-2.0.0-M06.jar +0 -0
- data/lib/neo4j/jars/org.apache.servicemix.bundles.jline-0.9.94_1.jar +0 -0
- data/lib/neo4j/jars/parboiled-core-1.1.6.jar +0 -0
- data/lib/neo4j/jars/parboiled-scala_2.10-1.1.6.jar +0 -0
- data/lib/neo4j/jars/scala-library-2.10.2.jar +0 -0
- data/lib/neo4j/label.rb +88 -0
- data/lib/neo4j/node.rb +185 -0
- data/lib/neo4j/property_container.rb +22 -0
- data/lib/neo4j/property_validator.rb +23 -0
- data/lib/neo4j/relationship.rb +84 -0
- data/lib/neo4j/session.rb +124 -0
- data/lib/neo4j/tasks/neo4j_server.rb +131 -0
- data/lib/neo4j/transaction.rb +52 -0
- data/neo4j-core.gemspec +35 -0
- metadata +144 -0
@@ -0,0 +1,156 @@
|
|
1
|
+
module Neo4j::Server
|
2
|
+
|
3
|
+
# Plugin
|
4
|
+
Neo4j::Session.register_db(:server_db) do |endpoint_url|
|
5
|
+
response = HTTParty.get(endpoint_url)
|
6
|
+
raise "Server not available on #{endpoint_url} (response code #{response.code})" unless response.code == 200
|
7
|
+
root_data = JSON.parse(response.body)
|
8
|
+
Neo4j::Server::CypherSession.new(root_data['data'])
|
9
|
+
end
|
10
|
+
|
11
|
+
class CypherSession < Neo4j::Session
|
12
|
+
include Resource
|
13
|
+
include Neo4j::Core::CypherTranslator
|
14
|
+
|
15
|
+
alias_method :super_query, :query
|
16
|
+
|
17
|
+
def initialize(data_url)
|
18
|
+
Neo4j::Session.register(self)
|
19
|
+
initialize_resource(data_url)
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_s
|
23
|
+
"CypherSession #{@resource_url}"
|
24
|
+
end
|
25
|
+
|
26
|
+
def initialize_resource(data_url)
|
27
|
+
response = HTTParty.get(data_url)
|
28
|
+
expect_response_code(response,200)
|
29
|
+
data_resource = JSON.parse(response.body)
|
30
|
+
raise "!!!!NO data_resource for #{response.body}" unless data_resource
|
31
|
+
# store the resource data
|
32
|
+
init_resource_data(data_resource, data_url)
|
33
|
+
end
|
34
|
+
|
35
|
+
def close
|
36
|
+
super
|
37
|
+
Neo4j::Transaction.unregister_current
|
38
|
+
end
|
39
|
+
|
40
|
+
def begin_tx
|
41
|
+
tx = wrap_resource(self, 'transaction', CypherTransaction, nil, :post)
|
42
|
+
Thread.current[:neo4j_curr_tx] = tx
|
43
|
+
tx
|
44
|
+
end
|
45
|
+
|
46
|
+
def create_node(props=nil, labels=[])
|
47
|
+
l = labels.empty? ? "" : ":" + labels.map{|k| "`#{k}`"}.join(':')
|
48
|
+
q = "CREATE (n#{l} #{cypher_prop_list(props)}) RETURN ID(n)"
|
49
|
+
cypher_response = _query_or_fail(q, true)
|
50
|
+
CypherNode.new(self, cypher_response)
|
51
|
+
end
|
52
|
+
|
53
|
+
def load_node(neo_id)
|
54
|
+
cypher_response = _query("START n=node(#{neo_id}) RETURN n")
|
55
|
+
if (!cypher_response.error?)
|
56
|
+
CypherNode.new(self, neo_id)
|
57
|
+
elsif (cypher_response.error_status == 'EntityNotFoundException')
|
58
|
+
return nil
|
59
|
+
else
|
60
|
+
cypher_response.raise_error
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def load_relationship(neo_id)
|
65
|
+
cypher_response = _query("START r=relationship(#{neo_id}) RETURN r")
|
66
|
+
if (!cypher_response.error?)
|
67
|
+
CypherRelationship.new(self, neo_id)
|
68
|
+
elsif (cypher_response.error_msg =~ /not found/) # Ugly that the Neo4j API gives us this error message
|
69
|
+
return nil
|
70
|
+
else
|
71
|
+
cypher_response.raise_error
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def create_label(name)
|
76
|
+
CypherLabel.new(self, name)
|
77
|
+
end
|
78
|
+
|
79
|
+
def indexes(label)
|
80
|
+
response = HTTParty.get("#{@resource_url}schema/index/#{label}")
|
81
|
+
expect_response_code(response, 200)
|
82
|
+
data_resource = JSON.parse(response.body)
|
83
|
+
|
84
|
+
property_keys = data_resource.map do |row|
|
85
|
+
row['property-keys'].map(&:to_sym)
|
86
|
+
end
|
87
|
+
|
88
|
+
{
|
89
|
+
property_keys: property_keys
|
90
|
+
}
|
91
|
+
end
|
92
|
+
|
93
|
+
def find_all_nodes(label_name)
|
94
|
+
response = _query_or_fail("MATCH (n:`#{label_name}`) RETURN ID(n)")
|
95
|
+
search_result_to_enumerable(response)
|
96
|
+
end
|
97
|
+
|
98
|
+
def find_nodes(label_name, key, value)
|
99
|
+
response = _query_or_fail <<-CYPHER
|
100
|
+
MATCH (n:`#{label_name}`)
|
101
|
+
WHERE n.#{key} = '#{value}'
|
102
|
+
RETURN ID(n)
|
103
|
+
CYPHER
|
104
|
+
search_result_to_enumerable(response)
|
105
|
+
end
|
106
|
+
|
107
|
+
def query(*params, &query_dsl)
|
108
|
+
result = super
|
109
|
+
if result.error?
|
110
|
+
raise Neo4j::Session::CypherError.new(result.error_msg, result.error_code, result.error_status)
|
111
|
+
end
|
112
|
+
result.to_hash_enumeration
|
113
|
+
end
|
114
|
+
|
115
|
+
# TODO remove this function and do not use cypher DSL internally
|
116
|
+
def _query_internal(*params, &query_dsl)
|
117
|
+
super_query(*params, &query_dsl)
|
118
|
+
end
|
119
|
+
|
120
|
+
def _query_or_fail(q, single_row = false, params=nil)
|
121
|
+
response = _query(q, params)
|
122
|
+
response.raise_error if response.error?
|
123
|
+
single_row ? response.first_data : response
|
124
|
+
end
|
125
|
+
|
126
|
+
def query_default_return
|
127
|
+
" RETURN ID(n)"
|
128
|
+
end
|
129
|
+
|
130
|
+
def _query(q, params=nil)
|
131
|
+
curr_tx = Neo4j::Transaction.current
|
132
|
+
if (curr_tx)
|
133
|
+
curr_tx._query(q, params)
|
134
|
+
else
|
135
|
+
url = resource_url('cypher')
|
136
|
+
q = params.nil? ? {query: q} : {query: q, params: params}
|
137
|
+
response = HTTParty.post(url, headers: resource_headers, body: q.to_json)
|
138
|
+
CypherResponse.create_with_no_tx(response)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def search_result_to_enumerable(response)
|
143
|
+
return [] unless response.data
|
144
|
+
|
145
|
+
Enumerator.new do |yielder|
|
146
|
+
response.data.each do |data|
|
147
|
+
yielder << CypherNode.new(self, data[0]).wrapper
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
|
153
|
+
|
154
|
+
|
155
|
+
end
|
156
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module Neo4j::Server
|
2
|
+
class CypherTransaction
|
3
|
+
attr_reader :commit_url, :exec_url
|
4
|
+
|
5
|
+
include Resource
|
6
|
+
include Neo4j::Core::CypherTranslator
|
7
|
+
|
8
|
+
class CypherError < StandardError
|
9
|
+
attr_reader :code, :status
|
10
|
+
def initialize(code, status, message)
|
11
|
+
super(message)
|
12
|
+
@code = code
|
13
|
+
@status = status
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(db, response, url)
|
18
|
+
@commit_url = response['commit']
|
19
|
+
@exec_url = response.headers['location']
|
20
|
+
init_resource_data(response, url)
|
21
|
+
expect_response_code(response,201)
|
22
|
+
Neo4j::Transaction.register(self)
|
23
|
+
end
|
24
|
+
|
25
|
+
def _query(cypher_query, params=nil)
|
26
|
+
statement = {statement: cypher_query}
|
27
|
+
body = {statements: [statement]}
|
28
|
+
|
29
|
+
if params
|
30
|
+
# TODO can't get this working for some reason using parameters
|
31
|
+
#props = params.keys.inject({}) do|ack, k|
|
32
|
+
# ack[k] = {name: params[k]}
|
33
|
+
# ack
|
34
|
+
#end
|
35
|
+
#statement[:parameters] = props
|
36
|
+
|
37
|
+
# So we have to do this workaround
|
38
|
+
params.each_pair do |k,v|
|
39
|
+
statement[:statement].gsub!("{ #{k} }", escape_value(v))
|
40
|
+
end
|
41
|
+
end
|
42
|
+
response = HTTParty.post(@exec_url, headers: resource_headers, body: body.to_json)
|
43
|
+
|
44
|
+
first_result = response['results'][0]
|
45
|
+
cr = CypherResponse.new(response, true)
|
46
|
+
|
47
|
+
if (response['errors'].empty?)
|
48
|
+
cr.set_data(first_result['data'], first_result['columns'])
|
49
|
+
else
|
50
|
+
first_error = response['errors'].first
|
51
|
+
cr.set_error(first_error['message'], first_error['status'], first_error['code'])
|
52
|
+
end
|
53
|
+
cr
|
54
|
+
end
|
55
|
+
|
56
|
+
def success
|
57
|
+
# this is need in the Java API
|
58
|
+
end
|
59
|
+
|
60
|
+
def failure
|
61
|
+
@failure = true
|
62
|
+
end
|
63
|
+
|
64
|
+
def failure?
|
65
|
+
!!@failure
|
66
|
+
end
|
67
|
+
|
68
|
+
def finish
|
69
|
+
Neo4j::Transaction.unregister(self)
|
70
|
+
if failure?
|
71
|
+
response = HTTParty.delete(@exec_url, headers: resource_headers)
|
72
|
+
else
|
73
|
+
response = HTTParty.post(@commit_url, headers: resource_headers)
|
74
|
+
end
|
75
|
+
expect_response_code(response,200)
|
76
|
+
response
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module Neo4j
|
2
|
+
module Server
|
3
|
+
module Resource
|
4
|
+
|
5
|
+
class ServerException < Exception
|
6
|
+
end
|
7
|
+
|
8
|
+
attr_reader :resource_data, :resource_url
|
9
|
+
|
10
|
+
def init_resource_data(resource_data, resource_url)
|
11
|
+
raise "Exception #{response['exception']}" if resource_data['exception']
|
12
|
+
@resource_url = resource_url
|
13
|
+
@resource_data = resource_data
|
14
|
+
raise "expected @resource_data to be Hash got #{@resource_data.class}" unless @resource_data.respond_to?(:[])
|
15
|
+
self
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
def wrap_resource(db, rel, resource_class, args=nil, verb=:get, payload=nil)
|
20
|
+
url = resource_url(rel, args)
|
21
|
+
response = HTTParty.send(verb, url, headers: {'Content-Type' => 'application/json'}, body: payload)
|
22
|
+
response.code == 404 ? nil : resource_class.new(db, response, url)
|
23
|
+
end
|
24
|
+
|
25
|
+
def resource_url(rel=nil, args=nil)
|
26
|
+
return @resource_url unless rel
|
27
|
+
url = @resource_data[rel.to_s]
|
28
|
+
raise "No resource rel '#{rel}', available #{@resource_data.keys.inspect}" unless url
|
29
|
+
return url unless args
|
30
|
+
if (args.is_a?(Hash))
|
31
|
+
args.keys.inject(url){|ack, key| ack.sub("{#{key}}",args[key].to_s)}
|
32
|
+
else
|
33
|
+
"#{url}/#{args.to_s}"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def handle_response_error(response, msg="Error for request", url = response.request.path.to_s )
|
38
|
+
raise ServerException.new("#{msg} #{url}, #{response.code}, #{response.body}")
|
39
|
+
end
|
40
|
+
|
41
|
+
def expect_response_code(response, expected_code, msg="Error for request", url=response.request.path.to_s )
|
42
|
+
handle_response_error(response, "Expected response code #{expected_code} #{msg}",url) unless response.code == expected_code
|
43
|
+
response
|
44
|
+
end
|
45
|
+
|
46
|
+
def response_exception(response)
|
47
|
+
return nil if response.body.nil? || response.body.empty?
|
48
|
+
JSON.parse(response.body)['exception']
|
49
|
+
end
|
50
|
+
|
51
|
+
def resource_headers
|
52
|
+
{'Content-Type' => 'application/json', 'Accept' => 'application/json'}
|
53
|
+
end
|
54
|
+
|
55
|
+
def resource_url_id(url = @resource_url)
|
56
|
+
url.match(/\/(\d+)$/)[1].to_i
|
57
|
+
end
|
58
|
+
|
59
|
+
def convert_from_json_value(value)
|
60
|
+
JSON.parse(value, :quirks_mode => true)
|
61
|
+
end
|
62
|
+
|
63
|
+
def convert_to_json_value(value)
|
64
|
+
case value
|
65
|
+
when String
|
66
|
+
%Q["#{value}"]
|
67
|
+
else
|
68
|
+
value.to_s
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
data/lib/neo4j/label.rb
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
module Neo4j
|
2
|
+
class Label
|
3
|
+
|
4
|
+
# @abstract
|
5
|
+
def name
|
6
|
+
raise 'not implemented'
|
7
|
+
end
|
8
|
+
|
9
|
+
# @abstract
|
10
|
+
def create_index(*properties)
|
11
|
+
raise 'not implemented'
|
12
|
+
end
|
13
|
+
|
14
|
+
# @abstract
|
15
|
+
def drop_index(*properties)
|
16
|
+
raise 'not implemented'
|
17
|
+
end
|
18
|
+
|
19
|
+
# List indices for a label
|
20
|
+
# @abstract
|
21
|
+
def indexes
|
22
|
+
raise 'not implemented'
|
23
|
+
end
|
24
|
+
|
25
|
+
class << self
|
26
|
+
include Neo4j::Core::CypherTranslator
|
27
|
+
|
28
|
+
def create(name, session = Neo4j::Session.current)
|
29
|
+
session.create_label(name)
|
30
|
+
end
|
31
|
+
|
32
|
+
def query(label_name, query, session = Neo4j::Session.current)
|
33
|
+
cypher = "MATCH (n:`#{label_name}`)"
|
34
|
+
cypher += condition_to_cypher(query) if query[:conditions] && !query[:conditions].empty?
|
35
|
+
cypher += session.query_default_return
|
36
|
+
cypher += order_to_cypher(query) if query[:order]
|
37
|
+
|
38
|
+
response = session._query_or_fail(cypher)
|
39
|
+
session.search_result_to_enumerable(response) # TODO make it work in Embedded and refactor
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
def find_all_nodes(label_name, session = Neo4j::Session.current)
|
44
|
+
session.find_all_nodes(label_name)
|
45
|
+
end
|
46
|
+
|
47
|
+
def find_nodes(label_name, key, value, session = Neo4j::Session.current)
|
48
|
+
session.find_nodes(label_name, key, value)
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def condition_to_cypher(query)
|
54
|
+
conditions = query[:conditions]
|
55
|
+
" WHERE " + conditions.keys.map do |k|
|
56
|
+
"n.#{k}=#{escape_value(conditions[k])}"
|
57
|
+
end.join(" AND ")
|
58
|
+
end
|
59
|
+
|
60
|
+
def order_to_cypher(query)
|
61
|
+
cypher = " ORDER BY "
|
62
|
+
order = query[:order]
|
63
|
+
|
64
|
+
handleHash = Proc.new do |hash|
|
65
|
+
if (hash.is_a?(Hash))
|
66
|
+
k, v = hash.first
|
67
|
+
raise "only :asc or :desc allowed in order, got #{query.inspect}" unless [:asc, :desc].include?(v)
|
68
|
+
v.to_sym == :asc ? "n.`#{k}`" : "n.`#{k}` DESC"
|
69
|
+
else
|
70
|
+
"n.`#{hash}`" unless hash.is_a?(Hash)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
case order
|
75
|
+
when Array
|
76
|
+
cypher += order.map(&handleHash).join(', ')
|
77
|
+
when Hash
|
78
|
+
cypher += handleHash.call(order)
|
79
|
+
else
|
80
|
+
cypher += "n.`#{order}`"
|
81
|
+
end
|
82
|
+
|
83
|
+
cypher
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
data/lib/neo4j/node.rb
ADDED
@@ -0,0 +1,185 @@
|
|
1
|
+
module Neo4j
|
2
|
+
|
3
|
+
# A module that allows plugins to register wrappers around Neo4j::Node objects
|
4
|
+
module Wrapper
|
5
|
+
# Used by Neo4j::NodeMixin to wrap nodes
|
6
|
+
def wrapper
|
7
|
+
self
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
# The base class for both the Embedded and Server Neo4j Node
|
12
|
+
# Notice this class is abstract and can't be instantiated
|
13
|
+
class Node
|
14
|
+
include EntityEquality
|
15
|
+
include Wrapper
|
16
|
+
include PropertyContainer
|
17
|
+
|
18
|
+
# @return [Hash] all properties of the node
|
19
|
+
def props()
|
20
|
+
raise 'not implemented'
|
21
|
+
end
|
22
|
+
|
23
|
+
# replace all properties with new properties
|
24
|
+
# @param hash a hash of properties the node should have
|
25
|
+
def props=(hash)
|
26
|
+
raise 'not implemented'
|
27
|
+
end
|
28
|
+
|
29
|
+
# Directly remove the property on the node (low level method, may need transaction)
|
30
|
+
def remove_property(key)
|
31
|
+
raise 'not implemented'
|
32
|
+
end
|
33
|
+
|
34
|
+
# Directly set the property on the node (low level method, may need transaction)
|
35
|
+
# @param [Hash, String] key
|
36
|
+
# @param value see Neo4j::PropertyValidator::VALID_PROPERTY_VALUE_CLASSES for valid values
|
37
|
+
def set_property(key, value)
|
38
|
+
raise 'not implemented'
|
39
|
+
end
|
40
|
+
|
41
|
+
# Directly get the property on the node (low level method, may need transaction)
|
42
|
+
# @param [Hash, String] key
|
43
|
+
# @return the value of the key
|
44
|
+
def get_property(key, value)
|
45
|
+
raise 'not implemented'
|
46
|
+
end
|
47
|
+
|
48
|
+
# Creates a relationship of given type to other_node with optionally properties
|
49
|
+
# @param [Symbol] type the type of the relation between the two nodes
|
50
|
+
# @param [Neo4j::Node] other_node the other node
|
51
|
+
# @param [Hash] props optionally properties for the created relationship
|
52
|
+
def create_rel(type, other_node, props = nil)
|
53
|
+
raise 'not implemented'
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
# Returns an enumeration of relationships.
|
58
|
+
# It always returns relationships of depth one.
|
59
|
+
#
|
60
|
+
# @param [Hash] opts the options to create a message with.
|
61
|
+
# @option opts [Symbol] :dir dir the direction of the relationship, allowed values: :both, :incoming, :outgoing.
|
62
|
+
# @option opts [Symbol] :type the type of relationship to navigate
|
63
|
+
# @option opts [Symbol] :between return all the relationships between this and given node
|
64
|
+
# @return [Enumerable] of Neo4j::Relationship objects
|
65
|
+
#
|
66
|
+
# @example Return both incoming and outgoing relationships of any type
|
67
|
+
# node_a.rels
|
68
|
+
#
|
69
|
+
# @example All outgoing or incoming relationship of type friends
|
70
|
+
# node_a.rels(type: :friends)
|
71
|
+
#
|
72
|
+
# @example All outgoing relationships between me and another node of type friends
|
73
|
+
# node_a.rels(type: :friends, dir: :outgoing, between: node_b)
|
74
|
+
#
|
75
|
+
def rels(match = {dir: :both})
|
76
|
+
raise 'not implemented'
|
77
|
+
end
|
78
|
+
|
79
|
+
# Adds one or more Neo4j labels on the node
|
80
|
+
def add_label(*labels)
|
81
|
+
raise 'not implemented'
|
82
|
+
end
|
83
|
+
|
84
|
+
# @return all labels on the node
|
85
|
+
def labels()
|
86
|
+
raise 'not implemented'
|
87
|
+
end
|
88
|
+
|
89
|
+
# Deletes this node from the database
|
90
|
+
def del()
|
91
|
+
raise 'not implemented'
|
92
|
+
end
|
93
|
+
|
94
|
+
# @return true if the node exists in the database
|
95
|
+
def exist?
|
96
|
+
raise 'not implemented'
|
97
|
+
end
|
98
|
+
|
99
|
+
# @returns all the Neo4j labels for this node
|
100
|
+
def labels
|
101
|
+
raise 'not implemented'
|
102
|
+
end
|
103
|
+
|
104
|
+
# Returns the only node of a given type and direction that is attached to this node, or nil.
|
105
|
+
# This is a convenience method that is used in the commonly occuring situation where a node has exactly zero or one relationships of a given type and direction to another node.
|
106
|
+
# Typically this invariant is maintained by the rest of the code: if at any time more than one such relationships exist, it is a fatal error that should generate an exception.
|
107
|
+
#
|
108
|
+
# This method reflects that semantics and returns either:
|
109
|
+
# * nil if there are zero relationships of the given type and direction,
|
110
|
+
# * the relationship if there's exactly one, or
|
111
|
+
# * throws an exception in all other cases.
|
112
|
+
#
|
113
|
+
# This method should be used only in situations with an invariant as described above. In those situations, a "state-checking" method (e.g. #rel?) is not required,
|
114
|
+
# because this method behaves correctly "out of the box."
|
115
|
+
#
|
116
|
+
# @param (see #rel)
|
117
|
+
def node(specs = {})
|
118
|
+
raise 'not implemented'
|
119
|
+
end
|
120
|
+
|
121
|
+
# Same as #node but returns the relationship. Notice it may raise an exception if there are more then one relationship matching.
|
122
|
+
def rel(spec = {})
|
123
|
+
raise 'not implemented'
|
124
|
+
end
|
125
|
+
|
126
|
+
# Returns true or false if there is one or more relationships
|
127
|
+
# Same as `!! #rel()`
|
128
|
+
def rel?(spec = {})
|
129
|
+
raise 'not implemented'
|
130
|
+
end
|
131
|
+
|
132
|
+
# Same as Neo4j::Node#exist?
|
133
|
+
def exist?
|
134
|
+
raise 'not implemented'
|
135
|
+
end
|
136
|
+
|
137
|
+
# Works like #rels method but instead returns the nodes.
|
138
|
+
# It does try to load a Ruby wrapper around each node
|
139
|
+
# @abstract
|
140
|
+
# @param (see #rels)
|
141
|
+
# @return [Enumerable] an Enumeration of either Neo4j::Node objects or wrapped Neo4j::Node objects
|
142
|
+
# @notice it's possible that the same node is returned more then once because of several relationship reaching to the same node, see #outgoing for alternative
|
143
|
+
def nodes(specs = {})
|
144
|
+
#rels(specs).map{|n| n.other_node(self)}
|
145
|
+
end
|
146
|
+
|
147
|
+
class << self
|
148
|
+
# Creates a node
|
149
|
+
def create(props=nil, *labels_or_db)
|
150
|
+
session = Neo4j::Core::ArgumentHelper.session(labels_or_db)
|
151
|
+
session.create_node(props, labels_or_db)
|
152
|
+
end
|
153
|
+
|
154
|
+
# Loads a node from the database with given id
|
155
|
+
def load(neo_id, session = Neo4j::Session.current)
|
156
|
+
node = session.load_node(neo_id)
|
157
|
+
node && node.wrapper
|
158
|
+
end
|
159
|
+
|
160
|
+
# Checks if the given entity node or entity id (Neo4j::Node#neo_id) exists in the database.
|
161
|
+
# @return [true, false] if exist
|
162
|
+
def exist?(entity_or_entity_id, session = Neo4j::Session.current)
|
163
|
+
session.node_exist?(neo_id)
|
164
|
+
end
|
165
|
+
|
166
|
+
# Find the node with given label and value
|
167
|
+
def find_nodes(label, value=nil, session = Neo4j::Session.current)
|
168
|
+
session.find_nodes(label, value)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
def initialize
|
173
|
+
raise "Can't instantiate abstract class" if abstract_class?
|
174
|
+
puts "Instantiated!"
|
175
|
+
end
|
176
|
+
|
177
|
+
private
|
178
|
+
def abstract_class?
|
179
|
+
self.class == Node
|
180
|
+
end
|
181
|
+
|
182
|
+
|
183
|
+
end
|
184
|
+
|
185
|
+
end
|