mirror of
https://github.com/zhigang1992/react-native-firebase.git
synced 2026-01-12 22:50:20 +08:00
[firestore][android] re-write serialize class and add support for NaN & Infinity numbers
This commit is contained in:
@@ -18,6 +18,7 @@ import com.google.firebase.firestore.FieldValue;
|
||||
import com.google.firebase.firestore.FirebaseFirestore;
|
||||
import com.google.firebase.firestore.GeoPoint;
|
||||
import com.google.firebase.firestore.QuerySnapshot;
|
||||
import com.google.firebase.firestore.SnapshotMetadata;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
@@ -25,19 +26,53 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import io.invertase.firebase.Utils;
|
||||
|
||||
public class FirestoreSerialize {
|
||||
class FirestoreSerialize {
|
||||
private static final String TAG = "FirestoreSerialize";
|
||||
private static final String KEY_CHANGES = "changes";
|
||||
|
||||
// Keys
|
||||
private static final String TYPE = "type";
|
||||
private static final String VALUE = "value";
|
||||
private static final String KEY_DATA = "data";
|
||||
private static final String KEY_PATH = "path";
|
||||
private static final String KEY_META = "metadata";
|
||||
private static final String KEY_CHANGES = "changes";
|
||||
private static final String KEY_OPTIONS = "options";
|
||||
private static final String KEY_LATITUDE = "latitude";
|
||||
private static final String KEY_LONGITUDE = "longitude";
|
||||
private static final String KEY_DOCUMENTS = "documents";
|
||||
private static final String KEY_DOC_CHANGE_TYPE = "type";
|
||||
private static final String KEY_META_FROM_CACHE = "fromCache";
|
||||
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";
|
||||
private static final String KEY_META_HAS_PENDING_WRITES = "hasPendingWrites";
|
||||
|
||||
// Types
|
||||
private static final String TYPE_NAN = "nan";
|
||||
private static final String TYPE_NULL = "null";
|
||||
private static final String TYPE_BLOB = "blob";
|
||||
private static final String TYPE_DATE = "date";
|
||||
private static final String TYPE_ARRAY = "array";
|
||||
private static final String TYPE_STRING = "string";
|
||||
private static final String TYPE_NUMBER = "number";
|
||||
private static final String TYPE_OBJECT = "object";
|
||||
private static final String TYPE_BOOLEAN = "boolean";
|
||||
private static final String TYPE_GEOPOINT = "geopoint";
|
||||
private static final String TYPE_INFINITY = "infinity";
|
||||
private static final String TYPE_REFERENCE = "reference";
|
||||
private static final String TYPE_DOCUMENTID = "documentid";
|
||||
private static final String TYPE_FIELDVALUE = "fieldvalue";
|
||||
private static final String TYPE_FIELDVALUE_DELETE = "delete";
|
||||
private static final String TYPE_FIELDVALUE_TIMESTAMP = "timestamp";
|
||||
|
||||
// Document Change Types
|
||||
private static final String CHANGE_ADDED = "added";
|
||||
private static final String CHANGE_MODIFIED = "modified";
|
||||
private static final String CHANGE_REMOVED = "removed";
|
||||
|
||||
/**
|
||||
* Convert a DocumentSnapshot instance into a React Native WritableMap
|
||||
@@ -46,67 +81,59 @@ public class FirestoreSerialize {
|
||||
* @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
|
||||
WritableMap metadata = Arguments.createMap();
|
||||
metadata.putBoolean(
|
||||
"fromCache",
|
||||
documentSnapshot
|
||||
.getMetadata()
|
||||
.isFromCache()
|
||||
);
|
||||
metadata.putBoolean(
|
||||
"hasPendingWrites",
|
||||
documentSnapshot
|
||||
.getMetadata()
|
||||
.hasPendingWrites()
|
||||
);
|
||||
documentMap.putMap(KEY_METADATA, metadata);
|
||||
WritableMap documentMap = Arguments.createMap();
|
||||
SnapshotMetadata snapshotMetadata = documentSnapshot.getMetadata();
|
||||
|
||||
// build metadata
|
||||
metadata.putBoolean(KEY_META_FROM_CACHE, snapshotMetadata.isFromCache());
|
||||
metadata.putBoolean(KEY_META_HAS_PENDING_WRITES, snapshotMetadata.hasPendingWrites());
|
||||
|
||||
documentMap.putMap(KEY_META, metadata);
|
||||
documentMap.putString(KEY_PATH, documentSnapshot.getReference().getPath());
|
||||
if (documentSnapshot.exists())
|
||||
documentMap.putMap(KEY_DATA, objectMapToWritable(documentSnapshot.getData()));
|
||||
|
||||
return documentMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a Firestore QuerySnapshot instance to a RN serializable WritableMap type map
|
||||
*
|
||||
* @param querySnapshot QuerySnapshot
|
||||
* @return WritableMap
|
||||
*/
|
||||
static WritableMap snapshotToWritableMap(QuerySnapshot querySnapshot) {
|
||||
WritableMap queryMap = Arguments.createMap();
|
||||
|
||||
List<DocumentChange> documentChanges = querySnapshot.getDocumentChanges();
|
||||
queryMap.putArray(KEY_CHANGES, documentChangesToWritableArray(documentChanges));
|
||||
|
||||
// documents
|
||||
WritableMap metadata = Arguments.createMap();
|
||||
WritableMap writableMap = Arguments.createMap();
|
||||
WritableArray documents = Arguments.createArray();
|
||||
|
||||
SnapshotMetadata snapshotMetadata = querySnapshot.getMetadata();
|
||||
List<DocumentSnapshot> documentSnapshots = querySnapshot.getDocuments();
|
||||
List<DocumentChange> documentChanges = querySnapshot.getDocumentChanges();
|
||||
|
||||
// convert documents documents
|
||||
for (DocumentSnapshot documentSnapshot : documentSnapshots) {
|
||||
documents.pushMap(snapshotToWritableMap(documentSnapshot));
|
||||
}
|
||||
queryMap.putArray(KEY_DOCUMENTS, documents);
|
||||
|
||||
// metadata
|
||||
WritableMap metadata = Arguments.createMap();
|
||||
metadata.putBoolean(
|
||||
"fromCache",
|
||||
querySnapshot
|
||||
.getMetadata()
|
||||
.isFromCache()
|
||||
);
|
||||
metadata.putBoolean(
|
||||
"hasPendingWrites",
|
||||
querySnapshot
|
||||
.getMetadata()
|
||||
.hasPendingWrites()
|
||||
);
|
||||
queryMap.putMap(KEY_METADATA, metadata);
|
||||
// build metadata
|
||||
metadata.putBoolean(KEY_META_FROM_CACHE, snapshotMetadata.isFromCache());
|
||||
metadata.putBoolean(KEY_META_HAS_PENDING_WRITES, snapshotMetadata.hasPendingWrites());
|
||||
|
||||
return queryMap;
|
||||
// set metadata
|
||||
writableMap.putMap(KEY_META, metadata);
|
||||
|
||||
// set documents
|
||||
writableMap.putArray(KEY_DOCUMENTS, documents);
|
||||
|
||||
// set document changes
|
||||
writableMap.putArray(
|
||||
KEY_CHANGES,
|
||||
documentChangesToWritableArray(documentChanges)
|
||||
);
|
||||
|
||||
return writableMap;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -117,9 +144,11 @@ public class FirestoreSerialize {
|
||||
*/
|
||||
private static WritableArray documentChangesToWritableArray(List<DocumentChange> documentChanges) {
|
||||
WritableArray documentChangesWritable = Arguments.createArray();
|
||||
|
||||
for (DocumentChange documentChange : documentChanges) {
|
||||
documentChangesWritable.pushMap(documentChangeToWritableMap(documentChange));
|
||||
}
|
||||
|
||||
return documentChangesWritable;
|
||||
}
|
||||
|
||||
@@ -134,19 +163,21 @@ public class FirestoreSerialize {
|
||||
|
||||
switch (documentChange.getType()) {
|
||||
case ADDED:
|
||||
documentChangeMap.putString(KEY_DOC_CHANGE_TYPE, "added");
|
||||
break;
|
||||
case REMOVED:
|
||||
documentChangeMap.putString(KEY_DOC_CHANGE_TYPE, "removed");
|
||||
documentChangeMap.putString(KEY_DOC_CHANGE_TYPE, CHANGE_ADDED);
|
||||
break;
|
||||
case MODIFIED:
|
||||
documentChangeMap.putString(KEY_DOC_CHANGE_TYPE, "modified");
|
||||
documentChangeMap.putString(KEY_DOC_CHANGE_TYPE, CHANGE_MODIFIED);
|
||||
break;
|
||||
case REMOVED:
|
||||
documentChangeMap.putString(KEY_DOC_CHANGE_TYPE, CHANGE_REMOVED);
|
||||
break;
|
||||
}
|
||||
|
||||
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());
|
||||
|
||||
@@ -161,15 +192,17 @@ public class FirestoreSerialize {
|
||||
*/
|
||||
private static WritableMap objectMapToWritable(Map<String, Object> map) {
|
||||
WritableMap writableMap = Arguments.createMap();
|
||||
|
||||
for (Map.Entry<String, Object> entry : map.entrySet()) {
|
||||
WritableMap typeMap = buildTypeMap(entry.getValue());
|
||||
writableMap.putMap(entry.getKey(), typeMap);
|
||||
}
|
||||
|
||||
return writableMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an Object array into a React Native WritableArray.
|
||||
* Converts a Object array into a React Native WritableArray.
|
||||
*
|
||||
* @param array Object[]
|
||||
* @return WritableArray
|
||||
@@ -186,155 +219,285 @@ public class FirestoreSerialize {
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects an objects type and creates a Map to represent the type and value.
|
||||
* Convert an Object to a type map for use in JS land to convert to JS equivalent.
|
||||
*
|
||||
* @param value Object
|
||||
* @return WritableMap
|
||||
*/
|
||||
private static WritableMap buildTypeMap(Object value) {
|
||||
WritableMap typeMap = Arguments.createMap();
|
||||
|
||||
if (value == null) {
|
||||
typeMap.putString("type", "null");
|
||||
typeMap.putNull("value");
|
||||
} else {
|
||||
if (value instanceof Boolean) {
|
||||
typeMap.putString("type", "boolean");
|
||||
typeMap.putBoolean("value", (Boolean) value);
|
||||
} else if (value instanceof Integer) {
|
||||
typeMap.putString("type", "number");
|
||||
typeMap.putDouble("value", ((Integer) value).doubleValue());
|
||||
} else if (value instanceof Long) {
|
||||
typeMap.putString("type", "number");
|
||||
typeMap.putDouble("value", ((Long) value).doubleValue());
|
||||
} else if (value instanceof Double) {
|
||||
typeMap.putString("type", "number");
|
||||
typeMap.putDouble("value", (Double) value);
|
||||
} else if (value instanceof Float) {
|
||||
typeMap.putString("type", "number");
|
||||
typeMap.putDouble("value", ((Float) value).doubleValue());
|
||||
} else if (value instanceof String) {
|
||||
typeMap.putString("type", "string");
|
||||
typeMap.putString("value", (String) value);
|
||||
} else if (Map.class.isAssignableFrom(value.getClass())) {
|
||||
typeMap.putString("type", "object");
|
||||
typeMap.putMap("value", objectMapToWritable((Map<String, Object>) value));
|
||||
} else if (List.class.isAssignableFrom(value.getClass())) {
|
||||
typeMap.putString("type", "array");
|
||||
List<Object> list = (List<Object>) value;
|
||||
Object[] array = list.toArray(new Object[list.size()]);
|
||||
typeMap.putArray("value", objectArrayToWritable(array));
|
||||
} else if (value instanceof DocumentReference) {
|
||||
typeMap.putString("type", "reference");
|
||||
typeMap.putString("value", ((DocumentReference) value).getPath());
|
||||
} else if (value instanceof GeoPoint) {
|
||||
typeMap.putString("type", "geopoint");
|
||||
WritableMap geoPoint = Arguments.createMap();
|
||||
geoPoint.putDouble("latitude", ((GeoPoint) value).getLatitude());
|
||||
geoPoint.putDouble("longitude", ((GeoPoint) value).getLongitude());
|
||||
typeMap.putMap("value", geoPoint);
|
||||
} else if (value instanceof Date) {
|
||||
typeMap.putString("type", "date");
|
||||
typeMap.putDouble("value", ((Date) value).getTime());
|
||||
} else if (value instanceof Blob) {
|
||||
typeMap.putString("type", "blob");
|
||||
typeMap.putString("value", Base64.encodeToString(((Blob) value).toBytes(), Base64.NO_WRAP));
|
||||
} else {
|
||||
Log.e(TAG, "buildTypeMap: Cannot convert object of type " + value.getClass());
|
||||
typeMap.putString("type", "null");
|
||||
typeMap.putNull("value");
|
||||
}
|
||||
typeMap.putString(TYPE, TYPE_NULL);
|
||||
typeMap.putNull(VALUE);
|
||||
return typeMap;
|
||||
}
|
||||
|
||||
if (value instanceof Boolean) {
|
||||
typeMap.putString(TYPE, TYPE_BOOLEAN);
|
||||
typeMap.putBoolean(VALUE, (Boolean) value);
|
||||
return typeMap;
|
||||
}
|
||||
|
||||
if (value instanceof Integer) {
|
||||
typeMap.putString(TYPE, TYPE_NUMBER);
|
||||
typeMap.putDouble(VALUE, ((Integer) value).doubleValue());
|
||||
return typeMap;
|
||||
}
|
||||
|
||||
if (value instanceof Double) {
|
||||
Double doubleValue = (Double) value;
|
||||
|
||||
if (Double.isInfinite(doubleValue)) {
|
||||
typeMap.putString(TYPE, TYPE_INFINITY);
|
||||
return typeMap;
|
||||
}
|
||||
|
||||
if (Double.isNaN(doubleValue)) {
|
||||
typeMap.putString(TYPE, TYPE_NAN);
|
||||
return typeMap;
|
||||
}
|
||||
|
||||
typeMap.putString(TYPE, TYPE_NUMBER);
|
||||
typeMap.putDouble(VALUE, doubleValue);
|
||||
return typeMap;
|
||||
}
|
||||
|
||||
if (value instanceof Float) {
|
||||
typeMap.putString(TYPE, TYPE_NUMBER);
|
||||
typeMap.putDouble(VALUE, ((Float) value).doubleValue());
|
||||
return typeMap;
|
||||
}
|
||||
|
||||
if (value instanceof Long) {
|
||||
typeMap.putString(TYPE, TYPE_NUMBER);
|
||||
typeMap.putDouble(VALUE, ((Long) value).doubleValue());
|
||||
return typeMap;
|
||||
}
|
||||
|
||||
if (value instanceof String) {
|
||||
typeMap.putString(TYPE, TYPE_STRING);
|
||||
typeMap.putString(VALUE, (String) value);
|
||||
return typeMap;
|
||||
}
|
||||
|
||||
if (value instanceof Date) {
|
||||
typeMap.putString(TYPE, TYPE_DATE);
|
||||
typeMap.putDouble(VALUE, ((Date) value).getTime());
|
||||
return typeMap;
|
||||
}
|
||||
|
||||
if (Map.class.isAssignableFrom(value.getClass())) {
|
||||
typeMap.putString(TYPE, TYPE_OBJECT);
|
||||
typeMap.putMap(VALUE, objectMapToWritable((Map<String, Object>) value));
|
||||
return typeMap;
|
||||
}
|
||||
|
||||
if (List.class.isAssignableFrom(value.getClass())) {
|
||||
typeMap.putString(TYPE, TYPE_ARRAY);
|
||||
List<Object> list = (List<Object>) value;
|
||||
Object[] array = list.toArray(new Object[list.size()]);
|
||||
typeMap.putArray(VALUE, objectArrayToWritable(array));
|
||||
return typeMap;
|
||||
}
|
||||
|
||||
if (value instanceof DocumentReference) {
|
||||
typeMap.putString(TYPE, TYPE_REFERENCE);
|
||||
typeMap.putString(VALUE, ((DocumentReference) value).getPath());
|
||||
return typeMap;
|
||||
}
|
||||
|
||||
if (value instanceof GeoPoint) {
|
||||
WritableMap geoPoint = Arguments.createMap();
|
||||
|
||||
geoPoint.putDouble(KEY_LATITUDE, ((GeoPoint) value).getLatitude());
|
||||
geoPoint.putDouble(KEY_LONGITUDE, ((GeoPoint) value).getLongitude());
|
||||
|
||||
typeMap.putMap(VALUE, geoPoint);
|
||||
typeMap.putString(TYPE, TYPE_GEOPOINT);
|
||||
|
||||
return typeMap;
|
||||
}
|
||||
|
||||
if (value instanceof Blob) {
|
||||
typeMap.putString(TYPE, TYPE_BLOB);
|
||||
typeMap.putString(VALUE, Base64.encodeToString(((Blob) value).toBytes(), Base64.NO_WRAP));
|
||||
return typeMap;
|
||||
}
|
||||
|
||||
Log.w(TAG, "Unknown object of type " + value.getClass());
|
||||
typeMap.putString(TYPE, TYPE_NULL);
|
||||
typeMap.putNull(VALUE);
|
||||
return typeMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a ReadableMap to a usable format for Firestore
|
||||
*
|
||||
* @param firestore FirebaseFirestore
|
||||
* @param readableMap ReadableMap
|
||||
* @return Map<>
|
||||
*/
|
||||
static Map<String, Object> parseReadableMap(
|
||||
FirebaseFirestore firestore,
|
||||
ReadableMap readableMap
|
||||
@Nullable ReadableMap readableMap
|
||||
) {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
if (readableMap != null) {
|
||||
ReadableMapKeySetIterator iterator = readableMap.keySetIterator();
|
||||
while (iterator.hasNextKey()) {
|
||||
String key = iterator.nextKey();
|
||||
map.put(key, parseTypeMap(firestore, readableMap.getMap(key)));
|
||||
}
|
||||
if (readableMap == null) return map;
|
||||
|
||||
ReadableMapKeySetIterator iterator = readableMap.keySetIterator();
|
||||
while (iterator.hasNextKey()) {
|
||||
String key = iterator.nextKey();
|
||||
map.put(key, parseTypeMap(firestore, readableMap.getMap(key)));
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
static List<Object> parseReadableArray(FirebaseFirestore firestore, ReadableArray readableArray) {
|
||||
/**
|
||||
* Convert a RN array to a valid Firestore array
|
||||
*
|
||||
* @param firestore FirebaseFirestore
|
||||
* @param readableArray ReadableArray
|
||||
* @return List<Object>
|
||||
*/
|
||||
static List<Object> parseReadableArray(
|
||||
FirebaseFirestore firestore,
|
||||
@Nullable ReadableArray readableArray
|
||||
) {
|
||||
List<Object> list = new ArrayList<>();
|
||||
if (readableArray != null) {
|
||||
for (int i = 0; i < readableArray.size(); i++) {
|
||||
list.add(parseTypeMap(firestore, readableArray.getMap(i)));
|
||||
}
|
||||
if (readableArray == null) return list;
|
||||
|
||||
for (int i = 0; i < readableArray.size(); i++) {
|
||||
list.add(parseTypeMap(firestore, readableArray.getMap(i)));
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a JS type to a Firestore type
|
||||
*
|
||||
* @param firestore FirebaseFirestore
|
||||
* @param typeMap ReadableMap
|
||||
* @return Object
|
||||
*/
|
||||
static Object parseTypeMap(FirebaseFirestore firestore, ReadableMap typeMap) {
|
||||
String type = typeMap.getString("type");
|
||||
if ("boolean".equals(type)) {
|
||||
return typeMap.getBoolean("value");
|
||||
} else if ("number".equals(type)) {
|
||||
return typeMap.getDouble("value");
|
||||
} else if ("string".equals(type)) {
|
||||
return typeMap.getString("value");
|
||||
} else if ("null".equals(type)) {
|
||||
return null;
|
||||
} else if ("array".equals(type)) {
|
||||
return parseReadableArray(firestore, typeMap.getArray("value"));
|
||||
} else if ("object".equals(type)) {
|
||||
return parseReadableMap(firestore, typeMap.getMap("value"));
|
||||
} else if ("reference".equals(type)) {
|
||||
String path = typeMap.getString("value");
|
||||
return firestore.document(path);
|
||||
} else if ("geopoint".equals(type)) {
|
||||
ReadableMap geoPoint = typeMap.getMap("value");
|
||||
return new GeoPoint(geoPoint.getDouble("latitude"), geoPoint.getDouble("longitude"));
|
||||
} else if ("blob".equals(type)) {
|
||||
String base64String = typeMap.getString("value");
|
||||
return Blob.fromBytes(Base64.decode(base64String, Base64.NO_WRAP));
|
||||
} else if ("date".equals(type)) {
|
||||
Double time = typeMap.getDouble("value");
|
||||
return new Date(time.longValue());
|
||||
} else if ("documentid".equals(type)) {
|
||||
return FieldPath.documentId();
|
||||
} else if ("fieldvalue".equals(type)) {
|
||||
String value = typeMap.getString("value");
|
||||
if ("delete".equals(value)) {
|
||||
return FieldValue.delete();
|
||||
} else if ("timestamp".equals(value)) {
|
||||
return FieldValue.serverTimestamp();
|
||||
} else {
|
||||
Log.e(TAG, "parseTypeMap: Invalid fieldvalue: " + value);
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
Log.e(TAG, "parseTypeMap: Cannot convert object of type " + type);
|
||||
String type = typeMap.getString(TYPE);
|
||||
|
||||
if (TYPE_NULL.equals(type)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (TYPE_BOOLEAN.equals(type)) {
|
||||
return typeMap.getBoolean(VALUE);
|
||||
}
|
||||
|
||||
if (TYPE_NAN.equals(type)) {
|
||||
return Double.NaN;
|
||||
}
|
||||
|
||||
if (TYPE_NUMBER.equals(type)) {
|
||||
return typeMap.getDouble(VALUE);
|
||||
}
|
||||
|
||||
if (TYPE_INFINITY.equals(type)) {
|
||||
return Double.POSITIVE_INFINITY;
|
||||
}
|
||||
|
||||
if (TYPE_STRING.equals(type)) {
|
||||
return typeMap.getString(VALUE);
|
||||
}
|
||||
|
||||
if (TYPE_ARRAY.equals(type)) {
|
||||
return parseReadableArray(firestore, typeMap.getArray(VALUE));
|
||||
}
|
||||
|
||||
if (TYPE_OBJECT.equals(type)) {
|
||||
return parseReadableMap(firestore, typeMap.getMap(VALUE));
|
||||
}
|
||||
|
||||
if (TYPE_DATE.equals(type)) {
|
||||
Double time = typeMap.getDouble(VALUE);
|
||||
return new Date(time.longValue());
|
||||
}
|
||||
|
||||
/* --------------------------
|
||||
* Firestore Specific Types
|
||||
* -------------------------- */
|
||||
|
||||
if (TYPE_DOCUMENTID.equals(type)) {
|
||||
return FieldPath.documentId();
|
||||
}
|
||||
|
||||
if (TYPE_GEOPOINT.equals(type)) {
|
||||
ReadableMap geoPoint = typeMap.getMap(VALUE);
|
||||
return new GeoPoint(geoPoint.getDouble(KEY_LATITUDE), geoPoint.getDouble(KEY_LONGITUDE));
|
||||
}
|
||||
|
||||
if (TYPE_BLOB.equals(type)) {
|
||||
String base64String = typeMap.getString(VALUE);
|
||||
return Blob.fromBytes(Base64.decode(base64String, Base64.NO_WRAP));
|
||||
}
|
||||
|
||||
if (TYPE_REFERENCE.equals(type)) {
|
||||
String path = typeMap.getString(VALUE);
|
||||
return firestore.document(path);
|
||||
}
|
||||
|
||||
if (TYPE_FIELDVALUE.equals(type)) {
|
||||
String fieldValueType = typeMap.getString(VALUE);
|
||||
|
||||
if (TYPE_FIELDVALUE_TIMESTAMP.equals(fieldValueType)) {
|
||||
return FieldValue.serverTimestamp();
|
||||
}
|
||||
|
||||
if (TYPE_FIELDVALUE_DELETE.equals(fieldValueType)) {
|
||||
return FieldValue.delete();
|
||||
}
|
||||
|
||||
Log.w(TAG, "Unknown FieldValue type: " + fieldValueType);
|
||||
return null;
|
||||
}
|
||||
|
||||
Log.w(TAG, "Unknown object of type " + type);
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse JS batches array
|
||||
*
|
||||
* @param firestore FirebaseFirestore
|
||||
* @param readableArray ReadableArray
|
||||
* @return List<Object>
|
||||
*/
|
||||
static List<Object> parseDocumentBatches(
|
||||
FirebaseFirestore firestore,
|
||||
ReadableArray readableArray
|
||||
) {
|
||||
List<Object> writes = new ArrayList<>(readableArray.size());
|
||||
|
||||
for (int i = 0; i < readableArray.size(); i++) {
|
||||
Map<String, Object> write = new HashMap<>();
|
||||
ReadableMap map = readableArray.getMap(i);
|
||||
if (map.hasKey("data")) {
|
||||
write.put("data", parseReadableMap(firestore, map.getMap("data")));
|
||||
|
||||
write.put(TYPE, map.getString(TYPE));
|
||||
write.put(KEY_PATH, map.getString(KEY_PATH));
|
||||
|
||||
if (map.hasKey(KEY_DATA)) {
|
||||
write.put(KEY_DATA, parseReadableMap(firestore, map.getMap(KEY_DATA)));
|
||||
}
|
||||
if (map.hasKey("options")) {
|
||||
write.put("options", Utils.recursivelyDeconstructReadableMap(map.getMap("options")));
|
||||
|
||||
if (map.hasKey(KEY_OPTIONS)) {
|
||||
write.put(
|
||||
KEY_OPTIONS,
|
||||
Utils.recursivelyDeconstructReadableMap(map.getMap(KEY_OPTIONS))
|
||||
);
|
||||
}
|
||||
write.put("path", map.getString("path"));
|
||||
write.put("type", map.getString("type"));
|
||||
|
||||
writes.add(write);
|
||||
}
|
||||
|
||||
return writes;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,7 +103,6 @@ describe('firestore()', () => {
|
||||
unsubscribe();
|
||||
});
|
||||
|
||||
// crappy race condition somewhere =/ will come back to it later
|
||||
it('calls callback with the initial data and then when document is added', async () => {
|
||||
const colDoc = await resetTestCollectionDoc();
|
||||
await sleep(50);
|
||||
|
||||
Reference in New Issue
Block a user