Skip to content

Commit

Permalink
feat(firestore): add getCountFromServer(...) method (#792)
Browse files Browse the repository at this point in the history
* feat(firestore): add getCountFromServer method

Add method definition.

* feat(firestore): add getCountFromServer method

Implement method on web.

* feat(firestore): add getCountFromServer method

Implement method on ios.

* feat(firestore): add getCountFromServer method

Implement method on android.

* feat(firestore): add getCountFromServer method

Run format script.

* feat(firestore): add getCountFromServer method

Generate changeset file.

* add missing documentation

* reorder method

---------

Co-authored-by: Robin Genz <[email protected]>
  • Loading branch information
ebarooni and robingenz authored Jan 9, 2025
1 parent 9bdd458 commit 5344006
Show file tree
Hide file tree
Showing 14 changed files with 256 additions and 5 deletions.
5 changes: 5 additions & 0 deletions .changeset/friendly-shoes-tell.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@capacitor-firebase/firestore': minor
---

feat: add `getCountFromServer` method
34 changes: 34 additions & 0 deletions packages/firestore/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,7 @@ const removeAllListeners = async () => {
* [`writeBatch(...)`](#writebatch)
* [`getCollection(...)`](#getcollection)
* [`getCollectionGroup(...)`](#getcollectiongroup)
* [`getCountFromServer(...)`](#getcountfromserver)
* [`clearPersistence()`](#clearpersistence)
* [`enableNetwork()`](#enablenetwork)
* [`disableNetwork()`](#disablenetwork)
Expand Down Expand Up @@ -433,6 +434,25 @@ Reads the collection group referenced by the specified reference.
--------------------


### getCountFromServer(...)

```typescript
getCountFromServer(options: GetCountFromServerOptions) => Promise<GetCountFromServerResult>
```

Fetches the number of documents in a collection.

| Param | Type |
| ------------- | ------------------------------------------------------------------------------- |
| **`options`** | <code><a href="#getcountfromserveroptions">GetCountFromServerOptions</a></code> |

**Returns:** <code>Promise&lt;<a href="#getcountfromserverresult">GetCountFromServerResult</a>&gt;</code>

**Since:** 6.4.0

--------------------


### clearPersistence()

```typescript
Expand Down Expand Up @@ -765,6 +785,20 @@ Remove all listeners for this plugin.
| **`queryConstraints`** | <code>QueryNonFilterConstraint[]</code> | Narrow or order the set of documents to retrieve, but do not explicitly filter for document fields. | 5.2.0 |


#### GetCountFromServerResult

| Prop | Type | Description | Since |
| ----------- | ------------------- | ------------------------------------------ | ----- |
| **`count`** | <code>number</code> | The number of documents in the collection. | 6.4.0 |


#### GetCountFromServerOptions

| Prop | Type | Description | Since |
| --------------- | ------------------- | ----------------------------------------------------------------------------------- | ----- |
| **`reference`** | <code>string</code> | The reference as a string, with path components separated by a forward slash (`/`). | 6.4.0 |


#### UseEmulatorOptions

| Prop | Type | Description | Default | Since |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
import androidx.annotation.NonNull;
import com.getcapacitor.PluginCall;
import com.google.android.gms.tasks.Task;
import com.google.firebase.firestore.AggregateQuery;
import com.google.firebase.firestore.AggregateQuerySnapshot;
import com.google.firebase.firestore.AggregateSource;
import com.google.firebase.firestore.CollectionReference;
import com.google.firebase.firestore.DocumentReference;
import com.google.firebase.firestore.Filter;
Expand All @@ -19,6 +22,7 @@
import io.capawesome.capacitorjs.plugins.firebase.firestore.classes.options.DeleteDocumentOptions;
import io.capawesome.capacitorjs.plugins.firebase.firestore.classes.options.GetCollectionGroupOptions;
import io.capawesome.capacitorjs.plugins.firebase.firestore.classes.options.GetCollectionOptions;
import io.capawesome.capacitorjs.plugins.firebase.firestore.classes.options.GetCountFromServerOptions;
import io.capawesome.capacitorjs.plugins.firebase.firestore.classes.options.GetDocumentOptions;
import io.capawesome.capacitorjs.plugins.firebase.firestore.classes.options.RemoveSnapshotListenerOptions;
import io.capawesome.capacitorjs.plugins.firebase.firestore.classes.options.SetDocumentOptions;
Expand All @@ -27,6 +31,7 @@
import io.capawesome.capacitorjs.plugins.firebase.firestore.classes.options.WriteBatchOptions;
import io.capawesome.capacitorjs.plugins.firebase.firestore.classes.results.AddDocumentResult;
import io.capawesome.capacitorjs.plugins.firebase.firestore.classes.results.GetCollectionResult;
import io.capawesome.capacitorjs.plugins.firebase.firestore.classes.results.GetCountFromServerResult;
import io.capawesome.capacitorjs.plugins.firebase.firestore.classes.results.GetDocumentResult;
import io.capawesome.capacitorjs.plugins.firebase.firestore.interfaces.EmptyResultCallback;
import io.capawesome.capacitorjs.plugins.firebase.firestore.interfaces.NonEmptyResultCallback;
Expand Down Expand Up @@ -238,6 +243,26 @@ public void useEmulator(@NonNull String host, int port) {
getFirebaseFirestoreInstance().useEmulator(host, port);
}

public void getCountFromServer(@NonNull GetCountFromServerOptions options, @NonNull NonEmptyResultCallback callback) {
String reference = options.getReference();
Query query = getFirebaseFirestoreInstance().collection(reference);
AggregateQuery countQuery = query.count();

countQuery
.get(AggregateSource.SERVER)
.addOnCompleteListener(
task -> {
if (task.isSuccessful()) {
AggregateQuerySnapshot snapshot = task.getResult();
GetCountFromServerResult result = new GetCountFromServerResult(snapshot.getCount());
callback.success(result);
} else {
callback.error(task.getException());
}
}
);
}

public void addDocumentSnapshotListener(@NonNull AddDocumentSnapshotListenerOptions options, @NonNull NonEmptyResultCallback callback) {
String reference = options.getReference();
String callbackId = options.getCallbackId();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import io.capawesome.capacitorjs.plugins.firebase.firestore.classes.options.DeleteDocumentOptions;
import io.capawesome.capacitorjs.plugins.firebase.firestore.classes.options.GetCollectionGroupOptions;
import io.capawesome.capacitorjs.plugins.firebase.firestore.classes.options.GetCollectionOptions;
import io.capawesome.capacitorjs.plugins.firebase.firestore.classes.options.GetCountFromServerOptions;
import io.capawesome.capacitorjs.plugins.firebase.firestore.classes.options.GetDocumentOptions;
import io.capawesome.capacitorjs.plugins.firebase.firestore.classes.options.RemoveSnapshotListenerOptions;
import io.capawesome.capacitorjs.plugins.firebase.firestore.classes.options.SetDocumentOptions;
Expand Down Expand Up @@ -394,6 +395,36 @@ public void useEmulator(PluginCall call) {
}
}

@PluginMethod
public void getCountFromServer(PluginCall call) {
try {
String reference = call.getString("reference");
if (reference == null) {
call.reject(ERROR_REFERENCE_MISSING);
return;
}

GetCountFromServerOptions options = new GetCountFromServerOptions(reference);
NonEmptyResultCallback callback = new NonEmptyResultCallback() {
@Override
public void success(Result result) {
call.resolve(result.toJSObject());
}

@Override
public void error(Exception exception) {
Logger.error(TAG, exception.getMessage(), exception);
call.reject(exception.getMessage());
}
};

implementation.getCountFromServer(options, callback);
} catch (Exception exception) {
Logger.error(TAG, exception.getMessage(), exception);
call.reject(exception.getMessage());
}
}

@PluginMethod(returnType = PluginMethod.RETURN_CALLBACK)
public void addDocumentSnapshotListener(PluginCall call) {
try {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package io.capawesome.capacitorjs.plugins.firebase.firestore.classes.options;

import androidx.annotation.NonNull;

public class GetCountFromServerOptions {

@NonNull
private final String reference;

public GetCountFromServerOptions(@NonNull String reference) {
this.reference = reference;
}

@NonNull
public String getReference() {
return reference;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package io.capawesome.capacitorjs.plugins.firebase.firestore.classes.results;

import com.getcapacitor.JSObject;
import io.capawesome.capacitorjs.plugins.firebase.firestore.interfaces.Result;

public class GetCountFromServerResult implements Result {

private final long count;

public GetCountFromServerResult(long count) {
this.count = count;
}

@Override
public JSObject toJSObject() {
JSObject result = new JSObject();
result.put("count", count);
return result;
}
}
8 changes: 8 additions & 0 deletions packages/firestore/ios/Plugin.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@
7C0070402ABC2DF8000C0F28 /* FirebaseFirestoreHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C00703F2ABC2DF8000C0F28 /* FirebaseFirestoreHelper.swift */; };
7C0070422ABC97E5000C0F28 /* QueryNonFilterConstraint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C0070412ABC97E5000C0F28 /* QueryNonFilterConstraint.swift */; };
7C0070442ABC9AE9000C0F28 /* QueryFilterConstraint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C0070432ABC9AE9000C0F28 /* QueryFilterConstraint.swift */; };
7C2AE7C92D2DBF7000F40418 /* GetCountFromServerOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C2AE7C82D2DBF6D00F40418 /* GetCountFromServerOptions.swift */; };
7C2AE7CB2D2DC2B400F40418 /* GetCountFromServerResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C2AE7CA2D2DC2B100F40418 /* GetCountFromServerResult.swift */; };
7C90A58E2C21519B00A71389 /* AddCollectionGroupSnapshotListenerOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C90A58D2C21519B00A71389 /* AddCollectionGroupSnapshotListenerOptions.swift */; };
7CF0EFE32C207844004D910D /* WriteBatchOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CF0EFE22C207844004D910D /* WriteBatchOptions.swift */; };
7CF0EFE52C20784E004D910D /* WriteBatchOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CF0EFE42C20784E004D910D /* WriteBatchOperation.swift */; };
Expand Down Expand Up @@ -92,6 +94,8 @@
7C00703F2ABC2DF8000C0F28 /* FirebaseFirestoreHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirebaseFirestoreHelper.swift; sourceTree = "<group>"; };
7C0070412ABC97E5000C0F28 /* QueryNonFilterConstraint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueryNonFilterConstraint.swift; sourceTree = "<group>"; };
7C0070432ABC9AE9000C0F28 /* QueryFilterConstraint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueryFilterConstraint.swift; sourceTree = "<group>"; };
7C2AE7C82D2DBF6D00F40418 /* GetCountFromServerOptions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GetCountFromServerOptions.swift; sourceTree = "<group>"; };
7C2AE7CA2D2DC2B100F40418 /* GetCountFromServerResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GetCountFromServerResult.swift; sourceTree = "<group>"; };
7C90A58D2C21519B00A71389 /* AddCollectionGroupSnapshotListenerOptions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddCollectionGroupSnapshotListenerOptions.swift; sourceTree = "<group>"; };
7CF0EFE22C207844004D910D /* WriteBatchOptions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WriteBatchOptions.swift; sourceTree = "<group>"; };
7CF0EFE42C20784E004D910D /* WriteBatchOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WriteBatchOperation.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -190,6 +194,7 @@
7C0070302ABC1FB6000C0F28 /* Options */ = {
isa = PBXGroup;
children = (
7C2AE7C82D2DBF6D00F40418 /* GetCountFromServerOptions.swift */,
7C00700D2ABC1ED4000C0F28 /* AddCollectionSnapshotListenerOptions.swift */,
7C00700F2ABC1EE0000C0F28 /* AddDocumentOptions.swift */,
7C0070132ABC1F0F000C0F28 /* AddDocumentSnapshotListenerOptions.swift */,
Expand Down Expand Up @@ -223,6 +228,7 @@
7C0070382ABC2007000C0F28 /* Results */ = {
isa = PBXGroup;
children = (
7C2AE7CA2D2DC2B100F40418 /* GetCountFromServerResult.swift */,
7C0070112ABC1F03000C0F28 /* AddDocumentResult.swift */,
7C0070192ABC1F29000C0F28 /* GetCollectionGroupResult.swift */,
7C00701D2ABC1F38000C0F28 /* GetCollectionResult.swift */,
Expand Down Expand Up @@ -467,10 +473,12 @@
50E1A94820377CB70090CE1A /* FirebaseFirestorePlugin.swift in Sources */,
7C00702B2ABC1F7B000C0F28 /* QueryLimitConstraint.swift in Sources */,
7C0070202ABC1F42000C0F28 /* GetDocumentOptions.swift in Sources */,
7C2AE7CB2D2DC2B400F40418 /* GetCountFromServerResult.swift in Sources */,
7CF0EFE52C20784E004D910D /* WriteBatchOperation.swift in Sources */,
7C00701E2ABC1F38000C0F28 /* GetCollectionResult.swift in Sources */,
7C00702F2ABC1FAF000C0F28 /* QueryStartAtConstraint.swift in Sources */,
7C0070182ABC1F20000C0F28 /* GetCollectionGroupOptions.swift in Sources */,
7C2AE7C92D2DBF7000F40418 /* GetCountFromServerOptions.swift in Sources */,
7CF0EFE32C207844004D910D /* WriteBatchOptions.swift in Sources */,
7C0070102ABC1EE0000C0F28 /* AddDocumentOptions.swift in Sources */,
7C0070162ABC1F18000C0F28 /* DeleteDocumentOptions.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import Foundation

@objc public class GetCountFromServerOptions: NSObject {
private let reference: String

init(reference: String) {
self.reference = reference
}

func getReference() -> String {
return reference
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import Capacitor

@objc public class GetCountFromServerResult: NSObject, Result {
let count: Int

init(_ count: Int) {
self.count = count
}

public func toJSObject() -> AnyObject {
var result = JSObject()
result["count"] = count
return result as AnyObject
}
}
24 changes: 20 additions & 4 deletions packages/firestore/ios/Plugin/FirebaseFirestore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,18 @@ import FirebaseFirestore

private actor ListenerRegistrationMap {
private var listenerRegistrationMap: [String: ListenerRegistration] = [:]

func addRegistration(_ listenerRegistration: ListenerRegistration, listenerId: String) async {
listenerRegistrationMap[listenerId] = listenerRegistration
}

func removeRegistration(listenerId: String) async {
if let listenerRegistration = listenerRegistrationMap[listenerId] {
listenerRegistration.remove()
}
listenerRegistrationMap.removeValue(forKey: listenerId)
}

func removeAll() async {
listenerRegistrationMap.forEach { _, value in
value.remove()
Expand All @@ -27,7 +27,7 @@ private actor ListenerRegistrationMap {
@objc public class FirebaseFirestore: NSObject {
private let plugin: FirebaseFirestorePlugin
private var listenerRegistrationMap = ListenerRegistrationMap()

init(plugin: FirebaseFirestorePlugin) {
self.plugin = plugin
super.init()
Expand Down Expand Up @@ -217,6 +217,22 @@ private actor ListenerRegistrationMap {
Firestore.firestore().settings = settings
}

@objc public func getCountFromServer(_ options: GetCountFromServerOptions, completion: @escaping (Result?, Error?) -> Void) {
let reference = options.getReference()
let collectionReference = Firestore.firestore().collection(reference)
let countQuery = collectionReference.count

Task {
do {
let snapshot = try await countQuery.getAggregation(source: .server)
let result = GetCountFromServerResult(snapshot.count.intValue)
completion(result, nil)
} catch {
completion(nil, error)
}
}
}

@objc public func addDocumentSnapshotListener(_ options: AddDocumentSnapshotListenerOptions, completion: @escaping (Result?, Error?) -> Void) {
let reference = options.getReference()
let includeMetadataChanges = options.getIncludeMetadataChanges()
Expand Down
1 change: 1 addition & 0 deletions packages/firestore/ios/Plugin/FirebaseFirestorePlugin.m
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
CAP_PLUGIN_METHOD(writeBatch, CAPPluginReturnPromise);
CAP_PLUGIN_METHOD(getCollection, CAPPluginReturnPromise);
CAP_PLUGIN_METHOD(getCollectionGroup, CAPPluginReturnPromise);
CAP_PLUGIN_METHOD(getCountFromServer, CAPPluginReturnPromise);
CAP_PLUGIN_METHOD(enableNetwork, CAPPluginReturnPromise);
CAP_PLUGIN_METHOD(disableNetwork, CAPPluginReturnPromise);
CAP_PLUGIN_METHOD(useEmulator, CAPPluginReturnPromise);
Expand Down
22 changes: 21 additions & 1 deletion packages/firestore/ios/Plugin/FirebaseFirestorePlugin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,26 @@ public class FirebaseFirestorePlugin: CAPPlugin {
call.resolve()
}

@objc func getCountFromServer(_ call: CAPPluginCall) {
guard let reference = call.getString("reference") else {
call.reject(errorReferenceMissing)
return
}

let options = GetCountFromServerOptions(reference: reference)

implementation?.getCountFromServer(options, completion: { result, error in
if let error = error {
CAPLog.print("[", self.tag, "] ", error)
call.reject(error.localizedDescription)
return
}
if let result = result?.toJSObject() as? JSObject {
call.resolve(result)
}
})
}

@objc func addDocumentSnapshotListener(_ call: CAPPluginCall) {
call.keepAlive = true

Expand Down Expand Up @@ -359,7 +379,7 @@ public class FirebaseFirestorePlugin: CAPPlugin {
}
self.pluginCallMap.removeAll()
self.eventListeners?.removeAllObjects()

implementation?.removeAllListeners {
call.resolve()
}
Expand Down
Loading

0 comments on commit 5344006

Please sign in to comment.