Module: ModelClass
- Includes:
- OrientSupport::Support
- Included in:
- ActiveOrient::Model
- Defined in:
- lib/model/the_class.rb
Instance Method Summary collapse
- #add_edge_link(name:, direction: :out, edge:) ⇒ Object
-
#all ⇒ Object
get all the elements of the class.
- #alter_property(property:, attribute: "DEFAULT", alteration:) ⇒ Object
-
#classname ⇒ Object
GET ###############.
-
#count(**args) ⇒ Object
Used to count of the elements in the class.
-
#create(**attributes) ⇒ Object
Universal method to create a new record.
-
#create_index(name, **attributes) ⇒ Object
Add an Index.
-
#create_properties(argument_hash, &b) ⇒ Object
Create more Properties in the Schema of the Class.
-
#create_property(field, type: :integer, index: nil, **args) ⇒ Object
Create a Property in the Schema of the Class and optionaly create an automatic index.
- #custom_where(search_string) ⇒ Object
-
#delete_property(field) ⇒ Object
Delete a property from the class.
-
#delete_record(*rid) ⇒ Object
(also: #delete_document)
Delete record(s) specified by their rid’s.
-
#delete_records(where: {}) ⇒ Object
(also: #delete_documents)
Query the database and delete the records of the resultset.
-
#first(where: {}) ⇒ Object
get the first element of the class.
-
#get(rid) ⇒ Object
get elements by rid.
-
#get_records(**args) ⇒ Object
(also: #get_documents)
»GetRecords« uses the REST-Interface to query the database.
-
#indexes ⇒ Object
list all Indexes.
-
#last(where: {}) ⇒ Object
get the last element of the class.
-
#link_list(*property) ⇒ Object
setter method to initialise a dummy ActiveOrient::Model class to enable multi-level access to links and linklists.
-
#match(where: {}) ⇒ Object
Performs a Match-Query.
-
#namespace_prefix ⇒ Object
Set the namespace_prefix for database-classes.
-
#naming_convention(name = nil) ⇒ Object
NamingConvention provides a translation from database-names to class-names.
-
#orientdb_class(name:, superclass: nil) ⇒ Object
orientdb_class is used to refer a ActiveOrient:Model-Object providing its name.
-
#print_properties ⇒ Object
Print the properties of the class.
-
#properties ⇒ Object
(also: #get_class_properties)
Get the properties of the class.
-
#query_database(query, set_from: true) ⇒ Object
QueryDatabase sends the Query directly to the database.
-
#remove(attribute, where: {}) ⇒ Object
removes a property from the collection (where given) or the entire class.
-
#require_model_file(the_directory = nil) ⇒ Object
requires the file specified in the model-dir.
-
#update_all(where: {}, set: {}, **arg) ⇒ Object
Sets a value to certain attributes, overwrites existing entries, creates new attributes if nessesary.
-
#upsert(set: nil, where:) ⇒ Object
Creates or updates a record.
-
#where(*attributes) ⇒ Object
Performs a query on the Class and returns an Array of ActiveOrient:Model-Records.
Methods included from OrientSupport::Support
#compose_where, #generate_sql_list
Instance Method Details
#add_edge_link(name:, direction: :out, edge:) ⇒ Object
590 591 592 593 594 595 |
# File 'lib/model/the_class.rb', line 590 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 |
#all ⇒ Object
get all the elements of the class
313 314 315 |
# File 'lib/model/the_class.rb', line 313 def all db.get_records from: self end |
#alter_property(property:, attribute: "DEFAULT", alteration:) ⇒ Object
601 602 603 |
# File 'lib/model/the_class.rb', line 601 def alter_property property:, attribute: "DEFAULT", alteration: # :nodoc: orientdb.alter_property self, property: property, attribute: attribute, alteration: alteration end |
#classname ⇒ Object
GET ###############
297 298 299 |
# File 'lib/model/the_class.rb', line 297 def classname # :nodoc: # ref_name end |
#count(**args) ⇒ Object
Used to count of the elements in the class
330 331 332 |
# File 'lib/model/the_class.rb', line 330 def count **args orientdb.count from: self, **args end |
#create(**attributes) ⇒ Object
Universal method to create a new record. It’s overloaded to create specific kinds, eg. edge and vertex and is called only for abstract classes
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' )
148 149 150 151 152 153 154 155 156 157 158 |
# File 'lib/model/the_class.rb', line 148 def create **attributes attributes.merge :created_at => DateTime.new result = db.create_record self, attributes: attributes if result.nil logger.error('Model::Class'){ "Table #{refname}: create failed: #{attributes.inspect}" } elsif block_given? yield result else result # return value end end |
#create_index(name, **attributes) ⇒ Object
Add an Index
287 288 289 |
# File 'lib/model/the_class.rb', line 287 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
281 282 283 |
# File 'lib/model/the_class.rb', line 281 def create_properties argument_hash, &b orientdb.create_properties self, argument_hash, &b end |
#create_property(field, type: :integer, index: nil, **args) ⇒ Object
Create a Property in the Schema of the Class and optionaly create an automatic index
Examples:
create_property :customer_id, type: integer, index: :unique
create_property( :name, type: :string ) { :unique }
create_property :in, type: :link, linked_class: V (used by edges)
:call-seq: create_property(field (required), type: :a_supported_type’, linked_class: nil
supported types: :bool :double :datetime :float :decimal
:embedded_list = :list :embedded_map = :map :embedded_set = :set
:int :integer :link_list :link_map :link_set
If :list, :map, :set, :link, :link_list, :link_map or :link_set is specified a linked_class: parameter can be specified. Argument is the OrientDB-Class-Constant
217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 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 269 270 271 272 273 274 275 276 277 |
# File 'lib/model/the_class.rb', line 217 def create_property field, type: :integer, index: nil, **args arguments = args.values.map do |y| if y.is_a?(Class) && ActiveOrient.database_classes.values.include?(y) y.ref_name elsif ActiveOrient.database_classes.keys.include?(y.to_s) y else puts ActiveOrient.database_classes.inspect puts "YY : #{y.to_s} #{y.class}" raise ArgumentError , "database class #{y.to_s} not allocated" end end.compact.join(',') supported_types = { :bool => "BOOLEAN", :double => "BYTE", :datetime => "DATE", :float => "FLOAT", :decimal => "DECIMAL", :embedded_list => "EMBEDDEDLIST", :list => "EMBEDDEDLIST", :embedded_map => "EMBEDDEDMAP", :map => "EMBEDDEDMAP", :embedded_set => "EMBEDDEDSET", :set => "EMBEDDEDSET", :string => "STRING", :int => "INTEGER", :integer => "INTEGER", :link => "LINK", :link_list => "LINKLIST", :link_map => "LINKMAP", :link_set => "LINKSET", } ## if the »type« argument is a string, it is used unchanged type = supported_types[type] if type.is_a?(Symbol) raise ArgumentError , "unsupported type" if type.nil? s= " CREATE PROPERTY #{ref_name}.#{field} #{type} #{arguments}" puts s db.execute { s } i = block_given? ? yield : index ## supported format of block: index: { name: 'something' , on: :automatic, type: :unique } ## or { name: 'something' , on: :automatic, type: :unique } # ## or { some_name: :unique } # manual index ## or { :unique } # automatic index if i.is_a? Hash att= i.key( :index ) ? i.values.first : i name, on, type = if att.size == 1 && att[:type].nil? [att.keys.first, field, att.values.first ] else [ att[:name] || field , att[:on] || field , att[:type] || :unique ] end create_index( name , on: on, type: type) elsif i.is_a?(Symbol) || i.is_a?(String) create_index field, type: i end # orientdb.create_property self, field, **keyword_arguments, &b end |
#custom_where(search_string) ⇒ Object
416 417 418 419 420 |
# File 'lib/model/the_class.rb', line 416 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
541 542 543 |
# File 'lib/model/the_class.rb', line 541 def delete_property field orientdb.delete_property self, field end |
#delete_record(*rid) ⇒ Object Also known as: delete_document
Delete record(s) specified by their rid’s
547 548 549 |
# File 'lib/model/the_class.rb', line 547 def delete_record *rid db.delete_record rid end |
#delete_records(where: {}) ⇒ Object Also known as: delete_documents
Query the database and delete the records of the resultset
554 555 556 |
# File 'lib/model/the_class.rb', line 554 def delete_records where: {} orientdb.delete_records self, where: where end |
#first(where: {}) ⇒ Object
get the first element of the class
319 320 321 |
# File 'lib/model/the_class.rb', line 319 def first where: {} db.get_records(from: self, where: where, limit: 1).pop end |
#get(rid) ⇒ Object
get elements by rid
303 304 305 306 307 308 309 |
# File 'lib/model/the_class.rb', line 303 def get rid if @excluded.blank? db.get_record(rid) else db.execute{ "select expand( @this.exclude( #{@excluded.map(&:to_or).join(",")})) from #{rid} "} end end |
#get_records(**args) ⇒ Object Also known as: get_documents
»GetRecords« uses the REST-Interface to query the database. The alternative »QueryDatabase« submits the query via Batch.
Both methods rely on OrientSupport::OrientQuery and its capacity to support complex query-builds. The method requires a hash of arguments. The following keys are supported:
projection:
SQL-Queries use »select« to specify a projection (ie. ‘select sum(a), b+5 as z from class where …`)
In ruby »select« is a method of enumeration. To specify anything etween »select« and »from« in the query-string we use »projection«, which acceps different arguments
projection: a_string --> inserts the sting as it appears
projection: an OrientSupport::OrientQuery-Object --> performs a sub-query and uses the result for further though the given parameters.
projection: [a, b, c] --> "a, b, c" (inserts a comma-separated list)
projection: {a: b, "sum(x)" => f} --> "a as b, sum(x) as f" (renames properties and uses functions)
distinct:
Constructs a query like »select distinct(property) [as property] from …«
distinct: :property --> the result is mapped to the property
order:
Sorts the result-set. If new properties were 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)
query:
Instead of providing the parameter to »get_records«, a OrientSupport::OrientQuery can build and tested prior to the method-call. The OrientQuery-Object is then 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.
410 411 412 |
# File 'lib/model/the_class.rb', line 410 def get_records **args db.get_records(from: self, **args){self} end |
#indexes ⇒ Object
list all Indexes
292 293 294 |
# File 'lib/model/the_class.rb', line 292 def indexes properties[:indexes] end |
#last(where: {}) ⇒ Object
get the last element of the class
325 326 327 |
# File 'lib/model/the_class.rb', line 325 def last where: {} db.get_records(from: self, where: where, order: {"@rid" => 'desc'}, limit: 1).pop end |
#link_list(*property) ⇒ Object
setter method to initialise a dummy ActiveOrient::Model class to enable multi-level access to links and linklists
75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/model/the_class.rb', line 75 def link_list *property property.each do |p| the_dummy_class = orientdb.allocate_class_in_ruby("dummy_"+p.to_s) the_dummy_class.ref_name = ref_name + "." + p.to_s singleton_class.send :define_method, p do the_dummy_class end end 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 returned:
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 before sending it 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.
486 487 488 489 490 491 492 493 494 495 |
# File 'lib/model/the_class.rb', line 486 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 send :where, where end end |
#namespace_prefix ⇒ Object
Set the namespace_prefix for database-classes.
If a namespace is set by
ActiveOrient::Init.define_namespace { ModuleName }
ActiveOrient translates this to
ModuleName::CamelizedClassName
The database-class becomes
modulename_class_name
If the namespace is set to a class (Object, ActiveOrient::Model ) namespace_prefix returns an empty string.
Override to change its behavior
51 52 53 |
# File 'lib/model/the_class.rb', line 51 def namespace_prefix namespace.is_a?(Class )? '' : namespace.to_s.downcase+'_' end |
#naming_convention(name = nil) ⇒ Object
NamingConvention provides a translation from database-names to class-names.
It can be overwritten to provide different conventions for different classes, eg. Vertexes or edges and to introduce distinct naming-conventions in differrent namespaces
To overwrite use
class Model # < ActiveOrient::Model[:: ...]
def self.naming_convention
( conversion code )
end
end
25 26 27 28 29 30 31 32 33 34 |
# File 'lib/model/the_class.rb', line 25 def naming_convention name=nil nc = name.present?? name.to_s : ref_name if namespace_prefix.present? nc.split(namespace_prefix).last.camelize else nc.camelize end rescue nil end |
#orientdb_class(name:, superclass: nil) ⇒ Object
orientdb_class is used to refer a ActiveOrient:Model-Object providing its name
Parameter: name: string or symbol
60 61 62 63 64 65 66 67 |
# File 'lib/model/the_class.rb', line 60 def orientdb_class name:, superclass: nil # :nodoc: # public method: autoload_class ActiveOrient.database_classes[name].presence || ActiveOrient::Model rescue NoMethodError => e logger.error { "Error in orientdb_class: is ActiveOrient.database_classes initialized ? \n\n\n" } logger.error{ e.backtrace.map {|l| " #{l}\n"}.join } Kernel.exit end |
#print_properties ⇒ Object
Print the properties of the class
345 346 347 |
# File 'lib/model/the_class.rb', line 345 def print_properties orientdb.print_class_properties self end |
#properties ⇒ Object Also known as: get_class_properties
Get the properties of the class
336 337 338 339 340 |
# File 'lib/model/the_class.rb', line 336 def properties object = orientdb.get_class_properties self #HashWithIndifferentAccess.new :properties => object['properties'], :indexes => object['indexes'] {:properties => object['properties'], :indexes => object['indexes']} end |
#query_database(query, set_from: true) ⇒ Object
QueryDatabase sends the Query directly to the database.
The result is not nessessary an Object of the Class.
The result can be modified further by passing a block. This is helpful, if a match-statement is used and the records should be autoloaded:
result = query_database(query, set_from: false){| record | record[ self.classname.pluralize ] }
This autoloads (fetches from the cache/ or database) the attribute self.classname.pluralize (taken from method: where )
query_database is used on model-level and submits
select (...) from class
#query performs queries on the instance-level and submits
select (...) from #{a}:{b}
519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 |
# File 'lib/model/the_class.rb', line 519 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 }} result = db.execute do query.to_s # sql_cmd[query.to_s] end if block_given? result.is_a?(Array)? result.map{|x| yield x } : yield(result) else result end if result.is_a? Array OrientSupport::Array.new work_on: self, work_with: result else result end # return value end |
#remove(attribute, where: {}) ⇒ Object
removes a property from the collection (where given) or the entire class
192 193 194 |
# File 'lib/model/the_class.rb', line 192 def remove attribute, where:{} db.update_records self, remove: attribute, where: where end |
#require_model_file(the_directory = nil) ⇒ Object
requires the file specified in the model-dir
In fact, the model-files are loaded instead of required. Thus, even 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.
The directory specified is expanded by the namespace. The parameter itself is the base-dir.
Example:
Namespace: HC
model_dir : 'lib/model'
searched directory: 'lib/model/hc'
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
# File 'lib/model/the_class.rb', line 104 def require_model_file the_directory = nil logger.progname = 'ModelClass#RequireModelFile' the_directory = Pathname( the_directory.presence || ActiveOrient::Model.model_dir ) rescue nil # the_directory is a Pathname return nil if the_directory.nil? if File.exists?( the_directory ) model= self.to_s.underscore + ".rb" filename = the_directory + model if File.exists?(filename ) if load filename logger.info{ "#{filename} sucessfully loaded" } self #return_value else logger.error{ "#{filename} load error" } nil #return_value end else logger.info{ "model-file not present: #{filename}" } nil #return_value end else logger.info{ "Directory #{ the_directory } not present " } nil #return_value 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 |
#update_all(where: {}, set: {}, **arg) ⇒ Object
Sets a value to certain attributes, overwrites existing entries, creates new attributes if nessesary
IB::Account.update_all connected: false
IB::Account.update_all where: "account containsText 'F'", set:{ connected: false }
**note: By calling UpdateAll, all records of the Class previously stored in the rid-cache are removed from the cache. Thus autoload gets the updated records.
183 184 185 186 187 188 189 |
# File 'lib/model/the_class.rb', line 183 def update_all where: {} , set: {}, **arg if where.empty? set.merge! arg end db.update_records self, set: set, where: where end |
#upsert(set: nil, where:) ⇒ Object
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.
returns the affected record
170 171 172 173 |
# File 'lib/model/the_class.rb', line 170 def upsert set: nil, where: set = where if set.nil? db.upsert self, set: set, where: where end |
#where(*attributes) ⇒ 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={ ... }, ...
Multible arguments are joined via “and” eg
Aktie.where symbol: 'TSL, exchange: 'ASX'
---> select from aktie where symbol = 'TLS' and exchange = 'ASX'
Where performs a »match-Query« that returns only links to the queries records. These are autoloaded (and reused from the cache). If changed database-records should be obtained, custom_query should be used. It performs a “select form class where … ” query which returns records instead of links.
Property.custom_where( "'Hamburg' in exchanges.label")
443 444 445 446 447 448 449 450 451 452 |
# File 'lib/model/the_class.rb', line 443 def where *attributes query= OrientSupport::OrientQuery.new kind: :match, start:{ class: self.classname } query.match_statements[0].where = attributes unless attributes.empty? # the block contains a result-record : #<ActiveOrient::Model:0x0000000003972e00 # @metadata={:type=>"d", :class=>nil, :version=>0, :fieldTypes=>"test_models=x"}, @d=nil, # @attributes={:test_models=>"#29:3", :created_at=>Thu, 28 Mar 2019 10:43:51 +0000}>] # ^...........° -> classname.pluralize query_database( query, set_from: false){| record | record.is_a?(ActiveOrient::Model) ? record : record.send( self.classnamepluralize.to_sym ) } end |