| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558 | /************************************************************************* * * 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/array.hpp>#include <realm/table_ref.hpp>#include <realm/keys.hpp>#include <realm/mixed.hpp>#include <map>#define REALM_CLUSTER_IFnamespace realm {class TableClusterTree;class Replication;class TableView;class CollectionBase;class CascadeState;class LstBase;class SetBase;struct GlobalKey;template <class>class Lst;template <class T>using LstPtr = std::unique_ptr<Lst<T>>;using LstBasePtr = std::unique_ptr<LstBase>;using SetBasePtr = std::unique_ptr<SetBase>;using CollectionBasePtr = std::unique_ptr<CollectionBase>;class LnkLst;using LnkLstPtr = std::unique_ptr<LnkLst>;class LnkSet;using LnkSetPtr = std::unique_ptr<LnkSet>;template <class>class Set;class Dictionary;using DictionaryPtr = std::unique_ptr<Dictionary>;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};// 'Object' would have been a better name, but it clashes with a class in ObjectStoreclass Obj {public:    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;    // Will throw if object is not valid    void check_valid() const;    // 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(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;    int cmp(const Obj& other, ColKey col_key) const;    size_t get_link_count(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<ColKey>& 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<ColKey> 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 = std::function<void(const Obj&, ColKey, size_t)>;    using PathSizer = std::function<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);    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);    void assign(const Obj& other);    Obj get_linked_object(ColKey link_col_key) const;    Obj get_linked_object(StringData link_col_name) 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;    LnkSet get_linkset(ColKey col_key) 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;    void assign_pk_and_backlinks(const Obj& other);private:    friend class ArrayBacklink;    friend class CascadeState;    friend class Cluster;    friend class ColumnListBase;    friend class CollectionBase;    friend class ConstTableView;    template <class, class>    friend class Collection;    template <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;    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    template <class T>    bool do_is_null(ColKey::Idx col_ndx) const;    const TableClusterTree* 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(ColKey col_key) const;    TableRef get_target_table(ObjLink link) const;    const Spec& get_spec() const;    template <typename U>    U _get(ColKey::Idx col_ndx) const;    template <class T>    int cmp(const Obj& other, ColKey::Idx col_ndx) const;    int cmp(const Obj& other, 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(Array& 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;    }    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);};std::ostream& operator<<(std::ostream&, const Obj& obj);template <>int64_t 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...    size_t index;   // index into link list (or 0)};struct Obj::PathElement {    ColKey col_key; // Column holding link or link list which embeds...    size_t index;   // index into link list (or 0)};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;}inline Obj Obj::get_linked_object(StringData link_col_name) const{    ColKey col = get_column_key(link_col_name);    return get_linked_object(col);}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
 |