class Volt::ArrayModel
Attributes
Public Class Methods
# File lib/volt/models/array_model.rb, line 89 def initialize(array = [], options = {}) @options = options @persistor = setup_persistor(options[:persistor]) array = wrap_values(array) super(array) if @persistor @persistor.loaded else change_state_to(:loaded_state, :loaded, false) end end
# File lib/volt/models/array_model.rb, line 306 def self.process_class_name(name) name.pluralize end
Some methods get passed down to the persistor.
# File lib/volt/models/array_model.rb, line 75 def self.proxy_to_persistor(*method_names) method_names.each do |method_name| define_method(method_name) do |*args, &block| if @persistor.respond_to?(method_name) @persistor.send(method_name, *args, &block) else fail "this model's persistance layer does not support #{method_name}, try using store" end end end end
For many methods, we want to register a dependency on the root_dep as soon as the method is called, so it can begin loading. Also, some persistors need to have special loading logic (such as returning a promise instead of immediately returning). To accomplish this, we call the run_once_loaded method on the persistor.
# File lib/volt/models/array_model.rb, line 24 def self.proxy_with_load(*method_names) imethods = instance_methods(false) method_names.each do |method_name| # Sometimes we want to alias a method_missing method, so we use super # instead to call it, if its not defined locally. if imethods.include?(method_name) imethod = true old_method_name = :"__old_#{method_name}" alias_method(old_method_name, method_name) else imethod = false end define_method(method_name) do |*args, &block| if imethod call_orig = proc do |*args| send(old_method_name, *args) end else call_orig = proc do |*args| super(*args) end end # track on the root dep persistor.try(:root_dep).try(:depend) if persistor.respond_to?(:run_once_loaded) && !Volt.in_mode?(:no_model_promises) promise = persistor.run_once_loaded.then do # We are already loaded and the result is going to be wrapped Volt.run_in_mode(:no_model_promises) do call_orig.call(*args) end end if block promise = promise.then do |val| block.call(val) end end promise else call_orig.call(*args) end end end end
Public Instance Methods
Make sure it gets wrapped
# File lib/volt/models/array_model.rb, line 232 def +(*args) args = wrap_values(args) super(*args) end
Make sure it gets wrapped
# File lib/volt/models/array_model.rb, line 132 def <<(model) create_new_model(model, :<<) end
Return the model, on store, .all is proxied to wait for load and return a promise.
# File lib/volt/models/array_model.rb, line 215 def all self end
Works like << except it always returns a promise
# File lib/volt/models/array_model.rb, line 139 def append(model) create_new_model(model, :append) end
# File lib/volt/models/array_model.rb, line 120 def attributes self end
# File lib/volt/models/array_model.rb, line 285 def buffer(attrs = {}) model_path = options[:path] + [:[]] model_klass = Volt::Model.class_at_path(model_path) new_options = options.merge(path: model_path, save_to: self, buffer: true).reject { |k, _| k.to_sym == :persistor } model = model_klass.new(attrs, new_options) model end
# File lib/volt/models/array_model.rb, line 311 def count(&block) all.reactive_count(&block) end
Create does append with a default empty model
# File lib/volt/models/array_model.rb, line 144 def create(model={}) create_new_model(model, :create) end
# File lib/volt/models/array_model.rb, line 149 def delete(val) # Check to make sure the models are allowed to be deleted if !val.is_a?(Model) # Not a model, return as a Promise super(val).then else val.can_delete?.then do |can_delete| if can_delete super(val) else Promise.new.reject("permissions did not allow delete for #{val.inspect}.") end end end end
Raise a RecordNotFoundException
if the promise returns a nil.
# File lib/volt/models/array_model.rb, line 296 def fail_not_found_if_nil(promise) promise.then do |val| if val val else raise RecordNotFoundException.new end end end
returns a promise to fetch the first instance
# File lib/volt/models/array_model.rb, line 220 def fetch_first(&block) Volt.logger.warn('.fetch_first is deprecated in favor of .first') first end
# File lib/volt/models/array_model.rb, line 165 def first if persistor.is_a?(Persistors::ArrayStore) limit(1)[0] else self[0] end end
Same as first, except it returns a promise (even on page collection), and it fails with a RecordNotFoundException
if no result is found.
# File lib/volt/models/array_model.rb, line 175 def first! fail_not_found_if_nil(first) end
Return the first item in the collection, or create one if one does not exist yet.
# File lib/volt/models/array_model.rb, line 181 def first_or_create first.then do |item| if item item else create end end end
# File lib/volt/models/array_model.rb, line 237 def flatten(*args) wrap_values(to_a.flatten(*args)) end
Make sure it gets wrapped
# File lib/volt/models/array_model.rb, line 226 def inject(*args) args = wrap_values(args) super(*args) end
# File lib/volt/models/array_model.rb, line 273 def inspect # Track on size @size_dep.depend str = "#<#{self.class}" # str += " state:#{loaded_state}" # str += " path:#{path.join('.')}" if path # str += " persistor:#{persistor.inspect}" if persistor str += " #{@array.inspect}>" str end
# File lib/volt/models/array_model.rb, line 191 def last self[-1] end
# File lib/volt/models/array_model.rb, line 246 def new_array_model(*args) Volt::ArrayModel.class_at_path(options[:path]).new(*args) end
# File lib/volt/models/array_model.rb, line 241 def new_model(*args) Volt::Model.class_at_path(options[:path]).new(*args) end
# File lib/volt/models/array_model.rb, line 104 def parent=(val) @options[:parent] = val end
# File lib/volt/models/array_model.rb, line 116 def path=(val) @options[:path] = val end
# File lib/volt/models/array_model.rb, line 195 def reverse @size_dep.depend @array.reverse end
Array#select, with reactive notification
# File lib/volt/models/array_model.rb, line 201 def select new_array = [] @array.size.times do |index| value = @array[index] if yield(value) new_array << value end end new_array end
Volt::StateManager#state_for
# File lib/volt/models/array_model.rb, line 124 def state_for(*args) # Track on root dep persistor.try(:root_dep).try(:depend) super end
Convert the model to an array all of the way down
# File lib/volt/models/array_model.rb, line 251 def to_a @size_dep.depend array = [] Volt.run_in_mode(:no_model_promises) do attributes.size.times do |index| array << deep_unwrap(self[index]) end end array end
# File lib/volt/models/array_model.rb, line 262 def to_json array = to_a if array.is_a?(Promise) array.then(&:to_json) else array.to_json end end
Private Instance Methods
called form <<, append, and create. If a hash is passed in, it converts it to a model. Then it takes the model and inserts it into the ArrayModel
then persists it.
# File lib/volt/models/array_model.rb, line 319 def create_new_model(model, from_method) if model.is_a?(Model) if model.buffer? fail "The #{from_method} does not take a buffer. Call .save! on buffer's to persist them." end # Set the new path and the persistor. model.options = @options.merge(parent: self, path: @options[:path] + [:[]]) else model = wrap_values([model]).first end if model.is_a?(Model) promise = model.can_create?.then do |can_create| unless can_create fail "permissions did not allow create for #{model.inspect}" end end.then do # Add it to the array and trigger any watches or on events. reactive_array_append(model) @persistor.added(model, @array.size - 1) end.then do nil.then do # Validate and save model.run_changed end.then do # Mark the model as not new model.instance_variable_set('@new', false) # Mark the model as loaded model.change_state_to(:loaded_state, :loaded) end.fail do |err| # remove from the collection because it failed to save on the server # we don't need to call delete on the server. index = @array.index(model) delete_at(index, true) # remove from the id list @persistor.try(:remove_tracking_id, model) # re-raise, err might not be an Error object, so we use a rejected promise to re-raise Promise.new.reject(err) end end else promise = nil.then do # Add it to the array and trigger any watches or on events. reactive_array_append(model) @persistor.added(model, @array.size - 1) end end promise = promise.then do # resolve the model model end # unwrap the promise if the persistor is synchronus. # This will return the value or raise the exception. promise = promise.unwrap unless @persistor.async? # return promise end