As we will be writing data in this chapter, here we will only cover how to write the PutResolver class for your entities. It is possible to generate them automatically, but it is also necessary to know how to write one yourself. This is often required in cases when the PutResolver involves modifying multiple database tables.
Create a class, named StockUpdatePutResolver, and make it extend DefaultPutResolver<StockUpdate>, as follows:
public class StockUpdatePutResolver extends
DefaultPutResolver<StockUpdate> {
DefaultPutResolver is an abstract class that extends the PutResolver interface and provides a convenient interface for mapping the data from domain objects to SQL data. This is done by implementing three methods:
- protected InsertQuery mapToInsertQuery(@NonNull T object);
- protected UpdateQuery mapToUpdateQuery(@NonNull T object);
- protected ContentValues mapToContentValues(@NonNull T object);
The first one (mapToInsertQuery()) is used to look up the right table where the data will be inserted. In our case, it must look like this:
@NonNull
@Override
protected InsertQuery mapToInsertQuery(@NonNull StockUpdate object) {
return InsertQuery.builder()
.table(StockUpdateTable.TABLE)
.build();
}
mapToUpdateQuery() is used to issue queries to look up whether the object that we are trying to save is already in the database or not. Our implementation for this method will be as follows:
@NonNull
@Override
protected UpdateQuery mapToUpdateQuery(@NonNull StockUpdate object) {
return UpdateQuery.builder()
.table(StockUpdateTable.TABLE)
.where(StockUpdateTable.Columns.ID + " = ?")
.whereArgs(object.getId())
.build();
}
We can see that, here, we are querying a StockUpdate table for the element that has a specific ID. If the element with that ID is found, it will be updated instead of it being inserted as a new entry.
Finally, the mapToContentValues() call maps the values from the domain object to the ContentValues object that the SQLite database can digest. We will implement that as the following:
@NonNull
@Override
protected ContentValues mapToContentValues(@NonNull StockUpdate entity) {
final ContentValues contentValues = new ContentValues();
contentValues.put(StockUpdateTable.Columns.ID, entity.getId());
contentValues.put(StockUpdateTable.Columns.STOCK_SYMBOL,
entity.getStockSymbol());
contentValues.put(StockUpdateTable.Columns.PRICE,
getPrice(entity));
contentValues.put(StockUpdateTable.Columns.DATE, getDate(entity));
return contentValues;
}
As you can see in the preceding code, the StockUpdate class now has an ID:
public class StockUpdate implements Serializable {
...
private Integer id;
....
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
}
The ID will be used to store the identifier retrieved from the database when an item is saved.
Note that StorIO (and Android's SQLite) cannot directly consume the BigDecimal data type that we use to store stock price and Date type. We will have to do a conversion to the appropriate types. For the sake of convenience, we will use the long data type, which can be easily digested by SQLite.
In the end, getPrice() will be as shown:
private long getPrice(@NonNull StockUpdate entity) {
return entity.getPrice().scaleByPowerOfTen(4).longValue();
}
In addition, getDate() will be as follows:
private long getDate(@NonNull StockUpdate entity) {
return entity.getDate().getTime();
}
Obviously, we will have to take similar steps to parse the long data type to its original format later.
We still haven't shown where the StockUpdatePutResolver class will be used. That will be covered in the section where we start configuring the StorIOSQLite interface.