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

realm / realm-core / github_pull_request_312964

19 Feb 2025 07:31PM UTC coverage: 90.814% (-0.3%) from 91.119%
github_pull_request_312964

Pull #8071

Evergreen

web-flow
Bump serialize-javascript and mocha

Bumps [serialize-javascript](https://github.com/yahoo/serialize-javascript) to 6.0.2 and updates ancestor dependency [mocha](https://github.com/mochajs/mocha). These dependencies need to be updated together.


Updates `serialize-javascript` from 6.0.0 to 6.0.2
- [Release notes](https://github.com/yahoo/serialize-javascript/releases)
- [Commits](https://github.com/yahoo/serialize-javascript/compare/v6.0.0...v6.0.2)

Updates `mocha` from 10.2.0 to 10.8.2
- [Release notes](https://github.com/mochajs/mocha/releases)
- [Changelog](https://github.com/mochajs/mocha/blob/main/CHANGELOG.md)
- [Commits](https://github.com/mochajs/mocha/compare/v10.2.0...v10.8.2)

---
updated-dependencies:
- dependency-name: serialize-javascript
  dependency-type: indirect
- dependency-name: mocha
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Pull Request #8071: Bump serialize-javascript and mocha

96552 of 179126 branches covered (53.9%)

212672 of 234185 relevant lines covered (90.81%)

3115802.0 hits per line

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

87.7
/src/realm/object-store/sync/impl/sync_file.cpp
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

19
#include <realm/object-store/sync/impl/sync_file.hpp>
20

21
#include <realm/object-store/sync/sync_user.hpp>
22

23
#include <realm/db.hpp>
24
#include <realm/object-store/sync/app_config.hpp>
25
#include <realm/sync/config.hpp>
26
#include <realm/util/file.hpp>
27
#include <realm/util/hex_dump.hpp>
28
#include <realm/util/sha_crypto.hpp>
29
#include <realm/util/time.hpp>
30
#include <realm/util/scope_exit.hpp>
31

32
#include <iomanip>
33
#include <sstream>
34
#include <system_error>
35
#include <fstream>
36

37
#ifdef _WIN32
38
#include <io.h>
39
#include <fcntl.h>
40

41
inline static int mkstemp(char* _template)
42
{
43
    return _open(_mktemp(_template), _O_CREAT | _O_TEMPORARY, _S_IREAD | _S_IWRITE);
44
}
45
#else
46
#include <unistd.h>
47
#endif
48

49

50
using File = realm::util::File;
51

52
namespace realm {
53

54
namespace {
55

56
uint8_t value_of_hex_digit(char hex_digit)
57
{
38✔
58
    if (hex_digit >= '0' && hex_digit <= '9') {
38✔
59
        return hex_digit - '0';
20✔
60
    }
20✔
61
    else if (hex_digit >= 'A' && hex_digit <= 'F') {
18✔
62
        return 10 + hex_digit - 'A';
18✔
63
    }
18✔
64
    else if (hex_digit >= 'a' && hex_digit <= 'f') {
×
65
        return 10 + hex_digit - 'a';
×
66
    }
×
67
    else {
×
68
        throw LogicError(ErrorCodes::InvalidArgument, "Cannot get the value of a character that isn't a hex digit.");
×
69
    }
×
70
}
38✔
71

72
bool filename_is_reserved(const std::string& filename)
73
{
2,431✔
74
    return (filename == "." || filename == "..");
2,431✔
75
}
2,431✔
76

77
bool character_is_unreserved(char character)
78
{
25,417✔
79
    bool is_capital_letter = (character >= 'A' && character <= 'Z');
25,417✔
80
    bool is_lowercase_letter = (character >= 'a' && character <= 'z');
25,417✔
81
    bool is_number = (character >= '0' && character <= '9');
25,417✔
82
    bool is_allowed_symbol = (character == '-' || character == '_' || character == '.');
25,417✔
83
    return is_capital_letter || is_lowercase_letter || is_number || is_allowed_symbol;
25,417✔
84
}
25,417✔
85

86
char decoded_char_for(const std::string& percent_encoding, size_t index)
87
{
19✔
88
    if (index + 2 >= percent_encoding.length()) {
19✔
89
        throw LogicError(ErrorCodes::InvalidArgument,
×
90
                         "Malformed string: not enough characters after '%' before end of string.");
×
91
    }
×
92
    REALM_ASSERT(percent_encoding[index] == '%');
19✔
93
    return (16 * value_of_hex_digit(percent_encoding[index + 1])) + value_of_hex_digit(percent_encoding[index + 2]);
19✔
94
}
19✔
95

96
} // namespace
97

98
namespace util {
99

100
std::string make_percent_encoded_string(const std::string& raw_string)
101
{
2,454✔
102
    std::string buffer;
2,454✔
103
    buffer.reserve(raw_string.size());
2,454✔
104
    for (size_t i = 0; i < raw_string.size(); i++) {
27,837✔
105
        unsigned char character = raw_string[i];
25,383✔
106
        if (character_is_unreserved(character)) {
25,383✔
107
            buffer.push_back(character);
25,107✔
108
        }
25,107✔
109
        else {
276✔
110
            buffer.resize(buffer.size() + 3);
276✔
111
            // Format string must resolve to exactly 3 characters.
112
            snprintf(&buffer.back() - 2, 4, "%%%2X", character);
276✔
113
        }
276✔
114
    }
25,383✔
115
    return buffer;
2,454✔
116
}
2,454✔
117

118
std::string make_raw_string(const std::string& percent_encoded_string)
119
{
2✔
120
    std::string buffer;
2✔
121
    size_t input_len = percent_encoded_string.length();
2✔
122
    buffer.reserve(input_len);
2✔
123
    size_t idx = 0;
2✔
124
    while (idx < input_len) {
55✔
125
        char current = percent_encoded_string[idx];
53✔
126
        if (current == '%') {
53✔
127
            // Decode. +3.
128
            buffer.push_back(decoded_char_for(percent_encoded_string, idx));
19✔
129
            idx += 3;
19✔
130
        }
19✔
131
        else {
34✔
132
            // No need to decode. +1.
133
            if (!character_is_unreserved(current)) {
34✔
134
                throw LogicError(ErrorCodes::InvalidArgument,
×
135
                                 "Input string is invalid: contains reserved characters.");
×
136
            }
×
137
            buffer.push_back(current);
34✔
138
            idx++;
34✔
139
        }
34✔
140
    }
53✔
141
    return buffer;
2✔
142
}
2✔
143

144
std::string file_path_by_appending_component(const std::string& path, const std::string& component,
145
                                             FilePathType path_type)
146
{
5,884✔
147
#ifdef _WIN32
148
    const char separator = '\\';
149
#else
150
    const char separator = '/';
5,884✔
151
#endif
5,884✔
152
    std::string buffer;
5,884✔
153
    buffer.reserve(2 + path.length() + component.length());
5,884✔
154
    buffer.append(path);
5,884✔
155
    std::string terminal = "";
5,884✔
156
    if (path_type == FilePathType::Directory && component[component.length() - 1] != separator) {
5,884✔
157
        terminal = separator;
5,374✔
158
    }
5,374✔
159
    char path_last = path[path.length() - 1];
5,884✔
160
    char component_first = component[0];
5,884✔
161
    if (path_last == separator && component_first == separator) {
5,884✔
162
        buffer.append(component.substr(1));
×
163
        buffer.append(terminal);
×
164
    }
×
165
    else if (path_last == separator || component_first == separator) {
5,884✔
166
        buffer.append(component);
3,625✔
167
        buffer.append(terminal);
3,625✔
168
    }
3,625✔
169
    else {
2,259✔
170
        buffer.append(std::string(1, separator));
2,259✔
171
        buffer.append(component);
2,259✔
172
        buffer.append(terminal);
2,259✔
173
    }
2,259✔
174
    return buffer;
5,884✔
175
}
5,884✔
176

177
std::string file_path_by_appending_extension(const std::string& path, const std::string& extension)
178
{
3✔
179
    std::string buffer;
3✔
180
    buffer.reserve(1 + path.length() + extension.length());
3✔
181
    buffer.append(path);
3✔
182
    char path_last = path[path.length() - 1];
3✔
183
    char extension_first = extension[0];
3✔
184
    if (path_last == '.' && extension_first == '.') {
3✔
185
        buffer.append(extension.substr(1));
1✔
186
    }
1✔
187
    else if (path_last == '.' || extension_first == '.') {
2✔
188
        buffer.append(extension);
2✔
189
    }
2✔
190
    else {
×
191
        buffer.append(".");
×
192
        buffer.append(extension);
×
193
    }
×
194
    return buffer;
3✔
195
}
3✔
196

197
std::string create_timestamped_template(const std::string& prefix, int wildcard_count)
198
{
37✔
199
    constexpr int WILDCARD_MAX = 20;
37✔
200
    constexpr int WILDCARD_MIN = 6;
37✔
201
    wildcard_count = std::min(WILDCARD_MAX, std::max(WILDCARD_MIN, wildcard_count));
37✔
202
    std::time_t time = std::time(nullptr);
37✔
203
    std::stringstream stream;
37✔
204
    stream << prefix << "-" << util::format_local_time(time, "%Y%m%d-%H%M%S") << "-"
37✔
205
           << std::string(wildcard_count, 'X');
37✔
206
    return stream.str();
37✔
207
}
37✔
208

209
std::string reserve_unique_file_name(const std::string& path, const std::string& template_string)
210
{
37✔
211
    REALM_ASSERT_DEBUG(template_string.find("XXXXXX") != std::string::npos);
37✔
212
    std::string path_buffer = file_path_by_appending_component(path, template_string, FilePathType::File);
37✔
213
    int fd = mkstemp(&path_buffer[0]);
37✔
214
    if (fd < 0) {
37✔
215
        int err = errno;
×
216
        throw RuntimeError(ErrorCodes::FileOperationFailed,
×
217
                           util::format("Failed to make temporary path: %1 (%2)",
×
218
                                        std::system_error(err, std::system_category()).what(), err));
×
219
    }
×
220
    // Remove the file so we can use the name for our own file.
221
#ifdef _WIN32
222
    _close(fd);
223
    _unlink(path_buffer.c_str());
224
#else
225
    close(fd);
37✔
226
    unlink(path_buffer.c_str());
37✔
227
#endif
37✔
228
    return path_buffer;
37✔
229
}
37✔
230

231
static std::string validate_and_clean_path(const std::string& path)
232
{
2,431✔
233
    REALM_ASSERT(path.length() > 0);
2,431✔
234
    std::string escaped_path = util::make_percent_encoded_string(path);
2,431✔
235
    if (filename_is_reserved(escaped_path))
2,431✔
236
        throw LogicError(
×
237
            ErrorCodes::InvalidArgument,
×
238
            util::format("A path can't have an identifier reserved by the filesystem: '%1'", escaped_path));
×
239
    return escaped_path;
2,431✔
240
}
2,431✔
241

242
} // namespace util
243

244
SyncFileManager::SyncFileManager(const app::AppConfig& config)
245
    : m_base_path(util::file_path_by_appending_component(config.base_file_path, c_sync_directory,
2,254✔
246
                                                         util::FilePathType::Directory))
2,254✔
247
    , m_app_path(util::file_path_by_appending_component(m_base_path, util::validate_and_clean_path(config.app_id),
2,254✔
248
                                                        util::FilePathType::Directory))
2,254✔
249
{
2,254✔
250
    util::try_make_dir(m_base_path);
2,254✔
251
    util::try_make_dir(m_app_path);
2,254✔
252
}
2,254✔
253

254
std::string SyncFileManager::get_special_directory(std::string directory_name) const
255
{
391✔
256
    auto dir_path = file_path_by_appending_component(m_app_path, directory_name, util::FilePathType::Directory);
391✔
257
    util::try_make_dir(dir_path);
391✔
258
    return dir_path;
391✔
259
}
391✔
260

261
std::string SyncFileManager::user_directory(const std::string& user_id) const
262
{
45✔
263
    std::string user_path = get_user_directory_path(user_id);
45✔
264
    util::try_make_dir(user_path);
45✔
265
    return user_path;
45✔
266
}
45✔
267

268
void SyncFileManager::remove_user_realms(const std::string& user_id) const
269
{
15✔
270
    // The following is redundant except for apps built before file tracking.
271
    std::string user_path = get_user_directory_path(user_id);
15✔
272
    util::try_remove_dir_recursive(user_path);
15✔
273
}
15✔
274

275
bool SyncFileManager::remove_realm(const std::string& absolute_path) const
276
{
22✔
277
    REALM_ASSERT(absolute_path.length() > 0);
22✔
278
    bool success = true;
22✔
279
    try {
22✔
280
        constexpr bool delete_lockfile = true;
22✔
281
        realm::DB::delete_files(absolute_path, &success, delete_lockfile);
22✔
282
    }
22✔
283
    catch (FileAccessError const&) {
22✔
284
        success = false;
×
285
    }
×
286
    return success;
22✔
287
}
22✔
288

289
bool SyncFileManager::copy_realm_file(const std::string& old_path, const std::string& new_path) const
290
{
7✔
291
    REALM_ASSERT(old_path.length() > 0);
7✔
292
    try {
7✔
293
        const bool overwrite_existing = false;
7✔
294
        return File::copy(old_path, new_path, overwrite_existing);
7✔
295
    }
7✔
296
    catch (FileAccessError const&) {
7✔
297
        return false;
×
298
    }
×
299
    return true;
×
300
}
7✔
301

302
bool SyncFileManager::remove_realm(const std::string& user_id, const std::vector<std::string>& legacy_user_identities,
303
                                   const std::string& raw_realm_path, const std::string& partition) const
304
{
2✔
305
    auto existing = get_existing_realm_file_path(user_id, legacy_user_identities, raw_realm_path, partition);
2✔
306
    if (existing) {
2✔
307
        return remove_realm(*existing);
1✔
308
    }
1✔
309
    return false; // if there is nothing to remove this is considered to be not successful
1✔
310
}
2✔
311

312
bool SyncFileManager::try_file_exists(const std::string& path) noexcept
313
{
121✔
314
    try {
121✔
315
        // May throw; for example when the path is too long
316
        return util::File::exists(path);
121✔
317
    }
121✔
318
    catch (const std::exception&) {
121✔
319
        return false;
4✔
320
    }
4✔
321
}
121✔
322

323
static bool try_file_remove(const std::string& path) noexcept
324
{
22✔
325
    try {
22✔
326
        return util::File::try_remove(path);
22✔
327
    }
22✔
328
    catch (const std::exception&) {
22✔
329
        return false;
3✔
330
    }
3✔
331
}
22✔
332

333
util::Optional<std::string>
334
SyncFileManager::get_existing_realm_file_path(const std::string& user_id,
335
                                              const std::vector<std::string>& legacy_user_identities,
336
                                              const std::string& realm_file_name, const std::string& partition) const
337
{
26✔
338
    std::string preferred_name_without_suffix = preferred_realm_path_without_suffix(user_id, realm_file_name);
26✔
339
    if (try_file_exists(preferred_name_without_suffix)) {
26✔
340
        return preferred_name_without_suffix;
×
341
    }
×
342

343
    std::string preferred_name_with_suffix = preferred_name_without_suffix + c_realm_file_suffix;
26✔
344
    if (try_file_exists(preferred_name_with_suffix)) {
26✔
345
        return preferred_name_with_suffix;
2✔
346
    }
2✔
347

348
    // Shorten the Realm path to just `<rootDir>/<hashedAbsolutePath>.realm`
349
    std::string hashed_name = fallback_hashed_realm_file_path(preferred_name_without_suffix);
24✔
350
    std::string hashed_path = hashed_name + c_realm_file_suffix;
24✔
351
    if (try_file_exists(hashed_path)) {
24✔
352
        // detected that the hashed fallback has been used previously
353
        // it was created for a reason so keep using it
354
        return hashed_path;
1✔
355
    }
1✔
356

357
    // The legacy fallback paths are not applicable to flexible sync
358
    if (partition.empty()) {
23✔
359
        return util::none;
5✔
360
    }
5✔
361

362
    // We used to hash the string value of the partition. For compatibility, check that SHA256
363
    // hash file name exists, and if it does, continue to use it.
364
    if (!partition.empty()) {
18✔
365
        std::string hashed_partition_path = legacy_hashed_partition_path(user_id, partition);
18✔
366
        if (try_file_exists(hashed_partition_path)) {
18✔
367
            return hashed_partition_path;
×
368
        }
×
369
    }
18✔
370

371
    for (auto& legacy_identity : legacy_user_identities) {
18✔
372
        // retain support for legacy paths
373
        std::string old_path = legacy_realm_file_path(legacy_identity, realm_file_name);
14✔
374
        if (try_file_exists(old_path)) {
14✔
375
            return old_path;
1✔
376
        }
1✔
377
        // retain support for legacy local identity paths
378
        std::string old_local_identity_path = legacy_local_identity_path(legacy_identity, partition);
13✔
379
        if (try_file_exists(old_local_identity_path)) {
13✔
380
            return old_local_identity_path;
2✔
381
        }
2✔
382
    }
13✔
383

384
    return util::none;
15✔
385
}
18✔
386

387
std::string SyncFileManager::realm_file_path(const std::string& user_id,
388
                                             const std::vector<std::string>& legacy_user_identities,
389
                                             const std::string& realm_file_name, const std::string& partition) const
390
{
24✔
391
    auto existing_path = get_existing_realm_file_path(user_id, legacy_user_identities, realm_file_name, partition);
24✔
392
    if (existing_path) {
24✔
393
        return *existing_path;
5✔
394
    }
5✔
395

396
    // since this appears to be a new file, test the normal location
397
    // we use a test file with the same name and a suffix of the
398
    // same length, so we can catch "filename too long" errors on windows
399
    std::string preferred_name_without_suffix = preferred_realm_path_without_suffix(user_id, realm_file_name);
19✔
400
    std::string preferred_name_with_suffix = preferred_name_without_suffix + c_realm_file_suffix;
19✔
401
    try {
19✔
402
        std::string test_path = preferred_name_without_suffix + c_realm_file_test_suffix;
19✔
403
        auto defer = util::make_scope_exit([test_path]() noexcept {
19✔
404
            try_file_remove(test_path);
19✔
405
        });
19✔
406
        util::File f(test_path, util::File::Mode::mode_Write);
19✔
407
        // if the test file succeeds, delete it and return the preferred location
408
    }
19✔
409
    catch (const FileAccessError&) {
19✔
410
        // the preferred test failed, test the hashed path
411
        std::string hashed_name = fallback_hashed_realm_file_path(preferred_name_without_suffix);
3✔
412
        std::string hashed_path = hashed_name + c_realm_file_suffix;
3✔
413
        try {
3✔
414
            std::string test_hashed_path = hashed_name + c_realm_file_test_suffix;
3✔
415
            auto defer = util::make_scope_exit([test_hashed_path]() noexcept {
3✔
416
                try_file_remove(test_hashed_path);
3✔
417
            });
3✔
418
            util::File f(test_hashed_path, util::File::Mode::mode_Write);
3✔
419
            // at this point the create succeeded, clean up the test file and return the hashed path
420
            return hashed_path;
3✔
421
        }
3✔
422
        catch (const FileAccessError& e_hashed) {
3✔
423
            // hashed test path also failed, give up and report error to user.
424
            throw LogicError(ErrorCodes::InvalidArgument,
×
425
                             util::format("A valid realm path cannot be created for the "
×
426
                                          "Realm identity '%1' at neither '%2' nor '%3'. %4",
×
427
                                          realm_file_name, preferred_name_with_suffix, hashed_path, e_hashed.what()));
×
428
        }
×
429
    }
3✔
430

431
    return preferred_name_with_suffix;
16✔
432
}
19✔
433

434
std::string SyncFileManager::metadata_path() const
435
{
353✔
436
    auto dir_path = file_path_by_appending_component(get_utility_directory(), c_metadata_directory,
353✔
437
                                                     util::FilePathType::Directory);
353✔
438
    util::try_make_dir(dir_path);
353✔
439
    return util::file_path_by_appending_component(dir_path, c_metadata_realm);
353✔
440
}
353✔
441

442
bool SyncFileManager::remove_metadata_realm() const
443
{
1✔
444
    auto dir_path = file_path_by_appending_component(get_utility_directory(), c_metadata_directory,
1✔
445
                                                     util::FilePathType::Directory);
1✔
446
    try {
1✔
447
        util::try_remove_dir_recursive(dir_path);
1✔
448
        return true;
1✔
449
    }
1✔
450
    catch (FileAccessError const&) {
1✔
451
        return false;
×
452
    }
×
453
}
1✔
454

455
std::string SyncFileManager::preferred_realm_path_without_suffix(const std::string& user_id,
456
                                                                 const std::string& realm_file_name) const
457
{
45✔
458
    auto escaped_file_name = util::validate_and_clean_path(realm_file_name);
45✔
459
    std::string preferred_name = util::file_path_by_appending_component(user_directory(user_id), escaped_file_name);
45✔
460
    if (StringData(preferred_name).ends_with(c_realm_file_suffix)) {
45✔
461
        preferred_name = preferred_name.substr(0, preferred_name.size() - strlen(c_realm_file_suffix));
5✔
462
    }
5✔
463
    return preferred_name;
45✔
464
}
45✔
465

466
std::string SyncFileManager::fallback_hashed_realm_file_path(const std::string& preferred_path) const
467
{
27✔
468
    std::array<unsigned char, 32> hash;
27✔
469
    util::sha256(preferred_path.data(), preferred_path.size(), hash.data());
27✔
470
    std::string hashed_name =
27✔
471
        util::file_path_by_appending_component(m_app_path, util::hex_dump(hash.data(), hash.size(), ""));
27✔
472
    return hashed_name;
27✔
473
}
27✔
474

475
std::string SyncFileManager::legacy_hashed_partition_path(const std::string& user_id,
476
                                                          const std::string& partition) const
477
{
18✔
478
    std::array<unsigned char, 32> hash;
18✔
479
    util::sha256(partition.data(), partition.size(), hash.data());
18✔
480
    std::string legacy_hashed_file_name = util::hex_dump(hash.data(), hash.size(), "");
18✔
481
    std::string legacy_partition_path = util::file_path_by_appending_component(
18✔
482
        get_user_directory_path(user_id), legacy_hashed_file_name + c_realm_file_suffix);
18✔
483
    return legacy_partition_path;
18✔
484
}
18✔
485

486
std::string SyncFileManager::legacy_realm_file_path(const std::string& local_user_identity,
487
                                                    const std::string& realm_file_name) const
488
{
14✔
489
    auto path =
14✔
490
        util::file_path_by_appending_component(m_app_path, c_legacy_sync_directory, util::FilePathType::Directory);
14✔
491
    path = util::file_path_by_appending_component(path, util::validate_and_clean_path(local_user_identity),
14✔
492
                                                  util::FilePathType::Directory);
14✔
493
    path = util::file_path_by_appending_component(path, util::validate_and_clean_path(realm_file_name));
14✔
494
    return path;
14✔
495
}
14✔
496

497
std::string SyncFileManager::legacy_local_identity_path(const std::string& local_user_identity,
498
                                                        const std::string& realm_file_name) const
499
{
13✔
500
    auto escaped_file_name = util::validate_and_clean_path(realm_file_name);
13✔
501
    std::string user_path = get_user_directory_path(local_user_identity);
13✔
502
    std::string path_name = util::file_path_by_appending_component(user_path, escaped_file_name);
13✔
503
    std::string path = path_name + c_realm_file_suffix;
13✔
504

505
    return path;
13✔
506
}
13✔
507

508
std::string SyncFileManager::get_user_directory_path(const std::string& user_id) const
509
{
91✔
510
    return file_path_by_appending_component(m_app_path, util::validate_and_clean_path(user_id),
91✔
511
                                            util::FilePathType::Directory);
91✔
512
}
91✔
513

514
static std::string string_from_partition(std::string_view partition)
515
{
7✔
516
    bson::Bson partition_value = bson::parse(partition);
7✔
517
    switch (partition_value.type()) {
7✔
518
        case bson::Bson::Type::Int32:
1✔
519
            return util::format("i_%1", static_cast<int32_t>(partition_value));
1✔
520
        case bson::Bson::Type::Int64:
1✔
521
            return util::format("l_%1", static_cast<int64_t>(partition_value));
1✔
522
        case bson::Bson::Type::String:
2✔
523
            return util::format("s_%1", static_cast<std::string>(partition_value));
2✔
524
        case bson::Bson::Type::ObjectId:
1✔
525
            return util::format("o_%1", static_cast<ObjectId>(partition_value).to_string());
1✔
526
        case bson::Bson::Type::Uuid:
1✔
527
            return util::format("u_%1", static_cast<UUID>(partition_value).to_string());
1✔
528
        case bson::Bson::Type::Null:
1✔
529
            return "null";
1✔
530
        default:
✔
531
            throw InvalidArgument(util::format("Unsupported partition key value: '%1'. Only int, string "
×
532
                                               "UUID and ObjectId types are currently supported.",
×
533
                                               partition_value.to_string()));
×
534
    }
7✔
535
}
7✔
536

537
std::string SyncFileManager::path_for_realm(const SyncConfig& config,
538
                                            std::optional<std::string> custom_file_name) const
539
{
14✔
540
    auto user = config.user;
14✔
541
    REALM_ASSERT(user);
14✔
542
    // Attempt to make a nicer filename which will ease debugging when
543
    // locating files in the filesystem.
544
    auto file_name = [&]() -> std::string {
14✔
545
        if (custom_file_name) {
14✔
546
            return *custom_file_name;
6✔
547
        }
6✔
548
        if (config.flx_sync_requested) {
8✔
549
            REALM_ASSERT_DEBUG(config.partition_value.empty());
1✔
550
            return "flx_sync_default";
1✔
551
        }
1✔
552
        return string_from_partition(config.partition_value);
7✔
553
    }();
8✔
554
    auto path = realm_file_path(user->user_id(), user->legacy_identities(), file_name, config.partition_value);
14✔
555
    user->track_realm(path);
14✔
556
    return path;
14✔
557
}
14✔
558

559
} // namespace realm
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

© 2025 Coveralls, Inc