diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b76b1d4416..556e96bb9b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ * `Realm::refresh()` did not actually advance to the latest version in some cases. If there was a version newer than the current version which did not require blocking it would advance to that instead, contrary to the documented behavior. * Fixed `realm_query_parse_for_results` ignoring query for `query_result_t` passed as parameter ([#5841](https://github.com/realm/realm-core/pull/5841)). * Fixed `realm_query_parse_for_list` ignoring existing query ([#5850](https://github.com/realm/realm-core/pull/5850)). +* Fixed not allowing asymmetric tables in partition based sync ([#5691](https://github.com/realm/realm-core/issues/5691)). ### Breaking changes * None. diff --git a/src/realm.h b/src/realm.h index 2bff945cdfd..86585fa37fe 100644 --- a/src/realm.h +++ b/src/realm.h @@ -122,8 +122,9 @@ typedef enum realm_value_type { typedef enum realm_schema_validation_mode { RLM_SCHEMA_VALIDATION_BASIC = 0, - RLM_SCHEMA_VALIDATION_SYNC = 1, - RLM_SCHEMA_VALIDATION_REJECT_EMBEDDED_ORPHANS = 2 + RLM_SCHEMA_VALIDATION_SYNC_PBS = 1, + RLM_SCHEMA_VALIDATION_REJECT_EMBEDDED_ORPHANS = 2, + RLM_SCHEMA_VALIDATION_SYNC_FLX = 4 } realm_schema_validation_mode_e; /** diff --git a/src/realm/object-store/c_api/schema.cpp b/src/realm/object-store/c_api/schema.cpp index efa4fbfca72..6c80dc5fca5 100644 --- a/src/realm/object-store/c_api/schema.cpp +++ b/src/realm/object-store/c_api/schema.cpp @@ -58,7 +58,7 @@ RLM_API uint64_t realm_get_schema_version(const realm_t* realm) RLM_API bool realm_schema_validate(const realm_schema_t* schema, uint64_t validation_mode) { return wrap_err([&]() { - schema->ptr->validate(validation_mode); + schema->ptr->validate(static_cast(validation_mode)); return true; }); } diff --git a/src/realm/object-store/object_schema.cpp b/src/realm/object-store/object_schema.cpp index 15909958015..512f47eb521 100644 --- a/src/realm/object-store/object_schema.cpp +++ b/src/realm/object-store/object_schema.cpp @@ -329,7 +329,7 @@ static void validate_property(Schema const& schema, ObjectSchema const& parent_o } void ObjectSchema::validate(Schema const& schema, std::vector& exceptions, - bool for_sync) const + SchemaValidationMode validation_mode) const { std::vector public_property_names; std::vector internal_property_names; @@ -416,6 +416,8 @@ void ObjectSchema::validate(Schema const& schema, std::vector& exceptions, - bool for_sync) const; + SchemaValidationMode validation_mode) const; friend bool operator==(ObjectSchema const& a, ObjectSchema const& b) noexcept; diff --git a/src/realm/object-store/schema.cpp b/src/realm/object-store/schema.cpp index ec5c37e47c4..eff678472d6 100644 --- a/src/realm/object-store/schema.cpp +++ b/src/realm/object-store/schema.cpp @@ -190,7 +190,7 @@ std::unordered_set get_embedded_object_orphans(const Schema& schema } // end anonymous namespace -void Schema::validate(uint64_t validation_mode) const +void Schema::validate(SchemaValidationMode validation_mode) const { std::vector exceptions; @@ -206,9 +206,8 @@ void Schema::validate(uint64_t validation_mode) const ObjectSchemaValidationException("Type '%1' appears more than once in the schema.", it->name)); } - const bool for_sync = validation_mode & SchemaValidationMode::Sync; for (auto const& object : *this) { - object.validate(*this, exceptions, for_sync); + object.validate(*this, exceptions, validation_mode); } // TODO: remove this client side check once the server supports it diff --git a/src/realm/object-store/schema.hpp b/src/realm/object-store/schema.hpp index e73d3de5be5..44522882eeb 100644 --- a/src/realm/object-store/schema.hpp +++ b/src/realm/object-store/schema.hpp @@ -31,7 +31,7 @@ class StringData; struct TableKey; struct Property; -enum SchemaValidationMode : uint64_t { Basic = 0, Sync = 1, RejectEmbeddedOrphans = 2 }; +enum SchemaValidationMode : uint64_t { Basic = 0, SyncPBS = 1, RejectEmbeddedOrphans = 2, SyncFLX = 4 }; // How to handle update_schema() being called on a file which has // already been initialized with a different schema @@ -147,7 +147,7 @@ class Schema : private std::vector { // Verify that this schema is internally consistent (i.e. all properties are // valid, links link to types that actually exist, etc.) - void validate(uint64_t validation_mode = SchemaValidationMode::Basic) const; + void validate(SchemaValidationMode validation_mode = SchemaValidationMode::Basic) const; // Get the changes which must be applied to this schema to produce the passed-in schema std::vector compare(Schema const&, SchemaMode = SchemaMode::Automatic, diff --git a/src/realm/object-store/shared_realm.cpp b/src/realm/object-store/shared_realm.cpp index d700f0de382..736bfe96a27 100644 --- a/src/realm/object-store/shared_realm.cpp +++ b/src/realm/object-store/shared_realm.cpp @@ -385,14 +385,17 @@ void Realm::update_schema(Schema schema, uint64_t version, MigrationFunction mig DataInitializationFunction initialization_function, bool in_transaction) { uint64_t validation_mode = SchemaValidationMode::Basic; - if (m_config.sync_config) { - validation_mode |= SchemaValidationMode::Sync; +#if REALM_ENABLE_SYNC + if (auto sync_config = m_config.sync_config) { + validation_mode |= + sync_config->flx_sync_requested ? SchemaValidationMode::SyncFLX : SchemaValidationMode::SyncPBS; } +#endif if (m_config.schema_mode == SchemaMode::AdditiveExplicit) { validation_mode |= SchemaValidationMode::RejectEmbeddedOrphans; } - schema.validate(validation_mode); + schema.validate(static_cast(validation_mode)); bool was_in_read_transaction = is_in_read_transaction(); Schema actual_schema = get_full_schema(); diff --git a/test/object-store/schema.cpp b/test/object-store/schema.cpp index 33846e3920e..58268e213d4 100644 --- a/test/object-store/schema.cpp +++ b/test/object-store/schema.cpp @@ -372,7 +372,8 @@ TEST_CASE("Schema") { ObjectSchema::ObjectType::TopLevelAsymmetric, {{"_id", PropertyType::Int, Property::IsPrimary{true}}, {"street", PropertyType::String}}}, }; - REQUIRE_NOTHROW(schema.validate(SchemaValidationMode::Sync)); + REQUIRE_NOTHROW(schema.validate(SchemaValidationMode::SyncFLX)); + REQUIRE_THROWS(schema.validate(SchemaValidationMode::SyncPBS)); } SECTION("asymmetric tables not allowed in local realm") { @@ -392,7 +393,7 @@ TEST_CASE("Schema") { {{"_id", PropertyType::Int, Property::IsPrimary{true}}}}, }; REQUIRE_THROWS_CONTAINING( - schema.validate(SchemaValidationMode::Sync), + schema.validate(SchemaValidationMode::SyncFLX), "Property 'object.link' of type 'object' cannot be a link to an asymmetric object."); } @@ -403,7 +404,7 @@ TEST_CASE("Schema") { {{"link", PropertyType::Object | PropertyType::Nullable, "link target"}}}, {"link target", {{"value", PropertyType::Int}}}, }; - REQUIRE_THROWS_CONTAINING(schema.validate(SchemaValidationMode::Sync), + REQUIRE_THROWS_CONTAINING(schema.validate(SchemaValidationMode::SyncFLX), "Asymmetric table with property 'object.link' of type 'object' cannot have a " "non-embedded object type."); } @@ -416,7 +417,7 @@ TEST_CASE("Schema") { {"link", PropertyType::Object | PropertyType::Nullable, "link target"}}}, {"link target", ObjectSchema::ObjectType::Embedded, {{"value", PropertyType::Int}}}, }; - schema.validate(SchemaValidationMode::Sync); + schema.validate(SchemaValidationMode::SyncFLX); } SECTION("rejects array properties with no target object") { diff --git a/test/object-store/sync/flx_sync.cpp b/test/object-store/sync/flx_sync.cpp index 4fa4432ce23..6caba2d9693 100644 --- a/test/object-store/sync/flx_sync.cpp +++ b/test/object-store/sync/flx_sync.cpp @@ -1950,6 +1950,21 @@ TEST_CASE("flx: asymmetric sync", "[sync][flx][app]") { }); } + SECTION("asymmetric table not allowed in PBS") { + Schema schema{ + {"Asymmetric2", + ObjectSchema::ObjectType::TopLevelAsymmetric, + { + {"_id", PropertyType::Int, Property::IsPrimary{true}}, + {"location", PropertyType::Int}, + {"reading", PropertyType::Int}, + }}, + }; + + SyncTestFile config(harness->app(), bson::Bson{}, schema); + REQUIRE_THROWS(Realm::get_shared_realm(config)); + } + // Add any new test sections above this point SECTION("teardown") {