Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Part2. Implement optional for SQLite #848

Merged
merged 2 commits into from Nov 13, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -0,0 +1,72 @@
package com.pushtorefresh.storio2;

import android.support.annotation.NonNull;
import android.support.annotation.Nullable;

public final class Optional<T> {

@NonNull
private transient static final Optional<?> EMPTY = new Optional<Object>(null);

@Nullable
private final T value;

private Optional(@Nullable T value) {
this.value = value;
}

@NonNull
public static <T> Optional<T> empty() {
//noinspection unchecked
return (Optional<T>) EMPTY;
}

@NonNull
public static <T> Optional<T> of(@Nullable T value) {
//noinspection unchecked
return value == null ? (Optional<T>) EMPTY : new Optional<T>(value);
}

@NonNull
public T get() {
if (value == null)
throw new NullPointerException();
return value;
}

public boolean isPresent() {
return value != null;
}

@NonNull
public T or(@NonNull T defaultValue) {
return value != null ? value : defaultValue;
}

@Nullable
public T orNull() {
return value;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;

Optional<?> optional = (Optional<?>) o;

return value != null ? value.equals(optional.value) : optional.value == null;
}

@Override
public int hashCode() {
return value != null ? value.hashCode() : 0;
}

@Override
public String toString() {
return "Optional{" +
"value=" + value +
'}';
}
}
Expand Up @@ -2,7 +2,6 @@

import android.support.annotation.CheckResult;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.WorkerThread;

import io.reactivex.BackpressureStrategy;
Expand All @@ -26,7 +25,7 @@ public interface PreparedOperation<Result, Data> {
*
* @return nullable result of operation.
*/
@Nullable
@NonNull
@WorkerThread
Result executeAsBlocking();

Expand Down
@@ -0,0 +1,103 @@
package com.pushtorefresh.storio2;

import com.pushtorefresh.storio2.test.ToStringChecker;

import org.assertj.core.api.ThrowableAssert;
import org.junit.Test;

import nl.jqno.equalsverifier.EqualsVerifier;

import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.assertj.core.api.Java6Assertions.assertThat;

public class OptionalTest {

@Test
public void emptyHasNullValue() {
assertThat(Optional.empty().orNull()).isEqualTo(null);
}

@Test
public void emptyReturnsTheSameInstance() {
assertThat(Optional.empty()).isSameAs(Optional.empty());
}

@Test
public void ofNullValueReturnsEmpty() {
assertThat(Optional.of(null)).isSameAs(Optional.empty());
}

@Test
public void ofNotNullValueReturnsEqualInstances() {
assertThat(Optional.of("some value"))
.isEqualTo(Optional.of("some value"));
}

@Test
public void getReturnsValueIfPresent() {
assertThat(Optional.of("some value").get()).isEqualTo("some value");
}

@Test
public void getThrowsIfNull() {
final Optional<Object> empty = Optional.empty();
assertThatThrownBy(new ThrowableAssert.ThrowingCallable() {
@Override
public void call() throws Throwable {
empty.get();
}
}).isInstanceOf(NullPointerException.class)
.hasMessage(null)
.hasNoCause();
}

@Test
public void isPresentReturnsTrueIfNotNull() {
assertThat(Optional.of("some value").isPresent()).isTrue();
}

@Test
public void isPresentReturnsFalseIfNull() {
assertThat(Optional.empty().isPresent()).isFalse();
}

@Test
public void orReturnsValueIfPresent() {
assertThat(Optional.of("some value").or("default value")).
isEqualTo("some value");
}

@Test
public void orReturnsDefaultIfNotPresent() {
assertThat(Optional.empty().or("default value")).
isEqualTo("default value");
}


@Test
public void orNullReturnsValueIfPresent() {
assertThat(Optional.of("some value").orNull()).
isEqualTo("some value");
}

@Test
public void orNullReturnsNullIfNotPresent() {
assertThat(Optional.empty().orNull()).isNull();
}

@Test
public void verifyEqualsAndHashCodeImplementation() {
EqualsVerifier
.forClass(Optional.class)
.allFieldsShouldBeUsed()
.withPrefabValues(Optional.class, Optional.of("some value"), Optional.of("another value"))
.verify();
}

@Test
public void checkToStringImplementation() {
ToStringChecker
.forClass(Optional.class)
.check();
}
}
Expand Up @@ -53,7 +53,7 @@ public class PreparedGetObject<T> extends PreparedGet<T> {
*/
@SuppressWarnings({"ConstantConditions", "NullableProblems"})
@WorkerThread
@Nullable
@NonNull
@Override
public T executeAsBlocking() {
try {
Expand Down
Expand Up @@ -13,6 +13,7 @@
import android.view.ViewGroup;
import android.widget.Toast;

import com.pushtorefresh.storio2.Optional;
import com.pushtorefresh.storio2.sample.R;
import com.pushtorefresh.storio2.sample.SampleApp;
import com.pushtorefresh.storio2.sample.db.entities.Tweet;
Expand Down Expand Up @@ -216,21 +217,24 @@ public void onUpdateTweet(@NonNull final Long tweetId) {
.prepare()
.asRxSingle()
// 2.
.map(new Function<Tweet, Tweet>() {
.map(new Function<Optional<Tweet>, Optional<Tweet>>() {
@Override
public Tweet apply(Tweet tweet) {
@NonNull
public Optional<Tweet> apply(@NonNull Optional<Tweet> tweet) {
// We can get NULL in parameter so we check it
return tweet == null ? tweet :
Tweet.newTweet(tweetId, tweet.author() + "+", tweet.content());
return tweet.isPresent()
? Optional.of(Tweet.newTweet(tweetId, tweet.get().author() + "+", tweet.get().content()))
: tweet;
}
})
// 3.
.flatMap(new Function<Tweet, Single<?>>() {
.flatMap(new Function<Optional<Tweet>, Single<?>>() {
@Override
public Single<?> apply(Tweet tweet) {
@NonNull
public Single<?> apply(Optional<Tweet> tweet) {
return storIOSQLite
.put()
.object(tweet)
.object(tweet.get())
.prepare()
.asRxSingle();
}
Expand All @@ -239,7 +243,7 @@ public Single<?> apply(Tweet tweet) {
.observeOn(mainThread())
.subscribe(new Consumer<Object>() {
@Override
public void accept(Object o) {
public void accept(@NonNull Object o) {

}
}, new Consumer<Throwable>() {
Expand Down
@@ -1,7 +1,6 @@
package com.pushtorefresh.storio2.sqlite;

import android.support.annotation.NonNull;
import android.support.annotation.Nullable;

import com.pushtorefresh.storio2.operations.PreparedOperation;

Expand All @@ -12,15 +11,15 @@
*/
public interface Interceptor {

@Nullable
@NonNull
<Result, Data> Result intercept(@NonNull PreparedOperation<Result, Data> operation, @NonNull Chain chain);

/**
* Encapsulates logic of proceeding from one interceptor to another.
*/
interface Chain {

@Nullable
@NonNull
<Result, Data> Result proceed(@NonNull PreparedOperation<Result, Data> operation);
}
}
Expand Up @@ -2,7 +2,6 @@

import android.os.SystemClock;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;

import com.pushtorefresh.storio2.operations.PreparedOperation;
Expand Down Expand Up @@ -33,7 +32,7 @@ private LoggingInterceptor(@NonNull Logger logger) {
this.logger = logger;
}

@Nullable
@NonNull
@Override
public <Result, Data> Result intercept(@NonNull PreparedOperation<Result, Data> operation, @NonNull Chain chain) {
final long startMillis = SystemClock.elapsedRealtime();
Expand Down
@@ -1,7 +1,6 @@
package com.pushtorefresh.storio2.sqlite.impl;

import android.support.annotation.NonNull;
import android.support.annotation.Nullable;

import com.pushtorefresh.storio2.operations.PreparedOperation;
import com.pushtorefresh.storio2.sqlite.Interceptor;
Expand Down Expand Up @@ -37,7 +36,7 @@ public ChainImpl(@NonNull ListIterator<Interceptor> interceptors) {
this.interceptors = interceptors;
}

@Nullable // can be null on PreparedGetObject
@NonNull
@Override
public <Result, Data> Result proceed(@NonNull PreparedOperation<Result, Data> operation) {
if (!interceptors.hasNext()) {
Expand All @@ -55,8 +54,7 @@ public <Result, Data> Result proceed(@NonNull PreparedOperation<Result, Data> op
// Call the nextChain nextInterceptor in the chain.
final Interceptor nextInterceptor = interceptors.next();
final ChainImpl nextChain = new ChainImpl(interceptors);
final Result result = nextInterceptor.intercept(operation, nextChain);

return result;
return nextInterceptor.intercept(operation, nextChain);
}
}
@@ -1,7 +1,6 @@
package com.pushtorefresh.storio2.sqlite.operations.delete;

import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.WorkerThread;

import com.pushtorefresh.storio2.operations.PreparedWriteOperation;
Expand Down Expand Up @@ -37,7 +36,7 @@ public abstract class PreparedDelete<T, Data> implements PreparedWriteOperation<
* @return non-null result of Delete Operation.
*/
@WorkerThread
@Nullable
@NonNull
public final T executeAsBlocking() {
return buildChain(storIOSQLite.interceptors(), getRealCallInterceptor())
.proceed(this);
Expand Down
Expand Up @@ -112,6 +112,7 @@ public <Result, Data> Result intercept(@NonNull PreparedOperation<Result, Data>
);
storIOSQLite.lowLevel().notifyAboutChanges(changes);
}
//noinspection unchecked
return (Result) deleteResult;
} catch (Exception exception) {
throw new StorIOException("Error has occurred during Delete operation. query = " + deleteQuery, exception);
Expand Down
Expand Up @@ -51,7 +51,7 @@ public abstract class PreparedGet<Result> implements PreparedOperation<Result, G
* @return result of an operation. Can be null in get(Object).
*/
@WorkerThread
@Nullable
@NonNull
public final Result executeAsBlocking() {
return buildChain(storIOSQLite.interceptors(), getRealCallInterceptor())
.proceed(this);
Expand Down