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.
- #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.
-
#fetch_each ⇒ Object
A combination of .fetch and .each.
-
#initialize(model, tasks = nil) ⇒ ArrayStore
constructor
A new instance of ArrayStore.
- #inspect ⇒ Object
- #limit(limit) ⇒ 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
-
#order(sort) ⇒ Object
.sort is already a ruby method, so we use order instead.
-
#query_listener ⇒ Object
Looks up the query listener for this ArrayStore.
-
#remove(ids) ⇒ Object
Called from the server when it removes an item.
-
#removed(model) ⇒ Object
Called when the client removes an item.
- #run_query ⇒ Object
- #skip(skip) ⇒ Object
-
#stop_listening ⇒ Object
Called when an event is removed and we no longer want to keep in sync with the database.
-
#where(query = nil) ⇒ Object
(also: #find)
Find takes a query object.
Methods inherited from Store
#clear_identity_map, #read_new_model, #saved?
Methods inherited from Base
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
233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 |
# File 'lib/volt/models/persistors/array_store.rb', line 233 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.
185 186 187 188 189 190 191 192 193 |
# File 'lib/volt/models/persistors/array_store.rb', line 185 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.
282 283 284 285 286 287 288 289 290 291 292 |
# File 'lib/volt/models/persistors/array_store.rb', line 282 def added(model, index) if model.persistor # Tell the persistor it was added, return the promise promise = model.persistor.add_to_collection # Track the the model got added @ids[model._id] = true promise end end |
#channel_name ⇒ Object
277 278 279 |
# File 'lib/volt/models/persistors/array_store.rb', line 277 def channel_name @model.path[-1] end |
#clear ⇒ Object
Called when all models are removed
273 274 275 |
# File 'lib/volt/models/persistors/array_store.rb', line 273 def clear @ids = {} end |
#event_added(event, first, first_for_event) ⇒ Object
Called when an each binding is listening
57 58 59 60 61 62 |
# File 'lib/volt/models/persistors/array_store.rb', line 57 def event_added(event, first, first_for_event) # First event, we load the data. if first @listener_event_counter.add end end |
#event_removed(event, last, last_for_event) ⇒ Object
Called when an each binding stops listening
65 66 67 68 69 70 |
# File 'lib/volt/models/persistors/array_store.rb', line 65 def event_removed(event, last, last_for_event) # Remove listener where there are no more events on this model if last @listener_event_counter.remove end 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.
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 |
# File 'lib/volt/models/persistors/array_store.rb', line 197 def fetch(&block) 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.new do |comp| if @model.loaded_state == :loaded promise.resolve(@model) comp.stop end end.watch! end promise end |
#fetch_each ⇒ Object
A combination of .fetch and .each. Returns the fetch promise
220 221 222 223 224 225 226 |
# File 'lib/volt/models/persistors/array_store.rb', line 220 def fetch_each fetch do |items| items.each do |item| yield(item) end end end |
#inspect ⇒ Object
52 53 54 |
# File 'lib/volt/models/persistors/array_store.rb', line 52 def inspect "<#{self.class.to_s}:#{object_id} #{@model.path.inspect} #{@query.inspect}>" end |
#limit(limit) ⇒ Object
168 169 170 |
# File 'lib/volt/models/persistors/array_store.rb', line 168 def limit(limit) add_query_part(:limit, limit) end |
#listener_added ⇒ Object
Called by child models to track their listeners
73 74 75 |
# File 'lib/volt/models/persistors/array_store.rb', line 73 def listener_added @listener_event_counter.add end |
#listener_removed ⇒ Object
Called by child models to track their listeners
78 79 80 |
# File 'lib/volt/models/persistors/array_store.rb', line 78 def listener_removed @listener_event_counter.remove end |
#load_data ⇒ Object
Called the first time data is requested from this collection
105 106 107 108 109 110 111 112 113 114 115 116 |
# File 'lib/volt/models/persistors/array_store.rb', line 105 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 |
#order(sort) ⇒ Object
.sort is already a ruby method, so we use order instead
177 178 179 |
# File 'lib/volt/models/persistors/array_store.rb', line 177 def order(sort) add_query_part(:sort, sort) end |
#query_listener ⇒ Object
Looks up the query listener for this ArrayStore
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 155 156 157 158 |
# File 'lib/volt/models/persistors/array_store.rb', line 129 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 && (attrs = parent.attributes) && attrs[:_id] query = query.dup query << [:find, {:"#{@model.path[-3].singularize}_id" => attrs[:_id]}] end end query = Query::Normalizer.normalize(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.
256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 |
# File 'lib/volt/models/persistors/array_store.rb', line 256 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 |
#removed(model) ⇒ Object
Called when the client removes an item
295 296 297 298 299 300 301 302 303 304 305 306 307 308 |
# File 'lib/volt/models/persistors/array_store.rb', line 295 def removed(model) if model.persistor # Tell the persistor it was removed model.persistor.remove_from_collection @ids.delete(model._id) end if defined?($loading_models) && $loading_models return else StoreTasks.delete(channel_name, model.attributes[:_id]) end end |
#run_query ⇒ Object
118 119 120 121 122 123 124 125 |
# File 'lib/volt/models/persistors/array_store.rb', line 118 def run_query unless @added_to_query @model.clear @added_to_query = true query_listener.add_store(self) end end |
#skip(skip) ⇒ Object
172 173 174 |
# File 'lib/volt/models/persistors/array_store.rb', line 172 def skip(skip) add_query_part(:skip, skip) 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.
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
# File 'lib/volt/models/persistors/array_store.rb', line 85 def stop_listening Timers.next_tick 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 |
#where(query = nil) ⇒ Object Also known as: find
Find takes a query object
161 162 163 164 165 |
# File 'lib/volt/models/persistors/array_store.rb', line 161 def where(query = nil) query ||= {} add_query_part(:find, query) end |