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

Add listDocuments() API #3759

Merged
merged 1 commit into from
Oct 4, 2018
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 @@ -19,7 +19,14 @@
import com.google.api.core.ApiFunction;
import com.google.api.core.ApiFuture;
import com.google.api.core.ApiFutures;
import com.google.api.gax.rpc.ApiException;
import com.google.api.gax.rpc.ApiExceptions;
import com.google.cloud.firestore.v1beta1.FirestoreClient.ListDocumentsPagedResponse;
import com.google.common.base.Preconditions;
import com.google.firestore.v1beta1.Document;
import com.google.firestore.v1beta1.DocumentMask;
import com.google.firestore.v1beta1.ListDocumentsRequest;
import java.util.Iterator;
import java.util.Map;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
Expand Down Expand Up @@ -104,6 +111,62 @@ public DocumentReference document(@Nonnull String childPath) {
return new DocumentReference(firestore, documentPath);
}

/**
* Retrieves the list of documents in this collection.
*
* <p>The document references returned may include references to "missing documents", i.e.
* document locations that have no document present but which contain subcollections with
* documents. Attempting to read such a document reference (e.g. via `get()` or `onSnapshot()`)
* will return a `DocumentSnapshot` whose `exists()` method returns false.
*
* @return {Promise<DocumentReference[]>} @return {Promise<DocumentReference[]>} The list of
* documents in this * collection.
*/
@Nonnull
public Iterable<DocumentReference> listDocuments() {
ListDocumentsRequest.Builder request = ListDocumentsRequest.newBuilder();
request.setParent(path.getParent().toString());
request.setCollectionId(this.getId());
request.setMask(DocumentMask.getDefaultInstance());
request.setShowMissing(true);

final ListDocumentsPagedResponse response;

try {
response =
ApiExceptions.callAndTranslateApiException(
firestore.sendRequest(
request.build(), firestore.getClient().listDocumentsPagedCallable()));
} catch (ApiException exception) {
throw FirestoreException.apiException(exception);
}

return new Iterable<DocumentReference>() {
@Override
@Nonnull
public Iterator<DocumentReference> iterator() {
final Iterator<Document> iterator = response.iterateAll().iterator();
return new Iterator<DocumentReference>() {
@Override
public boolean hasNext() {
return iterator.hasNext();
}

@Override
public DocumentReference next() {
ResourcePath path = ResourcePath.create(iterator.next().getName());
return document(path.getId());
}

@Override
public void remove() {
throw new UnsupportedOperationException("remove");
}
};
}
};
}

/**
* Adds a new document to this collection with the specified data, assigning it a document ID
* automatically.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,21 @@
import com.google.api.gax.rpc.UnaryCallable;
import com.google.cloud.ServiceRpc;
import com.google.cloud.firestore.v1beta1.FirestoreClient.ListCollectionIdsPagedResponse;
import com.google.cloud.firestore.v1beta1.FirestoreClient.ListDocumentsPagedResponse;
import com.google.firestore.v1beta1.BatchGetDocumentsRequest;
import com.google.firestore.v1beta1.BatchGetDocumentsResponse;
import com.google.firestore.v1beta1.BeginTransactionRequest;
import com.google.firestore.v1beta1.BeginTransactionResponse;
import com.google.firestore.v1beta1.CommitRequest;
import com.google.firestore.v1beta1.CommitResponse;
import com.google.firestore.v1beta1.ListCollectionIdsRequest;
import com.google.firestore.v1beta1.ListDocumentsRequest;
import com.google.firestore.v1beta1.ListenRequest;
import com.google.firestore.v1beta1.ListenResponse;
import com.google.firestore.v1beta1.RollbackRequest;
import com.google.firestore.v1beta1.RunQueryRequest;
import com.google.firestore.v1beta1.RunQueryResponse;
import com.google.protobuf.Empty;
import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledExecutorService;

/** Contains the RPC stubs used by the manual Cloud Firestore client. */
Expand Down Expand Up @@ -63,6 +64,9 @@ public interface FirestoreRpc extends AutoCloseable, ServiceRpc {
UnaryCallable<ListCollectionIdsRequest, ListCollectionIdsPagedResponse>
listCollectionIdsPagedCallable();

/** Returns a list of documents. */
UnaryCallable<ListDocumentsRequest, ListDocumentsPagedResponse> listDocumentsPagedCallable();

/** Returns a bi-directional watch stream. */
BidiStreamingCallable<ListenRequest, ListenResponse> listenCallable();
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,11 @@
import com.google.cloud.NoCredentials;
import com.google.cloud.ServiceOptions;
import com.google.cloud.firestore.FirestoreOptions;
import com.google.cloud.firestore.v1beta1.FirestoreSettings;
import com.google.cloud.firestore.v1beta1.stub.FirestoreStubSettings;
import com.google.cloud.firestore.v1beta1.FirestoreClient.ListCollectionIdsPagedResponse;
import com.google.cloud.firestore.v1beta1.FirestoreClient.ListDocumentsPagedResponse;
import com.google.cloud.firestore.v1beta1.FirestoreSettings;
import com.google.cloud.firestore.v1beta1.stub.FirestoreStub;
import com.google.cloud.firestore.v1beta1.stub.FirestoreStubSettings;
import com.google.cloud.firestore.v1beta1.stub.GrpcFirestoreStub;
import com.google.cloud.grpc.GrpcTransportOptions;
import com.google.cloud.grpc.GrpcTransportOptions.ExecutorFactory;
Expand All @@ -48,6 +49,7 @@
import com.google.firestore.v1beta1.CommitResponse;
import com.google.firestore.v1beta1.DatabaseRootName;
import com.google.firestore.v1beta1.ListCollectionIdsRequest;
import com.google.firestore.v1beta1.ListDocumentsRequest;
import com.google.firestore.v1beta1.ListenRequest;
import com.google.firestore.v1beta1.ListenResponse;
import com.google.firestore.v1beta1.RollbackRequest;
Expand All @@ -59,7 +61,6 @@
import io.grpc.ManagedChannelBuilder;
import java.io.IOException;
import java.util.Collections;
import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledExecutorService;

/**
Expand Down Expand Up @@ -129,7 +130,8 @@ public Void apply(UnaryCallSettings.Builder<?, ?> builder) {
}
};
FirestoreStubSettings.Builder firestoreBuilder =
FirestoreStubSettings.newBuilder(clientContext).applyToAllUnaryMethods(retrySettingsSetter);
FirestoreStubSettings.newBuilder(clientContext)
.applyToAllUnaryMethods(retrySettingsSetter);
firestoreStub = GrpcFirestoreStub.create(firestoreBuilder.build());
} catch (Exception e) {
throw new IOException(e);
Expand Down Expand Up @@ -187,6 +189,12 @@ public UnaryCallable<RollbackRequest, Empty> rollbackCallable() {
return firestoreStub.listCollectionIdsPagedCallable();
}

@Override
public UnaryCallable<ListDocumentsRequest, ListDocumentsPagedResponse>
listDocumentsPagedCallable() {
return firestoreStub.listDocumentsPagedCallable();
}

@Override
public BidiStreamingCallable<ListenRequest, ListenResponse> listenCallable() {
return firestoreStub.listenCallable();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -577,6 +577,39 @@ public void getCollections() throws Exception {
assertEquals(collections.length, count);
}

@Test
public void listDocuments() throws Exception {
// We test with 21 documents since 20 documents are by default returned in a single paged
// response.
String[] documents =
new String[] {
"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16",
"17", "18", "19", "20", "21"
};
Arrays.sort(documents); // Sort in alphabetical (non-numeric) order.

WriteBatch batch = firestore.batch();
for (String document : documents) {
batch.create(randomColl.document(document), SINGLE_FIELD_OBJECT);
}
batch.commit().get();

Iterable<DocumentReference> collectionRefs = randomColl.listDocuments();

int count = 0;
for (DocumentReference documentRef : collectionRefs) {
assertEquals(documents[count++], documentRef.getId());
}
assertEquals(documents.length, count);
}

@Test
public void listDocumentsListsMissingDocument() throws Exception {
randomColl.document("missing/foo/bar").set(SINGLE_FIELD_MAP).get();
Iterable<DocumentReference> collectionRefs = randomColl.listDocuments();
assertEquals(randomColl.document("missing"), collectionRefs.iterator().next());
}

@Test
public void addAndRemoveFields() throws ExecutionException, InterruptedException {
Map<String, Object> expected = new HashMap<>();
Expand Down