active-orient 0.4 → 0.80
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 +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
|