use of com.amplifyframework.core.Consumer in project amplify-android by aws-amplify.
the class Merger method merge.
/**
* Merge an item back into the local store, using a default strategy.
* TODO: Change this method to return a Maybe, and remove the Consumer argument.
* @param modelWithMetadata A model, combined with metadata about it
* @param changeTypeConsumer A callback invoked when the merge method saves or deletes the model.
* @param <T> Type of model
* @return A completable operation to merge the model
*/
<T extends Model> Completable merge(ModelWithMetadata<T> modelWithMetadata, Consumer<StorageItemChange.Type> changeTypeConsumer) {
AtomicReference<Long> startTime = new AtomicReference<>();
return Completable.defer(() -> {
ModelMetadata metadata = modelWithMetadata.getSyncMetadata();
boolean isDelete = Boolean.TRUE.equals(metadata.isDeleted());
int incomingVersion = metadata.getVersion() == null ? -1 : metadata.getVersion();
T model = modelWithMetadata.getModel();
return versionRepository.findModelVersion(model).onErrorReturnItem(-1).filter(currentVersion -> currentVersion == -1 || incomingVersion > currentVersion).flatMapCompletable(shouldMerge -> {
Completable firstStep;
if (mutationOutbox.hasPendingMutation(model.getId())) {
LOG.info("Mutation outbox has pending mutation for " + model.getId() + ". Saving the metadata, but not model itself.");
firstStep = Completable.complete();
} else {
firstStep = (isDelete ? delete(model, changeTypeConsumer) : save(model, changeTypeConsumer));
}
return firstStep.andThen(save(metadata, NoOpConsumer.create()));
}).doOnComplete(() -> {
announceSuccessfulMerge(modelWithMetadata);
LOG.debug("Remote model update was sync'd down into local storage: " + modelWithMetadata);
}).onErrorComplete(failure -> {
if (!ErrorInspector.contains(failure, SQLiteConstraintException.class)) {
return false;
}
LOG.warn("Sync failed: foreign key constraint violation: " + modelWithMetadata, failure);
return true;
}).doOnError(failure -> LOG.warn("Failed to sync remote model into local storage: " + modelWithMetadata, failure));
}).doOnSubscribe(disposable -> startTime.set(System.currentTimeMillis())).doOnTerminate(() -> {
long duration = System.currentTimeMillis() - startTime.get();
LOG.verbose("Merged a single item in " + duration + " ms.");
});
}
use of com.amplifyframework.core.Consumer in project amplify-android by aws-amplify.
the class AppSyncClient method mutation.
private <T extends Model> Cancelable mutation(final GraphQLRequest<ModelWithMetadata<T>> request, final Consumer<GraphQLResponse<ModelWithMetadata<T>>> onResponse, final Consumer<DataStoreException> onFailure) {
final Consumer<GraphQLResponse<ModelWithMetadata<T>>> responseConsumer = response -> {
if (response.hasErrors()) {
onResponse.accept(new GraphQLResponse<>(null, response.getErrors()));
} else {
onResponse.accept(response);
}
};
final Consumer<ApiException> failureConsumer = failure -> onFailure.accept(new DataStoreException("Failure during mutation.", failure, "Check details."));
final Cancelable cancelable = api.mutate(request, responseConsumer, failureConsumer);
if (cancelable != null) {
return cancelable;
}
return new NoOpCancelable();
}
use of com.amplifyframework.core.Consumer in project amplify-android by aws-amplify.
the class AppSyncClient method sync.
@NonNull
@Override
public <T extends Model> Cancelable sync(@NonNull GraphQLRequest<PaginatedResult<ModelWithMetadata<T>>> request, @NonNull Consumer<GraphQLResponse<PaginatedResult<ModelWithMetadata<T>>>> onResponse, @NonNull Consumer<DataStoreException> onFailure) {
final Consumer<GraphQLResponse<PaginatedResult<ModelWithMetadata<T>>>> responseConsumer = apiQueryResponse -> {
if (apiQueryResponse.hasErrors()) {
onFailure.accept(new DataStoreException("Failure performing sync query to AppSync: " + apiQueryResponse.getErrors().toString(), AmplifyException.TODO_RECOVERY_SUGGESTION));
} else {
onResponse.accept(apiQueryResponse);
}
};
final Consumer<ApiException> failureConsumer = failure -> onFailure.accept(new DataStoreException("Failure performing sync query to AppSync.", failure, AmplifyException.TODO_RECOVERY_SUGGESTION));
final Cancelable cancelable = api.query(request, responseConsumer, failureConsumer);
if (cancelable != null) {
return cancelable;
}
return new NoOpCancelable();
}
use of com.amplifyframework.core.Consumer in project amplify-android by aws-amplify.
the class AppSyncClient method subscription.
private <T extends Model> Cancelable subscription(SubscriptionType subscriptionType, ModelSchema modelSchema, Consumer<String> onSubscriptionStarted, Consumer<GraphQLResponse<ModelWithMetadata<T>>> onNextResponse, Consumer<DataStoreException> onSubscriptionFailure, Action onSubscriptionCompleted) {
final GraphQLRequest<ModelWithMetadata<T>> request;
try {
request = AppSyncRequestFactory.buildSubscriptionRequest(modelSchema, subscriptionType, authModeStrategyType);
} catch (DataStoreException requestGenerationException) {
onSubscriptionFailure.accept(requestGenerationException);
return new NoOpCancelable();
}
final Consumer<GraphQLResponse<ModelWithMetadata<T>>> responseConsumer = response -> {
if (response.hasErrors()) {
onSubscriptionFailure.accept(new DataStoreException.GraphQLResponseException("Subscription error for " + modelSchema.getName() + ": " + response.getErrors(), response.getErrors()));
} else {
onNextResponse.accept(response);
}
};
final Consumer<ApiException> failureConsumer = failure -> onSubscriptionFailure.accept(new DataStoreException("Error during subscription.", failure, "Evaluate details."));
final Cancelable cancelable = api.subscribe(request, onSubscriptionStarted, responseConsumer, failureConsumer, onSubscriptionCompleted);
if (cancelable != null) {
return cancelable;
}
return new NoOpCancelable();
}
use of com.amplifyframework.core.Consumer 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"));
}
});
}
Aggregations