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.
Files changed (61) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +1 -0
  3. data/.graphs.txt.swp +0 -0
  4. data/Gemfile +9 -5
  5. data/Guardfile +12 -4
  6. data/README.md +70 -281
  7. data/VERSION +1 -1
  8. data/active-orient.gemspec +9 -7
  9. data/bin/active-orient-0.6.gem +0 -0
  10. data/bin/active-orient-console +97 -0
  11. data/changelog.md +60 -0
  12. data/config/boot.rb +70 -17
  13. data/config/config.yml +10 -0
  14. data/config/connect.yml +11 -6
  15. data/examples/books.rb +154 -65
  16. data/examples/streets.rb +89 -85
  17. data/graphs.txt +70 -0
  18. data/lib/active-orient.rb +78 -6
  19. data/lib/base.rb +266 -168
  20. data/lib/base_properties.rb +76 -65
  21. data/lib/class_utils.rb +187 -0
  22. data/lib/database_utils.rb +99 -0
  23. data/lib/init.rb +80 -0
  24. data/lib/java-api.rb +442 -0
  25. data/lib/jdbc.rb +211 -0
  26. data/lib/model/custom.rb +29 -0
  27. data/lib/model/e.rb +6 -0
  28. data/lib/model/edge.rb +114 -0
  29. data/lib/model/model.rb +134 -0
  30. data/lib/model/the_class.rb +657 -0
  31. data/lib/model/the_record.rb +313 -0
  32. data/lib/model/vertex.rb +371 -0
  33. data/lib/orientdb_private.rb +48 -0
  34. data/lib/other.rb +423 -0
  35. data/lib/railtie.rb +68 -0
  36. data/lib/rest/change.rb +150 -0
  37. data/lib/rest/create.rb +287 -0
  38. data/lib/rest/delete.rb +150 -0
  39. data/lib/rest/operations.rb +222 -0
  40. data/lib/rest/read.rb +189 -0
  41. data/lib/rest/rest.rb +120 -0
  42. data/lib/rest_disabled.rb +24 -0
  43. data/lib/support/conversions.rb +42 -0
  44. data/lib/support/default_formatter.rb +7 -0
  45. data/lib/support/errors.rb +41 -0
  46. data/lib/support/logging.rb +38 -0
  47. data/lib/support/orient.rb +305 -0
  48. data/lib/support/orientquery.rb +647 -0
  49. data/lib/support/query.rb +92 -0
  50. data/rails.md +154 -0
  51. data/rails/activeorient.rb +32 -0
  52. data/rails/config.yml +10 -0
  53. data/rails/connect.yml +17 -0
  54. metadata +89 -30
  55. data/lib/model.rb +0 -461
  56. data/lib/orient.rb +0 -98
  57. data/lib/query.rb +0 -88
  58. data/lib/rest.rb +0 -1036
  59. data/lib/support.rb +0 -347
  60. data/test.rb +0 -4
  61. data/usecase.md +0 -91
@@ -0,0 +1,313 @@
1
+ module ModelRecord
2
+ ############### RECORD FUNCTIONS ###############
3
+
4
+ def to_s
5
+ to_human
6
+ end
7
+ ############# GET #############
8
+
9
+ def from_orient # :nodoc:
10
+ self
11
+ end
12
+
13
+ # Returns just the name of the Class
14
+
15
+ def self.classname # :nodoc:
16
+ self.class.to_s.split(':')[-1]
17
+ end
18
+ =begin
19
+ flag whether a property exists on the Record-level
20
+ =end
21
+ def has_property? property
22
+ attributes.keys.include? property.to_sym
23
+ end
24
+
25
+ def properties
26
+ { "@type" => "d", "@class" => self.metadata[:class] }.merge attributes
27
+ end
28
+
29
+ #
30
+ # Obtain the RID of the Record (format: *00:00*)
31
+ #
32
+
33
+ def rid
34
+ begin
35
+ "#{@metadata[:cluster]}:#{@metadata[:record]}"
36
+ rescue
37
+ "0:0"
38
+ end
39
+ end
40
+ =begin
41
+ The extended representation of RID (format: *#00:00* )
42
+ =end
43
+ def rrid
44
+ "#" + rid
45
+ end
46
+ alias to_orient rrid
47
+
48
+ def to_or
49
+ rid.rid? ? rrid : "{ #{embedded} }"
50
+ end
51
+
52
+ # returns a OrientSupport::OrientQuery
53
+ def query **args
54
+ OrientSupport::OrientQuery.new( **{ from: self}.merge(args))
55
+ end
56
+ =begin
57
+ Execute a Query using the current model-record as origin.
58
+
59
+ It sends the OrientSupport::OrientQuery to the database and returns an
60
+ ActiveOrient::Model-Object or an Array of Model-Objects as result.
61
+
62
+ *Usage:* Query the Database by traversing through links, edges and vertices starting at a known location
63
+
64
+ =end
65
+
66
+ # def execute query, delete_cash: false
67
+ #
68
+ # query.from rrid if query.is_a?( OrientSupport::OrientQuery) && query.from.nil?
69
+ # ActiveOrient::Base.remove_rid( self ) if delete_cash
70
+ # result = orientdb.execute{ query.to_s }
71
+ # result = if block_given?
72
+ # result.is_a?(Array)? result.map{|x| yield x } : yield(result)
73
+ # else
74
+ # result
75
+ # end
76
+ # if result.is_a? Array
77
+ # OrientSupport::Array.new work_on: self, work_with: result.orient_flatten
78
+ # else
79
+ # result
80
+ # end # return value
81
+ # end
82
+ #
83
+ =begin
84
+ Fires a »where-Query» to the database starting with the current model-record.
85
+
86
+ Attributes:
87
+ * a string ( obj.find "in().out().some_attribute >3" )
88
+ * a hash ( obj.find 'some_embedded_obj.name' => 'test' )
89
+ * an array
90
+
91
+ Returns the result-set, ie. a Query-Object which contains links to the addressed records.
92
+
93
+ =end
94
+ def find attributes = {}
95
+ q = OrientSupport::OrientQuery.new from: self, where: attributes
96
+ query q
97
+ end
98
+
99
+ # Get the version of the object
100
+ def version # :nodoc:
101
+ if document.present?
102
+ document.version
103
+ else
104
+ @metadata[:version]
105
+ end
106
+ end
107
+ private
108
+ def version= version # :nodoc:
109
+ @metadata[:version] = version
110
+ end
111
+
112
+ def increment_version # :nodoc:
113
+ @metadata[:version] += 1
114
+ end
115
+
116
+ public
117
+
118
+ ############# DELETE ###########
119
+
120
+ # Removes the Model-Instance from the database.
121
+ #
122
+ # It is overloaded in Vertex and Edge.
123
+
124
+ def delete
125
+ orientdb.delete_record self
126
+ end
127
+
128
+
129
+ ########### UPDATE ############
130
+
131
+ =begin
132
+ Convenient update of the dataset
133
+
134
+ A) Using PATCH
135
+
136
+ Previously changed attributes are saved to the database.
137
+
138
+ Using the optional »:set:« argument ad-hoc attributes can be defined
139
+ V.create_class :contracts
140
+ obj = Contracts.first
141
+ obj.name = 'new_name'
142
+ obj.update set: { yesterdays_event: 35 }
143
+ updates both, the »name« and the »yesterdays_event«-properties
144
+
145
+ B) Manual Modus
146
+
147
+ Update accepts a Block. The contents are parsed to »set«. Manual conversion of ruby-objects
148
+ to the database-input format is necessary
149
+
150
+ i.e.
151
+ hct is an Array of ActiveOrient::Model-records.
152
+ then
153
+ obj.update { "positions = #{hct.to_or} " }
154
+ translates to
155
+ update #83:64 set positions = [#90:18, #91:18, #92:18] return after @this
156
+ and returns the modified record.
157
+
158
+ The manual modus accepts the keyword »remove«.
159
+
160
+ obj.update(remove: true) { "positions = #{hct.first.to_or} " }
161
+ translates to
162
+ update #83:64 remove positions = #90:18 return after @this
163
+
164
+ This can be achieved by
165
+ obj.positions
166
+
167
+
168
+ If the update process is not successful, nil is returned
169
+ =end
170
+
171
+ def update set: {}, remove: {}, **args
172
+ logger.progname = 'ActiveOrient::Model#Update'
173
+ # query( kind: update, )
174
+ if block_given? # calling vs. a block is used internally
175
+ # to remove an Item from lists and sets call update(remove: true){ query }
176
+ set_or_remove = args[:remove].present? ? "remove" : "set"
177
+ #transfer_content from:
178
+ updated_record = db.execute{ "update #{rrid} #{ yield } return after $current" } &.first
179
+ transfer_content from: updated_record if updated_record.present?
180
+ else
181
+ set = if remove.present?
182
+ { remove: remove.merge!( args) }
183
+ elsif set.present?
184
+ set.merge!( args)
185
+ else
186
+ args
187
+ end
188
+ # set.merge updated_at: DateTime.now
189
+ if rid.rid?
190
+ q= query.kind(:update)
191
+ if remove.present?
192
+ q.remove(remove)
193
+ else
194
+ q.set(set)
195
+ end
196
+ transfer_content from: q.execute(reduce: true){ |y| y[:$current].reload! }
197
+ else # new record
198
+ self.attributes.merge! set
199
+ save
200
+ end
201
+ end
202
+ end
203
+
204
+ # mocking active record
205
+ def update_attribute the_attribute, the_value # :nodoc:
206
+ update the_attribute => the_value.to_or
207
+ end
208
+
209
+ def update_attributes **args # :nodoc:
210
+ update args
211
+ end
212
+
213
+ ########## SAVE ############
214
+
215
+ =begin
216
+ Saves the record by calling update or creating the record
217
+
218
+ ORD.create_class :a
219
+ a = A.new
220
+ a.test = 'test'
221
+ a.save
222
+
223
+ a = A.first
224
+ a.test = 'test'
225
+ a.save
226
+
227
+ =end
228
+ def save
229
+ transfer_content from: if rid.rid?
230
+ db.update self, attributes, version
231
+ else
232
+ db.create_record self, attributes: attributes, cache: false
233
+ end
234
+ ActiveOrient::Base.store_rid self
235
+ end
236
+
237
+ def reload!
238
+ transfer_content from: db.get_record(rid)
239
+ self
240
+ end
241
+
242
+
243
+ ########## CHECK PROPERTY ########
244
+
245
+ =begin
246
+ An Edge is defined
247
+ * when inherent from the superclass »E» (formal definition)
248
+ * if it has an in- and an out property
249
+
250
+ Actually we just check the second term as we trust the constructor to work properly
251
+ =end
252
+
253
+ def is_edge? # :nodoc:
254
+ attributes.keys.include?('in') && attributes.keys.include?('out')
255
+ end
256
+
257
+ =begin
258
+ How to handle other calls
259
+
260
+ * if attribute is specified, display it
261
+ * if attribute= is provided, assign to the known property or create a new one
262
+
263
+ Example:
264
+ ORD.create_class :a
265
+ a = A.new
266
+ a.test= 'test' # <--- attribute: 'test=', argument: 'test'
267
+ a.test # <--- attribute: 'test' --> fetch attributes[:test]
268
+
269
+ Assignments are performed only in ruby-space.
270
+
271
+ Automatic database-updates are deactivated for now
272
+ =end
273
+ def method_missing *args
274
+ # if the first entry of the parameter-array is a known attribute
275
+ # proceed with the assignment
276
+ if args.size == 1
277
+ attributes[args.first.to_sym] # return the attribute-value
278
+ elsif args[0][-1] == "="
279
+ if args.size == 2
280
+ # if rid.rid?
281
+ # update set:{ args[0][0..-2] => args.last }
282
+ # else
283
+ self.attributes[ args[0][0..-2] ] = args.last
284
+ # end
285
+ else
286
+ self.attributes[ args[0][0..-2] ] = args[1 .. -1]
287
+ # update set: {args[0][0..-2] => args[1 .. -1] } if rid.rid?
288
+ end
289
+ else
290
+ raise NameError, "Unknown method call #{args.first.to_s}", caller
291
+ end
292
+ end
293
+ #end
294
+
295
+ #protected
296
+ def transfer_content from:
297
+ # »from« can be either
298
+ # a model record (in case of create-record, get_record) or
299
+ # a hash containing {"@type"=>"d", "@rid"=>"#xx:yy", "@version"=>n, "@class"=>'a_classname'}
300
+ # and a list of updated properties (in case of db.update). Then update the version field and the
301
+ # attributes.
302
+ return nil if from.nil?
303
+ if from.is_a? ActiveOrient::Model
304
+ @metadata = from.metadata
305
+ self.attributes = from.attributes
306
+ else
307
+ self.version = from['@version']
308
+ # throw away from["@..."] and convert keys to symbols, finally merge to attributes
309
+ @attributes.merge! Hash[ from.delete_if{|k,_| k =~ /^@/}.map{|k,v| [k.to_sym, v.from_orient]}]
310
+ end
311
+ self # return the modified object
312
+ end
313
+ end
@@ -0,0 +1,371 @@
1
+ class V < ActiveOrient::Model
2
+ ## link to the library-class
3
+
4
+ =begin
5
+ specialized creation of vertices, overloads model#create
6
+
7
+ Vertex.create set: { a: 1, b: "2", c: :r }
8
+
9
+ or
10
+
11
+ Vertex.create a: 1, b: "2", c: :r
12
+
13
+ If a record cannot be created, because an index inhibits it, the original record is
14
+ silently loaded instead.
15
+ To avoid this behavior, call create_record and specify »silence: false«
16
+
17
+ =end
18
+ def self.create set: {}, **attributes
19
+ db.create_record self, attributes: set.merge(attributes)
20
+ # query.kind(:create).set( set.merge(attributes) ).execute(reduce: true)
21
+ end
22
+ =begin
23
+ Vertex.delete fires a "delete vertex" command to the database.
24
+
25
+ To remove all records of a class, use »all: true« as argument
26
+
27
+
28
+ The rid-cache is reset, too
29
+ =end
30
+ def self.delete where: {} , **args
31
+ if args[:all] == true
32
+ where = {}
33
+ else
34
+ where.merge!(args) if where.is_a?(Hash)
35
+ return 0 if where.empty?
36
+ end
37
+ # query returns [{count => n }]
38
+ count= db.execute { "delete vertex #{ref_name} #{db.compose_where(where)}" }.first[:count] rescue 0
39
+ reset_rid_store
40
+ count # return count of affected records
41
+ end
42
+
43
+
44
+ =begin
45
+ Creates a new Match-Statement
46
+ =end
47
+ def self.match **args
48
+ OrientSupport::MatchStatement.new self, **args
49
+ end
50
+
51
+ =begin
52
+ Performs a Where-Query on the vertex-class
53
+
54
+ The where-cause narrows the sample to certain records.
55
+
56
+ They are returned as OrientSupport::Array
57
+
58
+ Internally a match-query is fired.
59
+
60
+ To fire a »select from class where« query, use »Class.custom_where«.
61
+ =end
62
+
63
+
64
+ def self.where *attributes
65
+ query_database( match(where: attributes).compile ) { | record | record[classname.pluralize.to_sym] }
66
+ end
67
+
68
+ =begin
69
+ List edges
70
+
71
+ 1. call without any parameter: list all edges present
72
+ 2. call with :in or :out : list any incoming or outgoing edges
73
+ 3. call with /regexp/, Class, symbol or string: restrict to this edges, including inheritence
74
+ If a pattern, symbol string or class is provided, the default is to list outgoing edges
75
+
76
+ :call-seq:
77
+ edges in_or_out, pattern
78
+ =end
79
+ def edges *args
80
+ if args.empty?
81
+ detect_edges :both
82
+ else
83
+ kind = [:in, :out, :both, :all].detect{|x| args.include? x }
84
+ if kind.present?
85
+ args = args - [ kind ]
86
+ else
87
+ kind = :both
88
+ end
89
+ detect_edges kind, args.first
90
+
91
+ end
92
+ end
93
+
94
+ # Lists all connected Vertices
95
+ # ( returns a OrientSupport::Array )
96
+ #
97
+ # The Edge-classes can be specified via Classname or a regular expression.
98
+ #
99
+ # If a regular expression is used, the database-names are searched and inheritance is supported.
100
+ #
101
+ def nodes in_or_out = :out, via: nil, where: nil, expand: false
102
+ edges = detect_edges( in_or_out, via, expand: false )
103
+ return [] if edges.empty?
104
+ q = query # q.to_s => "select from #0x:0x "
105
+ edges = nil if via.nil?
106
+ q.nodes in_or_out, via: edges , where: where, expand: expand
107
+ detected_nodes= q.execute{| record | record.is_a?(Hash)? record.values.first : record }
108
+ end
109
+
110
+
111
+ # Returns a collection of all vertices passed during the traversal
112
+ #
113
+ # Includes the start_vertex (start_at =0 by default)
114
+ #
115
+ # If the vector should not include the start_vertex, call with `start_at:1` and increase the depth by 1
116
+ #
117
+ # fires a query
118
+ #
119
+ # select from ( traverse outE('}#{via}').in from #{vertex} while $depth < #{depth} )
120
+ # where $depth >= #{start_at}
121
+ #
122
+ # If » excecute: false « is specified, the traverse-statement is returned (as Orient-Query object)
123
+ def traverse in_or_out = :out, via: nil, depth: 1, execute: true, start_at: 0, where: nil
124
+
125
+ edges = detect_edges( in_or_out, via, expand: false)
126
+ the_query = query kind: 'traverse'
127
+ the_query.where where if where.present?
128
+ the_query.while "$depth < #{depth} " unless depth <=0
129
+ edges.each{ |ec| the_query.nodes in_or_out, via: ec, expand: false }
130
+ outer_query = OrientSupport::OrientQuery.new from: the_query, where: "$depth >= #{start_at}"
131
+ if execute
132
+ outer_query.execute
133
+ else
134
+ # the_query.from self # complete the query by assigning self
135
+ the_query # returns the OrientQuery -traverse object
136
+ end
137
+ end
138
+
139
+
140
+
141
+ =begin
142
+ Assigns another Vertex via an EdgeClass. If specified, puts attributes on the edge.
143
+
144
+ Wrapper for
145
+ Edge.create in: self, out: a_vertex, attributes: { some_attributes on the edge }
146
+
147
+ returns the assigned vertex, thus enabling to chain vertices through
148
+
149
+ Vertex.assign() via: E , vertex: VertexClass.create()).assign( via: E, ... )
150
+ or
151
+ (1..100).each{|n| vertex = vertex.assign(via: E2, vertex: V2.create(item: n))}
152
+ =end
153
+
154
+ def assign vertex: , via: E , attributes: {}
155
+
156
+ via.create from: self, to: vertex, set: attributes
157
+
158
+ vertex
159
+ end
160
+
161
+ ## Optimisation (not implemented jet)
162
+ #
163
+ # "LET $a = CREATE VERTEX VTest SET name = 'John';" +
164
+ # "CREATE EDGE ETest FROM :ParentRID TO $a;" +
165
+ # "RETURN $a;", params)
166
+
167
+
168
+
169
+
170
+ =begin
171
+ »in« and »out« provide the main access to edges.
172
+
173
+ »in» is a reserved keyword. Therefor its only an alias to `in_e`.
174
+
175
+ If called without a parameter, all connected edges are retrieved.
176
+
177
+ If called with a string, symbol or class, the edge-class is resolved and even inherent
178
+ edges are retrieved.
179
+
180
+ =end
181
+
182
+ def in_e edge_name= nil
183
+ detect_edges :in, edge_name
184
+ end
185
+
186
+ alias_method :in, :in_e
187
+
188
+ def out edge_name = nil
189
+ detect_edges :out, edge_name
190
+ end
191
+ =begin
192
+ Retrieves connected edges
193
+
194
+ The basic usage is to fetch all/ incoming/ outgoing edges
195
+
196
+ Model-Instance.edges :in :out | :both, :all
197
+
198
+ One can filter specific edges by providing parts of the edge-name
199
+
200
+ Model-Instance.edges /sector/, :in
201
+ Model-Instance.edges :out, /sector/
202
+ Model-Instance.edges /sector/
203
+ Model-Instance.edges :in
204
+
205
+
206
+
207
+ The method returns an array of expands edges.
208
+
209
+ »in_edges« and »out_edges« are shortcuts to »edges :in« and »edges :out«
210
+
211
+ Its easy to expand the result:
212
+ tg.out( :ohlc).out.out_edges
213
+ => [["#102:11032", "#121:0"]]
214
+ tg.out( :ohlc).out.out_edges.from_orient
215
+ => [[#<TG::GRID_OF:0x00000002620e38
216
+
217
+ this displays the out-edges correctly
218
+
219
+ whereas
220
+ tg.out( :ohlc).out.edges( :out)
221
+ => [["#101:11032", "#102:11032", "#94:10653", "#121:0"]]
222
+
223
+ returns all edges. The parameter (:out) is not recognized, because out is already a nested array.
224
+
225
+ this
226
+ tg.out( :ohlc).first.out.edges( :out)
227
+ is a workaround, but using in_- and out_edges is more elegant.
228
+ =end
229
+ def in_edges
230
+ edges :in
231
+ end
232
+ def out_edges
233
+ edges :out
234
+ end
235
+
236
+ # def remove
237
+ # db.delete_vertex self
238
+ # end
239
+ =begin
240
+ Human readable representation of Vertices
241
+
242
+ Format: < Classname: Edges, Attributes >
243
+ =end
244
+ def to_human
245
+ count_and_display_classes = ->(array){array.map(&:class)&.group_by(&:itself)&.transform_values(&:count)}
246
+
247
+ the_ins = count_and_display_classes[ in_e]
248
+ the_outs = count_and_display_classes[ out]
249
+
250
+ in_and_out = in_edges.empty? ? "" : "in: #{the_ins}, "
251
+ in_and_out += out_edges.empty? ? "" : "out: #{the_outs}, "
252
+
253
+
254
+ #Default presentation of ActiveOrient::Model-Objects
255
+
256
+ "<#{self.class.to_s.demodulize}[#{rid}]: " + in_and_out + content_attributes.map do |attr, value|
257
+ v= case value
258
+ when ActiveOrient::Model
259
+ "< #{self.class.to_s.demodulize}: #{value.rid} >"
260
+ when OrientSupport::Array
261
+ value.to_s
262
+ # value.rrid #.to_human #.map(&:to_human).join("::")
263
+ else
264
+ value.from_orient
265
+ end
266
+ "%s : %s" % [ attr, v] unless v.nil?
267
+ end.compact.sort.join(', ') + ">".gsub('"' , ' ')
268
+ end
269
+
270
+
271
+
272
+
273
+
274
+ #protected
275
+ #Present Classes (Hierarchy)
276
+ #---
277
+ #- - E
278
+ # - - - e1
279
+ # - - e2
280
+ # - e3
281
+ #- - V
282
+ # - - - v1
283
+ # - - v2
284
+
285
+ # v.to_human
286
+ # => "<V2[#36:0]: in: {E2=>1}, node : 4>"
287
+ #
288
+ # v.detect_edges( :in, 2).to_human
289
+ # => ["<E2: in : #<V2:0x0000000002e66228>, out : #<V1:0x0000000002ed0060>>"]
290
+ # v.detect_edges( :in, E1).to_human
291
+ # => ["<E2: in : #<V2:0x0000000002e66228>, out : #<V1:0x0000000002ed0060>>"]
292
+ # v.detect_edges( :in, /e/).to_human
293
+ # => ["<E2: in : #<V2:0x0000000002e66228>, out : #<V1:0x0000000002ed0060>>"]
294
+ #
295
+ #
296
+ # returns a OrientSupport::Array
297
+ def detect_edges kind = :in, edge_name = nil, expand: true #:nodoc:
298
+ ## returns a list of inherent DD classes
299
+ get_superclass = ->(e) do
300
+ if [nil,"", "e", "E", E, :e, :E ].include?(e)
301
+ "E"
302
+ else
303
+ n = orientdb.get_db_superclass(e)
304
+ n =='E' ? e : e + ',' + get_superclass[n]
305
+ end
306
+ end
307
+
308
+ expression = case kind
309
+ when :in
310
+ /^in_/
311
+ when :out
312
+ /^out_/
313
+ else
314
+ /^in_|^out_/
315
+ end
316
+
317
+ extract_database_class = ->(c){ y = c.to_s.gsub(expression, ''); y.empty? ? "E": y }
318
+ result, the_edges = [] # we have to declare result prior to its usage in the loop to make
319
+ # its content robust
320
+ attempt = 0
321
+ loop do
322
+ # get a set of available edge-names
323
+ # in_{abc} and out_{abc}
324
+ # with "out_" and "in_" as placeholder for E itself
325
+ # populate result in case no further action is required
326
+ result = the_edges = attributes.keys.find_all{ |x| x =~ expression }
327
+ # eager reloading
328
+ if result.empty? && attempt.zero?
329
+ reload!
330
+ attempt = 1
331
+ else
332
+ break
333
+ end
334
+ end
335
+
336
+ if edge_name.present?
337
+ # if a class is provided, match for the ref_name only
338
+ if edge_name.is_a?(Class)
339
+ result = [ the_edges.detect{ |x| edge_name.ref_name == extract_database_class[x] } ]
340
+ else
341
+ e_name = if edge_name.is_a?(Regexp)
342
+ edge_name
343
+ else
344
+ Regexp.new case edge_name
345
+ # when Class
346
+ # edge_name.ref_name
347
+ when String
348
+ edge_name
349
+ when Symbol
350
+ edge_name.to_s
351
+ when Numeric
352
+ edge_name.to_i.to_s
353
+ end
354
+ end
355
+ result = the_edges.find_all do |x|
356
+ get_superclass[extract_database_class[x] ].split(',').detect{|x| x =~ e_name }
357
+ end
358
+ end
359
+ end
360
+ # if expand = false , return the orientdb database name of the edges
361
+ # this is used by Vertex#nodes
362
+ # it avoids communications with the database prior to submitting the nodes-query
363
+ # if expand = true (default) load the edges instead
364
+ if expand
365
+ OrientSupport::Array.new work_on: self,
366
+ work_with: result.compact.map{|x| attributes[x]}.map(&:expand).orient_flatten
367
+ else
368
+ result.map{|x| extract_database_class[x] }
369
+ end
370
+ end
371
+ end