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