mirror of
https://github.com/zhigang1992/react-native-firebase.git
synced 2026-04-23 03:59:18 +08:00
merge master into omer_links
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
buildscript {
|
||||
ext.firebaseVersion = '11.2.0'
|
||||
ext.firebaseVersion = '11.4.2'
|
||||
repositories {
|
||||
jcenter()
|
||||
}
|
||||
@@ -33,6 +33,10 @@ android {
|
||||
allprojects {
|
||||
repositories {
|
||||
jcenter()
|
||||
mavenLocal()
|
||||
maven {
|
||||
url "https://maven.google.com"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,5 +89,6 @@ dependencies {
|
||||
compile "com.google.firebase:firebase-crash:$firebaseVersion"
|
||||
compile "com.google.firebase:firebase-perf:$firebaseVersion"
|
||||
compile "com.google.firebase:firebase-ads:$firebaseVersion"
|
||||
compile "com.google.firebase:firebase-firestore:$firebaseVersion"
|
||||
compile "com.google.firebase:firebase-invites:$firebaseVersion"
|
||||
}
|
||||
|
||||
27
android/src/main/java/io/invertase/firebase/ErrorUtils.java
Normal file
27
android/src/main/java/io/invertase/firebase/ErrorUtils.java
Normal file
@@ -0,0 +1,27 @@
|
||||
package io.invertase.firebase;
|
||||
|
||||
public class ErrorUtils {
|
||||
/**
|
||||
* Wrap a message string with the specified service name e.g. 'Database'
|
||||
*
|
||||
* @param message
|
||||
* @param service
|
||||
* @param fullCode
|
||||
* @return
|
||||
*/
|
||||
public static String getMessageWithService(String message, String service, String fullCode) {
|
||||
// Service: Error message (service/code).
|
||||
return service + ": " + message + " (" + fullCode.toLowerCase() + ").";
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a service error code string e.g. 'DATABASE/PERMISSION-DENIED'
|
||||
*
|
||||
* @param service
|
||||
* @param code
|
||||
* @return
|
||||
*/
|
||||
public static String getCodeWithService(String service, String code) {
|
||||
return service.toLowerCase() + "/" + code.toLowerCase();
|
||||
}
|
||||
}
|
||||
@@ -31,18 +31,6 @@ public class RNFirebasePackage implements ReactPackage {
|
||||
return modules;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list of JS modules to register with the newly created catalyst instance.
|
||||
* <p/>
|
||||
* IMPORTANT: Note that only modules that needs to be accessible from the native code should be
|
||||
* listed here. Also listing a native module here doesn't imply that the JS implementation of it
|
||||
* will be automatically included in the JS bundle.
|
||||
*/
|
||||
// TODO: Removed in 0.47.0. Here for backwards compatability
|
||||
public List<Class<? extends JavaScriptModule>> createJSModules() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param reactContext
|
||||
* @return a list of view managers that should be registered with {@link UIManagerModule}
|
||||
|
||||
@@ -78,7 +78,6 @@ public class Utils {
|
||||
|
||||
/**
|
||||
* @param dataSnapshot
|
||||
* @param registration
|
||||
* @param previousChildName
|
||||
* @return
|
||||
*/
|
||||
|
||||
@@ -29,18 +29,6 @@ public class RNFirebaseAdMobPackage implements ReactPackage {
|
||||
return modules;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list of JS modules to register with the newly created catalyst instance.
|
||||
* <p/>
|
||||
* IMPORTANT: Note that only modules that needs to be accessible from the native code should be
|
||||
* listed here. Also listing a native module here doesn't imply that the JS implementation of it
|
||||
* will be automatically included in the JS bundle.
|
||||
*/
|
||||
// TODO: Removed in 0.47.0. Here for backwards compatability
|
||||
public List<Class<? extends JavaScriptModule>> createJSModules() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param reactContext
|
||||
* @return a list of view managers that should be registered with {@link UIManagerModule}
|
||||
|
||||
@@ -33,18 +33,6 @@ public class RNFirebaseAnalyticsPackage implements ReactPackage {
|
||||
return modules;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list of JS modules to register with the newly created catalyst instance.
|
||||
* <p/>
|
||||
* IMPORTANT: Note that only modules that needs to be accessible from the native code should be
|
||||
* listed here. Also listing a native module here doesn't imply that the JS implementation of it
|
||||
* will be automatically included in the JS bundle.
|
||||
*/
|
||||
// TODO: Removed in 0.47.0. Here for backwards compatability
|
||||
public List<Class<? extends JavaScriptModule>> createJSModules() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param reactContext
|
||||
* @return a list of view managers that should be registered with {@link UIManagerModule}
|
||||
|
||||
@@ -813,7 +813,7 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule {
|
||||
TimeUnit.SECONDS,
|
||||
activity,
|
||||
callbacks
|
||||
// ,PhoneAuthProvider.ForceResendingToken.zzboe() // TODO FORCE RESENDING
|
||||
//, PhoneAuthProvider.ForceResendingToken.zzboe() // TODO FORCE RESENDING
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,18 +28,6 @@ public class RNFirebaseAuthPackage implements ReactPackage {
|
||||
return modules;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list of JS modules to register with the newly created catalyst instance.
|
||||
* <p/>
|
||||
* IMPORTANT: Note that only modules that needs to be accessible from the native code should be
|
||||
* listed here. Also listing a native module here doesn't imply that the JS implementation of it
|
||||
* will be automatically included in the JS bundle.
|
||||
*/
|
||||
// TODO: Removed in 0.47.0. Here for backwards compatability
|
||||
public List<Class<? extends JavaScriptModule>> createJSModules() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param reactContext
|
||||
* @return a list of view managers that should be registered with {@link UIManagerModule}
|
||||
|
||||
@@ -28,18 +28,6 @@ public class RNFirebaseRemoteConfigPackage implements ReactPackage {
|
||||
return modules;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list of JS modules to register with the newly created catalyst instance.
|
||||
* <p/>
|
||||
* IMPORTANT: Note that only modules that needs to be accessible from the native code should be
|
||||
* listed here. Also listing a native module here doesn't imply that the JS implementation of it
|
||||
* will be automatically included in the JS bundle.
|
||||
*/
|
||||
// TODO: Removed in 0.47.0. Here for backwards compatability
|
||||
public List<Class<? extends JavaScriptModule>> createJSModules() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param reactContext
|
||||
* @return a list of view managers that should be registered with {@link UIManagerModule}
|
||||
|
||||
@@ -28,18 +28,6 @@ public class RNFirebaseCrashPackage implements ReactPackage {
|
||||
return modules;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list of JS modules to register with the newly created catalyst instance.
|
||||
* <p/>
|
||||
* IMPORTANT: Note that only modules that needs to be accessible from the native code should be
|
||||
* listed here. Also listing a native module here doesn't imply that the JS implementation of it
|
||||
* will be automatically included in the JS bundle.
|
||||
*/
|
||||
// TODO: Removed in 0.47.0. Here for backwards compatability
|
||||
public List<Class<? extends JavaScriptModule>> createJSModules() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param reactContext
|
||||
* @return a list of view managers that should be registered with {@link UIManagerModule}
|
||||
|
||||
@@ -26,6 +26,7 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import io.invertase.firebase.ErrorUtils;
|
||||
import io.invertase.firebase.Utils;
|
||||
|
||||
|
||||
@@ -522,30 +523,6 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule {
|
||||
return existingRef;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap a message string with the specified service name e.g. 'Database'
|
||||
*
|
||||
* @param message
|
||||
* @param service
|
||||
* @param fullCode
|
||||
* @return
|
||||
*/
|
||||
private static String getMessageWithService(String message, String service, String fullCode) {
|
||||
// Service: Error message (service/code).
|
||||
return service + ": " + message + " (" + fullCode.toLowerCase() + ").";
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a service error code string e.g. 'DATABASE/PERMISSION-DENIED'
|
||||
*
|
||||
* @param service
|
||||
* @param code
|
||||
* @return
|
||||
*/
|
||||
private static String getCodeWithService(String service, String code) {
|
||||
return service.toLowerCase() + "/" + code.toLowerCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert as firebase DatabaseError instance into a writable map
|
||||
* with the correct web-like error codes.
|
||||
@@ -564,56 +541,56 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule {
|
||||
|
||||
switch (nativeError.getCode()) {
|
||||
case DatabaseError.DATA_STALE:
|
||||
code = getCodeWithService(service, "data-stale");
|
||||
message = getMessageWithService("The transaction needs to be run again with current data.", service, code);
|
||||
code = ErrorUtils.getCodeWithService(service, "data-stale");
|
||||
message = ErrorUtils.getMessageWithService("The transaction needs to be run again with current data.", service, code);
|
||||
break;
|
||||
case DatabaseError.OPERATION_FAILED:
|
||||
code = getCodeWithService(service, "failure");
|
||||
message = getMessageWithService("The server indicated that this operation failed.", service, code);
|
||||
code = ErrorUtils.getCodeWithService(service, "failure");
|
||||
message = ErrorUtils.getMessageWithService("The server indicated that this operation failed.", service, code);
|
||||
break;
|
||||
case DatabaseError.PERMISSION_DENIED:
|
||||
code = getCodeWithService(service, "permission-denied");
|
||||
message = getMessageWithService("Client doesn't have permission to access the desired data.", service, code);
|
||||
code = ErrorUtils.getCodeWithService(service, "permission-denied");
|
||||
message = ErrorUtils.getMessageWithService("Client doesn't have permission to access the desired data.", service, code);
|
||||
break;
|
||||
case DatabaseError.DISCONNECTED:
|
||||
code = getCodeWithService(service, "disconnected");
|
||||
message = getMessageWithService("The operation had to be aborted due to a network disconnect.", service, code);
|
||||
code = ErrorUtils.getCodeWithService(service, "disconnected");
|
||||
message = ErrorUtils.getMessageWithService("The operation had to be aborted due to a network disconnect.", service, code);
|
||||
break;
|
||||
case DatabaseError.EXPIRED_TOKEN:
|
||||
code = getCodeWithService(service, "expired-token");
|
||||
message = getMessageWithService("The supplied auth token has expired.", service, code);
|
||||
code = ErrorUtils.getCodeWithService(service, "expired-token");
|
||||
message = ErrorUtils.getMessageWithService("The supplied auth token has expired.", service, code);
|
||||
break;
|
||||
case DatabaseError.INVALID_TOKEN:
|
||||
code = getCodeWithService(service, "invalid-token");
|
||||
message = getMessageWithService("The supplied auth token was invalid.", service, code);
|
||||
code = ErrorUtils.getCodeWithService(service, "invalid-token");
|
||||
message = ErrorUtils.getMessageWithService("The supplied auth token was invalid.", service, code);
|
||||
break;
|
||||
case DatabaseError.MAX_RETRIES:
|
||||
code = getCodeWithService(service, "max-retries");
|
||||
message = getMessageWithService("The transaction had too many retries.", service, code);
|
||||
code = ErrorUtils.getCodeWithService(service, "max-retries");
|
||||
message = ErrorUtils.getMessageWithService("The transaction had too many retries.", service, code);
|
||||
break;
|
||||
case DatabaseError.OVERRIDDEN_BY_SET:
|
||||
code = getCodeWithService(service, "overridden-by-set");
|
||||
message = getMessageWithService("The transaction was overridden by a subsequent set.", service, code);
|
||||
code = ErrorUtils.getCodeWithService(service, "overridden-by-set");
|
||||
message = ErrorUtils.getMessageWithService("The transaction was overridden by a subsequent set.", service, code);
|
||||
break;
|
||||
case DatabaseError.UNAVAILABLE:
|
||||
code = getCodeWithService(service, "unavailable");
|
||||
message = getMessageWithService("The service is unavailable.", service, code);
|
||||
code = ErrorUtils.getCodeWithService(service, "unavailable");
|
||||
message = ErrorUtils.getMessageWithService("The service is unavailable.", service, code);
|
||||
break;
|
||||
case DatabaseError.USER_CODE_EXCEPTION:
|
||||
code = getCodeWithService(service, "user-code-exception");
|
||||
message = getMessageWithService("User code called from the Firebase Database runloop threw an exception.", service, code);
|
||||
code = ErrorUtils.getCodeWithService(service, "user-code-exception");
|
||||
message = ErrorUtils.getMessageWithService("User code called from the Firebase Database runloop threw an exception.", service, code);
|
||||
break;
|
||||
case DatabaseError.NETWORK_ERROR:
|
||||
code = getCodeWithService(service, "network-error");
|
||||
message = getMessageWithService("The operation could not be performed due to a network error.", service, code);
|
||||
code = ErrorUtils.getCodeWithService(service, "network-error");
|
||||
message = ErrorUtils.getMessageWithService("The operation could not be performed due to a network error.", service, code);
|
||||
break;
|
||||
case DatabaseError.WRITE_CANCELED:
|
||||
code = getCodeWithService(service, "write-cancelled");
|
||||
message = getMessageWithService("The write was canceled by the user.", service, code);
|
||||
code = ErrorUtils.getCodeWithService(service, "write-cancelled");
|
||||
message = ErrorUtils.getMessageWithService("The write was canceled by the user.", service, code);
|
||||
break;
|
||||
default:
|
||||
code = getCodeWithService(service, "unknown");
|
||||
message = getMessageWithService("An unknown error occurred.", service, code);
|
||||
code = ErrorUtils.getCodeWithService(service, "unknown");
|
||||
message = ErrorUtils.getMessageWithService("An unknown error occurred.", service, code);
|
||||
}
|
||||
|
||||
errorMap.putString("code", code);
|
||||
|
||||
@@ -28,18 +28,6 @@ public class RNFirebaseDatabasePackage implements ReactPackage {
|
||||
return modules;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list of JS modules to register with the newly created catalyst instance.
|
||||
* <p/>
|
||||
* IMPORTANT: Note that only modules that needs to be accessible from the native code should be
|
||||
* listed here. Also listing a native module here doesn't imply that the JS implementation of it
|
||||
* will be automatically included in the JS bundle.
|
||||
*/
|
||||
// TODO: Removed in 0.47.0. Here for backwards compatability
|
||||
public List<Class<? extends JavaScriptModule>> createJSModules() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param reactContext
|
||||
* @return a list of view managers that should be registered with {@link UIManagerModule}
|
||||
|
||||
@@ -29,8 +29,8 @@ class RNFirebaseDatabaseReference {
|
||||
private String appName;
|
||||
private ReactContext reactContext;
|
||||
private static final String TAG = "RNFirebaseDBReference";
|
||||
private HashMap<String, ChildEventListener> childEventListeners;
|
||||
private HashMap<String, ValueEventListener> valueEventListeners;
|
||||
private HashMap<String, ChildEventListener> childEventListeners = new HashMap<>();
|
||||
private HashMap<String, ValueEventListener> valueEventListeners = new HashMap<>();
|
||||
|
||||
/**
|
||||
* RNFirebase wrapper around FirebaseDatabaseReference,
|
||||
@@ -47,8 +47,6 @@ class RNFirebaseDatabaseReference {
|
||||
query = null;
|
||||
appName = app;
|
||||
reactContext = context;
|
||||
childEventListeners = new HashMap<>();
|
||||
valueEventListeners = new HashMap<>();
|
||||
buildDatabaseQueryAtPathAndModifiers(refPath, modifiersArray);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,210 @@
|
||||
package io.invertase.firebase.firestore;
|
||||
|
||||
import com.facebook.react.bridge.Arguments;
|
||||
import com.facebook.react.bridge.WritableArray;
|
||||
import com.facebook.react.bridge.WritableMap;
|
||||
import com.google.firebase.firestore.DocumentChange;
|
||||
import com.google.firebase.firestore.DocumentSnapshot;
|
||||
import com.google.firebase.firestore.QuerySnapshot;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class FirestoreSerialize {
|
||||
private static final String KEY_CHANGES = "changes";
|
||||
private static final String KEY_DATA = "data";
|
||||
private static final String KEY_DOC_CHANGE_DOCUMENT = "document";
|
||||
private static final String KEY_DOC_CHANGE_NEW_INDEX = "newIndex";
|
||||
private static final String KEY_DOC_CHANGE_OLD_INDEX = "oldIndex";
|
||||
private static final String KEY_DOC_CHANGE_TYPE = "type";
|
||||
private static final String KEY_DOCUMENTS = "documents";
|
||||
private static final String KEY_METADATA = "metadata";
|
||||
private static final String KEY_PATH = "path";
|
||||
|
||||
/**
|
||||
* Convert a DocumentSnapshot instance into a React Native WritableMap
|
||||
*
|
||||
* @param documentSnapshot DocumentSnapshot
|
||||
* @return WritableMap
|
||||
*/
|
||||
static WritableMap snapshotToWritableMap(DocumentSnapshot documentSnapshot) {
|
||||
WritableMap documentMap = Arguments.createMap();
|
||||
|
||||
documentMap.putString(KEY_PATH, documentSnapshot.getReference().getPath());
|
||||
if (documentSnapshot.exists()) {
|
||||
documentMap.putMap(KEY_DATA, objectMapToWritable(documentSnapshot.getData()));
|
||||
}
|
||||
// metadata
|
||||
if (documentSnapshot.getMetadata() != null) {
|
||||
WritableMap metadata = Arguments.createMap();
|
||||
metadata.putBoolean("fromCache", documentSnapshot.getMetadata().isFromCache());
|
||||
metadata.putBoolean("hasPendingWrites", documentSnapshot.getMetadata().hasPendingWrites());
|
||||
documentMap.putMap(KEY_METADATA, metadata);
|
||||
}
|
||||
|
||||
return documentMap;
|
||||
}
|
||||
|
||||
public static WritableMap snapshotToWritableMap(QuerySnapshot querySnapshot) {
|
||||
WritableMap queryMap = Arguments.createMap();
|
||||
|
||||
List<DocumentChange> documentChanges = querySnapshot.getDocumentChanges();
|
||||
queryMap.putArray(KEY_CHANGES, documentChangesToWritableArray(documentChanges));
|
||||
|
||||
// documents
|
||||
WritableArray documents = Arguments.createArray();
|
||||
List<DocumentSnapshot> documentSnapshots = querySnapshot.getDocuments();
|
||||
for (DocumentSnapshot documentSnapshot : documentSnapshots) {
|
||||
documents.pushMap(snapshotToWritableMap(documentSnapshot));
|
||||
}
|
||||
queryMap.putArray(KEY_DOCUMENTS, documents);
|
||||
|
||||
// metadata
|
||||
if (querySnapshot.getMetadata() != null) {
|
||||
WritableMap metadata = Arguments.createMap();
|
||||
metadata.putBoolean("fromCache", querySnapshot.getMetadata().isFromCache());
|
||||
metadata.putBoolean("hasPendingWrites", querySnapshot.getMetadata().hasPendingWrites());
|
||||
queryMap.putMap(KEY_METADATA, metadata);
|
||||
}
|
||||
|
||||
return queryMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a List of DocumentChange instances into a React Native WritableArray
|
||||
*
|
||||
* @param documentChanges List<DocumentChange>
|
||||
* @return WritableArray
|
||||
*/
|
||||
static WritableArray documentChangesToWritableArray(List<DocumentChange> documentChanges) {
|
||||
WritableArray documentChangesWritable = Arguments.createArray();
|
||||
for (DocumentChange documentChange : documentChanges) {
|
||||
documentChangesWritable.pushMap(documentChangeToWritableMap(documentChange));
|
||||
}
|
||||
return documentChangesWritable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a DocumentChange instance into a React Native WritableMap
|
||||
*
|
||||
* @param documentChange DocumentChange
|
||||
* @return WritableMap
|
||||
*/
|
||||
static WritableMap documentChangeToWritableMap(DocumentChange documentChange) {
|
||||
WritableMap documentChangeMap = Arguments.createMap();
|
||||
|
||||
switch (documentChange.getType()) {
|
||||
case ADDED:
|
||||
documentChangeMap.putString(KEY_DOC_CHANGE_TYPE, "added");
|
||||
break;
|
||||
case REMOVED:
|
||||
documentChangeMap.putString(KEY_DOC_CHANGE_TYPE, "removed");
|
||||
break;
|
||||
case MODIFIED:
|
||||
documentChangeMap.putString(KEY_DOC_CHANGE_TYPE, "modified");
|
||||
}
|
||||
|
||||
documentChangeMap.putMap(KEY_DOC_CHANGE_DOCUMENT,
|
||||
snapshotToWritableMap(documentChange.getDocument()));
|
||||
documentChangeMap.putInt(KEY_DOC_CHANGE_NEW_INDEX, documentChange.getNewIndex());
|
||||
documentChangeMap.putInt(KEY_DOC_CHANGE_OLD_INDEX, documentChange.getOldIndex());
|
||||
|
||||
return documentChangeMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an Object Map into a React Native WritableMap.
|
||||
*
|
||||
* @param map Map<String, Object>
|
||||
* @return WritableMap
|
||||
*/
|
||||
static WritableMap objectMapToWritable(Map<String, Object> map) {
|
||||
WritableMap writableMap = Arguments.createMap();
|
||||
for (Map.Entry<String, Object> entry : map.entrySet()) {
|
||||
putValue(writableMap, entry.getKey(), entry.getValue());
|
||||
}
|
||||
return writableMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an Object array into a React Native WritableArray.
|
||||
*
|
||||
* @param array Object[]
|
||||
* @return WritableArray
|
||||
*/
|
||||
static WritableArray objectArrayToWritable(Object[] array) {
|
||||
WritableArray writableArray = Arguments.createArray();
|
||||
|
||||
for (Object item : array) {
|
||||
if (item == null) {
|
||||
writableArray.pushNull();
|
||||
continue;
|
||||
}
|
||||
|
||||
Class itemClass = item.getClass();
|
||||
|
||||
if (itemClass == Boolean.class) {
|
||||
writableArray.pushBoolean((Boolean) item);
|
||||
} else if (itemClass == Integer.class) {
|
||||
writableArray.pushDouble(((Integer) item).doubleValue());
|
||||
} else if (itemClass == Double.class) {
|
||||
writableArray.pushDouble((Double) item);
|
||||
} else if (itemClass == Float.class) {
|
||||
writableArray.pushDouble(((Float) item).doubleValue());
|
||||
} else if (itemClass == String.class) {
|
||||
writableArray.pushString(item.toString());
|
||||
} else if (itemClass == Map.class) {
|
||||
writableArray.pushMap((objectMapToWritable((Map<String, Object>) item)));
|
||||
} else if (itemClass == Arrays.class) {
|
||||
writableArray.pushArray(objectArrayToWritable((Object[]) item));
|
||||
} else if (itemClass == List.class || itemClass == ArrayList.class) {
|
||||
List<Object> list = (List<Object>) item;
|
||||
Object[] listAsArray = list.toArray(new Object[list.size()]);
|
||||
writableArray.pushArray(objectArrayToWritable(listAsArray));
|
||||
} else {
|
||||
throw new RuntimeException("Cannot convert object of type " + item);
|
||||
}
|
||||
}
|
||||
|
||||
return writableArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects an objects type and calls the relevant WritableMap setter method to add the value.
|
||||
*
|
||||
* @param map WritableMap
|
||||
* @param key String
|
||||
* @param value Object
|
||||
*/
|
||||
static void putValue(WritableMap map, String key, Object value) {
|
||||
if (value == null) {
|
||||
map.putNull(key);
|
||||
} else {
|
||||
Class valueClass = value.getClass();
|
||||
|
||||
if (valueClass == Boolean.class) {
|
||||
map.putBoolean(key, (Boolean) value);
|
||||
} else if (valueClass == Integer.class) {
|
||||
map.putDouble(key, ((Integer) value).doubleValue());
|
||||
} else if (valueClass == Double.class) {
|
||||
map.putDouble(key, (Double) value);
|
||||
} else if (valueClass == Float.class) {
|
||||
map.putDouble(key, ((Float) value).doubleValue());
|
||||
} else if (valueClass == String.class) {
|
||||
map.putString(key, value.toString());
|
||||
} else if (valueClass == Map.class) {
|
||||
map.putMap(key, (objectMapToWritable((Map<String, Object>) value)));
|
||||
} else if (valueClass == Arrays.class) {
|
||||
map.putArray(key, objectArrayToWritable((Object[]) value));
|
||||
} else if (valueClass == List.class || valueClass == ArrayList.class) {
|
||||
List<Object> list = (List<Object>) value;
|
||||
Object[] array = list.toArray(new Object[list.size()]);
|
||||
map.putArray(key, objectArrayToWritable(array));
|
||||
} else {
|
||||
throw new RuntimeException("Cannot convert object of type " + value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,340 @@
|
||||
package io.invertase.firebase.firestore;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.util.Log;
|
||||
|
||||
import com.facebook.react.bridge.Arguments;
|
||||
import com.facebook.react.bridge.Promise;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
||||
import com.facebook.react.bridge.ReactMethod;
|
||||
import com.facebook.react.bridge.ReadableArray;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.bridge.WritableArray;
|
||||
import com.facebook.react.bridge.WritableMap;
|
||||
import com.google.android.gms.tasks.OnCompleteListener;
|
||||
import com.google.android.gms.tasks.Task;
|
||||
import com.google.firebase.FirebaseApp;
|
||||
import com.google.firebase.firestore.DocumentReference;
|
||||
import com.google.firebase.firestore.FieldValue;
|
||||
import com.google.firebase.firestore.FirebaseFirestore;
|
||||
import com.google.firebase.firestore.FirebaseFirestoreException;
|
||||
import com.google.firebase.firestore.SetOptions;
|
||||
import com.google.firebase.firestore.WriteBatch;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import io.invertase.firebase.ErrorUtils;
|
||||
import io.invertase.firebase.Utils;
|
||||
|
||||
|
||||
public class RNFirebaseFirestore extends ReactContextBaseJavaModule {
|
||||
private static final String TAG = "RNFirebaseFirestore";
|
||||
// private SparseArray<RNFirebaseTransactionHandler> transactionHandlers = new SparseArray<>();
|
||||
|
||||
RNFirebaseFirestore(ReactApplicationContext reactContext) {
|
||||
super(reactContext);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* REACT NATIVE METHODS
|
||||
*/
|
||||
@ReactMethod
|
||||
public void collectionGet(String appName, String path, ReadableArray filters,
|
||||
ReadableArray orders, ReadableMap options, final Promise promise) {
|
||||
RNFirebaseFirestoreCollectionReference ref = getCollectionForAppPath(appName, path, filters, orders, options);
|
||||
ref.get(promise);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void collectionOffSnapshot(String appName, String path, ReadableArray filters,
|
||||
ReadableArray orders, ReadableMap options, String listenerId) {
|
||||
RNFirebaseFirestoreCollectionReference.offSnapshot(listenerId);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void collectionOnSnapshot(String appName, String path, ReadableArray filters,
|
||||
ReadableArray orders, ReadableMap options, String listenerId) {
|
||||
RNFirebaseFirestoreCollectionReference ref = getCollectionForAppPath(appName, path, filters, orders, options);
|
||||
ref.onSnapshot(listenerId);
|
||||
}
|
||||
|
||||
|
||||
@ReactMethod
|
||||
public void documentBatch(final String appName, final ReadableArray writes,
|
||||
final Promise promise) {
|
||||
FirebaseFirestore firestore = getFirestoreForApp(appName);
|
||||
WriteBatch batch = firestore.batch();
|
||||
final List<Object> writesArray = Utils.recursivelyDeconstructReadableArray(writes);
|
||||
|
||||
for (Object w : writesArray) {
|
||||
Map<String, Object> write = (Map) w;
|
||||
String type = (String) write.get("type");
|
||||
String path = (String) write.get("path");
|
||||
Map<String, Object> data = (Map) write.get("data");
|
||||
|
||||
DocumentReference ref = firestore.document(path);
|
||||
switch (type) {
|
||||
case "DELETE":
|
||||
batch = batch.delete(ref);
|
||||
break;
|
||||
case "SET":
|
||||
Map<String, Object> options = (Map) write.get("options");
|
||||
if (options != null && options.containsKey("merge") && (boolean)options.get("merge")) {
|
||||
batch = batch.set(ref, data, SetOptions.merge());
|
||||
} else {
|
||||
batch = batch.set(ref, data);
|
||||
}
|
||||
|
||||
break;
|
||||
case "UPDATE":
|
||||
batch = batch.update(ref, data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
batch.commit().addOnCompleteListener(new OnCompleteListener<Void>() {
|
||||
@Override
|
||||
public void onComplete(@NonNull Task<Void> task) {
|
||||
if (task.isSuccessful()) {
|
||||
Log.d(TAG, "documentBatch:onComplete:success");
|
||||
promise.resolve(null);
|
||||
} else {
|
||||
Log.e(TAG, "documentBatch:onComplete:failure", task.getException());
|
||||
RNFirebaseFirestore.promiseRejectException(promise, (FirebaseFirestoreException)task.getException());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void documentCollections(String appName, String path, final Promise promise) {
|
||||
RNFirebaseFirestoreDocumentReference ref = getDocumentForAppPath(appName, path);
|
||||
ref.collections(promise);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void documentCreate(String appName, String path, ReadableMap data, final Promise promise) {
|
||||
RNFirebaseFirestoreDocumentReference ref = getDocumentForAppPath(appName, path);
|
||||
ref.create(data, promise);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void documentDelete(String appName, String path, final Promise promise) {
|
||||
RNFirebaseFirestoreDocumentReference ref = getDocumentForAppPath(appName, path);
|
||||
ref.delete(promise);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void documentGet(String appName, String path, final Promise promise) {
|
||||
RNFirebaseFirestoreDocumentReference ref = getDocumentForAppPath(appName, path);
|
||||
ref.get(promise);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void documentGetAll(String appName, ReadableArray documents, final Promise promise) {
|
||||
// Not supported on Android out of the box
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void documentOffSnapshot(String appName, String path, String listenerId) {
|
||||
RNFirebaseFirestoreDocumentReference.offSnapshot(listenerId);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void documentOnSnapshot(String appName, String path, String listenerId) {
|
||||
RNFirebaseFirestoreDocumentReference ref = getDocumentForAppPath(appName, path);
|
||||
ref.onSnapshot(listenerId);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void documentSet(String appName, String path, ReadableMap data, ReadableMap options, final Promise promise) {
|
||||
RNFirebaseFirestoreDocumentReference ref = getDocumentForAppPath(appName, path);
|
||||
ref.set(data, options, promise);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void documentUpdate(String appName, String path, ReadableMap data, final Promise promise) {
|
||||
RNFirebaseFirestoreDocumentReference ref = getDocumentForAppPath(appName, path);
|
||||
ref.update(data, promise);
|
||||
}
|
||||
|
||||
/*
|
||||
* INTERNALS/UTILS
|
||||
*/
|
||||
|
||||
/**
|
||||
* Generates a js-like error from an exception and rejects the provided promise with it.
|
||||
*
|
||||
* @param exception Exception Exception normally from a task result.
|
||||
* @param promise Promise react native promise
|
||||
*/
|
||||
static void promiseRejectException(Promise promise, FirebaseFirestoreException exception) {
|
||||
WritableMap jsError = getJSError(exception);
|
||||
promise.reject(
|
||||
jsError.getString("code"),
|
||||
jsError.getString("message"),
|
||||
exception
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a database instance for a specific firebase app instance
|
||||
*
|
||||
* @param appName
|
||||
* @return
|
||||
*/
|
||||
static FirebaseFirestore getFirestoreForApp(String appName) {
|
||||
FirebaseApp firebaseApp = FirebaseApp.getInstance(appName);
|
||||
return FirebaseFirestore.getInstance(firebaseApp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a collection reference for a specific app and path
|
||||
*
|
||||
* @param appName
|
||||
* @param filters
|
||||
* @param orders
|
||||
* @param options
|
||||
* @param path @return
|
||||
*/
|
||||
private RNFirebaseFirestoreCollectionReference getCollectionForAppPath(String appName, String path,
|
||||
ReadableArray filters,
|
||||
ReadableArray orders,
|
||||
ReadableMap options) {
|
||||
return new RNFirebaseFirestoreCollectionReference(this.getReactApplicationContext(), appName, path, filters, orders, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a document reference for a specific app and path
|
||||
*
|
||||
* @param appName
|
||||
* @param path
|
||||
* @return
|
||||
*/
|
||||
private RNFirebaseFirestoreDocumentReference getDocumentForAppPath(String appName, String path) {
|
||||
return new RNFirebaseFirestoreDocumentReference(this.getReactApplicationContext(), appName, path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert as firebase DatabaseError instance into a writable map
|
||||
* with the correct web-like error codes.
|
||||
*
|
||||
* @param nativeException
|
||||
* @return
|
||||
*/
|
||||
static WritableMap getJSError(FirebaseFirestoreException nativeException) {
|
||||
WritableMap errorMap = Arguments.createMap();
|
||||
errorMap.putInt("nativeErrorCode", nativeException.getCode().value());
|
||||
errorMap.putString("nativeErrorMessage", nativeException.getMessage());
|
||||
|
||||
String code;
|
||||
String message;
|
||||
String service = "Firestore";
|
||||
|
||||
// TODO: Proper error mappings
|
||||
switch (nativeException.getCode()) {
|
||||
case OK:
|
||||
code = ErrorUtils.getCodeWithService(service, "ok");
|
||||
message = ErrorUtils.getMessageWithService("Ok.", service, code);
|
||||
break;
|
||||
case CANCELLED:
|
||||
code = ErrorUtils.getCodeWithService(service, "cancelled");
|
||||
message = ErrorUtils.getMessageWithService("The operation was cancelled.", service, code);
|
||||
break;
|
||||
case UNKNOWN:
|
||||
code = ErrorUtils.getCodeWithService(service, "unknown");
|
||||
message = ErrorUtils.getMessageWithService("Unknown error or an error from a different error domain.", service, code);
|
||||
break;
|
||||
case INVALID_ARGUMENT:
|
||||
code = ErrorUtils.getCodeWithService(service, "invalid-argument");
|
||||
message = ErrorUtils.getMessageWithService("Client specified an invalid argument.", service, code);
|
||||
break;
|
||||
case DEADLINE_EXCEEDED:
|
||||
code = ErrorUtils.getCodeWithService(service, "deadline-exceeded");
|
||||
message = ErrorUtils.getMessageWithService("Deadline expired before operation could complete.", service, code);
|
||||
break;
|
||||
case NOT_FOUND:
|
||||
code = ErrorUtils.getCodeWithService(service, "not-found");
|
||||
message = ErrorUtils.getMessageWithService("Some requested document was not found.", service, code);
|
||||
break;
|
||||
case ALREADY_EXISTS:
|
||||
code = ErrorUtils.getCodeWithService(service, "already-exists");
|
||||
message = ErrorUtils.getMessageWithService("Some document that we attempted to create already exists.", service, code);
|
||||
break;
|
||||
case PERMISSION_DENIED:
|
||||
code = ErrorUtils.getCodeWithService(service, "permission-denied");
|
||||
message = ErrorUtils.getMessageWithService("The caller does not have permission to execute the specified operation.", service, code);
|
||||
break;
|
||||
case RESOURCE_EXHAUSTED:
|
||||
code = ErrorUtils.getCodeWithService(service, "resource-exhausted");
|
||||
message = ErrorUtils.getMessageWithService("Some resource has been exhausted, perhaps a per-user quota, or perhaps the entire file system is out of space.", service, code);
|
||||
break;
|
||||
case FAILED_PRECONDITION:
|
||||
code = ErrorUtils.getCodeWithService(service, "failed-precondition");
|
||||
message = ErrorUtils.getMessageWithService("Operation was rejected because the system is not in a state required for the operation`s execution.", service, code);
|
||||
break;
|
||||
case ABORTED:
|
||||
code = ErrorUtils.getCodeWithService(service, "aborted");
|
||||
message = ErrorUtils.getMessageWithService("The operation was aborted, typically due to a concurrency issue like transaction aborts, etc.", service, code);
|
||||
break;
|
||||
case OUT_OF_RANGE:
|
||||
code = ErrorUtils.getCodeWithService(service, "out-of-range");
|
||||
message = ErrorUtils.getMessageWithService("Operation was attempted past the valid range.", service, code);
|
||||
break;
|
||||
case UNIMPLEMENTED:
|
||||
code = ErrorUtils.getCodeWithService(service, "unimplemented");
|
||||
message = ErrorUtils.getMessageWithService("Operation is not implemented or not supported/enabled.", service, code);
|
||||
break;
|
||||
case INTERNAL:
|
||||
code = ErrorUtils.getCodeWithService(service, "internal");
|
||||
message = ErrorUtils.getMessageWithService("Internal errors.", service, code);
|
||||
break;
|
||||
case UNAVAILABLE:
|
||||
code = ErrorUtils.getCodeWithService(service, "unavailable");
|
||||
message = ErrorUtils.getMessageWithService("The service is currently unavailable.", service, code);
|
||||
break;
|
||||
case DATA_LOSS:
|
||||
code = ErrorUtils.getCodeWithService(service, "data-loss");
|
||||
message = ErrorUtils.getMessageWithService("Unrecoverable data loss or corruption.", service, code);
|
||||
break;
|
||||
case UNAUTHENTICATED:
|
||||
code = ErrorUtils.getCodeWithService(service, "unauthenticated");
|
||||
message = ErrorUtils.getMessageWithService("The request does not have valid authentication credentials for the operation.", service, code);
|
||||
break;
|
||||
default:
|
||||
code = ErrorUtils.getCodeWithService(service, "unknown");
|
||||
message = ErrorUtils.getMessageWithService("An unknown error occurred.", service, code);
|
||||
}
|
||||
|
||||
errorMap.putString("code", code);
|
||||
errorMap.putString("message", message);
|
||||
return errorMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* React Method - returns this module name
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public String getName() {
|
||||
return "RNFirebaseFirestore";
|
||||
}
|
||||
|
||||
/**
|
||||
* React Native constants for RNFirebaseFirestore
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Map<String, Object> getConstants() {
|
||||
final Map<String, Object> constants = new HashMap<>();
|
||||
constants.put("deleteFieldValue", FieldValue.delete().toString());
|
||||
constants.put("serverTimestampFieldValue", FieldValue.serverTimestamp().toString());
|
||||
return constants;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,218 @@
|
||||
package io.invertase.firebase.firestore;
|
||||
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.util.Log;
|
||||
|
||||
import com.facebook.react.bridge.Arguments;
|
||||
import com.facebook.react.bridge.Promise;
|
||||
import com.facebook.react.bridge.ReactContext;
|
||||
import com.facebook.react.bridge.ReadableArray;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.bridge.WritableMap;
|
||||
import com.google.android.gms.tasks.OnCompleteListener;
|
||||
import com.google.android.gms.tasks.Task;
|
||||
import com.google.firebase.firestore.EventListener;
|
||||
import com.google.firebase.firestore.FirebaseFirestoreException;
|
||||
import com.google.firebase.firestore.ListenerRegistration;
|
||||
import com.google.firebase.firestore.Query;
|
||||
import com.google.firebase.firestore.QuerySnapshot;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import io.invertase.firebase.Utils;
|
||||
|
||||
public class RNFirebaseFirestoreCollectionReference {
|
||||
private static final String TAG = "RNFSCollectionReference";
|
||||
private static Map<String, ListenerRegistration> collectionSnapshotListeners = new HashMap<>();
|
||||
|
||||
private final String appName;
|
||||
private final String path;
|
||||
private final ReadableArray filters;
|
||||
private final ReadableArray orders;
|
||||
private final ReadableMap options;
|
||||
private final Query query;
|
||||
private ReactContext reactContext;
|
||||
|
||||
RNFirebaseFirestoreCollectionReference(ReactContext reactContext, String appName, String path,
|
||||
ReadableArray filters, ReadableArray orders,
|
||||
ReadableMap options) {
|
||||
this.appName = appName;
|
||||
this.path = path;
|
||||
this.filters = filters;
|
||||
this.orders = orders;
|
||||
this.options = options;
|
||||
this.query = buildQuery();
|
||||
this.reactContext = reactContext;
|
||||
}
|
||||
|
||||
void get(final Promise promise) {
|
||||
query.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
|
||||
@Override
|
||||
public void onComplete(@NonNull Task<QuerySnapshot> task) {
|
||||
if (task.isSuccessful()) {
|
||||
Log.d(TAG, "get:onComplete:success");
|
||||
WritableMap data = FirestoreSerialize.snapshotToWritableMap(task.getResult());
|
||||
promise.resolve(data);
|
||||
} else {
|
||||
Log.e(TAG, "get:onComplete:failure", task.getException());
|
||||
RNFirebaseFirestore.promiseRejectException(promise, (FirebaseFirestoreException)task.getException());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void offSnapshot(final String listenerId) {
|
||||
ListenerRegistration listenerRegistration = collectionSnapshotListeners.remove(listenerId);
|
||||
if (listenerRegistration != null) {
|
||||
listenerRegistration.remove();
|
||||
}
|
||||
}
|
||||
|
||||
public void onSnapshot(final String listenerId) {
|
||||
if (!collectionSnapshotListeners.containsKey(listenerId)) {
|
||||
final EventListener<QuerySnapshot> listener = new EventListener<QuerySnapshot>() {
|
||||
@Override
|
||||
public void onEvent(QuerySnapshot querySnapshot, FirebaseFirestoreException exception) {
|
||||
if (exception == null) {
|
||||
handleQuerySnapshotEvent(listenerId, querySnapshot);
|
||||
} else {
|
||||
ListenerRegistration listenerRegistration = collectionSnapshotListeners.remove(listenerId);
|
||||
if (listenerRegistration != null) {
|
||||
listenerRegistration.remove();
|
||||
}
|
||||
handleQuerySnapshotError(listenerId, exception);
|
||||
}
|
||||
}
|
||||
};
|
||||
ListenerRegistration listenerRegistration = this.query.addSnapshotListener(listener);
|
||||
collectionSnapshotListeners.put(listenerId, listenerRegistration);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* INTERNALS/UTILS
|
||||
*/
|
||||
|
||||
boolean hasListeners() {
|
||||
return !collectionSnapshotListeners.isEmpty();
|
||||
}
|
||||
|
||||
private Query buildQuery() {
|
||||
Query query = RNFirebaseFirestore.getFirestoreForApp(appName).collection(path);
|
||||
query = applyFilters(query);
|
||||
query = applyOrders(query);
|
||||
query = applyOptions(query);
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
private Query applyFilters(Query query) {
|
||||
List<Object> filtersList = Utils.recursivelyDeconstructReadableArray(filters);
|
||||
|
||||
for (Object f : filtersList) {
|
||||
Map<String, Object> filter = (Map) f;
|
||||
String fieldPath = (String) filter.get("fieldPath");
|
||||
String operator = (String) filter.get("operator");
|
||||
Object value = filter.get("value");
|
||||
|
||||
switch (operator) {
|
||||
case "EQUAL":
|
||||
query = query.whereEqualTo(fieldPath, value);
|
||||
break;
|
||||
case "GREATER_THAN":
|
||||
query = query.whereGreaterThan(fieldPath, value);
|
||||
break;
|
||||
case "GREATER_THAN_OR_EQUAL":
|
||||
query = query.whereGreaterThanOrEqualTo(fieldPath, value);
|
||||
break;
|
||||
case "LESS_THAN":
|
||||
query = query.whereLessThan(fieldPath, value);
|
||||
break;
|
||||
case "LESS_THAN_OR_EQUAL":
|
||||
query = query.whereLessThanOrEqualTo(fieldPath, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return query;
|
||||
}
|
||||
|
||||
private Query applyOrders(Query query) {
|
||||
List<Object> ordersList = Utils.recursivelyDeconstructReadableArray(orders);
|
||||
for (Object o : ordersList) {
|
||||
Map<String, Object> order = (Map) o;
|
||||
String direction = (String) order.get("direction");
|
||||
String fieldPath = (String) order.get("fieldPath");
|
||||
|
||||
query = query.orderBy(fieldPath, Query.Direction.valueOf(direction));
|
||||
}
|
||||
return query;
|
||||
}
|
||||
|
||||
private Query applyOptions(Query query) {
|
||||
if (options.hasKey("endAt")) {
|
||||
ReadableArray endAtArray = options.getArray("endAt");
|
||||
query = query.endAt(Utils.recursivelyDeconstructReadableArray(endAtArray));
|
||||
}
|
||||
if (options.hasKey("endBefore")) {
|
||||
ReadableArray endBeforeArray = options.getArray("endBefore");
|
||||
query = query.endBefore(Utils.recursivelyDeconstructReadableArray(endBeforeArray));
|
||||
}
|
||||
if (options.hasKey("limit")) {
|
||||
int limit = options.getInt("limit");
|
||||
query = query.limit(limit);
|
||||
}
|
||||
if (options.hasKey("offset")) {
|
||||
// Android doesn't support offset
|
||||
}
|
||||
if (options.hasKey("selectFields")) {
|
||||
// Android doesn't support selectFields
|
||||
}
|
||||
if (options.hasKey("startAfter")) {
|
||||
ReadableArray startAfterArray = options.getArray("startAfter");
|
||||
query = query.startAfter(Utils.recursivelyDeconstructReadableArray(startAfterArray));
|
||||
}
|
||||
if (options.hasKey("startAt")) {
|
||||
ReadableArray startAtArray = options.getArray("startAt");
|
||||
query = query.startAt(Utils.recursivelyDeconstructReadableArray(startAtArray));
|
||||
}
|
||||
return query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles documentSnapshot events.
|
||||
*
|
||||
* @param listenerId
|
||||
* @param querySnapshot
|
||||
*/
|
||||
private void handleQuerySnapshotEvent(String listenerId, QuerySnapshot querySnapshot) {
|
||||
WritableMap event = Arguments.createMap();
|
||||
WritableMap data = FirestoreSerialize.snapshotToWritableMap(querySnapshot);
|
||||
|
||||
event.putString("appName", appName);
|
||||
event.putString("path", path);
|
||||
event.putString("listenerId", listenerId);
|
||||
event.putMap("querySnapshot", data);
|
||||
|
||||
Utils.sendEvent(reactContext, "firestore_collection_sync_event", event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a documentSnapshot error event
|
||||
*
|
||||
* @param listenerId
|
||||
* @param exception
|
||||
*/
|
||||
private void handleQuerySnapshotError(String listenerId, FirebaseFirestoreException exception) {
|
||||
WritableMap event = Arguments.createMap();
|
||||
|
||||
event.putString("appName", appName);
|
||||
event.putString("path", path);
|
||||
event.putString("listenerId", listenerId);
|
||||
event.putMap("error", RNFirebaseFirestore.getJSError(exception));
|
||||
|
||||
Utils.sendEvent(reactContext, "firestore_collection_sync_event", event);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,190 @@
|
||||
package io.invertase.firebase.firestore;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.util.Log;
|
||||
|
||||
import com.facebook.react.bridge.Arguments;
|
||||
import com.facebook.react.bridge.Promise;
|
||||
import com.facebook.react.bridge.ReactContext;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.bridge.WritableMap;
|
||||
import com.google.android.gms.tasks.OnCompleteListener;
|
||||
import com.google.android.gms.tasks.Task;
|
||||
import com.google.firebase.firestore.DocumentReference;
|
||||
import com.google.firebase.firestore.DocumentSnapshot;
|
||||
import com.google.firebase.firestore.EventListener;
|
||||
import com.google.firebase.firestore.FirebaseFirestoreException;
|
||||
import com.google.firebase.firestore.ListenerRegistration;
|
||||
import com.google.firebase.firestore.SetOptions;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import io.invertase.firebase.Utils;
|
||||
|
||||
|
||||
public class RNFirebaseFirestoreDocumentReference {
|
||||
private static final String TAG = "RNFBFSDocumentReference";
|
||||
private static Map<String, ListenerRegistration> documentSnapshotListeners = new HashMap<>();
|
||||
|
||||
private final String appName;
|
||||
private final String path;
|
||||
private ReactContext reactContext;
|
||||
private final DocumentReference ref;
|
||||
|
||||
RNFirebaseFirestoreDocumentReference(ReactContext reactContext, String appName, String path) {
|
||||
this.appName = appName;
|
||||
this.path = path;
|
||||
this.reactContext = reactContext;
|
||||
this.ref = RNFirebaseFirestore.getFirestoreForApp(appName).document(path);
|
||||
}
|
||||
|
||||
public void collections(Promise promise) {
|
||||
// Not supported on Android
|
||||
}
|
||||
|
||||
public void create(ReadableMap data, Promise promise) {
|
||||
// Not supported on Android out of the box
|
||||
}
|
||||
|
||||
public void delete(final Promise promise) {
|
||||
this.ref.delete().addOnCompleteListener(new OnCompleteListener<Void>() {
|
||||
@Override
|
||||
public void onComplete(@NonNull Task<Void> task) {
|
||||
if (task.isSuccessful()) {
|
||||
Log.d(TAG, "delete:onComplete:success");
|
||||
promise.resolve(null);
|
||||
} else {
|
||||
Log.e(TAG, "delete:onComplete:failure", task.getException());
|
||||
RNFirebaseFirestore.promiseRejectException(promise, (FirebaseFirestoreException)task.getException());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void get(final Promise promise) {
|
||||
this.ref.get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
|
||||
@Override
|
||||
public void onComplete(@NonNull Task<DocumentSnapshot> task) {
|
||||
if (task.isSuccessful()) {
|
||||
Log.d(TAG, "get:onComplete:success");
|
||||
WritableMap data = FirestoreSerialize.snapshotToWritableMap(task.getResult());
|
||||
promise.resolve(data);
|
||||
} else {
|
||||
Log.e(TAG, "get:onComplete:failure", task.getException());
|
||||
RNFirebaseFirestore.promiseRejectException(promise, (FirebaseFirestoreException)task.getException());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void offSnapshot(final String listenerId) {
|
||||
ListenerRegistration listenerRegistration = documentSnapshotListeners.remove(listenerId);
|
||||
if (listenerRegistration != null) {
|
||||
listenerRegistration.remove();
|
||||
}
|
||||
}
|
||||
|
||||
public void onSnapshot(final String listenerId) {
|
||||
if (!documentSnapshotListeners.containsKey(listenerId)) {
|
||||
final EventListener<DocumentSnapshot> listener = new EventListener<DocumentSnapshot>() {
|
||||
@Override
|
||||
public void onEvent(DocumentSnapshot documentSnapshot, FirebaseFirestoreException exception) {
|
||||
if (exception == null) {
|
||||
handleDocumentSnapshotEvent(listenerId, documentSnapshot);
|
||||
} else {
|
||||
ListenerRegistration listenerRegistration = documentSnapshotListeners.remove(listenerId);
|
||||
if (listenerRegistration != null) {
|
||||
listenerRegistration.remove();
|
||||
}
|
||||
handleDocumentSnapshotError(listenerId, exception);
|
||||
}
|
||||
}
|
||||
};
|
||||
ListenerRegistration listenerRegistration = this.ref.addSnapshotListener(listener);
|
||||
documentSnapshotListeners.put(listenerId, listenerRegistration);
|
||||
}
|
||||
}
|
||||
|
||||
public void set(final ReadableMap data, final ReadableMap options, final Promise promise) {
|
||||
Map<String, Object> map = Utils.recursivelyDeconstructReadableMap(data);
|
||||
Task<Void> task;
|
||||
SetOptions setOptions = null;
|
||||
if (options != null && options.hasKey("merge") && options.getBoolean("merge")) {
|
||||
task = this.ref.set(map, SetOptions.merge());
|
||||
} else {
|
||||
task = this.ref.set(map);
|
||||
}
|
||||
task.addOnCompleteListener(new OnCompleteListener<Void>() {
|
||||
@Override
|
||||
public void onComplete(@NonNull Task<Void> task) {
|
||||
if (task.isSuccessful()) {
|
||||
Log.d(TAG, "set:onComplete:success");
|
||||
promise.resolve(null);
|
||||
} else {
|
||||
Log.e(TAG, "set:onComplete:failure", task.getException());
|
||||
RNFirebaseFirestore.promiseRejectException(promise, (FirebaseFirestoreException)task.getException());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void update(final ReadableMap data, final Promise promise) {
|
||||
Map<String, Object> map = Utils.recursivelyDeconstructReadableMap(data);
|
||||
this.ref.update(map).addOnCompleteListener(new OnCompleteListener<Void>() {
|
||||
@Override
|
||||
public void onComplete(@NonNull Task<Void> task) {
|
||||
if (task.isSuccessful()) {
|
||||
Log.d(TAG, "update:onComplete:success");
|
||||
promise.resolve(null);
|
||||
} else {
|
||||
Log.e(TAG, "update:onComplete:failure", task.getException());
|
||||
RNFirebaseFirestore.promiseRejectException(promise, (FirebaseFirestoreException)task.getException());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* INTERNALS/UTILS
|
||||
*/
|
||||
|
||||
boolean hasListeners() {
|
||||
return !documentSnapshotListeners.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles documentSnapshot events.
|
||||
*
|
||||
* @param listenerId
|
||||
* @param documentSnapshot
|
||||
*/
|
||||
private void handleDocumentSnapshotEvent(String listenerId, DocumentSnapshot documentSnapshot) {
|
||||
WritableMap event = Arguments.createMap();
|
||||
WritableMap data = FirestoreSerialize.snapshotToWritableMap(documentSnapshot);
|
||||
|
||||
event.putString("appName", appName);
|
||||
event.putString("path", path);
|
||||
event.putString("listenerId", listenerId);
|
||||
event.putMap("documentSnapshot", data);
|
||||
|
||||
Utils.sendEvent(reactContext, "firestore_document_sync_event", event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a documentSnapshot error event
|
||||
*
|
||||
* @param listenerId
|
||||
* @param exception
|
||||
*/
|
||||
private void handleDocumentSnapshotError(String listenerId, FirebaseFirestoreException exception) {
|
||||
WritableMap event = Arguments.createMap();
|
||||
|
||||
event.putString("appName", appName);
|
||||
event.putString("path", path);
|
||||
event.putString("listenerId", listenerId);
|
||||
event.putMap("error", RNFirebaseFirestore.getJSError(exception));
|
||||
|
||||
Utils.sendEvent(reactContext, "firestore_document_sync_event", event);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package io.invertase.firebase.firestore;
|
||||
|
||||
import com.facebook.react.ReactPackage;
|
||||
import com.facebook.react.bridge.JavaScriptModule;
|
||||
import com.facebook.react.bridge.NativeModule;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.uimanager.UIManagerModule;
|
||||
import com.facebook.react.uimanager.ViewManager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class RNFirebaseFirestorePackage implements ReactPackage {
|
||||
public RNFirebaseFirestorePackage() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param reactContext react application context that can be used to create modules
|
||||
* @return list of native modules to register with the newly created catalyst instance
|
||||
*/
|
||||
@Override
|
||||
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
|
||||
List<NativeModule> modules = new ArrayList<>();
|
||||
modules.add(new RNFirebaseFirestore(reactContext));
|
||||
|
||||
return modules;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param reactContext
|
||||
* @return a list of view managers that should be registered with {@link UIManagerModule}
|
||||
*/
|
||||
@Override
|
||||
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
@@ -28,18 +28,6 @@ public class RNFirebaseMessagingPackage implements ReactPackage {
|
||||
return modules;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list of JS modules to register with the newly created catalyst instance.
|
||||
* <p/>
|
||||
* IMPORTANT: Note that only modules that needs to be accessible from the native code should be
|
||||
* listed here. Also listing a native module here doesn't imply that the JS implementation of it
|
||||
* will be automatically included in the JS bundle.
|
||||
*/
|
||||
// TODO: Removed in 0.47.0. Here for backwards compatability
|
||||
public List<Class<? extends JavaScriptModule>> createJSModules() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param reactContext
|
||||
* @return a list of view managers that should be registered with {@link UIManagerModule}
|
||||
|
||||
@@ -28,18 +28,6 @@ public class RNFirebasePerformancePackage implements ReactPackage {
|
||||
return modules;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list of JS modules to register with the newly created catalyst instance.
|
||||
* <p/>
|
||||
* IMPORTANT: Note that only modules that needs to be accessible from the native code should be
|
||||
* listed here. Also listing a native module here doesn't imply that the JS implementation of it
|
||||
* will be automatically included in the JS bundle.
|
||||
*/
|
||||
// TODO: Removed in 0.47.0. Here for backwards compatability
|
||||
public List<Class<? extends JavaScriptModule>> createJSModules() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param reactContext
|
||||
* @return a list of view managers that should be registered with {@link UIManagerModule}
|
||||
|
||||
@@ -33,18 +33,6 @@ public class RNFirebaseStoragePackage implements ReactPackage {
|
||||
return modules;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list of JS modules to register with the newly created catalyst instance.
|
||||
* <p/>
|
||||
* IMPORTANT: Note that only modules that needs to be accessible from the native code should be
|
||||
* listed here. Also listing a native module here doesn't imply that the JS implementation of it
|
||||
* will be automatically included in the JS bundle.
|
||||
*/
|
||||
// TODO: Removed in 0.47.0. Here for backwards compatibility
|
||||
public List<Class<? extends JavaScriptModule>> createJSModules() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param reactContext
|
||||
* @return a list of view managers that should be registered with {@link UIManagerModule}
|
||||
|
||||
Reference in New Issue
Block a user