Search in sources :

Example 31 with Consumer

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.");
    });
}
Also used : Amplify(com.amplifyframework.core.Amplify) HubChannel(com.amplifyframework.hub.HubChannel) NonNull(androidx.annotation.NonNull) QueryPredicates(com.amplifyframework.core.model.query.predicate.QueryPredicates) ModelWithMetadata(com.amplifyframework.datastore.appsync.ModelWithMetadata) StorageItemChange(com.amplifyframework.datastore.storage.StorageItemChange) DataStoreChannelEventName(com.amplifyframework.datastore.DataStoreChannelEventName) Model(com.amplifyframework.core.model.Model) Completable(io.reactivex.rxjava3.core.Completable) AtomicReference(java.util.concurrent.atomic.AtomicReference) ErrorInspector(com.amplifyframework.datastore.utils.ErrorInspector) Logger(com.amplifyframework.logging.Logger) Objects(java.util.Objects) Consumer(com.amplifyframework.core.Consumer) LocalStorageAdapter(com.amplifyframework.datastore.storage.LocalStorageAdapter) ModelMetadata(com.amplifyframework.datastore.appsync.ModelMetadata) SQLiteConstraintException(android.database.sqlite.SQLiteConstraintException) NoOpConsumer(com.amplifyframework.core.NoOpConsumer) HubEvent(com.amplifyframework.hub.HubEvent) Completable(io.reactivex.rxjava3.core.Completable) AtomicReference(java.util.concurrent.atomic.AtomicReference) ModelMetadata(com.amplifyframework.datastore.appsync.ModelMetadata)

Example 32 with Consumer

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();
}
Also used : Amplify(com.amplifyframework.core.Amplify) AmplifyException(com.amplifyframework.AmplifyException) NonNull(androidx.annotation.NonNull) QueryPredicates(com.amplifyframework.core.model.query.predicate.QueryPredicates) GraphQLRequest(com.amplifyframework.api.graphql.GraphQLRequest) Model(com.amplifyframework.core.model.Model) Action(com.amplifyframework.core.Action) ApiException(com.amplifyframework.api.ApiException) Logger(com.amplifyframework.logging.Logger) GraphQLBehavior(com.amplifyframework.api.graphql.GraphQLBehavior) DataStoreException(com.amplifyframework.datastore.DataStoreException) Consumer(com.amplifyframework.core.Consumer) Nullable(androidx.annotation.Nullable) Cancelable(com.amplifyframework.core.async.Cancelable) SubscriptionType(com.amplifyframework.api.graphql.SubscriptionType) AuthModeStrategyType(com.amplifyframework.api.aws.AuthModeStrategyType) NoOpCancelable(com.amplifyframework.core.async.NoOpCancelable) ModelSchema(com.amplifyframework.core.model.ModelSchema) GraphQLResponse(com.amplifyframework.api.graphql.GraphQLResponse) ApiCategoryBehavior(com.amplifyframework.api.ApiCategoryBehavior) PaginatedResult(com.amplifyframework.api.graphql.PaginatedResult) QueryPredicate(com.amplifyframework.core.model.query.predicate.QueryPredicate) DataStoreException(com.amplifyframework.datastore.DataStoreException) GraphQLResponse(com.amplifyframework.api.graphql.GraphQLResponse) NoOpCancelable(com.amplifyframework.core.async.NoOpCancelable) Cancelable(com.amplifyframework.core.async.Cancelable) NoOpCancelable(com.amplifyframework.core.async.NoOpCancelable) ApiException(com.amplifyframework.api.ApiException)

Example 33 with Consumer

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();
}
Also used : Amplify(com.amplifyframework.core.Amplify) AmplifyException(com.amplifyframework.AmplifyException) NonNull(androidx.annotation.NonNull) QueryPredicates(com.amplifyframework.core.model.query.predicate.QueryPredicates) GraphQLRequest(com.amplifyframework.api.graphql.GraphQLRequest) Model(com.amplifyframework.core.model.Model) Action(com.amplifyframework.core.Action) ApiException(com.amplifyframework.api.ApiException) Logger(com.amplifyframework.logging.Logger) GraphQLBehavior(com.amplifyframework.api.graphql.GraphQLBehavior) DataStoreException(com.amplifyframework.datastore.DataStoreException) Consumer(com.amplifyframework.core.Consumer) Nullable(androidx.annotation.Nullable) Cancelable(com.amplifyframework.core.async.Cancelable) SubscriptionType(com.amplifyframework.api.graphql.SubscriptionType) AuthModeStrategyType(com.amplifyframework.api.aws.AuthModeStrategyType) NoOpCancelable(com.amplifyframework.core.async.NoOpCancelable) ModelSchema(com.amplifyframework.core.model.ModelSchema) GraphQLResponse(com.amplifyframework.api.graphql.GraphQLResponse) ApiCategoryBehavior(com.amplifyframework.api.ApiCategoryBehavior) PaginatedResult(com.amplifyframework.api.graphql.PaginatedResult) QueryPredicate(com.amplifyframework.core.model.query.predicate.QueryPredicate) DataStoreException(com.amplifyframework.datastore.DataStoreException) GraphQLResponse(com.amplifyframework.api.graphql.GraphQLResponse) NoOpCancelable(com.amplifyframework.core.async.NoOpCancelable) Cancelable(com.amplifyframework.core.async.Cancelable) NoOpCancelable(com.amplifyframework.core.async.NoOpCancelable) ApiException(com.amplifyframework.api.ApiException) NonNull(androidx.annotation.NonNull)

Example 34 with Consumer

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();
}
Also used : Amplify(com.amplifyframework.core.Amplify) AmplifyException(com.amplifyframework.AmplifyException) NonNull(androidx.annotation.NonNull) QueryPredicates(com.amplifyframework.core.model.query.predicate.QueryPredicates) GraphQLRequest(com.amplifyframework.api.graphql.GraphQLRequest) Model(com.amplifyframework.core.model.Model) Action(com.amplifyframework.core.Action) ApiException(com.amplifyframework.api.ApiException) Logger(com.amplifyframework.logging.Logger) GraphQLBehavior(com.amplifyframework.api.graphql.GraphQLBehavior) DataStoreException(com.amplifyframework.datastore.DataStoreException) Consumer(com.amplifyframework.core.Consumer) Nullable(androidx.annotation.Nullable) Cancelable(com.amplifyframework.core.async.Cancelable) SubscriptionType(com.amplifyframework.api.graphql.SubscriptionType) AuthModeStrategyType(com.amplifyframework.api.aws.AuthModeStrategyType) NoOpCancelable(com.amplifyframework.core.async.NoOpCancelable) ModelSchema(com.amplifyframework.core.model.ModelSchema) GraphQLResponse(com.amplifyframework.api.graphql.GraphQLResponse) ApiCategoryBehavior(com.amplifyframework.api.ApiCategoryBehavior) PaginatedResult(com.amplifyframework.api.graphql.PaginatedResult) QueryPredicate(com.amplifyframework.core.model.query.predicate.QueryPredicate) DataStoreException(com.amplifyframework.datastore.DataStoreException) GraphQLResponse(com.amplifyframework.api.graphql.GraphQLResponse) NoOpCancelable(com.amplifyframework.core.async.NoOpCancelable) Cancelable(com.amplifyframework.core.async.Cancelable) NoOpCancelable(com.amplifyframework.core.async.NoOpCancelable) ApiException(com.amplifyframework.api.ApiException)

Example 35 with Consumer

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"));
        }
    });
}
Also used : ObjectsCompat(androidx.core.util.ObjectsCompat) AmplifyException(com.amplifyframework.AmplifyException) NonNull(androidx.annotation.NonNull) QueryPredicates(com.amplifyframework.core.model.query.predicate.QueryPredicates) ModelProvider(com.amplifyframework.core.model.ModelProvider) StorageItemChange(com.amplifyframework.datastore.storage.StorageItemChange) SQLiteDatabase(android.database.sqlite.SQLiteDatabase) Gson(com.google.gson.Gson) Map(java.util.Map) PublishSubject(io.reactivex.rxjava3.subjects.PublishSubject) QueryOptions(com.amplifyframework.core.model.query.QueryOptions) CustomTypeSchema(com.amplifyframework.core.model.CustomTypeSchema) SerializedModel(com.amplifyframework.core.model.SerializedModel) Immutable(com.amplifyframework.util.Immutable) Set(java.util.Set) Executors(java.util.concurrent.Executors) Logger(com.amplifyframework.logging.Logger) Objects(java.util.Objects) DataStoreException(com.amplifyframework.datastore.DataStoreException) LocalStorageAdapter(com.amplifyframework.datastore.storage.LocalStorageAdapter) List(java.util.List) Cancelable(com.amplifyframework.core.async.Cancelable) SQLiteTable(com.amplifyframework.datastore.storage.sqlite.adapter.SQLiteTable) Disposable(io.reactivex.rxjava3.disposables.Disposable) Context(android.content.Context) SerializedCustomType(com.amplifyframework.core.model.SerializedCustomType) QueryField(com.amplifyframework.core.model.query.predicate.QueryField) Single(io.reactivex.rxjava3.core.Single) ObserveQueryOptions(com.amplifyframework.core.model.query.ObserveQueryOptions) SystemModelsProviderFactory(com.amplifyframework.datastore.model.SystemModelsProviderFactory) HashMap(java.util.HashMap) CustomTypeField(com.amplifyframework.core.model.CustomTypeField) ModelField(com.amplifyframework.core.model.ModelField) ArrayList(java.util.ArrayList) SchemaRegistry(com.amplifyframework.core.model.SchemaRegistry) GsonFactory(com.amplifyframework.util.GsonFactory) HashSet(java.util.HashSet) Consumer(com.amplifyframework.core.Consumer) CompositeDisposable(io.reactivex.rxjava3.disposables.CompositeDisposable) ModelSchema(com.amplifyframework.core.model.ModelSchema) Subject(io.reactivex.rxjava3.subjects.Subject) QueryPredicate(com.amplifyframework.core.model.query.predicate.QueryPredicate) ExecutorService(java.util.concurrent.ExecutorService) Cursor(android.database.Cursor) DataStoreQuerySnapshot(com.amplifyframework.datastore.DataStoreQuerySnapshot) DataStoreConfiguration(com.amplifyframework.datastore.DataStoreConfiguration) Amplify(com.amplifyframework.core.Amplify) CompoundModelProvider(com.amplifyframework.datastore.model.CompoundModelProvider) Iterator(java.util.Iterator) Model(com.amplifyframework.core.model.Model) Completable(io.reactivex.rxjava3.core.Completable) Action(com.amplifyframework.core.Action) Where(com.amplifyframework.core.model.query.Where) ModelAssociation(com.amplifyframework.core.model.ModelAssociation) TimeUnit(java.util.concurrent.TimeUnit) ModelMigrations(com.amplifyframework.datastore.storage.sqlite.migrations.ModelMigrations) VisibleForTesting(androidx.annotation.VisibleForTesting) Collections(java.util.Collections) DataStoreException(com.amplifyframework.datastore.DataStoreException) ArrayList(java.util.ArrayList) AmplifyException(com.amplifyframework.AmplifyException) DataStoreException(com.amplifyframework.datastore.DataStoreException)

Aggregations

Consumer (com.amplifyframework.core.Consumer)35 Action (com.amplifyframework.core.Action)28 DataStoreException (com.amplifyframework.datastore.DataStoreException)28 ArrayList (java.util.ArrayList)26 List (java.util.List)26 Test (org.junit.Test)26 Cancelable (com.amplifyframework.core.async.Cancelable)25 BlogOwner (com.amplifyframework.testmodels.commentsblog.BlogOwner)25 TimeUnit (java.util.concurrent.TimeUnit)24 Collections (java.util.Collections)23 CountDownLatch (java.util.concurrent.CountDownLatch)22 Assert.assertEquals (org.junit.Assert.assertEquals)21 NoOpConsumer (com.amplifyframework.core.NoOpConsumer)20 ObserveQueryOptions (com.amplifyframework.core.model.query.ObserveQueryOptions)20 DataStoreQuerySnapshot (com.amplifyframework.datastore.DataStoreQuerySnapshot)20 Arrays (java.util.Arrays)20 NoOpAction (com.amplifyframework.core.NoOpAction)19 QuerySortBy (com.amplifyframework.core.model.query.QuerySortBy)19 Post (com.amplifyframework.testmodels.commentsblog.Post)19 PostStatus (com.amplifyframework.testmodels.commentsblog.PostStatus)19