neo4j-core 3.0.0.alpha.13 → 3.0.0.alpha.14
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +60 -49
- data/lib/mydb/active_tx_log +1 -0
- data/lib/mydb/index/lucene-store.db +0 -0
- data/lib/mydb/index/lucene.log.1 +0 -0
- data/lib/mydb/index/lucene.log.active +0 -0
- data/lib/mydb/lock +0 -0
- data/lib/mydb/messages.log +313 -0
- data/lib/mydb/neostore +0 -0
- data/lib/mydb/neostore.id +0 -0
- data/lib/mydb/neostore.labeltokenstore.db +0 -0
- data/lib/mydb/neostore.labeltokenstore.db.id +0 -0
- data/lib/mydb/neostore.labeltokenstore.db.names +0 -0
- data/lib/mydb/neostore.labeltokenstore.db.names.id +0 -0
- data/lib/mydb/neostore.nodestore.db +0 -0
- data/lib/mydb/neostore.nodestore.db.id +0 -0
- data/lib/mydb/neostore.nodestore.db.labels +0 -0
- data/lib/mydb/neostore.nodestore.db.labels.id +0 -0
- data/lib/mydb/neostore.propertystore.db +0 -0
- data/lib/mydb/neostore.propertystore.db.arrays +0 -0
- data/lib/mydb/neostore.propertystore.db.arrays.id +0 -0
- data/lib/mydb/neostore.propertystore.db.id +0 -0
- data/lib/mydb/neostore.propertystore.db.index +0 -0
- data/lib/mydb/neostore.propertystore.db.index.id +0 -0
- data/lib/mydb/neostore.propertystore.db.index.keys +0 -0
- data/lib/mydb/neostore.propertystore.db.index.keys.id +0 -0
- data/lib/mydb/neostore.propertystore.db.strings +0 -0
- data/lib/mydb/neostore.propertystore.db.strings.id +0 -0
- data/lib/mydb/neostore.relationshipstore.db +0 -0
- data/lib/mydb/neostore.relationshipstore.db.id +0 -0
- data/lib/mydb/neostore.relationshiptypestore.db +0 -0
- data/lib/mydb/neostore.relationshiptypestore.db.id +0 -0
- data/lib/mydb/neostore.relationshiptypestore.db.names +0 -0
- data/lib/mydb/neostore.relationshiptypestore.db.names.id +0 -0
- data/lib/mydb/neostore.schemastore.db +0 -0
- data/lib/mydb/neostore.schemastore.db.id +0 -0
- data/lib/mydb/nioneo_logical.log.1 +0 -0
- data/lib/mydb/nioneo_logical.log.active +0 -0
- data/lib/mydb/schema/label/lucene/write.lock +0 -0
- data/lib/mydb/store_lock +0 -0
- data/lib/mydb/tm_tx_log.1 +0 -0
- data/lib/neo4j-core.rb +1 -2
- data/lib/neo4j-core/query_builder.rb +200 -0
- data/lib/neo4j-core/version.rb +1 -1
- data/lib/neo4j-embedded.rb +1 -0
- data/lib/neo4j-embedded/cypher_response.rb +89 -0
- data/lib/neo4j-embedded/cypher_response.rb~ +85 -0
- data/lib/neo4j-embedded/embedded_node.rb +12 -0
- data/lib/neo4j-embedded/embedded_node.rb~ +201 -0
- data/lib/neo4j-embedded/embedded_relationship.rb +8 -0
- data/lib/neo4j-embedded/embedded_relationship.rb~ +62 -0
- data/lib/neo4j-embedded/embedded_session.rb +20 -12
- data/lib/neo4j-embedded/embedded_session.rb~ +145 -0
- data/lib/neo4j-server/cypher_relationship.rb +6 -11
- data/lib/neo4j-server/cypher_response.rb +43 -5
- data/lib/neo4j-server/cypher_response.rb~ +155 -0
- data/lib/neo4j-server/cypher_session.rb +54 -19
- data/lib/neo4j/label.rb +7 -51
- data/lib/neo4j/node.rb +21 -19
- data/lib/neo4j/relationship.rb +7 -7
- data/lib/neo4j/session.rb +70 -28
- data/lib/neo4j/session.rb~ +202 -0
- data/neo4j-core.gemspec +0 -1
- metadata +49 -16
data/lib/mydb/neostore
ADDED
Binary file
|
Binary file
|
File without changes
|
Binary file
|
Binary file
|
Binary file
|
File without changes
|
Binary file
|
Binary file
|
Binary file
|
File without changes
|
Binary file
|
Binary file
|
Binary file
|
File without changes
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
File without changes
|
Binary file
|
File without changes
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
File without changes
|
data/lib/mydb/store_lock
ADDED
File without changes
|
File without changes
|
data/lib/neo4j-core.rb
CHANGED
@@ -1,12 +1,11 @@
|
|
1
1
|
require 'forwardable'
|
2
2
|
require 'fileutils'
|
3
3
|
|
4
|
-
require 'neo4j-cypher'
|
5
|
-
|
6
4
|
require 'neo4j/property_validator'
|
7
5
|
require 'neo4j/property_container'
|
8
6
|
require 'neo4j-core/helpers'
|
9
7
|
require 'neo4j-core/cypher_translator'
|
8
|
+
require 'neo4j-core/query_builder'
|
10
9
|
|
11
10
|
require 'neo4j/entity_equality'
|
12
11
|
require 'neo4j/node'
|
@@ -0,0 +1,200 @@
|
|
1
|
+
module Neo4j::Core
|
2
|
+
|
3
|
+
class QueryBuilder
|
4
|
+
include CypherTranslator
|
5
|
+
|
6
|
+
DEFAULT_VAR_NAME = :n
|
7
|
+
|
8
|
+
class InvalidQueryError < StandardError;
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(map_return={})
|
12
|
+
@map_return = map_return
|
13
|
+
@map_return[:node] = ->(id) { "ID(#{id})" }
|
14
|
+
end
|
15
|
+
|
16
|
+
# TODO should be moved somewhere else
|
17
|
+
def self.default_cypher_map_return_procs
|
18
|
+
{
|
19
|
+
id_to_node: ->(column) { Neo4j::Node.load(column) },
|
20
|
+
to_node: ->(column) { column.wrapper }, # for embedded db
|
21
|
+
value: ->(column) { column },
|
22
|
+
id_to_rel: ->(column) { Neo4j::Relationship.load(column) },
|
23
|
+
to_rel: ->(column) { column.wrapper } # for embedded db
|
24
|
+
}
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
def to_query_hash(params, default_map_return)
|
29
|
+
if params.first.is_a?(Hash)
|
30
|
+
hash = params.first.clone
|
31
|
+
hash[:map_return] ||= default_map_return unless hash[:q] || hash[:return]
|
32
|
+
hash[:map_return] ||= :value if hash[:return].is_a?(Symbol)
|
33
|
+
return hash
|
34
|
+
else
|
35
|
+
hash = (params[1] && params[1].clone) || {}
|
36
|
+
hash[:q] = params[0]
|
37
|
+
return hash
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def to_map_return_procs(query_hash)
|
42
|
+
map_return_procs = query_hash[:map_return_procs] || self.class.default_cypher_map_return_procs
|
43
|
+
map_return = query_hash[:map_return]
|
44
|
+
case map_return
|
45
|
+
when NilClass
|
46
|
+
return {}
|
47
|
+
when Symbol, String
|
48
|
+
return map_return_procs[map_return.to_sym]
|
49
|
+
when Hash
|
50
|
+
map_return.keys.inject({}) do |ack, key|
|
51
|
+
proc_key = map_return[key]
|
52
|
+
ack[key] = map_return_procs[proc_key]
|
53
|
+
raise InvalidQueryError.new("Illegal map_return, '#{ack[key]}' not defined for #{key}") unless ack[key]
|
54
|
+
ack
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def to_cypher(query_hash)
|
60
|
+
return query_hash[:q] if query_hash[:q]
|
61
|
+
match_parts = label_parts(query_hash[:label])
|
62
|
+
match_parts += match_parts(query_hash[:match])
|
63
|
+
conditions_parts = conditions_parts(query_hash[:conditions])
|
64
|
+
conditions_parts += where_parts(query_hash[:where])
|
65
|
+
|
66
|
+
return_parts = return_parts(query_hash)
|
67
|
+
return_parts += order_parts(query_hash[:order])
|
68
|
+
return_parts += skip_parts(query_hash[:skip])
|
69
|
+
return_parts += limit_parts(query_hash[:limit])
|
70
|
+
|
71
|
+
cypher = "MATCH #{match_parts.join(',')}"
|
72
|
+
cypher += " WHERE #{conditions_parts.join(' AND ')}" if !conditions_parts.empty?
|
73
|
+
cypher + " RETURN #{return_parts.join(' ')}"
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
def order_parts(order)
|
78
|
+
return [] unless order
|
79
|
+
cypher = "ORDER BY "
|
80
|
+
|
81
|
+
handleHash = Proc.new do |hash|
|
82
|
+
if (hash.is_a?(Hash))
|
83
|
+
k, v = hash.first
|
84
|
+
raise "only :asc or :desc allowed in order, got #{query.inspect}" unless [:asc, :desc].include?(v)
|
85
|
+
v.to_sym == :asc ? "#{DEFAULT_VAR_NAME}.`#{k}`" : "#{DEFAULT_VAR_NAME}.`#{k}` DESC"
|
86
|
+
else
|
87
|
+
"#{DEFAULT_VAR_NAME}.`#{hash}`" unless hash.is_a?(Hash)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
case order
|
92
|
+
when Array
|
93
|
+
cypher += order.map(&handleHash).join(', ')
|
94
|
+
when Hash
|
95
|
+
cypher += handleHash.call(order)
|
96
|
+
else
|
97
|
+
cypher += "#{DEFAULT_VAR_NAME}.`#{order}`"
|
98
|
+
end
|
99
|
+
|
100
|
+
[cypher]
|
101
|
+
end
|
102
|
+
|
103
|
+
def return_parts(query_hash)
|
104
|
+
query_hash[:return] ? [cypher_return(query_hash[:return])] : [cypher_default_return(query_hash[:label], query_hash)]
|
105
|
+
end
|
106
|
+
|
107
|
+
def cypher_return(ret)
|
108
|
+
case ret
|
109
|
+
when Array
|
110
|
+
ret.map { |r| cypher_return_val(r) }.join(',')
|
111
|
+
when String, Symbol
|
112
|
+
cypher_return_val(ret)
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
|
117
|
+
def cypher_default_return(label, query_hash)
|
118
|
+
raise InvalidQueryError, "Can't have default return for two labels" if label.is_a?(Hash) && label.key.size > 1
|
119
|
+
if (query_hash[:map_return] == :id_to_node)
|
120
|
+
label.is_a?(Hash) ? "ID(#{label.key.first})" : "ID(#{DEFAULT_VAR_NAME})"
|
121
|
+
elsif (query_hash[:map_return] == :to_node)
|
122
|
+
label.is_a?(Hash) ? "#{label.key.first}" : "#{DEFAULT_VAR_NAME}"
|
123
|
+
else
|
124
|
+
raise InvalidQueryError.new("Don't know how to generate a cypher return #{query_hash.inspect}")
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
128
|
+
|
129
|
+
|
130
|
+
def where_parts(conditions)
|
131
|
+
return [] unless conditions
|
132
|
+
conditions.is_a?(Array) ? conditions : [conditions]
|
133
|
+
end
|
134
|
+
|
135
|
+
def limit_parts(limit)
|
136
|
+
return [] unless limit
|
137
|
+
raise InvalidQueryError.new ":limit value not a number" unless limit.is_a?(Integer)
|
138
|
+
return ["LIMIT #{limit}"]
|
139
|
+
end
|
140
|
+
|
141
|
+
def skip_parts(skip)
|
142
|
+
return [] unless skip
|
143
|
+
raise InvalidQueryError.new ":skip value not a number" unless skip.is_a?(Integer)
|
144
|
+
return ["SKIP #{skip}"]
|
145
|
+
end
|
146
|
+
|
147
|
+
def conditions_parts(conditions)
|
148
|
+
|
149
|
+
return [] unless conditions
|
150
|
+
neo_id = conditions.delete(:neo_id)
|
151
|
+
conditions["id(#{as})"] = neo_id if neo_id
|
152
|
+
|
153
|
+
conditions.map do |key, value|
|
154
|
+
operator, value_string = case value
|
155
|
+
when Regexp
|
156
|
+
pattern = (value.casefold? ? "(?i)" : "") + value.source
|
157
|
+
['=~', escape_value(pattern.gsub(/\\/, '\\\\\\'))]
|
158
|
+
else
|
159
|
+
['=', escape_value(value)]
|
160
|
+
end
|
161
|
+
|
162
|
+
k = key.to_s.dup
|
163
|
+
k = "#{DEFAULT_VAR_NAME}.#{k}" unless k.match(/[\(\.]/)
|
164
|
+
k + operator + value_string.to_s
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
def label_parts(label)
|
169
|
+
case label
|
170
|
+
when NilClass then
|
171
|
+
[]
|
172
|
+
when Hash
|
173
|
+
label.map { |variable, label_name| "(#{variable}:`#{label_name}`)" }
|
174
|
+
else
|
175
|
+
["(n:`#{label}`)"]
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
|
180
|
+
def match_parts(match)
|
181
|
+
case match
|
182
|
+
when Array then
|
183
|
+
return match
|
184
|
+
when String then
|
185
|
+
return [match]
|
186
|
+
when NilClass
|
187
|
+
return []
|
188
|
+
else
|
189
|
+
raise InvalidQueryError, "Invalid value for 'match' query key #{match.inspect}"
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
def cypher_return_val(val)
|
194
|
+
val.is_a?(Symbol) ? "#{DEFAULT_VAR_NAME}.`#{val}` AS `#{val}`" : val
|
195
|
+
end
|
196
|
+
|
197
|
+
end
|
198
|
+
|
199
|
+
end
|
200
|
+
|
data/lib/neo4j-core/version.rb
CHANGED
data/lib/neo4j-embedded.rb
CHANGED
@@ -8,6 +8,7 @@ require 'neo4j-embedded/embedded_label'
|
|
8
8
|
require 'neo4j-embedded/embedded_node'
|
9
9
|
require 'neo4j-embedded/embedded_relationship'
|
10
10
|
require 'neo4j-embedded/embedded_label'
|
11
|
+
require 'neo4j-embedded/cypher_response'
|
11
12
|
|
12
13
|
# TODO replace this with https://github.com/intridea/hashie gem
|
13
14
|
require 'neo4j-core/hash_with_indifferent_access'
|
@@ -0,0 +1,89 @@
|
|
1
|
+
module Neo4j::Embedded
|
2
|
+
|
3
|
+
# Wraps the Cypher query result.
|
4
|
+
# Loads the node and relationships wrapper if possible and use symbol as column keys.
|
5
|
+
# This is typically used in the native neo4j bindings since result does is not a Ruby enumerable with symbols as keys.
|
6
|
+
# @note The result is a once forward read only Enumerable, work if you need to read the result twice - use #to_a
|
7
|
+
#
|
8
|
+
class ResultWrapper
|
9
|
+
class ResultsAlreadyConsumedException < Exception;
|
10
|
+
end
|
11
|
+
|
12
|
+
include Enumerable
|
13
|
+
|
14
|
+
# @return the original result from the Neo4j Cypher Engine, once forward read only !
|
15
|
+
attr_reader :source
|
16
|
+
|
17
|
+
def initialize(source, map_return_procs, query)
|
18
|
+
@source = source
|
19
|
+
@unread = true
|
20
|
+
@map_return_procs = map_return_procs
|
21
|
+
@query = query
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_s
|
25
|
+
@query
|
26
|
+
end
|
27
|
+
|
28
|
+
def inspect
|
29
|
+
"Enumerable query: '#{@query}'"
|
30
|
+
end
|
31
|
+
|
32
|
+
# @return [Array<Symbol>] the columns in the query result
|
33
|
+
def columns
|
34
|
+
@source.columns.map { |x| x.to_sym }
|
35
|
+
end
|
36
|
+
|
37
|
+
# for the Enumerable contract
|
38
|
+
def each(&block)
|
39
|
+
raise ResultsAlreadyConsumedException unless @unread
|
40
|
+
|
41
|
+
if (block)
|
42
|
+
case @map_return_procs
|
43
|
+
when NilClass then
|
44
|
+
each_no_mapping &block
|
45
|
+
when Hash then
|
46
|
+
each_multi_column_mapping &block
|
47
|
+
else
|
48
|
+
each_single_column_mapping &block
|
49
|
+
end
|
50
|
+
else
|
51
|
+
Enumerator.new(self)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def each_no_mapping
|
59
|
+
@source.each do |row|
|
60
|
+
hash = {}
|
61
|
+
row.each do |key, value|
|
62
|
+
out[key.to_sym] = value
|
63
|
+
end
|
64
|
+
yield hash
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def each_multi_column_mapping
|
69
|
+
@source.each do |row|
|
70
|
+
hash = {}
|
71
|
+
row.each do |key, value|
|
72
|
+
k = key.to_sym
|
73
|
+
proc = @map_return_procs[k]
|
74
|
+
hash[k] = proc ? proc.call(value) : value
|
75
|
+
end
|
76
|
+
yield hash
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def each_single_column_mapping
|
81
|
+
@source.each do |row|
|
82
|
+
result = @map_return_procs.call(row.values.first)
|
83
|
+
yield result
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module Neo4j::Embedded
|
2
|
+
|
3
|
+
# Wraps the Cypher query result.
|
4
|
+
# Loads the node and relationships wrapper if possible and use symbol as column keys.
|
5
|
+
# This is typically used in the native neo4j bindings since result does is not a Ruby enumerable with symbols as keys.
|
6
|
+
# @note The result is a once forward read only Enumerable, work if you need to read the result twice - use #to_a
|
7
|
+
#
|
8
|
+
class ResultWrapper
|
9
|
+
class ResultsAlreadyConsumedException < Exception;
|
10
|
+
end
|
11
|
+
|
12
|
+
include Enumerable
|
13
|
+
|
14
|
+
# @return the original result from the Neo4j Cypher Engine, once forward read only !
|
15
|
+
attr_reader :source
|
16
|
+
|
17
|
+
def initialize(source, map_return_procs, query)
|
18
|
+
@source = source
|
19
|
+
@unread = true
|
20
|
+
@map_return_procs = map_return_procs
|
21
|
+
@query = query
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_s
|
25
|
+
@query
|
26
|
+
end
|
27
|
+
|
28
|
+
# @return [Array<Symbol>] the columns in the query result
|
29
|
+
def columns
|
30
|
+
@source.columns.map { |x| x.to_sym }
|
31
|
+
end
|
32
|
+
|
33
|
+
# for the Enumerable contract
|
34
|
+
def each(&block)
|
35
|
+
raise ResultsAlreadyConsumedException unless @unread
|
36
|
+
|
37
|
+
if (block)
|
38
|
+
case @map_return_procs
|
39
|
+
when NilClass then
|
40
|
+
each_no_mapping &block
|
41
|
+
when Hash then
|
42
|
+
each_multi_column_mapping &block
|
43
|
+
else
|
44
|
+
each_single_column_mapping &block
|
45
|
+
end
|
46
|
+
else
|
47
|
+
Enumerator.new(self)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def each_no_mapping
|
55
|
+
@source.each do |row|
|
56
|
+
hash = {}
|
57
|
+
row.each do |key, value|
|
58
|
+
out[key.to_sym] = value
|
59
|
+
end
|
60
|
+
yield hash
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def each_multi_column_mapping
|
65
|
+
@source.each do |row|
|
66
|
+
hash = {}
|
67
|
+
row.each do |key, value|
|
68
|
+
k = key.to_sym
|
69
|
+
proc = @map_return_procs[k]
|
70
|
+
hash[k] = proc ? proc.call(value) : value
|
71
|
+
end
|
72
|
+
yield hash
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def each_single_column_mapping
|
77
|
+
@source.each do |row|
|
78
|
+
result = @map_return_procs.call(row.values.first)
|
79
|
+
yield result
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|