Class: Arcade::Base
- Inherits:
-
Dry::Struct
- Object
- Dry::Struct
- Arcade::Base
- Extended by:
- Support::Sql
- Defined in:
- lib/arcade/init.rb,
lib/arcade/base.rb
Overview
Provides method ‘db` to every Model class
Class Method Summary collapse
-
.all(a = true, autoload: true, **args) ⇒ Object
Lists all records of a type.
- .begin_transaction ⇒ Object
- .commit ⇒ Object
-
.count(**args) ⇒ Object
- def create **attributes s = Api.begin_transaction db.database attributes.merge!( created: DateTime.now ) if timestamps record = insert **attributes Api.commit db.database, s record rescue HTTPX::HTTPError => e db.logger.error “Dataset NOT created” db.logger.error “Provided Attributes: #{ attributes.inspect }” Api.rollback db.database # —> raises “transactgion not begun” rescue Dry::Struct::Error => e Api.rollback db.database db.logger.error “#{ rid }
-
Validation failed, record deleted.“ db.logger.error e.message end.
- .create_type ⇒ Object
-
.database_name ⇒ Object
this has to be implemented on class level otherwise it interfere with attributes.
- .descendants ⇒ Object
- .drop_type ⇒ Object
-
.find(**args) ⇒ Object
Finds the first matching record providing the parameters of a ‘where` query Strategie.find symbol: ’Still’ is equivalent to Strategie.all.find{|y| y.symbol == ‘Still’ }.
-
.first(a = true, autoload: true, **args) ⇒ Object
Lists the first record of a type or a query.
-
.insert(**attributes) ⇒ Object
(also: create)
—————————————– insert ———————————- ##.
-
.last(a = true, autoload: true, **args) ⇒ Object
Lists the last record of a type or a query.
-
.not_permitted(*m) ⇒ Object
## Immutable Support.
- .properties ⇒ Object
- .query(**args) ⇒ Object
- .rollback ⇒ Object
-
.timestamps(set = nil) ⇒ Object
add timestamp attributes to the model.
-
.update(**args) ⇒ Object
update returns a list of updated records.
-
.update!(**args) ⇒ Object
update! returns the count of affected records.
-
.upsert(**args) ⇒ Object
returns a list of updated records.
-
.where(a = true, autoload: true, **args) ⇒ Object
Selects records of a type or a query.
Instance Method Summary collapse
- #==(arg) ⇒ Object
- #accepted_methods ⇒ Object
- #delete ⇒ Object
- #html_attributes ⇒ Object
- #in_and_out_attributes ⇒ Object
-
#insert_document(name, obj) ⇒ Object
inserts or updates a embedded document.
-
#inspect ⇒ Object
configure irb-output to to_human for all Arcade::Base-Objects.
- #invariant_attributes ⇒ Object
-
#method_missing(method, *key) ⇒ Object
enables to display values keys like methods.
- #query(**args) ⇒ Object
- #refresh ⇒ Object
- #rid? ⇒ Boolean
-
#to_html ⇒ Object
iruby.
- #to_human ⇒ Object
-
#to_json(*args) ⇒ Object
to JSON controlls the serialisation of Arcade::Base Objects for the HTTP-JSON API.
-
#to_or ⇒ Object
enables usage of Base-Objects in queries.
- #update(**args) ⇒ Object
-
#update_embedded(embedded, embedded_property, value) ⇒ Object
updates a single property in an embedded document.
-
#update_list(list, value, modus: :auto) ⇒ Object
Adds List-Elements to embedded List.
-
#update_map(m, key, value) ⇒ Object
updates a map property , actually adds the key-value pair to the property does not work on reduced model records.
Methods included from Support::Sql
compose_where, generate_sql_list
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(method, *key) ⇒ Object
enables to display values keys like methods
341 342 343 344 345 |
# File 'lib/arcade/base.rb', line 341 def method_missing method, *key if attributes[:values] &.keys &.include? method return values.fetch(method) end end |
Class Method Details
.all(a = true, autoload: true, **args) ⇒ Object
Lists all records of a type
Accepts any parameter supported by Arcade::Query
Model.all false –> suppresses the autoload mechanism
Example
My::Names.all order: ‘name’, autoload: false
178 179 180 181 |
# File 'lib/arcade/base.rb', line 178 def all a= true, autoload: true, **args autoload = false if a != autoload query(**args).query.allocate_model( autoload ) end |
.begin_transaction ⇒ Object
34 35 36 |
# File 'lib/arcade/base.rb', line 34 def begin_transaction db.begin_transaction end |
.commit ⇒ Object
37 38 39 |
# File 'lib/arcade/base.rb', line 37 def commit db.commit end |
.count(**args) ⇒ Object
def create **attributes
s = Api.begin_transaction db.database
attributes.merge!( created: DateTime.now ) if
record = insert **attributes
Api.commit db.database, s
record
rescue HTTPX::HTTPError => e
db.logger.error "Dataset NOT created"
db.logger.error "Provided Attributes: #{ attributes.inspect }"
Api.rollback db.database # ---> raises "transactgion not begun"
rescue Dry::Struct::Error => e
Api.rollback db.database
db.logger.error "#{ rid } :: Validation failed, record deleted."
db.logger.error e.
end
163 164 165 166 |
# File 'lib/arcade/base.rb', line 163 def count **args command = "count(*)" query( **( { projection: command }.merge args ) ).query.first[command.to_sym] rescue 0 end |
.create_type ⇒ Object
44 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 90 91 92 |
# File 'lib/arcade/base.rb', line 44 def create_type the_class = nil # declare as local var parent_present = ->(cl){ db.hierarchy.flatten.include? cl } e = ancestors.each myselfclass = e.next # start with the actual class(self) loop do superclass = the_class = e.next break if the_class.is_a? Class end begin loop do if the_class.respond_to?(:demodulize) if [ 'Document','Vertex', 'Edge'].include?(the_class.demodulize) if the_class == superclass # no inheritance db.create_type the_class.demodulize, to_s.snake_case else if superclass.is_a? Class # maybe its a module. extended = superclass.to_s.snake_case else extended = superclass.superclass.to_s.snake_case end if !parent_present[extended] superclass.create_type end db.create_type the_class.demodulize, to_s.snake_case, extends: extended end break # stop iteration end end the_class = e.next # iterate through the enumerator end # todo # include `created`` and `updated` properties to the aradedb-database schema if timestamps are set # (it works without declaring them explicitly, its thus omitted for now ) # Integration is easy: just execute two commands custom_setup = db_init rescue "" custom_setup.each_line do | command | the_command = command[0 .. -2] # remove '\n' next if the_command == '' # db.logger.info "Custom Setup:: #{the_command}" db.transmit { the_command } end unless custom_setup.nil? rescue RollbackError => e db.logger.warn e rescue RuntimeError => e db.logger.warn e end end |
.database_name ⇒ Object
this has to be implemented on class level otherwise it interfere with attributes
30 31 32 |
# File 'lib/arcade/base.rb', line 30 def database_name self.name.snake_case end |
.descendants ⇒ Object
24 25 26 |
# File 'lib/arcade/base.rb', line 24 def descendants ObjectSpace.each_object(Class).select { |klass| klass < self } end |
.drop_type ⇒ Object
95 96 97 |
# File 'lib/arcade/base.rb', line 95 def drop_type db.drop_type to_s.snake_case end |
.find(**args) ⇒ Object
Finds the first matching record providing the parameters of a ‘where` query
Strategie.find symbol: 'Still'
is equivalent to
Strategie.all.find{|y| y.symbol == 'Still' }
237 238 239 240 241 |
# File 'lib/arcade/base.rb', line 237 def find **args where(**args).first # f= where( "#{ args.keys.first } like #{ args.values.first.to_or }" ).first if f.nil? || f.empty? # f end |
.first(a = true, autoload: true, **args) ⇒ Object
Lists the first record of a type or a query
Accepts any parameter supported by Arcade::Query
Model.first false –> suppresses the autoload mechanism
Example
My::Names.first where: ‘age < 50’, autoload: false
193 194 195 196 |
# File 'lib/arcade/base.rb', line 193 def first a= true, autoload: true, **args autoload = false if a != autoload query( **( { order: "@rid" , limit: 1 }.merge args ) ).query.allocate_model( autoload ) &.first end |
.insert(**attributes) ⇒ Object Also known as: create
—————————————– insert ———————————- ##
Adds a record to the database
returns the inserted record
Bucket and Index are supported
fired Database-command
INSERT INTO <type> BUCKET<bucket> INDEX <index> [CONTENT {<attributes>}]
(not supported (jet): [RETURN <expression>] [FROM <query>] )
134 135 136 |
# File 'lib/arcade/base.rb', line 134 def insert **attributes db.insert type: database_name, session_id: attributes.delete(:session_id), **attributes end |
.last(a = true, autoload: true, **args) ⇒ Object
Lists the last record of a type or a query
Accepts any parameter supported by Arcade::Query
Model.last false –> suppresses the autoload mechanism
Example
My::Names.last where: ‘age > 50’, autoload: false
209 210 211 212 |
# File 'lib/arcade/base.rb', line 209 def last a= true, autoload: true, **args autoload = false if a != autoload query( **( { order: {"@rid" => 'desc'} , limit: 1 }.merge args ) ).query.allocate_model( autoload )&.first end |
.not_permitted(*m) ⇒ Object
## Immutable Support
To make a database type immutable add
`not_permitted :update, :upsert, :delete`
to the model-specification
Even after applying ‘not_permitted` the database-type can be modified via class-methods.
309 310 311 312 313 314 315 |
# File 'lib/arcade/base.rb', line 309 def not_permitted *m m.each do | def_m | define_method( def_m ) do | v = nil | raise Arcade::ImmutableError.new( "operation #{def_m} not permitted" ) end end end |
.properties ⇒ Object
99 100 101 |
# File 'lib/arcade/base.rb', line 99 def properties end |
.query(**args) ⇒ Object
297 298 299 |
# File 'lib/arcade/base.rb', line 297 def query **args Query.new( **{ from: self }.merge(args) ) end |
.rollback ⇒ Object
40 41 42 |
# File 'lib/arcade/base.rb', line 40 def rollback db.rollback end |
.timestamps(set = nil) ⇒ Object
add timestamp attributes to the model
updated is optional
timestamps are included in create and update statements
111 112 113 114 115 116 117 118 |
# File 'lib/arcade/base.rb', line 111 def set=nil if set && @stamps.nil? @stamps = true attribute :created, Types::JSON::DateTime attribute :updated?, Types::JSON::DateTime end @stamps end |
.update(**args) ⇒ Object
update returns a list of updated records
It fires a query update <type> set <property> = <new value > upsert return after $current where < condition >
which returns a list of modified rid’s
required parameter: set:
where:
todo refacture required parameters notification
253 254 255 256 257 258 259 260 261 262 |
# File 'lib/arcade/base.rb', line 253 def update **args if args.keys.include?(:set) && args.keys.include?(:where) args.merge!( updated: DateTime.now ) if query( **( { kind: :update }.merge args ) ).execute do |r| r[:"$current"] &.allocate_model(false) # do not autoload modelfiles end else raise "at least set: and where: are required to perform this operation" end end |
.update!(**args) ⇒ Object
update! returns the count of affected records
required parameter: set:
where:
269 270 271 272 273 274 275 276 |
# File 'lib/arcade/base.rb', line 269 def update! **args if args.keys.include?(:set) && args.keys.include?(:where) args.merge!( updated: DateTime.now ) if query( **( { kind: :update! }.merge args ) ).execute{|y| y[:count] } &.first else raise "at least set: and where: are required to perform this operation" end end |
.upsert(**args) ⇒ Object
returns a list of updated records
280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 |
# File 'lib/arcade/base.rb', line 280 def upsert **args set_statement = args.delete :set args.merge!( updated: DateTime.now ) if where_statement = args[:where] || args statement = if set_statement { set: set_statement, where: where_statement } else { where: where_statement } end result= query( **( { kind: :upsert }.merge statement ) ).execute do | answer| z= answer[:"$current"] &.allocate_model(false) # do not autoload modelfiles raise LoadError "Upsert failed" unless z.is_a? Base z # return record end end |
.where(a = true, autoload: true, **args) ⇒ Object
Selects records of a type or a query
Accepts only parameters to restrict the query (apart from autoload).
Use ‘Model.query where: args“to use the full range of supported parameters
Model.where false –> suppresses the autoload mechanism
Example
My::Names.last where: ‘age > 50’, autoload: false
226 227 228 229 230 231 |
# File 'lib/arcade/base.rb', line 226 def where a= true, autoload: true, **args autoload = false if a != autoload args = a if a.is_a?(String) ## the result is always an array query( where: args ).query.allocate_model(autoload) end |
Instance Method Details
#==(arg) ⇒ Object
499 500 501 502 |
# File 'lib/arcade/base.rb', line 499 def == arg # self.attributes == arg.attributes self.rid == arg.rid end |
#accepted_methods ⇒ Object
17 18 19 |
# File 'lib/arcade/base.rb', line 17 def accepted_methods [ :rid, :to_human, :delete ] end |
#delete ⇒ Object
495 496 497 498 |
# File 'lib/arcade/base.rb', line 495 def delete response = db.transmit { "delete from #{ rid }" } true if response == [{ count: 1 }] end |
#html_attributes ⇒ Object
400 401 402 |
# File 'lib/arcade/base.rb', line 400 def html_attributes invariant_attributes end |
#in_and_out_attributes ⇒ Object
404 405 406 407 408 |
# File 'lib/arcade/base.rb', line 404 def in_and_out_attributes _modul, _class = self.class.to_s.split "::" the_class = _modul == 'Arcade' ? _class : self.class.to_s the_attributes = { :"CLASS" => the_class, :"IN" => self.in.count, :"OUT" => self.out.count, :"RID" => rid } end |
#insert_document(name, obj) ⇒ Object
inserts or updates a embedded document
440 441 442 443 444 445 446 447 448 449 |
# File 'lib/arcade/base.rb', line 440 def insert_document name, obj value = if obj.is_a? Document obj.to_json else obj.to_or end # if send( name ).nil? || send( name ).empty? db.transmit { "update #{ rid } set #{ name } = #{ value }" }.first[:count] # end end |
#inspect ⇒ Object
configure irb-output to to_human for all Arcade::Base-Objects
395 396 397 |
# File 'lib/arcade/base.rb', line 395 def inspect to_human end |
#invariant_attributes ⇒ Object
330 331 332 333 334 335 336 337 |
# File 'lib/arcade/base.rb', line 330 def invariant_attributes result= attributes.except :rid, :in, :out, :values, :created_at, :updated_at if attributes.keys.include?(:values) result.merge values else result end end |
#query(**args) ⇒ Object
347 348 349 |
# File 'lib/arcade/base.rb', line 347 def query **args Query.new( **{ from: rid }.merge(args) ) end |
#refresh ⇒ Object
504 505 506 |
# File 'lib/arcade/base.rb', line 504 def refresh db.get(rid) end |
#rid? ⇒ Boolean
362 363 364 |
# File 'lib/arcade/base.rb', line 362 def rid? true unless ["#0:0", "#-1:-1"].include? rid end |
#to_html ⇒ Object
iruby
410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 |
# File 'lib/arcade/base.rb', line 410 def to_html # iruby in_and_out = ->(r) { "[#{r}] : {#{self.in.count}->}{->#{self.out.count }}" } the_rid = rid? && rid != "0:0" ? in_and_out[rid] : "" _modul, _class = self.class.to_s.split "::" the_class = _modul == 'Arcade' ? _class : self.class.to_s # the_attribute = ->(v) do # case v # when Base # "< #{ self.class.to_s.snake_case }: #{ v.rid } >" # when Array # v.map{|x| x.to_s} # else # v.to_s # end # end # last_part = invariant_attributes.map do |attr, value| # [ attr, the_attribute[value] ].join(": ") # end.join(', ') # IRuby.display( [IRuby.html("<span style=\"color: #50953DFF\"><b>#{the_class}</b><#{ the_class }</b>#{the_rid}</span><br/> ") , IRuby.table(html_attributes) ] ) IRuby.display IRuby.html("<span style=\"color: #50953DFF\"><b>#{the_class}</b><#{ the_class }</b>#{the_rid}</span>< #{ html_attributes.map{|_,v| v }.join(', ') } >") end |
#to_human ⇒ Object
375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 |
# File 'lib/arcade/base.rb', line 375 def to_human "<#{ self.class.to_s.snake_case }" + rid? ? "[#{ rid }]: " : " " + invariant_attributes.map do |attr, value| v= case value when Base "< #{ self.class.to_s.snake_case }: #{ value.rid } >" when Array value.map{|x| x.to_s} else value.from_db end "%s : %s" % [ attr, v] unless v.nil? end.compact.sort.join(', ') + ">".gsub('"' , ' ') rescue TypeError => e attributes end |
#to_json(*args) ⇒ Object
to JSON controlls the serialisation of Arcade::Base Objects for the HTTP-JSON API
ensure, that only the rid is transmitted to the database
355 356 357 358 359 360 361 |
# File 'lib/arcade/base.rb', line 355 def to_json *args unless ["#0:0", "#-1:-1"].include? rid # '#-1:-1' is the null-rid rid else invariant_attributes.merge( :'@type' => self.class.database_name ).to_json end end |
#to_or ⇒ Object
enables usage of Base-Objects in queries
367 368 369 370 371 372 373 |
# File 'lib/arcade/base.rb', line 367 def to_or if rid? rid else to_json end end |
#update(**args) ⇒ Object
434 435 436 437 |
# File 'lib/arcade/base.rb', line 434 def update **args Query.new( from: rid , kind: :update, set: args).execute refresh # return the updated record (the object itself is untouched!) end |
#update_embedded(embedded, embedded_property, value) ⇒ Object
updates a single property in an embedded document
452 453 454 |
# File 'lib/arcade/base.rb', line 452 def , , value db.transmit { " update #{rid} set `#{embedded}`.`#{embedded_property}` = #{value.to_or}" } end |
#update_list(list, value, modus: :auto) ⇒ Object
Adds List-Elements to embedded List
Arguments:
-
list: A symbol of the list property
-
value: A embedded document or a hash
-
modus: :auto, :first, :append
Prefered modus operandi
-
the-element.insert (…) , #list:[]
-
the_element.update_list list, value: :append
467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 |
# File 'lib/arcade/base.rb', line 467 def update_list list, value, modus: :auto value = if value.is_a? Document # embedded mode value.to_json else value.to_or end if modus == :auto modus = db.query( "select #{list}.size() from #{rid}" ).select_result.first.zero? ? :first : :append end if modus == :first db.transmit { "update #{ rid } set #{ list } = [#{ value }]" } else db.transmit { "update #{ rid } set #{ list } += #{ value }" } end # refresh end |
#update_map(m, key, value) ⇒ Object
updates a map property , actually adds the key-value pair to the property does not work on reduced model records
487 488 489 490 491 492 493 494 |
# File 'lib/arcade/base.rb', line 487 def update_map m, key, value if send( m ).nil? db.transmit { "update #{ rid } set #{ m } = MAP ( #{ key.to_s.to_or } , #{ value.to_or } ) " } else db.transmit { "update #{ rid } set #{ m }.`#{ key.to_s }` = #{ value.to_or }" } end refresh end |