[android] Add the first raft of Android support
This commit is contained in:
parent
dfd9080281
commit
52b70d58e3
|
@ -33,6 +33,10 @@ android {
|
||||||
allprojects {
|
allprojects {
|
||||||
repositories {
|
repositories {
|
||||||
jcenter()
|
jcenter()
|
||||||
|
mavenLocal()
|
||||||
|
maven {
|
||||||
|
url "https://maven.google.com"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,11 +82,12 @@ dependencies {
|
||||||
compile "com.google.android.gms:play-services-base:$firebaseVersion"
|
compile "com.google.android.gms:play-services-base:$firebaseVersion"
|
||||||
compile "com.google.firebase:firebase-core:$firebaseVersion"
|
compile "com.google.firebase:firebase-core:$firebaseVersion"
|
||||||
compile "com.google.firebase:firebase-config:$firebaseVersion"
|
compile "com.google.firebase:firebase-config:$firebaseVersion"
|
||||||
compile "com.google.firebase:firebase-auth:$firebaseVersion"
|
compile "com.google.firebase:firebase-auth:11.3.0"
|
||||||
compile "com.google.firebase:firebase-database:$firebaseVersion"
|
compile "com.google.firebase:firebase-database:$firebaseVersion"
|
||||||
compile "com.google.firebase:firebase-storage:$firebaseVersion"
|
compile "com.google.firebase:firebase-storage:$firebaseVersion"
|
||||||
compile "com.google.firebase:firebase-messaging:$firebaseVersion"
|
compile "com.google.firebase:firebase-messaging:$firebaseVersion"
|
||||||
compile "com.google.firebase:firebase-crash:$firebaseVersion"
|
compile "com.google.firebase:firebase-crash:$firebaseVersion"
|
||||||
compile "com.google.firebase:firebase-perf:$firebaseVersion"
|
compile "com.google.firebase:firebase-perf:$firebaseVersion"
|
||||||
compile "com.google.firebase:firebase-ads:$firebaseVersion"
|
compile "com.google.firebase:firebase-ads:$firebaseVersion"
|
||||||
|
compile 'com.google.firebase:firebase-firestore:11.3.0'
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,7 +78,6 @@ public class Utils {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param dataSnapshot
|
* @param dataSnapshot
|
||||||
* @param registration
|
|
||||||
* @param previousChildName
|
* @param previousChildName
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -0,0 +1,195 @@
|
||||||
|
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.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_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.getId());
|
||||||
|
documentMap.putMap(KEY_DATA, objectMapToWritable(documentSnapshot.getData()));
|
||||||
|
// Missing fields from web SDK
|
||||||
|
// createTime
|
||||||
|
// readTime
|
||||||
|
// updateTime
|
||||||
|
|
||||||
|
return documentMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static WritableMap snapshotToWritableMap(QuerySnapshot querySnapshot) {
|
||||||
|
WritableMap queryMap = Arguments.createMap();
|
||||||
|
|
||||||
|
List<DocumentChange> documentChanges = querySnapshot.getDocumentChanges();
|
||||||
|
if (!documentChanges.isEmpty()) {
|
||||||
|
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);
|
||||||
|
|
||||||
|
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()));
|
||||||
|
|
||||||
|
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) {
|
||||||
|
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) {
|
||||||
|
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,136 @@
|
||||||
|
package io.invertase.firebase.firestore;
|
||||||
|
|
||||||
|
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.facebook.react.bridge.Promise;
|
||||||
|
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.Query;
|
||||||
|
import com.google.firebase.firestore.QuerySnapshot;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import io.invertase.firebase.Utils;
|
||||||
|
|
||||||
|
public class RNFirebaseCollectionReference {
|
||||||
|
private static final String TAG = "RNFBCollectionReference";
|
||||||
|
private final String appName;
|
||||||
|
private final String path;
|
||||||
|
private final ReadableArray filters;
|
||||||
|
private final ReadableArray orders;
|
||||||
|
private final ReadableMap options;
|
||||||
|
private final Query query;
|
||||||
|
|
||||||
|
RNFirebaseCollectionReference(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();
|
||||||
|
}
|
||||||
|
|
||||||
|
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, task.getException());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private Query buildQuery() {
|
||||||
|
Query query = RNFirebaseFirestore.getFirestoreForApp(appName).collection(path);
|
||||||
|
query = applyFilters(query, filters);
|
||||||
|
query = applyOrders(query, orders);
|
||||||
|
query = applyOptions(query, options);
|
||||||
|
|
||||||
|
return query;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Query applyFilters(Query query, ReadableArray filters) {
|
||||||
|
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, ReadableArray orders) {
|
||||||
|
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, ReadableMap options) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,113 @@
|
||||||
|
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.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.SetOptions;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import io.invertase.firebase.Utils;
|
||||||
|
|
||||||
|
|
||||||
|
public class RNFirebaseDocumentReference {
|
||||||
|
private static final String TAG = "RNFBDocumentReference";
|
||||||
|
private final String appName;
|
||||||
|
private final String path;
|
||||||
|
private final DocumentReference ref;
|
||||||
|
|
||||||
|
RNFirebaseDocumentReference(String appName, String path) {
|
||||||
|
this.appName = appName;
|
||||||
|
this.path = path;
|
||||||
|
this.ref = RNFirebaseFirestore.getFirestoreForApp(appName).document(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void create(ReadableMap data, Promise promise) {
|
||||||
|
// Not supported on Android out of the box
|
||||||
|
}
|
||||||
|
|
||||||
|
public void delete(final ReadableMap options, 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");
|
||||||
|
// Missing fields from web SDK
|
||||||
|
// writeTime
|
||||||
|
promise.resolve(Arguments.createMap());
|
||||||
|
} else {
|
||||||
|
Log.e(TAG, "delete:onComplete:failure", task.getException());
|
||||||
|
RNFirebaseFirestore.promiseRejectException(promise, 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, task.getException());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void set(final ReadableMap data, final ReadableMap options, final Promise promise) {
|
||||||
|
Map<String, Object> map = Utils.recursivelyDeconstructReadableMap(data);
|
||||||
|
SetOptions setOptions = null;
|
||||||
|
if (options != null && options.hasKey("merge") && options.getBoolean("merge")) {
|
||||||
|
setOptions = SetOptions.merge();
|
||||||
|
}
|
||||||
|
this.ref.set(map, setOptions).addOnCompleteListener(new OnCompleteListener<Void>() {
|
||||||
|
@Override
|
||||||
|
public void onComplete(@NonNull Task<Void> task) {
|
||||||
|
if (task.isSuccessful()) {
|
||||||
|
Log.d(TAG, "set:onComplete:success");
|
||||||
|
// Missing fields from web SDK
|
||||||
|
// writeTime
|
||||||
|
promise.resolve(Arguments.createMap());
|
||||||
|
} else {
|
||||||
|
Log.e(TAG, "set:onComplete:failure", task.getException());
|
||||||
|
RNFirebaseFirestore.promiseRejectException(promise, task.getException());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update(final ReadableMap data, final ReadableMap options, 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");
|
||||||
|
// Missing fields from web SDK
|
||||||
|
// writeTime
|
||||||
|
promise.resolve(Arguments.createMap());
|
||||||
|
} else {
|
||||||
|
Log.e(TAG, "update:onComplete:failure", task.getException());
|
||||||
|
RNFirebaseFirestore.promiseRejectException(promise, task.getException());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void collections(Promise promise) {
|
||||||
|
// Not supported on Android out of the box
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,223 @@
|
||||||
|
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.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.SetOptions;
|
||||||
|
import com.google.firebase.firestore.WriteBatch;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import io.invertase.firebase.Utils;
|
||||||
|
|
||||||
|
|
||||||
|
public class RNFirebaseFirestore extends ReactContextBaseJavaModule {
|
||||||
|
private static final String TAG = "RNFirebaseFirestore";
|
||||||
|
// private HashMap<String, RNFirebaseDatabaseReference> references = new HashMap<>();
|
||||||
|
// 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) {
|
||||||
|
RNFirebaseCollectionReference ref = getCollectionForAppPath(appName, path, filters, orders, options);
|
||||||
|
ref.get(promise);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ReactMethod
|
||||||
|
public void documentBatch(final String appName, final ReadableArray writes,
|
||||||
|
final ReadableMap commitOptions, 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");
|
||||||
|
SetOptions setOptions = null;
|
||||||
|
if (options != null && options.containsKey("merge") && (boolean)options.get("merge")) {
|
||||||
|
setOptions = SetOptions.merge();
|
||||||
|
}
|
||||||
|
batch = batch.set(ref, data, setOptions);
|
||||||
|
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, "set:onComplete:success");
|
||||||
|
WritableArray result = Arguments.createArray();
|
||||||
|
for (Object w : writesArray) {
|
||||||
|
// Missing fields from web SDK
|
||||||
|
// writeTime
|
||||||
|
result.pushMap(Arguments.createMap());
|
||||||
|
}
|
||||||
|
promise.resolve(result);
|
||||||
|
} else {
|
||||||
|
Log.e(TAG, "set:onComplete:failure", task.getException());
|
||||||
|
RNFirebaseFirestore.promiseRejectException(promise, task.getException());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@ReactMethod
|
||||||
|
public void documentCollections(String appName, String path, final Promise promise) {
|
||||||
|
RNFirebaseDocumentReference ref = getDocumentForAppPath(appName, path);
|
||||||
|
ref.collections(promise);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ReactMethod
|
||||||
|
public void documentCreate(String appName, String path, ReadableMap data, final Promise promise) {
|
||||||
|
RNFirebaseDocumentReference ref = getDocumentForAppPath(appName, path);
|
||||||
|
ref.create(data, promise);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ReactMethod
|
||||||
|
public void documentDelete(String appName, String path, ReadableMap options, final Promise promise) {
|
||||||
|
RNFirebaseDocumentReference ref = getDocumentForAppPath(appName, path);
|
||||||
|
ref.delete(options, promise);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ReactMethod
|
||||||
|
public void documentGet(String appName, String path, final Promise promise) {
|
||||||
|
RNFirebaseDocumentReference 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 documentSet(String appName, String path, ReadableMap data, ReadableMap options, final Promise promise) {
|
||||||
|
RNFirebaseDocumentReference ref = getDocumentForAppPath(appName, path);
|
||||||
|
ref.set(data, options, promise);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ReactMethod
|
||||||
|
public void documentUpdate(String appName, String path, ReadableMap data, ReadableMap options, final Promise promise) {
|
||||||
|
RNFirebaseDocumentReference ref = getDocumentForAppPath(appName, path);
|
||||||
|
ref.update(data, options, 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, Exception exception) {
|
||||||
|
// TODO
|
||||||
|
// WritableMap jsError = getJSError(exception);
|
||||||
|
promise.reject(
|
||||||
|
"TODO", // jsError.getString("code"),
|
||||||
|
exception.getMessage(), // 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 RNFirebaseCollectionReference getCollectionForAppPath(String appName, String path,
|
||||||
|
ReadableArray filters,
|
||||||
|
ReadableArray orders,
|
||||||
|
ReadableMap options) {
|
||||||
|
return new RNFirebaseCollectionReference(appName, path, filters, orders, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a document reference for a specific app and path
|
||||||
|
*
|
||||||
|
* @param appName
|
||||||
|
* @param path
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private RNFirebaseDocumentReference getDocumentForAppPath(String appName, String path) {
|
||||||
|
return new RNFirebaseDocumentReference(appName, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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());
|
||||||
|
constants.put("serverTimestampFieldValue", FieldValue.serverTimestamp());
|
||||||
|
return constants;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,19 +5,14 @@
|
||||||
import CollectionReference from './CollectionReference';
|
import CollectionReference from './CollectionReference';
|
||||||
import DocumentSnapshot from './DocumentSnapshot';
|
import DocumentSnapshot from './DocumentSnapshot';
|
||||||
import Path from './Path';
|
import Path from './Path';
|
||||||
|
import INTERNALS from './../../internals';
|
||||||
|
|
||||||
export type DeleteOptions = {
|
export type DeleteOptions = {
|
||||||
lastUpdateTime?: string,
|
lastUpdateTime?: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
export type UpdateOptions = {
|
|
||||||
createIfMissing?: boolean,
|
|
||||||
lastUpdateTime?: string,
|
|
||||||
}
|
|
||||||
|
|
||||||
export type WriteOptions = {
|
export type WriteOptions = {
|
||||||
createIfMissing?: boolean,
|
merge?: boolean,
|
||||||
lastUpdateTime?: string,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type WriteResult = {
|
export type WriteResult = {
|
||||||
|
@ -63,24 +58,25 @@ export default class DocumentReference {
|
||||||
}
|
}
|
||||||
|
|
||||||
create(data: { [string]: any }): Promise<WriteResult> {
|
create(data: { [string]: any }): Promise<WriteResult> {
|
||||||
return this._firestore._native
|
/* return this._firestore._native
|
||||||
.documentCreate(this._documentPath._parts, data);
|
.documentCreate(this.path, data); */
|
||||||
|
throw new Error(INTERNALS.STRINGS.ERROR_UNSUPPORTED_CLASS_METHOD('DocumentReference', 'create'));
|
||||||
}
|
}
|
||||||
|
|
||||||
delete(deleteOptions?: DeleteOptions): Promise<WriteResult> {
|
delete(deleteOptions?: DeleteOptions): Promise<WriteResult> {
|
||||||
return this._firestore._native
|
return this._firestore._native
|
||||||
.documentDelete(this._documentPath._parts, deleteOptions);
|
.documentDelete(this.path, deleteOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
get(): Promise<DocumentSnapshot> {
|
get(): Promise<DocumentSnapshot> {
|
||||||
return this._firestore._native
|
return this._firestore._native
|
||||||
.documentGet(this._documentPath._parts)
|
.documentGet(this.path)
|
||||||
.then(result => new DocumentSnapshot(this._firestore, result));
|
.then(result => new DocumentSnapshot(this._firestore, result));
|
||||||
}
|
}
|
||||||
|
|
||||||
getCollections(): Promise<CollectionReference[]> {
|
getCollections(): Promise<CollectionReference[]> {
|
||||||
return this._firestore._native
|
/* return this._firestore._native
|
||||||
.documentCollections(this._documentPath._parts)
|
.documentCollections(this.path)
|
||||||
.then((collectionIds) => {
|
.then((collectionIds) => {
|
||||||
const collections = [];
|
const collections = [];
|
||||||
|
|
||||||
|
@ -89,7 +85,8 @@ export default class DocumentReference {
|
||||||
}
|
}
|
||||||
|
|
||||||
return collections;
|
return collections;
|
||||||
});
|
}); */
|
||||||
|
throw new Error(INTERNALS.STRINGS.ERROR_UNSUPPORTED_CLASS_METHOD('DocumentReference', 'getCollections'));
|
||||||
}
|
}
|
||||||
|
|
||||||
onSnapshot(onNext: () => any, onError?: () => any): () => void {
|
onSnapshot(onNext: () => any, onError?: () => any): () => void {
|
||||||
|
@ -98,12 +95,13 @@ export default class DocumentReference {
|
||||||
|
|
||||||
set(data: { [string]: any }, writeOptions?: WriteOptions): Promise<WriteResult> {
|
set(data: { [string]: any }, writeOptions?: WriteOptions): Promise<WriteResult> {
|
||||||
return this._firestore._native
|
return this._firestore._native
|
||||||
.documentSet(this._documentPath._parts, data, writeOptions);
|
.documentSet(this.path, data, writeOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
update(data: { [string]: any }, updateOptions?: UpdateOptions): Promise<WriteResult> {
|
// TODO: Update to new update method signature
|
||||||
|
update(data: { [string]: any }): Promise<WriteResult> {
|
||||||
return this._firestore._native
|
return this._firestore._native
|
||||||
.documentUpdate(this._documentPath._parts, data, updateOptions);
|
.documentUpdate(this.path, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -117,6 +115,6 @@ export default class DocumentReference {
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_getDocumentKey() {
|
_getDocumentKey() {
|
||||||
return `$${this._firestore._appName}$/${this._documentPath._parts.join('/')}`;
|
return `$${this._firestore._appName}$/${this.path}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,11 +4,12 @@
|
||||||
*/
|
*/
|
||||||
import DocumentReference from './DocumentReference';
|
import DocumentReference from './DocumentReference';
|
||||||
import Path from './Path';
|
import Path from './Path';
|
||||||
|
import INTERNALS from './../../internals';
|
||||||
|
|
||||||
export type DocumentSnapshotNativeData = {
|
export type DocumentSnapshotNativeData = {
|
||||||
createTime: string,
|
createTime: string,
|
||||||
data: Object,
|
data: Object,
|
||||||
name: string,
|
path: string,
|
||||||
readTime: string,
|
readTime: string,
|
||||||
updateTime: string,
|
updateTime: string,
|
||||||
}
|
}
|
||||||
|
@ -26,13 +27,14 @@ export default class DocumentSnapshot {
|
||||||
constructor(firestore: Object, nativeData: DocumentSnapshotNativeData) {
|
constructor(firestore: Object, nativeData: DocumentSnapshotNativeData) {
|
||||||
this._createTime = nativeData.createTime;
|
this._createTime = nativeData.createTime;
|
||||||
this._data = nativeData.data;
|
this._data = nativeData.data;
|
||||||
this._ref = new DocumentReference(firestore, Path.fromName(nativeData.name));
|
this._ref = new DocumentReference(firestore, Path.fromName(nativeData.path));
|
||||||
this._readTime = nativeData.readTime;
|
this._readTime = nativeData.readTime;
|
||||||
this._updateTime = nativeData.updateTime;
|
this._updateTime = nativeData.updateTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
get createTime(): string {
|
get createTime(): string {
|
||||||
return this._createTime;
|
// return this._createTime;
|
||||||
|
throw new Error(INTERNALS.STRINGS.ERROR_UNSUPPORTED_CLASS_PROPERTY('DocumentSnapshot', 'createTime'));
|
||||||
}
|
}
|
||||||
|
|
||||||
get exists(): boolean {
|
get exists(): boolean {
|
||||||
|
@ -44,7 +46,8 @@ export default class DocumentSnapshot {
|
||||||
}
|
}
|
||||||
|
|
||||||
get readTime(): string {
|
get readTime(): string {
|
||||||
return this._readTime;
|
// return this._readTime;
|
||||||
|
throw new Error(INTERNALS.STRINGS.ERROR_UNSUPPORTED_CLASS_PROPERTY('DocumentSnapshot', 'readTime'));
|
||||||
}
|
}
|
||||||
|
|
||||||
get ref(): DocumentReference {
|
get ref(): DocumentReference {
|
||||||
|
@ -52,7 +55,8 @@ export default class DocumentSnapshot {
|
||||||
}
|
}
|
||||||
|
|
||||||
get updateTime(): string {
|
get updateTime(): string {
|
||||||
return this._updateTime;
|
// return this._updateTime;
|
||||||
|
throw new Error(INTERNALS.STRINGS.ERROR_UNSUPPORTED_CLASS_PROPERTY('DocumentSnapshot', 'updateTime'));
|
||||||
}
|
}
|
||||||
|
|
||||||
data(): Object {
|
data(): Object {
|
||||||
|
|
|
@ -5,22 +5,23 @@
|
||||||
import DocumentSnapshot from './DocumentSnapshot';
|
import DocumentSnapshot from './DocumentSnapshot';
|
||||||
import Path from './Path';
|
import Path from './Path';
|
||||||
import QuerySnapshot from './QuerySnapshot';
|
import QuerySnapshot from './QuerySnapshot';
|
||||||
|
import INTERNALS from './../../internals';
|
||||||
|
|
||||||
const DIRECTIONS = {
|
const DIRECTIONS = {
|
||||||
DESC: 'descending',
|
ASC: 'ASCENDING',
|
||||||
desc: 'descending',
|
asc: 'ASCENDING',
|
||||||
ASC: 'ascending',
|
DESC: 'DESCENDING',
|
||||||
asc: 'ascending'
|
desc: 'DESCENDING',
|
||||||
};
|
};
|
||||||
const DOCUMENT_NAME_FIELD = '__name__';
|
const DOCUMENT_NAME_FIELD = '__name__';
|
||||||
|
|
||||||
const OPERATORS = {
|
const OPERATORS = {
|
||||||
'<': 'LESS_THAN',
|
|
||||||
'<=': 'LESS_THAN_OR_EQUAL',
|
|
||||||
'=': 'EQUAL',
|
'=': 'EQUAL',
|
||||||
'==': 'EQUAL',
|
'==': 'EQUAL',
|
||||||
'>': 'GREATER_THAN',
|
'>': 'GREATER_THAN',
|
||||||
'>=': 'GREATER_THAN_OR_EQUAL',
|
'>=': 'GREATER_THAN_OR_EQUAL',
|
||||||
|
'<': 'LESS_THAN',
|
||||||
|
'<=': 'LESS_THAN_OR_EQUAL',
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Direction = 'DESC' | 'desc' | 'ASC' | 'asc';
|
export type Direction = 'DESC' | 'desc' | 'ASC' | 'asc';
|
||||||
|
@ -34,6 +35,8 @@ type FieldOrder = {
|
||||||
fieldPath: string,
|
fieldPath: string,
|
||||||
}
|
}
|
||||||
type QueryOptions = {
|
type QueryOptions = {
|
||||||
|
endAt?: any[],
|
||||||
|
endBefore?: any[],
|
||||||
limit?: number,
|
limit?: number,
|
||||||
offset?: number,
|
offset?: number,
|
||||||
selectFields?: string[],
|
selectFields?: string[],
|
||||||
|
@ -92,12 +95,12 @@ export default class Query {
|
||||||
get(): Promise<QuerySnapshot> {
|
get(): Promise<QuerySnapshot> {
|
||||||
return this._firestore._native
|
return this._firestore._native
|
||||||
.collectionGet(
|
.collectionGet(
|
||||||
this._referencePath._parts,
|
this._referencePath.relativeName,
|
||||||
this._fieldFilters,
|
this._fieldFilters,
|
||||||
this._fieldOrders,
|
this._fieldOrders,
|
||||||
this._queryOptions,
|
this._queryOptions,
|
||||||
)
|
)
|
||||||
.then(nativeData => new QuerySnapshot(nativeData));
|
.then(nativeData => new QuerySnapshot(this._firestore, this, nativeData));
|
||||||
}
|
}
|
||||||
|
|
||||||
limit(n: number): Query {
|
limit(n: number): Query {
|
||||||
|
@ -116,12 +119,13 @@ export default class Query {
|
||||||
// TODO: Validation
|
// TODO: Validation
|
||||||
// validate.isInteger('n', n);
|
// validate.isInteger('n', n);
|
||||||
|
|
||||||
const options = {
|
/* const options = {
|
||||||
...this._queryOptions,
|
...this._queryOptions,
|
||||||
offset: n,
|
offset: n,
|
||||||
};
|
};
|
||||||
return new Query(this.firestore, this._referencePath, this._fieldFilters,
|
return new Query(this.firestore, this._referencePath, this._fieldFilters,
|
||||||
this._fieldOrders, options);
|
this._fieldOrders, options); */
|
||||||
|
throw new Error(INTERNALS.STRINGS.ERROR_UNSUPPORTED_CLASS_METHOD('Query', 'offset'));
|
||||||
}
|
}
|
||||||
|
|
||||||
onSnapshot(onNext: () => any, onError?: () => any): () => void {
|
onSnapshot(onNext: () => any, onError?: () => any): () => void {
|
||||||
|
@ -129,9 +133,9 @@ export default class Query {
|
||||||
}
|
}
|
||||||
|
|
||||||
orderBy(fieldPath: string, directionStr?: Direction = 'asc'): Query {
|
orderBy(fieldPath: string, directionStr?: Direction = 'asc'): Query {
|
||||||
//TODO: Validation
|
// TODO: Validation
|
||||||
//validate.isFieldPath('fieldPath', fieldPath);
|
// validate.isFieldPath('fieldPath', fieldPath);
|
||||||
//validate.isOptionalFieldOrder('directionStr', directionStr);
|
// validate.isOptionalFieldOrder('directionStr', directionStr);
|
||||||
|
|
||||||
if (this._queryOptions.startAt || this._queryOptions.endAt) {
|
if (this._queryOptions.startAt || this._queryOptions.endAt) {
|
||||||
throw new Error('Cannot specify an orderBy() constraint after calling ' +
|
throw new Error('Cannot specify an orderBy() constraint after calling ' +
|
||||||
|
@ -148,6 +152,7 @@ export default class Query {
|
||||||
}
|
}
|
||||||
|
|
||||||
select(varArgs: string[]): Query {
|
select(varArgs: string[]): Query {
|
||||||
|
/*
|
||||||
varArgs = Array.isArray(arguments[0]) ? arguments[0] : [].slice.call(arguments);
|
varArgs = Array.isArray(arguments[0]) ? arguments[0] : [].slice.call(arguments);
|
||||||
const fieldReferences = [];
|
const fieldReferences = [];
|
||||||
|
|
||||||
|
@ -167,7 +172,8 @@ export default class Query {
|
||||||
};
|
};
|
||||||
|
|
||||||
return new Query(this.firestore, this._referencePath, this._fieldFilters,
|
return new Query(this.firestore, this._referencePath, this._fieldFilters,
|
||||||
this._fieldOrders, options);
|
this._fieldOrders, options);*/
|
||||||
|
throw new Error(INTERNALS.STRINGS.ERROR_UNSUPPORTED_CLASS_METHOD('Query', 'select'));
|
||||||
}
|
}
|
||||||
|
|
||||||
startAfter(fieldValues: any): Query {
|
startAfter(fieldValues: any): Query {
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
*/
|
*/
|
||||||
import DocumentReference from './DocumentReference';
|
import DocumentReference from './DocumentReference';
|
||||||
|
|
||||||
import type { DeleteOptions, UpdateOptions, WriteOptions, WriteResult } from './DocumentReference';
|
import type { DeleteOptions, WriteOptions, WriteResult } from './DocumentReference';
|
||||||
|
|
||||||
type CommitOptions = {
|
type CommitOptions = {
|
||||||
transactionId: string,
|
transactionId: string,
|
||||||
|
@ -13,8 +13,8 @@ type CommitOptions = {
|
||||||
type DocumentWrite = {
|
type DocumentWrite = {
|
||||||
data?: Object,
|
data?: Object,
|
||||||
options?: Object,
|
options?: Object,
|
||||||
path: string[],
|
path: string,
|
||||||
type: 'delete' | 'set' | 'update',
|
type: 'DELETE' | 'SET' | 'UPDATE',
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -51,8 +51,8 @@ export default class WriteBatch {
|
||||||
// validate.isOptionalPrecondition('deleteOptions', deleteOptions);
|
// validate.isOptionalPrecondition('deleteOptions', deleteOptions);
|
||||||
this._writes.push({
|
this._writes.push({
|
||||||
options: deleteOptions,
|
options: deleteOptions,
|
||||||
path: docRef._documentPath._parts,
|
path: docRef.path,
|
||||||
type: 'delete',
|
type: 'DELETE',
|
||||||
});
|
});
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
|
@ -67,40 +67,25 @@ export default class WriteBatch {
|
||||||
this._writes.push({
|
this._writes.push({
|
||||||
data,
|
data,
|
||||||
options: writeOptions,
|
options: writeOptions,
|
||||||
path: docRef._documentPath._parts,
|
path: docRef.path,
|
||||||
type: 'set',
|
type: 'SET',
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO: DocumentTransform ?!
|
|
||||||
// let documentTransform = DocumentTransform.fromObject(docRef, data);
|
|
||||||
|
|
||||||
// if (!documentTransform.isEmpty) {
|
|
||||||
// this._writes.push({transform: documentTransform.toProto()});
|
|
||||||
// }
|
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
update(docRef: DocumentReference, data: Object, updateOptions: UpdateOptions): WriteBatch {
|
// TODO: Update to new method signature
|
||||||
|
update(docRef: DocumentReference, data: { [string]: any }): WriteBatch {
|
||||||
// TODO: Validation
|
// TODO: Validation
|
||||||
// validate.isDocumentReference('docRef', docRef);
|
// validate.isDocumentReference('docRef', docRef);
|
||||||
// validate.isDocument('data', data, true);
|
// validate.isDocument('data', data, true);
|
||||||
// validate.isOptionalPrecondition('updateOptions', updateOptions);
|
|
||||||
|
|
||||||
this._writes.push({
|
this._writes.push({
|
||||||
data,
|
data,
|
||||||
options: updateOptions,
|
path: docRef.path,
|
||||||
path: docRef._documentPath._parts,
|
type: 'UPDATE',
|
||||||
type: 'update',
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO: DocumentTransform ?!
|
|
||||||
// let documentTransform = DocumentTransform.fromObject(docRef, expandedObject);
|
|
||||||
|
|
||||||
// if (!documentTransform.isEmpty) {
|
|
||||||
// this._writes.push({transform: documentTransform.toProto()});
|
|
||||||
// }
|
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ import DocumentSnapshot from './DocumentSnapshot';
|
||||||
import GeoPoint from './GeoPoint';
|
import GeoPoint from './GeoPoint';
|
||||||
import Path from './Path';
|
import Path from './Path';
|
||||||
import WriteBatch from './WriteBatch';
|
import WriteBatch from './WriteBatch';
|
||||||
|
import INTERNALS from './../../internals';
|
||||||
|
|
||||||
const unquotedIdentifier_ = '(?:[A-Za-z_][A-Za-z_0-9]*)';
|
const unquotedIdentifier_ = '(?:[A-Za-z_][A-Za-z_0-9]*)';
|
||||||
const UNQUOTED_IDENTIFIER_REGEX = new RegExp(`^${unquotedIdentifier_}$`);
|
const UNQUOTED_IDENTIFIER_REGEX = new RegExp(`^${unquotedIdentifier_}$`);
|
||||||
|
@ -62,17 +63,18 @@ export default class Firestore extends ModuleBase {
|
||||||
}
|
}
|
||||||
|
|
||||||
getAll(varArgs: DocumentReference[]): Promise<DocumentSnapshot[]> {
|
getAll(varArgs: DocumentReference[]): Promise<DocumentSnapshot[]> {
|
||||||
varArgs = Array.isArray(arguments[0]) ? arguments[0] : [].slice.call(arguments);
|
/*varArgs = Array.isArray(arguments[0]) ? arguments[0] : [].slice.call(arguments);
|
||||||
|
|
||||||
const documents = [];
|
const documents = [];
|
||||||
varArgs.forEach((document) => {
|
varArgs.forEach((document) => {
|
||||||
// TODO: Validation
|
// TODO: Validation
|
||||||
// validate.isDocumentReference(i, varArgs[i]);
|
// validate.isDocumentReference(i, varArgs[i]);
|
||||||
documents.push(document._documentPath._parts);
|
documents.push(document.path);
|
||||||
});
|
});
|
||||||
return this._native
|
return this._native
|
||||||
.documentGetAll(documents)
|
.documentGetAll(documents)
|
||||||
.then(results => results.map(result => new DocumentSnapshot(this, result)));
|
.then(results => results.map(result => new DocumentSnapshot(this, result)));*/
|
||||||
|
throw new Error(INTERNALS.STRINGS.ERROR_UNSUPPORTED_MODULE_METHOD('Query', 'offset'));
|
||||||
}
|
}
|
||||||
|
|
||||||
getCollections(): Promise<CollectionReference[]> {
|
getCollections(): Promise<CollectionReference[]> {
|
||||||
|
|
|
@ -9,6 +9,14 @@ const AUTO_ID_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234
|
||||||
const hasOwnProperty = Object.hasOwnProperty;
|
const hasOwnProperty = Object.hasOwnProperty;
|
||||||
const DEFAULT_CHUNK_SIZE = 50;
|
const DEFAULT_CHUNK_SIZE = 50;
|
||||||
|
|
||||||
|
// Source: https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical
|
||||||
|
const REGEXP_FIELD_NAME = new RegExp(
|
||||||
|
`^(?:\\.?((?:(?:[A-Za-z_][A-Za-z_0-9]*)|(?:[A-Za-z_][A-Za-z_0-9]*))+))$`
|
||||||
|
);
|
||||||
|
const REGEXP_FIELD_PATH = new RegExp(
|
||||||
|
`^((?:(?:[A-Za-z_][A-Za-z_0-9]*)|(?:[A-Za-z_][A-Za-z_0-9]*))+)(?:\\.((?:(?:[A-Za-z_][A-Za-z_0-9]*)|(?:[A-Za-z_][A-Za-z_0-9]*))+))*$`
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deep get a value from an object.
|
* Deep get a value from an object.
|
||||||
* @website https://github.com/Salakar/deeps
|
* @website https://github.com/Salakar/deeps
|
||||||
|
@ -88,6 +96,16 @@ export function isString(value): Boolean {
|
||||||
return typeof value === 'string';
|
return typeof value === 'string';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Firestore field name/path validator.
|
||||||
|
* @param field
|
||||||
|
* @param paths
|
||||||
|
* @return {boolean}
|
||||||
|
*/
|
||||||
|
export function isValidFirestoreField(field, paths) {
|
||||||
|
return (paths ? REGEXP_FIELD_PATH : REGEXP_FIELD_NAME).test(field);
|
||||||
|
}
|
||||||
|
|
||||||
// platform checks
|
// platform checks
|
||||||
export const isIOS = Platform.OS === 'ios';
|
export const isIOS = Platform.OS === 'ios';
|
||||||
export const isAndroid = Platform.OS === 'android';
|
export const isAndroid = Platform.OS === 'android';
|
||||||
|
|
Loading…
Reference in New Issue