Module: ModelClass

Included in:
ActiveOrient::Model
Defined in:
lib/model/the_class.rb

Instance Method Summary collapse

Instance Method Details



465
466
467
468
469
470
# File 'lib/model/the_class.rb', line 465

def add_edge_link name:, direction: :out, edge:
  dir =  direction.to_s == "out" ? :out : :in
  define_method(name.to_sym) do
    return self["#{dir}_#{edge.classname}"].map{|x| x["in"]}
  end
end

#allObject

get all the elements of the class



230
231
232
# File 'lib/model/the_class.rb', line 230

def all
  db.get_records from: self
end

#alter_property(property:, attribute: "DEFAULT", alteration:) ⇒ Object



476
477
478
# File 'lib/model/the_class.rb', line 476

def alter_property property:, attribute: "DEFAULT", alteration:
  orientdb.alter_property self, property: property, attribute: attribute, alteration: alteration
end

#classnameObject

GET ###############



218
219
220
# File 'lib/model/the_class.rb', line 218

def classname  # :nodoc: #
   ref_name
end

#count(**args) ⇒ Object

Used to count of the elements in the class



247
248
249
# File 'lib/model/the_class.rb', line 247

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

#create(**attributes) ⇒ Object

Universal method to create a new record. It’s obverloaded to create specific kinds, eg. edges

Example:

ORD.create_class :test
Test.create string_attribute: 'a string', symbol_attribute: :a_symbol, array_attribute: [34,45,67]
Test.create link_attribute: Test.create( :a_new_attribute => 'new' )


154
155
156
157
# File 'lib/model/the_class.rb', line 154

def create **attributes
  attributes.merge :created_at => Time.new
  db.create_record self, attributes: attributes 
end

#create_index(name, **attributes) ⇒ Object

Add an Index



212
213
214
# File 'lib/model/the_class.rb', line 212

def create_index name, **attributes
  orientdb.create_index self, name: name, **attributes
end

#create_properties(argument_hash, &b) ⇒ Object

Create more Properties in the Schema of the Class



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

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

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

Create a Property in the Schema of the Class

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

Examples:

  create_property  :customer_id, type: integer, index: :unique
  create_property  :name, type: :string, index: :not_unique
  create_property  :in,  type: :link, linked_class: :V    (used by edges)


200
201
202
# File 'lib/model/the_class.rb', line 200

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

#custom_where(search_string) ⇒ Object

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

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


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

def custom_where search_string
  q = OrientSupport::OrientQuery.new from: self, where: search_string
  puts q.compose
  query_database q
end

#delete_property(field) ⇒ Object

Delete a property from the class



408
409
410
# File 'lib/model/the_class.rb', line 408

def delete_property field
  orientdb.delete_property self, field
end

#delete_record(*rid) ⇒ Object Also known as: delete_document

Delete a record



414
415
416
# File 'lib/model/the_class.rb', line 414

def delete_record *rid
  db.delete_record rid
end

#delete_records(where: {}) ⇒ Object Also known as: delete_documents

Delete a record from the class



421
422
423
# File 'lib/model/the_class.rb', line 421

def delete_records where: {}
  orientdb.delete_records self, where: where
end

#first(where: {}) ⇒ Object

get the first element of the class



236
237
238
# File 'lib/model/the_class.rb', line 236

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

#get(rid) ⇒ Object

get elements by rid



224
225
226
# File 'lib/model/the_class.rb', line 224

def get rid
  db.get_record rid
end

#get_model_class(name) ⇒ Object

Retrieves the preallocated class derived from ActiveOrient::Model

Only classes noted in the @classes-Array of orientdb are fetched.



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

def get_model_class name
  if orientdb.database_classes.include?(name)
    orientdb_class name: name, superclass: :find_ME
  else
    nil
  end
end

#get_propertiesObject Also known as: get_class_properties

Get the properties of the class



253
254
255
256
# File 'lib/model/the_class.rb', line 253

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

#get_records(**args) ⇒ Object Also known as: get_documents

Parameter projection:

: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 (https://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
    ORD.create_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.


306
307
308
# File 'lib/model/the_class.rb', line 306

def get_records **args
  db.get_records(from: self, **args){self}
end

#last(where: {}) ⇒ Object

get the last element of the class



242
243
244
# File 'lib/model/the_class.rb', line 242

def last where: {}
  db.get_records(from: self, where: where, order: {"@rid" => 'desc'}, limit: 1).pop
end

#match(where: {}) ⇒ Object

Performs a Match-Query

The Query starts at the given ActiveOrient::Model-Class. The where-cause narrows the sample to certain records. In the simplest version this can be returnd:

Industry.match where:{ name: "Communications" }
=> #<ActiveOrient::Model::Query:0x00000004309608 @metadata={"type"=>"d", "class"=>nil, "version"=>0, "fieldTypes"=>"Industries=x"}, @attributes={"Industries"=>"#21:1", (...)}>

The attributes are the return-Values of the Match-Query. Unless otherwise noted, the pluralized Model-Classname is used as attribute in the result-set.

I.match( where: { name: 'Communications' }).first.Industries

is the same then

Industry.where name: "Communications"

The Match-Query uses this result-set as start for subsequent queries on connected records. These connections are defined in the Block

var = Industry.match do | query |
  query.connect :in, count: 2, as: 'Subcategories'
  puts query.to_s  # print the query send to the database
  query            # important: block has to return the query 
end
=> MATCH {class: Industry, as: Industries} <-- {} <-- { as: Subcategories }  RETURN Industries, Subcategories

The result-set has two attributes: Industries and Subcategories, pointing to the filtered datasets.

By using subsequent »connect« and »statement« method-calls even complex Match-Queries can be clearly constructed.



363
364
365
366
367
368
369
370
371
372
373
# File 'lib/model/the_class.rb', line 363

def match where: {}
  query= OrientSupport::OrientQuery.new kind: :match, start:{ class: self.classname }
  query.match_statements[0].where =  where unless where.empty?
  if block_given?
    query_database yield(query), set_from: false
  else
    logger.progname = 'ActiveOrient::Model#Match'
    logger.error{ "Query-Details have to be specified in a Block" }
  end

end

#naming_convention(name = nil) ⇒ Object

NamingConvention provides a translation from database-names to class-names.

Should provide

to_s.capitalize_first_letter

as minimum. Can be overwritten to provide different conventions for different classes, eg. Vertexes or edges.

To overwrite use

 class Model < ActiveOrient::Model[:: ...]
   def self.naming_convention
   ( conversion code )
   end
end


24
25
26
# File 'lib/model/the_class.rb', line 24

def naming_convention name=nil  # :nodoc:
  name.present? ? name.to_s.camelize : ref_name.camelize
end

#orientdb_class(name:, superclass: nil) ⇒ Object

orientdb_class is used to create or refer a ActiveOrient:Model:class by providing its name

Parameter: name: string or symbol
Parameter: superclass: If class, then this is used unmodified

If string or symbol, its used to reference an existing class if :find_ME, its derived from the classes-hash

Attention: If a class is created by orientdb_class, its only allocated in ruby-space.

The class is thus not present in the classes-array, which reflects the database-classes. If a class depending on a superclass is to be created, the superclass is derived from the classes-array. In such a case, the allocation only works, if the class itself is used as parameter “superclass” i.e. ActiveOrient::Model.orientdb_class name: ‘hurra’ AvtiveOrient::Model.orientdb_class name: ‘hip_hip’ , superclass: Hurra



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/model/the_class.rb', line 45

def orientdb_class name:, superclass: nil   # :nodoc:    # public method: autoload_class
  logger.progname = "ModelClass#OrientDBClass"
  # @s-class is a cash for actual String -> Class relations
  @s_class = HashWithIndifferentAccess.new( V: V, E: E) unless @s_class.present?

  update_my_array = ->(s) { @s_class[s.ref_name] = s unless @s_class[s.ref_name].present? }
  get_class =  ->(n) { @s_class[n] }


  ref_name =  name.to_s
  klass = if superclass.present?   # superclass is parameter, use if class, otherwise transfer to class
     s= if superclass.is_a? Class
   namespace.send( :const_get, superclass.to_s )
 else
   superclass = orientdb.get_db_superclass( ref_name ) if superclass == :find_ME
   if superclass.present?
     namespace.send( :const_get, get_class[superclass].to_s )
   else
     self
   end
 end
     Class.new(s)
   else
     Class.new(self)
   end
  # namespace is defined in config/boot
  name = klass.naming_convention ref_name #
  if namespace.send :const_defined?, name
    retrieved_class = namespace.send :const_get, name
  else

    new_class = namespace.send :const_set, name, klass
    new_class.ref_name =  ref_name
    update_my_array[new_class]
#      logger.debug{"created:: Class #{new_class} < #{new_class.superclass} "}
#      logger.debug{"database-table:: #{ref_name} "}
    new_class # return_value
  end
rescue NameError => e
    logger.error "ModelClass #{name.inspect} cannot be initialized."
    logger.error e.message
    logger.error e.backtrace.map {|l| "  #{l}\n"}.join  
    nil  # return_value
  #end
end

Print the properties of the class



261
262
263
# File 'lib/model/the_class.rb', line 261

def print_class_properties
  orientdb.print_class_properties self
end

#query_database(query, set_from: true) ⇒ Object

QueryDatabase sends the Query, direct to the database.

The result is not nessessary an Object of self.
However, if the query does not return an array of Active::Model-Objects, then the entries become self


396
397
398
399
400
401
402
# File 'lib/model/the_class.rb', line 396

def 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 }}
  db.execute do
    sql_cmd[query.to_s]
  end
end

#require_model_fileObject

requires the file specified in the model-dir

In fact, the model-files are loaded instead of required. After recreation of a class (Class.delete_class, ORD.create_class classname) custom methods declared in the model files are present. Required modelfiles are gone, if the class is destroyed, but the interpreter thinks, they have already been required. Rebuilding the class does not reestablish the connection to the required model file.

Actual only a flat directory is supported. However -the Parameter model has the format: [ superclass, class ]. Its possible to extend the method adress a model-tree.



115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/model/the_class.rb', line 115

def require_model_file 
  logger.progname = 'ModelClass#RequireModelFile'
  if File.exists?( ActiveOrient::Model.model_dir )
    model= model.flatten.last if model.is_a?( Array )
    filename =   ActiveOrient::Model.model_dir + "/" + self.to_s.underscore + '.rb'
    puts "REQUIRE_MODEL_FILE: #{self.to_s} <-- #{self.superclass}"
    if  File.exists?(filename )
      if load filename
  logger.info{ "#{filename} sucessfully loaded"  }
      else
  logger.error{ "#{filename} load error" }
      end
    else
      logger.info{ "model-file not present: #{filename}" }
    end
  else
    logger.info{ "Directory #{ ActiveOrient::Model.model_dir  } not present " }
  end
rescue TypeError => e
     puts "TypeError:  #{e.message}" 
     puts "Working on #{self.to_s} -> #{self.superclass}"
     puts "Class_hierarchy: #{orientdb.class_hierarchy.inspect}."
     print e.backtrace.join("\n") 
     raise
  #
end

#superClassObject

Get the superclass of the class



378
379
380
381
382
383
384
385
386
387
388
# File 'lib/model/the_class.rb', line 378

def superClass
  { superclass => superclass.ref_name }
#    logger.progname = 'ActiveOrient::Model#Superclass'
#    r = orientdb.get_classes('name', 'superClass').detect{|x|
#      x["name"].downcase == new.class.to_s.downcase.split(':')[-1].to_s
#    }['superClass']
#    if r.empty?
#      logger.info{"#{self} does not have any superclass. Probably it is a Document"}
#    end
#    return r
end

#update_or_create_records(set: {}, where: {}, **args, &b) ⇒ Object Also known as: update_or_create_documents

Create a new Instance of the Class with the applied attributes if does not exists, otherwise update it. It returns the freshly instantiated Objects



178
179
180
# File 'lib/model/the_class.rb', line 178

def update_or_create_records set: {}, where: {}, **args, &b
  db.update_or_create_records self, set: set, where: where, **args, &b
end

#update_records(set:, where:) ⇒ Object Also known as: update_documents

Update records of a class



431
432
433
# File 'lib/model/the_class.rb', line 431

def update_records set:, where:
  db.update_records self, set: set, where: where
end

#upsert(set: {}, where: {}, &b) ⇒ Object Also known as: create_or_update_document, update_or_create

Creates or updates a record. Parameter:

set: A hash of attributes to insert or update unconditionally
where: A string or hash as condition which should return just one record.

The where-part should be covered with an unique-index. If :where is omitted, #Upsert becomes #Create, attributes are taken from :set.

returns the affected record



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

def upsert set: {}, where: {}, &b
  db.upsert self, set: set, where: where, &b
end

#where(**attributes) ⇒ Object



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

def where **attributes 
  ##puts "ATTRIBUTES: "+attributes.inspect
  q = OrientSupport::OrientQuery.new from: self, where: attributes
  query_database q
end