A DAO, or Data Access Object, is a universal interface to a collection of objects.
The guides for DAOs are split into three parts.
Here, we show many examples of manipulating DAOs.
Below, we discuss the
Finally, there is a separate DAO authorship guide.
Basic DAO operations
Note that all these operations are asynchronous, not just those that return
All of the operations take a
sink, whose interface is detailed below. Various
functions on the
sink are called asynchronously when operations are complete,
and data is available.
There are four more DAO operations that synchronously return modified DAOs. They essentially return a window onto part of the data stored in the original DAO. They can filter, sort, limit results, and skip early results.
These operations can be easily chained:
Sink interface is a target for data retrieved from a DAO. Its functions
are called asynchronously by the DAO.
When each of these is called is detailed as we summarize the DAO operations below.
Retrieves a single object from the DAO, whose
id is given.
If the object is found,
sink.put(obj) is called. If the object is not found,
sink.error is called instead.
Inserts a new object, or updates an existing one. The interface makes no
distinction. Many backends also don’t care, and DAO implementations for those
backends which do care may perform a
find() first to check if the object
When the object is stored successfully,
sink.put(newObj) is called. Why return
the object? Because the DAO is free to modify the object if necessary - filling
in an autoincremented
id, or a default value, or otherwise massaging the data.
Deletes a single object from the DAO.
If the removal is successful,
sink.remove(obj) is called.
NB: Trying to remove an object which does not exist is not an error.
remove() only calls
sink.error if it fails to communicate with the backend
in some fashion.
This is the main event.
select(sink) retrieves a collection of results from
the DAO. If unfiltered,
select() returns everything in the DAO.
limit() will be used first, to
limit the scope of the
options is almost never manipulated directly. The DAOs returned by
where() and friends are actually small wrappers around the original DAO that
options on a
sink.put(obj) repeatedly, once for each object retrieved. It
removeAll() return a
Future<Sink>, that is, a future whose
value is the same
sink passed in to
select(). That future resolves when
select() is completely done, at the same time as
sink.eof() is called.
removeAll() is very similar to
select(), with the obvious exception that it
removes all matching entries from the DAO instead of returning them.
myDAO.removeAll() without any filtering will delete every entry.
sink.remove(obj) whenever objects are
remove()d from the DAO. This can be used to log all changes, for
listen() will continue streaming results indefinitely.
listen() is filtered just like
myDAO.where(...).listen() will only listen for objects matching the query.
Stops streaming results to the provided
sink, which was previously passed to
pipe() is essentially
select() followed by
listen(): it returns all
currently stored objects, and then streams
remove events like
where(query) returns a new DAO that is a filtered window onto the data in the
query is structured using FOAM’s mLang syntax. This is a structured,
found in the DAO examples page.
orderBy(order) uses a small subset of mLang syntax (see
where() above) to
specify a sort order.
myDAO.orderBy(this.MyModel.NAME) myDAO.orderBy(DESC(this.MyModel.CREATED_TIME)) myDAO.orderBy(DESC(this.MyModel.RANK), this.MyModel.LAST_NAME, this.MyModel.FIRST_NAME)
Limits the maximum number of requests returned by the DAO. Mostly useful for paging results and infinite scrolling.
Ignores the first
num results from the DAO (according to the sort order).
Useful for paging and infinite scrolling.