- Enginio Manual
- Enginio C++ Classes and Examples
- EnginioModel
- Enginio 1.2.1 Reference Documentation

# EnginioModel Class

EnginioModel represents data from Enginio as a QAbstractListModel. More...

Header: | #include <EnginioModel>
Since: | Qt 5.3
Inherits: |

- List of all members, including inherited members

## Properties

- client : EnginioClient *
- operation : Enginio::Operation
- query : QJsonObject

## Public Functions

| EnginioModel(QObject * parent = 0)
| ~EnginioModel()
EnginioReply * | append(const QJsonObject & object)
EnginioClient * | client() const
Enginio::Operation | operation() const
QJsonObject | query()
EnginioReply * | reload()
EnginioReply * | remove(int row)
void | setClient(const EnginioClient * client)
EnginioReply * | setData(int row, const QVariant & value, const QString & role)
EnginioReply * | setData(int row, const QJsonObject & value)
void | setOperation(Enginio::Operation operation)
void | setQuery(const QJsonObject & query)

## Signals

void | clientChanged(EnginioClient * client)
void | operationChanged(Enginio::Operation operation)
void | queryChanged(const QJsonObject & query)

## Detailed Description

EnginioModel represents data from Enginio as a QAbstractListModel.

EnginioModel is a QAbstractListModel, together with a view it allows to show the result of a query in a convenient way. The model executes query, update and create operations asynchronously on an Enginio backend collection, which allows not only to read data from the cloud but also modify it.

The simplest type of query is:

    { "objectType": "objects.fruits" }

Assigning such a query to the model results in downloading of all objects from the "objects.fruits" collection. It is possible to append new objects, to modify or to remove them.

The query has to result in a list of objects, each object becomes an item in the model. Properties of the items are used as role names. There are a few predefined role names that will always be available (Role).

The operations are executed asynchronously, which means that user interface is not blocked while the model is initialized and updated. Every modification is divided in two steps; request and confirmation. For example when append is called EnginioModel returns immediately as if the operation had succeeded. In the background it waits for confirmation from the backend and only then the operation is really finished. It may happen that operation fails, for example because of insufficient access rights, in that case the operation will be reverted.

There are two, ways of tracking if an item state is the same in the model and backend. Each item has a role that returns a boolean SyncedRole, role name "_synced" which indicates whether the item is successfully updated on the server. This role can for example meant to be used for a busy indicator while a property is being updated. Alternatively the status of each EnginioReply returned by EnginioModel can be tracked. The operation is confirmed when the reply is finished without error.

When a reply is finished it is the user's responsibility to delete it, it can be done by connecting the finished signal to deleteLater.

    QObject::connect(reply, &EnginioReply::finished, reply, &EnginioReply::deleteLater);

Note: it is not safe to use the delete operator directly in finished.

Note: EnginioClient emits the finished and error signals for the model, not the model itself.

The query can contain one or more options: The "sort" option, to get presorted data:

    {
      "objectType": "objects.fruits",
      "sort": [{"sortBy":"price", "direction": "asc"}]
    }

The "query" option is used for filtering:

    {
      "objectType": "objects.fruits",
      "query": {"name": {"$in": ["apple", "orange", "kiwi"]}}
    }

The "limit" option to limit the amount of results:

    {
      "objectType": "objects.fruits",
      "limit": 10
    }

The "offset" option to skip some results from the beginning of a result set:

    {
      "objectType": "objects.fruits",
      "offset": 10
    }

The options are valid only during the initial model population and are not enforced in anyway when updating or otherwise modifying the model data. QSortFilterProxyModel can be used to do more advanced sorting and filtering on the client side.

EnginioModel can not detect when a property of a result is computed by the backend. For example the "include" option to query fills in the original creator of and object with the full object representing the "creator".

    {
      "objectType": "objects.fruits",
      "include": {"creator": {}}
    }

For the model the "creator" property is not longer a reference (as it is on the backend), but a full object. But while the full object is accessible, attempts to alter the object's data will fail.

## Property Documentation

### client : EnginioClient *

This property holds the EnginioClient used by the model.

Access functions:

EnginioClient * | client() const
void | setClient(const EnginioClient * client)

Notifier signal:

void | clientChanged(EnginioClient * client)

See also EnginioClient.

### operation : Enginio::Operation

This property holds the operation type of the query.

Access functions:

Enginio::Operation | operation() const
void | setOperation(Enginio::Operation operation)

Notifier signal:

void | operationChanged(Enginio::Operation operation)

See also Enginio::Operation and query().

### query : QJsonObject

This property holds the query used to populate the model with data from the backend.

See EnginioClient::query() documentation for information on how to construct a query.

While the EnginioClient implementation of `query()` returns the data of a query as a JSON object, for the model the query will be interpreted as the model data.

Usually, the query is for a single object type and will return all objects in the database of that type. The model will then represent each returned object as one row. It can be limited and sorted just like its counterpart in EnginioClient.

One important thing to note is that the model cannot keep the same sorting as the backend, and thus sorting and limits are only preserved until an insertion or deletion happens.

Access functions:

QJsonObject | query()
void | setQuery(const QJsonObject & query)

Notifier signal:

void | queryChanged(const QJsonObject & query)

See also EnginioClient::query().

## Member Function Documentation

### EnginioModel::EnginioModel(QObject * parent = 0)

Constructs a new model with parent as QObject parent.

### EnginioModel::~EnginioModel()

Destroys the model.

### EnginioReply * EnginioModel::append(const QJsonObject & object)

Add a new object to the model and database.

This function appends the new object to the local model cache and makes an asynchronous request to the backend.

Since adding an object to the database may fail for various reasons, the returned reply must be kept and used for error handling (see EnginioReply). If the operation fails, the object that was supposed to be appended will be removed from the local model again. If the model is used in a view and the backend does not accept the object because it violates a validator, it will be visible to the user that a new row in the view appears and disappears again.

Returns the EnginioReply from the backend

See also EnginioClient::create().

### EnginioReply * EnginioModel::reload()

Reload the model data from the server. This is similar to reset and will emit modelAboutToBeReset() and modelReset(). This function invalidated the internal state of the model, reloads it from the backend and resets all views.

Note: when using this function while other requests to the server are made the result is undefined. For example when calling append() and then reset() before append finished, the model may or may not contain the result of the append operation.

Returns reply from backend

This function was introduced in Qt 1.1.

### EnginioReply * EnginioModel::remove(int row)

Removes the row from the model and database.

This function immediately removes the row from the local cache and sends a remove request to the Enginio backend.

Returns the EnginioReply from the backend.

See also EnginioClient::remove().

### EnginioReply * EnginioModel::setData(int row, const QVariant & value, const QString & role)

Update a value on row of this model's local cache and send an update request to the Enginio backend.

The role is the property of the object that will be updated to be the new value.

Returns reply from backend.

See also EnginioClient::update().

### EnginioReply * EnginioModel::setData(int row, const QJsonObject & value)

This is an overloaded function.

Update a value on row of this model's local cache and send an update request to the Enginio backend.

All properties of the value will be used to update the item in row. This can be useful to update multiple item's properties with one request.

Returns reply from backend

See also EnginioClient::update().