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

realm / realm-core / 2029

12 Feb 2024 06:33PM UTC coverage: 91.838%. First build
2029

push

Evergreen

web-flow
Merge pull request #7329 from realm/tg/jwt-validation

Assorted sync metadata storage refactoring

93050 of 171486 branches covered (0.0%)

219 of 246 new or added lines in 23 files covered. (89.02%)

235273 of 256184 relevant lines covered (91.84%)

6516157.5 hits per line

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

32.7
/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<SyncUser> 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 {
×
NEW
124
        return bson::BsonArray(bson::parse({serialized, strlen(serialized)}));
×
125
    }
×
126
}
×
127

128
RLM_API realm_app_credentials_t* realm_app_credentials_new_anonymous(bool reuse_credentials) noexcept
129
{
2✔
130
    return new realm_app_credentials_t(AppCredentials::anonymous(reuse_credentials));
2✔
131
}
2✔
132

133
RLM_API realm_app_credentials_t* realm_app_credentials_new_facebook(const char* access_token) noexcept
134
{
×
135
    return new realm_app_credentials_t(AppCredentials::facebook(access_token));
×
136
}
×
137

138
RLM_API realm_app_credentials_t* realm_app_credentials_new_google_id_token(const char* id_token) noexcept
139
{
×
140
    return new realm_app_credentials_t(AppCredentials::google(IdToken(id_token)));
×
141
}
×
142

143
RLM_API realm_app_credentials_t* realm_app_credentials_new_google_auth_code(const char* auth_code) noexcept
144
{
×
145
    return new realm_app_credentials_t(AppCredentials::google(AuthCode(auth_code)));
×
146
}
×
147

148
RLM_API realm_app_credentials_t* realm_app_credentials_new_apple(const char* id_token) noexcept
149
{
×
150
    return new realm_app_credentials_t(AppCredentials::apple(id_token));
×
151
}
×
152

153
RLM_API realm_app_credentials_t* realm_app_credentials_new_jwt(const char* jwt_token) noexcept
154
{
×
155
    return new realm_app_credentials_t(AppCredentials::custom(jwt_token));
×
156
}
×
157

158
RLM_API realm_app_credentials_t* realm_app_credentials_new_email_password(const char* email,
159
                                                                          realm_string_t password) noexcept
160
{
×
161
    return new realm_app_credentials_t(AppCredentials::username_password(email, from_capi(password)));
×
162
}
×
163

164
RLM_API realm_app_credentials_t* realm_app_credentials_new_function(const char* serialized_ejson_payload)
165
{
×
166
    return wrap_err([&] {
×
167
        return new realm_app_credentials_t(AppCredentials::function(serialized_ejson_payload));
×
168
    });
×
169
}
×
170

171
RLM_API realm_app_credentials_t* realm_app_credentials_new_api_key(const char* api_key) noexcept
172
{
×
173
    return new realm_app_credentials_t(AppCredentials::api_key(api_key));
×
174
}
×
175

176
RLM_API realm_auth_provider_e realm_auth_credentials_get_provider(realm_app_credentials_t* credentials) noexcept
177
{
×
178
    return realm_auth_provider_e(credentials->provider());
×
179
}
×
180

181
RLM_API realm_app_config_t* realm_app_config_new(const char* app_id,
182
                                                 const realm_http_transport_t* http_transport) noexcept
183
{
2✔
184
    auto* config = new realm_app_config_t;
2✔
185
    config->app_id = app_id;
2✔
186
    config->transport = *http_transport; // realm_http_transport_t is a shared_ptr
2✔
187
    return config;
2✔
188
}
2✔
189

190
RLM_API void realm_app_config_set_base_url(realm_app_config_t* config, const char* base_url) noexcept
191
{
2✔
192
    config->base_url = std::string(base_url);
2✔
193
}
2✔
194

195
RLM_API void realm_app_config_set_default_request_timeout(realm_app_config_t* config, uint64_t ms) noexcept
196
{
2✔
197
    config->default_request_timeout_ms = ms;
2✔
198
}
2✔
199

200
RLM_API void realm_app_config_set_platform_version(realm_app_config_t* config, const char* platform_version) noexcept
201
{
2✔
202
    config->device_info.platform_version = std::string(platform_version);
2✔
203
}
2✔
204

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

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

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

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

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

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

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

241
RLM_API const char* realm_app_credentials_serialize_as_json(realm_app_credentials_t* app_credentials) noexcept
242
{
×
243
    return wrap_err([&] {
×
244
        return duplicate_string(app_credentials->serialize_as_json());
×
245
    });
×
246
}
×
247

248
RLM_API realm_app_t* realm_app_create(const realm_app_config_t* app_config,
249
                                      const realm_sync_client_config_t* sync_client_config)
250
{
2✔
251
    return wrap_err([&] {
2✔
252
        return new realm_app_t(App::get_app(app::App::CacheMode::Disabled, *app_config, *sync_client_config));
2✔
253
    });
2✔
254
}
2✔
255

256
RLM_API realm_app_t* realm_app_create_cached(const realm_app_config_t* app_config,
257
                                             const realm_sync_client_config_t* sync_client_config)
258
{
×
259
    return wrap_err([&] {
×
260
        return new realm_app_t(App::get_app(app::App::CacheMode::Enabled, *app_config, *sync_client_config));
×
261
    });
×
262
}
×
263

264
RLM_API bool realm_app_get_cached(const char* app_id, const char* base_url, realm_app_t** out_app)
265
{
×
266
    return wrap_err([&] {
×
267
        auto app =
×
268
            App::get_cached_app(std::string(app_id), base_url ? util::some<std::string>(base_url) : util::none);
×
269
        if (out_app) {
×
270
            *out_app = app ? new realm_app_t(app) : nullptr;
×
271
        }
×
272

273
        return true;
×
274
    });
×
275
}
×
276

277
RLM_API void realm_clear_cached_apps(void) noexcept
278
{
×
279
    App::clear_cached_apps();
×
280
}
×
281

282
RLM_API const char* realm_app_get_app_id(const realm_app_t* app) noexcept
283
{
×
284
    return (*app)->config().app_id.c_str();
×
285
}
×
286

287
RLM_API bool realm_app_update_base_url(realm_app_t* app, const char* base_url,
288
                                       realm_app_void_completion_func_t callback, realm_userdata_t userdata,
289
                                       realm_free_userdata_func_t userdata_free)
290
{
6✔
291
    std::optional<std::string> new_base_url;
6✔
292
    if (base_url) {
6✔
293
        new_base_url = base_url;
4✔
294
    }
4✔
295
    return wrap_err([&] {
6✔
296
        (*app)->update_base_url(new_base_url, make_callback(callback, userdata, userdata_free));
6✔
297
        return true;
6✔
298
    });
6✔
299
}
6✔
300

301
RLM_API char* realm_app_get_base_url(realm_app_t* app) noexcept
302
{
8✔
303
    auto url_stg = (*app)->get_base_url();
8✔
304
    return duplicate_string(url_stg);
8✔
305
}
8✔
306

307
RLM_API realm_user_t* realm_app_get_current_user(const realm_app_t* app) noexcept
308
{
4✔
309
    if (auto user = (*app)->current_user()) {
4✔
310
        return new realm_user_t(user);
4✔
311
    }
4✔
312

313
    return nullptr;
×
314
}
×
315

316
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)
317
{
4✔
318
    return wrap_err([&] {
4✔
319
        const auto& users = (*app)->all_users();
4✔
320
        set_out_param(out_n, users.size());
4✔
321
        if (out_users && capacity >= users.size()) {
4✔
322
            OutBuffer<realm_user_t> buf(out_users);
2✔
323
            for (const auto& user : users) {
4✔
324
                buf.emplace(user);
4✔
325
            }
4✔
326
            buf.release(out_n);
2✔
327
        }
2✔
328
        return true;
4✔
329
    });
4✔
330
}
4✔
331

332
RLM_API bool realm_app_log_in_with_credentials(realm_app_t* app, realm_app_credentials_t* credentials,
333
                                               realm_app_user_completion_func_t callback, realm_userdata_t userdata,
334
                                               realm_free_userdata_func_t userdata_free)
335
{
12✔
336
    return wrap_err([&] {
12✔
337
        (*app)->log_in_with_credentials(*credentials, make_callback(callback, userdata, userdata_free));
12✔
338
        return true;
12✔
339
    });
12✔
340
}
12✔
341

342
RLM_API bool realm_app_log_out_current_user(realm_app_t* app, realm_app_void_completion_func_t callback,
343
                                            realm_userdata_t userdata, realm_free_userdata_func_t userdata_free)
344
{
×
345
    return wrap_err([&] {
×
346
        (*app)->log_out(make_callback(callback, userdata, userdata_free));
×
347
        return true;
×
348
    });
×
349
}
×
350

351
RLM_API bool realm_app_refresh_custom_data(realm_app_t* app, realm_user_t* user,
352
                                           realm_app_void_completion_func_t callback, realm_userdata_t userdata,
353
                                           realm_free_userdata_func_t userdata_free)
354
{
6✔
355
    return wrap_err([&] {
6✔
356
        (*app)->refresh_custom_data(*user, make_callback(callback, userdata, userdata_free));
6✔
357
        return true;
6✔
358
    });
6✔
359
}
6✔
360

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

370
RLM_API bool realm_app_link_user(realm_app_t* app, realm_user_t* user, realm_app_credentials_t* credentials,
371
                                 realm_app_user_completion_func_t callback, realm_userdata_t userdata,
372
                                 realm_free_userdata_func_t userdata_free)
373
{
2✔
374
    return wrap_err([&] {
2✔
375
        (*app)->link_user(*user, *credentials, make_callback(callback, userdata, userdata_free));
2✔
376
        return true;
2✔
377
    });
2✔
378
}
2✔
379

380
RLM_API bool realm_app_switch_user(realm_app_t* app, realm_user_t* user, realm_user_t** new_user)
381
{
2✔
382
    return wrap_err([&] {
2✔
383
        auto new_user_local = (*app)->switch_user(*user);
2✔
384
        if (new_user) {
2✔
385
            *new_user = new realm_user_t(std::move(new_user_local));
2✔
386
        }
2✔
387
        return true;
2✔
388
    });
2✔
389
}
2✔
390

391
RLM_API bool realm_app_remove_user(realm_app_t* app, realm_user_t* user, realm_app_void_completion_func_t callback,
392
                                   realm_userdata_t userdata, realm_free_userdata_func_t userdata_free)
393
{
2✔
394
    return wrap_err([&] {
2✔
395
        (*app)->remove_user(*user, make_callback(callback, userdata, userdata_free));
2✔
396
        return true;
2✔
397
    });
2✔
398
}
2✔
399

400
RLM_API bool realm_app_delete_user(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)
402
{
2✔
403
    return wrap_err([&] {
2✔
404
        (*app)->delete_user(*user, make_callback(callback, userdata, userdata_free));
2✔
405
        return true;
2✔
406
    });
2✔
407
}
2✔
408

409
RLM_API bool realm_app_email_password_provider_client_register_email(realm_app_t* app, const char* email,
410
                                                                     realm_string_t password,
411
                                                                     realm_app_void_completion_func_t callback,
412
                                                                     realm_userdata_t userdata,
413
                                                                     realm_free_userdata_func_t userdata_free)
414
{
10✔
415
    return wrap_err([&] {
10✔
416
        (*app)->provider_client<App::UsernamePasswordProviderClient>().register_email(
10✔
417
            email, from_capi(password), make_callback(callback, userdata, userdata_free));
10✔
418
        return true;
10✔
419
    });
10✔
420
}
10✔
421

422
RLM_API bool realm_app_email_password_provider_client_confirm_user(realm_app_t* app, const char* token,
423
                                                                   const char* token_id,
424
                                                                   realm_app_void_completion_func_t callback,
425
                                                                   realm_userdata_t userdata,
426
                                                                   realm_free_userdata_func_t userdata_free)
427
{
×
428
    return wrap_err([&] {
×
429
        (*app)->provider_client<App::UsernamePasswordProviderClient>().confirm_user(
×
430
            token, token_id, make_callback(callback, userdata, userdata_free));
×
431
        return true;
×
432
    });
×
433
}
×
434

435
RLM_API bool realm_app_email_password_provider_client_resend_confirmation_email(
436
    realm_app_t* app, const char* email, realm_app_void_completion_func_t callback, realm_userdata_t userdata,
437
    realm_free_userdata_func_t userdata_free)
438
{
×
439
    return wrap_err([&] {
×
440
        (*app)->provider_client<App::UsernamePasswordProviderClient>().resend_confirmation_email(
×
441
            email, make_callback(callback, userdata, userdata_free));
×
442
        return true;
×
443
    });
×
444
}
×
445

446
RLM_API bool realm_app_email_password_provider_client_send_reset_password_email(
447
    realm_app_t* app, const char* email, realm_app_void_completion_func_t callback, realm_userdata_t userdata,
448
    realm_free_userdata_func_t userdata_free)
449
{
×
450
    return wrap_err([&] {
×
451
        (*app)->provider_client<App::UsernamePasswordProviderClient>().send_reset_password_email(
×
452
            email, make_callback(callback, userdata, userdata_free));
×
453
        return true;
×
454
    });
×
455
}
×
456

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

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

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

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

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

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

2✔
541
        (*app)->provider_client<App::UserAPIKeyProviderClient>().fetch_api_keys(*user, std::move(cb));
4✔
542
        return true;
4✔
543
    });
4✔
544
}
4✔
545

546
RLM_API bool realm_app_user_apikey_provider_client_delete_apikey(const realm_app_t* app, const realm_user_t* user,
547
                                                                 realm_object_id_t id,
548
                                                                 realm_app_void_completion_func_t callback,
549
                                                                 realm_userdata_t userdata,
550
                                                                 realm_free_userdata_func_t userdata_free)
551
{
×
552
    return wrap_err([&] {
×
553
        (*app)->provider_client<App::UserAPIKeyProviderClient>().delete_api_key(
×
554
            from_capi(id), *user, make_callback(callback, userdata, userdata_free));
×
555
        return true;
×
556
    });
×
557
}
×
558

559
RLM_API bool realm_app_user_apikey_provider_client_enable_apikey(const realm_app_t* app, const realm_user_t* user,
560
                                                                 realm_object_id_t id,
561
                                                                 realm_app_void_completion_func_t callback,
562
                                                                 realm_userdata_t userdata,
563
                                                                 realm_free_userdata_func_t userdata_free)
564
{
×
565
    return wrap_err([&] {
×
566
        (*app)->provider_client<App::UserAPIKeyProviderClient>().enable_api_key(
×
567
            from_capi(id), *user, make_callback(callback, userdata, userdata_free));
×
568
        return true;
×
569
    });
×
570
}
×
571

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

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

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

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

634
RLM_API void realm_app_sync_client_reconnect(realm_app_t* app) noexcept
635
{
×
636
    (*app)->sync_manager()->reconnect();
×
637
}
×
638

639
RLM_API bool realm_app_sync_client_has_sessions(const realm_app_t* app) noexcept
640
{
×
641
    return (*app)->sync_manager()->has_existing_sessions();
×
642
}
×
643

644
RLM_API void realm_app_sync_client_wait_for_sessions_to_terminate(realm_app_t* app) noexcept
645
{
×
646
    (*app)->sync_manager()->wait_for_sessions_to_terminate();
×
647
}
×
648

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

660
RLM_API const char* realm_user_get_identity(const realm_user_t* user) noexcept
661
{
×
662
    return (*user)->identity().c_str();
×
663
}
×
664

665
RLM_API realm_user_state_e realm_user_get_state(const realm_user_t* user) noexcept
666
{
4✔
667
    return realm_user_state_e((*user)->state());
4✔
668
}
4✔
669

670
RLM_API bool realm_user_get_all_identities(const realm_user_t* user, realm_user_identity_t* out_identities,
671
                                           size_t max, size_t* out_n)
672
{
2✔
673
    return wrap_err([&] {
2✔
674
        const auto& identities = (*user)->identities();
2✔
675
        set_out_param(out_n, identities.size());
2✔
676
        if (out_identities && max >= identities.size()) {
2✔
677
            for (size_t i = 0; i < identities.size(); i++) {
6✔
678
                out_identities[i] = {duplicate_string(identities[i].id),
4✔
679
                                     realm_auth_provider_e(enum_from_provider_type(identities[i].provider_type))};
4✔
680
            }
4✔
681
        }
2✔
682
        return true;
2✔
683
    });
2✔
684
}
2✔
685

686
RLM_API char* realm_user_get_device_id(const realm_user_t* user) noexcept
687
{
×
688
    if ((*user)->has_device_id()) {
×
689
        return duplicate_string((*user)->device_id());
×
690
    }
×
691

692
    return nullptr;
×
693
}
×
694

695
RLM_API bool realm_user_log_out(realm_user_t* user)
696
{
×
697
    return wrap_err([&] {
×
698
        (*user)->log_out();
×
699
        return true;
×
700
    });
×
701
}
×
702

703
RLM_API bool realm_user_is_logged_in(const realm_user_t* user) noexcept
704
{
×
705
    return (*user)->is_logged_in();
×
706
}
×
707

708
RLM_API char* realm_user_get_profile_data(const realm_user_t* user)
709
{
×
710
    return wrap_err([&] {
×
711
        std::string data = bson::Bson((*user)->user_profile().data()).to_string();
×
712
        return duplicate_string(data);
×
713
    });
×
714
}
×
715

716
RLM_API char* realm_user_get_custom_data(const realm_user_t* user) noexcept
717
{
×
718
    if (const auto& data = (*user)->custom_data()) {
×
719
        std::string json = bson::Bson(*data).to_string();
×
720
        return duplicate_string(json);
×
721
    }
×
722

723
    return nullptr;
×
724
}
×
725

726
RLM_API char* realm_user_get_access_token(const realm_user_t* user)
727
{
×
728
    return wrap_err([&] {
×
729
        return duplicate_string((*user)->access_token());
×
730
    });
×
731
}
×
732

733
RLM_API char* realm_user_get_refresh_token(const realm_user_t* user)
734
{
×
735
    return wrap_err([&] {
×
736
        return duplicate_string((*user)->refresh_token());
×
737
    });
×
738
}
×
739

740
RLM_API realm_app_t* realm_user_get_app(const realm_user_t* user) noexcept
741
{
×
742
    REALM_ASSERT(user);
×
743
    try {
×
744
        if (auto shared_app = (*user)->sync_manager()->app().lock()) {
×
745
            return new realm_app_t(shared_app);
×
746
        }
×
747
    }
×
748
    catch (const std::exception&) {
×
749
    }
×
750
    return nullptr;
×
751
}
×
752

753

754
RLM_API realm_sync_user_subscription_token_t*
755
realm_sync_user_on_state_change_register_callback(realm_user_t* user, realm_sync_on_user_state_changed_t callback,
756
                                                  realm_userdata_t userdata, realm_free_userdata_func_t userdata_free)
757
{
2✔
758
    return wrap_err([&] {
2✔
759
        auto cb = [callback,
2✔
760
                   userdata = SharedUserdata{userdata, FreeUserdata(userdata_free)}](const SyncUser& sync_user) {
6✔
761
            callback(userdata.get(), realm_user_state_e(sync_user.state()));
6✔
762
        };
6✔
763
        auto token = (*user)->subscribe(std::move(cb));
2✔
764
        return new realm_sync_user_subscription_token_t{*user, std::move(token)};
2✔
765
    });
2✔
766
}
2✔
767

768
template <typename T>
769
inline util::Optional<T> convert_to_optional(T data)
770
{
×
771
    return data ? util::Optional<T>(data) : util::Optional<T>();
×
772
}
×
773

774
template <typename T>
775
inline util::Optional<T> convert_to_optional_bson(realm_string_t doc)
776
{
×
777
    if (doc.data == nullptr || doc.size == 0) {
×
778
        return util::Optional<T>();
×
779
    }
×
780
    return util::Optional<T>(static_cast<T>(bson::parse({doc.data, doc.size})));
×
781
}
×
782

783
template <typename T>
784
inline T convert_to_bson(realm_string_t doc)
785
{
×
786
    auto res = convert_to_optional_bson<T>(doc);
×
787
    return res ? *res : T();
×
788
}
×
789

790
static MongoCollection::FindOptions to_mongodb_collection_find_options(const realm_mongodb_find_options_t* options)
791
{
×
792
    MongoCollection::FindOptions mongodb_options;
×
793
    mongodb_options.projection_bson = convert_to_optional_bson<bson::BsonDocument>(options->projection_bson);
×
794
    mongodb_options.sort_bson = convert_to_optional_bson<bson::BsonDocument>(options->sort_bson);
×
795
    mongodb_options.limit = convert_to_optional(options->limit);
×
796
    return mongodb_options;
×
797
}
×
798

799
static MongoCollection::FindOneAndModifyOptions
800
to_mongodb_collection_find_one_and_modify_options(const realm_mongodb_find_one_and_modify_options_t* options)
801
{
×
802
    MongoCollection::FindOneAndModifyOptions mongodb_options;
×
803
    mongodb_options.projection_bson = convert_to_optional_bson<bson::BsonDocument>(options->projection_bson);
×
804
    mongodb_options.sort_bson = convert_to_optional_bson<bson::BsonDocument>(options->sort_bson);
×
805
    mongodb_options.upsert = options->upsert;
×
806
    mongodb_options.return_new_document = options->return_new_document;
×
807
    return mongodb_options;
×
808
}
×
809

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

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

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

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

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

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

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

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

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

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

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

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

994
RLM_API bool realm_mongo_collection_find_one_and_update(realm_mongodb_collection_t* collection,
995
                                                        realm_string_t filter_ejson, realm_string_t update_ejson,
996
                                                        const realm_mongodb_find_one_and_modify_options_t* options,
997
                                                        realm_userdata_t data, realm_free_userdata_func_t delete_data,
998
                                                        realm_mongodb_callback_t callback)
999
{
×
1000
    REALM_ASSERT(collection);
×
1001
    return wrap_err([&] {
×
1002
        const auto& bson_filter = convert_to_bson<bson::BsonDocument>(filter_ejson);
×
1003
        const auto& bson_update = convert_to_bson<bson::BsonDocument>(update_ejson);
×
1004
        collection->find_one_and_update_bson(
×
1005
            bson_filter, bson_update, to_mongodb_collection_find_one_and_modify_options(options),
×
1006
            [=](util::Optional<bson::Bson> bson, util::Optional<AppError> app_error) {
×
1007
                handle_mongodb_collection_result(bson, app_error, {data, delete_data}, callback);
×
1008
            });
×
1009
        return true;
×
1010
    });
×
1011
}
×
1012

1013
RLM_API bool realm_mongo_collection_find_one_and_replace(
1014
    realm_mongodb_collection_t* collection, realm_string_t filter_ejson, realm_string_t replacement_ejson,
1015
    const realm_mongodb_find_one_and_modify_options_t* options, realm_userdata_t data,
1016
    realm_free_userdata_func_t delete_data, realm_mongodb_callback_t callback)
1017
{
×
1018
    REALM_ASSERT(collection);
×
1019
    return wrap_err([&] {
×
1020
        const auto& filter_bson = convert_to_bson<bson::BsonDocument>(filter_ejson);
×
1021
        const auto& replacement_bson = convert_to_bson<bson::BsonDocument>(replacement_ejson);
×
1022
        collection->find_one_and_replace_bson(
×
1023
            filter_bson, replacement_bson, to_mongodb_collection_find_one_and_modify_options(options),
×
1024
            [=](util::Optional<bson::Bson> bson, util::Optional<AppError> app_error) {
×
1025
                handle_mongodb_collection_result(bson, app_error, {data, delete_data}, callback);
×
1026
            });
×
1027
        return true;
×
1028
    });
×
1029
}
×
1030

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

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

© 2026 Coveralls, Inc