use of com.amplifyframework.datastore.storage.StorageItemChange in project amplify-android by aws-amplify.
the class ObserveQueryExecutorTest method observeQueryCancelsTheOperationOnCancel.
/**
* testing cancel on observe query.
* @throws DataStoreException DataStoreException
*/
@Test
public void observeQueryCancelsTheOperationOnCancel() throws DataStoreException {
final BlogOwner blogOwner = BlogOwner.builder().name("Alan Turing").build();
List<BlogOwner> resultList = new ArrayList<>();
resultList.add(blogOwner);
Consumer<DataStoreQuerySnapshot<BlogOwner>> onQuerySnapshot = NoOpConsumer.create();
Consumer<DataStoreException> onObservationError = NoOpConsumer.create();
Action onObservationComplete = () -> {
};
SqlQueryProcessor mockSqlQueryProcessor = mock(SqlQueryProcessor.class);
when(mockSqlQueryProcessor.queryOfflineData(eq(BlogOwner.class), any(), any())).thenReturn(resultList);
Subject<StorageItemChange<? extends Model>> subject = PublishSubject.<StorageItemChange<? extends Model>>create().toSerialized();
ExecutorService threadPool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 5);
ObserveQueryExecutor<BlogOwner> observeQueryExecutor = new ObserveQueryExecutor<>(subject, mockSqlQueryProcessor, threadPool, mock(SyncStatus.class), new ModelSorter<>(), DataStoreConfiguration.defaults());
Consumer<Cancelable> observationStarted = value -> {
value.cancel();
Assert.assertTrue(observeQueryExecutor.getIsCancelled());
assertEquals(0, observeQueryExecutor.getCompleteMap().size());
assertEquals(0, observeQueryExecutor.getChangeList().size());
subject.test().assertNoErrors().isDisposed();
};
observeQueryExecutor.observeQuery(BlogOwner.class, new ObserveQueryOptions(null, null), observationStarted, onQuerySnapshot, onObservationError, onObservationComplete);
}
use of com.amplifyframework.datastore.storage.StorageItemChange in project amplify-android by aws-amplify.
the class ObserveQueryExecutorTest method observeQueryReturnsRecordsBasedOnMaxTime.
/**
* observe Query Returns batched Records Based On MaxTime.
* @throws InterruptedException InterruptedException
* @throws DataStoreException DataStoreException
*/
@Test
public void observeQueryReturnsRecordsBasedOnMaxTime() throws InterruptedException, DataStoreException {
CountDownLatch latch = new CountDownLatch(1);
CountDownLatch changeLatch = new CountDownLatch(1);
AtomicInteger count = new AtomicInteger();
BlogOwner blogOwner = BlogOwner.builder().name("Alan Turing").build();
List<BlogOwner> datastoreResultList = new ArrayList<>();
int maxRecords = 50;
datastoreResultList.add(blogOwner);
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(blogOwner));
latch.countDown();
} else if (count.get() == 1) {
Assert.assertEquals(6, 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(datastoreResultList);
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);
observeQueryExecutor.observeQuery(BlogOwner.class, new ObserveQueryOptions(), observationStarted, onQuerySnapshot, onObservationError, onObservationComplete);
Assert.assertTrue(latch.await(1, TimeUnit.SECONDS));
for (int i = 0; i < 5; i++) {
BlogOwner itemChange = BlogOwner.builder().name("Alan Turing" + i).build();
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.UPDATE).build());
} catch (AmplifyException exception) {
exception.printStackTrace();
}
}
Assert.assertTrue(changeLatch.await(5, TimeUnit.SECONDS));
}
use of com.amplifyframework.datastore.storage.StorageItemChange 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.storage.StorageItemChange in project amplify-android by aws-amplify.
the class SQLiteStorageAdapter method save.
/**
* {@inheritDoc}
*/
@Override
public <T extends Model> void save(@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 ModelSchema modelSchema = schemaRegistry.getModelSchemaForModelClass(item.getModelName());
final StorageItemChange.Type writeType;
SerializedModel patchItem = null;
if (sqlQueryProcessor.modelExists(item, QueryPredicates.all())) {
// if data exists already, then UPDATE the row
writeType = StorageItemChange.Type.UPDATE;
// 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("Save failed because condition did not match existing model instance.", "The save will continue to fail until the model instance is updated.");
}
if (initiator == StorageItemChange.Initiator.DATA_STORE_API) {
// When saving items via the DataStore API, compute a SerializedModel of the changed model.
// This is not necessary when save
// is initiated by the sync engine, so skip it for optimization to avoid the extra SQL query.
patchItem = SerializedModel.create(item, modelSchema);
}
} else if (!QueryPredicates.all().equals(predicate)) {
// insert not permitted with a condition
throw new DataStoreException("Conditional update must be performed against an already existing data. " + "Insertion is not permitted while using a predicate.", "Please save without specifying a predicate.");
} else {
// if data doesn't exist yet, then INSERT a new row
writeType = StorageItemChange.Type.CREATE;
}
// execute local save
writeData(item, writeType);
// publish successful save
StorageItemChange<T> change = StorageItemChange.<T>builder().item(item).patchItem(patchItem != null ? patchItem : SerializedModel.create(item, modelSchema)).modelSchema(modelSchema).type(writeType).predicate(predicate).initiator(initiator).build();
itemChangeSubject.onNext(change);
onSuccess.accept(change);
} catch (DataStoreException dataStoreException) {
onError.accept(dataStoreException);
} catch (Exception someOtherTypeOfException) {
String modelToString = item.getModelName() + "[id=" + item.getId() + "]";
DataStoreException dataStoreException = new DataStoreException("Error in saving the model: " + modelToString, someOtherTypeOfException, "See attached exception for details.");
onError.accept(dataStoreException);
}
});
}
use of com.amplifyframework.datastore.storage.StorageItemChange in project amplify-android by aws-amplify.
the class SQLiteStorageAdapterDeleteTest method deleteModelCascades.
/**
* Assert that delete deletes item in the SQLite database without
* violating foreign key constraints.
* @throws DataStoreException On unexpected failure manipulating items in/out of DataStore
*/
@Test
public void deleteModelCascades() throws DataStoreException {
// Create 1 blog owner, which has 3 blogs each, which has 3 posts each.
// Insert 1 blog owner, 3 blogs, 9 posts
Set<String> expected = new HashSet<>();
BlogOwner ownerModel = BlogOwner.builder().name("Blog Owner 1").build();
adapter.save(ownerModel);
expected.add(ownerModel.getId());
for (int blog = 1; blog <= 3; blog++) {
Blog blogModel = Blog.builder().name("Blog " + blog).owner(ownerModel).build();
adapter.save(blogModel);
expected.add(blogModel.getId());
for (int post = 1; post <= 3; post++) {
Post postModel = Post.builder().title("Post " + post).status(PostStatus.INACTIVE).rating(5).blog(blogModel).build();
adapter.save(postModel);
expected.add(postModel.getId());
}
}
// Observe deletions
TestObserver<String> deleteObserver = adapter.observe().filter(change -> StorageItemChange.Type.DELETE.equals(change.type())).map(StorageItemChange::item).map(Model::getId).test();
// Triggers a delete.
// Deletes every saved model to prevent foreign key constraint violation
adapter.delete(ownerModel);
// Assert that cascaded deletions are observed.
deleteObserver.assertValueCount(13);
assertEquals(expected, new HashSet<>(deleteObserver.values()));
// Get data from the database and assert that everything is deleted.
assertTrue(adapter.query(BlogOwner.class).isEmpty());
assertTrue(adapter.query(Blog.class).isEmpty());
assertTrue(adapter.query(Post.class).isEmpty());
}
Aggregations