Skip to content
This repository was archived by the owner on Nov 8, 2021. It is now read-only.
Closed
30 changes: 25 additions & 5 deletions src/object_store.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ void insert_column(Group& group, Table& table, Property const& property, size_t
TableRef link_table = group.get_table(target_name);
REALM_ASSERT(link_table);
table.insert_column_link(col_ndx, is_array(property.type) ? type_LinkList : type_Link,
property.name, *link_table);
property.name, *link_table, property.link_type());
}
else if (is_array(property.type)) {
DescriptorRef desc;
Expand Down Expand Up @@ -408,6 +408,21 @@ struct SchemaDifferenceExplainer {
{
errors.emplace_back("Property '%1.%2' has been made unindexed.", op.object->name, op.property->name);
}
void operator()(schema_change::ChangeRelationshipType op)
{
std::string type;
switch (op.property->relationship) {
case Relationship::Strong:
type = "'Strong'";
break;

case Relationship::Weak:
type = "'Weak'";
break;
}

errors.emplace_back("Property '%1.%2' has changed the type of the relationship to %3.", op.object->name, op.property->name, type);
}
};

class TableHelper {
Expand Down Expand Up @@ -458,6 +473,7 @@ bool ObjectStore::needs_migration(std::vector<SchemaChange> const& changes)
bool operator()(MakePropertyRequired) { return true; }
bool operator()(RemoveIndex) { return false; }
bool operator()(RemoveProperty) { return true; }
bool operator()(ChangeRelationshipType) { return true; }
};

return std::any_of(begin(changes), end(changes),
Expand Down Expand Up @@ -586,11 +602,9 @@ static void create_initial_tables(Group& group, std::vector<SchemaChange> const&
void operator()(ChangePrimaryKey op) { ObjectStore::set_primary_key_for_object(group, op.object->name, op.property ? StringData{op.property->name} : ""); }
void operator()(AddIndex op) { table(op.object).add_search_index(op.property->table_column); }
void operator()(RemoveIndex op) { table(op.object).remove_search_index(op.property->table_column); }
void operator()(ChangePropertyType op) { replace_column(group, table(op.object), *op.old_property, *op.new_property); }
void operator()(ChangeRelationshipType op) { table(op.object).get_descriptor()->set_link_type(op.property->table_column, op.property->link_type()); }

void operator()(ChangePropertyType op)
{
replace_column(group, table(op.object), *op.old_property, *op.new_property);
}
} applier{group};

for (auto& change : changes) {
Expand Down Expand Up @@ -621,6 +635,7 @@ void ObjectStore::apply_additive_changes(Group& group, std::vector<SchemaChange>
void operator()(ChangePropertyType) { }
void operator()(MakePropertyNullable) { }
void operator()(MakePropertyRequired) { }
void operator()(ChangeRelationshipType) { }
} applier{group, update_indexes};

for (auto& change : changes) {
Expand All @@ -647,6 +662,8 @@ static void apply_pre_migration_changes(Group& group, std::vector<SchemaChange>
void operator()(ChangePrimaryKey op) { ObjectStore::set_primary_key_for_object(group, op.object->name.c_str(), op.property ? op.property->name.c_str() : ""); }
void operator()(AddIndex op) { table(op.object).add_search_index(op.property->table_column); }
void operator()(RemoveIndex op) { table(op.object).remove_search_index(op.property->table_column); }
void operator()(ChangeRelationshipType op) { table(op.object).get_descriptor()->set_link_type(op.property->table_column, op.property->link_type()); }

} applier{group};

for (auto& change : changes) {
Expand Down Expand Up @@ -704,6 +721,7 @@ static void apply_post_migration_changes(Group& group, std::vector<SchemaChange>
void operator()(MakePropertyNullable) { }
void operator()(MakePropertyRequired) { }
void operator()(AddProperty) { }
void operator()(ChangeRelationshipType) { }
} applier{group, initial_schema, did_reread_schema};

for (auto& change : changes) {
Expand Down Expand Up @@ -749,6 +767,7 @@ static void create_default_permissions(Group& group, std::vector<SchemaChange> c
void operator()(AddIndex) { }
void operator()(RemoveIndex) { }
void operator()(ChangePropertyType) { }
void operator()(ChangeRelationshipType) { }
} applier{group};

for (auto& change : changes) {
Expand Down Expand Up @@ -890,6 +909,7 @@ util::Optional<Property> ObjectStore::property_for_column_index(ConstTableRef& t
// set link type for objects and arrays
ConstTableRef linkTable = table->get_link_target(column_index);
property.object_type = ObjectStore::object_type_for_table_name(linkTable->get_name().data());
property.relationship = (table->get_link_type(column_index) == LinkType::link_Strong) ? Relationship::Strong : Relationship::Weak;
}
return property;
}
Expand Down
34 changes: 30 additions & 4 deletions src/property.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

#include "util/tagged_bool.hpp"

#include <realm/data_type.hpp>
#include <realm/util/features.h>

#include <string>
Expand Down Expand Up @@ -58,14 +59,22 @@ enum class PropertyType : unsigned char {
Flags = Nullable | Array
};

enum class Relationship : bool {
Strong = true,
Weak = false
};

struct Property {
using IsPrimary = util::TaggedBool<class IsPrimaryTag>;
using IsIndexed = util::TaggedBool<class IsIndexedTag>;

std::string name;
PropertyType type = PropertyType::Int;
std::string object_type;
std::string link_origin_property_name;
// Only used with LinkingObjects. `relationship` is ignored if this is different than ""
std::string link_origin_property_name = "";
// Only useful if the property is Link or LinkList property and `link_origin_property_name` is ""
Relationship relationship = Relationship::Weak;
IsPrimary is_primary = false;
IsIndexed is_indexed = false;

Expand All @@ -74,9 +83,8 @@ struct Property {
Property() = default;

Property(std::string name, PropertyType type, IsPrimary primary = false, IsIndexed indexed = false);

Property(std::string name, PropertyType type, std::string object_type,
std::string link_origin_property_name = "");
Property(std::string name, PropertyType type, std::string object_type, std::string link_origin_property_name = "");
Property(std::string name, PropertyType type, std::string object_type, Relationship relationship);

Property(Property const&) = default;
Property(Property&&) = default;
Expand All @@ -85,6 +93,14 @@ struct Property {

bool requires_index() const { return is_primary || is_indexed; }

// Return the underlying LinkType. Only useful for Object or Array properties.
LinkType link_type() const {
switch (relationship) {
case Relationship::Strong: return LinkType::link_Strong;
case Relationship::Weak: return LinkType::link_Weak;
}
}

bool type_is_indexable() const;
bool type_is_nullable() const;

Expand Down Expand Up @@ -214,6 +230,16 @@ inline Property::Property(std::string name, PropertyType type,
{
}

inline Property::Property(std::string name, PropertyType type,
std::string object_type,
Relationship relationship)
: name(std::move(name))
, type(type)
, object_type(std::move(object_type))
, relationship(relationship)
{
}

inline bool Property::type_is_indexable() const
{
return type == PropertyType::Int
Expand Down
4 changes: 4 additions & 0 deletions src/schema.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,9 @@ static void compare(ObjectSchema const& existing_schema,
else if (current_prop.requires_index()) {
changes.emplace_back(schema_change::RemoveIndex{&existing_schema, &current_prop});
}
if (target_prop->relationship != current_prop.relationship) {
changes.emplace_back(schema_change::ChangeRelationshipType{&existing_schema, &current_prop});
}
}

if (existing_schema.primary_key != target_schema.primary_key) {
Expand Down Expand Up @@ -262,6 +265,7 @@ bool operator==(SchemaChange const& lft, SchemaChange const& rgt)
REALM_SC_COMPARE(RemoveTable, v.object)
REALM_SC_COMPARE(ChangePrimaryKey, v.object, v.property)
REALM_SC_COMPARE(ChangePropertyType, v.object, v.old_property, v.new_property)
REALM_SC_COMPARE(ChangeRelationshipType, v.object, v.property)
REALM_SC_COMPARE(MakePropertyNullable, v.object, v.property)
REALM_SC_COMPARE(MakePropertyRequired, v.object, v.property)
REALM_SC_COMPARE(RemoveIndex, v.object, v.property)
Expand Down
6 changes: 6 additions & 0 deletions src/schema.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,11 @@ struct ChangePrimaryKey {
const ObjectSchema* object;
const Property* property;
};

struct ChangeRelationshipType {
const ObjectSchema* object;
const Property* property;
};
}

#define REALM_FOR_EACH_SCHEMA_CHANGE_TYPE(macro) \
Expand All @@ -144,6 +149,7 @@ struct ChangePrimaryKey {
macro(AddIndex) \
macro(RemoveIndex) \
macro(ChangePrimaryKey) \
macro(ChangeRelationshipType) \

class SchemaChange {
public:
Expand Down
27 changes: 25 additions & 2 deletions tests/migrations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,12 @@ Schema set_target(Schema schema, StringData object_name, StringData property_nam
return schema;
}

Schema set_relationship(Schema schema, StringData object_name, StringData property_name, Relationship new_relationship_type)
{
schema.find(object_name)->property_for_name(property_name)->relationship = new_relationship_type;
return schema;
}

Schema set_primary_key(Schema schema, StringData object_name, StringData new_primary_property)
{
auto& object_schema = *schema.find(object_name);
Expand Down Expand Up @@ -1735,7 +1741,7 @@ TEST_CASE("migration: Manual") {
{"link origin", {
{"not a pk", PropertyType::Int},
{"object", PropertyType::Object|PropertyType::Nullable, "object"},
{"array", PropertyType::Array|PropertyType::Object, "object"},
{"array", PropertyType::Array|PropertyType::Object, "object", Relationship::Strong},
}}
};
realm->update_schema(schema);
Expand Down Expand Up @@ -1814,7 +1820,7 @@ TEST_CASE("migration: Manual") {
[](SharedRealm, SharedRealm realm, Schema&) {
auto table = get_table(realm, "link origin");
table->remove_column(2);
table->add_column_link(type_LinkList, "array", *table);
table->add_column_link(type_LinkList, "array", *table, LinkType::link_Strong);
});
}
SECTION("make property optional") {
Expand Down Expand Up @@ -1873,4 +1879,21 @@ TEST_CASE("migration: Manual") {
Schema new_schema = remove_property(schema, "object", "value");
REQUIRE_THROWS_AS(realm->update_schema(new_schema, 1, nullptr), SchemaMismatchException);
}

SECTION("change relationship type from Weak to Strong") {
REQUIRE_MIGRATION(set_relationship(schema, "link origin", "object", Relationship::Strong),
[](SharedRealm, SharedRealm realm, Schema&) {
auto table = get_table(realm, "link origin");
table->get_descriptor()->set_link_type(1, LinkType::link_Strong);
});
}

SECTION("change relationship type from Strong to Weak") {
REQUIRE_MIGRATION(set_relationship(schema, "link origin", "array", Relationship::Weak),
[](SharedRealm, SharedRealm realm, Schema&) {
auto table = get_table(realm, "link origin");
table->get_descriptor()->set_link_type(2, LinkType::link_Weak);
});
}

}
1 change: 1 addition & 0 deletions tests/schema.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ struct SchemaChangePrinter {
REALM_SC_PRINT(AddInitialProperties, v.object)
REALM_SC_PRINT(ChangePrimaryKey, v.object, v.property)
REALM_SC_PRINT(ChangePropertyType, v.object, v.old_property, v.new_property)
REALM_SC_PRINT(ChangeRelationshipType, v.object, v.property)
REALM_SC_PRINT(MakePropertyNullable, v.object, v.property)
REALM_SC_PRINT(MakePropertyRequired, v.object, v.property)
REALM_SC_PRINT(RemoveIndex, v.object, v.property)
Expand Down