Class: Volt::Persistors::ArrayStore
- Includes:
- StoreState
- Defined in:
- lib/volt/models/persistors/array_store.rb
Constant Summary collapse
- @@query_pool =
QueryListenerPool.new
Instance Attribute Summary collapse
-
#model ⇒ Object
readonly
Returns the value of attribute model.
-
#root_dep ⇒ Object
readonly
Returns the value of attribute root_dep.
Class Method Summary collapse
Instance Method Summary collapse
-
#add(index, data) ⇒ Object
Called from backend when an item is added.
-
#add_query_part(*args) ⇒ Cursor
Add query part adds a [method_name, *arguments] array to the query.
-
#added(model, index) ⇒ Object
Called when the client adds an item.
- #async? ⇒ Boolean
- #channel_name ⇒ Object
-
#clear ⇒ Object
Called when all models are removed.
-
#event_added(event, first, first_for_event) ⇒ Object
Called when an each binding is listening.
-
#event_removed(event, last, last_for_event) ⇒ Object
Called when an each binding stops listening.
-
#fetch(&block) ⇒ Object
(also: #then)
Returns a promise that is resolved/rejected when the query is complete.
-
#initialize(model, tasks = nil) ⇒ ArrayStore
constructor
A new instance of ArrayStore.
- #inspect ⇒ Object
-
#listener_added ⇒ Object
Called by child models to track their listeners.
-
#listener_removed ⇒ Object
Called by child models to track their listeners.
-
#load_data ⇒ Object
Called the first time data is requested from this collection.
- #loaded(initial_state = nil) ⇒ Object
-
#query_listener ⇒ Object
Looks up the query listener for this ArrayStore.
-
#remove(ids) ⇒ Object
Called from the server when it removes an item.
- #remove_tracking_id(model) ⇒ Object
-
#removed(model) ⇒ Object
Called when the client removes an item.
-
#run_once_loaded ⇒ Object
Call a method on the model once the model is loaded.
- #run_query ⇒ Object
-
#stop_listening ⇒ Object
Called when an event is removed and we no longer want to keep in sync with the database.
Methods inherited from Store
#clear_identity_map, #read_new_model, #saved?
Methods inherited from Base
#auto_generate_id, #changed, #root_model
Constructor Details
#initialize(model, tasks = nil) ⇒ ArrayStore
Returns a new instance of ArrayStore.
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
# 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.[:query] end |
Instance Attribute Details
#model ⇒ Object (readonly)
Returns the value of attribute model.
14 15 16 |
# File 'lib/volt/models/persistors/array_store.rb', line 14 def model @model end |
#root_dep ⇒ Object (readonly)
Returns the value of attribute root_dep.
14 15 16 |
# File 'lib/volt/models/persistors/array_store.rb', line 14 def root_dep @root_dep end |
Class Method Details
.query_pool ⇒ Object
16 17 18 |
# File 'lib/volt/models/persistors/array_store.rb', line 16 def self.query_pool @@query_pool end |
Instance Method Details
#add(index, data) ⇒ Object
Called from backend when an item is added
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 |
# 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 = @model..merge(path: @model.path + [:[]], parent: @model) @model.new_model(data, , :loaded) end @model.insert(index, new_model) end end $loading_models = false end |
#add_query_part(*args) ⇒ Cursor
Add query part adds a [method_name, *arguments] array to the query. This will then be passed to the backend to run the query.
160 161 162 163 164 165 166 167 168 |
# File 'lib/volt/models/persistors/array_store.rb', line 160 def add_query_part(*args) opts = @model. 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) ⇒ Object
Called when the client adds an item.
268 269 270 271 272 273 |
# 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? ⇒ Boolean
293 294 295 |
# File 'lib/volt/models/persistors/array_store.rb', line 293 def async? true end |
#channel_name ⇒ Object
263 264 265 |
# File 'lib/volt/models/persistors/array_store.rb', line 263 def channel_name @model.path[-1] end |
#clear ⇒ Object
Called when all models are removed
259 260 261 |
# File 'lib/volt/models/persistors/array_store.rb', line 259 def clear @ids = {} end |
#event_added(event, first, first_for_event) ⇒ Object
Called when an each binding is listening
57 58 59 60 |
# 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) ⇒ Object
Called when an each binding stops listening
63 64 65 66 |
# 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) ⇒ Object Also known as: then
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.
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 |
# 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 |
#inspect ⇒ Object
52 53 54 |
# File 'lib/volt/models/persistors/array_store.rb', line 52 def inspect "<#{self.class}:#{object_id} #{@model.path.inspect} #{@query.inspect}>" end |
#listener_added ⇒ Object
Called by child models to track their listeners
69 70 71 |
# File 'lib/volt/models/persistors/array_store.rb', line 69 def listener_added @listener_event_counter.add end |
#listener_removed ⇒ Object
Called by child models to track their listeners
74 75 76 |
# File 'lib/volt/models/persistors/array_store.rb', line 74 def listener_removed @listener_event_counter.remove end |
#load_data ⇒ Object
Called the first time data is requested from this collection
101 102 103 104 105 106 107 108 109 110 111 112 |
# 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) ⇒ Object
40 41 42 43 44 45 46 47 48 49 50 |
# 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 ⇒ Object
Looks up the query listener for this ArrayStore
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 |
# 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) ⇒ Object
Called from the server when it removes an item.
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 |
# 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) ⇒ Object
286 287 288 289 290 291 |
# 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) ⇒ Object
Called when the client removes an item
276 277 278 279 280 281 282 283 284 |
# 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 ⇒ Object
Call a method on the model once the model is loaded. Return a promise that will resolve when the model is loaded
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 |
# 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 ⇒ Object
114 115 116 117 118 119 120 121 |
# 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 ⇒ Object
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.
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
# 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 |