class Volt::Persistors::ArrayStore

Attributes

model[R]
root_dep[R]

Public Class Methods

new(model, tasks = nil) click to toggle source
Calls superclass method
# File lib/volt/models/persistors/array_store.rb, line 20
def initialize(model, tasks = nil)
  # Keep a hash of all ids in this collection
  @ids = {}

  super

  # The listener event counter keeps track of how many things are listening
  # on this model and loads/unloads data when in use.
  @listener_event_counter = EventCounter.new(
    -> { load_data },
    -> { stop_listening }
  )

  # The root dependency tracks how many listeners are on the ArrayModel
  # @root_dep = Dependency.new(@listener_event_counter.method(:add), @listener_event_counter.method(:remove))
  @root_dep = Dependency.new(method(:listener_added), method(:listener_removed))

  @query = @model.options[:query]
end
query_pool() click to toggle source
# File lib/volt/models/persistors/array_store.rb, line 16
def self.query_pool
  @@query_pool
end

Public Instance Methods

add(index, data) click to toggle source

Called from backend when an item is added

# File lib/volt/models/persistors/array_store.rb, line 219
def add(index, data)
  $loading_models = true

  Model.no_validate do
    data_id = data['id'] || data[:id]

    # Don't add if the model is already in the ArrayModel (from the client already)
    unless @ids[data_id]
      @ids[data_id] = true
      # Find the existing model, or create one
      new_model = @@identity_map.find(data_id) do
        new_options = @model.options.merge(path: @model.path + [:[]], parent: @model)
        @model.new_model(data, new_options, :loaded)
      end

      @model.insert(index, new_model)
    end
  end

  $loading_models = false
end
add_query_part(*args) click to toggle source

Add query part adds a [method_name, *arguments] array to the query. This will then be passed to the backend to run the query.

@return [Cursor] a new cursor

# File lib/volt/models/persistors/array_store.rb, line 160
def add_query_part(*args)
  opts = @model.options
  query = opts[:query] ? opts[:query].deep_clone : []
  query << args

  # Make a new opts hash with changed query
  opts = opts.merge(query: query)
  Cursor.new([], opts)
end
added(model, index) click to toggle source

Called when the client adds an item.

# File lib/volt/models/persistors/array_store.rb, line 268
def added(model, index)
  if model.persistor
    # Track the the model got added
    @ids[model.id] = true
  end
end
async?() click to toggle source
# File lib/volt/models/persistors/array_store.rb, line 293
def async?
  true
end
channel_name() click to toggle source
# File lib/volt/models/persistors/array_store.rb, line 263
def channel_name
  @model.path[-1]
end
clear() click to toggle source

Called when all models are removed

# File lib/volt/models/persistors/array_store.rb, line 259
def clear
  @ids = {}
end
event_added(event, first, first_for_event) click to toggle source

Called when an each binding is listening

# File lib/volt/models/persistors/array_store.rb, line 57
def event_added(event, first, first_for_event)
  # First event, we load the data.
  @listener_event_counter.add if first
end
event_removed(event, last, last_for_event) click to toggle source

Called when an each binding stops listening

# File lib/volt/models/persistors/array_store.rb, line 63
def event_removed(event, last, last_for_event)
  # Remove listener where there are no more events on this model
  @listener_event_counter.remove if last
end
fetch(&block) click to toggle source

Returns a promise that is resolved/rejected when the query is complete. Any passed block will be passed to the promises then. Then will be passed the model.

# File lib/volt/models/persistors/array_store.rb, line 192
def fetch(&block)
  Volt.logger.warn('Deprication warning: in 0.9.3.pre4, all query methods on store now return Promises, so you can juse use .all or .first instead of .fetch')
  promise = Promise.new

  # Run the block after resolve if a block is passed in
  promise = promise.then(&block) if block

  if @model.loaded_state == :loaded
    promise.resolve(@model)
  else
    proc do |comp|
      if @model.loaded_state == :loaded
        promise.resolve(@model)

        comp.stop
      end
    end.watch!
  end

  promise
end
Also aliased as: then
inspect() click to toggle source
# File lib/volt/models/persistors/array_store.rb, line 52
def inspect
  "<#{self.class}:#{object_id} #{@model.path.inspect} #{@query.inspect}>"
end
listener_added() click to toggle source

Called by child models to track their listeners

# File lib/volt/models/persistors/array_store.rb, line 69
def listener_added
  @listener_event_counter.add
end
listener_removed() click to toggle source

Called by child models to track their listeners

# File lib/volt/models/persistors/array_store.rb, line 74
def listener_removed
  @listener_event_counter.remove
end
load_data() click to toggle source

Called the first time data is requested from this collection

# File lib/volt/models/persistors/array_store.rb, line 101
def load_data
  Computation.run_without_tracking do
    loaded_state = @model.loaded_state

    # Don't load data from any queried
    if loaded_state == :not_loaded || loaded_state == :dirty
      @model.change_state_to(:loaded_state, :loading)

      run_query
    end
  end
end
loaded(initial_state = nil) click to toggle source
Calls superclass method Volt::Persistors::StoreState#loaded
# File lib/volt/models/persistors/array_store.rb, line 40
def loaded(initial_state = nil)
  super

  # Setup up the query listener, and if it is already listening, then
  # go ahead and load that data in.  This allows us to use it immediately
  # if the data is loaded in another place.
  if query_listener.listening
    query_listener.add_store(self)
    @added_to_query = true
  end
end
query_listener() click to toggle source

Looks up the query listener for this ArrayStore @query should be treated as immutable.

# File lib/volt/models/persistors/array_store.rb, line 125
def query_listener
  return @query_listener if @query_listener

  collection = @model.path.last
  query = @query

  # Scope to the parent
  if @model.path.size > 1
    parent = @model.parent

    parent.persistor.ensure_setup if parent.persistor

    if parent && !@model.is_a?(Cursor) && (attrs = parent.attributes) && attrs[:id]
      query = query.dup

      query << [:find, { :"#{@model.path[-3].singularize}_id" => attrs[:id] }]
    end
  end

  query = Volt::DataStore.adaptor_client.normalize_query(query)

  @query_listener ||= @@query_pool.lookup(collection, query) do
    # Create if it does not exist
    QueryListener.new(@@query_pool, @tasks, collection, query)
  end

  # @@query_pool.print

  @query_listener
end
remove(ids) click to toggle source

Called from the server when it removes an item.

# File lib/volt/models/persistors/array_store.rb, line 242
def remove(ids)
  $loading_models = true
  ids.each do |id|
    # TODO: optimize this delete so we don't need to loop
    @model.each_with_index do |model, index|
      if model.id == id
        @ids.delete(id)
        del = @model.delete_at(index)
        break
      end
    end
  end

  $loading_models = false
end
remove_tracking_id(model) click to toggle source
# File lib/volt/models/persistors/array_store.rb, line 286
def remove_tracking_id(model)
  if model.persistor
    # Tell the persistor it was removed
    @ids.delete(model.id)
  end
end
removed(model) click to toggle source

Called when the client removes an item

# File lib/volt/models/persistors/array_store.rb, line 276
def removed(model)
  remove_tracking_id(model)

  if defined?($loading_models) && $loading_models
    return
  else
    StoreTasks.delete(channel_name, model.attributes[:id])
  end
end
run_once_loaded() click to toggle source

Call a method on the model once the model is loaded. Return a promise that will resolve when the model is loaded

# File lib/volt/models/persistors/array_store.rb, line 172
def run_once_loaded
  promise = Promise.new

  if @model.loaded_state == :loaded
    promise.resolve(nil)
  else
    proc do |comp|
      if @model.loaded_state == :loaded
        promise.resolve(nil)

        comp.stop
      end
    end.watch!
  end

  promise
end
run_query() click to toggle source
# File lib/volt/models/persistors/array_store.rb, line 114
def run_query
  unless @added_to_query
    @model.clear

    @added_to_query = true
    query_listener.add_store(self)
  end
end
stop_listening() click to toggle source

Called when an event is removed and we no longer want to keep in sync with the database. The data is kept in memory and the model's loaded_state is marked as “dirty” meaning it may not be in sync.

# File lib/volt/models/persistors/array_store.rb, line 81
def stop_listening
  Timers.client_set_timeout(5000) do
    Computation.run_without_tracking do
      if @listener_event_counter.count == 0
        if @added_to_query
          @query_listener.remove_store(self)
          @query_listener = nil

          @added_to_query = nil
        end

        @model.change_state_to(:loaded_state, :dirty)
      end
    end
  end

  Timers.flush_next_tick_timers! if Volt.server?
end
then(&block)

Alias then for now TODO: Deprecate

Alias for: fetch