A Query object defines intrinsically how data must be manipulated, containing inside all parameters required to execute the action.

The base definition of a query is empty, as this object must be customized in custom objects.

open class Query

For example, if one or many data sources can perform a serch by text, we would define a new query called SearchQuery as follows:

class SearchQuery(val text: String): Query()
// Searching in network
itemsNetworkDataSource.getAll(SearchQuery("lorem ipsum"))
// Searching in local storage
itemsStorageDataSource.getAll(SearchQuery("lorem ipsum"))

A query must be decoupled from any data source implementation.

Take for example a query called LastBookReadNerworkQuery. This is a bad naming as it clearly states a data source implementation. Instead use LastBookReadQuery as queries must be abstracted from its source and can potentially be reused in multiple data sources.

Default implementations

Harmony provides multiple predefined queries ready to be used. The most popular are:

  • VoidQuery: Empty query.
  • IdQuery: Query by id.
  • IdsQuery: Query containing a collection of Ids.
  • PaginationOffsetLimitQuery: Pagination query by offset and limit.

Specifically, IdQuery is very useful to identify objects by its id. For example, instead of having a UserIdQuery and call it into a UserNetworkDataSource (or any other user-based data source), just use IdQuery with the id of a user.

Review your Harmony platform library to find the complete list of queries available.

KeyQuery support

In an effort to build a friendly key-value ecosystem for data sources, Harmony defines the concept of KeyQuery as a subclass/subinteface of Query that exposes an string key attribute that can be used as a key for a key-value interface.

open class KeyQuery(val key: String) : Query()

For example, the Harmony predefined IdQuery<T> adopts KeyQuery and is ready to be used in key-value data sources.


It's a good practice to build your queries by either inheriting from already existing queries or by adopting KeyQuery.

By doing it so, you will ensure your queries reuse the most amount of attributes and data sources will easily support existing queries out of the box.


Only queries adopting KeyQuery can be used in key-value-based data sources.

Coming back to the SearchQuery example, we could now make it adopt KeyQuery, bringing us the option to use key-value-based data sources as InMemoryDataSource to cache results and improve performance of our system.

class SearchQuery(val text: String): KeyQuery(text)