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

realm / realm-core / thomas.goyne_275

09 Apr 2024 03:33AM UTC coverage: 92.608% (+0.5%) from 92.088%
thomas.goyne_275

Pull #7300

Evergreen

tgoyne
Extract some duplicated code in PushClient
Pull Request #7300: Rework sync user handling and metadata storage

102672 of 194970 branches covered (52.66%)

3165 of 3247 new or added lines in 46 files covered. (97.47%)

34 existing lines in 9 files now uncovered.

249420 of 269329 relevant lines covered (92.61%)

45087511.34 hits per line

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

54.06
/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
{
16✔
47
    auto ret = realm_app_error_t();
16✔
48

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

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

8✔
56
    ret.message = error.what();
16✔
57

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

8✔
62
    return ret;
16✔
63
}
16✔
64

65
static inline realm_app_user_apikey_t to_capi(const App::UserAPIKey& apikey)
66
{
32✔
67
    return {to_capi(apikey.id), apikey.key ? apikey.key->c_str() : nullptr, apikey.name.c_str(), apikey.disabled};
24✔
68
}
32✔
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
{
208✔
73
    return
208✔
74
        [callback, userdata = SharedUserdata(userdata, FreeUserdata(userdata_free))](util::Optional<AppError> error) {
208✔
75
            if (error) {
208✔
76
                realm_app_error_t c_err{to_capi(*error)};
×
77
                callback(userdata.get(), &c_err);
×
78
            }
×
79
            else {
208✔
80
                callback(userdata.get(), nullptr);
208✔
81
            }
208✔
82
        };
208✔
83
}
208✔
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
{
112✔
88
    return [callback, userdata = SharedUserdata(userdata, FreeUserdata(userdata_free))](
112✔
89
               std::shared_ptr<SyncUser> user, util::Optional<AppError> error) {
112✔
90
        if (error) {
112✔
91
            realm_app_error_t c_err{to_capi(*error)};
×
92
            callback(userdata.get(), nullptr, &c_err);
×
93
        }
×
94
        else {
112✔
95
            auto c_user = realm_user_t(std::move(user));
112✔
96
            callback(userdata.get(), &c_user, nullptr);
112✔
97
        }
112✔
98
    };
112✔
99
}
112✔
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
{
16✔
105
    return [callback, userdata = SharedUserdata(userdata, FreeUserdata(userdata_free))](
16✔
106
               App::UserAPIKey apikey, util::Optional<AppError> error) {
16✔
107
        if (error) {
16✔
108
            realm_app_error_t c_error(to_capi(*error));
×
109
            callback(userdata.get(), nullptr, &c_error);
×
110
        }
×
111
        else {
16✔
112
            realm_app_user_apikey_t c_apikey(to_capi(apikey));
16✔
113
            callback(userdata.get(), &c_apikey, nullptr);
16✔
114
        }
16✔
115
    };
16✔
116
}
16✔
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
{
16✔
130
    return app::App::default_base_url().data();
16✔
131
}
16✔
132

133
RLM_API realm_app_credentials_t* realm_app_credentials_new_anonymous(bool reuse_credentials) noexcept
134
{
16✔
135
    return new realm_app_credentials_t(AppCredentials::anonymous(reuse_credentials));
16✔
136
}
16✔
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
{
16✔
189
    auto* config = new realm_app_config_t;
16✔
190
    config->app_id = app_id;
16✔
191
    config->transport = *http_transport; // realm_http_transport_t is a shared_ptr
16✔
192
    return config;
16✔
193
}
16✔
194

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

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

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

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

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

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

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

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

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

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

246
RLM_API const char* realm_app_credentials_serialize_as_json(realm_app_credentials_t* app_credentials) noexcept
247
{
4✔
248
    return wrap_err([&] {
4✔
249
        return duplicate_string(app_credentials->serialize_as_json());
4✔
250
    });
251
}
252

253
RLM_API realm_app_t* realm_app_create(const realm_app_config_t* app_config,
8✔
254
                                      const realm_sync_client_config_t* sync_client_config)
8✔
255
{
22✔
256
    return wrap_err([&] {
14✔
257
        return new realm_app_t(App::get_app(app::App::CacheMode::Disabled, *app_config, *sync_client_config));
14✔
258
    });
16✔
259
}
16✔
260

2✔
261
RLM_API realm_app_t* realm_app_create_cached(const realm_app_config_t* app_config,
262
                                             const realm_sync_client_config_t* sync_client_config)
263
{
4✔
264
    return wrap_err([&] {
4✔
265
        return new realm_app_t(App::get_app(app::App::CacheMode::Enabled, *app_config, *sync_client_config));
4✔
266
    });
267
}
268

269
RLM_API bool realm_app_get_cached(const char* app_id, const char* base_url, realm_app_t** out_app)
270
{
×
271
    return wrap_err([&] {
×
272
        auto app =
×
273
            App::get_cached_app(std::string(app_id), base_url ? util::some<std::string>(base_url) : util::none);
×
274
        if (out_app) {
×
275
            *out_app = app ? new realm_app_t(app) : nullptr;
2!
276
        }
2✔
277

2✔
278
        return true;
2✔
279
    });
2✔
280
}
281

282
RLM_API void realm_clear_cached_apps(void) noexcept
283
{
×
NEW
284
    App::clear_cached_apps();
×
285
}
×
286

287
RLM_API const char* realm_app_get_app_id(const realm_app_t* app) noexcept
288
{
289
    return (*app)->config().app_id.c_str();
×
290
}
×
291

292
RLM_API bool realm_app_update_base_url(realm_app_t* app, const char* base_url,
×
293
                                       realm_app_void_completion_func_t callback, realm_userdata_t userdata,
×
294
                                       realm_free_userdata_func_t userdata_free)
×
295
{
42✔
296
    std::optional<std::string> new_base_url;
42✔
297
    if (base_url) {
42✔
298
        new_base_url = base_url;
28✔
299
    }
28✔
300
    return wrap_err([&] {
42✔
301
        (*app)->update_base_url(new_base_url, make_callback(callback, userdata, userdata_free));
42✔
302
        return true;
42✔
303
    });
42✔
304
}
42✔
305

306
RLM_API char* realm_app_get_base_url(realm_app_t* app) noexcept
307
{
56✔
308
    auto url_stg = (*app)->get_base_url();
56✔
309
    return duplicate_string(url_stg);
56✔
310
}
56✔
311

312
RLM_API realm_user_t* realm_app_get_current_user(const realm_app_t* app) noexcept
313
{
28✔
314
    if (auto user = (*app)->current_user()) {
34✔
315
        return new realm_user_t(user);
34✔
316
    }
33✔
317

6✔
318
    return nullptr;
6✔
319
}
6✔
320

321
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)
322
{
36✔
323
    return wrap_err([&] {
36✔
324
        const auto& users = (*app)->all_users();
36✔
325
        set_out_param(out_n, users.size());
36✔
326
        if (out_users && capacity >= users.size()) {
28✔
327
            OutBuffer<realm_user_t> buf(out_users);
14✔
328
            for (const auto& user : users) {
32✔
329
                buf.emplace(user);
32✔
330
            }
32✔
331
            buf.release(out_n);
18✔
332
        }
14✔
333
        return true;
28✔
334
    });
28✔
335
}
28✔
336

337
RLM_API bool realm_app_log_in_with_credentials(realm_app_t* app, realm_app_credentials_t* credentials,
4✔
338
                                               realm_app_user_completion_func_t callback, realm_userdata_t userdata,
4✔
339
                                               realm_free_userdata_func_t userdata_free)
4✔
340
{
88✔
341
    return wrap_err([&] {
88✔
342
        (*app)->log_in_with_credentials(*credentials, make_callback(callback, userdata, userdata_free));
86✔
343
        return true;
88✔
344
    });
88✔
345
}
88✔
346

2✔
347
RLM_API bool realm_app_log_out_current_user(realm_app_t* app, realm_app_void_completion_func_t callback,
2✔
348
                                            realm_userdata_t userdata, realm_free_userdata_func_t userdata_free)
4✔
349
{
4✔
350
    return wrap_err([&] {
4✔
351
        (*app)->log_out(make_callback(callback, userdata, userdata_free));
352
        return true;
353
    });
354
}
355

12✔
356
RLM_API bool realm_app_refresh_custom_data(realm_app_t* app, realm_user_t* user,
12✔
357
                                           realm_app_void_completion_func_t callback, realm_userdata_t userdata,
12✔
358
                                           realm_free_userdata_func_t userdata_free)
12✔
359
{
54✔
360
    return wrap_err([&] {
54✔
361
        (*app)->refresh_custom_data(*user, make_callback(callback, userdata, userdata_free));
42✔
362
        return true;
42✔
363
    });
42✔
364
}
42✔
365

366
RLM_API bool realm_app_log_out(realm_app_t* app, realm_user_t* user, realm_app_void_completion_func_t callback,
367
                               realm_userdata_t userdata, realm_free_userdata_func_t userdata_free)
368
{
×
369
    return wrap_err([&] {
×
370
        (*app)->log_out(*user, make_callback(callback, userdata, userdata_free));
371
        return true;
372
    });
373
}
374

24✔
375
RLM_API bool realm_app_link_user(realm_app_t* app, realm_user_t* user, realm_app_credentials_t* credentials,
24✔
376
                                 realm_app_user_completion_func_t callback, realm_userdata_t userdata,
24✔
377
                                 realm_free_userdata_func_t userdata_free)
24!
378
{
14✔
379
    return wrap_err([&] {
14✔
380
        (*app)->link_user(*user, *credentials, make_callback(callback, userdata, userdata_free));
38✔
381
        return true;
16✔
382
    });
16✔
383
}
16✔
384

2✔
385
RLM_API bool realm_app_switch_user(realm_app_t* app, realm_user_t* user, realm_user_t** new_user)
2✔
386
{
16✔
387
    return wrap_err([&] {
38✔
388
        auto new_user_local = (*app)->switch_user(*user);
38✔
389
        if (new_user) {
14✔
390
            *new_user = new realm_user_t(std::move(new_user_local));
14✔
391
        }
14✔
392
        return true;
14✔
393
    });
14✔
394
}
20✔
395

6✔
396
RLM_API bool realm_app_remove_user(realm_app_t* app, realm_user_t* user, realm_app_void_completion_func_t callback,
6✔
397
                                   realm_userdata_t userdata, realm_free_userdata_func_t userdata_free)
6✔
398
{
20✔
399
    return wrap_err([&] {
14✔
400
        (*app)->remove_user(*user, make_callback(callback, userdata, userdata_free));
14✔
401
        return true;
14✔
402
    });
14✔
403
}
14✔
404

405
RLM_API bool realm_app_delete_user(realm_app_t* app, realm_user_t* user, realm_app_void_completion_func_t callback,
406
                                   realm_userdata_t userdata, realm_free_userdata_func_t userdata_free)
407
{
14✔
408
    return wrap_err([&] {
14✔
409
        (*app)->delete_user(*user, make_callback(callback, userdata, userdata_free));
14✔
410
        return true;
14✔
411
    });
16✔
412
}
16✔
413

2✔
414
RLM_API bool realm_app_email_password_provider_client_register_email(realm_app_t* app, const char* email,
2✔
415
                                                                     realm_string_t password,
2✔
416
                                                                     realm_app_void_completion_func_t callback,
417
                                                                     realm_userdata_t userdata,
418
                                                                     realm_free_userdata_func_t userdata_free)
2✔
419
{
72✔
420
    return wrap_err([&] {
72✔
421
        (*app)->provider_client<App::UsernamePasswordProviderClient>().register_email(
72✔
422
            email, from_capi(password), make_callback(callback, userdata, userdata_free));
72✔
423
        return true;
70✔
424
    });
70✔
425
}
70✔
426

2✔
427
RLM_API bool realm_app_email_password_provider_client_confirm_user(realm_app_t* app, const char* token,
2✔
428
                                                                   const char* token_id,
2✔
429
                                                                   realm_app_void_completion_func_t callback,
2✔
430
                                                                   realm_userdata_t userdata,
2✔
431
                                                                   realm_free_userdata_func_t userdata_free)
432
{
433
    return wrap_err([&] {
434
        (*app)->provider_client<App::UsernamePasswordProviderClient>().confirm_user(
2✔
435
            token, token_id, make_callback(callback, userdata, userdata_free));
2✔
436
        return true;
2✔
437
    });
2✔
438
}
2✔
439

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

10✔
451
RLM_API bool realm_app_email_password_provider_client_send_reset_password_email(
10✔
452
    realm_app_t* app, const char* email, realm_app_void_completion_func_t callback, realm_userdata_t userdata,
453
    realm_free_userdata_func_t userdata_free)
454
{
455
    return wrap_err([&] {
456
        (*app)->provider_client<App::UsernamePasswordProviderClient>().send_reset_password_email(
457
            email, make_callback(callback, userdata, userdata_free));
458
        return true;
×
459
    });
×
460
}
×
461

462
RLM_API bool realm_app_email_password_provider_client_retry_custom_confirmation(
463
    realm_app_t* app, const char* email, realm_app_void_completion_func_t callback, realm_userdata_t userdata,
464
    realm_free_userdata_func_t userdata_free)
465
{
466
    return wrap_err([&] {
467
        (*app)->provider_client<App::UsernamePasswordProviderClient>().retry_custom_confirmation(
468
            email, make_callback(callback, userdata, userdata_free));
469
        return true;
×
470
    });
×
471
}
×
472

473
RLM_API bool realm_app_email_password_provider_client_reset_password(realm_app_t* app, realm_string_t password,
474
                                                                     const char* token, const char* token_id,
475
                                                                     realm_app_void_completion_func_t callback,
476
                                                                     realm_userdata_t userdata,
477
                                                                     realm_free_userdata_func_t userdata_free)
478
{
479
    return wrap_err([&] {
480
        (*app)->provider_client<App::UsernamePasswordProviderClient>().reset_password(
×
481
            from_capi(password), token, token_id, make_callback(callback, userdata, userdata_free));
×
482
        return true;
×
483
    });
×
484
}
×
485

486
RLM_API bool realm_app_email_password_provider_client_call_reset_password_function(
487
    realm_app_t* app, const char* email, realm_string_t password, const char* serialized_ejson_payload,
488
    realm_app_void_completion_func_t callback, realm_userdata_t userdata, realm_free_userdata_func_t userdata_free)
489
{
490
    return wrap_err([&] {
491
        bson::BsonArray args = parse_ejson_array(serialized_ejson_payload);
×
492
        (*app)->provider_client<App::UsernamePasswordProviderClient>().call_reset_password_function(
×
493
            email, from_capi(password), args, make_callback(callback, userdata, userdata_free));
×
494
        return true;
×
495
    });
×
496
}
×
497

498
RLM_API bool realm_app_user_apikey_provider_client_create_apikey(const realm_app_t* app, const realm_user_t* user,
499
                                                                 const char* name,
500
                                                                 realm_return_apikey_func_t callback,
501
                                                                 realm_userdata_t userdata,
502
                                                                 realm_free_userdata_func_t userdata_free)
503
{
14✔
504
    return wrap_err([&] {
14✔
505
        (*app)->provider_client<App::UserAPIKeyProviderClient>().create_api_key(
14✔
506
            name, *user, make_callback(callback, userdata, userdata_free));
14✔
507
        return true;
14✔
508
    });
14✔
509
}
14✔
510

511
RLM_API bool realm_app_user_apikey_provider_client_fetch_apikey(const realm_app_t* app, const realm_user_t* user,
512
                                                                realm_object_id_t id,
513
                                                                realm_return_apikey_func_t callback,
514
                                                                realm_userdata_t userdata,
515
                                                                realm_free_userdata_func_t userdata_free)
516
{
×
517
    return wrap_err([&] {
×
518
        (*app)->provider_client<App::UserAPIKeyProviderClient>().fetch_api_key(
×
519
            from_capi(id), *user, make_callback(callback, userdata, userdata_free));
×
520
        return true;
×
521
    });
×
522
}
×
523

524
RLM_API bool realm_app_user_apikey_provider_client_fetch_apikeys(const realm_app_t* app, const realm_user_t* user,
525
                                                                 realm_return_apikey_list_func_t callback,
526
                                                                 realm_userdata_t userdata,
527
                                                                 realm_free_userdata_func_t userdata_free)
528
{
28✔
529
    return wrap_err([&] {
30✔
530
        auto cb = [callback, userdata = SharedUserdata{userdata, FreeUserdata(userdata_free)}](
30✔
531
                      std::vector<App::UserAPIKey> apikeys, util::Optional<AppError> error) {
30✔
532
            if (error) {
30✔
533
                realm_app_error_t c_error(to_capi(*error));
16✔
534
                callback(userdata.get(), nullptr, 0, &c_error);
16✔
535
            }
14✔
536
            else {
14✔
537
                std::vector<realm_app_user_apikey_t> c_apikeys;
14✔
538
                c_apikeys.reserve(apikeys.size());
14✔
539
                for (const auto& apikey : apikeys) {
14✔
540
                    c_apikeys.push_back(to_capi(apikey));
14✔
541
                }
14✔
542
                callback(userdata.get(), c_apikeys.data(), c_apikeys.size(), nullptr);
14✔
543
            }
14✔
544
        };
28✔
545

14✔
546
        (*app)->provider_client<App::UserAPIKeyProviderClient>().fetch_api_keys(*user, std::move(cb));
28✔
547
        return true;
28✔
548
    });
28✔
549
}
28✔
550

551
RLM_API bool realm_app_user_apikey_provider_client_delete_apikey(const realm_app_t* app, const realm_user_t* user,
552
                                                                 realm_object_id_t id,
4✔
553
                                                                 realm_app_void_completion_func_t callback,
4✔
554
                                                                 realm_userdata_t userdata,
4✔
555
                                                                 realm_free_userdata_func_t userdata_free)
4✔
556
{
4✔
557
    return wrap_err([&] {
2✔
558
        (*app)->provider_client<App::UserAPIKeyProviderClient>().delete_api_key(
2✔
559
            from_capi(id), *user, make_callback(callback, userdata, userdata_free));
2✔
560
        return true;
2✔
561
    });
2✔
562
}
2✔
563

2✔
564
RLM_API bool realm_app_user_apikey_provider_client_enable_apikey(const realm_app_t* app, const realm_user_t* user,
2✔
565
                                                                 realm_object_id_t id,
2✔
566
                                                                 realm_app_void_completion_func_t callback,
2✔
567
                                                                 realm_userdata_t userdata,
2✔
568
                                                                 realm_free_userdata_func_t userdata_free)
4✔
569
{
2✔
570
    return wrap_err([&] {
4✔
571
        (*app)->provider_client<App::UserAPIKeyProviderClient>().enable_api_key(
4✔
572
            from_capi(id), *user, make_callback(callback, userdata, userdata_free));
4✔
573
        return true;
574
    });
575
}
576

577
RLM_API bool realm_app_user_apikey_provider_client_disable_apikey(const realm_app_t* app, const realm_user_t* user,
578
                                                                  realm_object_id_t id,
579
                                                                  realm_app_void_completion_func_t callback,
580
                                                                  realm_userdata_t userdata,
581
                                                                  realm_free_userdata_func_t userdata_free)
NEW
582
{
×
583
    return wrap_err([&] {
×
584
        (*app)->provider_client<App::UserAPIKeyProviderClient>().disable_api_key(
×
585
            from_capi(id), *user, make_callback(callback, userdata, userdata_free));
586
        return true;
587
    });
588
}
589

590
RLM_API bool realm_app_push_notification_client_register_device(
591
    const realm_app_t* app, const realm_user_t* user, const char* service_name, const char* registration_token,
592
    realm_app_void_completion_func_t callback, realm_userdata_t userdata, realm_free_userdata_func_t userdata_free)
593
{
×
NEW
594
    return wrap_err([&] {
×
595
        (*app)
×
596
            ->push_notification_client(service_name)
×
597
            .register_device(registration_token, *user, make_callback(callback, userdata, userdata_free));
598
        return true;
599
    });
600
}
601

602
RLM_API bool realm_app_push_notification_client_deregister_device(const realm_app_t* app, const realm_user_t* user,
603
                                                                  const char* service_name,
604
                                                                  realm_app_void_completion_func_t callback,
605
                                                                  realm_userdata_t userdata,
606
                                                                  realm_free_userdata_func_t userdata_free)
607
{
×
608
    return wrap_err([&] {
×
609
        (*app)
610
            ->push_notification_client(service_name)
611
            .deregister_device(*user, make_callback(callback, userdata, userdata_free));
612
        return true;
613
    });
×
NEW
614
}
×
615

616
RLM_API bool realm_app_call_function(const realm_app_t* app, const realm_user_t* user, const char* function_name,
617
                                     const char* serialized_ejson_payload, const char* service_name,
618
                                     realm_return_string_func_t callback, realm_userdata_t userdata,
619
                                     realm_free_userdata_func_t userdata_free)
620
{
621
    return wrap_err([&] {
622
        auto cb = [callback, userdata = SharedUserdata{userdata, FreeUserdata(userdata_free)}](
623
                      const std::string* reply, util::Optional<AppError> error) {
624
            if (error) {
×
625
                realm_app_error_t c_error(to_capi(*error));
626
                callback(userdata.get(), nullptr, &c_error);
×
NEW
627
            }
×
628
            else {
×
629
                callback(userdata.get(), reply->c_str(), nullptr);
×
NEW
630
            }
×
631
        };
×
632
        util::Optional<std::string> service_name_opt =
×
633
            service_name ? util::some<std::string>(service_name) : util::none;
×
634
        (*app)->call_function(*user, function_name, serialized_ejson_payload, service_name_opt, std::move(cb));
635
        return true;
636
    });
637
}
638

639
RLM_API void realm_app_sync_client_reconnect(realm_app_t* app) noexcept
640
{
×
641
    (*app)->sync_manager()->reconnect();
×
642
}
×
643

644
RLM_API bool realm_app_sync_client_has_sessions(const realm_app_t* app) noexcept
645
{
×
646
    return (*app)->sync_manager()->has_existing_sessions();
×
647
}
×
648

649
RLM_API void realm_app_sync_client_wait_for_sessions_to_terminate(realm_app_t* app) noexcept
650
{
×
651
    (*app)->sync_manager()->wait_for_sessions_to_terminate();
×
NEW
652
}
×
653

654
RLM_API char* realm_app_sync_client_get_default_file_path_for_realm(const realm_sync_config_t* config,
655
                                                                    const char* custom_filename)
656
{
657
    return wrap_err([&]() {
×
658
        util::Optional<std::string> filename =
×
659
            custom_filename ? util::some<std::string>(custom_filename) : util::none;
×
660
        std::string file_path = config->user->sync_manager()->path_for_realm(*config, std::move(filename));
661
        return duplicate_string(file_path);
662
    });
×
663
}
×
664

665
RLM_API const char* realm_user_get_identity(const realm_user_t* user) noexcept
666
{
667
    return (*user)->identity().c_str();
×
668
}
×
669

670
RLM_API realm_user_state_e realm_user_get_state(const realm_user_t* user) noexcept
671
{
28✔
672
    return realm_user_state_e((*user)->state());
28✔
673
}
28✔
674

675
RLM_API bool realm_user_get_all_identities(const realm_user_t* user, realm_user_identity_t* out_identities,
676
                                           size_t max, size_t* out_n)
×
677
{
14✔
678
    return wrap_err([&] {
14✔
679
        const auto& identities = (*user)->identities();
14✔
680
        set_out_param(out_n, identities.size());
14!
681
        if (out_identities && max >= identities.size()) {
14✔
682
            for (size_t i = 0; i < identities.size(); i++) {
42✔
683
                out_identities[i] = {duplicate_string(identities[i].id),
28✔
684
                                     realm_auth_provider_e(enum_from_provider_type(identities[i].provider_type))};
28✔
685
            }
28✔
686
        }
14✔
687
        return true;
14✔
688
    });
14✔
689
}
14✔
690

691
RLM_API char* realm_user_get_device_id(const realm_user_t* user) noexcept
692
{
4✔
693
    if ((*user)->has_device_id()) {
4!
694
        return duplicate_string((*user)->device_id());
4✔
695
    }
696

697
    return nullptr;
698
}
2✔
699

2✔
700
RLM_API bool realm_user_log_out(realm_user_t* user)
2✔
701
{
2✔
702
    return wrap_err([&] {
2✔
703
        (*user)->log_out();
6✔
704
        return true;
4✔
705
    });
4✔
706
}
4✔
707

2✔
708
RLM_API bool realm_user_is_logged_in(const realm_user_t* user) noexcept
2✔
709
{
2✔
710
    return (*user)->is_logged_in();
711
}
712

713
RLM_API char* realm_user_get_profile_data(const realm_user_t* user)
NEW
714
{
×
NEW
715
    return wrap_err([&] {
×
NEW
716
        std::string data = bson::Bson((*user)->user_profile().data()).to_string();
×
NEW
717
        return duplicate_string(data);
×
NEW
718
    });
×
NEW
719
}
×
720

721
RLM_API char* realm_user_get_custom_data(const realm_user_t* user) noexcept
722
{
723
    if (const auto& data = (*user)->custom_data()) {
×
NEW
724
        std::string json = bson::Bson(*data).to_string();
×
NEW
725
        return duplicate_string(json);
×
726
    }
×
727

728
    return nullptr;
729
}
730

731
RLM_API char* realm_user_get_access_token(const realm_user_t* user)
732
{
×
733
    return wrap_err([&] {
734
        return duplicate_string((*user)->access_token());
735
    });
×
NEW
736
}
×
737

738
RLM_API char* realm_user_get_refresh_token(const realm_user_t* user)
739
{
×
740
    return wrap_err([&] {
×
741
        return duplicate_string((*user)->refresh_token());
742
    });
743
}
×
744

745
RLM_API realm_app_t* realm_user_get_app(const realm_user_t* user) noexcept
×
NEW
746
{
×
NEW
747
    REALM_ASSERT(user);
×
NEW
748
    try {
×
NEW
749
        if (auto shared_app = (*user)->sync_manager()->app().lock()) {
×
NEW
750
            return new realm_app_t(shared_app);
×
UNCOV
751
        }
×
752
    }
753
    catch (const std::exception&) {
754
    }
×
755
    return nullptr;
×
756
}
×
757

758

759
RLM_API realm_sync_user_subscription_token_t*
760
realm_sync_user_on_state_change_register_callback(realm_user_t* user, realm_sync_on_user_state_changed_t callback,
761
                                                  realm_userdata_t userdata, realm_free_userdata_func_t userdata_free)
762
{
14✔
763
    return wrap_err([&] {
14✔
764
        auto cb = [callback,
14✔
765
                   userdata = SharedUserdata{userdata, FreeUserdata(userdata_free)}](const SyncUser& sync_user) {
42✔
766
            callback(userdata.get(), realm_user_state_e(sync_user.state()));
42✔
767
        };
42✔
768
        auto token = (*user)->subscribe(std::move(cb));
14✔
769
        return new realm_sync_user_subscription_token_t{*user, std::move(token)};
14!
770
    });
14✔
771
}
14✔
772

773
template <typename T>
774
inline util::Optional<T> convert_to_optional(T data)
775
{
776
    return data ? util::Optional<T>(data) : util::Optional<T>();
×
777
}
778

779
template <typename T>
2✔
780
inline util::Optional<T> convert_to_optional_bson(realm_string_t doc)
2✔
781
{
2✔
782
    if (doc.data == nullptr || doc.size == 0) {
6!
783
        return util::Optional<T>();
6✔
784
    }
6✔
785
    return util::Optional<T>(static_cast<T>(bson::parse({doc.data, doc.size})));
2✔
786
}
2✔
787

2✔
788
template <typename T>
2✔
789
inline T convert_to_bson(realm_string_t doc)
790
{
791
    auto res = convert_to_optional_bson<T>(doc);
792
    return res ? *res : T();
×
793
}
×
794

×
795
static MongoCollection::FindOptions to_mongodb_collection_find_options(const realm_mongodb_find_options_t* options)
796
{
797
    MongoCollection::FindOptions mongodb_options;
798
    mongodb_options.projection_bson = convert_to_optional_bson<bson::BsonDocument>(options->projection_bson);
799
    mongodb_options.sort_bson = convert_to_optional_bson<bson::BsonDocument>(options->sort_bson);
×
800
    mongodb_options.limit = convert_to_optional(options->limit);
×
801
    return mongodb_options;
×
802
}
×
803

804
static MongoCollection::FindOneAndModifyOptions
805
to_mongodb_collection_find_one_and_modify_options(const realm_mongodb_find_one_and_modify_options_t* options)
806
{
807
    MongoCollection::FindOneAndModifyOptions mongodb_options;
808
    mongodb_options.projection_bson = convert_to_optional_bson<bson::BsonDocument>(options->projection_bson);
×
809
    mongodb_options.sort_bson = convert_to_optional_bson<bson::BsonDocument>(options->sort_bson);
×
810
    mongodb_options.upsert = options->upsert;
×
811
    mongodb_options.return_new_document = options->return_new_document;
×
812
    return mongodb_options;
813
}
814

815
static void handle_mongodb_collection_result(util::Optional<bson::Bson> bson, util::Optional<AppError> app_error,
816
                                             UserdataPtr data, realm_mongodb_callback_t callback)
817
{
×
818
    if (app_error) {
×
819
        auto error = to_capi(*app_error);
×
820
        callback(data.get(), {nullptr, 0}, &error);
×
821
    }
822
    else if (bson) {
×
823
        const auto& bson_data = bson->to_string();
824
        callback(data.get(), {bson_data.c_str(), bson_data.size()}, nullptr);
×
825
    }
×
826
}
×
827

828
RLM_API realm_mongodb_collection_t* realm_mongo_collection_get(realm_user_t* user, const char* service,
829
                                                               const char* database, const char* collection)
830
{
×
831
    REALM_ASSERT(user);
×
832
    REALM_ASSERT(service);
×
833
    REALM_ASSERT(database);
×
834
    REALM_ASSERT(collection);
×
835
    return wrap_err([&]() {
×
836
        auto col = (*user)->mongo_client(service).db(database).collection(collection);
×
837
        return new realm_mongodb_collection_t(col);
×
838
    });
×
839
}
×
840

×
841
RLM_API bool realm_mongo_collection_find(realm_mongodb_collection_t* collection, realm_string_t filter_ejson,
842
                                         const realm_mongodb_find_options_t* options, realm_userdata_t data,
843
                                         realm_free_userdata_func_t delete_data, realm_mongodb_callback_t callback)
844
{
×
845
    REALM_ASSERT(collection);
×
846
    REALM_ASSERT(options);
×
847
    return wrap_err([&] {
848
        collection->find_bson(convert_to_bson<bson::BsonDocument>(filter_ejson),
849
                              to_mongodb_collection_find_options(options),
×
850
                              [=](util::Optional<bson::Bson> bson, util::Optional<AppError> app_error) {
×
851
                                  handle_mongodb_collection_result(bson, app_error, {data, delete_data}, callback);
×
852
                              });
×
853
        return true;
×
NEW
854
    });
×
NEW
855
}
×
856

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

874
RLM_API bool realm_mongo_collection_aggregate(realm_mongodb_collection_t* collection, realm_string_t filter_ejson,
875
                                              realm_userdata_t data, realm_free_userdata_func_t delete_data,
876
                                              realm_mongodb_callback_t callback)
877
{
878
    REALM_ASSERT(collection);
×
879
    return wrap_err([&] {
880
        collection->aggregate_bson(
×
881
            convert_to_bson<bson::BsonArray>(filter_ejson),
×
882
            [=](util::Optional<bson::Bson> bson, util::Optional<AppError> app_error) {
×
883
                handle_mongodb_collection_result(bson, app_error, {data, delete_data}, callback);
×
884
            });
×
885
        return true;
×
886
    });
×
887
}
×
888

889
RLM_API bool realm_mongo_collection_count(realm_mongodb_collection_t* collection, realm_string_t filter_ejson,
890
                                          int64_t limit, realm_userdata_t data,
891
                                          realm_free_userdata_func_t delete_data, realm_mongodb_callback_t callback)
892
{
893
    REALM_ASSERT(collection);
×
894
    return wrap_err([&] {
895
        collection->count_bson(convert_to_bson<bson::BsonDocument>(filter_ejson), limit,
896
                               [=](util::Optional<bson::Bson> bson, util::Optional<app::AppError> app_error) {
×
897
                                   handle_mongodb_collection_result(bson, app_error, {data, delete_data}, callback);
×
898
                               });
×
899
        return true;
×
900
    });
×
901
}
×
902

903
RLM_API bool realm_mongo_collection_insert_one(realm_mongodb_collection_t* collection, realm_string_t filter_ejson,
904
                                               realm_userdata_t data, realm_free_userdata_func_t delete_data,
905
                                               realm_mongodb_callback_t callback)
906
{
×
907
    REALM_ASSERT(collection);
×
908
    return wrap_err([&] {
909
        collection->insert_one_bson(
910
            convert_to_bson<bson::BsonDocument>(filter_ejson),
911
            [=](util::Optional<bson::Bson> bson, util::Optional<AppError> app_error) {
×
912
                handle_mongodb_collection_result(bson, app_error, {data, delete_data}, callback);
×
913
            });
×
914
        return true;
×
915
    });
×
916
}
×
917

918
RLM_API bool realm_mongo_collection_insert_many(realm_mongodb_collection_t* collection, realm_string_t filter_ejson,
919
                                                realm_userdata_t data, realm_free_userdata_func_t delete_data,
920
                                                realm_mongodb_callback_t callback)
921
{
922
    REALM_ASSERT(collection);
×
923
    return wrap_err([&] {
924
        collection->insert_many_bson(
925
            convert_to_bson<bson::BsonArray>(filter_ejson),
×
926
            [=](util::Optional<bson::Bson> bson, util::Optional<AppError> app_error) {
×
927
                handle_mongodb_collection_result(bson, app_error, {data, delete_data}, callback);
×
928
            });
×
929
        return true;
×
930
    });
×
931
}
×
932

933
RLM_API bool realm_mongo_collection_delete_one(realm_mongodb_collection_t* collection, realm_string_t filter_ejson,
934
                                               realm_userdata_t data, realm_free_userdata_func_t delete_data,
935
                                               realm_mongodb_callback_t callback)
936
{
937
    REALM_ASSERT(collection);
×
938
    return wrap_err([&] {
939
        collection->delete_one_bson(
940
            convert_to_bson<bson::BsonDocument>(filter_ejson),
×
941
            [=](util::Optional<bson::Bson> bson, util::Optional<AppError> app_error) {
×
942
                handle_mongodb_collection_result(bson, app_error, {data, delete_data}, callback);
×
943
            });
×
944
        return true;
×
945
    });
×
946
}
×
947

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

963
RLM_API bool realm_mongo_collection_update_one(realm_mongodb_collection_t* collection, realm_string_t filter_ejson,
964
                                               realm_string_t update_ejson, bool upsert, realm_userdata_t data,
965
                                               realm_free_userdata_func_t delete_data,
966
                                               realm_mongodb_callback_t callback)
967
{
968
    REALM_ASSERT(collection);
×
969
    return wrap_err([&] {
970
        const auto& bson_filter = convert_to_bson<bson::BsonDocument>(filter_ejson);
×
971
        const auto& bson_update = convert_to_bson<bson::BsonDocument>(update_ejson);
×
972
        collection->update_one_bson(
×
973
            bson_filter, bson_update, upsert,
×
974
            [=](util::Optional<bson::Bson> bson, util::Optional<AppError> app_error) {
×
975
                handle_mongodb_collection_result(bson, app_error, {data, delete_data}, callback);
×
976
            });
×
977
        return true;
×
978
    });
×
979
}
×
980

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

999
RLM_API bool realm_mongo_collection_find_one_and_update(realm_mongodb_collection_t* collection,
1000
                                                        realm_string_t filter_ejson, realm_string_t update_ejson,
1001
                                                        const realm_mongodb_find_one_and_modify_options_t* options,
1002
                                                        realm_userdata_t data, 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->find_one_and_update_bson(
×
1010
            bson_filter, bson_update, to_mongodb_collection_find_one_and_modify_options(options),
×
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_replace(
1019
    realm_mongodb_collection_t* collection, realm_string_t filter_ejson, realm_string_t replacement_ejson,
1020
    const realm_mongodb_find_one_and_modify_options_t* options, realm_userdata_t data,
1021
    realm_free_userdata_func_t delete_data, realm_mongodb_callback_t callback)
1022
{
1023
    REALM_ASSERT(collection);
×
1024
    return wrap_err([&] {
×
1025
        const auto& filter_bson = convert_to_bson<bson::BsonDocument>(filter_ejson);
×
1026
        const auto& replacement_bson = convert_to_bson<bson::BsonDocument>(replacement_ejson);
×
1027
        collection->find_one_and_replace_bson(
×
1028
            filter_bson, replacement_bson, to_mongodb_collection_find_one_and_modify_options(options),
×
1029
            [=](util::Optional<bson::Bson> bson, util::Optional<AppError> app_error) {
×
1030
                handle_mongodb_collection_result(bson, app_error, {data, delete_data}, callback);
×
1031
            });
×
1032
        return true;
×
1033
    });
×
1034
}
×
1035

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

1054
} // 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