123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637 |
- /*************************************************************************
- *
- * Copyright 2016 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_OBJ_HPP
- #define REALM_OBJ_HPP
- #include <realm/node.hpp>
- #include <realm/table_ref.hpp>
- #include <realm/keys.hpp>
- #include <realm/mixed.hpp>
- #include <map>
- #define REALM_CLUSTER_IF
- namespace realm {
- class ClusterTree;
- class Replication;
- class TableView;
- class CollectionBase;
- class CascadeState;
- class LstBase;
- class SetBase;
- class ObjList;
- struct GlobalKey;
- template <class>
- class Lst;
- template <class>
- class Set;
- template <class T>
- using LstPtr = std::unique_ptr<Lst<T>>;
- using LstBasePtr = std::unique_ptr<LstBase>;
- template <class T>
- using SetPtr = std::unique_ptr<Set<T>>;
- using SetBasePtr = std::unique_ptr<SetBase>;
- using CollectionBasePtr = std::unique_ptr<CollectionBase>;
- using LinkCollectionPtr = std::unique_ptr<ObjList>;
- class LnkLst;
- using LnkLstPtr = std::unique_ptr<LnkLst>;
- class LnkSet;
- using LnkSetPtr = std::unique_ptr<LnkSet>;
- template <class>
- class Set;
- class Dictionary;
- class DictionaryLinkValues;
- using DictionaryPtr = std::unique_ptr<Dictionary>;
- namespace _impl {
- class DeepChangeChecker;
- }
- enum JSONOutputMode {
- output_mode_json, // default / existing implementation for outputting realm to json
- output_mode_xjson, // extended json as described in the spec
- output_mode_xjson_plus, // extended json as described in the spec with additional modifier used for sync
- };
- /// The status of an accessor after a call to `update_if_needed()`.
- enum class UpdateStatus {
- /// The owning object or column no longer exist, and the accessor could
- /// not be updated. The accessor should be left in a detached state
- /// after this, and further calls to `update_if_needed()` are not
- /// guaranteed to reattach the accessor.
- Detached,
- /// The underlying data of the accessor was changed since the last call
- /// to `update_if_needed()`. The accessor is still valid.
- Updated,
- /// The underlying data of the accessor did not change since the last
- /// call to `update_if_needed()`, and the accessor is still valid in its
- /// current state.
- NoChange,
- };
- // 'Object' would have been a better name, but it clashes with a class in ObjectStore
- class Obj {
- public:
- constexpr Obj()
- : m_table(nullptr)
- , m_row_ndx(size_t(-1))
- , m_storage_version(-1)
- , m_valid(false)
- {
- }
- Obj(TableRef table, MemRef mem, ObjKey key, size_t row_ndx);
- TableRef get_table() const noexcept
- {
- return m_table.cast_away_const();
- }
- Allocator& get_alloc() const;
- bool operator==(const Obj& other) const;
- ObjKey get_key() const noexcept
- {
- return m_key;
- }
- GlobalKey get_object_id() const;
- ObjLink get_link() const;
- Replication* get_replication() const;
- // Check if this object is default constructed
- explicit operator bool() const noexcept
- {
- return m_table != nullptr;
- }
- /// Check if the object is still alive
- bool is_valid() const noexcept;
- /// Delete object from table. Object is invalid afterwards.
- void remove();
- /// Invalidate
- /// - this turns the object into a tombstone if links to the object exist.
- /// - deletes the object is no links to the object exist.
- /// - To be used by the Sync client.
- void invalidate();
- template <typename U>
- U get(ColKey col_key) const;
- Mixed get_any(ColKey col_key) const;
- Mixed get_any(StringData col_name) const
- {
- return get_any(get_column_key(col_name));
- }
- Mixed get_any(std::vector<std::string>::iterator path_start, std::vector<std::string>::iterator path_end) const;
- Mixed get_primary_key() const;
- template <typename U>
- U get(StringData col_name) const
- {
- return get<U>(get_column_key(col_name));
- }
- bool is_unresolved(ColKey col_key) const;
- size_t get_link_count(ColKey col_key) const;
- TableRef get_target_table(ColKey col_key) const;
- bool is_null(ColKey col_key) const;
- bool is_null(StringData col_name) const
- {
- return is_null(get_column_key(col_name));
- }
- bool has_backlinks(bool only_strong_links) const;
- size_t get_backlink_count() const;
- size_t get_backlink_count(const Table& origin, ColKey origin_col_key) const;
- ObjKey get_backlink(const Table& origin, ColKey origin_col_key, size_t backlink_ndx) const;
- TableView get_backlink_view(TableRef src_table, ColKey src_col_key);
- // To be used by the query system when a single object should
- // be tested. Will allow a function to be called in the context
- // of the owning cluster.
- template <class T>
- bool evaluate(T func) const;
- void to_json(std::ostream& out, size_t link_depth, const std::map<std::string, std::string>& renames,
- std::vector<ObjLink>& followed, JSONOutputMode output_mode) const;
- void to_json(std::ostream& out, size_t link_depth, const std::map<std::string, std::string>& renames,
- JSONOutputMode output_mode = output_mode_json) const
- {
- std::vector<ObjLink> followed;
- to_json(out, link_depth, renames, followed, output_mode);
- }
- std::string to_string() const;
- // Get the path in a minimal format without including object accessors.
- // If you need to obtain additional information for each object in the path,
- // you should use get_fat_path() or traverse_path() instead (see below).
- struct PathElement;
- struct Path {
- TableKey top_table;
- ObjKey top_objkey;
- std::vector<PathElement> path_from_top;
- };
- Path get_path() const;
- // Get the fat path to this object expressed as a vector of fat path elements.
- // each Fat path elements include a Obj allowing for low cost access to the
- // objects data.
- // For a top-level object, the returned vector will be empty.
- // For an embedded object, the vector has the top object as first element,
- // and the embedded object itself is not included in the path.
- struct FatPathElement;
- using FatPath = std::vector<FatPathElement>;
- FatPath get_fat_path() const;
- // For an embedded object, traverse the path leading to this object.
- // The PathSizer is called first to set the size of the path
- // Then there is one call for each object on that path, starting with the top level object
- // The embedded object itself is not considered part of the path.
- // Note: You should never provide the path_index for calls to traverse_path.
- using Visitor = util::FunctionRef<void(const Obj&, ColKey, Mixed)>;
- using PathSizer = util::FunctionRef<void(size_t)>;
- void traverse_path(Visitor v, PathSizer ps, size_t path_index = 0) const;
- template <typename U>
- Obj& set(ColKey col_key, U value, bool is_default = false);
- // Create a new object and link it. If an embedded object
- // is already set, it will be removed. If a non-embedded
- // object is already set, we throw LogicError (to prevent
- // dangling objects, since they do not delete automatically
- // if they are not embedded...)
- Obj create_and_set_linked_object(ColKey col_key, bool is_default = false);
- // Clear all fields of a linked object returning it to its
- // default state. If the object does not exist, create a
- // new object and link it. (To Be Implemented)
- Obj clear_linked_object(ColKey col_key);
- Obj& set_any(ColKey col_key, Mixed value, bool is_default = false);
- Obj& set_any(StringData col_name, Mixed value, bool is_default = false)
- {
- return set_any(get_column_key(col_name), value, is_default);
- }
- template <typename U>
- Obj& set(StringData col_name, U value, bool is_default = false)
- {
- return set(get_column_key(col_name), value, is_default);
- }
- Obj& set_null(ColKey col_key, bool is_default = false);
- Obj& set_null(StringData col_name, bool is_default = false)
- {
- return set_null(get_column_key(col_name), is_default);
- }
- Obj& add_int(ColKey col_key, int64_t value);
- Obj& add_int(StringData col_name, int64_t value)
- {
- return add_int(get_column_key(col_name), value);
- }
- template <typename U>
- Obj& set_list_values(ColKey col_key, const std::vector<U>& values);
- template <typename U>
- std::vector<U> get_list_values(ColKey col_key) const;
- template <class Head, class... Tail>
- Obj& set_all(Head v, Tail... tail);
- // The main algorithm for handling schema migrations if we try to convert
- // from TopLevel* to Embedded, in this case all the orphan objects are deleted
- // and all the objects with multiple backlinks are cloned in order to avoid to
- // get schema violations during the migration.
- // By default this alogirithm is disabled. RealmConfig contains a boolean flag
- // to enable it.
- void handle_multiple_backlinks_during_schema_migration();
- Obj get_linked_object(ColKey link_col_key) const
- {
- return _get_linked_object(link_col_key, get_any(link_col_key));
- }
- Obj get_linked_object(StringData link_col_name) const
- {
- return get_linked_object(get_column_key(link_col_name));
- }
- Obj get_parent_object() const;
- template <typename U>
- Lst<U> get_list(ColKey col_key) const;
- template <typename U>
- LstPtr<U> get_list_ptr(ColKey col_key) const;
- template <typename U>
- Lst<U> get_list(StringData col_name) const
- {
- return get_list<U>(get_column_key(col_name));
- }
- LnkLst get_linklist(ColKey col_key) const;
- LnkLstPtr get_linklist_ptr(ColKey col_key) const;
- LnkLst get_linklist(StringData col_name) const;
- /// Get a type-erased list instance for the given list column.
- ///
- /// Note: For lists of links, this always returns a `LnkLst`, rather than a
- /// `Lst<ObjKey>`. Use `get_list_ptr<ObjKey>(col_key)` to get a list of
- /// links with uncondensed indices.
- LstBasePtr get_listbase_ptr(ColKey col_key) const;
- template <typename U>
- Set<U> get_set(StringData col_name) const
- {
- return get_set<U>(get_column_key(col_name));
- }
- template <typename U>
- Set<U> get_set(ColKey col_key) const;
- template <typename U>
- SetPtr<U> get_set_ptr(ColKey col_key) const;
- LnkSet get_linkset(ColKey col_key) const;
- LnkSet get_linkset(StringData col_name) const;
- LnkSetPtr get_linkset_ptr(ColKey col_key) const;
- SetBasePtr get_setbase_ptr(ColKey col_key) const;
- Dictionary get_dictionary(ColKey col_key) const;
- DictionaryPtr get_dictionary_ptr(ColKey col_key) const;
- Dictionary get_dictionary(StringData col_name) const;
- CollectionBasePtr get_collection_ptr(ColKey col_key) const;
- CollectionBasePtr get_collection_ptr(StringData col_name) const;
- LinkCollectionPtr get_linkcollection_ptr(ColKey col_key) const;
- void assign_pk_and_backlinks(const Obj& other);
- class Internal {
- friend class _impl::DeepChangeChecker;
- static ref_type get_ref(const Obj& obj, ColKey col_key);
- };
- private:
- friend class ArrayBacklink;
- friend class CascadeState;
- friend class Cluster;
- friend class ColumnListBase;
- friend class CollectionBase;
- friend class TableView;
- template <class, class>
- friend class Collection;
- template <class, class>
- friend class CollectionBaseImpl;
- template <class>
- friend class Lst;
- friend class LnkLst;
- friend class Dictionary;
- friend class LinkMap;
- template <class>
- friend class Set;
- friend class Table;
- friend class Transaction;
- mutable TableRef m_table;
- ObjKey m_key;
- mutable MemRef m_mem;
- mutable size_t m_row_ndx;
- mutable uint64_t m_storage_version;
- mutable bool m_valid;
- Allocator& _get_alloc() const noexcept;
- /// Update the accessor. Returns true when the accessor was updated to
- /// reflect new changes to the underlying state.
- bool update() const;
- // update if needed - with and without check of table instance version:
- bool update_if_needed() const;
- bool _update_if_needed() const; // no check, use only when already checked
- /// Update the accessor (and return `UpdateStatus::Detached` if the Obj is
- /// no longer valid, rather than throwing an exception).
- UpdateStatus update_if_needed_with_status() const;
- template <class T>
- bool do_is_null(ColKey::Idx col_ndx) const;
- const ClusterTree* get_tree_top() const;
- ColKey get_column_key(StringData col_name) const;
- ColKey get_primary_key_column() const;
- TableKey get_table_key() const;
- TableRef get_target_table(ObjLink link) const;
- const Spec& get_spec() const;
- template <typename U>
- U _get(ColKey::Idx col_ndx) const;
- ObjKey get_backlink(ColKey backlink_col, size_t backlink_ndx) const;
- // Return all backlinks from a specific backlink column
- std::vector<ObjKey> get_all_backlinks(ColKey backlink_col) const;
- // Return number of backlinks from a specific backlink column
- size_t get_backlink_cnt(ColKey backlink_col) const;
- ObjKey get_unfiltered_link(ColKey col_key) const;
- template <class Val>
- Obj& _set(size_t col_ndx, Val v);
- template <class Head, class... Tail>
- Obj& _set(size_t col_ndx, Head v, Tail... tail);
- ColKey spec_ndx2colkey(size_t col_ndx);
- size_t colkey2spec_ndx(ColKey);
- bool ensure_writeable();
- void sync(Node& arr);
- int_fast64_t bump_content_version();
- void bump_both_versions();
- template <class T>
- void do_set_null(ColKey col_key);
- // Dictionary support
- size_t get_row_ndx() const
- {
- return m_row_ndx;
- }
- Obj _get_linked_object(ColKey link_col_key, Mixed link) const;
- Obj _get_linked_object(StringData link_col_name, Mixed link) const
- {
- return _get_linked_object(get_column_key(link_col_name), link);
- }
- void set_int(ColKey col_key, int64_t value);
- void add_backlink(ColKey backlink_col, ObjKey origin_key);
- bool remove_one_backlink(ColKey backlink_col, ObjKey origin_key);
- void nullify_link(ColKey origin_col, ObjLink target_key) &&;
- // Used when inserting a new link. You will not remove existing links in this process
- void set_backlink(ColKey col_key, ObjLink new_link) const;
- // Used when replacing a link, return true if CascadeState contains objects to remove
- bool replace_backlink(ColKey col_key, ObjLink old_link, ObjLink new_link, CascadeState& state) const;
- // Used when removing a backlink, return true if CascadeState contains objects to remove
- bool remove_backlink(ColKey col_key, ObjLink old_link, CascadeState& state) const;
- template <class T>
- inline void set_spec(T&, ColKey);
- template <class ValueType>
- inline void nullify_single_link(ColKey col, ValueType target);
- void fix_linking_object_during_schema_migration(Obj linking_obj, Obj obj, ColKey opposite_col_key) const;
- };
- std::ostream& operator<<(std::ostream&, const Obj& obj);
- template <>
- int64_t Obj::get(ColKey) const;
- template <>
- bool Obj::get(ColKey) const;
- template <>
- int64_t Obj::_get(ColKey::Idx col_ndx) const;
- template <>
- StringData Obj::_get(ColKey::Idx col_ndx) const;
- template <>
- BinaryData Obj::_get(ColKey::Idx col_ndx) const;
- template <>
- ObjKey Obj::_get(ColKey::Idx col_ndx) const;
- struct Obj::FatPathElement {
- Obj obj; // Object which embeds...
- ColKey col_key; // Column holding link or link list which embeds...
- Mixed index; // index into link list or dictionary (or null)
- };
- struct Obj::PathElement {
- ColKey col_key; // Column holding link or link list which embeds...
- Mixed index; // index into link list or dictionary (or null)
- };
- template <>
- Obj& Obj::set(ColKey, int64_t value, bool is_default);
- template <>
- Obj& Obj::set(ColKey, ObjKey value, bool is_default);
- template <>
- Obj& Obj::set(ColKey, ObjLink value, bool is_default);
- template <>
- inline Obj& Obj::set(ColKey col_key, int value, bool is_default)
- {
- return set(col_key, int_fast64_t(value), is_default);
- }
- template <>
- inline Obj& Obj::set(ColKey col_key, uint_fast64_t value, bool is_default)
- {
- int_fast64_t value_2 = 0;
- if (REALM_UNLIKELY(util::int_cast_with_overflow_detect(value, value_2))) {
- REALM_TERMINATE("Unsigned integer too big.");
- }
- return set(col_key, value_2, is_default);
- }
- template <>
- inline Obj& Obj::set(ColKey col_key, const char* str, bool is_default)
- {
- return set(col_key, StringData(str), is_default);
- }
- template <>
- inline Obj& Obj::set(ColKey col_key, char* str, bool is_default)
- {
- return set(col_key, StringData(str), is_default);
- }
- template <>
- inline Obj& Obj::set(ColKey col_key, std::string str, bool is_default)
- {
- return set(col_key, StringData(str), is_default);
- }
- template <>
- inline Obj& Obj::set(ColKey col_key, realm::null, bool is_default)
- {
- return set_null(col_key, is_default);
- }
- template <>
- inline Obj& Obj::set(ColKey col_key, util::Optional<bool> value, bool is_default)
- {
- return value ? set(col_key, *value, is_default) : set_null(col_key, is_default);
- }
- template <>
- inline Obj& Obj::set(ColKey col_key, util::Optional<int64_t> value, bool is_default)
- {
- return value ? set(col_key, *value, is_default) : set_null(col_key, is_default);
- }
- template <>
- inline Obj& Obj::set(ColKey col_key, util::Optional<float> value, bool is_default)
- {
- return value ? set(col_key, *value, is_default) : set_null(col_key, is_default);
- }
- template <>
- inline Obj& Obj::set(ColKey col_key, util::Optional<double> value, bool is_default)
- {
- return value ? set(col_key, *value, is_default) : set_null(col_key, is_default);
- }
- template <>
- inline Obj& Obj::set(ColKey col_key, util::Optional<ObjectId> value, bool is_default)
- {
- return value ? set(col_key, *value, is_default) : set_null(col_key, is_default);
- }
- template <>
- inline Obj& Obj::set(ColKey col_key, util::Optional<UUID> value, bool is_default)
- {
- return value ? set(col_key, *value, is_default) : set_null(col_key, is_default);
- }
- template <typename U>
- Obj& Obj::set_list_values(ColKey col_key, const std::vector<U>& values)
- {
- size_t sz = values.size();
- auto list = get_list<U>(col_key);
- size_t list_sz = list.size();
- if (sz < list_sz) {
- list.resize(sz);
- list_sz = sz;
- }
- size_t i = 0;
- while (i < list_sz) {
- list.set(i, values[i]);
- i++;
- }
- while (i < sz) {
- list.add(values[i]);
- i++;
- }
- return *this;
- }
- template <typename U>
- std::vector<U> Obj::get_list_values(ColKey col_key) const
- {
- std::vector<U> values;
- auto list = get_list<U>(col_key);
- for (auto v : list)
- values.push_back(v);
- return values;
- }
- template <class Val>
- inline Obj& Obj::_set(size_t col_ndx, Val v)
- {
- return set(spec_ndx2colkey(col_ndx), v);
- }
- template <class Head, class... Tail>
- inline Obj& Obj::_set(size_t col_ndx, Head v, Tail... tail)
- {
- set(spec_ndx2colkey(col_ndx), v);
- return _set(col_ndx + 1, tail...);
- }
- template <class Head, class... Tail>
- inline Obj& Obj::set_all(Head v, Tail... tail)
- {
- size_t start_index = 0;
- // Avoid trying to set the PK column.
- if (get_primary_key_column()) {
- REALM_ASSERT(colkey2spec_ndx(get_primary_key_column()) == 0);
- start_index = 1;
- }
- return _set(start_index, v, tail...);
- }
- inline bool Obj::update_if_needed() const
- {
- auto current_version = get_alloc().get_storage_version();
- if (current_version != m_storage_version) {
- return update();
- }
- return false;
- }
- inline int_fast64_t Obj::bump_content_version()
- {
- Allocator& alloc = get_alloc();
- return alloc.bump_content_version();
- }
- inline void Obj::bump_both_versions()
- {
- Allocator& alloc = get_alloc();
- alloc.bump_content_version();
- alloc.bump_storage_version();
- }
- } // namespace realm
- #endif // REALM_OBJ_HPP
|