added iOS source code
[wl-app.git] / iOS / Pods / Realm / Realm / ObjectStore / src / sync / partial_sync.cpp
diff --git a/iOS/Pods/Realm/Realm/ObjectStore/src/sync/partial_sync.cpp b/iOS/Pods/Realm/Realm/ObjectStore/src/sync/partial_sync.cpp
new file mode 100644 (file)
index 0000000..ed5a3c5
--- /dev/null
@@ -0,0 +1,133 @@
+////////////////////////////////////////////////////////////////////////////
+//
+// Copyright 2017 Realm Inc.
+//
+// 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 "sync/partial_sync.hpp"
+
+#include "impl/notification_wrapper.hpp"
+#include "impl/object_accessor_impl.hpp"
+#include "object_schema.hpp"
+#include "results.hpp"
+#include "shared_realm.hpp"
+#include "sync/sync_config.hpp"
+
+#include <realm/util/scope_exit.hpp>
+
+namespace realm {
+namespace partial_sync {
+
+namespace {
+
+constexpr const char* result_sets_type_name = "__ResultSets";
+
+void update_schema(Group& group, Property matches_property)
+{
+    Schema current_schema;
+    std::string table_name = ObjectStore::table_name_for_object_type(result_sets_type_name);
+    if (group.has_table(table_name))
+        current_schema = {ObjectSchema{group, result_sets_type_name}};
+
+    Schema desired_schema({
+        ObjectSchema(result_sets_type_name, {
+            {"matches_property", PropertyType::String},
+            {"query", PropertyType::String},
+            {"status", PropertyType::Int},
+            {"error_message", PropertyType::String},
+            {"query_parse_counter", PropertyType::Int},
+            std::move(matches_property)
+        })
+    });
+    auto required_changes = current_schema.compare(desired_schema);
+    if (!required_changes.empty())
+        ObjectStore::apply_additive_changes(group, required_changes, true);
+}
+
+} // unnamed namespace
+
+void register_query(std::shared_ptr<Realm> realm, const std::string &object_class, const std::string &query,
+                    std::function<void (Results, std::exception_ptr)> callback)
+{
+    auto sync_config = realm->config().sync_config;
+    if (!sync_config || !sync_config->is_partial)
+        throw std::logic_error("A partial sync query can only be registered in a partially synced Realm");
+
+    if (realm->schema().find(object_class) == realm->schema().end())
+        throw std::logic_error("A partial sync query can only be registered for a type that exists in the Realm's schema");
+
+    auto matches_property = object_class + "_matches";
+
+    // The object schema must outlive `object` below.
+    std::unique_ptr<ObjectSchema> result_sets_schema;
+    Object raw_object;
+    {
+        realm->begin_transaction();
+        auto cleanup = util::make_scope_exit([&]() noexcept {
+            if (realm->is_in_transaction())
+                realm->cancel_transaction();
+        });
+
+        update_schema(realm->read_group(),
+                      Property(matches_property, PropertyType::Object|PropertyType::Array, object_class));
+
+        result_sets_schema = std::make_unique<ObjectSchema>(realm->read_group(), result_sets_type_name);
+
+        CppContext context;
+        raw_object = Object::create<util::Any>(context, realm, *result_sets_schema,
+                                               AnyDict{
+                                                   {"matches_property", matches_property},
+                                                   {"query", query},
+                                                   {"status", int64_t(0)},
+                                                   {"error_message", std::string()},
+                                                   {"query_parse_counter", int64_t(0)},
+                                               }, false);
+
+        realm->commit_transaction();
+    }
+
+    auto object = std::make_shared<_impl::NotificationWrapper<Object>>(std::move(raw_object));
+
+    // Observe the new object and notify listener when the results are complete (status != 0).
+    auto notification_callback = [object, matches_property,
+                                  result_sets_schema=std::move(result_sets_schema),
+                                  callback=std::move(callback)](CollectionChangeSet, std::exception_ptr error) mutable {
+        if (error) {
+            callback(Results(), error);
+            object.reset();
+            return;
+        }
+
+        CppContext context;
+        auto status = any_cast<int64_t>(object->get_property_value<util::Any>(context, "status"));
+        if (status == 0) {
+            // Still computing...
+            return;
+        } else if (status == 1) {
+            // Finished successfully.
+            auto list = any_cast<List>(object->get_property_value<util::Any>(context, matches_property));
+            callback(list.as_results(), nullptr);
+        } else {
+            // Finished with error.
+            auto message = any_cast<std::string>(object->get_property_value<util::Any>(context, "error_message"));
+            callback(Results(), std::make_exception_ptr(std::runtime_error(std::move(message))));
+        }
+        object.reset();
+    };
+    object->add_notification_callback(std::move(notification_callback));
+}
+
+} // namespace partial_sync
+} // namespace realm