/*
* Copyright 2016 requery.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.requery.test;
import io.requery.Persistable;
import io.requery.cache.EntityCacheBuilder;
import io.requery.meta.EntityModel;
import io.requery.query.Result;
import io.requery.rx.RxResult;
import io.requery.rx.RxSupport;
import io.requery.rx.SingleEntityStore;
import io.requery.sql.Configuration;
import io.requery.sql.ConfigurationBuilder;
import io.requery.sql.EntityDataStore;
import io.requery.sql.Platform;
import io.requery.sql.SchemaModifier;
import io.requery.sql.TableCreationMode;
import io.requery.sql.platform.HSQL;
import io.requery.test.model.Person;
import io.requery.test.model.Phone;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import rx.Observable;
import rx.Single;
import rx.Subscriber;
import rx.Subscription;
import rx.functions.Action1;
import rx.functions.Func1;
import rx.schedulers.Schedulers;
import javax.cache.CacheManager;
import javax.cache.Caching;
import javax.cache.spi.CachingProvider;
import javax.sql.CommonDataSource;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
public class RxTest extends RandomData {
protected SingleEntityStore<Persistable> data;
@Before
public void setup() throws SQLException {
Platform platform = new HSQL();
CommonDataSource dataSource = DatabaseType.getDataSource(platform);
EntityModel model = io.requery.test.model.Models.DEFAULT;
CachingProvider provider = Caching.getCachingProvider();
CacheManager cacheManager = provider.getCacheManager();
Configuration configuration = new ConfigurationBuilder(dataSource, model)
.useDefaultLogging()
.setWriteExecutor(Executors.newSingleThreadExecutor())
.setEntityCache(new EntityCacheBuilder(model)
.useReferenceCache(true)
.useSerializableCache(true)
.useCacheManager(cacheManager)
.build())
.build();
SchemaModifier tables = new SchemaModifier(configuration);
tables.createTables(TableCreationMode.DROP_CREATE);
data = RxSupport.toReactiveStore(new EntityDataStore<Persistable>(configuration));
}
@After
public void teardown() {
if (data != null) {
data.close();
}
}
@Test
public void testInsert() throws Exception {
Person person = randomPerson();
final CountDownLatch latch = new CountDownLatch(1);
data.insert(person).subscribe(new Action1<Person>() {
@Override
public void call(Person person) {
assertTrue(person.getId() > 0);
Person cached = data.select(Person.class)
.where(Person.ID.equal(person.getId())).get().first();
assertSame(cached, person);
latch.countDown();
}
});
latch.await();
}
@Test
public void testInsertList() throws Exception {
final List<Person> items = new ArrayList<>();
for (int i = 0; i < 1; i++) {
Person person = randomPerson();
items.add(person);
}
final CountDownLatch latch = new CountDownLatch(1);
data.insert(items).subscribe(new Action1<Iterable<Person>>() {
@Override
public void call(Iterable<Person> iterable) {
List<Person> queried = data.select(Person.class).get().toList();
try {
assertEquals(queried, items);
} finally {
latch.countDown();
}
}
});
latch.await();
}
@Test
public void testDelete() throws Exception {
Person person = randomPerson();
data.insert(person).flatMap(new Func1<Person, Single<Void>>() {
@Override
public Single<Void> call(Person person) {
return data.delete(person);
}
}).toBlocking().value();
Person cached = data.select(Person.class)
.where(Person.ID.equal(person.getId())).get().firstOrNull();
assertNull(cached);
}
@Test
public void testInsertCount() throws Exception {
Person person = randomPerson();
Observable.just(person)
.concatMap(new Func1<Person, Observable<Person>>() {
@Override
public Observable<Person> call(Person person) {
return data.insert(person).toObservable();
}
});
Person p = data.insert(person).toBlocking().value();
assertTrue(p.getId() > 0);
int count = data.count(Person.class).get().toSingle().toBlocking().value();
assertEquals(1, count);
}
@Test
public void testInsertOneToMany() throws Exception {
final Person person = randomPerson();
data.insert(person).map(new Func1<Person, Phone>() {
@Override
public Phone call(Person person) {
Phone phone1 = randomPhone();
phone1.setOwner(person);
return phone1;
}
}).flatMap(new Func1<Phone, Single<?>>() {
@Override
public Single<?> call(Phone phone) {
return data.insert(phone);
}
}).toBlocking().value();
assertTrue(person.getPhoneNumbers().toList().size() == 1);
}
@Test
public void testQueryObservable() throws Exception {
for (int i = 0; i < 30; i++) {
Person person = randomPerson();
data.insert(person).toBlocking().value();
}
final List<Person> people = new ArrayList<>();
data.select(Person.class).limit(50).get()
.toObservable()
.subscribe(new Action1<Person>() {
@Override
public void call(Person person) {
people.add(person);
}
});
assertEquals(30, people.size());
}
@Test
public void testQuerySelfObservable() throws Exception {
final AtomicInteger count = new AtomicInteger();
data.select(Person.class).get().toSelfObservable().subscribe(
new Action1<Result<Person>>() {
@Override
public void call(Result<Person> persons) {
count.incrementAndGet();
}
});
data.insert(randomPerson()).toBlocking().value();
data.insert(randomPerson()).toBlocking().value();
assertEquals(3, count.get());
}
@Test
public void testQuerySelfObservableMap() throws Exception {
final AtomicInteger count = new AtomicInteger();
Subscription subscription = data.select(Person.class).limit(2).get().toSelfObservable()
.flatMap(new Func1<RxResult<Person>, Observable<Person>>() {
@Override
public Observable<Person> call(RxResult<Person> persons) {
return persons.toObservable();
}
}).subscribe(
new Action1<Person>() {
@Override
public void call(Person persons) {
count.incrementAndGet();
}
});
data.insert(randomPerson()).toBlocking().value();
data.insert(randomPerson()).toBlocking().value();
assertEquals(3, count.get());
subscription.unsubscribe();
}
@Test
public void testSelfObservableDelete() throws Exception {
final AtomicInteger count = new AtomicInteger();
Subscription subscription = data.select(Person.class).get().toSelfObservable().subscribe(
new Action1<Result<Person>>() {
@Override
public void call(Result<Person> persons) {
count.incrementAndGet();
}
});
Person person = randomPerson();
data.insert(person).toBlocking().value();
data.delete(person).toBlocking().value();
assertEquals(3, count.get());
subscription.unsubscribe();
}
@Test
public void testSelfObservableDeleteQuery() throws Exception {
final AtomicInteger count = new AtomicInteger();
Subscription subscription = data.select(Person.class).get().toSelfObservable().subscribe(
new Action1<Result<Person>>() {
@Override
public void call(Result<Person> persons) {
count.incrementAndGet();
}
});
Person person = randomPerson();
data.insert(person).toBlocking().value();
assertEquals(2, count.get());
int rows = data.delete(Person.class).get().value();
assertEquals(3, count.get());
subscription.unsubscribe();
assertEquals(rows, 1);
}
@Test
public void testQuerySelfObservableRelational() throws Exception {
final AtomicInteger count = new AtomicInteger();
Subscription subscription = data.select(Person.class).get().toSelfObservable().subscribe(
new Action1<Result<Person>>() {
@Override
public void call(Result<Person> persons) {
count.incrementAndGet();
}
});
Person person = randomPerson();
data.insert(person).toBlocking().value();
Phone phone = randomPhone();
person.getPhoneNumbers().add(phone);
data.update(person).toBlocking().value();
data.delete(phone).toBlocking().value();
assertEquals(4, count.get());
subscription.unsubscribe();
}
@Test
public void testQueryObservableFromEntity() throws Exception {
final Person person = randomPerson();
data.insert(person).map(new Func1<Person, Phone>() {
@Override
public Phone call(Person person) {
Phone phone1 = randomPhone();
phone1.setOwner(person);
return phone1;
}
}).flatMap(new Func1<Phone, Single<?>>() {
@Override
public Single<?> call(Phone phone) {
return data.insert(phone);
}
}).toBlocking().value();
int count = person.getPhoneNumbers().toList().size();
assertEquals(1, count);
}
@Test
public void testRunInTransaction() {
final Person person = randomPerson();
data.runInTransaction(
data.insert(person),
data.update(person),
data.delete(person)).toBlocking().forEach(new Action1<Object>() {
@Override
public void call(Object o) {
}
});
assertEquals(0, data.count(Person.class).get().value().intValue());
final Person person2 = randomPerson();
data.runInTransaction(
data.insert(person2)).toBlocking().forEach(new Action1<Person>() {
@Override
public void call(Person person) {
}
});
assertEquals(1, data.count(Person.class).get().value().intValue());
}
@Test
public void testQueryObservablePull() throws Exception {
for (int i = 0; i < 36; i++) {
Person person = randomPerson();
data.insert(person).toBlocking().value();
}
final List<Person> people = new ArrayList<>();
data.select(Person.class).get()
.toObservable()
//.observeOn(Schedulers.newThread())
.subscribeOn(Schedulers.immediate())
.subscribe(new Subscriber<Person>() {
@Override
public void onStart() {
super.onStart();
request(10);
}
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(Person person) {
//System.out.println("t: " + Thread.currentThread().getName());
people.add(person);
if (people.size() % 10 == 0 && people.size() > 1) {
request(10);
}
}
});
assertEquals(36, people.size());
}
}