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

Issue 624 - addCollectionGroupSnapshotListener #628

Closed
wants to merge 8 commits into from
Closed
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
5 changes: 5 additions & 0 deletions .changeset/cold-zebras-pump.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@capacitor-firebase/firestore': minor
---

feat: add `addCollectionGroupSnapshotListener` method
78 changes: 78 additions & 0 deletions packages/firestore/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,44 @@ const addCollectionSnapshotListener = async () => {
return callbackId;
};

const addCollectionGroupSnapshotListener = async () => {
const callbackId = await FirebaseFirestore.addCollectionGroupSnapshotListener(
{
reference: 'users',
compositeFilter: {
type: 'and',
queryConstraints: [
{
type: 'where',
fieldPath: 'born',
opStr: '==',
value: 1912,
},
],
},
queryConstraints: [
{
type: 'orderBy',
fieldPath: 'born',
directionStr: 'desc',
},
{
type: 'limit',
limit: 10,
},
],
},
(event, error) => {
if (error) {
console.error(error);
} else {
console.log(event);
}
},
);
return callbackId;
};

const removeSnapshotListener = async (callbackId: string) => {
await FirebaseFirestore.removeSnapshotListener({
callbackId,
Expand Down Expand Up @@ -203,6 +241,7 @@ const removeAllListeners = async () => {
* [`disableNetwork()`](#disablenetwork)
* [`addDocumentSnapshotListener(...)`](#adddocumentsnapshotlistener)
* [`addCollectionSnapshotListener(...)`](#addcollectionsnapshotlistener)
* [`addCollectionGroupSnapshotListener(...)`](#addcollectiongroupsnapshotlistener)
* [`removeSnapshotListener(...)`](#removesnapshotlistener)
* [`removeAllListeners()`](#removealllisteners)
* [Interfaces](#interfaces)
Expand Down Expand Up @@ -420,6 +459,26 @@ Adds a listener for collection snapshot events.
--------------------


### addCollectionGroupSnapshotListener(...)

```typescript
addCollectionGroupSnapshotListener<T extends DocumentData = DocumentData>(options: AddCollectionGroupSnapshotListenerOptions, callback: AddCollectionGroupSnapshotListenerCallback<T>) => Promise<CallbackId>
```

Adds a listener for collection group snapshot events.

| Param | Type |
| -------------- | -------------------------------------------------------------------------------------------------------------------------- |
| **`options`** | <code><a href="#addcollectiongroupsnapshotlisteneroptions">AddCollectionGroupSnapshotListenerOptions</a></code> |
| **`callback`** | <code><a href="#addcollectiongroupsnapshotlistenercallback">AddCollectionGroupSnapshotListenerCallback</a>&lt;T&gt;</code> |

**Returns:** <code>Promise&lt;string&gt;</code>

**Since:** 6.1.0

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


### removeSnapshotListener(...)

```typescript
Expand Down Expand Up @@ -625,6 +684,15 @@ 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 |


#### AddCollectionGroupSnapshotListenerOptions

| Prop | Type | Description | Since |
| ---------------------- | ----------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | ----- |
| **`reference`** | <code>string</code> | The reference as a string, with path components separated by a forward slash (`/`). | 6.1.0 |
| **`compositeFilter`** | <code><a href="#querycompositefilterconstraint">QueryCompositeFilterConstraint</a></code> | The filter to apply. | 6.1.0 |
| **`queryConstraints`** | <code>QueryNonFilterConstraint[]</code> | Narrow or order the set of documents to retrieve, but do not explicitly filter for document fields. | 6.1.0 |


#### RemoveSnapshotListenerOptions

| Prop | Type | Since |
Expand Down Expand Up @@ -679,6 +747,16 @@ Remove all listeners for this plugin.

<code><a href="#getcollectionresult">GetCollectionResult</a>&lt;T&gt;</code>


#### AddCollectionGroupSnapshotListenerCallback

<code>(event: <a href="#addcollectiongroupsnapshotlistenercallbackevent">AddCollectionGroupSnapshotListenerCallbackEvent</a>&lt;T&gt; | null, error: any): void</code>


#### AddCollectionGroupSnapshotListenerCallbackEvent

<code><a href="#getcollectiongroupresult">GetCollectionGroupResult</a>&lt;T&gt;</code>

</docgen-api>

## Changelog
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import com.google.firebase.firestore.SetOptions;
import io.capawesome.capacitorjs.plugins.firebase.firestore.classes.constraints.QueryCompositeFilterConstraint;
import io.capawesome.capacitorjs.plugins.firebase.firestore.classes.options.AddCollectionSnapshotListenerOptions;
import io.capawesome.capacitorjs.plugins.firebase.firestore.classes.options.AddCollectionGroupSnapshotListenerOptions;
import io.capawesome.capacitorjs.plugins.firebase.firestore.classes.options.AddDocumentOptions;
import io.capawesome.capacitorjs.plugins.firebase.firestore.classes.options.AddDocumentSnapshotListenerOptions;
import io.capawesome.capacitorjs.plugins.firebase.firestore.classes.options.DeleteDocumentOptions;
Expand All @@ -22,6 +23,7 @@
import io.capawesome.capacitorjs.plugins.firebase.firestore.classes.options.UpdateDocumentOptions;
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.GetCollectionGroupResult;
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 @@ -256,6 +258,39 @@ public void addCollectionSnapshotListener(
this.listenerRegistrationMap.put(callbackId, listenerRegistration);
}

public void addCollectionGroupSnapshotListener(
@NonNull AddCollectionGroupSnapshotListenerOptions options,
@NonNull NonEmptyResultCallback callback
) throws Exception {
String reference = options.getReference();
QueryCompositeFilterConstraint compositeFilter = options.getCompositeFilter();
QueryNonFilterConstraint[] queryConstraints = options.getQueryConstraints();
String callbackId = options.getCallbackId();

Query query = getFirebaseFirestoreInstance().collectionGroup(reference);
if (compositeFilter != null) {
Filter filter = compositeFilter.toFilter();
query = query.where(filter);
}
if (queryConstraints.length > 0) {
for (QueryNonFilterConstraint queryConstraint : queryConstraints) {
query = queryConstraint.toQuery(query, getFirebaseFirestoreInstance());
}
}

ListenerRegistration listenerRegistration = query.addSnapshotListener(
(querySnapshot, exception) -> {
if (exception != null) {
callback.error(exception);
} else {
GetCollectionGroupResult result = new GetCollectionGroupResult(querySnapshot);
callback.success(result);
}
}
);
this.listenerRegistrationMap.put(callbackId, listenerRegistration);
}

public void removeSnapshotListener(@NonNull RemoveSnapshotListenerOptions options) {
String callbackId = options.getCallbackId();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import com.getcapacitor.PluginMethod;
import com.getcapacitor.annotation.CapacitorPlugin;
import io.capawesome.capacitorjs.plugins.firebase.firestore.classes.options.AddCollectionSnapshotListenerOptions;
import io.capawesome.capacitorjs.plugins.firebase.firestore.classes.options.AddCollectionGroupSnapshotListenerOptions;
import io.capawesome.capacitorjs.plugins.firebase.firestore.classes.options.AddDocumentOptions;
import io.capawesome.capacitorjs.plugins.firebase.firestore.classes.options.AddDocumentSnapshotListenerOptions;
import io.capawesome.capacitorjs.plugins.firebase.firestore.classes.options.DeleteDocumentOptions;
Expand Down Expand Up @@ -419,6 +420,48 @@ public void error(Exception exception) {
}
}

@PluginMethod(returnType = PluginMethod.RETURN_CALLBACK)
public void addCollectionGroupSnapshotListener(PluginCall call) {
try {
call.setKeepAlive(true);

String reference = call.getString("reference");
if (reference == null) {
call.reject(ERROR_REFERENCE_MISSING);
return;
}
JSObject compositeFilter = call.getObject("compositeFilter");
JSArray queryConstraints = call.getArray("queryConstraints");
String callbackId = call.getCallbackId();

this.pluginCallMap.put(callbackId, call);

AddCollectionGroupSnapshotListenerOptions options = new AddCollectionGroupSnapshotListenerOptions(
reference,
compositeFilter,
queryConstraints,
callbackId
);
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.addCollectionGroupSnapshotListener(options, callback);
} catch (Exception exception) {
Logger.error(TAG, exception.getMessage(), exception);
call.reject(exception.getMessage());
}
}

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

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.getcapacitor.JSArray;
import com.getcapacitor.JSObject;
import com.getcapacitor.PluginCall;
import io.capawesome.capacitorjs.plugins.firebase.firestore.FirebaseFirestoreHelper;
import io.capawesome.capacitorjs.plugins.firebase.firestore.classes.constraints.QueryCompositeFilterConstraint;
import io.capawesome.capacitorjs.plugins.firebase.firestore.interfaces.QueryNonFilterConstraint;
import org.json.JSONException;

public class AddCollectionGroupSnapshotListenerOptions {

@NonNull
private String reference;

@Nullable
private QueryCompositeFilterConstraint compositeFilter;

@NonNull
private QueryNonFilterConstraint[] queryConstraints;

private String callbackId;

public AddCollectionGroupSnapshotListenerOptions(
String reference,
@Nullable JSObject compositeFilter,
@Nullable JSArray queryConstraints,
String callbackId
) throws JSONException {
this.reference = reference;
this.compositeFilter = FirebaseFirestoreHelper.createQueryCompositeFilterConstraintFromJSObject(compositeFilter);
this.queryConstraints = FirebaseFirestoreHelper.createQueryNonFilterConstraintArrayFromJSArray(queryConstraints);
this.callbackId = callbackId;
}

public String getReference() {
return reference;
}

@Nullable
public QueryCompositeFilterConstraint getCompositeFilter() {
return compositeFilter;
}

@NonNull
public QueryNonFilterConstraint[] getQueryConstraints() {
return queryConstraints;
}

public String getCallbackId() {
return callbackId;
}
}
4 changes: 4 additions & 0 deletions packages/firestore/ios/Plugin.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
03FC29A292ACC40490383A1F /* Pods_Plugin.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B2A61DA5A1F2DD4F959604D /* Pods_Plugin.framework */; };
20C0B05DCFC8E3958A738AF2 /* Pods_PluginTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F6753A823D3815DB436415E3 /* Pods_PluginTests.framework */; };
2F98D68224C9AAE500613A4C /* FirebaseFirestore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F98D68124C9AAE400613A4C /* FirebaseFirestore.swift */; };
379BF3AF2BFF26CE00F79C6D /* AddCollectionGroupSnapshotListenerOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 379BF3AE2BFF26CE00F79C6D /* AddCollectionGroupSnapshotListenerOptions.swift */; };
50ADFF92201F53D600D50D53 /* Plugin.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50ADFF88201F53D600D50D53 /* Plugin.framework */; };
50ADFF97201F53D600D50D53 /* FirebaseFirestoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50ADFF96201F53D600D50D53 /* FirebaseFirestoreTests.swift */; };
50ADFF99201F53D600D50D53 /* FirebaseFirestorePlugin.h in Headers */ = {isa = PBXBuildFile; fileRef = 50ADFF8B201F53D600D50D53 /* FirebaseFirestorePlugin.h */; settings = {ATTRIBUTES = (Public, ); }; };
Expand Down Expand Up @@ -54,6 +55,7 @@

/* Begin PBXFileReference section */
2F98D68124C9AAE400613A4C /* FirebaseFirestore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FirebaseFirestore.swift; sourceTree = "<group>"; };
379BF3AE2BFF26CE00F79C6D /* AddCollectionGroupSnapshotListenerOptions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddCollectionGroupSnapshotListenerOptions.swift; sourceTree = "<group>"; };
3B2A61DA5A1F2DD4F959604D /* Pods_Plugin.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Plugin.framework; sourceTree = BUILT_PRODUCTS_DIR; };
50ADFF88201F53D600D50D53 /* Plugin.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Plugin.framework; sourceTree = BUILT_PRODUCTS_DIR; };
50ADFF8B201F53D600D50D53 /* FirebaseFirestorePlugin.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FirebaseFirestorePlugin.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -184,6 +186,7 @@
7C0070302ABC1FB6000C0F28 /* Options */ = {
isa = PBXGroup;
children = (
379BF3AE2BFF26CE00F79C6D /* AddCollectionGroupSnapshotListenerOptions.swift */,
7C00700D2ABC1ED4000C0F28 /* AddCollectionSnapshotListenerOptions.swift */,
7C00700F2ABC1EE0000C0F28 /* AddDocumentOptions.swift */,
7C0070132ABC1F0F000C0F28 /* AddDocumentSnapshotListenerOptions.swift */,
Expand Down Expand Up @@ -470,6 +473,7 @@
2F98D68224C9AAE500613A4C /* FirebaseFirestore.swift in Sources */,
7C0070222ABC1F4A000C0F28 /* GetDocumentResult.swift in Sources */,
7C0070262ABC1F62000C0F28 /* QueryEndAtConstraint.swift in Sources */,
379BF3AF2BFF26CE00F79C6D /* AddCollectionGroupSnapshotListenerOptions.swift in Sources */,
7C00701C2ABC1F31000C0F28 /* GetCollectionOptions.swift in Sources */,
50ADFFA82020EE4F00D50D53 /* FirebaseFirestorePlugin.m in Sources */,
7C0070422ABC97E5000C0F28 /* QueryNonFilterConstraint.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import Foundation
import Capacitor

@objc public class AddCollectionGroupSnapshotListenerOptions: NSObject {
private var reference: String
private var compositeFilter: QueryCompositeFilterConstraint?
private var queryConstraints: [QueryNonFilterConstraint]
private var callbackId: String

init(reference: String, compositeFilter: JSObject?, queryConstraints: [JSObject]?, callbackId: String) {
self.reference = reference
self.compositeFilter = FirebaseFirestoreHelper.createQueryCompositeFilterConstraintFromJSObject(compositeFilter)
self.queryConstraints = FirebaseFirestoreHelper.createQueryNonFilterConstraintArrayFromJSArray(queryConstraints)
self.callbackId = callbackId
}

func getReference() -> String {
return reference
}

func getCompositeFilter() -> QueryCompositeFilterConstraint? {
return compositeFilter
}

func getQueryConstraints() -> [QueryNonFilterConstraint] {
return queryConstraints
}

func getCallbackId() -> String {
return callbackId
}
}
36 changes: 36 additions & 0 deletions packages/firestore/ios/Plugin/FirebaseFirestore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,42 @@ import FirebaseFirestore
}
}

@obj public func addCollectionGroupSnapshotListener(_ options: AddCollectionGroupSnapshotListenerOptions, completion: @escaping (Result?, Error?) -> Void) {
let reference = options.getReference()
let compositeFilter = options.getCompositeFilter()
let queryConstraints = options.getQueryConstraints()
let callbackId = options.getCallbackId()

Task {
do {
let collectionReference = Firestore.firestore().collectionGroup(reference)
var query = collectionReference as Query
if let compositeFilter = compositeFilter {
if let filter = compositeFilter.toFilter() {
query = query.whereFilter(filter)
}
}
if !queryConstraints.isEmpty {
for queryConstraint in queryConstraints {
query = try await queryConstraint.toQuery(query: query)
}
}

let listenerRegistration = query.addSnapshotListener { querySnapshot, error in
if let error = error {
completion(nil, error)
} else {
let result = GetCollectionGroupResult(querySnapshot!)
completion(result, nil)
}
}
self.listenerRegistrationMap[callbackId] = listenerRegistration
} catch {
completion(nil, error)
}
}
}

@objc public func removeSnapshotListener(_ options: RemoveSnapshotListenerOptions) {
let callbackId = options.getCallbackId()

Expand Down
Loading
Loading