neo4j-core 3.1.1 → 4.0.0
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 +7 -12
- data/README.md +7 -7
- data/lib/neo4j-core.rb +3 -2
- data/lib/neo4j-core/active_entity.rb +8 -10
- data/lib/neo4j-core/cypher_translator.rb +61 -59
- data/lib/neo4j-core/hash_with_indifferent_access.rb +31 -22
- data/lib/neo4j-core/helpers.rb +15 -17
- data/lib/neo4j-core/label.rb +7 -6
- data/lib/neo4j-core/query.rb +271 -268
- data/lib/neo4j-core/query_clauses.rb +371 -355
- data/lib/neo4j-core/query_find_in_batches.rb +26 -26
- data/lib/neo4j-core/version.rb +1 -1
- data/lib/neo4j-embedded.rb +2 -2
- data/lib/neo4j-embedded/cypher_response.rb +40 -41
- data/lib/neo4j-embedded/embedded_database.rb +21 -22
- data/lib/neo4j-embedded/embedded_ha_session.rb +13 -11
- data/lib/neo4j-embedded/embedded_impermanent_session.rb +9 -8
- data/lib/neo4j-embedded/embedded_label.rb +64 -70
- data/lib/neo4j-embedded/embedded_node.rb +68 -73
- data/lib/neo4j-embedded/embedded_relationship.rb +6 -13
- data/lib/neo4j-embedded/embedded_session.rb +128 -132
- data/lib/neo4j-embedded/embedded_transaction.rb +34 -33
- data/lib/neo4j-embedded/property.rb +84 -77
- data/lib/neo4j-embedded/to_java.rb +24 -23
- data/lib/neo4j-server.rb +1 -1
- data/lib/neo4j-server/cypher_authentication.rb +105 -103
- data/lib/neo4j-server/cypher_label.rb +25 -23
- data/lib/neo4j-server/cypher_node.rb +180 -177
- data/lib/neo4j-server/cypher_node_uncommited.rb +11 -9
- data/lib/neo4j-server/cypher_relationship.rb +101 -102
- data/lib/neo4j-server/cypher_response.rb +171 -170
- data/lib/neo4j-server/cypher_session.rb +209 -205
- data/lib/neo4j-server/cypher_transaction.rb +66 -48
- data/lib/neo4j-server/resource.rb +17 -22
- data/lib/neo4j/entity_equality.rb +3 -4
- data/lib/neo4j/label.rb +13 -16
- data/lib/neo4j/node.rb +30 -34
- data/lib/neo4j/property_container.rb +3 -3
- data/lib/neo4j/property_validator.rb +4 -5
- data/lib/neo4j/relationship.rb +17 -22
- data/lib/neo4j/session.rb +19 -21
- data/lib/neo4j/tasks/config_server.rb +2 -3
- data/lib/neo4j/tasks/neo4j_server.rake +82 -74
- data/lib/neo4j/transaction.rb +23 -22
- data/neo4j-core.gemspec +21 -16
- metadata +72 -2
@@ -1,496 +1,512 @@
|
|
1
|
-
module Neo4j
|
2
|
-
module
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
1
|
+
module Neo4j
|
2
|
+
module Core
|
3
|
+
module QueryClauses
|
4
|
+
class ArgError < StandardError
|
5
|
+
attr_reader :arg_part
|
6
|
+
def initialize(arg_part = nil)
|
7
|
+
super
|
8
|
+
@arg_part = arg_part
|
9
|
+
end
|
9
10
|
end
|
10
|
-
end
|
11
11
|
|
12
12
|
|
13
|
-
|
14
|
-
|
13
|
+
class Clause
|
14
|
+
include CypherTranslator
|
15
15
|
|
16
|
-
|
16
|
+
attr_reader :params
|
17
17
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
18
|
+
def initialize(arg, options = {})
|
19
|
+
@arg = arg
|
20
|
+
@options = options
|
21
|
+
@params = {}
|
22
|
+
end
|
23
23
|
|
24
|
-
|
25
|
-
|
26
|
-
|
24
|
+
def value
|
25
|
+
[String, Symbol, Integer, Hash].each do |arg_class|
|
26
|
+
from_method = "from_#{arg_class.name.downcase}"
|
27
|
+
return send(from_method, @arg) if @arg.is_a?(arg_class) && self.respond_to?(from_method)
|
28
|
+
end
|
27
29
|
|
28
|
-
|
29
|
-
|
30
|
+
fail ArgError
|
31
|
+
rescue ArgError => arg_error
|
32
|
+
message = "Invalid argument for #{self.class.keyword}. Full arguments: #{@arg.inspect}"
|
33
|
+
message += " | Invalid part: #{arg_error.arg_part.inspect}" if arg_error.arg_part
|
30
34
|
|
31
|
-
|
32
|
-
|
35
|
+
raise ArgumentError, message
|
36
|
+
end
|
33
37
|
|
34
|
-
|
35
|
-
if self.respond_to?(:
|
36
|
-
|
37
|
-
|
38
|
-
@arg.map do |key, value|
|
39
|
-
self.from_key_and_value key, value
|
38
|
+
def from_hash(value)
|
39
|
+
if self.respond_to?(:from_key_and_value)
|
40
|
+
value.map do |k, v|
|
41
|
+
from_key_and_value k, v
|
40
42
|
end
|
41
43
|
else
|
42
|
-
|
44
|
+
fail ArgError
|
43
45
|
end
|
44
|
-
|
45
|
-
else
|
46
|
-
raise ArgError.new
|
47
46
|
end
|
48
47
|
|
49
|
-
|
50
|
-
|
51
|
-
|
48
|
+
def from_string(value)
|
49
|
+
value
|
50
|
+
end
|
52
51
|
|
53
|
-
|
54
|
-
|
52
|
+
def node_from_key_and_value(key, value, options = {})
|
53
|
+
var = var_from_key_and_value(key, value, options[:prefer] || :var)
|
54
|
+
label = label_from_key_and_value(key, value, options[:prefer] || :var)
|
55
|
+
attributes = attributes_from_key_and_value(key, value)
|
55
56
|
|
56
|
-
|
57
|
-
|
58
|
-
end
|
57
|
+
"(#{var}#{format_label(label)}#{attributes_string(attributes)})"
|
58
|
+
end
|
59
59
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
when Hash
|
70
|
-
if !value.values.any? {|v| v.is_a?(Hash) }
|
71
|
-
case prefer
|
72
|
-
when :var
|
73
|
-
var = key
|
74
|
-
when :label
|
75
|
-
label_string = key
|
60
|
+
def var_from_key_and_value(key, value, prefer = :var)
|
61
|
+
case value
|
62
|
+
when String, Symbol, Class, Module
|
63
|
+
key
|
64
|
+
when Hash
|
65
|
+
if value.values.none? { |v| v.is_a?(Hash) }
|
66
|
+
key if prefer == :var
|
67
|
+
else
|
68
|
+
key
|
76
69
|
end
|
77
70
|
else
|
78
|
-
|
71
|
+
fail ArgError, value
|
79
72
|
end
|
73
|
+
end
|
80
74
|
|
81
|
-
|
82
|
-
|
83
|
-
|
75
|
+
def label_from_key_and_value(key, value, prefer = :var)
|
76
|
+
case value
|
77
|
+
when String, Symbol
|
78
|
+
value
|
79
|
+
when Class, Module
|
80
|
+
defined?(value::CYPHER_LABEL) ? value::CYPHER_LABEL : value.name
|
81
|
+
when Hash
|
82
|
+
if value.values.map(&:class) == [Hash]
|
83
|
+
value.first.first
|
84
|
+
else
|
85
|
+
key if value.values.none? { |v| v.is_a?(Hash) } && prefer == :label
|
86
|
+
end
|
84
87
|
else
|
85
|
-
|
88
|
+
fail ArgError, value
|
86
89
|
end
|
87
|
-
when Class, Module
|
88
|
-
var = key
|
89
|
-
label_string = defined?(value::CYPHER_LABEL) ? value::CYPHER_LABEL : value.name
|
90
|
-
else
|
91
|
-
raise ArgError.new(value)
|
92
90
|
end
|
93
91
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
class << self
|
98
|
-
attr_reader :keyword
|
92
|
+
def attributes_from_key_and_value(key, value)
|
93
|
+
return nil unless value.is_a?(Hash)
|
99
94
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
end.compact
|
95
|
+
if value.values.map(&:class) == [Hash]
|
96
|
+
value.first[1]
|
97
|
+
else
|
98
|
+
value
|
99
|
+
end
|
106
100
|
end
|
107
101
|
|
108
|
-
|
109
|
-
|
102
|
+
class << self
|
103
|
+
attr_reader :keyword
|
104
|
+
|
105
|
+
def from_args(args, options = {})
|
106
|
+
args.flatten.map do |arg|
|
107
|
+
new(arg, options) if !arg.respond_to?(:empty?) || !arg.empty?
|
108
|
+
end.compact
|
109
|
+
end
|
110
|
+
|
111
|
+
def to_cypher(clauses)
|
112
|
+
string = clause_string(clauses)
|
113
|
+
string.strip!
|
110
114
|
|
111
|
-
|
115
|
+
"#{@keyword} #{string}" if string.size > 0
|
116
|
+
end
|
112
117
|
end
|
113
|
-
end
|
114
118
|
|
115
|
-
|
119
|
+
private
|
116
120
|
|
117
|
-
|
118
|
-
|
119
|
-
|
121
|
+
def key_value_string(key, value, previous_keys = [], force_equals = false)
|
122
|
+
param = (previous_keys << key).join('_')
|
123
|
+
param.gsub!(/[^a-z0-9]+/i, '_')
|
124
|
+
param.gsub!(/^_+|_+$/, '')
|
125
|
+
@params[param.to_sym] = value
|
120
126
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
127
|
+
if !value.is_a?(Array) || force_equals
|
128
|
+
"#{key} = {#{param}}"
|
129
|
+
else
|
130
|
+
"#{key} IN {#{param}}"
|
131
|
+
end
|
125
132
|
end
|
126
|
-
end
|
127
133
|
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
label_string
|
132
|
-
|
134
|
+
def format_label(label_string)
|
135
|
+
label_string = label_string.to_s
|
136
|
+
label_string.strip!
|
137
|
+
if !label_string.empty? && label_string[0] != ':'
|
138
|
+
label_string = "`#{label_string}`" unless label_string.match(' ')
|
139
|
+
label_string = ":#{label_string}"
|
140
|
+
end
|
141
|
+
label_string
|
133
142
|
end
|
134
|
-
label_string
|
135
|
-
end
|
136
143
|
|
137
|
-
|
138
|
-
|
139
|
-
v = if value.nil?
|
140
|
-
'null'
|
141
|
-
else
|
142
|
-
value.to_s.match(/^{.+}$/) ? value : value.inspect
|
143
|
-
end
|
144
|
-
"#{key}: #{v}"
|
145
|
-
end.join(', ')
|
144
|
+
def attributes_string(attributes)
|
145
|
+
return '' if not attributes
|
146
146
|
|
147
|
-
|
147
|
+
attributes_string = attributes.map do |key, value|
|
148
|
+
v = if value.nil?
|
149
|
+
'null'
|
150
|
+
else
|
151
|
+
value.to_s.match(/^{.+}$/) ? value : value.inspect
|
152
|
+
end
|
153
|
+
"#{key}: #{v}"
|
154
|
+
end.join(', ')
|
155
|
+
|
156
|
+
" {#{attributes_string}}"
|
157
|
+
end
|
148
158
|
end
|
149
|
-
end
|
150
159
|
|
151
|
-
|
152
|
-
|
160
|
+
class StartClause < Clause
|
161
|
+
@keyword = 'START'
|
153
162
|
|
154
|
-
|
155
|
-
|
156
|
-
|
163
|
+
def from_symbol(value)
|
164
|
+
from_string(value.to_s)
|
165
|
+
end
|
157
166
|
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
167
|
+
def from_key_and_value(key, value)
|
168
|
+
case value
|
169
|
+
when String, Symbol
|
170
|
+
"#{key} = #{value}"
|
171
|
+
else
|
172
|
+
fail ArgError, value
|
173
|
+
end
|
164
174
|
end
|
165
|
-
end
|
166
175
|
|
167
|
-
|
168
|
-
|
169
|
-
|
176
|
+
class << self
|
177
|
+
def clause_string(clauses)
|
178
|
+
clauses.map!(&:value).join(', ')
|
179
|
+
end
|
170
180
|
end
|
171
181
|
end
|
172
|
-
end
|
173
182
|
|
174
|
-
|
175
|
-
|
183
|
+
class WhereClause < Clause
|
184
|
+
@keyword = 'WHERE'
|
176
185
|
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
186
|
+
def from_key_and_value(key, value, previous_keys = [])
|
187
|
+
case value
|
188
|
+
when Hash
|
189
|
+
value.map do |k, v|
|
190
|
+
if k.to_sym == :neo_id
|
191
|
+
clause_id = "neo_id_#{v}"
|
192
|
+
@params[clause_id] = v.to_i
|
193
|
+
"ID(#{key}) = {#{clause_id}}"
|
194
|
+
else
|
195
|
+
"#{key}.#{from_key_and_value(k, v, previous_keys + [key])}"
|
196
|
+
end
|
197
|
+
end.join(' AND ')
|
198
|
+
when NilClass
|
199
|
+
"#{key} IS NULL"
|
200
|
+
when Regexp
|
201
|
+
pattern = (value.casefold? ? '(?i)' : '') + value.source
|
202
|
+
"#{key} =~ #{escape_value(pattern.gsub(/\\/, '\\\\\\'))}"
|
203
|
+
when Array
|
204
|
+
key_value_string(key, value, previous_keys)
|
205
|
+
else
|
206
|
+
key_value_string(key, value, previous_keys)
|
207
|
+
end
|
196
208
|
end
|
197
|
-
end
|
198
209
|
|
199
|
-
|
200
|
-
|
201
|
-
|
210
|
+
class << self
|
211
|
+
def clause_string(clauses)
|
212
|
+
clauses.map!(&:value).join(' AND ')
|
213
|
+
end
|
202
214
|
end
|
203
215
|
end
|
204
|
-
end
|
205
216
|
|
206
217
|
|
207
|
-
|
208
|
-
|
218
|
+
class MatchClause < Clause
|
219
|
+
@keyword = 'MATCH'
|
209
220
|
|
210
|
-
|
211
|
-
|
212
|
-
|
221
|
+
def from_symbol(value)
|
222
|
+
from_string(value.to_s)
|
223
|
+
end
|
213
224
|
|
214
|
-
|
215
|
-
|
216
|
-
|
225
|
+
def from_key_and_value(key, value)
|
226
|
+
node_from_key_and_value(key, value)
|
227
|
+
end
|
217
228
|
|
218
|
-
|
219
|
-
|
220
|
-
|
229
|
+
class << self
|
230
|
+
def clause_string(clauses)
|
231
|
+
clauses.map!(&:value).join(', ')
|
232
|
+
end
|
221
233
|
end
|
222
234
|
end
|
223
|
-
end
|
224
235
|
|
225
|
-
|
226
|
-
|
227
|
-
|
236
|
+
class OptionalMatchClause < MatchClause
|
237
|
+
@keyword = 'OPTIONAL MATCH'
|
238
|
+
end
|
228
239
|
|
229
|
-
|
230
|
-
|
240
|
+
class WithClause < Clause
|
241
|
+
@keyword = 'WITH'
|
231
242
|
|
232
|
-
|
233
|
-
|
234
|
-
|
243
|
+
def from_symbol(value)
|
244
|
+
from_string(value.to_s)
|
245
|
+
end
|
235
246
|
|
236
|
-
|
237
|
-
|
238
|
-
|
247
|
+
def from_key_and_value(key, value)
|
248
|
+
"#{value} AS #{key}"
|
249
|
+
end
|
239
250
|
|
240
|
-
|
241
|
-
|
242
|
-
|
251
|
+
class << self
|
252
|
+
def clause_string(clauses)
|
253
|
+
clauses.map!(&:value).join(', ')
|
254
|
+
end
|
243
255
|
end
|
244
256
|
end
|
245
|
-
end
|
246
257
|
|
247
|
-
|
248
|
-
|
258
|
+
class UsingClause < Clause
|
259
|
+
@keyword = 'USING'
|
249
260
|
|
250
|
-
|
251
|
-
|
252
|
-
|
261
|
+
class << self
|
262
|
+
def clause_string(clauses)
|
263
|
+
clauses.map!(&:value).join(" #{@keyword} ")
|
264
|
+
end
|
253
265
|
end
|
254
266
|
end
|
255
|
-
end
|
256
267
|
|
257
|
-
|
258
|
-
|
268
|
+
class CreateClause < Clause
|
269
|
+
@keyword = 'CREATE'
|
259
270
|
|
260
|
-
|
261
|
-
|
262
|
-
|
271
|
+
def from_string(value)
|
272
|
+
value
|
273
|
+
end
|
263
274
|
|
264
|
-
|
265
|
-
|
266
|
-
|
275
|
+
def from_symbol(value)
|
276
|
+
"(:#{value})"
|
277
|
+
end
|
267
278
|
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
279
|
+
def from_hash(hash)
|
280
|
+
if hash.values.any? { |value| value.is_a?(Hash) }
|
281
|
+
hash.map do |key, value|
|
282
|
+
from_key_and_value(key, value)
|
283
|
+
end
|
284
|
+
else
|
285
|
+
"(#{attributes_string(hash)})"
|
272
286
|
end
|
273
|
-
else
|
274
|
-
"(#{attributes_string(hash)})"
|
275
287
|
end
|
276
|
-
end
|
277
288
|
|
278
|
-
|
279
|
-
|
280
|
-
|
289
|
+
def from_key_and_value(key, value)
|
290
|
+
node_from_key_and_value(key, value, prefer: :label)
|
291
|
+
end
|
281
292
|
|
282
|
-
|
283
|
-
|
284
|
-
|
293
|
+
class << self
|
294
|
+
def clause_string(clauses)
|
295
|
+
clauses.map!(&:value).join(', ')
|
296
|
+
end
|
285
297
|
end
|
286
298
|
end
|
287
|
-
end
|
288
299
|
|
289
|
-
|
290
|
-
|
291
|
-
|
300
|
+
class CreateUniqueClause < CreateClause
|
301
|
+
@keyword = 'CREATE UNIQUE'
|
302
|
+
end
|
292
303
|
|
293
|
-
|
294
|
-
|
295
|
-
|
304
|
+
class MergeClause < CreateClause
|
305
|
+
@keyword = 'MERGE'
|
306
|
+
end
|
296
307
|
|
297
|
-
|
298
|
-
|
308
|
+
class DeleteClause < Clause
|
309
|
+
@keyword = 'DELETE'
|
299
310
|
|
300
|
-
|
301
|
-
|
302
|
-
|
311
|
+
def from_symbol(value)
|
312
|
+
from_string(value.to_s)
|
313
|
+
end
|
303
314
|
|
304
|
-
|
305
|
-
|
306
|
-
|
315
|
+
class << self
|
316
|
+
def clause_string(clauses)
|
317
|
+
clauses.map!(&:value).join(', ')
|
318
|
+
end
|
307
319
|
end
|
308
320
|
end
|
309
|
-
end
|
310
321
|
|
311
|
-
|
312
|
-
|
322
|
+
class OrderClause < Clause
|
323
|
+
@keyword = 'ORDER BY'
|
313
324
|
|
314
|
-
|
315
|
-
|
316
|
-
|
325
|
+
def from_symbol(value)
|
326
|
+
from_string(value.to_s)
|
327
|
+
end
|
317
328
|
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
329
|
+
def from_key_and_value(key, value)
|
330
|
+
case value
|
331
|
+
when String, Symbol
|
332
|
+
"#{key}.#{value}"
|
333
|
+
when Array
|
334
|
+
value.map do |v|
|
335
|
+
if v.is_a?(Hash)
|
336
|
+
from_key_and_value(key, v)
|
337
|
+
else
|
338
|
+
"#{key}.#{v}"
|
339
|
+
end
|
340
|
+
end
|
341
|
+
when Hash
|
342
|
+
value.map do |k, v|
|
343
|
+
"#{key}.#{k} #{v.upcase}"
|
328
344
|
end
|
329
|
-
end
|
330
|
-
when Hash
|
331
|
-
value.map do |k, v|
|
332
|
-
"#{key}.#{k} #{v.upcase}"
|
333
345
|
end
|
334
346
|
end
|
335
|
-
end
|
336
347
|
|
337
|
-
|
338
|
-
|
339
|
-
|
348
|
+
class << self
|
349
|
+
def clause_string(clauses)
|
350
|
+
clauses.map!(&:value).join(', ')
|
351
|
+
end
|
340
352
|
end
|
341
353
|
end
|
342
|
-
end
|
343
354
|
|
344
|
-
|
345
|
-
|
355
|
+
class LimitClause < Clause
|
356
|
+
@keyword = 'LIMIT'
|
346
357
|
|
347
|
-
|
348
|
-
|
349
|
-
|
358
|
+
def from_string(value)
|
359
|
+
clause_id = "#{self.class.keyword.downcase}_#{value}"
|
360
|
+
@params[clause_id] = value.to_i
|
361
|
+
"{#{clause_id}}"
|
362
|
+
end
|
350
363
|
|
351
|
-
|
352
|
-
|
353
|
-
|
364
|
+
def from_integer(value)
|
365
|
+
clause_id = "#{self.class.keyword.downcase}_#{value}"
|
366
|
+
@params[clause_id] = value
|
367
|
+
"{#{clause_id}}"
|
368
|
+
end
|
354
369
|
|
355
|
-
|
356
|
-
|
357
|
-
|
370
|
+
class << self
|
371
|
+
def clause_string(clauses)
|
372
|
+
clauses.last.value
|
373
|
+
end
|
358
374
|
end
|
359
375
|
end
|
360
|
-
end
|
361
376
|
|
362
|
-
|
363
|
-
|
377
|
+
class SkipClause < Clause
|
378
|
+
@keyword = 'SKIP'
|
364
379
|
|
365
|
-
|
366
|
-
|
367
|
-
|
380
|
+
def from_string(value)
|
381
|
+
clause_id = "#{self.class.keyword.downcase}_#{value}"
|
382
|
+
@params[clause_id] = value.to_i
|
383
|
+
"{#{clause_id}}"
|
384
|
+
end
|
368
385
|
|
369
|
-
|
370
|
-
|
371
|
-
|
386
|
+
def from_integer(value)
|
387
|
+
clause_id = "#{self.class.keyword.downcase}_#{value}"
|
388
|
+
@params[clause_id] = value
|
389
|
+
"{#{clause_id}}"
|
390
|
+
end
|
372
391
|
|
373
|
-
|
374
|
-
|
375
|
-
|
392
|
+
class << self
|
393
|
+
def clause_string(clauses)
|
394
|
+
clauses.last.value
|
395
|
+
end
|
376
396
|
end
|
377
397
|
end
|
378
|
-
end
|
379
398
|
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
399
|
+
class SetClause < Clause
|
400
|
+
@keyword = 'SET'
|
401
|
+
|
402
|
+
def from_key_and_value(key, value)
|
403
|
+
case value
|
404
|
+
when String, Symbol
|
405
|
+
"#{key} = #{value}"
|
406
|
+
when Hash
|
407
|
+
if @options[:set_props]
|
408
|
+
attribute_string = value.map { |k, v| "#{k}: #{v.inspect}" }.join(', ')
|
409
|
+
"#{key} = {#{attribute_string}}"
|
410
|
+
else
|
411
|
+
value.map do |k, v|
|
412
|
+
key_value_string("#{key}.`#{k}`", v, ['setter'], true)
|
413
|
+
end
|
394
414
|
end
|
415
|
+
else
|
416
|
+
fail ArgError, value
|
395
417
|
end
|
396
|
-
else
|
397
|
-
raise ArgError.new(value)
|
398
418
|
end
|
399
|
-
end
|
400
419
|
|
401
|
-
|
402
|
-
|
403
|
-
|
420
|
+
class << self
|
421
|
+
def clause_string(clauses)
|
422
|
+
clauses.map!(&:value).join(', ')
|
423
|
+
end
|
404
424
|
end
|
405
425
|
end
|
406
|
-
end
|
407
426
|
|
408
|
-
|
409
|
-
|
427
|
+
class OnCreateSetClause < SetClause
|
428
|
+
@keyword = 'ON CREATE SET'
|
410
429
|
|
411
|
-
|
412
|
-
|
413
|
-
|
430
|
+
def initialize(*args)
|
431
|
+
super
|
432
|
+
@options[:set_props] = false
|
433
|
+
end
|
414
434
|
end
|
415
|
-
end
|
416
435
|
|
417
|
-
|
418
|
-
|
419
|
-
|
436
|
+
class OnMatchSetClause < OnCreateSetClause
|
437
|
+
@keyword = 'ON MATCH SET'
|
438
|
+
end
|
420
439
|
|
421
|
-
|
422
|
-
|
440
|
+
class RemoveClause < Clause
|
441
|
+
@keyword = 'REMOVE'
|
423
442
|
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
443
|
+
def from_key_and_value(key, value)
|
444
|
+
case value
|
445
|
+
when /^:/
|
446
|
+
"#{key}:#{value[1..-1]}"
|
447
|
+
when String
|
448
|
+
"#{key}.#{value}"
|
449
|
+
when Symbol
|
450
|
+
"#{key}:#{value}"
|
451
|
+
else
|
452
|
+
fail ArgError, value
|
453
|
+
end
|
434
454
|
end
|
435
455
|
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
clauses.map(&:value).join(', ')
|
456
|
+
class << self
|
457
|
+
def clause_string(clauses)
|
458
|
+
clauses.map!(&:value).join(', ')
|
459
|
+
end
|
441
460
|
end
|
442
461
|
end
|
443
|
-
end
|
444
462
|
|
445
|
-
|
446
|
-
|
463
|
+
class UnwindClause < Clause
|
464
|
+
@keyword = 'UNWIND'
|
447
465
|
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
466
|
+
def from_key_and_value(key, value)
|
467
|
+
case value
|
468
|
+
when String, Symbol
|
469
|
+
"#{value} AS #{key}"
|
470
|
+
when Array
|
471
|
+
"#{value.inspect} AS #{key}"
|
472
|
+
else
|
473
|
+
fail ArgError, value
|
474
|
+
end
|
456
475
|
end
|
457
|
-
end
|
458
476
|
|
459
|
-
|
460
|
-
|
461
|
-
|
477
|
+
class << self
|
478
|
+
def clause_string(clauses)
|
479
|
+
clauses.map!(&:value).join(' UNWIND ')
|
480
|
+
end
|
462
481
|
end
|
463
482
|
end
|
464
|
-
end
|
465
483
|
|
466
|
-
|
467
|
-
|
484
|
+
class ReturnClause < Clause
|
485
|
+
@keyword = 'RETURN'
|
468
486
|
|
469
|
-
|
470
|
-
|
471
|
-
|
487
|
+
def from_symbol(value)
|
488
|
+
from_string(value.to_s)
|
489
|
+
end
|
472
490
|
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
491
|
+
def from_key_and_value(key, value)
|
492
|
+
case value
|
493
|
+
when Array
|
494
|
+
value.map do |v|
|
495
|
+
from_key_and_value(key, v)
|
496
|
+
end.join(', ')
|
497
|
+
when String, Symbol
|
498
|
+
"#{key}.#{value}"
|
499
|
+
else
|
500
|
+
fail ArgError, value
|
501
|
+
end
|
483
502
|
end
|
484
|
-
end
|
485
503
|
|
486
|
-
|
487
|
-
|
488
|
-
|
504
|
+
class << self
|
505
|
+
def clause_string(clauses)
|
506
|
+
clauses.map!(&:value).join(', ')
|
507
|
+
end
|
489
508
|
end
|
490
509
|
end
|
491
510
|
end
|
492
|
-
|
493
|
-
|
494
511
|
end
|
495
512
|
end
|
496
|
-
|