aboutsummaryrefslogtreecommitdiffhomepage
path: root/Firestore/core/src/firebase/firestore/model
diff options
context:
space:
mode:
authorGravatar Michael Lehenbauer <mikelehen@gmail.com>2018-05-08 15:33:10 -0700
committerGravatar GitHub <noreply@github.com>2018-05-08 15:33:10 -0700
commit8409f21830f1282a39c4b7888972011f43d2644a (patch)
treef09e374eb38474a52ba15226f43518e9c29bd274 /Firestore/core/src/firebase/firestore/model
parentf32e4606e0bee158be9418b050ec2a71b2777311 (diff)
Backport array contains / transform improvements from Web. (#1242)
Diffstat (limited to 'Firestore/core/src/firebase/firestore/model')
-rw-r--r--Firestore/core/src/firebase/firestore/model/transform_operations.h109
1 files changed, 96 insertions, 13 deletions
diff --git a/Firestore/core/src/firebase/firestore/model/transform_operations.h b/Firestore/core/src/firebase/firestore/model/transform_operations.h
index a1c2de0..abc8d1b 100644
--- a/Firestore/core/src/firebase/firestore/model/transform_operations.h
+++ b/Firestore/core/src/firebase/firestore/model/transform_operations.h
@@ -20,6 +20,8 @@
#include <utility>
#include <vector>
+#include "Firestore/core/include/firebase/firestore/timestamp.h"
+
#if defined(__OBJC__)
#import "Firestore/Source/Model/FSTFieldValue.h"
#endif
@@ -49,11 +51,28 @@ class TransformOperation {
/** Returns the actual type. */
virtual Type type() const = 0;
+// TODO(mikelehen): apply methods require FSTFieldValue which is Obj-C only.
+#if defined(__OBJC__)
+ /**
+ * Computes the local transform result against the provided `previousValue`,
+ * optionally using the provided localWriteTime.
+ */
+ virtual FSTFieldValue *applyToLocalView(
+ FSTFieldValue *previousValue, FIRTimestamp *localWriteTime) const = 0;
+
+ /**
+ * Computes a final transform result after the transform has been acknowledged
+ * by the server, potentially using the server-provided transformResult.
+ */
+ virtual FSTFieldValue *applyToRemoteDocument(
+ FSTFieldValue *previousValue, FSTFieldValue *transformResult) const = 0;
+#endif
+
/** Returns whether the two are equal. */
- virtual bool operator==(const TransformOperation& other) const = 0;
+ virtual bool operator==(const TransformOperation &other) const = 0;
/** Returns whether the two are not equal. */
- bool operator!=(const TransformOperation& other) const {
+ bool operator!=(const TransformOperation &other) const {
return !operator==(other);
}
@@ -74,12 +93,28 @@ class ServerTimestampTransform : public TransformOperation {
return Type::ServerTimestamp;
}
- bool operator==(const TransformOperation& other) const override {
+// TODO(mikelehen): apply methods require FSTFieldValue which is Obj-C only.
+#if defined(__OBJC__)
+ FSTFieldValue *applyToLocalView(FSTFieldValue *previousValue,
+ FIRTimestamp *localWriteTime) const override {
+ return [FSTServerTimestampValue
+ serverTimestampValueWithLocalWriteTime:localWriteTime
+ previousValue:previousValue];
+ }
+
+ FSTFieldValue *applyToRemoteDocument(
+ FSTFieldValue *previousValue,
+ FSTFieldValue *transformResult) const override {
+ return transformResult;
+ }
+#endif
+
+ bool operator==(const TransformOperation &other) const override {
// All ServerTimestampTransform objects are equal.
return other.type() == Type::ServerTimestamp;
}
- static const ServerTimestampTransform& Get() {
+ static const ServerTimestampTransform &Get() {
static ServerTimestampTransform shared_instance;
return shared_instance;
}
@@ -102,13 +137,14 @@ class ServerTimestampTransform : public TransformOperation {
// TODO(mikelehen): ArrayTransform can only be used from Obj-C until we switch
// to using FieldValue instead of FSTFieldValue.
#if defined(__OBJC__)
+
/**
* Transforms an array via a union or remove operation (for convenience, we use
* this class for both Type::ArrayUnion and Type::ArrayRemove).
*/
class ArrayTransform : public TransformOperation {
public:
- ArrayTransform(Type type, std::vector<FSTFieldValue*> elements)
+ ArrayTransform(Type type, std::vector<FSTFieldValue *> elements)
: type_(type), elements_(std::move(elements)) {
}
@@ -119,15 +155,29 @@ class ArrayTransform : public TransformOperation {
return type_;
}
- const std::vector<FSTFieldValue*>& elements() const {
+ FSTFieldValue *applyToLocalView(FSTFieldValue *previousValue,
+ FIRTimestamp *localWriteTime) const override {
+ return apply(previousValue);
+ }
+
+ FSTFieldValue *applyToRemoteDocument(
+ FSTFieldValue *previousValue,
+ FSTFieldValue *transformResult) const override {
+ // The server just sends null as the transform result for array operations,
+ // so we have to calculate a result the same as we do for local
+ // applications.
+ return apply(previousValue);
+ }
+
+ const std::vector<FSTFieldValue *> &elements() const {
return elements_;
}
- bool operator==(const TransformOperation& other) const override {
+ bool operator==(const TransformOperation &other) const override {
if (other.type() != type()) {
return false;
}
- auto array_transform = static_cast<const ArrayTransform&>(other);
+ auto array_transform = static_cast<const ArrayTransform &>(other);
if (array_transform.elements_.size() != elements_.size()) {
return false;
}
@@ -145,23 +195,56 @@ class ArrayTransform : public TransformOperation {
NSUInteger Hash() const override {
NSUInteger result = 37;
result = 31 * result + (type() == Type::ArrayUnion ? 1231 : 1237);
- for (FSTFieldValue* element : elements_) {
+ for (FSTFieldValue *element : elements_) {
result = 31 * result + [element hash];
}
return result;
}
#endif // defined(__OBJC__)
- static const std::vector<FSTFieldValue*>& Elements(
- const TransformOperation& op) {
+ static const std::vector<FSTFieldValue *> &Elements(
+ const TransformOperation &op) {
FIREBASE_ASSERT(op.type() == Type::ArrayUnion ||
op.type() == Type::ArrayRemove);
- return static_cast<const ArrayTransform&>(op).elements();
+ return static_cast<const ArrayTransform &>(op).elements();
}
private:
Type type_;
- std::vector<FSTFieldValue*> elements_;
+ std::vector<FSTFieldValue *> elements_;
+
+ /**
+ * Inspects the provided value, returning a mutable copy of the internal array
+ * if it's an FSTArrayValue and an empty mutable array if it's nil or any
+ * other type of FSTFieldValue.
+ */
+ static NSMutableArray<FSTFieldValue *> *CoercedFieldValuesArray(
+ FSTFieldValue *value) {
+ if ([value isMemberOfClass:[FSTArrayValue class]]) {
+ return [NSMutableArray
+ arrayWithArray:reinterpret_cast<FSTArrayValue *>(value)
+ .internalValue];
+ } else {
+ // coerce to empty array.
+ return [NSMutableArray array];
+ }
+ }
+
+ FSTFieldValue *apply(FSTFieldValue *previousValue) const {
+ NSMutableArray<FSTFieldValue *> *result =
+ ArrayTransform::CoercedFieldValuesArray(previousValue);
+ for (FSTFieldValue *element : elements_) {
+ if (type_ == Type::ArrayUnion) {
+ if (![result containsObject:element]) {
+ [result addObject:element];
+ }
+ } else {
+ FIREBASE_ASSERT(type_ == Type::ArrayRemove);
+ [result removeObject:element];
+ }
+ }
+ return [[FSTArrayValue alloc] initWithValueNoCopy:result];
+ }
};
#endif