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

realm / realm-core / 2213

10 Apr 2024 11:21PM UTC coverage: 91.792% (-0.8%) from 92.623%
2213

push

Evergreen

web-flow
Add missing availability checks for SecCopyErrorMessageString (#7577)

This requires iOS 11.3 and we currently target iOS 11.

94842 of 175770 branches covered (53.96%)

7 of 22 new or added lines in 2 files covered. (31.82%)

1861 existing lines in 82 files now uncovered.

242866 of 264583 relevant lines covered (91.79%)

5593111.45 hits per line

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

34.1
/src/realm/object-store/c_api/app.cpp
1
////////////////////////////////////////////////////////////////////////////
2
//
3
// Copyright 2021 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 utilied.
14
// See the License for the specific language governing permissions and
15
// limitations under the License.
16
//
17
////////////////////////////////////////////////////////////////////////////
18

19
#include "types.hpp"
20
#include "util.hpp"
21
#include "conversion.hpp"
22

23
#include <realm/object-store/sync/sync_user.hpp>
24
#include <realm/object-store/sync/mongo_client.hpp>
25
#include <realm/object-store/sync/mongo_database.hpp>
26

27
namespace realm::c_api {
28
using namespace realm::app;
29

30
static_assert(realm_user_state_e(SyncUser::State::LoggedOut) == RLM_USER_STATE_LOGGED_OUT);
31
static_assert(realm_user_state_e(SyncUser::State::LoggedIn) == RLM_USER_STATE_LOGGED_IN);
32
static_assert(realm_user_state_e(SyncUser::State::Removed) == RLM_USER_STATE_REMOVED);
33

34
static_assert(realm_auth_provider_e(AuthProvider::ANONYMOUS) == RLM_AUTH_PROVIDER_ANONYMOUS);
35
static_assert(realm_auth_provider_e(AuthProvider::ANONYMOUS_NO_REUSE) == RLM_AUTH_PROVIDER_ANONYMOUS_NO_REUSE);
36
static_assert(realm_auth_provider_e(AuthProvider::FACEBOOK) == RLM_AUTH_PROVIDER_FACEBOOK);
37
static_assert(realm_auth_provider_e(AuthProvider::GOOGLE) == RLM_AUTH_PROVIDER_GOOGLE);
38
static_assert(realm_auth_provider_e(AuthProvider::APPLE) == RLM_AUTH_PROVIDER_APPLE);
39
static_assert(realm_auth_provider_e(AuthProvider::CUSTOM) == RLM_AUTH_PROVIDER_CUSTOM);
40
static_assert(realm_auth_provider_e(AuthProvider::USERNAME_PASSWORD) == RLM_AUTH_PROVIDER_EMAIL_PASSWORD);
41
static_assert(realm_auth_provider_e(AuthProvider::FUNCTION) == RLM_AUTH_PROVIDER_FUNCTION);
42
static_assert(realm_auth_provider_e(AuthProvider::API_KEY) == RLM_AUTH_PROVIDER_API_KEY);
43

44

45
static realm_app_error_t to_capi(const AppError& error)
46
{
2✔
47
    auto ret = realm_app_error_t();
2✔
48

1✔
49
    ret.error = realm_errno_e(error.code());
2✔
50
    ret.categories = ErrorCodes::error_categories(error.code()).value();
2✔
51

1✔
52
    if (error.additional_status_code) {
2✔
53
        ret.http_status_code = *error.additional_status_code;
2✔
54
    }
2✔
55

1✔
56
    ret.message = error.what();
2✔
57

1✔
58
    if (error.link_to_server_logs.size() > 0) {
2✔
59
        ret.link_to_server_logs = error.link_to_server_logs.c_str();
×
60
    }
×
61

1✔
62
    return ret;
2✔
63
}
2✔
64

65
static inline realm_app_user_apikey_t to_capi(const App::UserAPIKey& apikey)
66
{
4✔
67
    return {to_capi(apikey.id), apikey.key ? apikey.key->c_str() : nullptr, apikey.name.c_str(), apikey.disabled};
3✔
68
}
4✔
69

70
static inline auto make_callback(realm_app_void_completion_func_t callback, realm_userdata_t userdata,
71
                                 realm_free_userdata_func_t userdata_free)
72
{
26✔
73
    return
26✔
74
        [callback, userdata = SharedUserdata(userdata, FreeUserdata(userdata_free))](util::Optional<AppError> error) {
26✔
75
            if (error) {
26✔
76
                realm_app_error_t c_err{to_capi(*error)};
×
77
                callback(userdata.get(), &c_err);
×
78
            }
×
79
            else {
26✔
80
                callback(userdata.get(), nullptr);
26✔
81
            }
26✔
82
        };
26✔
83
}
26✔
84

85
static inline auto make_callback(realm_app_user_completion_func_t callback, realm_userdata_t userdata,
86
                                 realm_free_userdata_func_t userdata_free)
87
{
14✔
88
    return [callback, userdata = SharedUserdata(userdata, FreeUserdata(userdata_free))](
14✔
89
               std::shared_ptr<app::User> user, util::Optional<AppError> error) {
14✔
90
        if (error) {
14✔
91
            realm_app_error_t c_err{to_capi(*error)};
×
92
            callback(userdata.get(), nullptr, &c_err);
×
93
        }
×
94
        else {
14✔
95
            auto c_user = realm_user_t(std::move(user));
14✔
96
            callback(userdata.get(), &c_user, nullptr);
14✔
97
        }
14✔
98
    };
14✔
99
}
14✔
100

101
static inline auto make_callback(void (*callback)(realm_userdata_t userdata, realm_app_user_apikey_t*,
102
                                                  const realm_app_error_t*),
103
                                 realm_userdata_t userdata, realm_free_userdata_func_t userdata_free)
104
{
2✔
105
    return [callback, userdata = SharedUserdata(userdata, FreeUserdata(userdata_free))](
2✔
106
               App::UserAPIKey apikey, util::Optional<AppError> error) {
2✔
107
        if (error) {
2✔
108
            realm_app_error_t c_error(to_capi(*error));
×
109
            callback(userdata.get(), nullptr, &c_error);
×
110
        }
×
111
        else {
2✔
112
            realm_app_user_apikey_t c_apikey(to_capi(apikey));
2✔
113
            callback(userdata.get(), &c_apikey, nullptr);
2✔
114
        }
2✔
115
    };
2✔
116
}
2✔
117

118
static inline bson::BsonArray parse_ejson_array(const char* serialized)
119
{
×
120
    if (!serialized) {
×
121
        return {};
×
122
    }
×
123
    else {
×
124
        return bson::BsonArray(bson::parse({serialized, strlen(serialized)}));
×
125
    }
×
126
}
×
127

128
RLM_API const char* realm_app_get_default_base_url(void) noexcept
129
{
2✔
130
    return app::App::default_base_url().data();
2✔
131
}
2✔
132

133
RLM_API realm_app_credentials_t* realm_app_credentials_new_anonymous(bool reuse_credentials) noexcept
134
{
2✔
135
    return new realm_app_credentials_t(AppCredentials::anonymous(reuse_credentials));
2✔
136
}
2✔
137

138
RLM_API realm_app_credentials_t* realm_app_credentials_new_facebook(const char* access_token) noexcept
139
{
×
140
    return new realm_app_credentials_t(AppCredentials::facebook(access_token));
×
141
}
×
142

143
RLM_API realm_app_credentials_t* realm_app_credentials_new_google_id_token(const char* id_token) noexcept
144
{
×
145
    return new realm_app_credentials_t(AppCredentials::google(IdToken(id_token)));
×
146
}
×
147

148
RLM_API realm_app_credentials_t* realm_app_credentials_new_google_auth_code(const char* auth_code) noexcept
149
{
×
150
    return new realm_app_credentials_t(AppCredentials::google(AuthCode(auth_code)));
×
151
}
×
152

153
RLM_API realm_app_credentials_t* realm_app_credentials_new_apple(const char* id_token) noexcept
154
{
×
155
    return new realm_app_credentials_t(AppCredentials::apple(id_token));
×
156
}
×
157

158
RLM_API realm_app_credentials_t* realm_app_credentials_new_jwt(const char* jwt_token) noexcept
159
{
×
160
    return new realm_app_credentials_t(AppCredentials::custom(jwt_token));
×
161
}
×
162

163
RLM_API realm_app_credentials_t* realm_app_credentials_new_email_password(const char* email,
164
                                                                          realm_string_t password) noexcept
165
{
×
166
    return new realm_app_credentials_t(AppCredentials::username_password(email, from_capi(password)));
×
167
}
×
168

169
RLM_API realm_app_credentials_t* realm_app_credentials_new_function(const char* serialized_ejson_payload)
170
{
×
171
    return wrap_err([&] {
×
172
        return new realm_app_credentials_t(AppCredentials::function(serialized_ejson_payload));
×
173
    });
×
174
}
×
175

176
RLM_API realm_app_credentials_t* realm_app_credentials_new_api_key(const char* api_key) noexcept
177
{
×
178
    return new realm_app_credentials_t(AppCredentials::api_key(api_key));
×
179
}
×
180

181
RLM_API realm_auth_provider_e realm_auth_credentials_get_provider(realm_app_credentials_t* credentials) noexcept
182
{
×
183
    return realm_auth_provider_e(credentials->provider());
×
184
}
×
185

186
RLM_API realm_app_config_t* realm_app_config_new(const char* app_id,
187
                                                 const realm_http_transport_t* http_transport) noexcept
188
{
2✔
189
    auto* config = new realm_app_config_t;
2✔
190
    config->app_id = app_id;
2✔
191
    config->transport = *http_transport; // realm_http_transport_t is a shared_ptr
2✔
192
    return config;
2✔
193
}
2✔
194

195
RLM_API void realm_app_config_set_base_url(realm_app_config_t* config, const char* base_url) noexcept
196
{
2✔
197
    config->base_url = std::string(base_url);
2✔
198
}
2✔
199

200
RLM_API void realm_app_config_set_default_request_timeout(realm_app_config_t* config, uint64_t ms) noexcept
201
{
2✔
202
    config->default_request_timeout_ms = ms;
2✔
203
}
2✔
204

205
RLM_API void realm_app_config_set_platform_version(realm_app_config_t* config, const char* platform_version) noexcept
206
{
2✔
207
    config->device_info.platform_version = std::string(platform_version);
2✔
208
}
2✔
209

210
RLM_API void realm_app_config_set_sdk_version(realm_app_config_t* config, const char* sdk_version) noexcept
211
{
2✔
212
    config->device_info.sdk_version = std::string(sdk_version);
2✔
213
}
2✔
214

215
RLM_API void realm_app_config_set_sdk(realm_app_config_t* config, const char* sdk) noexcept
216
{
2✔
217
    config->device_info.sdk = std::string(sdk);
2✔
218
}
2✔
219

220
RLM_API void realm_app_config_set_device_name(realm_app_config_t* config, const char* device_name) noexcept
221
{
2✔
222
    config->device_info.device_name = std::string(device_name);
2✔
223
}
2✔
224

225
RLM_API void realm_app_config_set_device_version(realm_app_config_t* config, const char* device_version) noexcept
226
{
2✔
227
    config->device_info.device_version = std::string(device_version);
2✔
228
}
2✔
229

230
RLM_API void realm_app_config_set_framework_name(realm_app_config_t* config, const char* framework_name) noexcept
231
{
2✔
232
    config->device_info.framework_name = std::string(framework_name);
2✔
233
}
2✔
234

235
RLM_API void realm_app_config_set_framework_version(realm_app_config_t* config,
236
                                                    const char* framework_version) noexcept
237
{
2✔
238
    config->device_info.framework_version = std::string(framework_version);
2✔
239
}
2✔
240

241
RLM_API void realm_app_config_set_bundle_id(realm_app_config_t* config, const char* bundle_id) noexcept
242
{
2✔
243
    config->device_info.bundle_id = std::string(bundle_id);
2✔
244
}
2✔
245

246
RLM_API void realm_app_config_set_base_file_path(realm_app_config_t* config, const char* path) noexcept
247
{
4✔
248
    config->base_file_path = path;
4✔
249
}
4✔
250

251
RLM_API void realm_app_config_set_metadata_mode(realm_app_config_t* config,
252
                                                realm_sync_client_metadata_mode_e mode) noexcept
253
{
8✔
254
    config->metadata_mode = app::AppConfig::MetadataMode(mode);
8✔
255
}
8✔
256

257
RLM_API void realm_app_config_set_metadata_encryption_key(realm_app_config_t* config, const uint8_t key[64]) noexcept
258
{
2✔
259
    config->custom_encryption_key = std::vector<char>(key, key + 64);
2✔
260
}
2✔
261

262
RLM_API void realm_app_config_set_security_access_group(realm_app_config_t* config, const char* group) noexcept
263
{
4✔
264
    config->security_access_group = group;
4✔
265
}
4✔
266

267
RLM_API const char* realm_app_credentials_serialize_as_json(realm_app_credentials_t* app_credentials) noexcept
UNCOV
268
{
×
UNCOV
269
    return wrap_err([&] {
×
270
        return duplicate_string(app_credentials->serialize_as_json());
×
271
    });
×
272
}
×
273

274
RLM_API realm_app_t* realm_app_create(const realm_app_config_t* app_config)
275
{
2✔
276
    return wrap_err([&] {
2✔
277
        return new realm_app_t(App::get_app(app::App::CacheMode::Disabled, *app_config));
2✔
278
    });
2✔
279
}
2✔
280

281
RLM_API realm_app_t* realm_app_create_cached(const realm_app_config_t* app_config)
UNCOV
282
{
×
283
    return wrap_err([&] {
×
284
        return new realm_app_t(App::get_app(app::App::CacheMode::Enabled, *app_config));
×
285
    });
×
UNCOV
286
}
×
287

288
RLM_API bool realm_app_get_cached(const char* app_id, const char* base_url, realm_app_t** out_app)
289
{
×
290
    return wrap_err([&] {
×
UNCOV
291
        auto app =
×
UNCOV
292
            App::get_cached_app(std::string(app_id), base_url ? util::some<std::string>(base_url) : util::none);
×
UNCOV
293
        if (out_app) {
×
UNCOV
294
            *out_app = app ? new realm_app_t(app) : nullptr;
×
UNCOV
295
        }
×
296

UNCOV
297
        return true;
×
UNCOV
298
    });
×
UNCOV
299
}
×
300

301
RLM_API void realm_clear_cached_apps(void) noexcept
UNCOV
302
{
×
UNCOV
303
    App::clear_cached_apps();
×
UNCOV
304
}
×
305

306
RLM_API const char* realm_app_get_app_id(const realm_app_t* app) noexcept
UNCOV
307
{
×
UNCOV
308
    return (*app)->app_id().c_str();
×
UNCOV
309
}
×
310

311
RLM_API bool realm_app_update_base_url(realm_app_t* app, const char* base_url,
312
                                       realm_app_void_completion_func_t callback, realm_userdata_t userdata,
313
                                       realm_free_userdata_func_t userdata_free)
314
{
6✔
315
    return wrap_err([&] {
6✔
316
        (*app)->update_base_url(base_url ? base_url : "", make_callback(callback, userdata, userdata_free));
5✔
317
        return true;
6✔
318
    });
6✔
319
}
6✔
320

321
RLM_API char* realm_app_get_base_url(realm_app_t* app) noexcept
322
{
8✔
323
    auto url_stg = (*app)->get_base_url();
8✔
324
    return duplicate_string(url_stg);
8✔
325
}
8✔
326

327
RLM_API realm_user_t* realm_app_get_current_user(const realm_app_t* app) noexcept
328
{
4✔
329
    if (auto user = (*app)->current_user()) {
4✔
330
        return new realm_user_t(user);
4✔
331
    }
4✔
332

UNCOV
333
    return nullptr;
×
UNCOV
334
}
×
335

336
RLM_API bool realm_app_get_all_users(const realm_app_t* app, realm_user_t** out_users, size_t capacity, size_t* out_n)
337
{
4✔
338
    return wrap_err([&] {
4✔
339
        const auto& users = (*app)->all_users();
4✔
340
        set_out_param(out_n, users.size());
4✔
341
        if (out_users && capacity >= users.size()) {
4✔
342
            OutBuffer<realm_user_t> buf(out_users);
2✔
343
            for (const auto& user : users) {
4✔
344
                buf.emplace(user);
4✔
345
            }
4✔
346
            buf.release(out_n);
2✔
347
        }
2✔
348
        return true;
4✔
349
    });
4✔
350
}
4✔
351

352
RLM_API bool realm_app_log_in_with_credentials(realm_app_t* app, realm_app_credentials_t* credentials,
353
                                               realm_app_user_completion_func_t callback, realm_userdata_t userdata,
354
                                               realm_free_userdata_func_t userdata_free)
355
{
12✔
356
    return wrap_err([&] {
12✔
357
        (*app)->log_in_with_credentials(*credentials, make_callback(callback, userdata, userdata_free));
12✔
358
        return true;
12✔
359
    });
12✔
360
}
12✔
361

362
RLM_API bool realm_app_log_out_current_user(realm_app_t* app, realm_app_void_completion_func_t callback,
363
                                            realm_userdata_t userdata, realm_free_userdata_func_t userdata_free)
UNCOV
364
{
×
UNCOV
365
    return wrap_err([&] {
×
UNCOV
366
        (*app)->log_out(make_callback(callback, userdata, userdata_free));
×
UNCOV
367
        return true;
×
368
    });
×
369
}
×
370

371
namespace {
372
template <typename Fn>
373
auto with_app_user(const realm_user_t* user, Fn&& fn)
374
{
24✔
375
    auto app_user = std::dynamic_pointer_cast<realm::app::User>(*user);
24✔
376
    return wrap_err([&] {
24✔
377
        if (!app_user) {
24!
UNCOV
378
            throw Exception(ErrorCodes::InvalidArgument, "App Services function require a user obtained from an App");
×
UNCOV
379
        }
×
380
        if constexpr (std::is_void_v<decltype(fn(app_user))>) {
24✔
381
            fn(app_user);
2✔
382
            return true;
2✔
383
        }
2✔
384
        else {
2✔
385
            return fn(app_user);
2✔
386
        }
2✔
387
    });
24✔
388
}
24✔
389
} // anonymous namespace
390

391
RLM_API bool realm_app_refresh_custom_data(realm_app_t* app, realm_user_t* user,
392
                                           realm_app_void_completion_func_t callback, realm_userdata_t userdata,
393
                                           realm_free_userdata_func_t userdata_free)
394
{
6✔
395
    return with_app_user(user, [&](auto& user) {
6✔
396
        (*app)->refresh_custom_data(user, make_callback(callback, userdata, userdata_free));
6✔
397
    });
6✔
398
}
6✔
399

400
RLM_API bool realm_app_log_out(realm_app_t* app, realm_user_t* user, realm_app_void_completion_func_t callback,
401
                               realm_userdata_t userdata, realm_free_userdata_func_t userdata_free)
UNCOV
402
{
×
UNCOV
403
    return with_app_user(user, [&](auto& user) {
×
UNCOV
404
        (*app)->log_out(user, make_callback(callback, userdata, userdata_free));
×
UNCOV
405
    });
×
UNCOV
406
}
×
407

408
RLM_API bool realm_app_link_user(realm_app_t* app, realm_user_t* user, realm_app_credentials_t* credentials,
409
                                 realm_app_user_completion_func_t callback, realm_userdata_t userdata,
410
                                 realm_free_userdata_func_t userdata_free)
411
{
2✔
412
    return with_app_user(user, [&](auto& user) {
2✔
413
        (*app)->link_user(user, *credentials, make_callback(callback, userdata, userdata_free));
2✔
414
    });
2✔
415
}
2✔
416

417
RLM_API bool realm_app_switch_user(realm_app_t* app, realm_user_t* user)
418
{
2✔
419
    return with_app_user(user, [&](auto& user) {
2✔
420
        (*app)->switch_user(user);
2✔
421
    });
2✔
422
}
2✔
423

424
RLM_API bool realm_app_remove_user(realm_app_t* app, realm_user_t* user, realm_app_void_completion_func_t callback,
425
                                   realm_userdata_t userdata, realm_free_userdata_func_t userdata_free)
426
{
2✔
427
    return with_app_user(user, [&](auto& user) {
2✔
428
        (*app)->remove_user(user, make_callback(callback, userdata, userdata_free));
2✔
429
    });
2✔
430
}
2✔
431

432
RLM_API bool realm_app_delete_user(realm_app_t* app, realm_user_t* user, realm_app_void_completion_func_t callback,
433
                                   realm_userdata_t userdata, realm_free_userdata_func_t userdata_free)
434
{
2✔
435
    return with_app_user(user, [&](auto& user) {
2✔
436
        (*app)->delete_user(user, make_callback(callback, userdata, userdata_free));
2✔
437
    });
2✔
438
}
2✔
439

440
RLM_API bool realm_app_email_password_provider_client_register_email(realm_app_t* app, const char* email,
441
                                                                     realm_string_t password,
442
                                                                     realm_app_void_completion_func_t callback,
443
                                                                     realm_userdata_t userdata,
444
                                                                     realm_free_userdata_func_t userdata_free)
445
{
10✔
446
    return wrap_err([&] {
10✔
447
        (*app)->provider_client<App::UsernamePasswordProviderClient>().register_email(
10✔
448
            email, from_capi(password), make_callback(callback, userdata, userdata_free));
10✔
449
        return true;
10✔
450
    });
10✔
451
}
10✔
452

453
RLM_API bool realm_app_email_password_provider_client_confirm_user(realm_app_t* app, const char* token,
454
                                                                   const char* token_id,
455
                                                                   realm_app_void_completion_func_t callback,
456
                                                                   realm_userdata_t userdata,
457
                                                                   realm_free_userdata_func_t userdata_free)
458
{
×
459
    return wrap_err([&] {
×
460
        (*app)->provider_client<App::UsernamePasswordProviderClient>().confirm_user(
×
UNCOV
461
            token, token_id, make_callback(callback, userdata, userdata_free));
×
UNCOV
462
        return true;
×
UNCOV
463
    });
×
UNCOV
464
}
×
465

466
RLM_API bool realm_app_email_password_provider_client_resend_confirmation_email(
467
    realm_app_t* app, const char* email, realm_app_void_completion_func_t callback, realm_userdata_t userdata,
468
    realm_free_userdata_func_t userdata_free)
469
{
×
470
    return wrap_err([&] {
×
471
        (*app)->provider_client<App::UsernamePasswordProviderClient>().resend_confirmation_email(
×
UNCOV
472
            email, make_callback(callback, userdata, userdata_free));
×
UNCOV
473
        return true;
×
UNCOV
474
    });
×
UNCOV
475
}
×
476

477
RLM_API bool realm_app_email_password_provider_client_send_reset_password_email(
478
    realm_app_t* app, const char* email, realm_app_void_completion_func_t callback, realm_userdata_t userdata,
479
    realm_free_userdata_func_t userdata_free)
480
{
×
481
    return wrap_err([&] {
×
482
        (*app)->provider_client<App::UsernamePasswordProviderClient>().send_reset_password_email(
×
483
            email, make_callback(callback, userdata, userdata_free));
×
484
        return true;
×
UNCOV
485
    });
×
UNCOV
486
}
×
487

488
RLM_API bool realm_app_email_password_provider_client_retry_custom_confirmation(
489
    realm_app_t* app, const char* email, realm_app_void_completion_func_t callback, realm_userdata_t userdata,
490
    realm_free_userdata_func_t userdata_free)
491
{
×
492
    return wrap_err([&] {
×
493
        (*app)->provider_client<App::UsernamePasswordProviderClient>().retry_custom_confirmation(
×
494
            email, make_callback(callback, userdata, userdata_free));
×
495
        return true;
×
496
    });
×
UNCOV
497
}
×
498

499
RLM_API bool realm_app_email_password_provider_client_reset_password(realm_app_t* app, realm_string_t password,
500
                                                                     const char* token, const char* token_id,
501
                                                                     realm_app_void_completion_func_t callback,
502
                                                                     realm_userdata_t userdata,
503
                                                                     realm_free_userdata_func_t userdata_free)
UNCOV
504
{
×
UNCOV
505
    return wrap_err([&] {
×
UNCOV
506
        (*app)->provider_client<App::UsernamePasswordProviderClient>().reset_password(
×
UNCOV
507
            from_capi(password), token, token_id, make_callback(callback, userdata, userdata_free));
×
UNCOV
508
        return true;
×
UNCOV
509
    });
×
UNCOV
510
}
×
511

512
RLM_API bool realm_app_email_password_provider_client_call_reset_password_function(
513
    realm_app_t* app, const char* email, realm_string_t password, const char* serialized_ejson_payload,
514
    realm_app_void_completion_func_t callback, realm_userdata_t userdata, realm_free_userdata_func_t userdata_free)
UNCOV
515
{
×
516
    return wrap_err([&] {
×
517
        bson::BsonArray args = parse_ejson_array(serialized_ejson_payload);
×
518
        (*app)->provider_client<App::UsernamePasswordProviderClient>().call_reset_password_function(
×
519
            email, from_capi(password), args, make_callback(callback, userdata, userdata_free));
×
520
        return true;
×
521
    });
×
522
}
×
523

524
RLM_API bool realm_app_user_apikey_provider_client_create_apikey(const realm_app_t* app, const realm_user_t* user,
525
                                                                 const char* name,
526
                                                                 realm_return_apikey_func_t callback,
527
                                                                 realm_userdata_t userdata,
528
                                                                 realm_free_userdata_func_t userdata_free)
529
{
2✔
530
    return with_app_user(user, [&](auto& user) {
2✔
531
        (*app)->provider_client<App::UserAPIKeyProviderClient>().create_api_key(
2✔
532
            name, user, make_callback(callback, userdata, userdata_free));
2✔
533
    });
2✔
534
}
2✔
535

536
RLM_API bool realm_app_user_apikey_provider_client_fetch_apikey(const realm_app_t* app, const realm_user_t* user,
537
                                                                realm_object_id_t id,
538
                                                                realm_return_apikey_func_t callback,
539
                                                                realm_userdata_t userdata,
540
                                                                realm_free_userdata_func_t userdata_free)
UNCOV
541
{
×
UNCOV
542
    return with_app_user(user, [&](auto& user) {
×
UNCOV
543
        (*app)->provider_client<App::UserAPIKeyProviderClient>().fetch_api_key(
×
UNCOV
544
            from_capi(id), user, make_callback(callback, userdata, userdata_free));
×
UNCOV
545
    });
×
UNCOV
546
}
×
547

548
RLM_API bool realm_app_user_apikey_provider_client_fetch_apikeys(const realm_app_t* app, const realm_user_t* user,
549
                                                                 realm_return_apikey_list_func_t callback,
550
                                                                 realm_userdata_t userdata,
551
                                                                 realm_free_userdata_func_t userdata_free)
552
{
4✔
553
    return with_app_user(user, [&](auto& user) {
4✔
554
        auto cb = [callback, userdata = SharedUserdata{userdata, FreeUserdata(userdata_free)}](
4✔
555
                      std::vector<App::UserAPIKey> apikeys, util::Optional<AppError> error) {
4✔
556
            if (error) {
4✔
557
                realm_app_error_t c_error(to_capi(*error));
2✔
558
                callback(userdata.get(), nullptr, 0, &c_error);
2✔
559
            }
2✔
560
            else {
2✔
561
                std::vector<realm_app_user_apikey_t> c_apikeys;
2✔
562
                c_apikeys.reserve(apikeys.size());
2✔
563
                for (const auto& apikey : apikeys) {
2✔
564
                    c_apikeys.push_back(to_capi(apikey));
2✔
565
                }
2✔
566
                callback(userdata.get(), c_apikeys.data(), c_apikeys.size(), nullptr);
2✔
567
            }
2✔
568
        };
4✔
569

2✔
570
        (*app)->provider_client<App::UserAPIKeyProviderClient>().fetch_api_keys(user, std::move(cb));
4✔
571
    });
4✔
572
}
4✔
573

574
RLM_API bool realm_app_user_apikey_provider_client_delete_apikey(const realm_app_t* app, const realm_user_t* user,
575
                                                                 realm_object_id_t id,
576
                                                                 realm_app_void_completion_func_t callback,
577
                                                                 realm_userdata_t userdata,
578
                                                                 realm_free_userdata_func_t userdata_free)
UNCOV
579
{
×
UNCOV
580
    return with_app_user(user, [&](auto& user) {
×
UNCOV
581
        (*app)->provider_client<App::UserAPIKeyProviderClient>().delete_api_key(
×
582
            from_capi(id), user, make_callback(callback, userdata, userdata_free));
×
583
    });
×
584
}
×
585

586
RLM_API bool realm_app_user_apikey_provider_client_enable_apikey(const realm_app_t* app, const realm_user_t* user,
587
                                                                 realm_object_id_t id,
588
                                                                 realm_app_void_completion_func_t callback,
589
                                                                 realm_userdata_t userdata,
590
                                                                 realm_free_userdata_func_t userdata_free)
UNCOV
591
{
×
UNCOV
592
    return with_app_user(user, [&](auto& user) {
×
593
        (*app)->provider_client<App::UserAPIKeyProviderClient>().enable_api_key(
×
594
            from_capi(id), user, make_callback(callback, userdata, userdata_free));
×
595
    });
×
596
}
×
597

598
RLM_API bool realm_app_user_apikey_provider_client_disable_apikey(const realm_app_t* app, const realm_user_t* user,
599
                                                                  realm_object_id_t id,
600
                                                                  realm_app_void_completion_func_t callback,
601
                                                                  realm_userdata_t userdata,
602
                                                                  realm_free_userdata_func_t userdata_free)
UNCOV
603
{
×
UNCOV
604
    return with_app_user(user, [&](auto& user) {
×
UNCOV
605
        (*app)->provider_client<App::UserAPIKeyProviderClient>().disable_api_key(
×
UNCOV
606
            from_capi(id), user, make_callback(callback, userdata, userdata_free));
×
607
    });
×
608
}
×
609

610
RLM_API bool realm_app_push_notification_client_register_device(
611
    const realm_app_t* app, const realm_user_t* user, const char* service_name, const char* registration_token,
612
    realm_app_void_completion_func_t callback, realm_userdata_t userdata, realm_free_userdata_func_t userdata_free)
613
{
×
614
    return with_app_user(user, [&](auto& user) {
×
UNCOV
615
        (*app)
×
UNCOV
616
            ->push_notification_client(service_name)
×
UNCOV
617
            .register_device(registration_token, user, make_callback(callback, userdata, userdata_free));
×
UNCOV
618
    });
×
UNCOV
619
}
×
620

621
RLM_API bool realm_app_push_notification_client_deregister_device(const realm_app_t* app, const realm_user_t* user,
622
                                                                  const char* service_name,
623
                                                                  realm_app_void_completion_func_t callback,
624
                                                                  realm_userdata_t userdata,
625
                                                                  realm_free_userdata_func_t userdata_free)
626
{
×
627
    return with_app_user(user, [&](auto& user) {
×
628
        (*app)
×
629
            ->push_notification_client(service_name)
×
630
            .deregister_device(user, make_callback(callback, userdata, userdata_free));
×
631
    });
×
632
}
×
633

634
RLM_API bool realm_app_call_function(const realm_app_t* app, const realm_user_t* user, const char* function_name,
635
                                     const char* serialized_ejson_payload, const char* service_name,
636
                                     realm_return_string_func_t callback, realm_userdata_t userdata,
637
                                     realm_free_userdata_func_t userdata_free)
UNCOV
638
{
×
UNCOV
639
    return with_app_user(user, [&](auto& user) {
×
640
        auto cb = [callback, userdata = SharedUserdata{userdata, FreeUserdata(userdata_free)}](
×
641
                      const std::string* reply, util::Optional<AppError> error) {
×
642
            if (error) {
×
UNCOV
643
                realm_app_error_t c_error(to_capi(*error));
×
UNCOV
644
                callback(userdata.get(), nullptr, &c_error);
×
645
            }
×
646
            else {
×
647
                callback(userdata.get(), reply->c_str(), nullptr);
×
UNCOV
648
            }
×
UNCOV
649
        };
×
650
        util::Optional<std::string> service_name_opt =
×
651
            service_name ? util::some<std::string>(service_name) : util::none;
×
652
        (*app)->call_function(user, function_name, serialized_ejson_payload, service_name_opt, std::move(cb));
×
UNCOV
653
    });
×
UNCOV
654
}
×
655

656
RLM_API void realm_app_sync_client_reconnect(realm_app_t* app) noexcept
657
{
×
658
    (*app)->sync_manager()->reconnect();
×
659
}
×
660

661
RLM_API bool realm_app_sync_client_has_sessions(const realm_app_t* app) noexcept
662
{
×
663
    return (*app)->sync_manager()->has_existing_sessions();
×
UNCOV
664
}
×
665

666
RLM_API void realm_app_sync_client_wait_for_sessions_to_terminate(realm_app_t* app) noexcept
667
{
×
668
    (*app)->sync_manager()->wait_for_sessions_to_terminate();
×
UNCOV
669
}
×
670

671
RLM_API char* realm_app_sync_client_get_default_file_path_for_realm(const realm_sync_config_t* config,
672
                                                                    const char* custom_filename)
UNCOV
673
{
×
UNCOV
674
    return wrap_err([&]() -> char* {
×
UNCOV
675
        auto user = std::dynamic_pointer_cast<app::User>(config->user);
×
UNCOV
676
        if (!user) {
×
UNCOV
677
            return nullptr;
×
UNCOV
678
        }
×
UNCOV
679
        util::Optional<std::string> filename =
×
UNCOV
680
            custom_filename ? util::some<std::string>(custom_filename) : util::none;
×
UNCOV
681
        std::string file_path = user->app()->path_for_realm(*config, std::move(filename));
×
UNCOV
682
        return duplicate_string(file_path);
×
UNCOV
683
    });
×
UNCOV
684
}
×
685

686
RLM_API char* realm_user_get_identity(const realm_user_t* user) noexcept
UNCOV
687
{
×
UNCOV
688
    return duplicate_string((*user)->user_id());
×
UNCOV
689
}
×
690

691
RLM_API realm_user_state_e realm_user_get_state(const realm_user_t* user) noexcept
692
{
4✔
693
    return realm_user_state_e((*user)->state());
4✔
694
}
4✔
695

696
RLM_API bool realm_user_get_all_identities(const realm_user_t* user, realm_user_identity_t* out_identities,
697
                                           size_t max, size_t* out_n)
698
{
2✔
699
    return with_app_user(user, [&](auto& user) {
2✔
700
        const auto& identities = user->identities();
2✔
701
        set_out_param(out_n, identities.size());
2✔
702
        if (out_identities && max >= identities.size()) {
2✔
703
            for (size_t i = 0; i < identities.size(); i++) {
6✔
704
                out_identities[i] = {duplicate_string(identities[i].id),
4✔
705
                                     realm_auth_provider_e(enum_from_provider_type(identities[i].provider_type))};
4✔
706
            }
4✔
707
        }
2✔
708
    });
2✔
709
}
2✔
710

711
RLM_API char* realm_user_get_device_id(const realm_user_t* user) noexcept
UNCOV
712
{
×
UNCOV
713
    char* device_id = nullptr;
×
714
    with_app_user(user, [&](auto& user) {
×
715
        if (user->has_device_id()) {
×
716
            device_id = duplicate_string(user->device_id());
×
717
        }
×
718
    });
×
719
    return device_id;
×
UNCOV
720
}
×
721

722
RLM_API bool realm_user_log_out(realm_user_t* user)
723
{
×
724
    return with_app_user(user, [&](auto& user) {
×
725
        user->log_out();
×
726
    });
×
UNCOV
727
}
×
728

729
RLM_API bool realm_user_is_logged_in(const realm_user_t* user) noexcept
UNCOV
730
{
×
UNCOV
731
    return (*user)->is_logged_in();
×
732
}
×
733

734
RLM_API char* realm_user_get_profile_data(const realm_user_t* user)
735
{
×
736
    return with_app_user(user, [&](auto& user) {
×
UNCOV
737
        std::string data = bson::Bson(user->user_profile().data()).to_string();
×
UNCOV
738
        return duplicate_string(data);
×
739
    });
×
740
}
×
741

742
RLM_API char* realm_user_get_custom_data(const realm_user_t* user) noexcept
743
{
×
UNCOV
744
    return with_app_user(user, [&](auto& user) -> char* {
×
UNCOV
745
        if (const auto& data = user->custom_data()) {
×
746
            std::string json = bson::Bson(*data).to_string();
×
747
            return duplicate_string(json);
×
748
        }
×
749
        return nullptr;
×
750
    });
×
751
}
×
752

753
RLM_API char* realm_user_get_access_token(const realm_user_t* user)
754
{
×
755
    return wrap_err([&] {
×
756
        return duplicate_string((*user)->access_token());
×
UNCOV
757
    });
×
UNCOV
758
}
×
759

760
RLM_API char* realm_user_get_refresh_token(const realm_user_t* user)
UNCOV
761
{
×
UNCOV
762
    return wrap_err([&] {
×
UNCOV
763
        return duplicate_string((*user)->refresh_token());
×
UNCOV
764
    });
×
UNCOV
765
}
×
766

767
RLM_API realm_app_t* realm_user_get_app(const realm_user_t* user) noexcept
UNCOV
768
{
×
UNCOV
769
    REALM_ASSERT(user);
×
UNCOV
770
    return with_app_user(user, [&](auto& user) {
×
UNCOV
771
        return new realm_app_t(user->app());
×
UNCOV
772
    });
×
UNCOV
773
}
×
774

775

776
RLM_API realm_app_user_subscription_token_t*
777
realm_sync_user_on_state_change_register_callback(realm_user_t* user, realm_sync_on_user_state_changed_t callback,
778
                                                  realm_userdata_t userdata, realm_free_userdata_func_t userdata_free)
779
{
2✔
780
    return with_app_user(user, [&](auto& user) {
2✔
781
        auto cb = [callback,
2✔
782
                   userdata = SharedUserdata{userdata, FreeUserdata(userdata_free)}](const SyncUser& sync_user) {
6✔
783
            callback(userdata.get(), realm_user_state_e(sync_user.state()));
6✔
784
        };
6✔
785
        auto token = user->subscribe(std::move(cb));
2✔
786
        return new realm_app_user_subscription_token_t{user, std::move(token)};
2✔
787
    });
2✔
788
}
2✔
789

790
namespace {
791
template <typename T>
792
util::Optional<T> convert_to_optional(T data)
793
{
×
UNCOV
794
    return data ? util::Optional<T>(data) : util::Optional<T>();
×
UNCOV
795
}
×
796

797
template <typename T>
798
util::Optional<T> convert_to_optional_bson(realm_string_t doc)
799
{
×
800
    if (doc.data == nullptr || doc.size == 0) {
×
801
        return util::Optional<T>();
×
802
    }
×
UNCOV
803
    return util::Optional<T>(static_cast<T>(bson::parse({doc.data, doc.size})));
×
UNCOV
804
}
×
805

806
template <typename T>
807
T convert_to_bson(realm_string_t doc)
808
{
×
809
    auto res = convert_to_optional_bson<T>(doc);
×
810
    return res ? *res : T();
×
811
}
×
812

813
MongoCollection::FindOptions to_mongodb_collection_find_options(const realm_mongodb_find_options_t* options)
UNCOV
814
{
×
UNCOV
815
    MongoCollection::FindOptions mongodb_options;
×
UNCOV
816
    mongodb_options.projection_bson = convert_to_optional_bson<bson::BsonDocument>(options->projection_bson);
×
817
    mongodb_options.sort_bson = convert_to_optional_bson<bson::BsonDocument>(options->sort_bson);
×
818
    mongodb_options.limit = convert_to_optional(options->limit);
×
819
    return mongodb_options;
×
820
}
×
821

822
MongoCollection::FindOneAndModifyOptions
823
to_mongodb_collection_find_one_and_modify_options(const realm_mongodb_find_one_and_modify_options_t* options)
824
{
×
825
    MongoCollection::FindOneAndModifyOptions mongodb_options;
×
826
    mongodb_options.projection_bson = convert_to_optional_bson<bson::BsonDocument>(options->projection_bson);
×
UNCOV
827
    mongodb_options.sort_bson = convert_to_optional_bson<bson::BsonDocument>(options->sort_bson);
×
UNCOV
828
    mongodb_options.upsert = options->upsert;
×
UNCOV
829
    mongodb_options.return_new_document = options->return_new_document;
×
830
    return mongodb_options;
×
831
}
×
832

833
void handle_mongodb_collection_result(util::Optional<bson::Bson> bson, util::Optional<AppError> app_error,
834
                                      UserdataPtr data, realm_mongodb_callback_t callback)
835
{
×
836
    if (app_error) {
×
837
        auto error = to_capi(*app_error);
×
838
        callback(data.get(), {nullptr, 0}, &error);
×
839
    }
×
UNCOV
840
    else if (bson) {
×
UNCOV
841
        const auto& bson_data = bson->to_string();
×
UNCOV
842
        callback(data.get(), {bson_data.c_str(), bson_data.size()}, nullptr);
×
UNCOV
843
    }
×
844
}
×
845
} // anonymous namespace
846

847
RLM_API realm_mongodb_collection_t* realm_mongo_collection_get(realm_user_t* user, const char* service,
848
                                                               const char* database, const char* collection)
849
{
×
850
    REALM_ASSERT(user);
×
851
    REALM_ASSERT(service);
×
852
    REALM_ASSERT(database);
×
853
    REALM_ASSERT(collection);
×
854
    return with_app_user(user, [&](auto& user) {
×
855
        auto col = user->mongo_client(service).db(database).collection(collection);
×
UNCOV
856
        return new realm_mongodb_collection_t(col);
×
UNCOV
857
    });
×
UNCOV
858
}
×
859

860
RLM_API bool realm_mongo_collection_find(realm_mongodb_collection_t* collection, realm_string_t filter_ejson,
861
                                         const realm_mongodb_find_options_t* options, realm_userdata_t data,
862
                                         realm_free_userdata_func_t delete_data, realm_mongodb_callback_t callback)
863
{
×
864
    REALM_ASSERT(collection);
×
865
    REALM_ASSERT(options);
×
866
    return wrap_err([&] {
×
867
        collection->find_bson(convert_to_bson<bson::BsonDocument>(filter_ejson),
×
868
                              to_mongodb_collection_find_options(options),
×
869
                              [=](util::Optional<bson::Bson> bson, util::Optional<AppError> app_error) {
×
870
                                  handle_mongodb_collection_result(bson, app_error, {data, delete_data}, callback);
×
871
                              });
×
872
        return true;
×
UNCOV
873
    });
×
UNCOV
874
}
×
875

876
RLM_API bool realm_mongo_collection_find_one(realm_mongodb_collection_t* collection, realm_string_t filter_ejson,
877
                                             const realm_mongodb_find_options_t* options, realm_userdata_t data,
878
                                             realm_free_userdata_func_t delete_data,
879
                                             realm_mongodb_callback_t callback)
880
{
×
881
    REALM_ASSERT(collection);
×
882
    REALM_ASSERT(options);
×
883
    return wrap_err([&] {
×
884
        collection->find_one_bson(
×
885
            convert_to_bson<bson::BsonDocument>(filter_ejson), to_mongodb_collection_find_options(options),
×
886
            [=](util::Optional<bson::Bson> bson, util::Optional<AppError> app_error) {
×
887
                handle_mongodb_collection_result(bson, app_error, {data, delete_data}, callback);
×
UNCOV
888
            });
×
UNCOV
889
        return true;
×
UNCOV
890
    });
×
UNCOV
891
}
×
892

893
RLM_API bool realm_mongo_collection_aggregate(realm_mongodb_collection_t* collection, realm_string_t filter_ejson,
894
                                              realm_userdata_t data, realm_free_userdata_func_t delete_data,
895
                                              realm_mongodb_callback_t callback)
896
{
×
897
    REALM_ASSERT(collection);
×
898
    return wrap_err([&] {
×
899
        collection->aggregate_bson(
×
900
            convert_to_bson<bson::BsonArray>(filter_ejson),
×
901
            [=](util::Optional<bson::Bson> bson, util::Optional<AppError> app_error) {
×
UNCOV
902
                handle_mongodb_collection_result(bson, app_error, {data, delete_data}, callback);
×
UNCOV
903
            });
×
UNCOV
904
        return true;
×
UNCOV
905
    });
×
906
}
×
907

908
RLM_API bool realm_mongo_collection_count(realm_mongodb_collection_t* collection, realm_string_t filter_ejson,
909
                                          int64_t limit, realm_userdata_t data,
910
                                          realm_free_userdata_func_t delete_data, realm_mongodb_callback_t callback)
911
{
×
912
    REALM_ASSERT(collection);
×
913
    return wrap_err([&] {
×
914
        collection->count_bson(convert_to_bson<bson::BsonDocument>(filter_ejson), limit,
×
915
                               [=](util::Optional<bson::Bson> bson, util::Optional<app::AppError> app_error) {
×
916
                                   handle_mongodb_collection_result(bson, app_error, {data, delete_data}, callback);
×
UNCOV
917
                               });
×
UNCOV
918
        return true;
×
UNCOV
919
    });
×
UNCOV
920
}
×
921

922
RLM_API bool realm_mongo_collection_insert_one(realm_mongodb_collection_t* collection, realm_string_t filter_ejson,
923
                                               realm_userdata_t data, realm_free_userdata_func_t delete_data,
924
                                               realm_mongodb_callback_t callback)
925
{
×
926
    REALM_ASSERT(collection);
×
927
    return wrap_err([&] {
×
928
        collection->insert_one_bson(
×
929
            convert_to_bson<bson::BsonDocument>(filter_ejson),
×
930
            [=](util::Optional<bson::Bson> bson, util::Optional<AppError> app_error) {
×
931
                handle_mongodb_collection_result(bson, app_error, {data, delete_data}, callback);
×
UNCOV
932
            });
×
UNCOV
933
        return true;
×
UNCOV
934
    });
×
UNCOV
935
}
×
936

937
RLM_API bool realm_mongo_collection_insert_many(realm_mongodb_collection_t* collection, realm_string_t filter_ejson,
938
                                                realm_userdata_t data, realm_free_userdata_func_t delete_data,
939
                                                realm_mongodb_callback_t callback)
940
{
×
941
    REALM_ASSERT(collection);
×
942
    return wrap_err([&] {
×
943
        collection->insert_many_bson(
×
944
            convert_to_bson<bson::BsonArray>(filter_ejson),
×
945
            [=](util::Optional<bson::Bson> bson, util::Optional<AppError> app_error) {
×
946
                handle_mongodb_collection_result(bson, app_error, {data, delete_data}, callback);
×
UNCOV
947
            });
×
UNCOV
948
        return true;
×
UNCOV
949
    });
×
UNCOV
950
}
×
951

952
RLM_API bool realm_mongo_collection_delete_one(realm_mongodb_collection_t* collection, realm_string_t filter_ejson,
953
                                               realm_userdata_t data, realm_free_userdata_func_t delete_data,
954
                                               realm_mongodb_callback_t callback)
955
{
×
956
    REALM_ASSERT(collection);
×
957
    return wrap_err([&] {
×
958
        collection->delete_one_bson(
×
959
            convert_to_bson<bson::BsonDocument>(filter_ejson),
×
960
            [=](util::Optional<bson::Bson> bson, util::Optional<AppError> app_error) {
×
961
                handle_mongodb_collection_result(bson, app_error, {data, delete_data}, callback);
×
UNCOV
962
            });
×
UNCOV
963
        return true;
×
UNCOV
964
    });
×
UNCOV
965
}
×
966

967
RLM_API bool realm_mongo_collection_delete_many(realm_mongodb_collection_t* collection, realm_string_t filter_ejson,
968
                                                realm_userdata_t data, realm_free_userdata_func_t delete_data,
969
                                                realm_mongodb_callback_t callback)
970
{
×
971
    REALM_ASSERT(collection);
×
972
    return wrap_err([&] {
×
973
        collection->delete_many_bson(
×
974
            convert_to_bson<bson::BsonDocument>(filter_ejson),
×
975
            [=](util::Optional<bson::Bson> bson, util::Optional<AppError> app_error) {
×
976
                handle_mongodb_collection_result(bson, app_error, {data, delete_data}, callback);
×
977
            });
×
978
        return true;
×
979
    });
×
UNCOV
980
}
×
981

982
RLM_API bool realm_mongo_collection_update_one(realm_mongodb_collection_t* collection, realm_string_t filter_ejson,
983
                                               realm_string_t update_ejson, bool upsert, realm_userdata_t data,
984
                                               realm_free_userdata_func_t delete_data,
985
                                               realm_mongodb_callback_t callback)
986
{
×
987
    REALM_ASSERT(collection);
×
988
    return wrap_err([&] {
×
989
        const auto& bson_filter = convert_to_bson<bson::BsonDocument>(filter_ejson);
×
990
        const auto& bson_update = convert_to_bson<bson::BsonDocument>(update_ejson);
×
991
        collection->update_one_bson(
×
992
            bson_filter, bson_update, upsert,
×
993
            [=](util::Optional<bson::Bson> bson, util::Optional<AppError> app_error) {
×
994
                handle_mongodb_collection_result(bson, app_error, {data, delete_data}, callback);
×
995
            });
×
996
        return true;
×
997
    });
×
UNCOV
998
}
×
999

1000
RLM_API bool realm_mongo_collection_update_many(realm_mongodb_collection_t* collection, realm_string_t filter_ejson,
1001
                                                realm_string_t update_ejson, bool upsert, realm_userdata_t data,
1002
                                                realm_free_userdata_func_t delete_data,
1003
                                                realm_mongodb_callback_t callback)
1004
{
×
1005
    REALM_ASSERT(collection);
×
1006
    return wrap_err([&] {
×
1007
        const auto& bson_filter = convert_to_bson<bson::BsonDocument>(filter_ejson);
×
1008
        const auto& bson_update = convert_to_bson<bson::BsonDocument>(update_ejson);
×
1009
        collection->update_many_bson(
×
1010
            bson_filter, bson_update, upsert,
×
1011
            [=](util::Optional<bson::Bson> bson, util::Optional<AppError> app_error) {
×
1012
                handle_mongodb_collection_result(bson, app_error, {data, delete_data}, callback);
×
1013
            });
×
1014
        return true;
×
1015
    });
×
1016
}
×
1017

1018
RLM_API bool realm_mongo_collection_find_one_and_update(realm_mongodb_collection_t* collection,
1019
                                                        realm_string_t filter_ejson, realm_string_t update_ejson,
1020
                                                        const realm_mongodb_find_one_and_modify_options_t* options,
1021
                                                        realm_userdata_t data, realm_free_userdata_func_t delete_data,
1022
                                                        realm_mongodb_callback_t callback)
1023
{
×
1024
    REALM_ASSERT(collection);
×
1025
    return wrap_err([&] {
×
1026
        const auto& bson_filter = convert_to_bson<bson::BsonDocument>(filter_ejson);
×
1027
        const auto& bson_update = convert_to_bson<bson::BsonDocument>(update_ejson);
×
1028
        collection->find_one_and_update_bson(
×
1029
            bson_filter, bson_update, to_mongodb_collection_find_one_and_modify_options(options),
×
1030
            [=](util::Optional<bson::Bson> bson, util::Optional<AppError> app_error) {
×
1031
                handle_mongodb_collection_result(bson, app_error, {data, delete_data}, callback);
×
1032
            });
×
1033
        return true;
×
1034
    });
×
UNCOV
1035
}
×
1036

1037
RLM_API bool realm_mongo_collection_find_one_and_replace(
1038
    realm_mongodb_collection_t* collection, realm_string_t filter_ejson, realm_string_t replacement_ejson,
1039
    const realm_mongodb_find_one_and_modify_options_t* options, realm_userdata_t data,
1040
    realm_free_userdata_func_t delete_data, realm_mongodb_callback_t callback)
1041
{
×
1042
    REALM_ASSERT(collection);
×
1043
    return wrap_err([&] {
×
1044
        const auto& filter_bson = convert_to_bson<bson::BsonDocument>(filter_ejson);
×
1045
        const auto& replacement_bson = convert_to_bson<bson::BsonDocument>(replacement_ejson);
×
1046
        collection->find_one_and_replace_bson(
×
1047
            filter_bson, replacement_bson, to_mongodb_collection_find_one_and_modify_options(options),
×
1048
            [=](util::Optional<bson::Bson> bson, util::Optional<AppError> app_error) {
×
1049
                handle_mongodb_collection_result(bson, app_error, {data, delete_data}, callback);
×
1050
            });
×
1051
        return true;
×
1052
    });
×
UNCOV
1053
}
×
1054

1055
RLM_API bool realm_mongo_collection_find_one_and_delete(realm_mongodb_collection_t* collection,
1056
                                                        realm_string_t filter_ejson,
1057
                                                        const realm_mongodb_find_one_and_modify_options_t* options,
1058
                                                        realm_userdata_t data, realm_free_userdata_func_t delete_data,
1059
                                                        realm_mongodb_callback_t callback)
UNCOV
1060
{
×
UNCOV
1061
    REALM_ASSERT(collection);
×
UNCOV
1062
    return wrap_err([&] {
×
UNCOV
1063
        const auto& bson_filter = convert_to_bson<bson::BsonDocument>(filter_ejson);
×
UNCOV
1064
        collection->find_one_and_delete_bson(
×
UNCOV
1065
            bson_filter, to_mongodb_collection_find_one_and_modify_options(options),
×
UNCOV
1066
            [=](util::Optional<bson::Bson> bson, util::Optional<AppError> app_error) {
×
UNCOV
1067
                handle_mongodb_collection_result(bson, app_error, {data, delete_data}, callback);
×
UNCOV
1068
            });
×
UNCOV
1069
        return true;
×
UNCOV
1070
    });
×
UNCOV
1071
}
×
1072

1073
} // namespace realm::c_api
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