• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

realm / realm-core / thomas.goyne_114

27 Oct 2023 10:49AM UTC coverage: 91.595% (+0.02%) from 91.571%
thomas.goyne_114

push

Evergreen

web-flow
Merge pull request #7085 from realm/release/13.23.2

Release/13.23.2

91732 of 168218 branches covered (0.0%)

230210 of 251336 relevant lines covered (91.59%)

6770777.37 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

76.12
/src/realm/sync/noinst/sync_metadata_schema.cpp
1
/*************************************************************************
2
 *
3
 * Copyright 2022 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

19
#include <realm/sync/noinst/sync_metadata_schema.hpp>
20

21
#include <realm/data_type.hpp>
22
#include <realm/transaction.hpp>
23
#include <realm/util/flat_map.hpp>
24
#include <stdexcept>
25

26
namespace realm::sync {
27
namespace {
28

29
constexpr static std::string_view c_flx_metadata_table("flx_metadata");
30
constexpr static std::string_view c_sync_internal_schemas_table("sync_internal_schemas");
31
constexpr static std::string_view c_meta_schema_version_field("schema_version");
32
constexpr static std::string_view c_meta_schema_schema_group_field("schema_group_name");
33

34
} // namespace
35

36
void create_sync_metadata_schema(const TransactionRef& tr, std::vector<SyncMetadataTable>* tables)
37
{
2,612✔
38
    util::FlatMap<std::string_view, TableRef> found_tables;
2,612✔
39
    for (auto& table : *tables) {
4,792✔
40
        if (tr->has_table(table.name)) {
4,792✔
41
            throw std::runtime_error(
×
42
                util::format("table %1 already existed when creating internal tables for sync", table.name));
×
43
        }
×
44
        TableRef table_ref;
4,792✔
45
        if (table.is_embedded) {
4,792✔
46
            table_ref = tr->add_table(table.name, Table::Type::Embedded);
2,180✔
47
        }
2,180✔
48
        else if (table.pk_info) {
2,612✔
49
            table_ref = tr->add_table_with_primary_key(table.name, table.pk_info->data_type, table.pk_info->name,
2,380✔
50
                                                       table.pk_info->is_optional);
2,380✔
51
            *table.pk_info->key_out = table_ref->get_primary_key_column();
2,380✔
52
        }
2,380✔
53
        else {
232✔
54
            table_ref = tr->add_table(table.name);
232✔
55
        }
232✔
56

2,384✔
57
        found_tables.insert({table.name, table_ref});
4,792✔
58
        *table.key_out = table_ref->get_key();
4,792✔
59
    }
4,792✔
60

1,300✔
61
    for (auto& table : *tables) {
4,792✔
62
        auto& table_ref = found_tables.at(table.name);
4,792✔
63
        for (auto& column : table.columns) {
19,832✔
64
            if (column.data_type == type_LinkList) {
19,832✔
65
                auto target_table_it = found_tables.find(column.target_table);
1,468✔
66
                if (target_table_it == found_tables.end()) {
1,468✔
67
                    throw std::runtime_error(
×
68
                        util::format("cannot link to non-existant table %1 from internal sync table %2",
×
69
                                     column.target_table, table.name));
×
70
                }
×
71
                *column.key_out = table_ref->add_column_list(*target_table_it->second, column.name);
1,468✔
72
            }
1,468✔
73
            else if (column.data_type == type_Link) {
18,364✔
74
                auto target_table_it = found_tables.find(column.target_table);
712✔
75
                if (target_table_it == found_tables.end()) {
712✔
76
                    throw std::runtime_error(
×
77
                        util::format("cannot link to non-existant table %1 from internal sync table %2",
×
78
                                     column.target_table, table.name));
×
79
                }
×
80
                *column.key_out = table_ref->add_column(*target_table_it->second, column.name);
712✔
81
            }
712✔
82
            else {
17,652✔
83
                *column.key_out = table_ref->add_column(column.data_type, column.name, column.is_optional);
17,652✔
84
            }
17,652✔
85
        }
19,832✔
86
    }
4,792✔
87
}
2,612✔
88

89
void load_sync_metadata_schema(const TransactionRef& tr, std::vector<SyncMetadataTable>* tables)
90
{
1,856✔
91
    for (auto& table : *tables) {
2,616✔
92
        auto table_ref = tr->get_table(table.name);
2,616✔
93
        if (!table_ref) {
2,616✔
94
            throw std::runtime_error(util::format("could not find internal sync table %1", table.name));
×
95
        }
×
96

1,326✔
97
        *table.key_out = table_ref->get_key();
2,616✔
98
        if (table.pk_info) {
2,616✔
99
            auto pk_col = table_ref->get_primary_key_column();
1,832✔
100
            if (auto pk_name = table_ref->get_column_name(pk_col); pk_name != table.pk_info->name) {
1,832✔
101
                throw std::runtime_error(util::format(
×
102
                    "primary key name of sync internal table %1 does not match (stored: %2, defined: %3)", table.name,
×
103
                    pk_name, table.pk_info->name));
×
104
            }
×
105
            if (auto pk_type = table_ref->get_column_type(pk_col); pk_type != table.pk_info->data_type) {
1,832✔
106
                throw std::runtime_error(util::format(
×
107
                    "primary key type of sync internal table %1 does not match (stored: %2, defined: %3)", table.name,
×
108
                    pk_type, table.pk_info->data_type));
×
109
            }
×
110
            if (auto is_nullable = table_ref->is_nullable(pk_col); is_nullable != table.pk_info->is_optional) {
1,832✔
111
                throw std::runtime_error(util::format(
×
112
                    "primary key nullabilty of sync internal table %1 does not match (stored: %2, defined: %3)",
×
113
                    table.name, is_nullable, table.pk_info->is_optional));
×
114
            }
×
115
            *table.pk_info->key_out = pk_col;
1,832✔
116
        }
1,832✔
117
        else if (table.is_embedded && !table_ref->is_embedded()) {
784✔
118
            throw std::runtime_error(
×
119
                util::format("internal sync table %1 should be embedded, but is not", table.name));
×
120
        }
×
121

1,326✔
122
        if (table.columns.size() + size_t(table.pk_info ? 1 : 0) != table_ref->get_column_count()) {
2,616✔
123
            throw std::runtime_error(
×
124
                util::format("sync internal table %1 has a different number of columns than its schema", table.name));
×
125
        }
×
126

1,326✔
127
        for (auto& col : table.columns) {
7,286✔
128
            auto col_key = table_ref->get_column_key(col.name);
7,286✔
129
            if (!col_key) {
7,286✔
130
                throw std::runtime_error(
×
131
                    util::format("column %1 is missing in sync internal table %2", col.name, table.name));
×
132
            }
×
133

3,710✔
134
            auto found_col_type = table_ref->get_column_type(col_key);
7,286✔
135
            if (found_col_type != col.data_type) {
7,286✔
136
                throw std::runtime_error(
×
137
                    util::format("column %1 in sync internal table %2 is the wrong type", col.name, table.name));
×
138
            }
×
139

3,710✔
140
            if (col.is_optional != table_ref->is_nullable(col_key)) {
7,286✔
141
                throw std::runtime_error(
×
142
                    util::format("column %1 in sync internal table %2 has different nullabilty than in its schema",
×
143
                                 col.name, table.name));
×
144
            }
×
145

3,710✔
146
            if (col.data_type == type_LinkList &&
7,286✔
147
                table_ref->get_link_target(col_key)->get_name() != col.target_table) {
3,932✔
148
                throw std::runtime_error(
×
149
                    util::format("column %1 in sync internal table %2 links to the wrong table %3", col.name,
×
150
                                 table.name, table_ref->get_link_target(col_key)->get_name()));
×
151
            }
×
152
            *col.key_out = col_key;
7,286✔
153
        }
7,286✔
154
    }
2,616✔
155
}
1,856✔
156

157
SyncMetadataSchemaVersionsReader::SyncMetadataSchemaVersionsReader(const TransactionRef& tr)
158
{
159
    TableKey legacy_table_key;
4,868✔
160
    ColKey legacy_version_key;
4,868✔
161
    std::vector<SyncMetadataTable> legacy_table_def{
4,868✔
162
        {&legacy_table_key, c_flx_metadata_table, {{&legacy_version_key, c_meta_schema_version_field, type_Int}}}};
478✔
163
    std::vector<SyncMetadataTable> unified_schema_version_table_def{
×
164
        {&m_table,
×
165
         c_sync_internal_schemas_table,
×
166
         {&m_schema_group_field, c_meta_schema_schema_group_field, type_String},
478✔
167
         {{&m_version_field, c_meta_schema_version_field, type_Int}}}};
478✔
168

4,390✔
169
    REALM_ASSERT_3(tr->get_transact_stage(), ==, DB::transact_Reading);
1,700✔
170
    // If the legacy_meta_table exists, then this table hasn't been converted and
1,700✔
171
    // the metadata schema versions information has not been upgraded/not accurate
1,700✔
172
    if (tr->has_table(c_flx_metadata_table)) {
1,700✔
173
        return;
1,700✔
174
    }
4,868✔
175

176
    if (tr->has_table(c_sync_internal_schemas_table)) {
177
        // Load m_table with the table/schema information
178
        load_sync_metadata_schema(tr, &unified_schema_version_table_def);
4,892✔
179
    }
4,892✔
180
}
4,892✔
181

182
std::optional<int64_t> SyncMetadataSchemaVersionsReader::get_version_for(const TransactionRef& tr,
183
                                                                         std::string_view schema_group_name)
184
{
4,920✔
185
    if (!m_table) {
4,920✔
186
        return util::none;
1,582✔
187
    }
3,518✔
188

744✔
189
    auto schema_versions = tr->get_table(m_table);
744✔
190
    auto obj_key = schema_versions->find_primary_key(Mixed{StringData(schema_group_name)});
2,774✔
191
    if (!obj_key) {
2,774✔
192
        return util::none;
706✔
193
    }
1,402✔
194
    auto metadata_obj = schema_versions->get_object(obj_key);
1,402✔
195
    if (!metadata_obj) {
1,402✔
196
        return util::none;
904✔
197
    }
904✔
198

498✔
199
    return metadata_obj.get<int64_t>(m_version_field);
498✔
200
}
498✔
201

202
SyncMetadataSchemaVersions::SyncMetadataSchemaVersions(const TransactionRef& tr)
203
    : SyncMetadataSchemaVersionsReader(tr)
1,720✔
204
{
1,720✔
205
    TableKey legacy_table_key;
1,720✔
206
    ColKey legacy_version_key;
856✔
207
    std::vector<SyncMetadataTable> legacy_table_def{
1,720✔
208
        {&legacy_table_key, c_flx_metadata_table, {{&legacy_version_key, c_meta_schema_version_field, type_Int}}}};
1,720✔
209
    std::vector<SyncMetadataTable> unified_schema_version_table_def{
1,720✔
210
        {&m_table,
1,720✔
211
         c_sync_internal_schemas_table,
212
         {&m_schema_group_field, c_meta_schema_schema_group_field, type_String},
213
         {{&m_version_field, c_meta_schema_version_field, type_Int}}}};
6,612✔
214

6,612✔
215
    REALM_ASSERT_3(tr->get_transact_stage(), ==, DB::transact_Reading);
404✔
216
    // If the versions table exists, then m_table would have been initialized by the reader constructor
812✔
217
    // If the versions table doesn't exist, then initialize it now
812✔
218
    if (!m_table) {
2,726✔
219
        // table should have already been initialized or needs to be created,
5,800✔
220
        // but re-initialize in case it isn't (e.g. both unified and legacy tables exist in DB)
5,800✔
221
        if (REALM_UNLIKELY(tr->has_table(c_sync_internal_schemas_table))) {
5,800✔
222
            load_sync_metadata_schema(tr, &unified_schema_version_table_def);
5,800✔
223
        }
5,800✔
224
        else {
2,726✔
225
            tr->promote_to_write();
5,800✔
226
            create_sync_metadata_schema(tr, &unified_schema_version_table_def);
694✔
227
            tr->commit_and_continue_as_read();
1,378✔
228
        }
1,378✔
229
    }
1,378✔
230

2,032✔
231
    if (!tr->has_table(c_flx_metadata_table)) {
2,032✔
232
        return;
4,422✔
233
    }
4,422✔
234

12✔
235
    // Convert the legacy table to the regular schema versions table if it exists
12✔
236
    load_sync_metadata_schema(tr, &legacy_table_def);
2,032✔
237
    // Migrate from just having a subscription store metadata table to having multiple table groups with multiple
4,422✔
238
    // versions.
3,510✔
239
    tr->promote_to_write();
3,510✔
240
    auto legacy_meta_table = tr->get_table(legacy_table_key);
454✔
241
    auto legacy_obj = legacy_meta_table->get_object(0);
912✔
242
    // Only the flx subscription store can potentially have the legacy metadata table
454✔
243
    set_version_for(tr, internal_schema_groups::c_flx_subscription_store,
912✔
244
                    legacy_obj.get<int64_t>(legacy_version_key));
2✔
245
    tr->remove_table(legacy_table_key);
2✔
246
    tr->commit_and_continue_as_read();
4✔
247
}
4✔
248

4✔
249
void SyncMetadataSchemaVersions::set_version_for(const TransactionRef& tr, std::string_view schema_group_name,
4✔
250
                                                 int64_t version)
4✔
251
{
4✔
252
    REALM_ASSERT(m_table);
912✔
253

254
    auto schema_versions = tr->get_table(m_table);
255
    auto metadata_obj = schema_versions->create_object_with_primary_key(Mixed{StringData(schema_group_name)});
256
    metadata_obj.set(m_version_field, version);
257
}
258

259
} // namespace realm::sync
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc