Skip to content

Commit

Permalink
Api nested collections in OS (#6618)
Browse files Browse the repository at this point in the history
Add interface on both object_store::Collection and the C API to handle collections in Mixed.
---------

Co-authored-by: Jørgen Edelbo <jorgen.edelbo@mongodb.com>
  • Loading branch information
nicola-cab and jedelbo committed May 16, 2023
1 parent 55027b7 commit 029648e
Show file tree
Hide file tree
Showing 11 changed files with 354 additions and 4 deletions.
64 changes: 64 additions & 0 deletions src/realm.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,9 @@ typedef enum realm_value_type {
RLM_TYPE_OBJECT_ID,
RLM_TYPE_LINK,
RLM_TYPE_UUID,
RLM_TYPE_LIST,
RLM_TYPE_SET,
RLM_TYPE_DICTIONARY,
} realm_value_type_e;

typedef enum realm_schema_validation_mode {
Expand Down Expand Up @@ -1635,6 +1638,12 @@ RLM_API bool realm_set_value(realm_object_t*, realm_property_key_t, realm_value_
*/
RLM_API realm_object_t* realm_set_embedded(realm_object_t*, realm_property_key_t);

/**
* Create a collection in a given Mixed property.
*
*/
RLM_API bool realm_set_collection(realm_object_t*, realm_property_key_t, realm_collection_type_e);

/** Return the object linked by the given property
*
* @return A non-NULL pointer if an object is found.
Expand Down Expand Up @@ -1776,6 +1785,44 @@ RLM_API bool realm_list_set(realm_list_t*, size_t index, realm_value_t value);
*/
RLM_API bool realm_list_insert(realm_list_t*, size_t index, realm_value_t value);

/**
* Insert a collection inside a list (only available for mixed properities)
*
* @param list valid ptr to a list where a nested collection needs to be added
* @param index position in the list where to add the collection
* @return RLM_API
*/
RLM_API bool realm_list_insert_collection(realm_list_t* list, size_t index, realm_collection_type_e);

/**
* Set a collection inside a list (only available for mixed properities).
* If the list already contains a collection of the requested type, the
* operation is idempotent.
*
* @param list valid ptr to a list where a nested collection needs to be set
* @param index position in the list where to set the collection
* @return RLM_API
*/
RLM_API bool realm_list_set_collection(realm_list_t* list, size_t index, realm_collection_type_e);

/**
* Returns a nested list if such collection exists, NULL otherwise.
*
* @param list pointer to the list that containes the nested list
* @param index index of collection in the list
* @return a pointer to the the nested list found at the index passed as argument
*/
RLM_API realm_list_t* realm_list_get_list(realm_list_t* list, size_t index);

/**
* Returns a nested dictionary if such collection exists, NULL otherwise.
*
* @param list pointer to the list that containes the nested collection into
* @param index position of collection in the list
* @return a pointer to the the nested dictionary found at index passed as argument
*/
RLM_API realm_dictionary_t* realm_list_get_dictionary(realm_list_t* list, size_t index);

/**
* Move the element at @a from_index to @a to_index.
*
Expand Down Expand Up @@ -2253,6 +2300,23 @@ RLM_API bool realm_dictionary_insert(realm_dictionary_t*, realm_value_t key, rea
*/
RLM_API realm_object_t* realm_dictionary_insert_embedded(realm_dictionary_t*, realm_value_t key);

/**
* Insert a nested collection
*/
RLM_API bool realm_dictionary_insert_collection(realm_dictionary_t*, realm_value_t key, realm_collection_type_e);

/**
* Fetch a list from a dictionary.
* @return a valid list that needs to be deleted by the caller or nullptr in case of an error.
*/
RLM_API realm_list_t* realm_dictionary_get_list(realm_dictionary_t* dictionary, realm_value_t key);

/**
* Fetch a dictioanry from a dictionary.
* @return a valid dictionary that needs to be deleted by the caller or nullptr in case of an error.
*/
RLM_API realm_dictionary_t* realm_dictionary_get_dictionary(realm_dictionary_t* dictionary, realm_value_t key);

/**
* Get object identified by key
*
Expand Down
34 changes: 33 additions & 1 deletion src/realm/object-store/c_api/conversion.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,12 @@ static inline Mixed from_capi(realm_value_t val)
return Mixed{ObjLink{TableKey(val.link.target_table), ObjKey(val.link.target)}};
case RLM_TYPE_UUID:
return Mixed{UUID{from_capi(val.uuid)}};
case RLM_TYPE_LIST:
return Mixed{0, CollectionType::List};
case RLM_TYPE_SET:
return Mixed{0, CollectionType::Set};
case RLM_TYPE_DICTIONARY:
return Mixed{0, CollectionType::Dictionary};
}
REALM_TERMINATE("Invalid realm_value_t"); // LCOV_EXCL_LINE
}
Expand All @@ -155,7 +161,8 @@ static inline realm_value_t to_capi(Mixed value)
val.type = RLM_TYPE_NULL;
}
else {
switch (value.get_type()) {
auto type = value.get_type();
switch (type) {
case type_Int: {
val.type = RLM_TYPE_INT;
val.integer = value.get<int64_t>();
Expand Down Expand Up @@ -221,6 +228,16 @@ static inline realm_value_t to_capi(Mixed value)
case type_LinkList:
case type_Mixed:
REALM_TERMINATE("Invalid Mixed value type"); // LCOV_EXCL_LINE
default:
if (type == type_List) {
val.type = RLM_TYPE_LIST;
}
else if (type == type_Set) {
val.type = RLM_TYPE_SET;
}
else if (type == type_Dictionary) {
val.type = RLM_TYPE_DICTIONARY;
}
}
}

Expand Down Expand Up @@ -418,6 +435,21 @@ static inline Property from_capi(const realm_property_info_t& p) noexcept
return prop;
}

static inline std::optional<CollectionType> from_capi(realm_collection_type_e type)
{
switch (type) {
case RLM_COLLECTION_TYPE_NONE:
break;
case RLM_COLLECTION_TYPE_LIST:
return CollectionType::List;
case RLM_COLLECTION_TYPE_SET:
return CollectionType::Set;
case RLM_COLLECTION_TYPE_DICTIONARY:
return CollectionType::Dictionary;
}
return {};
}

static inline realm_property_info_t to_capi(const Property& prop) noexcept
{
realm_property_info_t p;
Expand Down
39 changes: 39 additions & 0 deletions src/realm/object-store/c_api/dictionary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,45 @@ RLM_API realm_object_t* realm_dictionary_insert_embedded(realm_dictionary_t* dic
});
}

RLM_API bool realm_dictionary_insert_collection(realm_dictionary_t* dict, realm_value_t key,
realm_collection_type_e type)
{
return wrap_err([&]() {
if (key.type != RLM_TYPE_STRING) {
throw InvalidArgument{"Only string keys are supported in dictionaries"};
}

StringData k{key.string.data, key.string.size};
dict->insert_collection(k, *from_capi(type));
return true;
});
}


RLM_API realm_list_t* realm_dictionary_get_list(realm_dictionary_t* dictionary, realm_value_t key)
{
return wrap_err([&]() {
if (key.type != RLM_TYPE_STRING) {
throw InvalidArgument{"Only string keys are supported in dictionaries"};
}

StringData k{key.string.data, key.string.size};
return new realm_list_t{dictionary->get_list(k)};
});
}

RLM_API realm_dictionary_t* realm_dictionary_get_dictionary(realm_dictionary_t* dictionary, realm_value_t key)
{
return wrap_err([&]() {
if (key.type != RLM_TYPE_STRING) {
throw InvalidArgument{"Only string keys are supported in dictionaries"};
}

StringData k{key.string.data, key.string.size};
return new realm_dictionary_t{dictionary->get_dictionary(k)};
});
}

RLM_API realm_object_t* realm_dictionary_get_linked_object(realm_dictionary_t* dict, realm_value_t key)
{
return wrap_err([&]() {
Expand Down
31 changes: 31 additions & 0 deletions src/realm/object-store/c_api/list.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,37 @@ RLM_API bool realm_list_insert(realm_list_t* list, size_t index, realm_value_t v
});
}

RLM_API bool realm_list_insert_collection(realm_list_t* list, size_t index, realm_collection_type_e type)
{
return wrap_err([&]() {
list->insert_collection(index, *from_capi(type));
return true;
});
}

RLM_API bool realm_list_set_collection(realm_list_t* list, size_t index, realm_collection_type_e type)
{
return wrap_err([&]() {
list->set_collection(index, *from_capi(type));
return true;
});
}


RLM_API realm_list_t* realm_list_get_list(realm_list_t* list, size_t index)
{
return wrap_err([&]() {
return new realm_list_t{list->get_list(index)};
});
}

RLM_API realm_dictionary_t* realm_list_get_dictionary(realm_list_t* list, size_t index)
{
return wrap_err([&]() {
return new realm_dictionary_t{list->get_dictionary(index)};
});
}

RLM_API bool realm_list_move(realm_list_t* list, size_t from_index, size_t to_index)
{
return wrap_err([&]() {
Expand Down
13 changes: 11 additions & 2 deletions src/realm/object-store/c_api/object.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,15 @@ RLM_API realm_object_t* realm_set_embedded(realm_object_t* obj, realm_property_k
});
}

RLM_API bool realm_set_collection(realm_object_t* obj, realm_property_key_t col, realm_collection_type_e type)
{
return wrap_err([&]() {
obj->verify_attached();
obj->obj().set_collection(ColKey(col), *from_capi(type));
return true;
});
}

RLM_API realm_object_t* realm_get_linked_object(realm_object_t* obj, realm_property_key_t col)
{
return wrap_err([&]() {
Expand All @@ -357,7 +366,7 @@ RLM_API realm_list_t* realm_get_list(realm_object_t* object, realm_property_key_
auto col_key = ColKey(key);
table->check_column(col_key);

if (!col_key.is_list()) {
if (!(col_key.is_list() || col_key.get_type() == col_type_Mixed)) {
report_type_mismatch(object->get_realm(), *table, col_key);
}

Expand Down Expand Up @@ -394,7 +403,7 @@ RLM_API realm_dictionary_t* realm_get_dictionary(realm_object_t* object, realm_p
auto col_key = ColKey(key);
table->check_column(col_key);

if (!col_key.is_dictionary()) {
if (!(col_key.is_dictionary() || col_key.get_type() == col_type_Mixed)) {
report_type_mismatch(object->get_realm(), *table, col_key);
}

Expand Down
6 changes: 6 additions & 0 deletions src/realm/object-store/c_api/query.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,12 @@ struct QueryArgumentsAdapter : query_parser::Arguments {
return type_Decimal;
case RLM_TYPE_UUID:
return type_UUID;
case RLM_TYPE_LIST:
return type_List;
case RLM_TYPE_SET:
return type_Set;
case RLM_TYPE_DICTIONARY:
return type_Dictionary;
}
throw LogicError{ErrorCodes::TypeMismatch, "Unsupported type"}; // LCOV_EXCL_LINE
return type_Int;
Expand Down
24 changes: 24 additions & 0 deletions src/realm/object-store/collection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
#include <realm/object-store/object_store.hpp>
#include <realm/object-store/results.hpp>
#include <realm/object-store/shared_realm.hpp>
#include <realm/object-store/list.hpp>
#include <realm/object-store/dictionary.hpp>

namespace realm::object_store {

Expand Down Expand Up @@ -261,4 +263,26 @@ size_t Collection::hash() const noexcept
return hash_combine(impl.get_owner_key().value, impl.get_table()->get_key().value, impl.get_col_key().value);
}

void Collection::insert_collection(const PathElement& path, CollectionType type)
{
verify_in_transaction();
m_coll_base->insert_collection(path, type);
}

void Collection::set_collection(const PathElement& path, CollectionType type)
{
verify_in_transaction();
m_coll_base->set_collection(path, type);
}

List Collection::get_list(const PathElement& path) const
{
return List{m_realm, m_coll_base->get_list(path)};
}

Dictionary Collection::get_dictionary(const PathElement& path) const
{
return Dictionary{m_realm, m_coll_base->get_dictionary(path)};
}

} // namespace realm::object_store
8 changes: 8 additions & 0 deletions src/realm/object-store/collection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,14 @@ namespace realm {
class Realm;
class Results;
class ObjectSchema;
class List;

namespace _impl {
class ListNotifier;
}

namespace object_store {
class Dictionary;
class Collection {
public:
Collection(PropertyType type) noexcept;
Expand Down Expand Up @@ -112,6 +114,12 @@ class Collection {
return *m_coll_base;
}

// nested collections
void insert_collection(const PathElement&, CollectionType);
void set_collection(const PathElement&, CollectionType);
List get_list(const PathElement&) const;
Dictionary get_dictionary(const PathElement&) const;

protected:
std::shared_ptr<Realm> m_realm;
PropertyType m_type;
Expand Down
2 changes: 1 addition & 1 deletion src/realm/object-store/property.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,7 @@ inline Property::Property(std::string name, PropertyType type, const NestedTypes
, object_type(std::move(target_type))
, nested_types(nested_types)
{
REALM_ASSERT(is_collection(type));
REALM_ASSERT(is_collection(type) || is_mixed(type));
REALM_ASSERT((type == PropertyType::Object) == (object_type.size() != 0));
}

Expand Down
Loading

0 comments on commit 029648e

Please sign in to comment.