use of com.amplifyframework.datastore.DataStoreException in project amplify-android by aws-amplify.
the class ObserveQueryExecutorTest method observeQueryReturnsSortedListOfTotalItems.
/**
* observe Query Returns Sorted List Of Total Items.
* @throws InterruptedException InterruptedException
* @throws DataStoreException DataStoreException
*/
@Test
public void observeQueryReturnsSortedListOfTotalItems() throws InterruptedException, DataStoreException {
CountDownLatch latch = new CountDownLatch(1);
CountDownLatch changeLatch = new CountDownLatch(1);
AtomicInteger count = new AtomicInteger();
List<String> names = Arrays.asList("John", "Jacob", "Joe", "Bob", "Bobby", "Bobb", "Dan", "Dany", "Daniel");
List<String> weas = Arrays.asList("pon", "lth", "ver", "kly", "ken", "sel", "ner", "rer", "ned");
List<BlogOwner> owners = new ArrayList<>();
for (int i = 0; i < names.size() / 2; i++) {
BlogOwner owner = BlogOwner.builder().name(names.get(i)).wea(weas.get(i)).build();
owners.add(owner);
}
int maxRecords = 50;
Consumer<Cancelable> observationStarted = NoOpConsumer.create();
SyncStatus mockSyncStatus = mock(SyncStatus.class);
when(mockSyncStatus.get(any(), any())).thenReturn(false);
Subject<StorageItemChange<? extends Model>> subject = PublishSubject.<StorageItemChange<? extends Model>>create().toSerialized();
Consumer<DataStoreQuerySnapshot<BlogOwner>> onQuerySnapshot = value -> {
if (count.get() == 0) {
Assert.assertTrue(value.getItems().contains(owners.get(0)));
latch.countDown();
} else if (count.get() == 1) {
List<BlogOwner> sorted = new ArrayList<>(owners);
Collections.sort(sorted, Comparator.comparing(BlogOwner::getName).reversed().thenComparing(BlogOwner::getWea));
assertEquals(sorted, value.getItems());
Assert.assertEquals(8, value.getItems().size());
changeLatch.countDown();
}
count.getAndIncrement();
};
Consumer<DataStoreException> onObservationError = NoOpConsumer.create();
Action onObservationComplete = () -> {
};
SqlQueryProcessor mockSqlQueryProcessor = mock(SqlQueryProcessor.class);
when(mockSqlQueryProcessor.queryOfflineData(eq(BlogOwner.class), any(), any())).thenReturn(owners);
when(mockSqlQueryProcessor.modelExists(any(), any())).thenReturn(true);
ExecutorService threadPool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 5);
ObserveQueryExecutor<BlogOwner> observeQueryExecutor = new ObserveQueryExecutor<>(subject, mockSqlQueryProcessor, threadPool, mockSyncStatus, new ModelSorter<>(), maxRecords, 1);
List<QuerySortBy> sortBy = new ArrayList<>();
sortBy.add(BlogOwner.NAME.descending());
sortBy.add(BlogOwner.WEA.ascending());
observeQueryExecutor.observeQuery(BlogOwner.class, new ObserveQueryOptions(null, sortBy), observationStarted, onQuerySnapshot, onObservationError, onObservationComplete);
Assert.assertTrue(latch.await(1, TimeUnit.SECONDS));
for (int i = (names.size() / 2) + 1; i < names.size(); i++) {
BlogOwner itemChange = BlogOwner.builder().name(names.get(i)).wea(weas.get(i)).build();
owners.add(itemChange);
try {
subject.onNext(StorageItemChange.<BlogOwner>builder().changeId(UUID.randomUUID().toString()).initiator(StorageItemChange.Initiator.SYNC_ENGINE).item(itemChange).patchItem(SerializedModel.create(itemChange, ModelSchema.fromModelClass(BlogOwner.class))).modelSchema(ModelSchema.fromModelClass(BlogOwner.class)).predicate(QueryPredicates.all()).type(StorageItemChange.Type.CREATE).build());
} catch (AmplifyException exception) {
exception.printStackTrace();
}
}
Assert.assertTrue(changeLatch.await(7, TimeUnit.SECONDS));
}
use of com.amplifyframework.datastore.DataStoreException in project amplify-android by aws-amplify.
the class VersionRepositoryTest method emitsErrorForNoMetadataInRepo.
/**
* When you try to get a model version, but there's no metadata for that model,
* this should fail with an {@link DataStoreException}.
* @throws InterruptedException If interrupted while awaiting terminal result in test observer
*/
@Test
public void emitsErrorForNoMetadataInRepo() throws InterruptedException {
// Arrange: no metadata is in the repo.
BlogOwner blogOwner = BlogOwner.builder().name("Jameson Williams").build();
// Note that this line is NOT executed in arrangement.
// ModelMetadata metadata = new ModelMetadata(blogOwner.getId(), false, 1, Time.now());
// putInStore(blogOwner blogOwner);
// Act: try to lookup the metadata. Is it going to work? Duh.
TestObserver<Integer> observer = versionRepository.findModelVersion(blogOwner).test();
assertTrue(observer.await(REASONABLE_WAIT_TIME, TimeUnit.MILLISECONDS));
// Assert: this failed. There was no version available.
observer.assertError(error -> {
if (!(error instanceof DataStoreException)) {
return false;
}
String expectedMessage = String.format(Locale.US, "Wanted 1 metadata for item with id = %s, but had 0.", blogOwner.getId());
return expectedMessage.equals(error.getMessage());
});
}
use of com.amplifyframework.datastore.DataStoreException in project amplify-android by aws-amplify.
the class SQLiteStorageAdapter method query.
/**
* {@inheritDoc}
*/
@Override
public void query(@NonNull String modelName, @NonNull QueryOptions options, @NonNull Consumer<Iterator<? extends Model>> onSuccess, @NonNull Consumer<DataStoreException> onError) {
Objects.requireNonNull(modelName);
Objects.requireNonNull(options);
Objects.requireNonNull(onSuccess);
Objects.requireNonNull(onError);
threadPool.submit(() -> {
final ModelSchema modelSchema = schemaRegistry.getModelSchemaForModelClass(modelName);
try (Cursor cursor = sqlCommandProcessor.rawQuery(sqlCommandFactory.queryFor(modelSchema, options))) {
LOG.debug("Querying item for: " + modelName);
final List<Model> models = new ArrayList<>();
final SQLiteModelFieldTypeConverter converter = new SQLiteModelFieldTypeConverter(modelSchema, schemaRegistry, gson);
if (cursor == null) {
onError.accept(new DataStoreException("Error in getting a cursor to the table for class: " + modelName, AmplifyException.TODO_RECOVERY_SUGGESTION));
return;
}
if (cursor.moveToFirst()) {
do {
final Map<String, Object> data = converter.buildMapForModel(cursor);
final SerializedModel model = createSerializedModel(modelSchema, data);
models.add(model);
} while (cursor.moveToNext());
}
onSuccess.accept(models.iterator());
} catch (Exception exception) {
onError.accept(new DataStoreException("Error in querying the model.", exception, "See attached exception for details."));
}
});
}
use of com.amplifyframework.datastore.DataStoreException in project amplify-android by aws-amplify.
the class SQLiteStorageAdapter method delete.
/**
* {@inheritDoc}
*/
@Override
public <T extends Model> void delete(@NonNull T item, @NonNull StorageItemChange.Initiator initiator, @NonNull QueryPredicate predicate, @NonNull Consumer<StorageItemChange<T>> onSuccess, @NonNull Consumer<DataStoreException> onError) {
Objects.requireNonNull(item);
Objects.requireNonNull(initiator);
Objects.requireNonNull(predicate);
Objects.requireNonNull(onSuccess);
Objects.requireNonNull(onError);
threadPool.submit(() -> {
try {
final String modelName = item.getModelName();
final ModelSchema modelSchema = schemaRegistry.getModelSchemaForModelClass(modelName);
// Check if data being deleted exists; "Succeed" deletion in that case.
if (!sqlQueryProcessor.modelExists(item, QueryPredicates.all())) {
LOG.verbose(modelName + " model with id = " + item.getId() + " does not exist.");
// Pass back item change instance without publishing it.
onSuccess.accept(StorageItemChange.<T>builder().item(item).patchItem(SerializedModel.create(item, modelSchema)).modelSchema(modelSchema).type(StorageItemChange.Type.DELETE).predicate(predicate).initiator(initiator).build());
return;
}
// Check if existing data meets the condition, only if a condition other than all() was provided.
if (!QueryPredicates.all().equals(predicate) && !sqlQueryProcessor.modelExists(item, predicate)) {
throw new DataStoreException("Deletion failed because condition did not match existing model instance.", "The deletion will continue to fail until the model instance is updated.");
}
// identify items affected by cascading delete before deleting them
List<Model> cascadedModels = sqliteModelTree.descendantsOf(Collections.singleton(item));
// execute local deletion
writeData(item, StorageItemChange.Type.DELETE);
// publish cascaded deletions
for (Model cascadedModel : cascadedModels) {
ModelSchema schema = schemaRegistry.getModelSchemaForModelClass(cascadedModel.getModelName());
itemChangeSubject.onNext(StorageItemChange.builder().item(cascadedModel).patchItem(SerializedModel.create(cascadedModel, schema)).modelSchema(schema).type(StorageItemChange.Type.DELETE).predicate(QueryPredicates.all()).initiator(initiator).build());
}
// publish successful deletion of top-level item
StorageItemChange<T> change = StorageItemChange.<T>builder().item(item).patchItem(SerializedModel.create(item, modelSchema)).modelSchema(modelSchema).type(StorageItemChange.Type.DELETE).predicate(predicate).initiator(initiator).build();
itemChangeSubject.onNext(change);
onSuccess.accept(change);
} catch (DataStoreException dataStoreException) {
onError.accept(dataStoreException);
} catch (Exception someOtherTypeOfException) {
DataStoreException dataStoreException = new DataStoreException("Error in deleting the model.", someOtherTypeOfException, "See attached exception for details.");
onError.accept(dataStoreException);
}
});
}
use of com.amplifyframework.datastore.DataStoreException in project amplify-android by aws-amplify.
the class SQLiteStorageAdapter method observe.
/**
* {@inheritDoc}
*/
@NonNull
@Override
public Cancelable observe(@NonNull Consumer<StorageItemChange<? extends Model>> onItemChanged, @NonNull Consumer<DataStoreException> onObservationError, @NonNull Action onObservationComplete) {
Objects.requireNonNull(onItemChanged);
Objects.requireNonNull(onObservationError);
Objects.requireNonNull(onObservationComplete);
Disposable disposable = itemChangeSubject.subscribe(onItemChanged::accept, failure -> {
if (failure instanceof DataStoreException) {
onObservationError.accept((DataStoreException) failure);
return;
}
onObservationError.accept(new DataStoreException("Failed to observe items in storage adapter.", failure, "Inspect the failure details."));
}, onObservationComplete::call);
return disposable::dispose;
}
Aggregations