Class: ActiveOrient::Model

Inherits:
Base
  • Object
show all
Includes:
BaseProperties
Defined in:
lib/model.rb

Overview

require ‘base’ require ‘base_properties’

Direct Known Subclasses

Query

Class Method Summary collapse

Instance Method Summary collapse

Methods included from BaseProperties

#==, #content_attributes, #default_attributes, #set_attribute_defaults, #to_human, #update_missing

Methods inherited from Base

#[], #[]=, attr_accessible, attr_protected, #attributes, #attributes=, belongs_to, display_riid, find, get_riid, has_many, has_one, #initialize, remove_riid, serialize, store_riid, #to_model, #update_attribute

Constructor Details

This class inherits a constructor from ActiveOrient::Base

Class Method Details

.allObject



322
323
324
# File 'lib/model.rb', line 322

def self.all
     orientdb.get_documents from: self 
end

.autoload_object(link) ⇒ Object

ActiveOrient::Model.autoload_object “#00:00” either retrieves the object from the rid_store or loads it from the DB

the rid_store is updated!

to_do: fetch for version in the db and load the object if a change is detected



51
52
53
54
55
# File 'lib/model.rb', line 51

def self.autoload_object   link
#     puts "autoload_object #{link}"
  link_cluster_and_record = link[1,link.size].split(':').map &:to_i
  @@rid_store[link_cluster_and_record].presence || orientdb.get_document( link ) 
end

.count(**args) ⇒ Object

Queries the database and fetches the count of datasets

Any parameter that qualifies a database-query is suppoerted (see method get_documents)



131
132
133
# File 'lib/model.rb', line 131

def self.count **args
  orientdb.count_documents from: self , **args
end

.create(properties = {}) ⇒ Object

Creates a new Instance of the Class with the applied attributes and returns the freshly instantiated Object



139
140
141
# File 'lib/model.rb', line 139

def self.create properties = {}
   orientdb.create_or_update_document  self, set: properties
end

.create_edge(**keyword_arguments) ⇒ Object

Only if the Class inherents from »E« Instantiate a new Edge betwen two Vertices

Parameter: unique: (true) In case of an existing Edge just update its Properties. The parameters »from« and »to« can take a list of model-records. Then subsequent edges are created.

:call-seq: 
 self.create_edge from: , to: , unique: false, attributes:{}


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

def self.create_edge **keyword_arguments 
   o=orientdb.nexus_edge  self, **keyword_arguments 
   [:from,:to].each{|y| keyword_arguments[y].is_a?(Array) ? keyword_arguments[y].each( &:reload! ):  keyword_arguments[y].reload! }
   o  # return_value
end


173
174
175
# File 'lib/model.rb', line 173

def self.create_link name, class_name
  orientdb.create_property self,  name, type: 'link', linked_class: class_name
end

.create_linkset(name, class_name) ⇒ Object



176
177
178
# File 'lib/model.rb', line 176

def self.create_linkset name, class_name
  orientdb.create_property self,  name, type: 'linkset', linked_class: class_name
end

.create_properties(argument_hash, &b) ⇒ Object



169
170
171
# File 'lib/model.rb', line 169

def self.create_properties argument_hash, &b
  orientdb.create_properties self, argument_hash, &b
end

.create_property(field, **keyword_arguments, &b) ⇒ Object



165
166
167
# File 'lib/model.rb', line 165

def self.create_property field, **keyword_arguments, &b
  orientdb.create_property  self, field,  **keyword_arguments, &b
end

.first(where: {}) ⇒ Object



325
326
327
# File 'lib/model.rb', line 325

def self.first where: {}
  orientdb.get_documents(  from: self, where: where, limit: 1).pop
end

.get(rid) ⇒ Object

get enables loading of datasets if a link is followed

model_class.all.first.link.get


319
320
321
# File 'lib/model.rb', line 319

def self.get rid
  orientdb.get_document rid
end

.get_documents(**args) ⇒ Object

Parameter projection:

»select« is a method of enumeration, we use »projection:« to specify anything between »select« and »from«in the query-string.

projection:  a_string -->  inserts the sting as it appears

an OrientSupport::OrientQuery-Object –> performs a sub-query and uses the result for further querying though the given parameters. [ a, b, c ] –> “a , b , c ” ( inserts a comma-separated list )

{ a: b, “sum(x) ”=> f } –> “a as b, sum(x) as f” (renames properties and uses functions ) Parameter distinct:

Performs a Query like » select distinct( property ) [ as property ] from …«

distinct: :property               -->  the result is mapped to the property »distinct«.

          [ :property ]           -->  the result replaces the property

{ property: :some_name} –> the result is mapped to ModelInstance.some_name

Parameter Order

Sorts the result-set.

If new properties are introduced via select:, distinct: etc

Sorting takes place on these properties

order: :property
       { property: asc, property: desc }
       [property, property, ..  ]  ( orderdirection is 'asc' )

Further supported Parameter:

group_by
skip
limit
unwind

see orientdb- documentation (orientdb.com/docs/last/SQL-Query.html)

Parameter query: Instead of providing the parameter, the OrientSupport::OrientQuery can build and tested before the method-call. The OrientQuery-Object can be provided with the query-parameter i.e.

q=  OrientSupport::OrientQuery.new
TestModel =  r.open_class 'test_model'
q.from TestModel
q.where { name: 'Thomas' }

count= TestModel.count query:q
q.limit 10
0.step(count,10) do |x|
  q.skip = x
  puts TestModel.get_documents( query: q ).map{|x| x.adress }.join('\t')
end

prints a Table with 10 columns.



271
272
273
274
# File 'lib/model.rb', line 271

def self.get_documents **args 
  orientdb.get_documents( from: self,  **args ){ self }
 
end

.get_propertiesObject

Create a Property in the Schema of the Class

:call-seq: 
 self.create_property(  field (required) , type: 'string', linked_class: nil, index: nil)  do

index end



160
161
162
163
# File 'lib/model.rb', line 160

def self.get_properties 
  object =  orientdb.get_class_properties self
  {:properties => object['properties'] , :indexes => object['indexes'] }
end

.last(where: {}) ⇒ Object



329
330
331
332
# File 'lib/model.rb', line 329

def self.last where: {}
  #  debug:: orientdb.get_documents( self, order: { "@rid" => 'desc' }, limit: 1 ){ |x| puts x }.pop
  orientdb.get_documents( from: self, where: where,  order: { "@rid" => 'desc' }, limit: 1 ).pop
end

.new_document(attributes: {}) ⇒ Object

historic method



149
150
151
# File 'lib/model.rb', line 149

def self.new_document attributes: {}  # :nodoc:
   orientdb.create_or_update_document  self, set: attributes
end

.orientdb_class(name:) ⇒ Object

orientdb_class is used to instantiate a ActiveOrient:Model:class by providing its name todo: implement object-inherence



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

def self.orientdb_class name: 
  klass = Class.new( self )
  name =  name.to_s.camelize
  if self.send :const_defined?, name 
    retrieved_class =  self.send :const_get, name
  else
	new_class = self.send :const_set  , name , klass
	new_class.orientdb =  orientdb
	new_class # return_value
  end
rescue NameError => e
 logger.error "Model:: Class name cannot be initialized"
 puts "klass: #{klass.inspect}"
 puts "name : #{name.inspect}" 
 puts e.inspect
end

.query_database(query, set_from: true) ⇒ Object

QueryDatabase sends the Query, direct to the database. The result is not nessessary a Object of self. However, if the query does not return an array of Active::Model-Objects, then the entries become self



198
199
200
201
202
203
204
# File 'lib/model.rb', line 198

def self.query_database query, set_from: true
  query.from self if set_from && query.is_a?( OrientSupport::OrientQuery ) && query.from.nil? 
  sql_cmd = -> (command) { { type: "cmd", language: "sql", command: command } }
  orientdb.execute( self.to_s.split(':')[-1] ) do
    [ sql_cmd[ query.to_s ] ]
  end 
end

.superClassObject



58
59
60
61
# File 'lib/model.rb', line 58

def self.superClass
  orientdb.get_classes( 'name', 'superClass').detect{|x| x["name"].downcase ==  new.class.to_s.downcase.split(':')[-1].to_s
  }['superClass']
end

.update_or_create(set: {}, where: {}, **args, &b) ⇒ Object



143
144
145
146
# File 'lib/model.rb', line 143

def self.update_or_create set: {}, where:{} ,**args, &b
	orientdb.update_or_create_documents self , set: set,  where: where , **args , &b  

end

.where(attributes = {}) ⇒ Object

Performs a query on the Class and returns an Array of ActiveOrient:Model-Records.

Example:

Log =  r.open_class 'Log'
Log.where priority: 'high'
--> submited database-request: query/hc_database/sql/select from Log where priority = 'high'/-1
=> [ #<ActiveOrient::Model::Log:0x0000000480f7d8 @metadata={ ... },  ... ]


286
287
288
289
# File 'lib/model.rb', line 286

def self.where attributes =  {}
  q = OrientSupport::OrientQuery.new where: attributes
  query_database q 
end

Instance Method Details

#add_item_to_property(array, item = nil) ⇒ Object Also known as: add_items_to_property, update_linkset, update_embedded

Convient method for populating embedded- or linkset-properties

In both cases an array/ a collection is stored in the database.

its called via

model.add_item_to_property( linkset- or embedded property, Object_to_be_linked_to )

or

mode.add_items_to_property( linkset- or embedded property ) do
    Array_of_Objects_to_be_linked_to
    (actually, the objects must inherent from ActiveOrient::Model, Numeric, String)
end

to_do:  use "<<" to add the item to the property


412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
# File 'lib/model.rb', line 412

def add_item_to_property array, item=nil
  logger.progname = 'ActiveOrient::Model#AddItem2Property'
  execute_array =  Array.new
  self.attributes[array] = Array.new unless attributes[array].present?
  add_2_execute_array = -> (it) do
    case it
    when ActiveOrient::Model
	 execute_array <<  {type: "cmd", language: "sql", command: "update #{link} add #{array} = #{it.link}"} 
    when String
execute_array <<  {type: "cmd", language: "sql", command: "update #{link} add #{array} = '#{it}'"} 
    when Numeric
execute_array <<  {type: "cmd", language: "sql", command: "update #{link} add #{array} = #{it}"} 
    else
	 logger.error { "Only Basic Formats supported . Cannot Serialize #{it.class} this way" }
	 logger.error { "Try to load the array from the DB, modify it and update the hole record" }
    end
  end

  if block_given?
    items =  yield
    items.each{|x| add_2_execute_array[x];   self.attributes[array] << x }
  elsif item.present?
    add_2_execute_array[item]
    self.attributes[array] << item
  end
  orientdb.execute do
    execute_array
  end
  reload!

rescue RestClient::InternalServerError => e
  logger.error " Duplicate found in #{array} "
  logger.error e.inspect
end

#classnameObject

Returns just the name of the Class



72
73
74
# File 'lib/model.rb', line 72

def classname
   self.class.to_s.split(':')[-1]
end

#deleteObject

removes the Model-Instance from the database

returns true (successfully deleted) or false ( obj not deleted)



296
297
298
299
300
301
302
303
304
305
306
# File 'lib/model.rb', line 296

def delete
  
  r= if is_edge?
    # returns the count of deleted edges
    orientdb.delete_edge rid
  else
   orientdb.delete_document  rid
  end
  ActiveOrient::Base.remove_riid self if r # removes the obj from the rid_store
  r # true or false 
end

#from_orientObject



66
67
68
# File 'lib/model.rb', line 66

def from_orient
  self
end

#is_edge?Boolean

An Edge is defined

  • when inherented from the superclass »E» (formal definition)

  • if it has an in- and an out property

Actually we just check the second term as we trust the constuctor to work properly

Returns:

  • (Boolean)


314
315
316
# File 'lib/model.rb', line 314

def is_edge?
  attributes.keys.include?( 'in') && attributes.keys.include?('out')
end

link is used in any sql-commands eg . update #link set …



106
107
108
# File 'lib/model.rb', line 106

def link
  "##{rid}"
end

#nested_under_indifferent_accessObject

If a Rest::Model-Object is included in a HashWidhtIndifferentAccess-Object, only the link is stored



79
80
81
# File 'lib/model.rb', line 79

def nested_under_indifferent_access # :nodoc:
           link
end

#query(q) ⇒ Object



205
206
207
208
209
# File 'lib/model.rb', line 205

def query  q 
  a= ActiveOrient::Query.new 
  a.queries << q
  a.execute_queries
end

#reload!(updated_dataset = nil) ⇒ Object

Overwrite the attributes with Database-Contents (or attributes provided by the updated_dataset.model-instance)



354
355
356
357
358
359
# File 'lib/model.rb', line 354

def reload!  updated_dataset=nil
  updated_dataset = orientdb.get_document( link) if updated_dataset.nil?
  @metadata[:version]= updated_dataset.version
  attributes = updated_dataset.attributes
  self  # return_value  (otherwise only the attributes would be returned)
end

#remove_item_from_property(array, item = nil) ⇒ Object



361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
# File 'lib/model.rb', line 361

def remove_item_from_property array, item=nil
  logger.progname = 'ActiveOrient::Model#RemoveItemFromProperty'
  execute_array =  Array.new
  return unless attributes.has_key? array
  remove_execute_array = -> (it) do
    case it
    when ActiveOrient::Model
	 execute_array <<  {type: "cmd", language: "sql", command: "update #{link} remove #{array} = #{it.link}"} 
    when String
execute_array <<  {type: "cmd", language: "sql", command: "update #{link} remove #{array} = '#{it}'"} 
    when Numeric
execute_array <<  {type: "cmd", language: "sql", command: "update #{link} remove #{array} = #{it}"} 
    else
	 logger.error { "Only Basic Formats supported . Cannot Serialize #{it.class} this way" }
	 logger.error { "Try to load the array from the DB, modify it and update the hole record" }
    end
  end

  if block_given?
    items =  yield
    items.each{|x| remove_execute_array[x];   self.attributes[array].delete( x ) }
  elsif item.present?
    remove_execute_array[item]
    a= attributes; a.delete item
    self.attributes[array].delete( item )
  end
  orientdb.execute do
    execute_array
  end
  reload!

rescue RestClient::InternalServerError => e
  logger.error " Could not remove item in #{array} "
  logger.error e.inspect
end

#ridObject

rid is used in the where-part of sql-queries



97
98
99
100
101
# File 'lib/model.rb', line 97

def rid
    "#{@metadata[ :cluster ]}:#{@metadata[ :record ]}"
rescue 
    "0:0"
end

#riidObject

def default_attributes

  super.merge cluster: 0
  super.merge version: 0
  super.merge record: 0
end


91
92
93
# File 'lib/model.rb', line 91

def riid # :nodoc:
    [ @metadata[ :cluster ] , @metadata[ :record ] ]
end

#to_orientObject



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

def to_orient
  link
end

#update(set: {}) ⇒ Object

Convient update of the dataset by calling sql-patch The attributes are saved to the database. With the optional :set argument ad-hoc attributes can be defined

obj = ActiveOrient::Model::Contracts.first
obj.name =  'new_name'
obj.update set: { yesterdays_event: 35 }


341
342
343
344
345
346
347
348
349
350
# File 'lib/model.rb', line 341

def update  set: {}
   attributes.merge!( set ) if set.present?
   result= orientdb.patch_document(rid) do
    attributes.merge( { '@version' => @metadata[ :version ], '@class' => @metadata[ :class ] } )
  end
#     returns a new instance of ActiveOrient::Model
  reload! ActiveOrient::Model.orientdb_class(name: classname).new(  JSON.parse( result ))  
  # instantiate object, update rid_store and reassign to self

end

#versionObject

private



462
463
464
# File 'lib/model.rb', line 462

def version
  @metadata[ :version ] 
end