The store collection backs data in the database. Currently, the only supported database is Mongo. (More coming soon, RethinkDb and Postgres will probably be next). Because store
sometimes need to wait for data to come back from the server, all query methods on store
return a Promise. If you are new to promises, be sure to read more about Opal's promises before continuing.
In Volt, you can access store
on the front-end and the back-end. Data will automatically be synced between the browser and the server. Any changes to the data in store
will be reflected on any clients using the data (unless a buffer is in use - see below).
store._items.create({name: 'Item 1'})
# => #<Promise(70297824266280): #<Volt::Model id: "9a46..5dd7", name: "Item 1">>
store._items[0]
# => #<Promise(70297821413860): #<Volt::Model id: "9a46..5dd7", name: "Item 1">>
Calling create
(or append
, or <<
) on store._items
will create an items
table in the data store (if it doesn't exist) and insert the model document into it. A globally unique id
will be generated automatically.
In order to support asynchronus loading, methods on store ArrayModels return promises. If you want to work with the results of a query, you can call .then on it.
store._items.first.then do |item|
# work with item
end
See here for more information on promises in ruby/opal.
Promises can be passed to bindings and the bindings will update with the value once the promise resolves. This means you can do something like the following:
{{ store._items.first.then {|i| i._name } }}
This would grab the first item, then return its name once it resolves. This also preserves the reactivity, since if the first item changes, it will re-run the binding all together and re-resolve.
To make the above example simpler, Volt extends promises so you can call methods directly on the promise and it will call the method on the resolved value once the promise resolved. The following are the semantically the same:
store._items.first.then {|i| i._name }
store._items.first._name
Promise method forwarding only works on methods not already defined on the Promise class. Currently the following methods are defined on Promise. (The plan is to redo the Promise class at some point to remove most of these)
error, prev, next, value, act?, action, exception?, realized?, resolved?, rejected?, ^, <<, >>, resolve, resolve!, reject, reject!, exception!, then, do, fail, rescue, catch, always, finally, ensure, trace, inspect, method_missing, each, value_or_error, to_json, unwrap, sync
The ones you may run into are .to_json and .inspect
If you are working with store on the server only (in tasks for example), you can call .sync
on a Promise to have it synchronusly resolve and return the result. If the promise is rejected, .sync
will raise an error.
# Remember this only works on the server or console
store._items.create({name: 'Item 1'})
# .sync blocks until the items are loaded
store._items.first.sync
# => #<Volt::Model id: "3607..a0b0", name: "Item 1">
store._items.size.sync
# => 1
Currently store persists to a mongodb database. We are working on adding a data provider api that will allow support for any data store. Volt currently supports the following query methods:
.where
passes down its arguments to a mongodb .find
call.
.limit
lets you restrict how many results you want.
.skip
says how many items in you want to start fetching. So store._items.skip(5).limit(10) would grab items 5-15.
.order
passes its arguments to a mongodb .sort
call. Since .sort
is already a method on ruby's Enum class, we use .order
instead.
Because there is a delay when syncing data to the server, store models provide a loaded_state
method that can be used to determine if the model is in the process of loading.
state | description |
---|---|
not_loaded | data is not loaded |
loading | model is fetching data from the server |
loaded | data is loaded and no changes are unsynced |
dirty | the data was loaded, but it is no longer being kept in sync with the server |