class AbstractDynamoDao extends AbstractDao<M,P,K,I> {

    protected UpdateItemSpec toUpdateItemSpec(K id, Update<P> update, Instant updateAt, I updaterId) {
        String updateExpression = "";
        NameMap nameMap = new NameMap();
        ValueMap valueMap = new ValueMap();

        Item setFields = partialMapper.toItem(update.getPartial());
        Map<String,Object> set = new LinkedHashMap<>();
        for (String field : update.getSetFields()) {
            set.put(field, setFields.get(field));
        }

        // add the @UpdatedBy and @UpdatedAt fields
        Field updatedByField = getFieldData().getUpdatedBy();
        if (updatedByField != null && updaterId != null) {
            set.put(updatedByField.getStorageName(), toStorageValue(updaterId));
        }
        Field updatedAtField = getFieldData().getUpdatedAt();
        if (updatedAtField != null && updateAt != null) {
            set.put(updatedAtField.getStorageName(), toStorageValue(updateAt));
        }

        for (Map.Entry<String,Object> e : set.entrySet()) {
            String key = e.getKey();
            nameMap.put("#" + key, key);
            valueMap.put(":" + key, toStorageValue(e.getValue()));
            updateExpression += "#" + key + " = :" + key + ", ";
        }
        if (updateExpression.length() > 0) {
            updateExpression = "SET " + updateExpression.substring(0, updateExpression.length()-2);
        }

        if (update.getRemoveFields().size() > 0) {
            updateExpression += " REMOVE ";
            for (String key : update.getRemoveFields()) {
                nameMap.put("#" + key, key);
                updateExpression += "#" + key + ", ";
            }
            updateExpression = updateExpression.substring(0, updateExpression.length()-2);
        }
        UpdateItemSpec spec = new UpdateItemSpec()
                .withPrimaryKey(toPrimaryKey(id))
                .withUpdateExpression(updateExpression)
                .withNameMap(nameMap);
        if (!valueMap.isEmpty()) {
            spec = spec.withValueMap(valueMap);
        }
        return spec;
    }

    public  AbstractDynamoDao(Class<M> modelClass, Class<P> partialClass, AmazonDynamoDB db, String tableName);
    public  AbstractDynamoDao(Class<M> modelClass, Class<P> partialClass, AmazonDynamoDB db, String tableName, ItemMapper<M> modelMapper, ItemMapper<P> partialMapper);

}