From 817f455e45e6e1c2daa467a6f801cbe353e72e37 Mon Sep 17 00:00:00 2001 From: abhinav Date: Mon, 12 Aug 2019 13:47:15 +0530 Subject: [PATCH 1/7] Fix getAll and get methods With observer --- .../cloud/firestore/DocumentReference.java | 10 ++ .../com/google/cloud/firestore/Firestore.java | 14 +++ .../google/cloud/firestore/FirestoreImpl.java | 92 +++++++++++++++++++ .../cloud/firestore/it/ITSystemTest.java | 52 +++++++++++ 4 files changed, 168 insertions(+) diff --git a/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/DocumentReference.java b/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/DocumentReference.java index 3a6e95b8ad33..d888970a3b2b 100644 --- a/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/DocumentReference.java +++ b/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/DocumentReference.java @@ -21,6 +21,7 @@ import com.google.api.core.ApiFutures; import com.google.api.gax.rpc.ApiException; import com.google.api.gax.rpc.ApiExceptions; +import com.google.api.gax.rpc.ApiStreamObserver; import com.google.cloud.firestore.v1.FirestoreClient.ListCollectionIdsPagedResponse; import com.google.common.util.concurrent.MoreExecutors; import com.google.firestore.v1.ListCollectionIdsRequest; @@ -354,6 +355,15 @@ public ApiFuture get() { return extractFirst(firestore.getAll(this)); } + /** Reads the document referenced by this DocumentReference. */ + @Nonnull + public void get( + @Nullable FieldMask fieldMask, + ApiStreamObserver responseObserver, + DocumentReference documentReference) { + firestore.getAll(fieldMask, responseObserver, documentReference); + } + /** * Fetches the subcollections that are direct children of this document. * diff --git a/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Firestore.java b/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Firestore.java index cf1be3eb3826..51d95bae8d9d 100644 --- a/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Firestore.java +++ b/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Firestore.java @@ -17,6 +17,7 @@ package com.google.cloud.firestore; import com.google.api.core.ApiFuture; +import com.google.api.gax.rpc.ApiStreamObserver; import com.google.cloud.Service; import java.util.List; import javax.annotation.Nonnull; @@ -117,6 +118,19 @@ ApiFuture runTransaction( ApiFuture> getAll( @Nonnull DocumentReference[] documentReferences, @Nullable FieldMask fieldMask); + /** + * Retrieves multiple documents from Firestore, while optionally applying a field mask to reduce + * the amount of data transmitted. + * + * @param documentReferences Array with Document References to fetch. + * @param responseObserver ApiStreamObserver of DocumentSnapshot + * @param fieldMask If set, specifies the subset of fields to return. + */ + void getAll( + @Nullable FieldMask fieldMask, + final ApiStreamObserver responseObserver, + DocumentReference... documentReferences); + /** * Gets a Firestore {@link WriteBatch} instance that can be used to combine multiple writes. * diff --git a/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/FirestoreImpl.java b/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/FirestoreImpl.java index 77a29901c995..0c94e6873c81 100644 --- a/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/FirestoreImpl.java +++ b/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/FirestoreImpl.java @@ -248,6 +248,98 @@ public void onCompleted() { return futureList; } + void getAll( + final DocumentReference[] documentReferences, + @Nullable FieldMask fieldMask, + @Nullable ByteString transactionId, + final ApiStreamObserver apiStreamObserver) { + ApiStreamObserver responseObserver = + new ApiStreamObserver() { + int numResponses; + + @Override + public void onNext(BatchGetDocumentsResponse response) { + DocumentReference documentReference; + DocumentSnapshot documentSnapshot; + + numResponses++; + if (numResponses == 1) { + tracer.getCurrentSpan().addAnnotation("Firestore.BatchGet: First response"); + } else if (numResponses % 100 == 0) { + tracer.getCurrentSpan().addAnnotation("Firestore.BatchGet: Received 100 responses"); + } + + switch (response.getResultCase()) { + case FOUND: + documentSnapshot = + DocumentSnapshot.fromDocument( + FirestoreImpl.this, + Timestamp.fromProto(response.getReadTime()), + response.getFound()); + break; + case MISSING: + documentReference = + new DocumentReference( + FirestoreImpl.this, ResourcePath.create(response.getMissing())); + documentSnapshot = + DocumentSnapshot.fromMissing( + FirestoreImpl.this, + documentReference, + Timestamp.fromProto(response.getReadTime())); + break; + default: + return; + } + apiStreamObserver.onNext(documentSnapshot); + } + + @Override + public void onError(Throwable throwable) { + tracer.getCurrentSpan().addAnnotation("Firestore.BatchGet: Error"); + apiStreamObserver.onError(throwable.getCause()); + } + + @Override + public void onCompleted() { + tracer.getCurrentSpan().addAnnotation("Firestore.BatchGet: Complete"); + apiStreamObserver.onCompleted(); + } + }; + + BatchGetDocumentsRequest.Builder request = BatchGetDocumentsRequest.newBuilder(); + request.setDatabase(getDatabaseName()); + + if (fieldMask != null) { + request.setMask(fieldMask.toPb()); + } + + if (transactionId != null) { + request.setTransaction(transactionId); + } + + for (DocumentReference docRef : documentReferences) { + request.addDocuments(docRef.getName()); + } + + tracer + .getCurrentSpan() + .addAnnotation( + "Firestore.BatchGet: Start", + ImmutableMap.of( + "numDocuments", AttributeValue.longAttributeValue(documentReferences.length))); + + streamRequest(request.build(), responseObserver, firestoreClient.batchGetDocumentsCallable()); + } + + @Nonnull + @Override + public void getAll( + @Nullable FieldMask fieldMask, + final ApiStreamObserver responseObserver, + DocumentReference... documentReferences) { + this.getAll(documentReferences, fieldMask, null, responseObserver); + } + @Nonnull @Override public Query collectionGroup(@Nonnull final String collectionId) { diff --git a/google-cloud-clients/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITSystemTest.java b/google-cloud-clients/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITSystemTest.java index de19f5492da7..f55f3ed2785e 100644 --- a/google-cloud-clients/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITSystemTest.java +++ b/google-cloud-clients/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITSystemTest.java @@ -29,6 +29,7 @@ import com.google.api.core.ApiFuture; import com.google.api.core.ApiFutures; +import com.google.api.gax.rpc.ApiStreamObserver; import com.google.cloud.Timestamp; import com.google.cloud.firestore.CollectionReference; import com.google.cloud.firestore.DocumentChange; @@ -1327,4 +1328,55 @@ private static final class ListenerEvent { this.error = error; } } + + @Test + public void getAllWithObserver() throws Exception { + DocumentReference ref = randomColl.document("doc1"); + ref.set(ALL_SUPPORTED_TYPES_MAP).get(); + + final List documentSnapshots = new ArrayList<>(); + final DocumentReference[] documentReferences = {ref}; + firestore.getAll( + FieldMask.of("foo"), + new ApiStreamObserver() { + + @Override + public void onNext(DocumentSnapshot documentSnapshot) { + documentSnapshots.add(documentSnapshot); + } + + @Override + public void onError(Throwable throwable) {} + + @Override + public void onCompleted() {} + }, + documentReferences); + Thread.sleep(1000); + assertEquals(map("foo", "bar"), documentSnapshots.get(0).getData()); + } + + @Test + public void getWithObserver() throws Exception { + final DocumentReference ref = randomColl.document("doc1"); + final List documentSnapshots = new ArrayList<>(); + ref.set(ALL_SUPPORTED_TYPES_MAP).get(); + ApiStreamObserver responseObserver = + new ApiStreamObserver() { + + @Override + public void onNext(DocumentSnapshot documentSnapshot) { + documentSnapshots.add(documentSnapshot); + } + + @Override + public void onError(Throwable throwable) {} + + @Override + public void onCompleted() {} + }; + ref.get(FieldMask.of("foo"), responseObserver, ref); + Thread.sleep(1000); + assertEquals(map("foo", "bar"), documentSnapshots.get(0).getData()); + } } From e28a7ba43049c2c66218162b752490681661e4cb Mon Sep 17 00:00:00 2001 From: abhinav Date: Mon, 12 Aug 2019 15:13:40 +0530 Subject: [PATCH 2/7] Fix getAll and get method changes --- .../main/java/com/google/cloud/firestore/DocumentReference.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/DocumentReference.java b/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/DocumentReference.java index d888970a3b2b..dc38ecbb5cf1 100644 --- a/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/DocumentReference.java +++ b/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/DocumentReference.java @@ -359,7 +359,7 @@ public ApiFuture get() { @Nonnull public void get( @Nullable FieldMask fieldMask, - ApiStreamObserver responseObserver, + ApiStreamObserver responseObserver, DocumentReference documentReference) { firestore.getAll(fieldMask, responseObserver, documentReference); } From c998ec4f948b985b875a838d81ff6b452d3a48a3 Mon Sep 17 00:00:00 2001 From: abhinav Date: Mon, 12 Aug 2019 18:31:37 +0530 Subject: [PATCH 3/7] getAll and get method changes --- .../com/google/cloud/firestore/DocumentReference.java | 2 +- .../java/com/google/cloud/firestore/FirestoreImpl.java | 1 + .../java/com/google/cloud/firestore/it/ITSystemTest.java | 9 +++++++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/DocumentReference.java b/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/DocumentReference.java index dc38ecbb5cf1..60ddee0bcf78 100644 --- a/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/DocumentReference.java +++ b/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/DocumentReference.java @@ -355,7 +355,7 @@ public ApiFuture get() { return extractFirst(firestore.getAll(this)); } - /** Reads the document referenced by this DocumentReference. */ + /** fetches the document reference in the form of the stream inside apiStreamObserver */ @Nonnull public void get( @Nullable FieldMask fieldMask, diff --git a/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/FirestoreImpl.java b/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/FirestoreImpl.java index 0c94e6873c81..a78c34ed9e68 100644 --- a/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/FirestoreImpl.java +++ b/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/FirestoreImpl.java @@ -288,6 +288,7 @@ public void onNext(BatchGetDocumentsResponse response) { Timestamp.fromProto(response.getReadTime())); break; default: + tracer.getCurrentSpan().addAnnotation("Unknown ResultCase received"); return; } apiStreamObserver.onNext(documentSnapshot); diff --git a/google-cloud-clients/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITSystemTest.java b/google-cloud-clients/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITSystemTest.java index f55f3ed2785e..2d4b2e1a2148 100644 --- a/google-cloud-clients/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITSystemTest.java +++ b/google-cloud-clients/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITSystemTest.java @@ -77,6 +77,7 @@ import java.util.concurrent.atomic.AtomicInteger; import javax.annotation.Nullable; import org.junit.After; +import org.junit.Assert; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -1346,7 +1347,9 @@ public void onNext(DocumentSnapshot documentSnapshot) { } @Override - public void onError(Throwable throwable) {} + public void onError(Throwable throwable) { + Assert.fail("Error occurred while streaming"); + } @Override public void onCompleted() {} @@ -1370,7 +1373,9 @@ public void onNext(DocumentSnapshot documentSnapshot) { } @Override - public void onError(Throwable throwable) {} + public void onError(Throwable throwable) { + Assert.fail("Error occurred while streaming"); + } @Override public void onCompleted() {} From 0cdd424bfd60f293e2d7b2116d7c3a43d9141fbc Mon Sep 17 00:00:00 2001 From: abhinav Date: Tue, 20 Aug 2019 13:28:38 +0530 Subject: [PATCH 4/7] get method javadoc changes --- .../main/java/com/google/cloud/firestore/DocumentReference.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/DocumentReference.java b/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/DocumentReference.java index 60ddee0bcf78..671b60d058fc 100644 --- a/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/DocumentReference.java +++ b/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/DocumentReference.java @@ -355,7 +355,7 @@ public ApiFuture get() { return extractFirst(firestore.getAll(this)); } - /** fetches the document reference in the form of the stream inside apiStreamObserver */ + /** Fetches the document reference in the form of the stream inside apiStreamObserver */ @Nonnull public void get( @Nullable FieldMask fieldMask, From a553d5ac71a882f17d9abc804765029e7155cd8e Mon Sep 17 00:00:00 2001 From: abhinav Date: Wed, 28 Aug 2019 17:00:04 +0530 Subject: [PATCH 5/7] Fix review changes --- .../cloud/firestore/DocumentReference.java | 10 -- .../com/google/cloud/firestore/Firestore.java | 11 +- .../google/cloud/firestore/FirestoreImpl.java | 118 ++++-------------- .../google/cloud/firestore/Transaction.java | 7 +- .../cloud/firestore/it/ITSystemTest.java | 57 ++++----- 5 files changed, 58 insertions(+), 145 deletions(-) diff --git a/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/DocumentReference.java b/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/DocumentReference.java index 671b60d058fc..3a6e95b8ad33 100644 --- a/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/DocumentReference.java +++ b/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/DocumentReference.java @@ -21,7 +21,6 @@ import com.google.api.core.ApiFutures; import com.google.api.gax.rpc.ApiException; import com.google.api.gax.rpc.ApiExceptions; -import com.google.api.gax.rpc.ApiStreamObserver; import com.google.cloud.firestore.v1.FirestoreClient.ListCollectionIdsPagedResponse; import com.google.common.util.concurrent.MoreExecutors; import com.google.firestore.v1.ListCollectionIdsRequest; @@ -355,15 +354,6 @@ public ApiFuture get() { return extractFirst(firestore.getAll(this)); } - /** Fetches the document reference in the form of the stream inside apiStreamObserver */ - @Nonnull - public void get( - @Nullable FieldMask fieldMask, - ApiStreamObserver responseObserver, - DocumentReference documentReference) { - firestore.getAll(fieldMask, responseObserver, documentReference); - } - /** * Fetches the subcollections that are direct children of this document. * diff --git a/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Firestore.java b/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Firestore.java index 51d95bae8d9d..f37835a9eb8e 100644 --- a/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Firestore.java +++ b/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Firestore.java @@ -119,17 +119,18 @@ ApiFuture> getAll( @Nonnull DocumentReference[] documentReferences, @Nullable FieldMask fieldMask); /** - * Retrieves multiple documents from Firestore, while optionally applying a field mask to reduce - * the amount of data transmitted. + * Retrieves multiple documents from Firestore while optionally applying a field mask to reduce + * the amount of data transmitted. Returned documents will be out of order and missing documents + * will not be returned. * * @param documentReferences Array with Document References to fetch. - * @param responseObserver ApiStreamObserver of DocumentSnapshot * @param fieldMask If set, specifies the subset of fields to return. + * @param responseObserver ApiStreamObserver of DocumentSnapshot */ void getAll( + @Nonnull DocumentReference[] documentReferences, @Nullable FieldMask fieldMask, - final ApiStreamObserver responseObserver, - DocumentReference... documentReferences); + final ApiStreamObserver responseObserver); /** * Gets a Firestore {@link WriteBatch} instance that can be used to combine multiple writes. diff --git a/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/FirestoreImpl.java b/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/FirestoreImpl.java index a78c34ed9e68..17d8648eb361 100644 --- a/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/FirestoreImpl.java +++ b/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/FirestoreImpl.java @@ -140,21 +140,31 @@ public Iterable getCollections() { @Override public ApiFuture> getAll( @Nonnull DocumentReference... documentReferences) { - return this.getAll(documentReferences, null, null); + return this.getAll(documentReferences, null, null, null); } @Nonnull @Override public ApiFuture> getAll( @Nonnull DocumentReference[] documentReferences, @Nullable FieldMask fieldMask) { - return this.getAll(documentReferences, fieldMask, null); + return this.getAll(documentReferences, fieldMask, null, null); + } + + @Nonnull + @Override + public void getAll( + @Nonnull DocumentReference[] documentReferences, + @Nullable FieldMask fieldMask, + final ApiStreamObserver responseObserver) { + this.getAll(documentReferences, fieldMask, null, responseObserver); } /** Internal getAll() method that accepts an optional transaction id. */ ApiFuture> getAll( final DocumentReference[] documentReferences, @Nullable FieldMask fieldMask, - @Nullable ByteString transactionId) { + @Nullable ByteString transactionId, + @Nullable final ApiStreamObserver apiStreamObserver) { final SettableApiFuture> futureList = SettableApiFuture.create(); final Map resultMap = new HashMap<>(); @@ -200,12 +210,18 @@ public void onNext(BatchGetDocumentsResponse response) { } resultMap.put(documentReference, documentSnapshot); + if (null != apiStreamObserver) { + apiStreamObserver.onNext(documentSnapshot); + } } @Override public void onError(Throwable throwable) { tracer.getCurrentSpan().addAnnotation("Firestore.BatchGet: Error"); futureList.setException(throwable); + if (null != apiStreamObserver) { + apiStreamObserver.onError(throwable); + } } @Override @@ -218,92 +234,9 @@ public void onCompleted() { } futureList.set(documentSnapshots); - } - }; - - BatchGetDocumentsRequest.Builder request = BatchGetDocumentsRequest.newBuilder(); - request.setDatabase(getDatabaseName()); - - if (fieldMask != null) { - request.setMask(fieldMask.toPb()); - } - - if (transactionId != null) { - request.setTransaction(transactionId); - } - - for (DocumentReference docRef : documentReferences) { - request.addDocuments(docRef.getName()); - } - - tracer - .getCurrentSpan() - .addAnnotation( - "Firestore.BatchGet: Start", - ImmutableMap.of( - "numDocuments", AttributeValue.longAttributeValue(documentReferences.length))); - - streamRequest(request.build(), responseObserver, firestoreClient.batchGetDocumentsCallable()); - - return futureList; - } - - void getAll( - final DocumentReference[] documentReferences, - @Nullable FieldMask fieldMask, - @Nullable ByteString transactionId, - final ApiStreamObserver apiStreamObserver) { - ApiStreamObserver responseObserver = - new ApiStreamObserver() { - int numResponses; - - @Override - public void onNext(BatchGetDocumentsResponse response) { - DocumentReference documentReference; - DocumentSnapshot documentSnapshot; - - numResponses++; - if (numResponses == 1) { - tracer.getCurrentSpan().addAnnotation("Firestore.BatchGet: First response"); - } else if (numResponses % 100 == 0) { - tracer.getCurrentSpan().addAnnotation("Firestore.BatchGet: Received 100 responses"); - } - - switch (response.getResultCase()) { - case FOUND: - documentSnapshot = - DocumentSnapshot.fromDocument( - FirestoreImpl.this, - Timestamp.fromProto(response.getReadTime()), - response.getFound()); - break; - case MISSING: - documentReference = - new DocumentReference( - FirestoreImpl.this, ResourcePath.create(response.getMissing())); - documentSnapshot = - DocumentSnapshot.fromMissing( - FirestoreImpl.this, - documentReference, - Timestamp.fromProto(response.getReadTime())); - break; - default: - tracer.getCurrentSpan().addAnnotation("Unknown ResultCase received"); - return; + if (null != apiStreamObserver) { + apiStreamObserver.onCompleted(); } - apiStreamObserver.onNext(documentSnapshot); - } - - @Override - public void onError(Throwable throwable) { - tracer.getCurrentSpan().addAnnotation("Firestore.BatchGet: Error"); - apiStreamObserver.onError(throwable.getCause()); - } - - @Override - public void onCompleted() { - tracer.getCurrentSpan().addAnnotation("Firestore.BatchGet: Complete"); - apiStreamObserver.onCompleted(); } }; @@ -330,15 +263,8 @@ public void onCompleted() { "numDocuments", AttributeValue.longAttributeValue(documentReferences.length))); streamRequest(request.build(), responseObserver, firestoreClient.batchGetDocumentsCallable()); - } - @Nonnull - @Override - public void getAll( - @Nullable FieldMask fieldMask, - final ApiStreamObserver responseObserver, - DocumentReference... documentReferences) { - this.getAll(documentReferences, fieldMask, null, responseObserver); + return futureList; } @Nonnull diff --git a/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Transaction.java b/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Transaction.java index 13f51c0c7aec..a3f844fa41f0 100644 --- a/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Transaction.java +++ b/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Transaction.java @@ -137,7 +137,8 @@ public ApiFuture get(@Nonnull DocumentReference documentRef) { Preconditions.checkState(isEmpty(), READ_BEFORE_WRITE_ERROR_MSG); return ApiFutures.transform( - firestore.getAll(new DocumentReference[] {documentRef}, /*fieldMask=*/ null, transactionId), + firestore.getAll( + new DocumentReference[] {documentRef}, /*fieldMask=*/ null, transactionId, null), new ApiFunction, DocumentSnapshot>() { @Override public DocumentSnapshot apply(List snapshots) { @@ -158,7 +159,7 @@ public ApiFuture> getAll( @Nonnull DocumentReference... documentReferences) { Preconditions.checkState(isEmpty(), READ_BEFORE_WRITE_ERROR_MSG); - return firestore.getAll(documentReferences, /*fieldMask=*/ null, transactionId); + return firestore.getAll(documentReferences, /*fieldMask=*/ null, transactionId, null); } /** @@ -174,7 +175,7 @@ public ApiFuture> getAll( @Nonnull DocumentReference[] documentReferences, @Nullable FieldMask fieldMask) { Preconditions.checkState(isEmpty(), READ_BEFORE_WRITE_ERROR_MSG); - return firestore.getAll(documentReferences, fieldMask, transactionId); + return firestore.getAll(documentReferences, fieldMask, transactionId, null); } /** diff --git a/google-cloud-clients/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITSystemTest.java b/google-cloud-clients/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITSystemTest.java index 2d4b2e1a2148..cdbff02111f4 100644 --- a/google-cloud-clients/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITSystemTest.java +++ b/google-cloud-clients/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITSystemTest.java @@ -29,6 +29,7 @@ import com.google.api.core.ApiFuture; import com.google.api.core.ApiFutures; +import com.google.api.core.SettableApiFuture; import com.google.api.gax.rpc.ApiStreamObserver; import com.google.cloud.Timestamp; import com.google.cloud.firestore.CollectionReference; @@ -77,7 +78,6 @@ import java.util.concurrent.atomic.AtomicInteger; import javax.annotation.Nullable; import org.junit.After; -import org.junit.Assert; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -1335,9 +1335,18 @@ public void getAllWithObserver() throws Exception { DocumentReference ref = randomColl.document("doc1"); ref.set(ALL_SUPPORTED_TYPES_MAP).get(); + DocumentReference ref1 = randomColl.document("doc2"); + ref1.set(ALL_SUPPORTED_TYPES_MAP).get(); + + DocumentReference ref2 = randomColl.document("doc3"); + ref2.set(ALL_SUPPORTED_TYPES_MAP).get(); + ref2.delete(); + final List documentSnapshots = new ArrayList<>(); - final DocumentReference[] documentReferences = {ref}; + final DocumentReference[] documentReferences = {ref, ref1, ref2}; + final SettableApiFuture future = SettableApiFuture.create(); firestore.getAll( + documentReferences, FieldMask.of("foo"), new ApiStreamObserver() { @@ -1348,40 +1357,26 @@ public void onNext(DocumentSnapshot documentSnapshot) { @Override public void onError(Throwable throwable) { - Assert.fail("Error occurred while streaming"); + future.setException(throwable); } @Override - public void onCompleted() {} - }, - documentReferences); - Thread.sleep(1000); - assertEquals(map("foo", "bar"), documentSnapshots.get(0).getData()); - } - - @Test - public void getWithObserver() throws Exception { - final DocumentReference ref = randomColl.document("doc1"); - final List documentSnapshots = new ArrayList<>(); - ref.set(ALL_SUPPORTED_TYPES_MAP).get(); - ApiStreamObserver responseObserver = - new ApiStreamObserver() { - - @Override - public void onNext(DocumentSnapshot documentSnapshot) { - documentSnapshots.add(documentSnapshot); + public void onCompleted() { + future.set(null); } + }); - @Override - public void onError(Throwable throwable) { - Assert.fail("Error occurred while streaming"); - } + future.get(); - @Override - public void onCompleted() {} - }; - ref.get(FieldMask.of("foo"), responseObserver, ref); - Thread.sleep(1000); - assertEquals(map("foo", "bar"), documentSnapshots.get(0).getData()); + if (null != documentSnapshots && documentSnapshots.size() > 0) { + for (DocumentSnapshot documentSnapshot : documentSnapshots) { + if (null != documentSnapshot.getData()) { + assertEquals(map("foo", "bar"), documentSnapshot.getData()); + } else { + assertFalse(documentSnapshot.exists()); + } + } + } + assertEquals(3, documentSnapshots.size()); } } From 70b827f2502f3c4bc7dfda0f28c0dd7d25f563ce Mon Sep 17 00:00:00 2001 From: abhinav Date: Mon, 2 Sep 2019 16:18:27 +0530 Subject: [PATCH 6/7] review changes --- .../com/google/cloud/firestore/Firestore.java | 5 +- .../google/cloud/firestore/FirestoreImpl.java | 75 ++++++++++--------- .../google/cloud/firestore/Transaction.java | 7 +- .../cloud/firestore/it/ITSystemTest.java | 35 ++++----- 4 files changed, 64 insertions(+), 58 deletions(-) diff --git a/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Firestore.java b/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Firestore.java index f37835a9eb8e..2d2e722bef4c 100644 --- a/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Firestore.java +++ b/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Firestore.java @@ -19,6 +19,7 @@ import com.google.api.core.ApiFuture; import com.google.api.gax.rpc.ApiStreamObserver; import com.google.cloud.Service; +import com.google.protobuf.ByteString; import java.util.List; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -124,12 +125,14 @@ ApiFuture> getAll( * will not be returned. * * @param documentReferences Array with Document References to fetch. - * @param fieldMask If set, specifies the subset of fields to return. + * @param fieldMask If not null, specifies the subset of fields to return. + * @param transactionId Id of {@link Transaction} * @param responseObserver ApiStreamObserver of DocumentSnapshot */ void getAll( @Nonnull DocumentReference[] documentReferences, @Nullable FieldMask fieldMask, + @Nullable ByteString transactionId, final ApiStreamObserver responseObserver); /** diff --git a/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/FirestoreImpl.java b/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/FirestoreImpl.java index 17d8648eb361..855140dbd36f 100644 --- a/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/FirestoreImpl.java +++ b/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/FirestoreImpl.java @@ -140,33 +140,23 @@ public Iterable getCollections() { @Override public ApiFuture> getAll( @Nonnull DocumentReference... documentReferences) { - return this.getAll(documentReferences, null, null, null); + return this.getAll(documentReferences, null, null); } @Nonnull @Override public ApiFuture> getAll( @Nonnull DocumentReference[] documentReferences, @Nullable FieldMask fieldMask) { - return this.getAll(documentReferences, fieldMask, null, null); + return this.getAll(documentReferences, fieldMask, null); } @Nonnull @Override public void getAll( - @Nonnull DocumentReference[] documentReferences, - @Nullable FieldMask fieldMask, - final ApiStreamObserver responseObserver) { - this.getAll(documentReferences, fieldMask, null, responseObserver); - } - - /** Internal getAll() method that accepts an optional transaction id. */ - ApiFuture> getAll( - final DocumentReference[] documentReferences, + final @Nonnull DocumentReference[] documentReferences, @Nullable FieldMask fieldMask, @Nullable ByteString transactionId, - @Nullable final ApiStreamObserver apiStreamObserver) { - final SettableApiFuture> futureList = SettableApiFuture.create(); - final Map resultMap = new HashMap<>(); + final ApiStreamObserver apiStreamObserver) { ApiStreamObserver responseObserver = new ApiStreamObserver() { @@ -186,9 +176,6 @@ public void onNext(BatchGetDocumentsResponse response) { switch (response.getResultCase()) { case FOUND: - documentReference = - new DocumentReference( - FirestoreImpl.this, ResourcePath.create(response.getFound().getName())); documentSnapshot = DocumentSnapshot.fromDocument( FirestoreImpl.this, @@ -208,35 +195,19 @@ public void onNext(BatchGetDocumentsResponse response) { default: return; } - - resultMap.put(documentReference, documentSnapshot); - if (null != apiStreamObserver) { - apiStreamObserver.onNext(documentSnapshot); - } + apiStreamObserver.onNext(documentSnapshot); } @Override public void onError(Throwable throwable) { tracer.getCurrentSpan().addAnnotation("Firestore.BatchGet: Error"); - futureList.setException(throwable); - if (null != apiStreamObserver) { - apiStreamObserver.onError(throwable); - } + apiStreamObserver.onError(throwable); } @Override public void onCompleted() { tracer.getCurrentSpan().addAnnotation("Firestore.BatchGet: Complete"); - List documentSnapshots = new ArrayList<>(); - - for (DocumentReference documentReference : documentReferences) { - documentSnapshots.add(resultMap.get(documentReference)); - } - - futureList.set(documentSnapshots); - if (null != apiStreamObserver) { - apiStreamObserver.onCompleted(); - } + apiStreamObserver.onCompleted(); } }; @@ -263,7 +234,39 @@ public void onCompleted() { "numDocuments", AttributeValue.longAttributeValue(documentReferences.length))); streamRequest(request.build(), responseObserver, firestoreClient.batchGetDocumentsCallable()); + } + /** Internal getAll() method that accepts an optional transaction id. */ + ApiFuture> getAll( + final @Nonnull DocumentReference[] documentReferences, + @Nullable FieldMask fieldMask, + @Nullable ByteString transactionId) { + final SettableApiFuture> futureList = SettableApiFuture.create(); + final Map documentSnapshotMap = new HashMap<>(); + getAll( + documentReferences, + fieldMask, + transactionId, + new ApiStreamObserver() { + @Override + public void onNext(DocumentSnapshot documentSnapshot) { + documentSnapshotMap.put(documentSnapshot.getReference(), documentSnapshot); + } + + @Override + public void onError(Throwable throwable) { + futureList.setException(throwable); + } + + @Override + public void onCompleted() { + List documentSnapshotsList = new ArrayList<>(); + for (DocumentReference documentReference : documentReferences) { + documentSnapshotsList.add(documentSnapshotMap.get(documentReference)); + } + futureList.set(documentSnapshotsList); + } + }); return futureList; } diff --git a/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Transaction.java b/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Transaction.java index a3f844fa41f0..13f51c0c7aec 100644 --- a/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Transaction.java +++ b/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Transaction.java @@ -137,8 +137,7 @@ public ApiFuture get(@Nonnull DocumentReference documentRef) { Preconditions.checkState(isEmpty(), READ_BEFORE_WRITE_ERROR_MSG); return ApiFutures.transform( - firestore.getAll( - new DocumentReference[] {documentRef}, /*fieldMask=*/ null, transactionId, null), + firestore.getAll(new DocumentReference[] {documentRef}, /*fieldMask=*/ null, transactionId), new ApiFunction, DocumentSnapshot>() { @Override public DocumentSnapshot apply(List snapshots) { @@ -159,7 +158,7 @@ public ApiFuture> getAll( @Nonnull DocumentReference... documentReferences) { Preconditions.checkState(isEmpty(), READ_BEFORE_WRITE_ERROR_MSG); - return firestore.getAll(documentReferences, /*fieldMask=*/ null, transactionId, null); + return firestore.getAll(documentReferences, /*fieldMask=*/ null, transactionId); } /** @@ -175,7 +174,7 @@ public ApiFuture> getAll( @Nonnull DocumentReference[] documentReferences, @Nullable FieldMask fieldMask) { Preconditions.checkState(isEmpty(), READ_BEFORE_WRITE_ERROR_MSG); - return firestore.getAll(documentReferences, fieldMask, transactionId, null); + return firestore.getAll(documentReferences, fieldMask, transactionId); } /** diff --git a/google-cloud-clients/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITSystemTest.java b/google-cloud-clients/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITSystemTest.java index cdbff02111f4..727c002d4179 100644 --- a/google-cloud-clients/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITSystemTest.java +++ b/google-cloud-clients/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITSystemTest.java @@ -22,6 +22,7 @@ import static java.util.Arrays.asList; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; @@ -1332,22 +1333,22 @@ private static final class ListenerEvent { @Test public void getAllWithObserver() throws Exception { - DocumentReference ref = randomColl.document("doc1"); - ref.set(ALL_SUPPORTED_TYPES_MAP).get(); - - DocumentReference ref1 = randomColl.document("doc2"); + DocumentReference ref1 = randomColl.document("doc1"); ref1.set(ALL_SUPPORTED_TYPES_MAP).get(); - DocumentReference ref2 = randomColl.document("doc3"); + DocumentReference ref2 = randomColl.document("doc2"); ref2.set(ALL_SUPPORTED_TYPES_MAP).get(); - ref2.delete(); - final List documentSnapshots = new ArrayList<>(); - final DocumentReference[] documentReferences = {ref, ref1, ref2}; + DocumentReference ref3 = randomColl.document("doc3"); + + final List documentSnapshots = + Collections.synchronizedList(new ArrayList()); + final DocumentReference[] documentReferences = {ref1, ref2, ref3}; final SettableApiFuture future = SettableApiFuture.create(); firestore.getAll( documentReferences, FieldMask.of("foo"), + null, new ApiStreamObserver() { @Override @@ -1368,15 +1369,15 @@ public void onCompleted() { future.get(); - if (null != documentSnapshots && documentSnapshots.size() > 0) { - for (DocumentSnapshot documentSnapshot : documentSnapshots) { - if (null != documentSnapshot.getData()) { - assertEquals(map("foo", "bar"), documentSnapshot.getData()); - } else { - assertFalse(documentSnapshot.exists()); - } - } - } + assertEquals( + ALL_SUPPORTED_TYPES_OBJECT, documentSnapshots.get(0).toObject(AllSupportedTypes.class)); + assertEquals( + ALL_SUPPORTED_TYPES_OBJECT, documentSnapshots.get(1).toObject(AllSupportedTypes.class)); + assertNotEquals( + ALL_SUPPORTED_TYPES_OBJECT, documentSnapshots.get(2).toObject(AllSupportedTypes.class)); + assertEquals(ref1.getId(), documentSnapshots.get(0).getId()); + assertEquals(ref2.getId(), documentSnapshots.get(1).getId()); + assertEquals(ref3.getId(), documentSnapshots.get(2).getId()); assertEquals(3, documentSnapshots.size()); } } From 74a4aec6933906eebd2872c7f4ed505cabac82e7 Mon Sep 17 00:00:00 2001 From: abhinav Date: Wed, 4 Sep 2019 15:47:50 +0530 Subject: [PATCH 7/7] review changes --- .../java/com/google/cloud/firestore/Firestore.java | 9 +++------ .../com/google/cloud/firestore/FirestoreImpl.java | 11 +++++++++-- .../com/google/cloud/firestore/it/ITSystemTest.java | 1 - 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Firestore.java b/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Firestore.java index 2d2e722bef4c..26ee155ea599 100644 --- a/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Firestore.java +++ b/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Firestore.java @@ -19,7 +19,6 @@ import com.google.api.core.ApiFuture; import com.google.api.gax.rpc.ApiStreamObserver; import com.google.cloud.Service; -import com.google.protobuf.ByteString; import java.util.List; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -121,18 +120,16 @@ ApiFuture> getAll( /** * Retrieves multiple documents from Firestore while optionally applying a field mask to reduce - * the amount of data transmitted. Returned documents will be out of order and missing documents - * will not be returned. + * the amount of data transmitted. Returned documents will be out of order. * * @param documentReferences Array with Document References to fetch. * @param fieldMask If not null, specifies the subset of fields to return. - * @param transactionId Id of {@link Transaction} - * @param responseObserver ApiStreamObserver of DocumentSnapshot + * @param responseObserver The observer to be notified when {@link DocumentSnapshot} details + * arrive. */ void getAll( @Nonnull DocumentReference[] documentReferences, @Nullable FieldMask fieldMask, - @Nullable ByteString transactionId, final ApiStreamObserver responseObserver); /** diff --git a/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/FirestoreImpl.java b/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/FirestoreImpl.java index 855140dbd36f..cf9bfdb483c8 100644 --- a/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/FirestoreImpl.java +++ b/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/FirestoreImpl.java @@ -140,19 +140,26 @@ public Iterable getCollections() { @Override public ApiFuture> getAll( @Nonnull DocumentReference... documentReferences) { - return this.getAll(documentReferences, null, null); + return this.getAll(documentReferences, null, (ByteString) null); } @Nonnull @Override public ApiFuture> getAll( @Nonnull DocumentReference[] documentReferences, @Nullable FieldMask fieldMask) { - return this.getAll(documentReferences, fieldMask, null); + return this.getAll(documentReferences, fieldMask, (ByteString) null); } @Nonnull @Override public void getAll( + final @Nonnull DocumentReference[] documentReferences, + @Nullable FieldMask fieldMask, + @Nonnull final ApiStreamObserver apiStreamObserver) { + this.getAll(documentReferences, fieldMask, null, apiStreamObserver); + } + + void getAll( final @Nonnull DocumentReference[] documentReferences, @Nullable FieldMask fieldMask, @Nullable ByteString transactionId, diff --git a/google-cloud-clients/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITSystemTest.java b/google-cloud-clients/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITSystemTest.java index 727c002d4179..eb9e56888efa 100644 --- a/google-cloud-clients/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITSystemTest.java +++ b/google-cloud-clients/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITSystemTest.java @@ -1348,7 +1348,6 @@ public void getAllWithObserver() throws Exception { firestore.getAll( documentReferences, FieldMask.of("foo"), - null, new ApiStreamObserver() { @Override