From 2ceea9b66eb8ea516702e1ef409e801fec068682 Mon Sep 17 00:00:00 2001 From: zxu Date: Thu, 12 Apr 2018 21:32:19 -0400 Subject: Port `Precondition` to C++ (#1040) * port FieldMask to C++ * address changes * address changes * fix test * address change * Port transform operations (FSTTransformOperation, FSTServerTimestampTransform) to C++ * address changes * address changes * address changes * implement `FieldTransform` in C++ * port `FieldTransform` * make `fieldTransforms` shared inside `context` * Implement Precondition in C++ w/o test yet * add unit test for `Precondition` * port `Precondition` * address changes * address changes * fix bugs for integration test * address changes * fix lint * address changes * address changes --- .../src/firebase/firestore/model/CMakeLists.txt | 2 + .../src/firebase/firestore/model/precondition.cc | 67 +++++++++ .../src/firebase/firestore/model/precondition.h | 160 +++++++++++++++++++++ .../firebase/firestore/model/snapshot_version.h | 23 +++ 4 files changed, 252 insertions(+) create mode 100644 Firestore/core/src/firebase/firestore/model/precondition.cc create mode 100644 Firestore/core/src/firebase/firestore/model/precondition.h (limited to 'Firestore/core/src/firebase/firestore/model') diff --git a/Firestore/core/src/firebase/firestore/model/CMakeLists.txt b/Firestore/core/src/firebase/firestore/model/CMakeLists.txt index de783ad..02affdb 100644 --- a/Firestore/core/src/firebase/firestore/model/CMakeLists.txt +++ b/Firestore/core/src/firebase/firestore/model/CMakeLists.txt @@ -32,6 +32,8 @@ cc_library( maybe_document.h no_document.cc no_document.h + precondition.cc + precondition.h resource_path.cc resource_path.h snapshot_version.cc diff --git a/Firestore/core/src/firebase/firestore/model/precondition.cc b/Firestore/core/src/firebase/firestore/model/precondition.cc new file mode 100644 index 0000000..423d5a2 --- /dev/null +++ b/Firestore/core/src/firebase/firestore/model/precondition.cc @@ -0,0 +1,67 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Firestore/core/src/firebase/firestore/model/precondition.h" + +#include "Firestore/core/src/firebase/firestore/model/maybe_document.h" +#include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" +#include "Firestore/core/src/firebase/firestore/util/firebase_assert.h" + +namespace firebase { +namespace firestore { +namespace model { + +Precondition::Precondition(Type type, SnapshotVersion update_time, bool exists) + : type_(type), update_time_(std::move(update_time)), exists_(exists) { +} + +/* static */ +Precondition Precondition::Exists(bool exists) { + return Precondition{Type::Exists, SnapshotVersion::None(), exists}; +} + +/* static */ +Precondition Precondition::UpdateTime(SnapshotVersion update_time) { + // update_time could be SnapshotVersion::None() in particular for locally + // deleted documents. + return Precondition{Type::UpdateTime, std::move(update_time), false}; +} + +/* static */ +Precondition Precondition::None() { + return Precondition{Type::None, SnapshotVersion::None(), false}; +} + +bool Precondition::IsValidFor(const MaybeDocument& maybe_doc) const { + switch (type_) { + case Type::UpdateTime: + return maybe_doc.type() == MaybeDocument::Type::Document && + maybe_doc.version() == update_time_; + case Type::Exists: + if (exists_) { + return maybe_doc.type() == MaybeDocument::Type::Document; + } else { + return maybe_doc.type() == MaybeDocument::Type::NoDocument; + } + case Type::None: + return true; + } + FIREBASE_UNREACHABLE(); +} + +} // namespace model +} // namespace firestore +} // namespace firebase diff --git a/Firestore/core/src/firebase/firestore/model/precondition.h b/Firestore/core/src/firebase/firestore/model/precondition.h new file mode 100644 index 0000000..4ab03c2 --- /dev/null +++ b/Firestore/core/src/firebase/firestore/model/precondition.h @@ -0,0 +1,160 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_PRECONDITION_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_PRECONDITION_H_ + +#include + +#if defined(__OBJC__) +#import "FIRTimestamp.h" +#import "Firestore/Source/Core/FSTSnapshotVersion.h" +#import "Firestore/Source/Model/FSTDocument.h" +#include "Firestore/core/include/firebase/firestore/timestamp.h" +#endif // defined(__OBJC__) + +#include "Firestore/core/src/firebase/firestore/model/maybe_document.h" +#include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" +#include "Firestore/core/src/firebase/firestore/util/firebase_assert.h" + +namespace firebase { +namespace firestore { +namespace model { + +/** + * Encodes a precondition for a mutation. This follows the model that the + * backend accepts with the special case of an explicit "empty" precondition + * (meaning no precondition). + */ +class Precondition { + public: + enum class Type { + None, + Exists, + UpdateTime, + }; + + /** Creates a new Precondition with an exists flag. */ + static Precondition Exists(bool exists); + + /** Creates a new Precondition based on a time the document exists at. */ + static Precondition UpdateTime(SnapshotVersion update_time); + + /** Returns a precondition representing no precondition. */ + static Precondition None(); + + /** + * Returns true if the precondition is valid for the given document (and the + * document is available). + */ + bool IsValidFor(const MaybeDocument& maybe_doc) const; + + /** Returns whether this Precondition represents no precondition. */ + bool IsNone() const { + return type_ == Type::None; + } + + Type type() const { + return type_; + } + + const SnapshotVersion& update_time() const { + return update_time_; + } + + bool operator==(const Precondition& other) const { + return type_ == other.type_ && update_time_ == other.update_time_ && + exists_ == other.exists_; + } + +#if defined(__OBJC__) + // Objective-C requires a default constructor. + Precondition() + : type_(Type::None), + update_time_(SnapshotVersion::None()), + exists_(false) { + } + + // MaybeDocument is not fully ported yet. So we suppose this addition helper. + bool IsValidFor(FSTMaybeDocument* maybe_doc) const { + switch (type_) { + case Type::UpdateTime: + return [maybe_doc isKindOfClass:[FSTDocument class]] && + firebase::firestore::model::SnapshotVersion(maybe_doc.version) == + update_time_; + case Type::Exists: + if (exists_) { + return [maybe_doc isKindOfClass:[FSTDocument class]]; + } else { + return maybe_doc == nil || + [maybe_doc isKindOfClass:[FSTDeletedDocument class]]; + } + case Type::None: + return true; + } + FIREBASE_UNREACHABLE(); + } + + // For Objective-C++ hash; to be removed after migration. + // Do NOT use in C++ code. + NSUInteger Hash() const { + NSUInteger hash = std::hash()(update_time_.timestamp()); + hash = hash * 31 + exists_; + hash = hash * 31 + static_cast(type_); + return hash; + } + + NSString* description() const { + switch (type_) { + case Type::None: + return @">"; + case Type::Exists: + if (exists_) { + return @""; + } else { + return @""; + } + case Type::UpdateTime: + return [NSString + stringWithFormat:@"", + update_time_.timestamp().ToString().c_str()]; + } + // We only raise dev assertion here. This function is mainly used in + // logging. + FIREBASE_DEV_ASSERT_MESSAGE(false, "precondition invalid"); + return @""; + } +#endif // defined(__OBJC__) + + private: + Precondition(Type type, SnapshotVersion update_time, bool exists); + + // The actual time of this precondition. + Type type_ = Type::None; + + // For UpdateTime type, preconditions a mutation based on the last updateTime. + SnapshotVersion update_time_; + + // For Exists type, preconditions a mutation based on whether the document + // exists. + bool exists_; +}; + +} // namespace model +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_PRECONDITION_H_ diff --git a/Firestore/core/src/firebase/firestore/model/snapshot_version.h b/Firestore/core/src/firebase/firestore/model/snapshot_version.h index 56e8c50..1fbba1c 100644 --- a/Firestore/core/src/firebase/firestore/model/snapshot_version.h +++ b/Firestore/core/src/firebase/firestore/model/snapshot_version.h @@ -19,6 +19,11 @@ #include "Firestore/core/include/firebase/firestore/timestamp.h" +#if defined(__OBJC__) +#import "FIRTimestamp.h" +#import "Firestore/Source/Core/FSTSnapshotVersion.h" +#endif // defined(__OBJC__) + namespace firebase { namespace firestore { namespace model { @@ -38,6 +43,24 @@ class SnapshotVersion { /** Creates a new version that is smaller than all other versions. */ static const SnapshotVersion& None(); +#if defined(__OBJC__) + SnapshotVersion(FSTSnapshotVersion* version) // NOLINT(runtime/explicit) + : timestamp_{version.timestamp.seconds, version.timestamp.nanoseconds} { + } + + operator FSTSnapshotVersion*() const { + if (timestamp_ == Timestamp{}) { + return [FSTSnapshotVersion noVersion]; + } else { + return [FSTSnapshotVersion + versionWithTimestamp:[FIRTimestamp + timestampWithSeconds:timestamp_.seconds() + nanoseconds:timestamp_ + .nanoseconds()]]; + } + } +#endif // defined(__OBJC__) + private: Timestamp timestamp_; }; -- cgit v1.2.3