Skip to content

Commit

Permalink
feat(firestore): support batched writes (#643)
Browse files Browse the repository at this point in the history
* feat(firestore): support batched writes

* style: format

* docs

* fix

* wip
  • Loading branch information
robingenz committed Jun 18, 2024
1 parent 9cca701 commit 7c33d62
Show file tree
Hide file tree
Showing 16 changed files with 334 additions and 40 deletions.
5 changes: 5 additions & 0 deletions .changeset/empty-owls-relax.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@capacitor-firebase/firestore': minor
---

feat: support batched writes
20 changes: 10 additions & 10 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 5 additions & 16 deletions packages/crashlytics/ios/Plugin/FirebaseCrashlytics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,27 +18,16 @@ import FirebaseCrashlytics
switch type {
case "string":
Crashlytics.crashlytics().setCustomValue(call.getString("value") as Any, forKey: key)
break

case "int":
case "int":
Crashlytics.crashlytics().setCustomValue(call.getInt("value") as Any, forKey: key)
break

case "boolean":
case "boolean":
Crashlytics.crashlytics().setCustomValue(call.getBool("value") as Any, forKey: key)
break

case "long":
case "long":
Crashlytics.crashlytics().setCustomValue(call.getInt("value") as Any, forKey: key)
break

case "double":
case "double":
Crashlytics.crashlytics().setCustomValue(call.getDouble("value") as Any, forKey: key)
break

case "float":
case "float":
Crashlytics.crashlytics().setCustomValue(call.getFloat("value") as Any, forKey: key)
break

default:
Crashlytics.crashlytics().setCustomValue(call.getString("value") as Any, forKey: key)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import com.google.firebase.firestore.ListenerRegistration;
import com.google.firebase.firestore.Query;
import com.google.firebase.firestore.SetOptions;
import com.google.firebase.firestore.WriteBatch;
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.AddDocumentOptions;
Expand All @@ -20,6 +21,8 @@
import io.capawesome.capacitorjs.plugins.firebase.firestore.classes.options.RemoveSnapshotListenerOptions;
import io.capawesome.capacitorjs.plugins.firebase.firestore.classes.options.SetDocumentOptions;
import io.capawesome.capacitorjs.plugins.firebase.firestore.classes.options.UpdateDocumentOptions;
import io.capawesome.capacitorjs.plugins.firebase.firestore.classes.options.WriteBatchOperation;
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.GetDocumentResult;
Expand Down Expand Up @@ -105,6 +108,31 @@ public void deleteDocument(@NonNull DeleteDocumentOptions options, @NonNull Empt
.addOnFailureListener(exception -> callback.error(exception));
}

public void writeBatch(@NonNull WriteBatchOptions options, @NonNull EmptyResultCallback callback) {
WriteBatchOperation[] operations = options.getOperations();

WriteBatch batch = getFirebaseFirestoreInstance().batch();
for (WriteBatchOperation operation : operations) {
String type = operation.getType();
String reference = operation.getReference();
Map<String, Object> data = operation.getData();

DocumentReference documentReference = getFirebaseFirestoreInstance().document(reference);
switch (type) {
case "set":
batch.set(documentReference, data);
break;
case "update":
batch.update(documentReference, data);
break;
case "delete":
batch.delete(documentReference);
break;
}
}
batch.commit().addOnSuccessListener(unused -> callback.success()).addOnFailureListener(exception -> callback.error(exception));
}

public void getCollection(@NonNull GetCollectionOptions options, @NonNull NonEmptyResultCallback callback) throws Exception {
String reference = options.getReference();
QueryCompositeFilterConstraint compositeFilter = options.getCompositeFilter();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,20 +49,6 @@ public static JSObject createJSObjectFromMap(@Nullable Map<String, Object> map)
return object;
}

public static ArrayList<Object> createArrayListFromJSONArray(JSONArray array) throws JSONException {
ArrayList<Object> arrayList = new ArrayList<>();
for (int x = 0; x < array.length(); x++) {
Object value = array.get(x);
if (value instanceof JSONObject) {
value = createHashMapFromJSONObject((JSONObject) value);
} else if (value instanceof JSONArray) {
value = createArrayListFromJSONArray((JSONArray) value);
}
arrayList.add(value);
}
return arrayList;
}

public static Object createObjectFromJSValue(Object value) throws JSONException {
if (value.toString().equals("null")) {
return null;
Expand Down Expand Up @@ -116,6 +102,20 @@ public static QueryNonFilterConstraint[] createQueryNonFilterConstraintArrayFrom
}
}

private static ArrayList<Object> createArrayListFromJSONArray(JSONArray array) throws JSONException {
ArrayList<Object> arrayList = new ArrayList<>();
for (int x = 0; x < array.length(); x++) {
Object value = array.get(x);
if (value instanceof JSONObject) {
value = createHashMapFromJSONObject((JSONObject) value);
} else if (value instanceof JSONArray) {
value = createArrayListFromJSONArray((JSONArray) value);
}
arrayList.add(value);
}
return arrayList;
}

private static JSArray createJSArrayFromArrayList(ArrayList arrayList) {
JSArray array = new JSArray();
for (Object value : arrayList) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import io.capawesome.capacitorjs.plugins.firebase.firestore.classes.options.RemoveSnapshotListenerOptions;
import io.capawesome.capacitorjs.plugins.firebase.firestore.classes.options.SetDocumentOptions;
import io.capawesome.capacitorjs.plugins.firebase.firestore.classes.options.UpdateDocumentOptions;
import io.capawesome.capacitorjs.plugins.firebase.firestore.classes.options.WriteBatchOptions;
import io.capawesome.capacitorjs.plugins.firebase.firestore.interfaces.EmptyResultCallback;
import io.capawesome.capacitorjs.plugins.firebase.firestore.interfaces.NonEmptyResultCallback;
import io.capawesome.capacitorjs.plugins.firebase.firestore.interfaces.Result;
Expand All @@ -33,6 +34,7 @@ public class FirebaseFirestorePlugin extends Plugin {
public static final String ERROR_REFERENCE_MISSING = "reference must be provided.";
public static final String ERROR_CALLBACK_ID_MISSING = "callbackId must be provided.";
public static final String ERROR_DATA_MISSING = "data must be provided.";
public static final String ERROR_OPERATIONS_MISSING = "operations must be provided.";

private Map<String, PluginCall> pluginCallMap = new HashMap<>();

Expand Down Expand Up @@ -208,6 +210,36 @@ public void error(Exception exception) {
}
}

@PluginMethod
public void writeBatch(PluginCall call) {
try {
JSArray operations = call.getArray("operations");
if (operations == null) {
call.reject(ERROR_OPERATIONS_MISSING);
return;
}

WriteBatchOptions options = new WriteBatchOptions(operations);
EmptyResultCallback callback = new EmptyResultCallback() {
@Override
public void success() {
call.resolve();
}

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

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

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

import androidx.annotation.NonNull;
import com.getcapacitor.JSObject;
import io.capawesome.capacitorjs.plugins.firebase.firestore.FirebaseFirestoreHelper;
import java.util.Map;
import org.json.JSONException;

public class WriteBatchOperation {

private String type;
private String reference;
private Map<String, Object> data;

public WriteBatchOperation(@NonNull JSObject operation) throws JSONException {
this.type = operation.getString("type");
this.reference = operation.getString("reference");
this.data = FirebaseFirestoreHelper.createHashMapFromJSONObject(operation.getJSObject("data"));
}

public String getType() {
return type;
}

public String getReference() {
return reference;
}

public Map<String, Object> getData() {
return data;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
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 org.json.JSONException;

public class WriteBatchOptions {

private WriteBatchOperation[] operations;

public WriteBatchOptions(@Nullable JSArray operations) throws JSONException {
this.operations = createWriteBatchOperationArrayFromJSArray(operations);
}

@NonNull
private static WriteBatchOperation[] createWriteBatchOperationArrayFromJSArray(@Nullable JSArray data) throws JSONException {
if (data == null) {
return new WriteBatchOperation[0];
} else {
WriteBatchOperation[] operations = new WriteBatchOperation[data.length()];
for (int i = 0; i < data.length(); i++) {
JSObject operation = JSObject.fromJSONObject(data.getJSONObject(i));
operations[i] = new WriteBatchOperation(operation);
}
return operations;
}
}

@NonNull
public WriteBatchOperation[] getOperations() {
return operations;
}
}
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 */; };
7CF0EFE32C207844004D910D /* WriteBatchOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CF0EFE22C207844004D910D /* WriteBatchOptions.swift */; };
7CF0EFE52C20784E004D910D /* WriteBatchOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CF0EFE42C20784E004D910D /* WriteBatchOperation.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -89,6 +91,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>"; };
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>"; };
91781294A431A2A7CC6EB714 /* Pods-Plugin.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Plugin.release.xcconfig"; path = "Pods/Target Support Files/Pods-Plugin/Pods-Plugin.release.xcconfig"; sourceTree = "<group>"; };
96ED1B6440D6672E406C8D19 /* Pods-PluginTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PluginTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-PluginTests/Pods-PluginTests.debug.xcconfig"; sourceTree = "<group>"; };
F65BB2953ECE002E1EF3E424 /* Pods-PluginTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PluginTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-PluginTests/Pods-PluginTests.release.xcconfig"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -194,6 +198,8 @@
7C0070332ABC1FCD000C0F28 /* SetDocumentOptions.swift */,
7C0070352ABC1FD7000C0F28 /* UpdateDocumentOptions.swift */,
7C00701F2ABC1F42000C0F28 /* GetDocumentOptions.swift */,
7CF0EFE22C207844004D910D /* WriteBatchOptions.swift */,
7CF0EFE42C20784E004D910D /* WriteBatchOperation.swift */,
);
path = Options;
sourceTree = "<group>";
Expand Down Expand Up @@ -460,9 +466,11 @@
50E1A94820377CB70090CE1A /* FirebaseFirestorePlugin.swift in Sources */,
7C00702B2ABC1F7B000C0F28 /* QueryLimitConstraint.swift in Sources */,
7C0070202ABC1F42000C0F28 /* GetDocumentOptions.swift in Sources */,
7CF0EFE52C20784E004D910D /* WriteBatchOperation.swift in Sources */,
7C00701E2ABC1F38000C0F28 /* GetCollectionResult.swift in Sources */,
7C00702F2ABC1FAF000C0F28 /* QueryStartAtConstraint.swift in Sources */,
7C0070182ABC1F20000C0F28 /* GetCollectionGroupOptions.swift in Sources */,
7CF0EFE32C207844004D910D /* WriteBatchOptions.swift in Sources */,
7C0070102ABC1EE0000C0F28 /* AddDocumentOptions.swift in Sources */,
7C0070162ABC1F18000C0F28 /* DeleteDocumentOptions.swift in Sources */,
7C0070122ABC1F03000C0F28 /* AddDocumentResult.swift in Sources */,
Expand Down
Loading

0 comments on commit 7c33d62

Please sign in to comment.