obj.hpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558
  1. /*************************************************************************
  2. *
  3. * Copyright 2016 Realm Inc.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. **************************************************************************/
  18. #ifndef REALM_OBJ_HPP
  19. #define REALM_OBJ_HPP
  20. #include <realm/array.hpp>
  21. #include <realm/table_ref.hpp>
  22. #include <realm/keys.hpp>
  23. #include <realm/mixed.hpp>
  24. #include <map>
  25. #define REALM_CLUSTER_IF
  26. namespace realm {
  27. class TableClusterTree;
  28. class Replication;
  29. class TableView;
  30. class CollectionBase;
  31. class CascadeState;
  32. class LstBase;
  33. class SetBase;
  34. struct GlobalKey;
  35. template <class>
  36. class Lst;
  37. template <class T>
  38. using LstPtr = std::unique_ptr<Lst<T>>;
  39. using LstBasePtr = std::unique_ptr<LstBase>;
  40. using SetBasePtr = std::unique_ptr<SetBase>;
  41. using CollectionBasePtr = std::unique_ptr<CollectionBase>;
  42. class LnkLst;
  43. using LnkLstPtr = std::unique_ptr<LnkLst>;
  44. class LnkSet;
  45. using LnkSetPtr = std::unique_ptr<LnkSet>;
  46. template <class>
  47. class Set;
  48. class Dictionary;
  49. using DictionaryPtr = std::unique_ptr<Dictionary>;
  50. enum JSONOutputMode {
  51. output_mode_json, // default / existing implementation for outputting realm to json
  52. output_mode_xjson, // extended json as described in the spec
  53. output_mode_xjson_plus, // extended json as described in the spec with additional modifier used for sync
  54. };
  55. // 'Object' would have been a better name, but it clashes with a class in ObjectStore
  56. class Obj {
  57. public:
  58. Obj()
  59. : m_table(nullptr)
  60. , m_row_ndx(size_t(-1))
  61. , m_storage_version(-1)
  62. , m_valid(false)
  63. {
  64. }
  65. Obj(TableRef table, MemRef mem, ObjKey key, size_t row_ndx);
  66. TableRef get_table() const noexcept
  67. {
  68. return m_table.cast_away_const();
  69. }
  70. Allocator& get_alloc() const;
  71. bool operator==(const Obj& other) const;
  72. ObjKey get_key() const noexcept
  73. {
  74. return m_key;
  75. }
  76. GlobalKey get_object_id() const;
  77. ObjLink get_link() const;
  78. Replication* get_replication() const;
  79. // Check if this object is default constructed
  80. explicit operator bool() const noexcept
  81. {
  82. return m_table != nullptr;
  83. }
  84. // Check if the object is still alive
  85. bool is_valid() const noexcept;
  86. // Will throw if object is not valid
  87. void check_valid() const;
  88. // Delete object from table. Object is invalid afterwards.
  89. void remove();
  90. // Invalidate
  91. // - this turns the object into a tombstone if links to the object exist.
  92. // - deletes the object is no links to the object exist.
  93. // - To be used by the Sync client.
  94. void invalidate();
  95. template <typename U>
  96. U get(ColKey col_key) const;
  97. Mixed get_any(ColKey col_key) const;
  98. Mixed get_any(std::vector<std::string>::iterator path_start, std::vector<std::string>::iterator path_end) const;
  99. Mixed get_primary_key() const;
  100. template <typename U>
  101. U get(StringData col_name) const
  102. {
  103. return get<U>(get_column_key(col_name));
  104. }
  105. bool is_unresolved(ColKey col_key) const;
  106. int cmp(const Obj& other, ColKey col_key) const;
  107. size_t get_link_count(ColKey col_key) const;
  108. bool is_null(ColKey col_key) const;
  109. bool is_null(StringData col_name) const
  110. {
  111. return is_null(get_column_key(col_name));
  112. }
  113. bool has_backlinks(bool only_strong_links) const;
  114. size_t get_backlink_count() const;
  115. size_t get_backlink_count(const Table& origin, ColKey origin_col_key) const;
  116. ObjKey get_backlink(const Table& origin, ColKey origin_col_key, size_t backlink_ndx) const;
  117. TableView get_backlink_view(TableRef src_table, ColKey src_col_key);
  118. // To be used by the query system when a single object should
  119. // be tested. Will allow a function to be called in the context
  120. // of the owning cluster.
  121. template <class T>
  122. bool evaluate(T func) const;
  123. void to_json(std::ostream& out, size_t link_depth, const std::map<std::string, std::string>& renames,
  124. std::vector<ColKey>& followed, JSONOutputMode output_mode) const;
  125. void to_json(std::ostream& out, size_t link_depth, const std::map<std::string, std::string>& renames,
  126. JSONOutputMode output_mode = output_mode_json) const
  127. {
  128. std::vector<ColKey> followed;
  129. to_json(out, link_depth, renames, followed, output_mode);
  130. }
  131. std::string to_string() const;
  132. // Get the path in a minimal format without including object accessors.
  133. // If you need to obtain additional information for each object in the path,
  134. // you should use get_fat_path() or traverse_path() instead (see below).
  135. struct PathElement;
  136. struct Path {
  137. TableKey top_table;
  138. ObjKey top_objkey;
  139. std::vector<PathElement> path_from_top;
  140. };
  141. Path get_path() const;
  142. // Get the fat path to this object expressed as a vector of fat path elements.
  143. // each Fat path elements include a Obj allowing for low cost access to the
  144. // objects data.
  145. // For a top-level object, the returned vector will be empty.
  146. // For an embedded object, the vector has the top object as first element,
  147. // and the embedded object itself is not included in the path.
  148. struct FatPathElement;
  149. using FatPath = std::vector<FatPathElement>;
  150. FatPath get_fat_path() const;
  151. // For an embedded object, traverse the path leading to this object.
  152. // The PathSizer is called first to set the size of the path
  153. // Then there is one call for each object on that path, starting with the top level object
  154. // The embedded object itself is not considered part of the path.
  155. // Note: You should never provide the path_index for calls to traverse_path.
  156. using Visitor = std::function<void(const Obj&, ColKey, size_t)>;
  157. using PathSizer = std::function<void(size_t)>;
  158. void traverse_path(Visitor v, PathSizer ps, size_t path_index = 0) const;
  159. template <typename U>
  160. Obj& set(ColKey col_key, U value, bool is_default = false);
  161. // Create a new object and link it. If an embedded object
  162. // is already set, it will be removed. If a non-embedded
  163. // object is already set, we throw LogicError (to prevent
  164. // dangling objects, since they do not delete automatically
  165. // if they are not embedded...)
  166. Obj create_and_set_linked_object(ColKey col_key, bool is_default = false);
  167. // Clear all fields of a linked object returning it to its
  168. // default state. If the object does not exist, create a
  169. // new object and link it. (To Be Implemented)
  170. Obj clear_linked_object(ColKey col_key);
  171. Obj& set_any(ColKey col_key, Mixed value, bool is_default = false);
  172. template <typename U>
  173. Obj& set(StringData col_name, U value, bool is_default = false)
  174. {
  175. return set(get_column_key(col_name), value, is_default);
  176. }
  177. Obj& set_null(ColKey col_key, bool is_default = false);
  178. Obj& set_null(StringData col_name, bool is_default = false)
  179. {
  180. return set_null(get_column_key(col_name), is_default);
  181. }
  182. Obj& add_int(ColKey col_key, int64_t value);
  183. Obj& add_int(StringData col_name, int64_t value)
  184. {
  185. return add_int(get_column_key(col_name), value);
  186. }
  187. template <typename U>
  188. Obj& set_list_values(ColKey col_key, const std::vector<U>& values);
  189. template <typename U>
  190. std::vector<U> get_list_values(ColKey col_key) const;
  191. template <class Head, class... Tail>
  192. Obj& set_all(Head v, Tail... tail);
  193. void assign(const Obj& other);
  194. Obj get_linked_object(ColKey link_col_key) const;
  195. Obj get_linked_object(StringData link_col_name) const;
  196. template <typename U>
  197. Lst<U> get_list(ColKey col_key) const;
  198. template <typename U>
  199. LstPtr<U> get_list_ptr(ColKey col_key) const;
  200. template <typename U>
  201. Lst<U> get_list(StringData col_name) const
  202. {
  203. return get_list<U>(get_column_key(col_name));
  204. }
  205. LnkLst get_linklist(ColKey col_key) const;
  206. LnkLstPtr get_linklist_ptr(ColKey col_key) const;
  207. LnkLst get_linklist(StringData col_name) const;
  208. /// Get a type-erased list instance for the given list column.
  209. ///
  210. /// Note: For lists of links, this always returns a `LnkLst`, rather than a
  211. /// `Lst<ObjKey>`. Use `get_list_ptr<ObjKey>(col_key)` to get a list of
  212. /// links with uncondensed indices.
  213. LstBasePtr get_listbase_ptr(ColKey col_key) const;
  214. template <typename U>
  215. Set<U> get_set(StringData col_name) const
  216. {
  217. return get_set<U>(get_column_key(col_name));
  218. }
  219. template <typename U>
  220. Set<U> get_set(ColKey col_key) const;
  221. LnkSet get_linkset(ColKey col_key) const;
  222. LnkSetPtr get_linkset_ptr(ColKey col_key) const;
  223. SetBasePtr get_setbase_ptr(ColKey col_key) const;
  224. Dictionary get_dictionary(ColKey col_key) const;
  225. DictionaryPtr get_dictionary_ptr(ColKey col_key) const;
  226. Dictionary get_dictionary(StringData col_name) const;
  227. CollectionBasePtr get_collection_ptr(ColKey col_key) const;
  228. void assign_pk_and_backlinks(const Obj& other);
  229. private:
  230. friend class ArrayBacklink;
  231. friend class CascadeState;
  232. friend class Cluster;
  233. friend class ColumnListBase;
  234. friend class CollectionBase;
  235. friend class ConstTableView;
  236. template <class, class>
  237. friend class Collection;
  238. template <class>
  239. friend class CollectionBaseImpl;
  240. template <class>
  241. friend class Lst;
  242. friend class LnkLst;
  243. friend class Dictionary;
  244. friend class LinkMap;
  245. template <class>
  246. friend class Set;
  247. friend class Table;
  248. friend class Transaction;
  249. mutable TableRef m_table;
  250. ObjKey m_key;
  251. mutable MemRef m_mem;
  252. mutable size_t m_row_ndx;
  253. mutable uint64_t m_storage_version;
  254. mutable bool m_valid;
  255. Allocator& _get_alloc() const noexcept;
  256. bool update() const;
  257. // update if needed - with and without check of table instance version:
  258. bool update_if_needed() const;
  259. bool _update_if_needed() const; // no check, use only when already checked
  260. template <class T>
  261. bool do_is_null(ColKey::Idx col_ndx) const;
  262. const TableClusterTree* get_tree_top() const;
  263. ColKey get_column_key(StringData col_name) const;
  264. ColKey get_primary_key_column() const;
  265. TableKey get_table_key() const;
  266. TableRef get_target_table(ColKey col_key) const;
  267. TableRef get_target_table(ObjLink link) const;
  268. const Spec& get_spec() const;
  269. template <typename U>
  270. U _get(ColKey::Idx col_ndx) const;
  271. template <class T>
  272. int cmp(const Obj& other, ColKey::Idx col_ndx) const;
  273. int cmp(const Obj& other, ColKey::Idx col_ndx) const;
  274. ObjKey get_backlink(ColKey backlink_col, size_t backlink_ndx) const;
  275. // Return all backlinks from a specific backlink column
  276. std::vector<ObjKey> get_all_backlinks(ColKey backlink_col) const;
  277. // Return number of backlinks from a specific backlink column
  278. size_t get_backlink_cnt(ColKey backlink_col) const;
  279. ObjKey get_unfiltered_link(ColKey col_key) const;
  280. template <class Val>
  281. Obj& _set(size_t col_ndx, Val v);
  282. template <class Head, class... Tail>
  283. Obj& _set(size_t col_ndx, Head v, Tail... tail);
  284. ColKey spec_ndx2colkey(size_t col_ndx);
  285. size_t colkey2spec_ndx(ColKey);
  286. bool ensure_writeable();
  287. void sync(Array& arr);
  288. int_fast64_t bump_content_version();
  289. void bump_both_versions();
  290. template <class T>
  291. void do_set_null(ColKey col_key);
  292. // Dictionary support
  293. size_t get_row_ndx() const
  294. {
  295. return m_row_ndx;
  296. }
  297. void set_int(ColKey col_key, int64_t value);
  298. void add_backlink(ColKey backlink_col, ObjKey origin_key);
  299. bool remove_one_backlink(ColKey backlink_col, ObjKey origin_key);
  300. void nullify_link(ColKey origin_col, ObjLink target_key);
  301. // Used when inserting a new link. You will not remove existing links in this process
  302. void set_backlink(ColKey col_key, ObjLink new_link) const;
  303. // Used when replacing a link, return true if CascadeState contains objects to remove
  304. bool replace_backlink(ColKey col_key, ObjLink old_link, ObjLink new_link, CascadeState& state) const;
  305. // Used when removing a backlink, return true if CascadeState contains objects to remove
  306. bool remove_backlink(ColKey col_key, ObjLink old_link, CascadeState& state) const;
  307. template <class T>
  308. inline void set_spec(T&, ColKey);
  309. };
  310. std::ostream& operator<<(std::ostream&, const Obj& obj);
  311. template <>
  312. int64_t Obj::_get(ColKey::Idx col_ndx) const;
  313. struct Obj::FatPathElement {
  314. Obj obj; // Object which embeds...
  315. ColKey col_key; // Column holding link or link list which embeds...
  316. size_t index; // index into link list (or 0)
  317. };
  318. struct Obj::PathElement {
  319. ColKey col_key; // Column holding link or link list which embeds...
  320. size_t index; // index into link list (or 0)
  321. };
  322. template <>
  323. Obj& Obj::set(ColKey, int64_t value, bool is_default);
  324. template <>
  325. Obj& Obj::set(ColKey, ObjKey value, bool is_default);
  326. template <>
  327. Obj& Obj::set(ColKey, ObjLink value, bool is_default);
  328. template <>
  329. inline Obj& Obj::set(ColKey col_key, int value, bool is_default)
  330. {
  331. return set(col_key, int_fast64_t(value), is_default);
  332. }
  333. template <>
  334. inline Obj& Obj::set(ColKey col_key, uint_fast64_t value, bool is_default)
  335. {
  336. int_fast64_t value_2 = 0;
  337. if (REALM_UNLIKELY(util::int_cast_with_overflow_detect(value, value_2))) {
  338. REALM_TERMINATE("Unsigned integer too big.");
  339. }
  340. return set(col_key, value_2, is_default);
  341. }
  342. template <>
  343. inline Obj& Obj::set(ColKey col_key, const char* str, bool is_default)
  344. {
  345. return set(col_key, StringData(str), is_default);
  346. }
  347. template <>
  348. inline Obj& Obj::set(ColKey col_key, char* str, bool is_default)
  349. {
  350. return set(col_key, StringData(str), is_default);
  351. }
  352. template <>
  353. inline Obj& Obj::set(ColKey col_key, std::string str, bool is_default)
  354. {
  355. return set(col_key, StringData(str), is_default);
  356. }
  357. template <>
  358. inline Obj& Obj::set(ColKey col_key, realm::null, bool is_default)
  359. {
  360. return set_null(col_key, is_default);
  361. }
  362. template <>
  363. inline Obj& Obj::set(ColKey col_key, util::Optional<bool> value, bool is_default)
  364. {
  365. return value ? set(col_key, *value, is_default) : set_null(col_key, is_default);
  366. }
  367. template <>
  368. inline Obj& Obj::set(ColKey col_key, util::Optional<int64_t> value, bool is_default)
  369. {
  370. return value ? set(col_key, *value, is_default) : set_null(col_key, is_default);
  371. }
  372. template <>
  373. inline Obj& Obj::set(ColKey col_key, util::Optional<float> value, bool is_default)
  374. {
  375. return value ? set(col_key, *value, is_default) : set_null(col_key, is_default);
  376. }
  377. template <>
  378. inline Obj& Obj::set(ColKey col_key, util::Optional<double> value, bool is_default)
  379. {
  380. return value ? set(col_key, *value, is_default) : set_null(col_key, is_default);
  381. }
  382. template <>
  383. inline Obj& Obj::set(ColKey col_key, util::Optional<ObjectId> value, bool is_default)
  384. {
  385. return value ? set(col_key, *value, is_default) : set_null(col_key, is_default);
  386. }
  387. template <>
  388. inline Obj& Obj::set(ColKey col_key, util::Optional<UUID> value, bool is_default)
  389. {
  390. return value ? set(col_key, *value, is_default) : set_null(col_key, is_default);
  391. }
  392. template <typename U>
  393. Obj& Obj::set_list_values(ColKey col_key, const std::vector<U>& values)
  394. {
  395. size_t sz = values.size();
  396. auto list = get_list<U>(col_key);
  397. size_t list_sz = list.size();
  398. if (sz < list_sz) {
  399. list.resize(sz);
  400. list_sz = sz;
  401. }
  402. size_t i = 0;
  403. while (i < list_sz) {
  404. list.set(i, values[i]);
  405. i++;
  406. }
  407. while (i < sz) {
  408. list.add(values[i]);
  409. i++;
  410. }
  411. return *this;
  412. }
  413. template <typename U>
  414. std::vector<U> Obj::get_list_values(ColKey col_key) const
  415. {
  416. std::vector<U> values;
  417. auto list = get_list<U>(col_key);
  418. for (auto v : list)
  419. values.push_back(v);
  420. return values;
  421. }
  422. inline Obj Obj::get_linked_object(StringData link_col_name) const
  423. {
  424. ColKey col = get_column_key(link_col_name);
  425. return get_linked_object(col);
  426. }
  427. template <class Val>
  428. inline Obj& Obj::_set(size_t col_ndx, Val v)
  429. {
  430. return set(spec_ndx2colkey(col_ndx), v);
  431. }
  432. template <class Head, class... Tail>
  433. inline Obj& Obj::_set(size_t col_ndx, Head v, Tail... tail)
  434. {
  435. set(spec_ndx2colkey(col_ndx), v);
  436. return _set(col_ndx + 1, tail...);
  437. }
  438. template <class Head, class... Tail>
  439. inline Obj& Obj::set_all(Head v, Tail... tail)
  440. {
  441. size_t start_index = 0;
  442. // Avoid trying to set the PK column.
  443. if (get_primary_key_column()) {
  444. REALM_ASSERT(colkey2spec_ndx(get_primary_key_column()) == 0);
  445. start_index = 1;
  446. }
  447. return _set(start_index, v, tail...);
  448. }
  449. inline bool Obj::update_if_needed() const
  450. {
  451. auto current_version = get_alloc().get_storage_version();
  452. if (current_version != m_storage_version) {
  453. return update();
  454. }
  455. return false;
  456. }
  457. inline int_fast64_t Obj::bump_content_version()
  458. {
  459. Allocator& alloc = get_alloc();
  460. return alloc.bump_content_version();
  461. }
  462. inline void Obj::bump_both_versions()
  463. {
  464. Allocator& alloc = get_alloc();
  465. alloc.bump_content_version();
  466. alloc.bump_storage_version();
  467. }
  468. } // namespace realm
  469. #endif // REALM_OBJ_HPP