object.hpp 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. /*************************************************************************
  2. *
  3. * Copyright 2017 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_SYNC_OBJECT_HPP
  19. #define REALM_SYNC_OBJECT_HPP
  20. #include <realm/util/logger.hpp>
  21. #include <realm/table_ref.hpp>
  22. #include <realm/string_data.hpp>
  23. #include <realm/group.hpp>
  24. #include <realm/sync/object_id.hpp>
  25. #include <vector>
  26. /// This file presents a convenience API for making changes to a Realm file that
  27. /// adhere to the conventions of assigning stable IDs to every object.
  28. namespace realm {
  29. class Group;
  30. class ReadTransaction;
  31. class WriteTransaction;
  32. namespace sync {
  33. class SyncHistory;
  34. /// Determine whether the Group has a sync-type history, and therefore whether
  35. /// it supports globally stable object IDs.
  36. ///
  37. /// The Group does not need to be in a transaction.
  38. bool has_object_ids(const Table&);
  39. /// Determine whether object IDs for objects without primary keys are globally
  40. /// stable. This is true if and only if the Group has been in touch with the
  41. /// server (or is the server), and will remain true forever thereafter.
  42. ///
  43. /// It is an error to call this function for groups that do not have object IDs
  44. /// (i.e. where `has_object_ids()` returns false).
  45. ///
  46. /// The Group is assumed to be in a read transaction.
  47. bool is_object_id_stability_achieved(const DB&, const Transaction&);
  48. /// Create a table with an object ID column.
  49. ///
  50. /// It is an error to add tables to Groups with a sync history type directly.
  51. /// This function or related functions must be used instead.
  52. ///
  53. /// The resulting table will be born with 1 column, which is a column used
  54. /// in the maintenance of object IDs.
  55. ///
  56. /// NOTE: The table name must begin with the prefix "class_" in accordance with
  57. /// Object Store conventions.
  58. ///
  59. /// The Group must be in a write transaction.
  60. inline TableRef create_table(Transaction& wt, StringData name)
  61. {
  62. return wt.get_or_add_table(name);
  63. }
  64. /// Create a table with an object ID column and a primary key column.
  65. ///
  66. /// It is an error to add tables to Groups with a sync history type directly.
  67. /// This function or related functions must be used instead.
  68. ///
  69. /// The resulting table will be born with 2 columns, which is a column used
  70. /// in the maintenance of object IDs and the requested primary key column.
  71. /// The primary key column must have either integer or string type, and it
  72. /// will be given the name provided in the argument \a pk_column_name.
  73. ///
  74. /// The 'pk' metadata table is updated with information about the primary key
  75. /// column. If the 'pk' table does not yet exist, it is created.
  76. ///
  77. /// Please note: The 'pk' metadata table will not be synchronized directly,
  78. /// so subsequent updates to it will be lost (as they constitute schema-breaking
  79. /// changes).
  80. ///
  81. /// NOTE: The table name must begin with the prefix "class_" in accordance with
  82. /// Object Store conventions.
  83. ///
  84. /// The Group must be in a write transaction.
  85. inline TableRef create_table_with_primary_key(Transaction& wt, StringData name, DataType pk_type,
  86. StringData pk_column_name, bool nullable = false)
  87. {
  88. if (TableRef table = wt.get_table(name)) {
  89. if (!table->get_primary_key_column() ||
  90. table->get_column_name(table->get_primary_key_column()) != pk_column_name ||
  91. table->is_nullable(table->get_primary_key_column()) != nullable) {
  92. throw std::runtime_error("Inconsistent schema");
  93. }
  94. return table;
  95. }
  96. return wt.add_table_with_primary_key(name, pk_type, pk_column_name, nullable);
  97. }
  98. //@{
  99. /// Erase table and update metadata.
  100. ///
  101. /// It is an error to erase tables via the Group API, because it does not
  102. /// correctly update metadata tables (such as the `pk` table).
  103. void erase_table(Transaction&, StringData name);
  104. void erase_table(Transaction&, TableRef);
  105. //@}
  106. /// Create an array column with the specified element type.
  107. ///
  108. /// The result will be a column of type type_Table with one subcolumn named
  109. /// "!ARRAY_VALUE" of the specified element type and nullability.
  110. ///
  111. /// Return the column index of the inserted array column.
  112. ColKey add_array_column(Table&, DataType element_type, StringData column_name, bool is_nullable = false);
  113. /// Determine whether it is safe to call `object_id_for_row()` on tables without
  114. /// primary keys. If the table has a primary key, always returns true.
  115. bool has_globally_stable_object_ids(const Table&);
  116. bool table_has_primary_key(const Table&);
  117. PrimaryKey primary_key_for_row(const Table&, ObjKey);
  118. PrimaryKey primary_key_for_row(const Obj&);
  119. /// Get the index of the row with the object ID.
  120. ///
  121. /// \returns realm::npos if the object does not exist in the table.
  122. ObjKey row_for_object_id(const Table&, GlobalKey);
  123. Obj obj_for_object_id(const Table&, GlobalKey);
  124. ObjKey row_for_primary_key(const Table&, PrimaryKey);
  125. Obj obj_for_primary_key(const Table&, PrimaryKey);
  126. /// Migrate a server-side Realm file whose history type is
  127. /// `Replication::hist_SyncServer` and whose history schema version is 0 (i.e.,
  128. /// Realm files without stable identifiers).
  129. void import_from_legacy_format(const Group& old_group, Group& new_group, util::Logger&);
  130. using TableNameBuffer = std::array<char, Group::max_table_name_length>;
  131. StringData table_name_to_class_name(StringData);
  132. StringData class_name_to_table_name(StringData, TableNameBuffer&);
  133. // Implementation:
  134. inline StringData table_name_to_class_name(StringData table_name)
  135. {
  136. REALM_ASSERT(table_name.begins_with("class_"));
  137. return table_name.substr(6);
  138. }
  139. inline StringData class_name_to_table_name(StringData class_name, TableNameBuffer& buffer)
  140. {
  141. constexpr const char class_prefix[] = "class_";
  142. constexpr size_t class_prefix_len = sizeof(class_prefix) - 1;
  143. char* p = std::copy_n(class_prefix, class_prefix_len, buffer.data());
  144. size_t len = std::min(class_name.size(), buffer.size() - class_prefix_len);
  145. std::copy_n(class_name.data(), len, p);
  146. return StringData(buffer.data(), class_prefix_len + len);
  147. }
  148. } // namespace sync
  149. } // namespace realm
  150. #endif // REALM_SYNC_OBJECT_HPP