Class: Arcade::Base
- Inherits:
-
Dry::Struct
- Object
- Dry::Struct
- Arcade::Base
- Extended by:
- Support::Sql
- Defined in:
- lib/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.
- .count(**args) ⇒ Object
-
.create(**attributes) ⇒ Object
—————————————– create ———————————- ##.
- .create_type ⇒ Object
-
.database_name ⇒ Object
this has to be implemented on class level otherwise it interfere with attributes.
- .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
—————————————– insert ———————————- ##.
-
.last(a = true, autoload: true, **args) ⇒ Object
Lists the last record of a type or a query.
-
.not_permitted(*m) ⇒ Object
immutable support to make a database type immutable add ‘not_permitted :update, :upsert, :delete` to the model-specification.
- .properties ⇒ Object
- .query(**args) ⇒ 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
-
#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) ⇒ Object
-
#update_map(m, key, value) ⇒ Object
updates a map property , actually adds the key-value pair to the property.
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
322 323 324 325 326 |
# File 'lib/arcade/base.rb', line 322 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
162 163 164 165 |
# File 'lib/arcade/base.rb', line 162 def all a= true, autoload: true, **args autoload = false if a != autoload query(**args).query.allocate_model( autoload ) end |
.count(**args) ⇒ Object
147 148 149 150 |
# File 'lib/arcade/base.rb', line 147 def count **args command = "count(*)" query( **( { projection: command }.merge args ) ).query.first[command.to_sym] rescue 0 end |
.create(**attributes) ⇒ Object
—————————————– create ———————————- ##
Adds a record to the database
returns the model dataset
( depreciated )
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
# File 'lib/arcade/base.rb', line 131 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 QueryError => 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 |
.create_type ⇒ Object
30 31 32 33 34 35 36 37 38 39 40 41 42 43 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 |
# File 'lib/arcade/base.rb', line 30 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.execute { 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
26 27 28 |
# File 'lib/arcade/base.rb', line 26 def database_name self.name.snake_case end |
.drop_type ⇒ Object
81 82 83 |
# File 'lib/arcade/base.rb', line 81 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' }
221 222 223 224 225 |
# File 'lib/arcade/base.rb', line 221 def find **args f= 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
177 178 179 180 |
# File 'lib/arcade/base.rb', line 177 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
—————————————– 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>] )
120 121 122 |
# File 'lib/arcade/base.rb', line 120 def insert **attributes db.insert type: database_name, **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
193 194 195 196 |
# File 'lib/arcade/base.rb', line 193 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
290 291 292 293 294 295 296 |
# File 'lib/arcade/base.rb', line 290 def not_permitted *m m.each do | def_m | define_method( def_m ) do | v = nil | raise ArcadeImmutableError "operation not permitted", caller end end end |
.properties ⇒ Object
85 86 87 |
# File 'lib/arcade/base.rb', line 85 def properties end |
.query(**args) ⇒ Object
281 282 283 |
# File 'lib/arcade/base.rb', line 281 def query **args Query.new( **{ from: self }.merge(args) ) end |
.timestamps(set = nil) ⇒ Object
add timestamp attributes to the model
updated is optional
timestamps are included in create and update statements
97 98 99 100 101 102 103 104 |
# File 'lib/arcade/base.rb', line 97 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
237 238 239 240 241 242 243 244 245 246 |
# File 'lib/arcade/base.rb', line 237 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:
253 254 255 256 257 258 259 260 |
# 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{|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
264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 |
# File 'lib/arcade/base.rb', line 264 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
210 211 212 213 214 215 |
# File 'lib/arcade/base.rb', line 210 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
445 446 447 448 |
# File 'lib/arcade/base.rb', line 445 def == arg # self.attributes == arg.attributes self.rid == arg.rid end |
#accepted_methods ⇒ Object
16 17 18 |
# File 'lib/arcade/base.rb', line 16 def accepted_methods [ :rid, :to_human, :delete ] end |
#delete ⇒ Object
441 442 443 444 |
# File 'lib/arcade/base.rb', line 441 def delete response = db.execute { "delete from #{ rid }" } true if response == [{ count: 1 }] end |
#insert_document(name, obj) ⇒ Object
inserts or updates a embedded document
402 403 404 405 406 407 408 409 410 411 |
# File 'lib/arcade/base.rb', line 402 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.execute { "update #{ rid } set #{ name } = #{ value }" }.first[:count] # end end |
#inspect ⇒ Object
configure irb-output to to_human for all Arcade::Base-Objects
375 376 377 |
# File 'lib/arcade/base.rb', line 375 def inspect to_human end |
#invariant_attributes ⇒ Object
311 312 313 314 315 316 317 318 |
# File 'lib/arcade/base.rb', line 311 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
328 329 330 |
# File 'lib/arcade/base.rb', line 328 def query **args Query.new( **{ from: rid }.merge(args) ) end |
#refresh ⇒ Object
450 451 452 |
# File 'lib/arcade/base.rb', line 450 def refresh db.get(rid) end |
#rid? ⇒ Boolean
343 344 345 |
# File 'lib/arcade/base.rb', line 343 def rid? true unless ["#0:0", "#-1:-1"].include? rid end |
#to_html ⇒ Object
iruby
379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 |
# File 'lib/arcade/base.rb', line 379 def to_html # iruby _modul, _class = self.class.to_s.split "::" the_class = _modul == 'Arcade' ? _class : self.class.to_s IRuby.display IRuby.html "<b style=\"color: #50953DFF\"><#{ the_class}</b>" + 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('"' , ' ') end |
#to_human ⇒ Object
356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 |
# File 'lib/arcade/base.rb', line 356 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('"' , ' ') 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
336 337 338 339 340 341 342 |
# File 'lib/arcade/base.rb', line 336 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
348 349 350 351 352 353 354 |
# File 'lib/arcade/base.rb', line 348 def to_or if rid? rid else to_json end end |
#update(**args) ⇒ Object
396 397 398 399 |
# File 'lib/arcade/base.rb', line 396 def update **args Query.new( from: rid , kind: :update, set: args).execute refresh end |
#update_embedded(embedded, embedded_property, value) ⇒ Object
updates a single property in an embedded document
414 415 416 |
# File 'lib/arcade/base.rb', line 414 def , , value db.execute{ " update #{rid} set `#{}`.`#{}` = #{value.to_or}" } end |
#update_list(list, value) ⇒ Object
418 419 420 421 422 423 424 425 426 427 428 429 430 |
# File 'lib/arcade/base.rb', line 418 def update_list list, value value = if value.is_a? Document value.to_json else value.to_or end if send( list ).nil? || send( list ).empty? db.execute { "update #{ rid } set #{ list } = [#{ value }]" } else db.execute { "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
433 434 435 436 437 438 439 440 |
# File 'lib/arcade/base.rb', line 433 def update_map m, key, value if send( m ).nil? db.execute { "update #{ rid } set #{ m } = MAP ( #{ key.to_s.to_or } , #{ value.to_or } ) " } else db.execute { "update #{ rid } set #{ m }.`#{ key.to_s }` = #{ value.to_or }" } end refresh end |