Merge pull request #9 from realm/al-accessors
Accessor classes for Object and List
This commit is contained in:
commit
028ed2a4c2
|
@ -18,25 +18,23 @@
|
|||
|
||||
#include "transact_log_handler.hpp"
|
||||
|
||||
#include "../realm_binding_context.hpp"
|
||||
#include "../binding_context.hpp"
|
||||
|
||||
#include <realm/commit_log.hpp>
|
||||
#include <realm/group_shared.hpp>
|
||||
#include <realm/lang_bind_helper.hpp>
|
||||
|
||||
using namespace realm;
|
||||
|
||||
namespace {
|
||||
namespace realm {
|
||||
class TransactLogHandler {
|
||||
using ColumnInfo = RealmBindingContext::ColumnInfo;
|
||||
using ObserverState = RealmBindingContext::ObserverState;
|
||||
using ColumnInfo = BindingContext::ColumnInfo;
|
||||
using ObserverState = BindingContext::ObserverState;
|
||||
|
||||
// Observed table rows which need change information
|
||||
std::vector<ObserverState> m_observers;
|
||||
// Userdata pointers for rows which have been deleted
|
||||
std::vector<void *> invalidated;
|
||||
// Delegate to send change information to
|
||||
RealmBindingContext* m_binding_context;
|
||||
BindingContext* m_binding_context;
|
||||
|
||||
// Index of currently selected table
|
||||
size_t m_current_table = 0;
|
||||
|
@ -84,7 +82,7 @@ class TransactLogHandler {
|
|||
|
||||
public:
|
||||
template<typename Func>
|
||||
TransactLogHandler(RealmBindingContext* binding_context, SharedGroup& sg, Func&& func)
|
||||
TransactLogHandler(BindingContext* binding_context, SharedGroup& sg, Func&& func)
|
||||
: m_binding_context(binding_context)
|
||||
{
|
||||
if (!binding_context) {
|
||||
|
@ -325,19 +323,19 @@ public:
|
|||
namespace realm {
|
||||
namespace _impl {
|
||||
namespace transaction {
|
||||
void advance(SharedGroup& sg, ClientHistory& history, RealmBindingContext* binding_context) {
|
||||
void advance(SharedGroup& sg, ClientHistory& history, BindingContext* binding_context) {
|
||||
TransactLogHandler(binding_context, sg, [&](auto&&... args) {
|
||||
LangBindHelper::advance_read(sg, history, std::move(args)...);
|
||||
});
|
||||
}
|
||||
|
||||
void begin(SharedGroup& sg, ClientHistory& history, RealmBindingContext* binding_context) {
|
||||
void begin(SharedGroup& sg, ClientHistory& history, BindingContext* binding_context) {
|
||||
TransactLogHandler(binding_context, sg, [&](auto&&... args) {
|
||||
LangBindHelper::promote_to_write(sg, history, std::move(args)...);
|
||||
});
|
||||
}
|
||||
|
||||
void commit(SharedGroup& sg, ClientHistory&, RealmBindingContext* binding_context) {
|
||||
void commit(SharedGroup& sg, ClientHistory&, BindingContext* binding_context) {
|
||||
LangBindHelper::commit_and_continue_as_read(sg);
|
||||
|
||||
if (binding_context) {
|
||||
|
@ -345,7 +343,7 @@ void commit(SharedGroup& sg, ClientHistory&, RealmBindingContext* binding_contex
|
|||
}
|
||||
}
|
||||
|
||||
void cancel(SharedGroup& sg, ClientHistory& history, RealmBindingContext* binding_context) {
|
||||
void cancel(SharedGroup& sg, ClientHistory& history, BindingContext* binding_context) {
|
||||
TransactLogHandler(binding_context, sg, [&](auto&&... args) {
|
||||
LangBindHelper::rollback_and_continue_as_read(sg, history, std::move(args)...);
|
||||
});
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
#define REALM_TRANSACT_LOG_HANDLER_HPP
|
||||
|
||||
namespace realm {
|
||||
class RealmBindingContext;
|
||||
class BindingContext;
|
||||
class SharedGroup;
|
||||
class ClientHistory;
|
||||
|
||||
|
@ -28,19 +28,19 @@ namespace _impl {
|
|||
namespace transaction {
|
||||
// Advance the read transaction version, with change notifications sent to delegate
|
||||
// Must not be called from within a write transaction.
|
||||
void advance(SharedGroup& sg, ClientHistory& history, RealmBindingContext* binding_context);
|
||||
void advance(SharedGroup& sg, ClientHistory& history, BindingContext* binding_context);
|
||||
|
||||
// Begin a write transaction
|
||||
// If the read transaction version is not up to date, will first advance to the
|
||||
// most recent read transaction and sent notifications to delegate
|
||||
void begin(SharedGroup& sg, ClientHistory& history, RealmBindingContext* binding_context);
|
||||
void begin(SharedGroup& sg, ClientHistory& history, BindingContext* binding_context);
|
||||
|
||||
// Commit a write transaction
|
||||
void commit(SharedGroup& sg, ClientHistory& history, RealmBindingContext* binding_context);
|
||||
void commit(SharedGroup& sg, ClientHistory& history, BindingContext* binding_context);
|
||||
|
||||
// Cancel a write transaction and roll back all changes, with change notifications
|
||||
// for reverting to the old values sent to delegate
|
||||
void cancel(SharedGroup& sg, ClientHistory& history, RealmBindingContext* binding_context);
|
||||
void cancel(SharedGroup& sg, ClientHistory& history, BindingContext* binding_context);
|
||||
} // namespace transaction
|
||||
} // namespace _impl
|
||||
} // namespace realm
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright 2015 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 "list.hpp"
|
||||
#import <stdexcept>
|
||||
|
||||
using namespace realm;
|
||||
|
||||
size_t List::size() {
|
||||
verify_attached();
|
||||
return m_link_view->size();
|
||||
}
|
||||
|
||||
Row List::get(std::size_t row_ndx) {
|
||||
verify_attached();
|
||||
verify_valid_row(row_ndx);
|
||||
return m_link_view->get(row_ndx);
|
||||
}
|
||||
|
||||
void List::set(std::size_t row_ndx, std::size_t target_row_ndx) {
|
||||
verify_attached();
|
||||
verify_in_tranaction();
|
||||
verify_valid_row(row_ndx);
|
||||
m_link_view->set(row_ndx, target_row_ndx);
|
||||
}
|
||||
|
||||
void List::add(std::size_t target_row_ndx) {
|
||||
verify_attached();
|
||||
verify_in_tranaction();
|
||||
m_link_view->add(target_row_ndx);
|
||||
}
|
||||
|
||||
void List::insert(std::size_t row_ndx, std::size_t target_row_ndx) {
|
||||
verify_attached();
|
||||
verify_in_tranaction();
|
||||
verify_valid_row(row_ndx, true);
|
||||
m_link_view->insert(row_ndx, target_row_ndx);
|
||||
}
|
||||
|
||||
void List::remove(std::size_t row_ndx) {
|
||||
verify_attached();
|
||||
verify_in_tranaction();
|
||||
verify_valid_row(row_ndx);
|
||||
m_link_view->remove(row_ndx);
|
||||
}
|
||||
|
||||
void List::verify_valid_row(std::size_t row_ndx, bool insertion) {
|
||||
size_t size = m_link_view->size();
|
||||
if (row_ndx > size || (!insertion && row_ndx == size)) {
|
||||
throw std::out_of_range(std::string("Index ") + std::to_string(row_ndx) + " is outside of range 0..." + std::to_string(size) + ".");
|
||||
}
|
||||
}
|
||||
|
||||
void List::verify_attached() {
|
||||
if (!m_link_view->is_attached()) {
|
||||
throw std::runtime_error("Tableview is not attached");
|
||||
}
|
||||
m_link_view->sync_if_needed();
|
||||
}
|
||||
|
||||
void List::verify_in_tranaction() {
|
||||
if (!m_realm->is_in_transaction()) {
|
||||
throw std::runtime_error("Can only mutate a list within a transaction.");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright 2015 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.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef REALM_LIST_HPP
|
||||
#define REALM_LIST_HPP
|
||||
|
||||
#import "shared_realm.hpp"
|
||||
#import <realm/link_view.hpp>
|
||||
|
||||
namespace realm {
|
||||
class List {
|
||||
public:
|
||||
List(SharedRealm &r, const ObjectSchema &s, LinkViewRef l) : m_realm(r), object_schema(s), m_link_view(l) {}
|
||||
|
||||
const ObjectSchema &object_schema;
|
||||
SharedRealm realm() { return m_realm; }
|
||||
|
||||
size_t size();
|
||||
Row get(std::size_t row_ndx);
|
||||
void set(std::size_t row_ndx, std::size_t target_row_ndx);
|
||||
|
||||
void add(size_t target_row_ndx);
|
||||
void remove(size_t list_ndx);
|
||||
void insert(size_t list_ndx, size_t target_row_ndx);
|
||||
|
||||
template<typename ValueType, typename ContextType>
|
||||
void add(ContextType ctx, ValueType value);
|
||||
|
||||
template<typename ValueType, typename ContextType>
|
||||
void insert(ContextType ctx, ValueType value, size_t list_ndx);
|
||||
|
||||
template<typename ValueType, typename ContextType>
|
||||
void set(ContextType ctx, ValueType value, size_t list_ndx);
|
||||
|
||||
void verify_valid_row(std::size_t row_ndx, bool insertion = false);
|
||||
void verify_attached();
|
||||
void verify_in_tranaction();
|
||||
|
||||
private:
|
||||
SharedRealm m_realm;
|
||||
LinkViewRef m_link_view;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif /* REALM_LIST_HPP */
|
|
@ -0,0 +1,323 @@
|
|||
/* Copyright 2015 Realm Inc - All Rights Reserved
|
||||
* Proprietary and Confidential
|
||||
*/
|
||||
|
||||
#ifndef REALM_OBJECT_ACCESSOR_HPP
|
||||
#define REALM_OBJECT_ACCESSOR_HPP
|
||||
|
||||
#include <string>
|
||||
#include "shared_realm.hpp"
|
||||
#include "list.hpp"
|
||||
|
||||
namespace realm {
|
||||
|
||||
class Object {
|
||||
public:
|
||||
Object(SharedRealm r, const ObjectSchema &s, Row o) : m_realm(r), object_schema(s), m_row(o) {}
|
||||
|
||||
// property getter/setter
|
||||
template<typename ValueType, typename ContextType>
|
||||
inline void set_property_value(ContextType ctx, std::string prop_name, ValueType value, bool try_update);
|
||||
|
||||
template<typename ValueType, typename ContextType>
|
||||
inline ValueType get_property_value(ContextType ctx, std::string prop_name);
|
||||
|
||||
// create an Object from a native representation
|
||||
template<typename ValueType, typename ContextType>
|
||||
static inline Object create(ContextType ctx, SharedRealm realm, ObjectSchema &object_schema, ValueType value, bool try_update);
|
||||
|
||||
const ObjectSchema &object_schema;
|
||||
SharedRealm realm() { return m_realm; }
|
||||
Row row() { return m_row; }
|
||||
|
||||
private:
|
||||
SharedRealm m_realm;
|
||||
Row m_row;
|
||||
|
||||
template<typename ValueType, typename ContextType>
|
||||
inline void set_property_value_impl(ContextType ctx, const Property &property, ValueType value, bool try_update);
|
||||
template<typename ValueType, typename ContextType>
|
||||
inline ValueType get_property_value_impl(ContextType ctx, const Property &property);
|
||||
};
|
||||
|
||||
//
|
||||
// Value converters - template specializations must be implemented for each platform in order to call templated methods on Object
|
||||
//
|
||||
template<typename ValueType, typename ContextType>
|
||||
class NativeAccessor {
|
||||
public:
|
||||
static bool dict_has_value_for_key(ContextType ctx, ValueType dict, const std::string &prop_name);
|
||||
static ValueType dict_value_for_key(ContextType ctx, ValueType dict, const std::string &prop_name);
|
||||
|
||||
static bool has_default_value_for_property(ContextType ctx, Realm *realm, const ObjectSchema &object_schema, const std::string &prop_name);
|
||||
static ValueType default_value_for_property(ContextType ctx, Realm *realm, const ObjectSchema &object_schema, const std::string &prop_name);
|
||||
|
||||
static bool to_bool(ContextType, ValueType &);
|
||||
static ValueType from_bool(ContextType, bool);
|
||||
static long long to_long(ContextType, ValueType &);
|
||||
static ValueType from_long(ContextType, long long);
|
||||
static float to_float(ContextType, ValueType &);
|
||||
static ValueType from_float(ContextType, float);
|
||||
static double to_double(ContextType, ValueType &);
|
||||
static ValueType from_double(ContextType, double);
|
||||
static std::string to_string(ContextType, ValueType &);
|
||||
static ValueType from_string(ContextType, StringData);
|
||||
static std::string to_binary(ContextType, ValueType &);
|
||||
static ValueType from_binary(ContextType, BinaryData);
|
||||
static DateTime to_datetime(ContextType, ValueType &);
|
||||
static ValueType from_datetime(ContextType, DateTime);
|
||||
|
||||
static bool is_null(ContextType, ValueType &);
|
||||
static ValueType null_value(ContextType);
|
||||
|
||||
// convert value to persisted object
|
||||
// for existing objects return the existing row index
|
||||
// for new/updated objects return the row index
|
||||
static size_t to_object_index(ContextType ctx, SharedRealm realm, ValueType &val, const std::string &type, bool try_update);
|
||||
static ValueType from_object(ContextType ctx, Object);
|
||||
|
||||
// list value acessors
|
||||
static size_t list_size(ContextType ctx, ValueType &val);
|
||||
static ValueType list_value_at_index(ContextType ctx, ValueType &val, size_t index);
|
||||
static ValueType from_list(ContextType ctx, List);
|
||||
|
||||
//
|
||||
// Deprecated
|
||||
//
|
||||
static Mixed to_mixed(ContextType ctx, ValueType &val) { throw std::runtime_error("'Any' type is unsupported"); }
|
||||
};
|
||||
|
||||
class InvalidPropertyException : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
InvalidPropertyException(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 MissingPropertyValueException : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
MissingPropertyValueException(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) {}
|
||||
};
|
||||
|
||||
//
|
||||
// template method implementations
|
||||
//
|
||||
template <typename ValueType, typename ContextType>
|
||||
inline void Object::set_property_value(ContextType ctx, std::string prop_name, ValueType value, bool try_update)
|
||||
{
|
||||
const Property *prop = object_schema.property_for_name(prop_name);
|
||||
if (!prop) {
|
||||
throw InvalidPropertyException(object_schema.name, prop_name,
|
||||
"Setting invalid property '" + prop_name + "' on object '" + object_schema.name + "'.");
|
||||
}
|
||||
set_property_value_impl(ctx, *prop, value, try_update);
|
||||
};
|
||||
|
||||
template <typename ValueType, typename ContextType>
|
||||
inline ValueType Object::get_property_value(ContextType ctx, std::string prop_name)
|
||||
{
|
||||
const Property *prop = object_schema.property_for_name(prop_name);
|
||||
if (!prop) {
|
||||
throw InvalidPropertyException(object_schema.name, prop_name,
|
||||
"Getting invalid property '" + prop_name + "' on object '" + object_schema.name + "'.");
|
||||
}
|
||||
return get_property_value_impl<ValueType>(ctx, *prop);
|
||||
};
|
||||
|
||||
template <typename ValueType, typename ContextType>
|
||||
inline void Object::set_property_value_impl(ContextType ctx, const Property &property, ValueType value, bool try_update)
|
||||
{
|
||||
using Accessor = NativeAccessor<ValueType, ContextType>;
|
||||
|
||||
if (!m_realm->is_in_transaction()) {
|
||||
throw MutationOutsideTransactionException("Can only set property values within a transaction.");
|
||||
}
|
||||
|
||||
size_t column = property.table_column;
|
||||
if (property.is_nullable && Accessor::is_null(ctx, value)) {
|
||||
m_row.set_null(column);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (property.type) {
|
||||
case PropertyTypeBool:
|
||||
m_row.set_bool(column, Accessor::to_bool(ctx, value));
|
||||
break;
|
||||
case PropertyTypeInt:
|
||||
m_row.set_int(column, Accessor::to_long(ctx, value));
|
||||
break;
|
||||
case PropertyTypeFloat:
|
||||
m_row.set_float(column, Accessor::to_float(ctx, value));
|
||||
break;
|
||||
case PropertyTypeDouble:
|
||||
m_row.set_double(column, Accessor::to_double(ctx, value));
|
||||
break;
|
||||
case PropertyTypeString:
|
||||
m_row.set_string(column, Accessor::to_string(ctx, value));
|
||||
break;
|
||||
case PropertyTypeData:
|
||||
m_row.set_binary(column, BinaryData(Accessor::to_binary(ctx, value)));
|
||||
break;
|
||||
case PropertyTypeAny:
|
||||
m_row.set_mixed(column, Accessor::to_mixed(ctx, value));
|
||||
break;
|
||||
case PropertyTypeDate:
|
||||
m_row.set_datetime(column, Accessor::to_datetime(ctx, value));
|
||||
break;
|
||||
case PropertyTypeObject: {
|
||||
if (Accessor::is_null(ctx, value)) {
|
||||
m_row.nullify_link(column);
|
||||
}
|
||||
else {
|
||||
m_row.set_link(column, Accessor::to_object_index(ctx, m_realm, value, property.object_type, try_update));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PropertyTypeArray: {
|
||||
realm::LinkViewRef link_view = m_row.get_linklist(column);
|
||||
link_view->clear();
|
||||
size_t count = Accessor::list_size(ctx, value);
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
ValueType element = Accessor::list_value_at_index(ctx, value, i);
|
||||
link_view->add(Accessor::to_object_index(ctx, m_realm, element, property.object_type, try_update));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ValueType, typename ContextType>
|
||||
inline ValueType Object::get_property_value_impl(ContextType ctx, const Property &property)
|
||||
{
|
||||
using Accessor = NativeAccessor<ValueType, ContextType>;
|
||||
|
||||
size_t column = property.table_column;
|
||||
if (property.is_nullable && m_row.is_null(column)) {
|
||||
return Accessor::null_value(ctx);
|
||||
}
|
||||
|
||||
switch (property.type) {
|
||||
case PropertyTypeBool:
|
||||
return Accessor::from_bool(ctx, m_row.get_bool(column));
|
||||
case PropertyTypeInt:
|
||||
return Accessor::from_long(ctx, m_row.get_int(column));
|
||||
case PropertyTypeFloat:
|
||||
return Accessor::from_float(ctx, m_row.get_float(column));
|
||||
case PropertyTypeDouble:
|
||||
return Accessor::from_double(ctx, m_row.get_double(column));
|
||||
case PropertyTypeString:
|
||||
return Accessor::from_string(ctx, m_row.get_string(column));
|
||||
case PropertyTypeData:
|
||||
return Accessor::from_binary(ctx, m_row.get_binary(column));
|
||||
case PropertyTypeAny:
|
||||
throw "Any not supported";
|
||||
case PropertyTypeDate:
|
||||
return Accessor::from_datetime(ctx, m_row.get_datetime(column));
|
||||
case PropertyTypeObject: {
|
||||
auto linkObjectSchema = m_realm->config().schema->find(property.object_type);
|
||||
TableRef table = ObjectStore::table_for_object_type(m_realm->read_group(), linkObjectSchema->name);
|
||||
if (m_row.is_null_link(property.table_column)) {
|
||||
return Accessor::null_value(ctx);
|
||||
}
|
||||
return Accessor::from_object(ctx, std::move(Object(m_realm, *linkObjectSchema, table->get(m_row.get_link(column)))));
|
||||
}
|
||||
case PropertyTypeArray: {
|
||||
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)))));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename ValueType, typename ContextType>
|
||||
inline Object Object::create(ContextType ctx, SharedRealm realm, ObjectSchema &object_schema, ValueType value, bool try_update)
|
||||
{
|
||||
using Accessor = NativeAccessor<ValueType, ContextType>;
|
||||
|
||||
if (!realm->is_in_transaction()) {
|
||||
throw MutationOutsideTransactionException("Can only create objects within a transaction.");
|
||||
}
|
||||
|
||||
// get or create our accessor
|
||||
bool created;
|
||||
|
||||
// try to get existing row if updating
|
||||
size_t row_index = realm::not_found;
|
||||
realm::TableRef table = ObjectStore::table_for_object_type(realm->read_group(), object_schema.name);
|
||||
const Property *primary_prop = object_schema.primary_key_property();
|
||||
if (primary_prop) {
|
||||
// search for existing object based on primary key type
|
||||
ValueType primary_value = Accessor::dict_value_for_key(ctx, value, object_schema.primary_key);
|
||||
if (primary_prop->type == PropertyTypeString) {
|
||||
row_index = table->find_first_string(primary_prop->table_column, Accessor::to_string(ctx, primary_value));
|
||||
}
|
||||
else {
|
||||
row_index = table->find_first_int(primary_prop->table_column, Accessor::to_long(ctx, primary_value));
|
||||
}
|
||||
|
||||
if (!try_update && row_index != realm::not_found) {
|
||||
throw DuplicatePrimaryKeyValueException(object_schema.name, *primary_prop,
|
||||
"Attempting to create an object of type '" + object_schema.name + "' with an exising primary key value.");
|
||||
}
|
||||
}
|
||||
|
||||
// if no existing, create row
|
||||
created = false;
|
||||
if (row_index == realm::not_found) {
|
||||
row_index = table->add_empty_row();
|
||||
created = true;
|
||||
}
|
||||
|
||||
// populate
|
||||
Object object(realm, object_schema, table->get(row_index));
|
||||
for (Property &prop : object_schema.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);
|
||||
}
|
||||
else if (created) {
|
||||
if (Accessor::has_default_value_for_property(ctx, realm.get(), object_schema, prop.name)) {
|
||||
object.set_property_value_impl(ctx, prop, Accessor::default_value_for_property(ctx, realm.get(), object_schema, prop.name), try_update);
|
||||
}
|
||||
else {
|
||||
throw MissingPropertyValueException(object_schema.name, prop.name,
|
||||
"Missing property value for property " + prop.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
//
|
||||
// List implementation
|
||||
//
|
||||
template<typename ValueType, typename ContextType>
|
||||
void List::add(ContextType ctx, ValueType value)
|
||||
{
|
||||
add(NativeAccessor<ValueType, ContextType>::to_object_index(ctx, m_realm, value, object_schema.name, false));
|
||||
}
|
||||
|
||||
template<typename ValueType, typename ContextType>
|
||||
void List::insert(ContextType ctx, ValueType value, size_t list_ndx)
|
||||
{
|
||||
insert(list_ndx, NativeAccessor<ValueType, ContextType>::to_object_index(ctx, m_realm, value, object_schema.name, false));
|
||||
}
|
||||
|
||||
template<typename ValueType, typename ContextType>
|
||||
void List::set(ContextType ctx, ValueType value, size_t list_ndx)
|
||||
{
|
||||
set(list_ndx, NativeAccessor<ValueType, ContextType>::to_object_index(ctx, m_realm, value, object_schema.name, false));
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* defined(REALM_OBJECT_ACCESSOR_HPP) */
|
|
@ -25,6 +25,7 @@
|
|||
#include <vector>
|
||||
|
||||
namespace realm {
|
||||
class Property;
|
||||
class Group;
|
||||
struct Property;
|
||||
|
||||
|
|
|
@ -328,6 +328,7 @@ bool ObjectStore::create_tables(Group *group, Schema &target_schema, bool update
|
|||
case PropertyTypeObject:
|
||||
case PropertyTypeArray: {
|
||||
TableRef link_table = ObjectStore::table_for_object_type(group, target_prop.object_type);
|
||||
REALM_ASSERT(link_table);
|
||||
target_prop.table_column = table->add_column_link(DataType(target_prop.type), target_prop.name, *link_table);
|
||||
break;
|
||||
}
|
||||
|
@ -525,8 +526,12 @@ DuplicatePrimaryKeyValueException::DuplicatePrimaryKeyValueException(std::string
|
|||
m_object_type(object_type), m_property(property)
|
||||
{
|
||||
m_what = "Primary key property '" + property.name + "' has duplicate values after migration.";
|
||||
};
|
||||
}
|
||||
|
||||
DuplicatePrimaryKeyValueException::DuplicatePrimaryKeyValueException(std::string const& object_type, Property const& property, const std::string message) : m_object_type(object_type), m_property(property)
|
||||
{
|
||||
m_what = message;
|
||||
}
|
||||
|
||||
SchemaValidationException::SchemaValidationException(std::vector<ObjectSchemaValidationException> const& errors) :
|
||||
m_validation_errors(errors)
|
||||
|
@ -607,3 +612,4 @@ DuplicatePrimaryKeysException::DuplicatePrimaryKeysException(std::string const&
|
|||
{
|
||||
m_what = "Duplicate primary keys for object '" + object_type + "'.";
|
||||
}
|
||||
|
||||
|
|
|
@ -140,6 +140,8 @@ namespace realm {
|
|||
class DuplicatePrimaryKeyValueException : public MigrationException {
|
||||
public:
|
||||
DuplicatePrimaryKeyValueException(std::string const& object_type, Property const& property);
|
||||
DuplicatePrimaryKeyValueException(std::string const& object_type, Property const& property, const std::string message);
|
||||
|
||||
std::string object_type() const { return m_object_type; }
|
||||
Property const& property() const { return m_property; }
|
||||
private:
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
/* Copyright 2015 Realm Inc - All Rights Reserved
|
||||
* Proprietary and Confidential
|
||||
*/
|
||||
|
||||
#include "results.hpp"
|
||||
#import <stdexcept>
|
||||
|
||||
using namespace realm;
|
||||
|
||||
Results::Results(SharedRealm &r, ObjectSchema &o, Query q, SortOrder s) :
|
||||
realm(r), object_schema(o), backing_query(q), table_view(backing_query.find_all())
|
||||
{
|
||||
setSort(std::move(s));
|
||||
}
|
||||
|
||||
size_t Results::size()
|
||||
{
|
||||
verify_attached();
|
||||
return table_view.size();
|
||||
}
|
||||
|
||||
void Results::setSort(SortOrder s)
|
||||
{
|
||||
sort_order = std::make_unique<SortOrder>(std::move(s));
|
||||
table_view.sort(sort_order->columnIndices, sort_order->ascending);
|
||||
}
|
||||
|
||||
Row Results::get(std::size_t row_ndx)
|
||||
{
|
||||
verify_attached();
|
||||
if (row_ndx >= table_view.size()) {
|
||||
throw std::out_of_range(std::string("Index ") + std::to_string(row_ndx) + " is outside of range 0..." +
|
||||
std::to_string(table_view.size()) + ".");
|
||||
}
|
||||
return table_view.get(row_ndx);
|
||||
}
|
||||
|
||||
void Results::verify_attached()
|
||||
{
|
||||
if (!table_view.is_attached()) {
|
||||
throw std::runtime_error("Tableview is not attached");
|
||||
}
|
||||
table_view.sync_if_needed();
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/* Copyright 2015 Realm Inc - All Rights Reserved
|
||||
* Proprietary and Confidential
|
||||
*/
|
||||
|
||||
#ifndef REALM_RESULTS_HPP
|
||||
#define REALM_RESULTS_HPP
|
||||
|
||||
#import "shared_realm.hpp"
|
||||
#import <realm/table_view.hpp>
|
||||
|
||||
namespace realm {
|
||||
struct SortOrder {
|
||||
std::vector<size_t> columnIndices;
|
||||
std::vector<bool> ascending;
|
||||
|
||||
explicit operator bool() const {
|
||||
return !columnIndices.empty();
|
||||
}
|
||||
};
|
||||
|
||||
static SortOrder s_defaultSort = {{}, {}};
|
||||
|
||||
struct Results {
|
||||
Results(SharedRealm &r, ObjectSchema &o, Query q, SortOrder s = s_defaultSort);
|
||||
size_t size();
|
||||
Row get(std::size_t row_ndx);
|
||||
void verify_attached();
|
||||
|
||||
SharedRealm realm;
|
||||
ObjectSchema &object_schema;
|
||||
Query backing_query;
|
||||
TableView table_view;
|
||||
std::unique_ptr<SortOrder> sort_order;
|
||||
|
||||
void setSort(SortOrder s);
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* REALM_RESULTS_HPP */
|
|
@ -203,7 +203,9 @@ bool Realm::update_schema(std::unique_ptr<Schema> schema, uint64_t version)
|
|||
auto migration_function = [&](Group*, Schema&) {
|
||||
SharedRealm old_realm(new Realm(old_config));
|
||||
auto updated_realm = shared_from_this();
|
||||
if (m_config.migration_function) {
|
||||
m_config.migration_function(old_realm, updated_realm);
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
|
@ -285,8 +287,6 @@ void Realm::cancel_transaction()
|
|||
void Realm::invalidate()
|
||||
{
|
||||
verify_thread();
|
||||
check_read_write(this);
|
||||
|
||||
if (m_in_transaction) {
|
||||
cancel_transaction();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue