Add the linking objects property type.
This commit is contained in:
parent
abca7c26e1
commit
152697d199
|
@ -22,10 +22,13 @@
|
|||
#include "list.hpp"
|
||||
#include "object_schema.hpp"
|
||||
#include "object_store.hpp"
|
||||
#include "results.hpp"
|
||||
#include "schema.hpp"
|
||||
#include "shared_realm.hpp"
|
||||
#include "util/format.hpp"
|
||||
|
||||
#include <realm/link_view.hpp>
|
||||
#include <realm/table_view.hpp>
|
||||
|
||||
namespace realm {
|
||||
|
||||
|
@ -103,6 +106,8 @@ namespace realm {
|
|||
static ValueType list_value_at_index(ContextType ctx, ValueType &val, size_t index);
|
||||
static ValueType from_list(ContextType ctx, List);
|
||||
|
||||
static ValueType from_results(ContextType ctx, Results);
|
||||
|
||||
//
|
||||
// Deprecated
|
||||
//
|
||||
|
@ -125,8 +130,15 @@ namespace realm {
|
|||
const std::string property_name;
|
||||
};
|
||||
|
||||
class MutationOutsideTransactionException : public std::runtime_error
|
||||
{
|
||||
class ReadOnlyPropertyValueException : public std::runtime_error {
|
||||
public:
|
||||
ReadOnlyPropertyValueException(const std::string& object_type, const std::string& property_name, const std::string& message)
|
||||
: std::runtime_error(message), object_type(object_type), property_name(property_name) {}
|
||||
const std::string object_type;
|
||||
const std::string property_name;
|
||||
};
|
||||
|
||||
class MutationOutsideTransactionException : public std::runtime_error {
|
||||
public:
|
||||
MutationOutsideTransactionException(std::string message) : std::runtime_error(message) {}
|
||||
};
|
||||
|
@ -217,6 +229,10 @@ namespace realm {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case PropertyType::LinkingObjects:
|
||||
throw ReadOnlyPropertyValueException(m_object_schema->name, property.name,
|
||||
util::format("Cannot modify read-only property '%1.%2'",
|
||||
m_object_schema->name, property.name));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -259,6 +275,14 @@ namespace realm {
|
|||
auto arrayObjectSchema = m_realm->config().schema->find(property.object_type);
|
||||
return Accessor::from_list(ctx, std::move(List(m_realm, *arrayObjectSchema, static_cast<LinkViewRef>(m_row.get_linklist(column)))));
|
||||
}
|
||||
case PropertyType::LinkingObjects: {
|
||||
auto target_object_schema = m_realm->config().schema->find(property.object_type);
|
||||
auto link_property = target_object_schema->property_for_name(property.link_origin_property_name);
|
||||
TableRef table = ObjectStore::table_for_object_type(m_realm->read_group(), target_object_schema->name);
|
||||
auto tv = m_row.get_table()->get_backlink_view(m_row.get_index(), table.get(), link_property->table_column);
|
||||
Results results(m_realm, *m_object_schema, std::move(tv), {});
|
||||
return Accessor::from_results(ctx, std::move(results));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -303,7 +327,7 @@ namespace realm {
|
|||
|
||||
// populate
|
||||
Object object(realm, object_schema, table->get(row_index));
|
||||
for (const Property &prop : object_schema.properties) {
|
||||
for (const Property& prop : object_schema.persisted_properties) {
|
||||
if (created || !prop.is_primary) {
|
||||
if (Accessor::dict_has_value_for_key(ctx, value, prop.name)) {
|
||||
object.set_property_value_impl(ctx, prop, Accessor::dict_value_for_key(ctx, value, prop.name), try_update);
|
||||
|
|
|
@ -565,11 +565,24 @@ MissingPropertyException::MissingPropertyException(std::string const& object_typ
|
|||
InvalidNullabilityException::InvalidNullabilityException(std::string const& object_type, Property const& property) :
|
||||
ObjectSchemaPropertyException(object_type, property)
|
||||
{
|
||||
if (property.type == PropertyType::Object) {
|
||||
switch (property.type) {
|
||||
case PropertyType::Object:
|
||||
m_what = util::format("'Object' property '%1' must be nullable.", property.name);
|
||||
}
|
||||
else {
|
||||
m_what = util::format("Array or Mixed property '%1' cannot be nullable", property.name);
|
||||
break;
|
||||
case PropertyType::Any:
|
||||
case PropertyType::Array:
|
||||
case PropertyType::LinkingObjects:
|
||||
m_what = util::format("Property '%1' of type '%2' cannoy be nullable",
|
||||
property.name, string_for_property_type(property.type));
|
||||
break;
|
||||
case PropertyType::Int:
|
||||
case PropertyType::Bool:
|
||||
case PropertyType::Data:
|
||||
case PropertyType::Date:
|
||||
case PropertyType::Float:
|
||||
case PropertyType::Double:
|
||||
case PropertyType::String:
|
||||
REALM_ASSERT(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -627,3 +640,24 @@ DuplicatePrimaryKeysException::DuplicatePrimaryKeysException(std::string const&
|
|||
m_what = util::format("Duplicate primary keys for object '%1'.", object_type);
|
||||
}
|
||||
|
||||
InvalidLinkingObjectsPropertyException::InvalidLinkingObjectsPropertyException(Type error_type, std::string const& object_type, Property const& property)
|
||||
: ObjectSchemaPropertyException(object_type, property)
|
||||
{
|
||||
switch (error_type) {
|
||||
case Type::OriginPropertyDoesNotExist:
|
||||
m_what = util::format("Property '%1.%2' declared as origin of linking objects property '%3.%4' does not exist",
|
||||
property.object_type, property.link_origin_property_name,
|
||||
object_type, property.name);
|
||||
break;
|
||||
case Type::OriginPropertyIsNotALink:
|
||||
m_what = util::format("Property '%1.%2' declared as origin of linking objects property '%3.%4' is not a link",
|
||||
property.object_type, property.link_origin_property_name,
|
||||
object_type, property.name);
|
||||
break;
|
||||
case Type::OriginPropertyInvalidLinkTarget:
|
||||
m_what = util::format("Property '%1.%2' declared as origin of linking objects property '%3.%4' links to a different class",
|
||||
property.object_type, property.link_origin_property_name,
|
||||
object_type, property.name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -240,6 +240,16 @@ namespace realm {
|
|||
private:
|
||||
std::string m_primary_key;
|
||||
};
|
||||
|
||||
class InvalidLinkingObjectsPropertyException : public ObjectSchemaPropertyException {
|
||||
public:
|
||||
enum class Type {
|
||||
OriginPropertyDoesNotExist,
|
||||
OriginPropertyIsNotALink,
|
||||
OriginPropertyInvalidLinkTarget,
|
||||
};
|
||||
InvalidLinkingObjectsPropertyException(Type error_type, std::string const& object_type, Property const& property);
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* defined(REALM_OBJECT_STORE_HPP) */
|
||||
|
|
|
@ -33,12 +33,14 @@ namespace realm {
|
|||
Date = 8,
|
||||
Object = 12,
|
||||
Array = 13,
|
||||
LinkingObjects = 14,
|
||||
};
|
||||
|
||||
struct Property {
|
||||
std::string name;
|
||||
PropertyType type;
|
||||
std::string object_type;
|
||||
std::string link_origin_property_name;
|
||||
bool is_primary = false;
|
||||
bool is_indexed = false;
|
||||
bool is_nullable = false;
|
||||
|
@ -55,11 +57,13 @@ namespace realm {
|
|||
|
||||
#if __GNUC__ < 5
|
||||
// GCC 4.9 does not support C++14 braced-init with NSDMIs
|
||||
Property(std::string name="", PropertyType type=PropertyType::Int, std::string object_type="",
|
||||
Property(std::string name="", PropertyType type=PropertyType::Int,
|
||||
std::string object_type="", std::string link_origin_property_name="",
|
||||
bool is_primary=false, bool is_indexed=false, bool is_nullable=false)
|
||||
: name(std::move(name))
|
||||
, type(type)
|
||||
, object_type(std::move(object_type))
|
||||
, link_origin_property_name(std::move(link_origin_property_name))
|
||||
, is_primary(is_primary)
|
||||
, is_indexed(is_indexed)
|
||||
, is_nullable(is_nullable)
|
||||
|
|
|
@ -72,13 +72,36 @@ void Schema::validate() const
|
|||
|
||||
for (auto const& prop : all_properties) {
|
||||
// check object_type existence
|
||||
if (!prop.object_type.empty() && find(prop.object_type) == end()) {
|
||||
if (!prop.object_type.empty()) {
|
||||
auto it = find(prop.object_type);
|
||||
if (it == end()) {
|
||||
exceptions.emplace_back(MissingObjectTypeException(object.name, prop));
|
||||
}
|
||||
// validate linking objects property.
|
||||
else if (!prop.link_origin_property_name.empty()) {
|
||||
using ErrorType = InvalidLinkingObjectsPropertyException::Type;
|
||||
util::Optional<ErrorType> error;
|
||||
|
||||
const Property *origin_property = it->property_for_name(prop.link_origin_property_name);
|
||||
if (!origin_property) {
|
||||
error = ErrorType::OriginPropertyDoesNotExist;
|
||||
}
|
||||
else if (origin_property->type != PropertyType::Object && origin_property->type != PropertyType::Array) {
|
||||
error = ErrorType::OriginPropertyIsNotALink;
|
||||
}
|
||||
else if (origin_property->object_type != object.name) {
|
||||
error = ErrorType::OriginPropertyInvalidLinkTarget;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
exceptions.emplace_back(InvalidLinkingObjectsPropertyException(*error, object.name, prop));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check nullablity
|
||||
if (prop.is_nullable) {
|
||||
if (prop.type == PropertyType::Array || prop.type == PropertyType::Any) {
|
||||
if (prop.type == PropertyType::Array || prop.type == PropertyType::Any || prop.type == PropertyType::LinkingObjects) {
|
||||
exceptions.emplace_back(InvalidNullabilityException(object.name, prop));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,13 +24,13 @@ TEST_CASE("[results] notifications") {
|
|||
config.schema = std::make_unique<Schema>(Schema{
|
||||
{"object", "", {
|
||||
{"value", PropertyType::Int},
|
||||
{"link", PropertyType::Object, "linked to object", false, false, true}
|
||||
{"link", PropertyType::Object, "linked to object", "", false, false, true}
|
||||
}},
|
||||
{"other object", "", {
|
||||
{"value", PropertyType::Int}
|
||||
}},
|
||||
{"linking object", "", {
|
||||
{"link", PropertyType::Object, "object", false, false, true}
|
||||
{"link", PropertyType::Object, "object", "", false, false, true}
|
||||
}},
|
||||
{"linked to object", "", {
|
||||
{"value", PropertyType::Int}
|
||||
|
|
|
@ -114,7 +114,7 @@ TEST_CASE("Transaction log parsing") {
|
|||
config.schema = std::make_unique<Schema>(Schema{
|
||||
{"table", "", {
|
||||
{"unindexed", PropertyType::Int},
|
||||
{"indexed", PropertyType::Int, "", false, true}
|
||||
{"indexed", PropertyType::Int, "", "", false, true}
|
||||
}},
|
||||
});
|
||||
auto r = Realm::get_shared_realm(config);
|
||||
|
@ -807,7 +807,7 @@ TEST_CASE("DeepChangeChecker") {
|
|||
config.schema = std::make_unique<Schema>(Schema{
|
||||
{"table", "", {
|
||||
{"int", PropertyType::Int},
|
||||
{"link", PropertyType::Object, "table", false, false, true},
|
||||
{"link", PropertyType::Object, "table", "", false, false, true},
|
||||
{"array", PropertyType::Array, "table"}
|
||||
}},
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue