use of com.amplifyframework.datastore.DataStoreException in project amplify-android by aws-amplify.
the class SQLiteModelFieldTypeConverter method convertValueFromSource.
@Override
public Object convertValueFromSource(@NonNull Cursor cursor, @NonNull ModelField field) throws DataStoreException {
final JavaFieldType javaFieldType = TypeConverter.getJavaFieldType(field);
try {
// Skip if there is no equivalent column for field in object
final SQLiteColumn column = columns.get(field.getName());
if (column == null) {
LOGGER.verbose(String.format("Column with name %s does not exist", field.getName()));
return null;
}
String columnName = column.getAliasedName();
if (javaFieldType == JavaFieldType.MODEL) {
int newInnerModelCount = 1;
String fieldTargetType = field.getTargetType();
if (cursorInnerModelCounts.containsKey(fieldTargetType)) {
Integer currentInnerModelCount = cursorInnerModelCounts.get(fieldTargetType);
newInnerModelCount += currentInnerModelCount == null ? 0 : currentInnerModelCount;
}
cursorInnerModelCounts.put(fieldTargetType, newInnerModelCount);
}
if (isInnerModel && cursorInnerModelCounts.containsKey(parentSchema.getName())) {
Integer modelCount = cursorInnerModelCounts.get(parentSchema.getName());
if (!Objects.equals(modelCount, 1)) {
// More than 1 of the model the field belongs to is present in the cursor
columnName += modelCount;
}
}
final int columnIndex = cursor.getColumnIndexOrThrow(columnName);
// This check is necessary, because primitive values will return 0 even when null
if (cursor.isNull(columnIndex)) {
return null;
}
final String valueAsString = cursor.getString(columnIndex);
LOGGER.verbose(String.format("Attempt to convert value \"%s\" from field %s of type %s in model %s", valueAsString, field.getName(), field.getTargetType(), parentSchema.getName()));
switch(javaFieldType) {
case STRING:
return cursor.getString(columnIndex);
case MODEL:
return convertModelAssociationToTarget(cursor, field);
case ENUM:
return convertEnumValueToTarget(valueAsString, field);
case CUSTOM_TYPE:
return convertCustomTypeToTarget(cursor, field, columnIndex);
case INTEGER:
return cursor.getInt(columnIndex);
case BOOLEAN:
return cursor.getInt(columnIndex) != 0;
case FLOAT:
return cursor.getFloat(columnIndex);
case DOUBLE:
return cursor.getDouble(columnIndex);
case LONG:
return cursor.getLong(columnIndex);
case DATE:
return new Temporal.Date(valueAsString);
case DATE_TIME:
return new Temporal.DateTime(valueAsString);
case TIME:
return new Temporal.Time(valueAsString);
case TIMESTAMP:
return new Temporal.Timestamp(cursor.getLong(columnIndex), TimeUnit.SECONDS);
default:
LOGGER.warn(String.format("Field of type %s is not supported. Fallback to null.", javaFieldType));
return null;
}
} catch (Exception exception) {
throw new DataStoreException(String.format("Error converting field \"%s\" from model \"%s\"", field.getName(), parentSchema.getName()), exception, AmplifyException.REPORT_BUG_TO_AWS_SUGGESTION);
}
}
use of com.amplifyframework.datastore.DataStoreException in project amplify-android by aws-amplify.
the class SQLiteStorageAdapter method writeData.
private <T extends Model> void writeData(T item, StorageItemChange.Type writeType) throws DataStoreException {
final String modelName = item.getModelName();
final ModelSchema modelSchema = schemaRegistry.getModelSchemaForModelClass(modelName);
final SQLiteTable sqliteTable = SQLiteTable.fromSchema(modelSchema);
// Generate SQL command for given action
switch(writeType) {
case CREATE:
LOG.verbose("Creating item in " + sqliteTable.getName() + " identified by ID: " + item.getId());
sqlCommandProcessor.execute(sqlCommandFactory.insertFor(modelSchema, item));
break;
case UPDATE:
LOG.verbose("Updating item in " + sqliteTable.getName() + " identified by ID: " + item.getId());
sqlCommandProcessor.execute(sqlCommandFactory.updateFor(modelSchema, item));
break;
case DELETE:
LOG.verbose("Deleting item in " + sqliteTable.getName() + " identified by ID: " + item.getId());
final String primaryKeyName = sqliteTable.getPrimaryKey().getName();
final QueryPredicate matchId = QueryField.field(modelName, primaryKeyName).eq(item.getId());
sqlCommandProcessor.execute(sqlCommandFactory.deleteFor(modelSchema, matchId));
break;
default:
throw new DataStoreException("Unexpected change was requested: " + writeType.name(), "Valid storage changes are CREATE, UPDATE, and DELETE.");
}
}
use of com.amplifyframework.datastore.DataStoreException in project amplify-android by aws-amplify.
the class SQLiteStorageAdapter method initialize.
/**
* {@inheritDoc}
*/
@Override
public synchronized void initialize(@NonNull Context context, @NonNull Consumer<List<ModelSchema>> onSuccess, @NonNull Consumer<DataStoreException> onError, @NonNull DataStoreConfiguration dataStoreConfiguration) {
Objects.requireNonNull(context);
Objects.requireNonNull(onSuccess);
Objects.requireNonNull(onError);
// Create a thread pool large enough to take advantage of parallelization, but small enough to avoid
// OutOfMemoryError and CursorWindowAllocationException issues.
this.threadPool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * THREAD_POOL_SIZE_MULTIPLIER);
this.context = context;
this.dataStoreConfiguration = dataStoreConfiguration;
threadPool.submit(() -> {
try {
/*
* Start with a fresh registry.
*/
schemaRegistry.clear();
/*
* Create {@link ModelSchema} objects for the corresponding {@link Model}.
* Any exception raised during this when inspecting the Model classes
* through reflection will be notified via the `onError` callback.
*/
schemaRegistry.register(modelsProvider.modelSchemas(), modelsProvider.customTypeSchemas());
/*
* Create the CREATE TABLE and CREATE INDEX commands for each of the
* Models. Instantiate {@link SQLiteStorageHelper} to execute those
* create commands.
*/
this.sqlCommandFactory = new SQLiteCommandFactory(schemaRegistry, gson);
CreateSqlCommands createSqlCommands = getCreateCommands(modelsProvider.modelNames());
sqliteStorageHelper = SQLiteStorageHelper.getInstance(context, databaseName, DATABASE_VERSION, createSqlCommands);
/*
* Create and/or open a database. This also invokes
* {@link SQLiteStorageHelper#onCreate(SQLiteDatabase)} which executes the tasks
* to create tables and indexes. When the function returns without any exception
* being thrown, invoke the `onError` callback.
*
* Errors are thrown when there is no write permission to the database, no space
* left in the database for any write operation and other errors thrown while
* creating and opening a database. All errors are passed through the
* `onError` callback.
*
* databaseConnectionHandle represents a connection handle to the database.
* All database operations will happen through this handle.
*/
databaseConnectionHandle = sqliteStorageHelper.getWritableDatabase();
/*
* Create helper instance that can traverse through model relations.
*/
this.sqliteModelTree = new SQLiteModelTree(schemaRegistry, databaseConnectionHandle);
/*
* Create a command processor which runs the actual SQL transactions.
*/
this.sqlCommandProcessor = new SQLCommandProcessor(databaseConnectionHandle);
sqlQueryProcessor = new SqlQueryProcessor(sqlCommandProcessor, sqlCommandFactory, schemaRegistry);
syncStatus = new SyncStatus(sqlQueryProcessor, dataStoreConfiguration);
/*
* Detect if the version of the models stored in SQLite is different
* from the version passed in through {@link ModelProvider#version()}.
* Delete the database if there is a version change.
*/
toBeDisposed.add(updateModels().subscribe(() -> onSuccess.accept(Immutable.of(new ArrayList<>(schemaRegistry.getModelSchemaMap().values()))), throwable -> onError.accept(new DataStoreException("Error in initializing the SQLiteStorageAdapter", throwable, AmplifyException.TODO_RECOVERY_SUGGESTION))));
} catch (Exception exception) {
onError.accept(new DataStoreException("Error in initializing the SQLiteStorageAdapter", exception, "See attached exception"));
}
});
}
use of com.amplifyframework.datastore.DataStoreException in project amplify-android by aws-amplify.
the class SqlQueryProcessor method queryOfflineData.
<T extends Model> List<T> queryOfflineData(@NonNull Class<T> itemClass, @NonNull QueryOptions options, @NonNull Consumer<DataStoreException> onError) {
final ModelSchema modelSchema = modelSchemaRegistry.getModelSchemaForModelClass(itemClass.getSimpleName());
final List<T> models = new ArrayList<>();
try (Cursor cursor = sqlCommandProcessor.rawQuery(sqlCommandFactory.queryFor(modelSchema, options))) {
LOG.debug("Querying item for: " + itemClass.getSimpleName());
final SQLiteModelFieldTypeConverter converter = new SQLiteModelFieldTypeConverter(modelSchema, modelSchemaRegistry, gson);
if (cursor == null) {
onError.accept(new DataStoreException("Error in getting a cursor to the table for class: " + itemClass.getSimpleName(), AmplifyException.TODO_RECOVERY_SUGGESTION));
} else if (cursor.moveToFirst()) {
do {
Map<String, Object> map = converter.buildMapForModel(cursor);
String jsonString = gson.toJson(map);
models.add(gson.fromJson(jsonString, itemClass));
} while (cursor.moveToNext());
}
} catch (Exception exception) {
onError.accept(new DataStoreException("Error in querying the model.", exception, "See attached exception for details."));
}
return models;
}
use of com.amplifyframework.datastore.DataStoreException in project amplify-android by aws-amplify.
the class SyncStatus method get.
/**
* Method returns sync status.
* @param modelClassName model class name.
* @param onObservationError invoked on error.
* @return returns the sync status of true or false.
*/
public boolean get(@NonNull String modelClassName, @NonNull Consumer<DataStoreException> onObservationError) {
LastSyncMetadata lastSyncMetadata;
boolean syncStatus = false;
try {
lastSyncMetadata = getLastSyncMetaData(modelClassName, onObservationError);
if (lastSyncMetadata.getLastSyncTime() != null) {
syncStatus = (Time.now() - lastSyncMetadata.getLastSyncTime()) < TimeUnit.MINUTES.toMillis(dataStoreConfiguration.getSyncIntervalInMinutes());
}
} catch (DataStoreException exception) {
onObservationError.accept(exception);
}
return syncStatus;
}
Aggregations