Skip to content

Fix bundle query resume issue #4824

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

Merged
merged 6 commits into from
Apr 14, 2023
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.
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 @@ -22,7 +22,6 @@
import com.google.firebase.firestore.core.Filter;
import com.google.firebase.firestore.core.OrderBy;
import com.google.firebase.firestore.core.Query;
import com.google.firebase.firestore.core.Target;
import com.google.firebase.firestore.model.DocumentKey;
import com.google.firebase.firestore.model.FieldPath;
import com.google.firebase.firestore.model.MutableDocument;
Expand Down Expand Up @@ -154,7 +153,20 @@ private BundledQuery decodeBundledQuery(JSONObject bundledQuery) throws JSONExce
Query.LimitType limitType = decodeLimitType(bundledQuery);

return new BundledQuery(
new Target(parent, collectionGroup, filters, orderBys, limit, startAt, endAt), limitType);
new Query(
parent,
collectionGroup,
filters,
orderBys,
limit,
// Not using `limitType` because bundled queries are what the backend sees,
// and there is no limit_to_last for the backend.
// Limit type is applied when the query is read back instead.
Query.LimitType.LIMIT_TO_FIRST,
startAt,
endAt)
.toTarget(),
limitType);
}

private int decodeLimit(JSONObject structuredQuery) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
import static org.junit.Assert.assertThrows;

import com.google.firebase.firestore.core.Query;
import com.google.firebase.firestore.core.Target;
import com.google.firebase.firestore.model.DatabaseId;
import com.google.firebase.firestore.model.ObjectValue;
import com.google.firebase.firestore.model.ResourcePath;
Expand Down Expand Up @@ -57,28 +56,34 @@ public class BundleReaderTest {
new NamedQuery(
"limitQuery",
new BundledQuery(
new Target(
ResourcePath.fromString("foo"),
null,
Collections.emptyList(),
Collections.singletonList(orderBy("sort")),
1,
null,
null),
new Query(
ResourcePath.fromString("foo"),
null,
Collections.emptyList(),
Collections.singletonList(orderBy("sort")),
1,
Query.LimitType.LIMIT_TO_FIRST,
null,
null)
.toTarget(),
Query.LimitType.LIMIT_TO_FIRST),
version(1590011379000001L));
public static final NamedQuery LIMIT_TO_LAST_QUERY =
new NamedQuery(
"limitToLastQuery",
new BundledQuery(
new Target(
ResourcePath.fromString("foo"),
null,
Collections.emptyList(),
Collections.singletonList(orderBy("sort")),
1,
null,
null),
new Query(
ResourcePath.fromString("foo"),
null,
Collections.emptyList(),
Collections.singletonList(orderBy("sort")),
1,
// Note this is LIMIT_TO_FIRST because it is the expected
// limit type in bundle files.
Query.LimitType.LIMIT_TO_FIRST,
null,
null)
.toTarget(),
Query.LimitType.LIMIT_TO_LAST),
version(1590011379000002L));
public static final BundledDocumentMetadata DELETED_DOC_METADATA =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,10 @@
@RunWith(RobolectricTestRunner.class)
@Config(manifest = Config.NONE)
public class BundleSerializerTest {
// Note: This tests uses single-quoted JSON strings, which are accepted by org.json.JSONObject.
// While they are invalid JSON, they allow us to no use non-escaped quotes in the test file.
// Note: This tests uses single-quoted JSON strings, which are accepted by
// org.json.JSONObject.
// While they are invalid JSON, they allow us to no use non-escaped quotes in
// the test file.

private static String TEST_PROJECT = "projects/project/databases/(default)/documents";
private static String TEST_DOCUMENT = TEST_PROJECT + "/coll/doc";
Expand Down Expand Up @@ -568,9 +570,34 @@ public void testDecodesLimitQuery() throws JSONException {

@Test
public void testDecodesLimitToLastQuery() throws JSONException {
String json = "{ from: [ { collectionId: 'coll' } ], limit: {value: 5 } }";
Query query = TestUtil.query("coll").limitToLast(5);
assertDecodesNamedQuery(json, query);
String queryJson =
"{\n"
+ " name: 'query-1',\n"
+ " bundledQuery: {\n"
+ " parent: '"
+ TEST_PROJECT
+ "',\n"
+ " structuredQuery:\n"
+ "{ from: [ { collectionId: 'coll' } ], limit: {value: 5 } }"
+ ",\n"
+ " limitType: 'LAST'\n"
+ " },\n"
+ " readTime: '2020-01-01T00:00:01.000000001Z'\n"
+ "}";
NamedQuery actualNamedQuery = serializer.decodeNamedQuery(new JSONObject(queryJson));

// Note we use limitToFirst instead of limitToLast to avoid order reverse.
// Because this is what is saved in bundle files.
Query query = TestUtil.query("coll").limitToFirst(5);
Target target = query.toTarget();
BundledQuery bundledQuery = new BundledQuery(target, Query.LimitType.LIMIT_TO_LAST);
NamedQuery expectedNamedQuery =
new NamedQuery(
"query-1",
bundledQuery,
new SnapshotVersion(new com.google.firebase.Timestamp(1577836801, 1)));

assertEquals(expectedNamedQuery, actualNamedQuery);
}

@Test
Expand Down Expand Up @@ -672,6 +699,33 @@ public void testDecodesBundledDocumentMetadata() throws JSONException {
assertEquals(expectedMetadata, actualMetadata);
}

@Test
public void testDecodesTargetWithoutImplicitOrderByOnName() throws JSONException {
String json =
"{\"name\":\"myNamedQuery\",\"bundledQuery\":{\"parent\":\"projects/project/databases"
+ "/(default)/documents\",\"structuredQuery\":{\"from\":[{\"collectionId\":\"foo\"}],"
+ "\"limit\":{\"value\":10}},\"limitType\":\"FIRST\"},"
+ "\"readTime\":{\"seconds\":\"1679674432\",\"nanos\":579934000}}";
NamedQuery query = serializer.decodeNamedQuery(new JSONObject(json));
assertEquals(
TestUtil.query("foo").limitToFirst(10).toTarget(), query.getBundledQuery().getTarget());
assertEquals(Query.LimitType.LIMIT_TO_FIRST, query.getBundledQuery().getLimitType());
}

@Test
public void testDecodesLimitToLastTargetWithoutImplicitOrderByOnName() throws JSONException {
String json =
"{\"name\":\"myNamedQuery\",\"bundledQuery\":{\"parent\":\"projects/project/databases"
+ "/(default)/documents\",\"structuredQuery\":{\"from\":[{\"collectionId\":\"foo\"}],"
+ "\"limit\":{\"value\":10}},\"limitType\":\"LAST\"},"
+ "\"readTime\":{\"seconds\":\"1679674432\",\"nanos\":579934000}}";
NamedQuery query = serializer.decodeNamedQuery(new JSONObject(json));
assertEquals(
// Note that `limitToFirst(10)` is expected.
TestUtil.query("foo").limitToFirst(10).toTarget(), query.getBundledQuery().getTarget());
assertEquals(Query.LimitType.LIMIT_TO_LAST, query.getBundledQuery().getLimitType());
}

private void assertDecodesValue(String json, Value proto) throws JSONException {
String documentJson =
"{\n"
Expand Down Expand Up @@ -719,15 +773,7 @@ private void assertDecodesNamedQuery(String json, Query query) throws JSONExcept
+ "}";
NamedQuery actualNamedQuery = serializer.decodeNamedQuery(new JSONObject(queryJson));

Target target =
new Target(
query.getPath(),
query.getCollectionGroup(),
query.getFilters(),
query.getExplicitOrderBy(),
query.getLimit(),
query.getStartAt(),
query.getEndAt());
Target target = query.toTarget();
BundledQuery bundledQuery =
new BundledQuery(
target,
Expand Down