neo4j-core 3.0.0.alpha.18 → 3.0.0.alpha.19
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/Gemfile +2 -1
- data/README.md +2 -1
- data/lib/neo4j-core/query.rb +1 -1
- data/lib/neo4j-core/version.rb +1 -1
- data/lib/neo4j-core/version.rb~ +5 -0
- data/lib/neo4j-embedded.rb +1 -0
- data/lib/neo4j-embedded/cypher_response.rb~ +85 -0
- data/lib/neo4j-embedded/embedded_node.rb~ +201 -0
- data/lib/neo4j-embedded/embedded_relationship.rb +4 -0
- data/lib/neo4j-embedded/embedded_relationship.rb~ +62 -0
- data/lib/neo4j-embedded/embedded_session.rb +14 -0
- data/lib/neo4j-embedded/embedded_session.rb~ +145 -0
- data/lib/neo4j-embedded/embedded_transaction.rb +35 -0
- data/lib/neo4j-embedded/property.rb +6 -2
- data/lib/neo4j-server/cypher_node.rb +20 -7
- data/lib/neo4j-server/cypher_relationship.rb +16 -4
- data/lib/neo4j-server/cypher_response.rb +43 -17
- data/lib/neo4j-server/cypher_response.rb~ +155 -0
- data/lib/neo4j-server/cypher_session.rb +26 -3
- data/lib/neo4j-server/cypher_transaction.rb +14 -21
- data/lib/neo4j/node.rb +5 -7
- data/lib/neo4j/relationship.rb +5 -0
- data/lib/neo4j/session.rb +16 -0
- data/lib/neo4j/session.rb~ +202 -0
- data/lib/neo4j/transaction.rb +100 -33
- metadata +53 -31
@@ -23,6 +23,10 @@ module Neo4j::Embedded
|
|
23
23
|
Neo4j::Session.register(self)
|
24
24
|
end
|
25
25
|
|
26
|
+
def db_type
|
27
|
+
:embedded_db
|
28
|
+
end
|
29
|
+
|
26
30
|
def inspect
|
27
31
|
"#{self.class} db_location: '#{@db_location}', running: #{running?}"
|
28
32
|
end
|
@@ -41,6 +45,16 @@ module Neo4j::Embedded
|
|
41
45
|
Java::OrgNeo4jTest::ImpermanentGraphDatabase
|
42
46
|
end
|
43
47
|
|
48
|
+
def begin_tx
|
49
|
+
if Neo4j::Transaction.current
|
50
|
+
# Handle nested transaction "placebo transaction"
|
51
|
+
Neo4j::Transaction.current.push_nested!
|
52
|
+
else
|
53
|
+
Neo4j::Embedded::EmbeddedTransaction.new(@graph_db.begin_tx)
|
54
|
+
end
|
55
|
+
Neo4j::Transaction.current
|
56
|
+
end
|
57
|
+
|
44
58
|
def close
|
45
59
|
super
|
46
60
|
shutdown
|
@@ -0,0 +1,145 @@
|
|
1
|
+
# Plugin
|
2
|
+
|
3
|
+
Neo4j::Session.register_db(:embedded_db) do |*args|
|
4
|
+
Neo4j::Embedded::EmbeddedSession.new(*args)
|
5
|
+
end
|
6
|
+
|
7
|
+
|
8
|
+
module Neo4j::Embedded
|
9
|
+
class EmbeddedSession < Neo4j::Session
|
10
|
+
|
11
|
+
class Error < StandardError
|
12
|
+
end
|
13
|
+
|
14
|
+
attr_reader :graph_db, :db_location
|
15
|
+
extend Forwardable
|
16
|
+
extend Neo4j::Core::TxMethods
|
17
|
+
def_delegator :@graph_db, :begin_tx
|
18
|
+
|
19
|
+
|
20
|
+
def initialize(db_location, config={})
|
21
|
+
@db_location = db_location
|
22
|
+
@auto_commit = !!config[:auto_commit]
|
23
|
+
Neo4j::Session.register(self)
|
24
|
+
@query_builder = Neo4j::Core::QueryBuilder.new
|
25
|
+
end
|
26
|
+
|
27
|
+
def start
|
28
|
+
raise Error.new("Embedded Neo4j db is already running") if running?
|
29
|
+
puts "Start embedded Neo4j db at #{db_location}"
|
30
|
+
factory = Java::OrgNeo4jGraphdbFactory::GraphDatabaseFactory.new
|
31
|
+
@graph_db = factory.newEmbeddedDatabase(db_location)
|
32
|
+
Neo4j::Session._notify_listeners(:session_available, self)
|
33
|
+
end
|
34
|
+
|
35
|
+
def factory_class
|
36
|
+
Java::OrgNeo4jGraphdbFactory::GraphDatabaseFactory
|
37
|
+
Java::OrgNeo4jTest::ImpermanentGraphDatabase
|
38
|
+
end
|
39
|
+
|
40
|
+
def close
|
41
|
+
super
|
42
|
+
shutdown
|
43
|
+
end
|
44
|
+
|
45
|
+
def shutdown
|
46
|
+
graph_db && graph_db.shutdown
|
47
|
+
@graph_db = nil
|
48
|
+
end
|
49
|
+
|
50
|
+
def running?
|
51
|
+
!!graph_db
|
52
|
+
end
|
53
|
+
|
54
|
+
def create_label(name)
|
55
|
+
EmbeddedLabel.new(self, name)
|
56
|
+
end
|
57
|
+
|
58
|
+
def load_node(neo_id)
|
59
|
+
_load_node(neo_id)
|
60
|
+
end
|
61
|
+
tx_methods :load_node
|
62
|
+
|
63
|
+
# Same as load but does not return the node as a wrapped Ruby object.
|
64
|
+
#
|
65
|
+
def _load_node(neo_id)
|
66
|
+
return nil if neo_id.nil?
|
67
|
+
@graph_db.get_node_by_id(neo_id.to_i)
|
68
|
+
rescue Java::OrgNeo4jGraphdb.NotFoundException
|
69
|
+
nil
|
70
|
+
end
|
71
|
+
|
72
|
+
def load_relationship(neo_id)
|
73
|
+
_load_relationship(neo_id)
|
74
|
+
end
|
75
|
+
tx_methods :load_relationship
|
76
|
+
|
77
|
+
def _load_relationship(neo_id)
|
78
|
+
return nil if neo_id.nil?
|
79
|
+
@graph_db.get_relationship_by_id(neo_id.to_i)
|
80
|
+
rescue Java::OrgNeo4jGraphdb.NotFoundException
|
81
|
+
nil
|
82
|
+
end
|
83
|
+
|
84
|
+
def query(*params)
|
85
|
+
query_hash = @query_builder.to_query_hash(params, :to_node)
|
86
|
+
cypher = @query_builder.to_cypher(query_hash)
|
87
|
+
|
88
|
+
result = _query(cypher, query_hash[:params])
|
89
|
+
if result.respond_to?(:error?) && result.error?
|
90
|
+
raise Neo4j::Session::CypherError.new(result.error_msg, result.error_code, result.error_status)
|
91
|
+
end
|
92
|
+
|
93
|
+
map_return_procs = @query_builder.to_map_return_procs(query_hash)
|
94
|
+
ResultWrapper.new(result, map_return_procs, cypher)
|
95
|
+
end
|
96
|
+
|
97
|
+
def find_all_nodes(label)
|
98
|
+
EmbeddedLabel.new(self, label).find_nodes
|
99
|
+
end
|
100
|
+
|
101
|
+
def find_nodes(label, key, value)
|
102
|
+
EmbeddedLabel.new(self, label).find_nodes(key,value)
|
103
|
+
end
|
104
|
+
|
105
|
+
# Performs a cypher query with given string.
|
106
|
+
# Remember that you should close the resource iterator.
|
107
|
+
# @param [String] q the cypher query as a String
|
108
|
+
# @return (see #query)
|
109
|
+
def _query(q, params={})
|
110
|
+
engine = Java::OrgNeo4jCypherJavacompat::ExecutionEngine.new(@graph_db)
|
111
|
+
engine.execute(q, Neo4j::Core::HashWithIndifferentAccess.new(params))
|
112
|
+
rescue Exception => e
|
113
|
+
raise Neo4j::Session::CypherError.new(e.message, e.class, 'cypher error')
|
114
|
+
end
|
115
|
+
|
116
|
+
def query_default_return(as)
|
117
|
+
" RETURN #{as}"
|
118
|
+
end
|
119
|
+
|
120
|
+
def _query_or_fail(q)
|
121
|
+
engine = Java::OrgNeo4jCypherJavacompat::ExecutionEngine.new(@graph_db)
|
122
|
+
engine.execute(q)
|
123
|
+
end
|
124
|
+
|
125
|
+
def search_result_to_enumerable(result)
|
126
|
+
result.map {|column| column['n'].wrapper}
|
127
|
+
end
|
128
|
+
|
129
|
+
def create_node(properties = nil, labels=[])
|
130
|
+
if labels.empty?
|
131
|
+
_java_node = graph_db.create_node
|
132
|
+
else
|
133
|
+
labels = EmbeddedLabel.as_java(labels)
|
134
|
+
_java_node = graph_db.create_node(labels)
|
135
|
+
end
|
136
|
+
properties.each_pair { |k, v| _java_node[k]=v } if properties
|
137
|
+
_java_node
|
138
|
+
end
|
139
|
+
tx_methods :create_node
|
140
|
+
|
141
|
+
end
|
142
|
+
|
143
|
+
|
144
|
+
|
145
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Neo4j::Embedded
|
2
|
+
class EmbeddedTransaction
|
3
|
+
attr_reader :root_tx
|
4
|
+
include Neo4j::Transaction::Instance
|
5
|
+
|
6
|
+
def initialize(root_tx)
|
7
|
+
@root_tx = root_tx
|
8
|
+
register_instance
|
9
|
+
end
|
10
|
+
|
11
|
+
def acquire_read_lock(entity)
|
12
|
+
@root_tx.acquire_read_lock(entity)
|
13
|
+
end
|
14
|
+
|
15
|
+
def acquire_write_lock(entity)
|
16
|
+
@root_tx.acquire_write_lock(entity)
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
def inspect
|
21
|
+
"EmbeddedTransaction [nested: #{@pushed_nested} failed?: #{failure?} active: #{Neo4j::Transaction.current == self}]"
|
22
|
+
end
|
23
|
+
|
24
|
+
def _delete_tx
|
25
|
+
@root_tx.failure
|
26
|
+
@root_tx.close
|
27
|
+
end
|
28
|
+
|
29
|
+
def _commit_tx
|
30
|
+
@root_tx.success
|
31
|
+
@root_tx.close
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
@@ -22,8 +22,8 @@ module Neo4j::Embedded::Property
|
|
22
22
|
# * Values in the array must be of the same type.
|
23
23
|
# * You can *not* delete or add one item in the array (e.g. person.phones.delete('123')) but instead you must create a new array instead.
|
24
24
|
#
|
25
|
-
# @param [String, Symbol]
|
26
|
-
# @param [String,Fixnum,Float,true,false, Array]
|
25
|
+
# @param [String, Symbol] k of the property to set
|
26
|
+
# @param [String,Fixnum,Float,true,false, Array] v to set
|
27
27
|
def []=(k, v)
|
28
28
|
to_java_property(k, v)
|
29
29
|
end
|
@@ -61,6 +61,10 @@ module Neo4j::Embedded::Property
|
|
61
61
|
get_id
|
62
62
|
end
|
63
63
|
|
64
|
+
def refresh
|
65
|
+
# nothing is needed in the embedded db since we always asks the database
|
66
|
+
end
|
67
|
+
|
64
68
|
private
|
65
69
|
|
66
70
|
def to_ruby_property(key)
|
@@ -7,9 +7,9 @@ module Neo4j::Server
|
|
7
7
|
@session = session
|
8
8
|
|
9
9
|
@id = if value.is_a?(Hash)
|
10
|
-
|
11
|
-
@props =
|
12
|
-
|
10
|
+
hash = value['data']
|
11
|
+
@props = Hash[hash.map{ |k, v| [k.to_sym, v] }]
|
12
|
+
value['id'] # value['self'].match(/\d+$/)[0].to_i
|
13
13
|
else
|
14
14
|
value
|
15
15
|
end
|
@@ -40,29 +40,37 @@ module Neo4j::Server
|
|
40
40
|
if @props
|
41
41
|
@props
|
42
42
|
else
|
43
|
-
|
44
|
-
props.
|
43
|
+
hash = @session._query_entity_data("START n=node(#{neo_id}) RETURN n")
|
44
|
+
@props = Hash[hash['data'].map{ |k, v| [k.to_sym, v] }]
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
48
|
+
def refresh
|
49
|
+
@props = nil
|
50
|
+
end
|
51
|
+
|
48
52
|
# (see Neo4j::Node#remove_property)
|
49
53
|
def remove_property(key)
|
54
|
+
refresh
|
50
55
|
@session._query_or_fail("START n=node(#{neo_id}) REMOVE n.`#{key}`")
|
51
56
|
end
|
52
57
|
|
53
58
|
# (see Neo4j::Node#set_property)
|
54
59
|
def set_property(key,value)
|
60
|
+
refresh
|
55
61
|
@session._query_or_fail("START n=node(#{neo_id}) SET n.`#{key}` = { value }", false, value: value)
|
56
62
|
value
|
57
63
|
end
|
58
64
|
|
59
65
|
# (see Neo4j::Node#props=)
|
60
66
|
def props=(properties)
|
67
|
+
refresh
|
61
68
|
@session._query_or_fail("START n=node(#{neo_id}) SET n = { props }", false, {props: properties})
|
62
69
|
properties
|
63
70
|
end
|
64
71
|
|
65
72
|
def remove_properties(properties)
|
73
|
+
refresh
|
66
74
|
q = "START n=node(#{neo_id}) REMOVE " + properties.map do |k|
|
67
75
|
"n.`#{k}`"
|
68
76
|
end.join(', ')
|
@@ -71,6 +79,7 @@ module Neo4j::Server
|
|
71
79
|
|
72
80
|
# (see Neo4j::Node#update_props)
|
73
81
|
def update_props(properties)
|
82
|
+
refresh
|
74
83
|
return if properties.empty?
|
75
84
|
|
76
85
|
removed_keys = properties.keys.select{|k| properties[k].nil?}
|
@@ -86,7 +95,11 @@ module Neo4j::Server
|
|
86
95
|
|
87
96
|
# (see Neo4j::Node#get_property)
|
88
97
|
def get_property(key)
|
89
|
-
@
|
98
|
+
if @props
|
99
|
+
@props[key.to_sym]
|
100
|
+
else
|
101
|
+
@session._query_or_fail("START n=node(#{neo_id}) RETURN n.`#{key}`", true)
|
102
|
+
end
|
90
103
|
end
|
91
104
|
|
92
105
|
# (see Neo4j::Node#labels)
|
@@ -134,7 +147,7 @@ module Neo4j::Server
|
|
134
147
|
response = @session._query("START n=node(#{neo_id}) RETURN ID(n)")
|
135
148
|
if (!response.error?)
|
136
149
|
return true
|
137
|
-
elsif (response.error_status
|
150
|
+
elsif (response.error_status =~ /EntityNotFound/)
|
138
151
|
return false
|
139
152
|
else
|
140
153
|
response.raise_error
|
@@ -15,8 +15,7 @@ module Neo4j::Server
|
|
15
15
|
@props = @response_hash['data']
|
16
16
|
@start_node_neo_id = @response_hash['start'].match(/\d+$/)[0].to_i
|
17
17
|
@end_node_neo_id = @response_hash['end'].match(/\d+$/)[0].to_i
|
18
|
-
|
19
|
-
@response_hash['self'].match(/\d+$/)[0].to_i
|
18
|
+
@response_hash['id']
|
20
19
|
else
|
21
20
|
@rel_type = rel_type
|
22
21
|
|
@@ -44,6 +43,14 @@ module Neo4j::Server
|
|
44
43
|
end
|
45
44
|
end
|
46
45
|
|
46
|
+
def _start_node_id
|
47
|
+
@start_node_neo_id ||= get_node_id(:start)
|
48
|
+
end
|
49
|
+
|
50
|
+
def _end_node_id
|
51
|
+
@end_node_neo_id ||= get_node_id(:end)
|
52
|
+
end
|
53
|
+
|
47
54
|
def _start_node
|
48
55
|
load_resource
|
49
56
|
id = resource_url_id(resource_url(:start))
|
@@ -56,6 +63,11 @@ module Neo4j::Server
|
|
56
63
|
Neo4j::Node._load(id)
|
57
64
|
end
|
58
65
|
|
66
|
+
def get_node_id(direction)
|
67
|
+
load_resource
|
68
|
+
resource_url_id(resource_url(direction))
|
69
|
+
end
|
70
|
+
|
59
71
|
def get_property(key)
|
60
72
|
id = neo_id
|
61
73
|
@session._query_or_fail("START n=relationship(#{id}) RETURN n.`#{key}`", true)
|
@@ -76,8 +88,8 @@ module Neo4j::Server
|
|
76
88
|
if @props
|
77
89
|
@props
|
78
90
|
else
|
79
|
-
|
80
|
-
props.
|
91
|
+
hash = @session._query_entity_data("START n=relationship(#{neo_id}) RETURN n")
|
92
|
+
@props = Hash[hash['data'].map{ |k, v| [k.to_sym, v] }]
|
81
93
|
end
|
82
94
|
end
|
83
95
|
|
@@ -19,7 +19,6 @@ module Neo4j::Server
|
|
19
19
|
def_delegator :@response, :error_msg
|
20
20
|
def_delegator :@response, :error_status
|
21
21
|
def_delegator :@response, :error_code
|
22
|
-
def_delegator :@response, :data
|
23
22
|
def_delegator :@response, :columns
|
24
23
|
def_delegator :@response, :struct
|
25
24
|
|
@@ -37,7 +36,7 @@ module Neo4j::Server
|
|
37
36
|
end
|
38
37
|
|
39
38
|
def each(&block)
|
40
|
-
|
39
|
+
@response.each_data_row do |row|
|
41
40
|
yield(row.each_with_index.each_with_object(struct.new) do |(value, i), result|
|
42
41
|
result[columns[i].to_sym] = value
|
43
42
|
end)
|
@@ -53,23 +52,26 @@ module Neo4j::Server
|
|
53
52
|
Enumerator.new do |yielder|
|
54
53
|
self.to_struct_enumeration(cypher).each do |row|
|
55
54
|
yielder << row.each_pair.each_with_object(@struct.new) do |(column, value), result|
|
56
|
-
|
57
|
-
result[column] = if value.is_a?(Hash)
|
58
|
-
if value['labels']
|
59
|
-
CypherNode.new(session, value).wrapper
|
60
|
-
elsif value['type']
|
61
|
-
CypherRelationship.new(session, value).wrapper
|
62
|
-
else
|
63
|
-
value
|
64
|
-
end
|
65
|
-
else
|
66
|
-
value
|
67
|
-
end
|
55
|
+
result[column] = map_row_value(value, session)
|
68
56
|
end
|
69
57
|
end
|
70
58
|
end
|
71
59
|
end
|
72
60
|
|
61
|
+
def map_row_value(value, session)
|
62
|
+
return value unless value.is_a?(Hash)
|
63
|
+
|
64
|
+
if value['labels']
|
65
|
+
add_entity_id(value)
|
66
|
+
CypherNode.new(session, value).wrapper
|
67
|
+
elsif value['type']
|
68
|
+
add_entity_id(value)
|
69
|
+
CypherRelationship.new(session, value).wrapper
|
70
|
+
else
|
71
|
+
value
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
73
75
|
attr_reader :struct
|
74
76
|
|
75
77
|
def initialize(response, uncommited = false)
|
@@ -78,14 +80,30 @@ module Neo4j::Server
|
|
78
80
|
end
|
79
81
|
|
80
82
|
|
81
|
-
def
|
83
|
+
def entity_data(id=nil)
|
84
|
+
if uncommited?
|
85
|
+
data = @data.first['row'].first
|
86
|
+
data.is_a?(Hash) ? {'data' => data, 'id' => id} : data
|
87
|
+
else
|
88
|
+
data = @data[0][0]
|
89
|
+
data.is_a?(Hash) ? add_entity_id(data) : data
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def first_data(id = nil)
|
82
94
|
if uncommited?
|
83
|
-
@data.first['row'].first
|
95
|
+
data = @data.first['row'].first
|
96
|
+
#data.is_a?(Hash) ? {'data' => data, 'id' => id} : data
|
84
97
|
else
|
85
|
-
@data[0][0]
|
98
|
+
data = @data[0][0]
|
99
|
+
data.is_a?(Hash) ? add_entity_id(data) : data
|
86
100
|
end
|
87
101
|
end
|
88
102
|
|
103
|
+
def add_entity_id(data)
|
104
|
+
data.merge!({'id' => data['self'].match(/\d+$/)[0].to_i})
|
105
|
+
end
|
106
|
+
|
89
107
|
def error?
|
90
108
|
!!@error
|
91
109
|
end
|
@@ -98,6 +116,14 @@ module Neo4j::Server
|
|
98
116
|
raise "Response code #{response.code}, expected #{code} for #{response.request.path}, #{response.body}" unless response.code == code
|
99
117
|
end
|
100
118
|
|
119
|
+
def each_data_row
|
120
|
+
if uncommited?
|
121
|
+
data.each{|r| yield r['row']}
|
122
|
+
else
|
123
|
+
data.each{|r| yield r}
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
101
127
|
def set_data(data, columns)
|
102
128
|
@data = data
|
103
129
|
@columns = columns
|