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

Refactor the DatabasePagingSource to deal with orderbyChild queries #2165

Open
wants to merge 1 commit into
base: version-8.0.2-dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ public Builder<T> setQuery(@NonNull Query query,
public Builder<T> setQuery(@NonNull Query query,
@NonNull PagingConfig config,
@NotNull SnapshotParser<T> parser) {
final Pager<String, DataSnapshot> pager = new Pager<>(config,
final Pager<Object, DataSnapshot> pager = new Pager<>(config,
() -> new DatabasePagingSource(query));
mData = PagingLiveData.cachedIn(PagingLiveData.getLiveData(pager),
mOwner.getLifecycle());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package com.firebase.ui.database.paging;

import android.annotation.SuppressLint;
import android.util.Pair;

import com.google.android.gms.tasks.Task;
import com.google.android.gms.tasks.Tasks;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.Query;
import com.google.firebase.database.snapshot.Index;

import org.jetbrains.annotations.Nullable;

Expand All @@ -21,7 +23,7 @@
import io.reactivex.rxjava3.core.Single;
import io.reactivex.rxjava3.schedulers.Schedulers;

public class DatabasePagingSource extends RxPagingSource<String, DataSnapshot> {
public class DatabasePagingSource extends RxPagingSource<Object, DataSnapshot> {
private final Query mQuery;

private static final String STATUS_DATABASE_NOT_FOUND = "DATA_NOT_FOUND";
Expand All @@ -32,18 +34,45 @@ public DatabasePagingSource(Query query) {
this.mQuery = query;
}

public Query startAt_childvalue(Object startvalue, String keyvalue) {
if (startvalue instanceof String)
return mQuery.startAt((String) startvalue, keyvalue);
else if (startvalue instanceof Boolean)
return mQuery.startAt((Boolean) startvalue, keyvalue);
else if (startvalue instanceof Double)
return mQuery.startAt((Double) startvalue, keyvalue);
else if (startvalue instanceof Long)
return mQuery.startAt(((Long) startvalue).doubleValue(), keyvalue);
else
return mQuery;
}

/**
* DatabaseError.fromStatus() is not meant to be public.
*/
@SuppressLint("RestrictedApi")
@NonNull
@Override
public Single<LoadResult<String, DataSnapshot>> loadSingle(@NonNull LoadParams<String> params) {
public Single<LoadResult<Object, DataSnapshot>> loadSingle(@NonNull LoadParams<Object> params) {
Task<DataSnapshot> task;

Index queryChildPathIndex = mQuery.getSpec().getIndex();
Pair<Object, String> pKey = (Pair<Object, String>) params.getKey();

if (params.getKey() == null) {
task = mQuery.limitToFirst(params.getLoadSize()).get();
} else {
task = mQuery.startAt(null, params.getKey()).limitToFirst(params.getLoadSize() + 1).get();
//change mQuery.startAt at value if child index
//if not null then what we have here is orderByChild query
if (queryChildPathIndex != null) {//orderByChild query mode
task = startAt_childvalue(pKey.first, pKey.second)
.limitToFirst(params.getLoadSize() + 1)
.get();
} else {
task = mQuery.startAt(null, pKey.second)
.limitToFirst(params.getLoadSize() + 1)
.get();
}
}

return Single.fromCallable(() -> {
Expand All @@ -54,7 +83,7 @@ public Single<LoadResult<String, DataSnapshot>> loadSingle(@NonNull LoadParams<S

//Make List of DataSnapshot
List<DataSnapshot> data = new ArrayList<>();
String lastKey = null;
Pair<Object, String> lastKey = null;

if (params.getKey() == null) {
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
Expand All @@ -77,7 +106,14 @@ public Single<LoadResult<String, DataSnapshot>> loadSingle(@NonNull LoadParams<S
//Detect End of Data
if (!data.isEmpty()) {
//Get Last Key
lastKey = getLastPageKey(data);
Object lastkey_c = getLastPageChildKey(data, queryChildPathIndex);
String lastkey_k = getLastPageKey(data);
lastKey = (lastkey_c == null && lastkey_k == null)
? null
: (lastkey_k == null) ? new Pair<>(lastkey_c, "") : new Pair<>(
lastkey_c,
lastkey_k);

}
return toLoadResult(data, lastKey);
} else {
Expand All @@ -99,9 +135,9 @@ public Single<LoadResult<String, DataSnapshot>> loadSingle(@NonNull LoadParams<S
}).subscribeOn(Schedulers.io()).onErrorReturn(LoadResult.Error::new);
}

private LoadResult<String, DataSnapshot> toLoadResult(
private LoadResult<Object, DataSnapshot> toLoadResult(
@NonNull List<DataSnapshot> snapshots,
String nextPage
Pair<Object, String> nextPage
) {
return new LoadResult.Page<>(
snapshots,
Expand All @@ -111,6 +147,24 @@ private LoadResult<String, DataSnapshot> toLoadResult(
LoadResult.Page.COUNT_UNDEFINED);
}

@SuppressLint("RestrictedApi")
private Object getLastPageChildKey(@NonNull List<DataSnapshot> data, Index index) {
if (index == null) return null;
if (data.isEmpty()) {
return null;
} else {
return getChildValue(data.get(data.size() - 1), index);
}
}

@SuppressLint("RestrictedApi")
private Object getChildValue(DataSnapshot snapshot, Index index) {
String keypath = index.getQueryDefinition();
DataSnapshot data = snapshot.child(keypath);
if (!data.exists()) return null;
return data.getValue();
}

@Nullable
private String getLastPageKey(@NonNull List<DataSnapshot> data) {
if (data.isEmpty()) {
Expand All @@ -122,7 +176,7 @@ private String getLastPageKey(@NonNull List<DataSnapshot> data) {

@Nullable
@Override
public String getRefreshKey(@NonNull PagingState<String, DataSnapshot> state) {
public String getRefreshKey(@NonNull PagingState<Object, DataSnapshot> state) {
return null;
}
}