active-orient 0.4 → 0.80
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitignore +1 -0
- data/.graphs.txt.swp +0 -0
- data/Gemfile +9 -5
- data/Guardfile +12 -4
- data/README.md +70 -281
- data/VERSION +1 -1
- data/active-orient.gemspec +9 -7
- data/bin/active-orient-0.6.gem +0 -0
- data/bin/active-orient-console +97 -0
- data/changelog.md +60 -0
- data/config/boot.rb +70 -17
- data/config/config.yml +10 -0
- data/config/connect.yml +11 -6
- data/examples/books.rb +154 -65
- data/examples/streets.rb +89 -85
- data/graphs.txt +70 -0
- data/lib/active-orient.rb +78 -6
- data/lib/base.rb +266 -168
- data/lib/base_properties.rb +76 -65
- data/lib/class_utils.rb +187 -0
- data/lib/database_utils.rb +99 -0
- data/lib/init.rb +80 -0
- data/lib/java-api.rb +442 -0
- data/lib/jdbc.rb +211 -0
- data/lib/model/custom.rb +29 -0
- data/lib/model/e.rb +6 -0
- data/lib/model/edge.rb +114 -0
- data/lib/model/model.rb +134 -0
- data/lib/model/the_class.rb +657 -0
- data/lib/model/the_record.rb +313 -0
- data/lib/model/vertex.rb +371 -0
- data/lib/orientdb_private.rb +48 -0
- data/lib/other.rb +423 -0
- data/lib/railtie.rb +68 -0
- data/lib/rest/change.rb +150 -0
- data/lib/rest/create.rb +287 -0
- data/lib/rest/delete.rb +150 -0
- data/lib/rest/operations.rb +222 -0
- data/lib/rest/read.rb +189 -0
- data/lib/rest/rest.rb +120 -0
- data/lib/rest_disabled.rb +24 -0
- data/lib/support/conversions.rb +42 -0
- data/lib/support/default_formatter.rb +7 -0
- data/lib/support/errors.rb +41 -0
- data/lib/support/logging.rb +38 -0
- data/lib/support/orient.rb +305 -0
- data/lib/support/orientquery.rb +647 -0
- data/lib/support/query.rb +92 -0
- data/rails.md +154 -0
- data/rails/activeorient.rb +32 -0
- data/rails/config.yml +10 -0
- data/rails/connect.yml +17 -0
- metadata +89 -30
- data/lib/model.rb +0 -461
- data/lib/orient.rb +0 -98
- data/lib/query.rb +0 -88
- data/lib/rest.rb +0 -1036
- data/lib/support.rb +0 -347
- data/test.rb +0 -4
- data/usecase.md +0 -91
@@ -0,0 +1,647 @@
|
|
1
|
+
require 'active_support/inflector'
|
2
|
+
|
3
|
+
module OrientSupport
|
4
|
+
module Support
|
5
|
+
|
6
|
+
=begin
|
7
|
+
supports
|
8
|
+
where: 'string'
|
9
|
+
where: { property: 'value', property: value, ... }
|
10
|
+
where: ['string, { property: value, ... }, ... ]
|
11
|
+
|
12
|
+
Used by update and select
|
13
|
+
|
14
|
+
_Usecase:_
|
15
|
+
ORD.compose_where 'z=34', {u:6}
|
16
|
+
=> "where z=34 and u = 6"
|
17
|
+
=end
|
18
|
+
|
19
|
+
#
|
20
|
+
def compose_where *arg , &b
|
21
|
+
arg = arg.flatten.compact
|
22
|
+
|
23
|
+
unless arg.blank?
|
24
|
+
g= generate_sql_list( arg , &b)
|
25
|
+
"where #{g}" unless g.empty?
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
=begin
|
30
|
+
designs a list of "Key = Value" pairs combined by "and" or the binding provided by the block
|
31
|
+
ORD.generate_sql_list where: 25 , upper: '65'
|
32
|
+
=> "where = 25 and upper = '65'"
|
33
|
+
ORD.generate_sql_list( con_id: 25 , symbol: :G) { ',' }
|
34
|
+
=> "con_id = 25 , symbol = 'G'"
|
35
|
+
|
36
|
+
If »NULL« should be addressed, { key: nil } is translated to "key = NULL" (used by set: in update and upsert),
|
37
|
+
{ key: [nil] } is translated to "key is NULL" ( used by where )
|
38
|
+
|
39
|
+
=end
|
40
|
+
def generate_sql_list attributes = {}, &b
|
41
|
+
fill = block_given? ? yield : 'and'
|
42
|
+
case attributes
|
43
|
+
when ::Hash
|
44
|
+
attributes.map do |key, value|
|
45
|
+
case value
|
46
|
+
when nil
|
47
|
+
"#{key} = NULL"
|
48
|
+
when ::Array
|
49
|
+
if value == [nil]
|
50
|
+
"#{key} is NULL"
|
51
|
+
else
|
52
|
+
"#{key} in #{value.to_orient}"
|
53
|
+
end
|
54
|
+
when Range
|
55
|
+
"#{key} between #{value.first} and #{value.last} "
|
56
|
+
else # String, Symbol, Time, Trueclass, Falseclass ...
|
57
|
+
"#{key} = #{value.to_or}"
|
58
|
+
end
|
59
|
+
end.join(" #{fill} ")
|
60
|
+
when ::Array
|
61
|
+
attributes.map{|y| generate_sql_list y, &b }.join( " #{fill} " )
|
62
|
+
when String
|
63
|
+
attributes
|
64
|
+
when Symbol, Numeric
|
65
|
+
attributes.to_s
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
# used both in OrientQuery and MatchConnect
|
71
|
+
# while and where depend on @q, a struct
|
72
|
+
def while_s value=nil # :nodoc:
|
73
|
+
if value.present?
|
74
|
+
@q[:while] << value
|
75
|
+
self
|
76
|
+
elsif @q[:while].present?
|
77
|
+
"while #{ generate_sql_list( @q[:while] ) }"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
def where value=nil # :nodoc:
|
81
|
+
if value.present?
|
82
|
+
if value.is_a?( Hash ) && value.size >1
|
83
|
+
value.each {| a,b| where( {a => b} ) }
|
84
|
+
else
|
85
|
+
@q[:where] << value
|
86
|
+
end
|
87
|
+
self
|
88
|
+
elsif @q[:where].present?
|
89
|
+
"where #{ generate_sql_list( @q[:where] ){ @fill || 'and' } }"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def as a=nil
|
94
|
+
if a
|
95
|
+
@q[:as] = a # subsequent calls overwrite older entries
|
96
|
+
else
|
97
|
+
if @q[:as].blank?
|
98
|
+
nil
|
99
|
+
else
|
100
|
+
"as: #{ @q[:as] }"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end # module
|
105
|
+
|
106
|
+
######################## MatchConnection ###############################
|
107
|
+
|
108
|
+
MatchAttributes = Struct.new(:edge, :direction, :as, :count, :where, :while, :max_depth , :depth_alias, :path_alias, :optional )
|
109
|
+
|
110
|
+
# where and while can be composed incremental
|
111
|
+
# direction, as, connect and edge cannot be changed after initialisation
|
112
|
+
class MatchConnection
|
113
|
+
include Support
|
114
|
+
|
115
|
+
def initialize edge= nil, direction: :both, as: nil, count: 1, **args
|
116
|
+
|
117
|
+
the_edge = edge.is_a?( Class ) ? edge.ref_name : edge.to_s unless edge.nil? || edge == E
|
118
|
+
@q = MatchAttributes.new the_edge , # class
|
119
|
+
direction, # may be :both, :in, :out
|
120
|
+
as, # a string
|
121
|
+
count, # a number
|
122
|
+
args[:where],
|
123
|
+
args[:while],
|
124
|
+
args[:max_depth],
|
125
|
+
args[:depth_alias], # not implemented
|
126
|
+
args[:path_alias], # not implemented
|
127
|
+
args[:optional] # not implemented
|
128
|
+
end
|
129
|
+
|
130
|
+
def direction= dir
|
131
|
+
@q[:direction] = dir
|
132
|
+
end
|
133
|
+
|
134
|
+
|
135
|
+
def direction
|
136
|
+
fillup = @q[:edge].present? ? @q[:edge] : ''
|
137
|
+
case @q[:direction]
|
138
|
+
when :both
|
139
|
+
".both(#{fillup})"
|
140
|
+
when :in
|
141
|
+
".in(#{fillup})"
|
142
|
+
when :out
|
143
|
+
".out(#{fillup})"
|
144
|
+
when :both_vertex, :bothV
|
145
|
+
".bothV()"
|
146
|
+
when :out_vertex, :outV
|
147
|
+
".outV()"
|
148
|
+
when :in_vertex, :inV
|
149
|
+
".inV()"
|
150
|
+
when :both_edge, :bothE
|
151
|
+
".bothE(#{fillup})"
|
152
|
+
when :out_edge, :outE
|
153
|
+
".outE(#{fillup})"
|
154
|
+
when :in_edge, :outE
|
155
|
+
".inE(#{fillup})"
|
156
|
+
end
|
157
|
+
|
158
|
+
end
|
159
|
+
|
160
|
+
def count c=nil
|
161
|
+
if c
|
162
|
+
@q[:count] = c
|
163
|
+
else
|
164
|
+
@q[:count]
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
def max_depth d=nil
|
169
|
+
if d.nil?
|
170
|
+
@q[:max_depth].present? ? "maxDepth: #{@q[:max_depth] }" : nil
|
171
|
+
else
|
172
|
+
@q[:max_depth] = d
|
173
|
+
end
|
174
|
+
end
|
175
|
+
def edge
|
176
|
+
@q[:edge]
|
177
|
+
end
|
178
|
+
|
179
|
+
def compose
|
180
|
+
where_statement =( where.nil? || where.size <5 ) ? nil : "where: ( #{ generate_sql_list( @q[:where] ) })"
|
181
|
+
while_statement =( while_s.nil? || while_s.size <5) ? nil : "while: ( #{ generate_sql_list( @q[:while] )})"
|
182
|
+
|
183
|
+
ministatement = "{"+ [ as, where_statement, while_statement, max_depth].compact.join(', ') + "}"
|
184
|
+
ministatement = "" if ministatement=="{}"
|
185
|
+
|
186
|
+
(1 .. count).map{|x| direction }.join("") + ministatement
|
187
|
+
|
188
|
+
end
|
189
|
+
alias :to_s :compose
|
190
|
+
|
191
|
+
end # class
|
192
|
+
|
193
|
+
|
194
|
+
######################## MatchStatement ################################
|
195
|
+
|
196
|
+
MatchSAttributes = Struct.new(:match_class, :as, :where )
|
197
|
+
class MatchStatement
|
198
|
+
include Support
|
199
|
+
def initialize match_class, as: 0, **args
|
200
|
+
reduce_class = ->(c){ c.is_a?(Class) ? c.ref_name : c.to_s }
|
201
|
+
|
202
|
+
@q = MatchSAttributes.new( reduce_class[match_class], # class
|
203
|
+
as.respond_to?(:zero?) && as.zero? ? reduce_class[match_class].pluralize : as ,
|
204
|
+
args[ :where ])
|
205
|
+
|
206
|
+
@query_stack = [ self ]
|
207
|
+
end
|
208
|
+
|
209
|
+
def match_alias
|
210
|
+
"as: #{@q[:as]}"
|
211
|
+
end
|
212
|
+
|
213
|
+
|
214
|
+
|
215
|
+
# used for the first compose-statement of a compose-query
|
216
|
+
def compose_simple
|
217
|
+
where_statement = where.is_a?(String) && where.size <3 ? nil : "where: ( #{ generate_sql_list( @q[:where] ) })"
|
218
|
+
'{'+ [ "class: #{@q[:match_class]}", as , where_statement].compact.join(', ') + '}'
|
219
|
+
end
|
220
|
+
|
221
|
+
|
222
|
+
def << connection
|
223
|
+
@query_stack << connection
|
224
|
+
self # return MatchStatement
|
225
|
+
end
|
226
|
+
#
|
227
|
+
def compile &b
|
228
|
+
"match " + @query_stack.map( &:to_s ).join + return_statement( &b )
|
229
|
+
end
|
230
|
+
|
231
|
+
|
232
|
+
# executes the standard-case.
|
233
|
+
# returns
|
234
|
+
# * as: :hash : an array of hashes
|
235
|
+
# * as: :array : an array of hash-values
|
236
|
+
# * as :flatten: a simple array of hash-values
|
237
|
+
#
|
238
|
+
# The optional block is used to customize the output.
|
239
|
+
# All previously defiend »as«-Statements are provided though the control variable.
|
240
|
+
#
|
241
|
+
# Background
|
242
|
+
# A match query "Match {class aaa, as: 'aa'} return aa "
|
243
|
+
#
|
244
|
+
# returns [ aa: { result of the query, a Vertex or a value-item }, aa: {}...}, ...] ]
|
245
|
+
# (The standard case)
|
246
|
+
#
|
247
|
+
# A match query "Match {class aaa, as: 'aa'} return aa.name "
|
248
|
+
# returns [ aa.name: { name }, aa.name: { name }., ...] ]
|
249
|
+
#
|
250
|
+
# Now, execute( as: :flatten){ "aa.name" } returns
|
251
|
+
# [name1, name2 ,. ...]
|
252
|
+
#
|
253
|
+
#
|
254
|
+
# Return statements (examples from https://orientdb.org/docs/3.0.x/sql/SQL-Match.html)
|
255
|
+
# "person.name as name, friendship.since as since, friend.name as friend"
|
256
|
+
#
|
257
|
+
# " person.name + \" is a friend of \" + friend.name as friends"
|
258
|
+
#
|
259
|
+
# "$matches"
|
260
|
+
# "$elements"
|
261
|
+
# "$paths"
|
262
|
+
# "$pathElements"
|
263
|
+
#
|
264
|
+
#
|
265
|
+
#
|
266
|
+
def execute as: :hash, &b
|
267
|
+
r = V.db.execute{ compile &b }
|
268
|
+
case as
|
269
|
+
when :hash
|
270
|
+
r
|
271
|
+
when :array
|
272
|
+
r.map{|y| y.values}
|
273
|
+
when :flatten
|
274
|
+
r.map{|y| y.values}.orient_flatten
|
275
|
+
else
|
276
|
+
raise ArgumentError, "Specify parameter «as:» with :hash, :array, :flatten"
|
277
|
+
end
|
278
|
+
end
|
279
|
+
# def compose
|
280
|
+
#
|
281
|
+
# '{'+ [ "class: #{@q[:match_class]}",
|
282
|
+
# "as: #{@as}" , where, while_s,
|
283
|
+
# @maxdepth >0 ? "maxdepth: #{maxdepth}": nil ].compact.join(', ')+'}'
|
284
|
+
# end
|
285
|
+
|
286
|
+
alias :to_s :compose_simple
|
287
|
+
|
288
|
+
|
289
|
+
## return_statement
|
290
|
+
#
|
291
|
+
# summarizes defined as-statements ready to be included as last parameter
|
292
|
+
# in the match-statement-stack
|
293
|
+
#
|
294
|
+
# They can be modified through a block.
|
295
|
+
#
|
296
|
+
# i.e
|
297
|
+
#
|
298
|
+
# t= TestQuery.match( where: {a: 9, b: 's'}, as: nil ) << E.connect("<-", as: :test)
|
299
|
+
# t.return_statement{|y| "#{y.last}.name"}
|
300
|
+
#
|
301
|
+
# =>> " return test.name"
|
302
|
+
#
|
303
|
+
#return_statement is always called through compile
|
304
|
+
#
|
305
|
+
# t.compile{|y| "#{y.last}.name"}
|
306
|
+
|
307
|
+
private
|
308
|
+
def return_statement
|
309
|
+
resolve_as = ->{ @query_stack.map{|s| s.as.split(':').last unless s.as.nil? }.compact }
|
310
|
+
" return " + statement = if block_given?
|
311
|
+
a= yield resolve_as[]
|
312
|
+
a.is_a?(Array) ? a.join(', ') : a
|
313
|
+
else
|
314
|
+
resolve_as[].join(', ')
|
315
|
+
end
|
316
|
+
|
317
|
+
|
318
|
+
end
|
319
|
+
|
320
|
+
end # class
|
321
|
+
|
322
|
+
|
323
|
+
######################## OrientQuery ###################################
|
324
|
+
|
325
|
+
QueryAttributes = Struct.new( :kind, :projection, :where, :let, :order, :while, :misc,
|
326
|
+
:class, :return, :aliases, :database,
|
327
|
+
:set, :remove, :group, :skip, :limit, :unwind )
|
328
|
+
|
329
|
+
class OrientQuery
|
330
|
+
include Support
|
331
|
+
|
332
|
+
|
333
|
+
#
|
334
|
+
def initialize **args
|
335
|
+
@q = QueryAttributes.new args[:kind] || 'select' ,
|
336
|
+
[], # :projection
|
337
|
+
[], # :where ,
|
338
|
+
[], # :let ,
|
339
|
+
[], # :order,
|
340
|
+
[], # :while,
|
341
|
+
[] , # misc
|
342
|
+
'', # class
|
343
|
+
'', # return
|
344
|
+
[], # aliases
|
345
|
+
'', # database
|
346
|
+
[], #set,
|
347
|
+
[] # remove
|
348
|
+
args.each{|k,v| send k, v}
|
349
|
+
@fill = block_given? ? yield : 'and'
|
350
|
+
end
|
351
|
+
|
352
|
+
|
353
|
+
=begin
|
354
|
+
where: "r > 9" --> where r > 9
|
355
|
+
where: {a: 9, b: 's'} --> where a = 9 and b = 's'
|
356
|
+
where:[{ a: 2} , 'b > 3',{ c: 'ufz' }] --> where a = 2 and b > 3 and c = 'ufz'
|
357
|
+
=end
|
358
|
+
def method_missing method, *arg, &b # :nodoc:
|
359
|
+
if method ==:while || method=='while'
|
360
|
+
while_s arg.first
|
361
|
+
else
|
362
|
+
@q[:misc] << method.to_s << generate_sql_list(arg)
|
363
|
+
end
|
364
|
+
self
|
365
|
+
end
|
366
|
+
|
367
|
+
def misc # :nodoc:
|
368
|
+
@q[:misc].join(' ') unless @q[:misc].empty?
|
369
|
+
end
|
370
|
+
|
371
|
+
def subquery # :nodoc:
|
372
|
+
nil
|
373
|
+
end
|
374
|
+
|
375
|
+
|
376
|
+
def kind value=nil
|
377
|
+
if value.present?
|
378
|
+
@q[:kind] = value
|
379
|
+
self
|
380
|
+
else
|
381
|
+
@q[:kind]
|
382
|
+
end
|
383
|
+
end
|
384
|
+
=begin
|
385
|
+
Output the compiled query
|
386
|
+
Parameter: destination (rest, batch )
|
387
|
+
If the query is submitted via the REST-Interface (as get-command), the limit parameter is extracted.
|
388
|
+
=end
|
389
|
+
|
390
|
+
def compose(destination: :batch)
|
391
|
+
if kind.to_sym == :update
|
392
|
+
return_statement = "return after " + ( @q[:aliases].empty? ? "$current" : @q[:aliases].first.to_s)
|
393
|
+
[ 'update', target, set, remove, return_statement , where, limit ].compact.join(' ')
|
394
|
+
elsif kind.to_sym == :update!
|
395
|
+
[ 'update', target, set, where, limit, misc ].compact.join(' ')
|
396
|
+
elsif kind.to_sym == :create
|
397
|
+
[ "CREATE VERTEX", target, set ].compact.join(' ')
|
398
|
+
# [ kind, target, set, return_statement ,where, limit, misc ].compact.join(' ')
|
399
|
+
elsif kind.to_sym == :upsert
|
400
|
+
return_statement = "return after " + ( @q[:aliases].empty? ? "$current" : @q[:aliases].first.to_s)
|
401
|
+
[ "update", target, set,"upsert", return_statement , where, limit, misc ].compact.join(' ')
|
402
|
+
#[ kind, where, return_statement ].compact.join(' ')
|
403
|
+
elsif destination == :rest
|
404
|
+
[ kind, projection, from, let, where, subquery, misc, order, group_by, unwind, skip].compact.join(' ')
|
405
|
+
else
|
406
|
+
[ kind, projection, from, let, where, subquery, while_s, misc, order, group_by, limit, unwind, skip].compact.join(' ')
|
407
|
+
end
|
408
|
+
end
|
409
|
+
alias :to_s :compose
|
410
|
+
|
411
|
+
|
412
|
+
def to_or
|
413
|
+
compose.to_or
|
414
|
+
end
|
415
|
+
|
416
|
+
def target arg = nil
|
417
|
+
if arg.present?
|
418
|
+
@q[:database] = arg
|
419
|
+
self # return query-object
|
420
|
+
elsif @q[:database].present?
|
421
|
+
the_argument = @q[:database]
|
422
|
+
case @q[:database]
|
423
|
+
when ActiveOrient::Model # a single record
|
424
|
+
the_argument.rrid
|
425
|
+
when self.class # result of a query
|
426
|
+
' ( '+ the_argument.compose + ' ) '
|
427
|
+
when Class
|
428
|
+
the_argument.ref_name
|
429
|
+
else
|
430
|
+
if the_argument.to_s.rid? # a string with "#ab:cd"
|
431
|
+
the_argument
|
432
|
+
else # a database-class-name
|
433
|
+
the_argument.to_s
|
434
|
+
end
|
435
|
+
end
|
436
|
+
else
|
437
|
+
raise "cannot complete until a target is specified"
|
438
|
+
end
|
439
|
+
end
|
440
|
+
|
441
|
+
=begin
|
442
|
+
from can either be a Databaseclass to operate on or a Subquery providing data to query further
|
443
|
+
=end
|
444
|
+
def from arg = nil
|
445
|
+
if arg.present?
|
446
|
+
@q[:database] = arg
|
447
|
+
self # return query-object
|
448
|
+
elsif @q[:database].present? # read from
|
449
|
+
"from #{ target }"
|
450
|
+
end
|
451
|
+
end
|
452
|
+
|
453
|
+
|
454
|
+
def order value = nil
|
455
|
+
if value.present?
|
456
|
+
@q[:order] << value
|
457
|
+
self
|
458
|
+
elsif @q[:order].present?
|
459
|
+
|
460
|
+
"order by " << @q[:order].compact.flatten.map do |o|
|
461
|
+
case o
|
462
|
+
when String, Symbol, Array
|
463
|
+
o.to_s
|
464
|
+
else
|
465
|
+
o.map{|x,y| "#{x} #{y}"}.join(" ")
|
466
|
+
end # case
|
467
|
+
end.join(', ')
|
468
|
+
else
|
469
|
+
''
|
470
|
+
end # unless
|
471
|
+
end # def
|
472
|
+
|
473
|
+
|
474
|
+
def database_class # :nodoc:
|
475
|
+
@q[:database]
|
476
|
+
end
|
477
|
+
|
478
|
+
def database_class= arg # :nodoc:
|
479
|
+
@q[:database] = arg
|
480
|
+
end
|
481
|
+
|
482
|
+
def distinct d
|
483
|
+
@q[:projection] << "distinct " + generate_sql_list( d ){ ' as ' }
|
484
|
+
self
|
485
|
+
end
|
486
|
+
|
487
|
+
class << self
|
488
|
+
def mk_simple_setter *m
|
489
|
+
m.each do |def_m|
|
490
|
+
define_method( def_m ) do | value=nil |
|
491
|
+
if value.present?
|
492
|
+
@q[def_m] = value
|
493
|
+
self
|
494
|
+
elsif @q[def_m].present?
|
495
|
+
"#{def_m.to_s} #{generate_sql_list(@q[def_m]){' ,'}}"
|
496
|
+
end
|
497
|
+
end
|
498
|
+
end
|
499
|
+
end
|
500
|
+
def mk_std_setter *m
|
501
|
+
m.each do |def_m|
|
502
|
+
define_method( def_m ) do | value = nil |
|
503
|
+
if value.present?
|
504
|
+
@q[def_m] << case value
|
505
|
+
when String
|
506
|
+
value
|
507
|
+
when ::Hash
|
508
|
+
value.map{|k,v| "#{k} = #{v.to_or}"}.join(", ")
|
509
|
+
else
|
510
|
+
raise "Only String or Hash allowed in #{def_m} statement"
|
511
|
+
end
|
512
|
+
self
|
513
|
+
elsif @q[def_m].present?
|
514
|
+
"#{def_m.to_s} #{@q[def_m].join(',')}"
|
515
|
+
end # branch
|
516
|
+
end # def_method
|
517
|
+
end # each
|
518
|
+
end # def
|
519
|
+
end # class << self
|
520
|
+
mk_simple_setter :limit, :skip, :unwind
|
521
|
+
mk_std_setter :set, :remove
|
522
|
+
|
523
|
+
def let value = nil
|
524
|
+
if value.present?
|
525
|
+
@q[:let] << value
|
526
|
+
self
|
527
|
+
elsif @q[:let].present?
|
528
|
+
"let " << @q[:let].map do |s|
|
529
|
+
case s
|
530
|
+
when String
|
531
|
+
s
|
532
|
+
when ::Hash
|
533
|
+
s.map do |x,y|
|
534
|
+
# if the symbol: value notation of Hash is used, add "$" to the key
|
535
|
+
x = "$#{x.to_s}" unless x.is_a?(String) && x[0] == "$"
|
536
|
+
"#{x} = #{ case y
|
537
|
+
when self.class
|
538
|
+
"(#{y.compose})"
|
539
|
+
else
|
540
|
+
y.to_orient
|
541
|
+
end }"
|
542
|
+
end
|
543
|
+
end
|
544
|
+
end.join(', ')
|
545
|
+
end
|
546
|
+
end
|
547
|
+
#
|
548
|
+
def projection value= nil # :nodoc:
|
549
|
+
if value.present?
|
550
|
+
@q[:projection] << value
|
551
|
+
self
|
552
|
+
elsif @q[:projection].present?
|
553
|
+
@q[:projection].compact.map do | s |
|
554
|
+
case s
|
555
|
+
when ::Array
|
556
|
+
s.join(', ')
|
557
|
+
when String, Symbol
|
558
|
+
s.to_s
|
559
|
+
when ::Hash
|
560
|
+
s.map{ |x,y| "#{x} as #{y}"}.join( ', ')
|
561
|
+
end
|
562
|
+
end.join( ', ' )
|
563
|
+
end
|
564
|
+
end
|
565
|
+
|
566
|
+
|
567
|
+
|
568
|
+
def group value = nil
|
569
|
+
if value.present?
|
570
|
+
@q[:group] << value
|
571
|
+
self
|
572
|
+
elsif @q[:group].present?
|
573
|
+
"group by #{@q[:group].join(', ')}"
|
574
|
+
end
|
575
|
+
end
|
576
|
+
|
577
|
+
alias order_by order
|
578
|
+
alias group_by group
|
579
|
+
|
580
|
+
def get_limit # :nodoc:
|
581
|
+
@q[:limit].nil? ? -1 : @q[:limit].to_i
|
582
|
+
end
|
583
|
+
|
584
|
+
def expand item
|
585
|
+
@q[:projection] =[ " expand ( #{item.to_s} )" ]
|
586
|
+
self
|
587
|
+
end
|
588
|
+
|
589
|
+
# connects by adding {in_or_out}('edgeClass')
|
590
|
+
def connect_with in_or_out, via: nil
|
591
|
+
argument = " #{in_or_out}(#{via.to_or if via.present?})"
|
592
|
+
end
|
593
|
+
# adds a connection
|
594
|
+
# in_or_out: :out ---> outE('edgeClass').in[where-condition]
|
595
|
+
# :in ---> inE('edgeClass').out[where-condition]
|
596
|
+
|
597
|
+
def nodes in_or_out = :out, via: nil, where: nil, expand: true
|
598
|
+
condition = where.present? ? "[ #{generate_sql_list(where)} ]" : ""
|
599
|
+
start = if in_or_out == :in
|
600
|
+
'inE'
|
601
|
+
elsif in_or_out == :out
|
602
|
+
'outE'
|
603
|
+
else
|
604
|
+
"both"
|
605
|
+
end
|
606
|
+
the_end = if in_or_out == :in
|
607
|
+
'.out'
|
608
|
+
elsif in_or_out == :out
|
609
|
+
'.in'
|
610
|
+
else
|
611
|
+
''
|
612
|
+
end
|
613
|
+
argument = " #{start}(#{[via].flatten.map(&:to_or).join(',') if via.present?})#{the_end}#{condition} "
|
614
|
+
|
615
|
+
if expand.present?
|
616
|
+
send :expand, argument
|
617
|
+
else
|
618
|
+
@q[:projection] << argument
|
619
|
+
end
|
620
|
+
self
|
621
|
+
end
|
622
|
+
|
623
|
+
|
624
|
+
# returns nil if the query was not sucessfully executed
|
625
|
+
def execute(reduce: false)
|
626
|
+
#puts "Compose: #{compose}"
|
627
|
+
result = V.orientdb.execute{ compose }
|
628
|
+
return nil unless result.is_a?(::Array)
|
629
|
+
result = result.map{|x| yield x } if block_given?
|
630
|
+
return result.first if reduce && result.size == 1
|
631
|
+
## standard case: return Array
|
632
|
+
OrientSupport::Array.new( work_on: resolve_target, work_with: result.orient_flatten)
|
633
|
+
end
|
634
|
+
:protected
|
635
|
+
def resolve_target
|
636
|
+
if @q[:database].is_a? OrientSupport::OrientQuery
|
637
|
+
@q[:database].resolve_target
|
638
|
+
else
|
639
|
+
@q[:database]
|
640
|
+
end
|
641
|
+
end
|
642
|
+
|
643
|
+
# end
|
644
|
+
end # class
|
645
|
+
|
646
|
+
|
647
|
+
end # module
|