Class: V

Inherits:
ActiveOrient::Model show all
Defined in:
lib/model/vertex.rb

Constant Summary

Constants included from OrientDB

OrientDB::DocumentDatabase, OrientDB::DocumentDatabasePool, OrientDB::DocumentDatabasePooled, OrientDB::GraphDatabase, OrientDB::IndexType, OrientDB::OClassImpl, OrientDB::OTraverse, OrientDB::PropertyImpl, OrientDB::RemoteStorage, OrientDB::SQLCommand, OrientDB::SQLSynchQuery, OrientDB::Schema, OrientDB::SchemaProxy, OrientDB::SchemaType, OrientDB::ServerAdmin, OrientDB::User, OrientDB::UsingJava

Instance Attribute Summary

Attributes inherited from ActiveOrient::Model

#metadata

Attributes inherited from ActiveOrient::Base

#metadata

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from ActiveOrient::Model

_to_partial_path, autoload_object, delete_class, #document, #persisted?, #to_ary, to_or, use_or_allocate

Methods included from CustomClass

#like

Methods included from ModelClass

#add_edge_link, #all, #alter_property, #classname, #count, #create, #create_class, #create_index, #create_properties, #create_property, #delete_property, #delete_record, #delete_records, #first, #get, #get_records, #indexes, #last, #link_list, #migrate_property, #namespace_prefix, #naming_convention, #orientdb_class, #print_properties, #properties, #query, #query_database, #require_model_file, #update, #update!, #upsert, #where

Methods included from OrientSupport::Support

#as, #compose_where, #generate_sql_list, #where, #while_s

Methods included from ModelRecord

classname, #delete, #find, #from_orient, #has_property?, #is_edge?, #method_missing, #properties, #query, #reload!, #rid, #rrid, #save, #to_or, #to_s, #transfer_content, #update, #update_attribute, #update_attributes, #version

Methods included from ActiveOrient::BaseProperties

#==, #content_attributes, #default_attributes, #embedded, #set_attribute_defaults, #update_missing

Methods inherited from ActiveOrient::Base

#[], #[]=, attr_accessible, attr_protected, #attributes, #attributes=, belongs_to, display_rid, exclude_the_following_properties, get_rid, has_many, has_one, #included_links, #initialize, #my_metadata, remove_rid, reset_rid_store, serialize, store_rid, #to_model, #update_attribute

Methods included from Conversions

#to_key, #to_param, #to_partial_path

Constructor Details

This class inherits a constructor from ActiveOrient::Base

Dynamic Method Handling

This class handles dynamic methods through the method_missing method in the class ModelRecord

Class Method Details

.create(set: {}, **attributes) ⇒ Object

specialized creation of vertices, overloads model#create

Vertex.create set: { a: 1, b: "2", c: :r }

or

Vertex.create  a: 1, b: "2", c: :r

If a record cannot be created, because an index inhibits it, the original record is silently loaded instead. To avoid this behavior, call create_record and specify »silence: false«



18
19
20
21
# File 'lib/model/vertex.rb', line 18

def self.create set: {},  **attributes
db.create_record self, attributes: set.merge(attributes)
  #  query.kind(:create).set( set.merge(attributes) ).execute(reduce: true)
end

.delete(where: {}, **args) ⇒ Object

Vertex.delete fires a “delete vertex” command to the database.

To remove all records of a class, use »all: true« as argument

The rid-cache is reset, too



30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/model/vertex.rb', line 30

def self.delete where: {} , **args
if args[:all] == true 
  where = {}
else
  where.merge!(args) if where.is_a?(Hash)
  return 0 if where.empty?
end
# query returns [{count => n }]
count= db.execute { "delete vertex #{ref_name} #{db.compose_where(where)}" }.first[:count] rescue 0
  reset_rid_store
count #  return count of affected records
end

.match(**args) ⇒ Object

Creates a new Match-Statement



47
48
49
# File 'lib/model/vertex.rb', line 47

def self.match  **args
  OrientSupport::MatchStatement.new self,  **args
end

.where(*attributes) ⇒ Object



64
65
66
# File 'lib/model/vertex.rb', line 64

def self.where *attributes 
    query_database( match(where: attributes).compile ) { | record | record[classname.pluralize.to_sym] }
end

Instance Method Details

#assign(vertex:, via: E, attributes: {}) ⇒ Object

Assigns another Vertex via an EdgeClass. If specified, puts attributes on the edge.

Wrapper for

Edge.create in: self, out: a_vertex, attributes: { some_attributes on the edge }

returns the assigned vertex, thus enabling to chain vertices through

Vertex.assign() via: E , vertex: VertexClass.create()).assign( via: E, ... )

or (1..100).each{|n| vertex = vertex.assign(via: E2, vertex: V2.create(item: n))}



154
155
156
157
158
159
# File 'lib/model/vertex.rb', line 154

def assign vertex: , via: E , attributes: {}

  via.create from: self, to: vertex, set: attributes
  
vertex
end

#detect_edges(kind = :in, edge_name = nil, expand: true) ⇒ Object

v.to_human

> “<V2: in: E2=>1, node : 4>”

v.detect_edges( :in, 2).to_human

> [“<E2: in : #<V2:0x0000000002e66228>, out : #<V1:0x0000000002ed0060>>”]

v.detect_edges( :in, E1).to_human

> [“<E2: in : #<V2:0x0000000002e66228>, out : #<V1:0x0000000002ed0060>>”]

v.detect_edges( :in, /e/).to_human

> [“<E2: in : #<V2:0x0000000002e66228>, out : #<V1:0x0000000002ed0060>>”]

returns a OrientSupport::Array


297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
# File 'lib/model/vertex.rb', line 297

def detect_edges kind = :in,  edge_name = nil, expand: true  #:nodoc:
  ## returns a list of inherent DD classes
  get_superclass = ->(e) do
    if [nil,"", "e", "E", E, :e, :E ].include?(e)
      "E"
    else
      n = orientdb.get_db_superclass(e)
      n =='E' ? e : e + ',' + get_superclass[n]
    end
  end

  expression = case kind
               when :in
                 /^in_/ 
               when :out
                 /^out_/
               else
                 /^in_|^out_/ 
               end

  extract_database_class = ->(c){ y =  c.to_s.gsub(expression, ''); y.empty? ? "E": y   }
  result, the_edges  = []   #  we have to declare result prior to its usage in the loop to make
                            #  its content robust 
  attempt =  0
  loop do
    # get a set of available edge-names 
    # in_{abc} and out_{abc}
    # with "out_" and "in_" as placeholder for E itself
    # populate result in case no further action is required
    result = the_edges = attributes.keys.find_all{ |x|  x =~  expression }
    # eager reloading
    if result.empty? && attempt.zero?
      reload!
      attempt = 1
    else
      break
    end
  end

  if edge_name.present?
    # if a class is provided, match for the ref_name only
    if edge_name.is_a?(Class) 
      result = [ the_edges.detect{ |x| edge_name.ref_name == extract_database_class[x] } ]
    else
      e_name = if edge_name.is_a?(Regexp)
                 edge_name
               else
                 Regexp.new  case  edge_name
                                     #         when  Class
                                     #           edge_name.ref_name 
                                   when String
                                     edge_name
                                   when Symbol
                                     edge_name.to_s 
                                   when Numeric
                                     edge_name.to_i.to_s
                                   end
              end  
      result = the_edges.find_all do |x|
        get_superclass[extract_database_class[x] ].split(',').detect{|x| x =~ e_name } 
      end
    end
  end
  # if expand = false , return the orientdb database name of the edges
  #  this is used by  Vertex#nodes 
  #  it avoids communications with the database prior to submitting the nodes-query
  # if expand = true (default) load the edges instead
  if expand
    OrientSupport::Array.new work_on: self, 
      work_with:   result.compact.map{|x| attributes[x]}.map(&:expand).orient_flatten
  else
    result.map{|x|  extract_database_class[x] }
  end
end

#edges(*args) ⇒ Object

List edges

  1. call without any parameter: list all edges present

  2. call with :in or :out : list any incoming or outgoing edges

  3. call with /regexp/, Class, symbol or string: restrict to this edges, including inheritence If a pattern, symbol string or class is provided, the default is to list outgoing edges

:call-seq:
edges in_or_out, pattern


79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/model/vertex.rb', line 79

def edges *args
  if args.empty?
    detect_edges  :both
  else
    kind =   [:in, :out, :both, :all].detect{|x|  args.include? x }
    if kind.present?
      args =  args - [ kind ]
    else
      kind = :both
    end
    detect_edges  kind, args.first

  end
end

#in_e(edge_name = nil) ⇒ Object Also known as: in

»in« and »out« provide the main access to edges.

»in» is a reserved keyword. Therefor its only an alias to ‘in_e`.

If called without a parameter, all connected edges are retrieved.

If called with a string, symbol or class, the edge-class is resolved and even inherent edges are retrieved.



182
183
184
# File 'lib/model/vertex.rb', line 182

def in_e edge_name= nil
  detect_edges :in, edge_name
end

#in_edgesObject

Retrieves connected edges

The basic usage is to fetch all/ incoming/ outgoing edges

Model-Instance.edges :in  :out | :both, :all

One can filter specific edges by providing parts of the edge-name

Model-Instance.edges /sector/, :in
Model-Instance.edges :out, /sector/
Model-Instance.edges  /sector/
Model-Instance.edges  :in

The method returns an array of expands edges.

»in_edges« and »out_edges« are shortcuts to »edges :in« and »edges :out«

Its easy to expand the result:

tg.out( :ohlc).out.out_edges
 => [["#102:11032", "#121:0"]] 
 tg.out( :ohlc).out.out_edges.from_orient
 => [[#<TG::GRID_OF:0x00000002620e38

this displays the out-edges correctly

whereas tg.out( :ohlc).out.edges( :out)

=> [["#101:11032", "#102:11032", "#94:10653", "#121:0"]]

returns all edges. The parameter (:out) is not recognized, because out is already a nested array.

this

tg.out( :ohlc).first.out.edges( :out)

is a workaround, but using in_- and out_edges is more elegant.



229
230
231
# File 'lib/model/vertex.rb', line 229

def in_edges
  edges :in
end

#nodes(in_or_out = :out, via: nil, where: nil, expand: false) ⇒ Object

The Edge-classes can be specified via Classname or a regular expression.

If a regular expression is used, the database-names are searched and inheritance is supported.



101
102
103
104
105
106
107
108
# File 'lib/model/vertex.rb', line 101

def nodes in_or_out = :out, via:  nil, where: nil, expand:  false
    edges =  detect_edges( in_or_out, via, expand: false )
    return [] if edges.empty?
    q = query     # q.to_s  => "select from #0x:0x "
    edges = nil if via.nil?
    q.nodes in_or_out, via:  edges , where: where, expand: expand
    detected_nodes= q.execute{| record | record.is_a?(Hash)?  record.values.first : record  }
end

#out(edge_name = nil) ⇒ Object



188
189
190
# File 'lib/model/vertex.rb', line 188

def out edge_name =  nil
  detect_edges :out, edge_name
end

#out_edgesObject



232
233
234
# File 'lib/model/vertex.rb', line 232

def out_edges
  edges :out
end

#to_humanObject

Human readable representation of Vertices

Format: < Classname: Edges, Attributes >



244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
# File 'lib/model/vertex.rb', line 244

def to_human
  count_and_display_classes = ->(array){array.map(&:class)&.group_by(&:itself)&.transform_values(&:count)} 

  the_ins =    count_and_display_classes[ in_e] 
  the_outs =  count_and_display_classes[ out]

  in_and_out = in_edges.empty? ? "" : "in: #{the_ins}, " 
  in_and_out += out_edges.empty? ? "" : "out: #{the_outs}, " 


  #Default presentation of ActiveOrient::Model-Objects

  "<#{self.class.to_s.demodulize}[#{rid}]: " + in_and_out  + content_attributes.map do |attr, value|
    v= case value
       when ActiveOrient::Model
         "< #{self.class.to_s.demodulize}: #{value.rid} >"
       when OrientSupport::Array
         value.to_s
#          value.rrid #.to_human #.map(&:to_human).join("::")
       else
         value.from_orient
       end
    "%s : %s" % [ attr, v]  unless v.nil?
  end.compact.sort.join(', ') + ">".gsub('"' , ' ')
end

#traverse(in_or_out = :out, via: nil, depth: 1, execute: true, start_at: 0, where: nil) ⇒ Object

Returns a collection of all vertices passed during the traversal

Includes the start_vertex (start_at =0 by default)

If the vector should not include the start_vertex, call with ‘start_at:1` and increase the depth by 1

fires a query

select  from  ( traverse  outE('}#{via}').in  from #{vertex}  while $depth < #{depth}   ) 
        where $depth >= #{start_at}

If » excecute: false « is specified, the traverse-statement is returned (as Orient-Query object)



123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/model/vertex.rb', line 123

def traverse in_or_out = :out, via: nil,  depth: 1, execute: true, start_at: 0, where: nil

  edges = detect_edges( in_or_out, via, expand: false)
  the_query = query kind: 'traverse' 
  the_query.where where if where.present?
  the_query.while "$depth < #{depth} " unless depth <=0
  edges.each{ |ec| the_query.nodes in_or_out, via: ec, expand: false }
  outer_query = OrientSupport::OrientQuery.new from: the_query, where: "$depth >= #{start_at}"
  if execute 
     outer_query.execute
    else
#     the_query.from self  #  complete the query by assigning self 
      the_query            #  returns the OrientQuery  -traverse object
    end
end