Class: ReactiveRecord::ServerDataCache
- Defined in:
- lib/reactive_record/server_data_cache.rb
Overview
- Todo, [find, 119], owner, todos, active, *all
-
-> [[Todo, [find, 119], owner, todos, active, *all], [119, 123], 119, 12]
Defined Under Namespace
Classes: CacheItem
Instance Attribute Summary collapse
-
#cache ⇒ Object
readonly
Returns the value of attribute cache.
-
#cache_reps ⇒ Object
readonly
Returns the value of attribute cache_reps.
-
#requested_cache_items ⇒ Object
readonly
Returns the value of attribute requested_cache_items.
Class Method Summary collapse
- .[](models, associations, vectors, acting_user) ⇒ Object
- .get_model(str) ⇒ Object
- .load_from_json(tree, target = nil) ⇒ Object
- .start_timing(&block) ⇒ Object
- .timing(tag, &block) ⇒ Object
Instance Method Summary collapse
- #[](*vector) ⇒ Object
- #add_item_to_cache(item) ⇒ Object
- #as_json ⇒ Object
- #clear_requests ⇒ Object
- #detect(&block) ⇒ Object
-
#initialize(acting_user, preloaded_records) ⇒ ServerDataCache
constructor
A new instance of ServerDataCache.
- #inject(initial, &block) ⇒ Object
- #select(&block) ⇒ Object
- #start_timing(&block) ⇒ Object
- #timing(tag, &block) ⇒ Object
Constructor Details
#initialize(acting_user, preloaded_records) ⇒ ServerDataCache
Returns a new instance of ServerDataCache.
95 96 97 98 99 100 101 |
# File 'lib/reactive_record/server_data_cache.rb', line 95 def initialize(acting_user, preloaded_records) @acting_user = acting_user @cache = [] @cache_reps = {} @requested_cache_items = Set.new @preloaded_records = preloaded_records end |
Instance Attribute Details
#cache ⇒ Object (readonly)
Returns the value of attribute cache.
103 104 105 |
# File 'lib/reactive_record/server_data_cache.rb', line 103 def cache @cache end |
#cache_reps ⇒ Object (readonly)
Returns the value of attribute cache_reps.
104 105 106 |
# File 'lib/reactive_record/server_data_cache.rb', line 104 def cache_reps @cache_reps end |
#requested_cache_items ⇒ Object (readonly)
Returns the value of attribute requested_cache_items.
105 106 107 |
# File 'lib/reactive_record/server_data_cache.rb', line 105 def requested_cache_items @requested_cache_items end |
Class Method Details
.[](models, associations, vectors, acting_user) ⇒ Object
168 169 170 171 172 173 174 175 176 177 178 179 180 |
# File 'lib/reactive_record/server_data_cache.rb', line 168 def self.[](models, associations, vectors, acting_user) start_timing do timing(:public_columns_hash) { ActiveRecord::Base.public_columns_hash } result = nil ActiveRecord::Base.transaction do cache = new(acting_user, timing(:save_records) { ReactiveRecord::Base.save_records(models, associations, acting_user, false, false) }) timing(:process_vectors) { vectors.each { |vector| cache[*vector] } } timing(:as_json) { result = cache.as_json } raise ActiveRecord::Rollback, "This Rollback is intentional!" end result end end |
.get_model(str) ⇒ Object
115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
# File 'lib/reactive_record/server_data_cache.rb', line 115 def self.get_model(str) # We don't want to open a security hole by allowing some client side string to # autoload a class, which would happen if we did a simple str.constantize. # # Because all AR models are loaded at boot time on the server to define the # ActiveRecord::Base.public_columns_hash method any model which the client has # access to should already be loaded. # # If str is not already loaded then we have an access violation. unless const_defined? str Hyperloop::InternalPolicy.raise_operation_access_violation(:undefined_const, "#{str} is not a loaded constant") end str.constantize end |
.load_from_json(tree, target = nil) ⇒ Object
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 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 |
# File 'lib/reactive_record/server_data_cache.rb', line 415 def self.load_from_json(tree, target = nil) # have to process *all before any other items # we leave the "*all" key in just for debugging purposes, and then skip it below if sorted_collection = tree["*all"] target.replace sorted_collection.collect { |id| target.proxy_association.klass.find(id) } end if id_value = tree["id"] and id_value.is_a? Array target.id = id_value.first end tree.each do |method, value| method = JSON.parse(method) rescue method new_target = nil if method == "*all" next # its already been processed above elsif !target load_from_json(value, Object.const_get(method)) elsif method == "*count" target.set_count_state(value.first) elsif method.is_a? Integer or method =~ /^[0-9]+$/ new_target = target.push_and_update_belongs_to(method) #target << (new_target = target.proxy_association.klass.find(method)) elsif method.is_a? Array if method[0] == "new" new_target = ReactiveRecord::Base.lookup_by_object_id(method[1]) elsif !(target.class < ActiveRecord::Base) new_target = target.send(*method) # value is an array if scope returns nil, so we destroy the bogus record new_target.destroy and new_target = nil if value.is_a? Array else target.backing_record.update_simple_attribute([method], target.backing_record.convert(method, value.first)) end elsif target.class.respond_to?(:reflect_on_aggregation) && (aggregation = target.class.reflect_on_aggregation(method)) && !(aggregation.klass < ActiveRecord::Base) value = [aggregation.deserialize(value.first)] unless value.first.is_a?(aggregation.klass) target.send "#{method}=", value.first elsif value.is_a? Array # we cannot use target.send "#{method}=" here because it might be a server method, which does not have a setter # a better fix might be something like target._internal_attribute_hash[method] = ... target.backing_record.set_attr_value(method, value.first) unless method == :id elsif value.is_a? Hash and value[:id] and value[:id].first and association = target.class.reflect_on_association(method) # not sure if its necessary to check the id above... is it possible to for the method to be an association but not have an id? new_target = association.klass.find(value[:id].first) target.send "#{method}=", new_target elsif !(target.class < ActiveRecord::Base) new_target = target.send(*method) # value is an array if scope returns nil, so we destroy the bogus record new_target.destroy and new_target = nil if value.is_a? Array else new_target = target.send("#{method}=", target.send(method)) end load_from_json(value, new_target) if new_target end rescue Exception => e # debugger raise e end |
.start_timing(&block) ⇒ Object
148 149 150 151 152 153 154 155 156 157 158 159 160 |
# File 'lib/reactive_record/server_data_cache.rb', line 148 def self.start_timing(&block) @timings = Hash.new { |h, k| h[k] = 0 } start_time = Time.now yield.tap do ::Rails.logger.debug "********* Total Time #{total = Time.now - start_time} ***********************" sum = 0 @timings.sort_by(&:last).reverse.each do |tag, time| ::Rails.logger.debug " #{tag}: #{time} (#{(time/total*100).to_i})%" sum += time end ::Rails.logger.debug "********* Other Time ***********************" end end |
Instance Method Details
#[](*vector) ⇒ Object
130 131 132 133 134 135 136 137 138 |
# File 'lib/reactive_record/server_data_cache.rb', line 130 def [](*vector) timing('building cache_items') do root = CacheItem.new(self, @acting_user, vector[0], @preloaded_records) vector[1..-1].inject(root) { |cache_item, method| cache_item.apply_method method if cache_item } final = vector[1..-1].inject(root) { |cache_item, method| cache_item.apply_method method if cache_item } next final unless final && final.value.respond_to?(:superclass) && final.value.superclass <= ActiveRecord::Base Hyperloop::InternalPolicy.raise_operation_access_violation(:invalid_vector, "attempt to insecurely access relationship #{vector.last}.") end end |
#add_item_to_cache(item) ⇒ Object
107 108 109 110 111 |
# File 'lib/reactive_record/server_data_cache.rb', line 107 def add_item_to_cache(item) cache << item cache_reps[item.vector] = item requested_cache_items << item end |
#as_json ⇒ Object
186 187 188 189 190 |
# File 'lib/reactive_record/server_data_cache.rb', line 186 def as_json @requested_cache_items.inject({}) do |hash, cache_item| hash.deep_merge! cache_item.as_hash end end |
#clear_requests ⇒ Object
182 183 184 |
# File 'lib/reactive_record/server_data_cache.rb', line 182 def clear_requests @requested_cache_items = Set.new end |
#detect(&block) ⇒ Object
194 |
# File 'lib/reactive_record/server_data_cache.rb', line 194 def detect(&block); @cache.detect(&block); end |
#inject(initial, &block) ⇒ Object
196 |
# File 'lib/reactive_record/server_data_cache.rb', line 196 def inject(initial, &block); @cache.inject(initial) █ end |
#select(&block) ⇒ Object
192 |
# File 'lib/reactive_record/server_data_cache.rb', line 192 def select(&block); @cache.select(&block); end |
#start_timing(&block) ⇒ Object
140 141 142 |
# File 'lib/reactive_record/server_data_cache.rb', line 140 def start_timing(&block) ServerDataCache.start_timing(&block) end |
#timing(tag, &block) ⇒ Object
144 145 146 |
# File 'lib/reactive_record/server_data_cache.rb', line 144 def timing(tag, &block) ServerDataCache.timing(tag, &block) end |