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

realm / realm-core / nikola.irinchev_478

10 Jun 2024 05:02PM UTC coverage: 90.821% (-0.2%) from 90.975%
nikola.irinchev_478

Pull #7792

Evergreen

nirinchev
Replace app_config_get_sync_client_config with _set_sync_client_config
Pull Request #7792: Replace app_config_get_sync_client_config with _set_sync_client_config

101696 of 180086 branches covered (56.47%)

0 of 3 new or added lines in 1 file covered. (0.0%)

1872 existing lines in 57 files now uncovered.

214568 of 236253 relevant lines covered (90.82%)

5116114.57 hits per line

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

34.38
/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
#if REALM_APP_SERVICES
35

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

46
static_assert(realm_sync_client_metadata_mode_e(app::AppConfig::MetadataMode::NoEncryption) ==
47
              RLM_SYNC_CLIENT_METADATA_MODE_PLAINTEXT);
48
static_assert(realm_sync_client_metadata_mode_e(app::AppConfig::MetadataMode::Encryption) ==
49
              RLM_SYNC_CLIENT_METADATA_MODE_ENCRYPTED);
50
static_assert(realm_sync_client_metadata_mode_e(app::AppConfig::MetadataMode::InMemory) ==
51
              RLM_SYNC_CLIENT_METADATA_MODE_DISABLED);
52

53
static inline bson::BsonArray parse_ejson_array(const char* serialized)
54
{
×
55
    if (!serialized) {
×
56
        return {};
×
57
    }
×
58
    else {
×
59
        return bson::BsonArray(bson::parse({serialized, strlen(serialized)}));
×
60
    }
×
61
}
×
62

63
static realm_app_error_t to_capi(const AppError& error)
64
{
2✔
65
    auto ret = realm_app_error_t();
2✔
66

67
    ret.error = realm_errno_e(error.code());
2✔
68
    ret.categories = ErrorCodes::error_categories(error.code()).value();
2✔
69

70
    if (error.additional_status_code) {
2✔
71
        ret.http_status_code = *error.additional_status_code;
2✔
72
    }
2✔
73

74
    ret.message = error.what();
2✔
75

76
    if (error.link_to_server_logs.size() > 0) {
2✔
77
        ret.link_to_server_logs = error.link_to_server_logs.c_str();
×
78
    }
×
79

80
    return ret;
2✔
81
}
2✔
82

83
static inline realm_app_user_apikey_t to_capi(const App::UserAPIKey& apikey)
84
{
4✔
85
    return {to_capi(apikey.id), apikey.key ? apikey.key->c_str() : nullptr, apikey.name.c_str(), apikey.disabled};
4✔
86
}
4✔
87

88
static inline auto make_callback(realm_app_void_completion_func_t callback, realm_userdata_t userdata,
89
                                 realm_free_userdata_func_t userdata_free)
90
{
26✔
91
    return
26✔
92
        [callback, userdata = SharedUserdata(userdata, FreeUserdata(userdata_free))](util::Optional<AppError> error) {
26✔
93
            if (error) {
26✔
94
                realm_app_error_t c_err{to_capi(*error)};
×
95
                callback(userdata.get(), &c_err);
×
96
            }
×
97
            else {
26✔
98
                callback(userdata.get(), nullptr);
26✔
99
            }
26✔
100
        };
26✔
101
}
26✔
102

103
static inline auto make_callback(realm_app_user_completion_func_t callback, realm_userdata_t userdata,
104
                                 realm_free_userdata_func_t userdata_free)
105
{
14✔
106
    return [callback, userdata = SharedUserdata(userdata, FreeUserdata(userdata_free))](
14✔
107
               std::shared_ptr<app::User> user, util::Optional<AppError> error) {
14✔
108
        if (error) {
14✔
109
            realm_app_error_t c_err{to_capi(*error)};
×
110
            callback(userdata.get(), nullptr, &c_err);
×
111
        }
×
112
        else {
14✔
113
            auto c_user = realm_user_t(std::move(user));
14✔
114
            callback(userdata.get(), &c_user, nullptr);
14✔
115
        }
14✔
116
    };
14✔
117
}
14✔
118

119
static inline auto make_callback(void (*callback)(realm_userdata_t userdata, realm_app_user_apikey_t*,
120
                                                  const realm_app_error_t*),
121
                                 realm_userdata_t userdata, realm_free_userdata_func_t userdata_free)
122
{
2✔
123
    return [callback, userdata = SharedUserdata(userdata, FreeUserdata(userdata_free))](
2✔
124
               App::UserAPIKey apikey, util::Optional<AppError> error) {
2✔
125
        if (error) {
2✔
126
            realm_app_error_t c_error(to_capi(*error));
×
127
            callback(userdata.get(), nullptr, &c_error);
×
128
        }
×
129
        else {
2✔
130
            realm_app_user_apikey_t c_apikey(to_capi(apikey));
2✔
131
            callback(userdata.get(), &c_apikey, nullptr);
2✔
132
        }
2✔
133
    };
2✔
134
}
2✔
135

136
RLM_API const char* realm_app_get_default_base_url(void) noexcept
137
{
2✔
138
    return app::App::default_base_url().data();
2✔
139
}
2✔
140

141
RLM_API realm_app_credentials_t* realm_app_credentials_new_anonymous(bool reuse_credentials) noexcept
142
{
2✔
143
    return new realm_app_credentials_t(AppCredentials::anonymous(reuse_credentials));
2✔
144
}
2✔
145

146
RLM_API realm_app_credentials_t* realm_app_credentials_new_facebook(const char* access_token) noexcept
147
{
×
148
    return new realm_app_credentials_t(AppCredentials::facebook(access_token));
×
149
}
×
150

151
RLM_API realm_app_credentials_t* realm_app_credentials_new_google_id_token(const char* id_token) noexcept
152
{
×
153
    return new realm_app_credentials_t(AppCredentials::google(IdToken(id_token)));
×
154
}
×
155

156
RLM_API realm_app_credentials_t* realm_app_credentials_new_google_auth_code(const char* auth_code) noexcept
157
{
×
158
    return new realm_app_credentials_t(AppCredentials::google(AuthCode(auth_code)));
×
159
}
×
160

161
RLM_API realm_app_credentials_t* realm_app_credentials_new_apple(const char* id_token) noexcept
162
{
×
163
    return new realm_app_credentials_t(AppCredentials::apple(id_token));
×
164
}
×
165

166
RLM_API realm_app_credentials_t* realm_app_credentials_new_jwt(const char* jwt_token) noexcept
167
{
×
168
    return new realm_app_credentials_t(AppCredentials::custom(jwt_token));
×
169
}
×
170

171
RLM_API realm_app_credentials_t* realm_app_credentials_new_email_password(const char* email,
172
                                                                          realm_string_t password) noexcept
173
{
×
174
    return new realm_app_credentials_t(AppCredentials::username_password(email, from_capi(password)));
×
175
}
×
176

177
RLM_API realm_app_credentials_t* realm_app_credentials_new_function(const char* serialized_ejson_payload)
178
{
×
179
    return wrap_err([&] {
×
180
        return new realm_app_credentials_t(AppCredentials::function(serialized_ejson_payload));
×
181
    });
×
182
}
×
183

184
RLM_API realm_app_credentials_t* realm_app_credentials_new_api_key(const char* api_key) noexcept
185
{
×
186
    return new realm_app_credentials_t(AppCredentials::api_key(api_key));
×
187
}
×
188

189
RLM_API realm_auth_provider_e realm_auth_credentials_get_provider(realm_app_credentials_t* credentials) noexcept
190
{
×
191
    return realm_auth_provider_e(credentials->provider());
×
192
}
×
193

194
RLM_API realm_app_config_t* realm_app_config_new(const char* app_id,
195
                                                 const realm_http_transport_t* http_transport) noexcept
196
{
2✔
197
    auto* config = new realm_app_config_t;
2✔
198
    config->app_id = app_id;
2✔
199
    config->transport = *http_transport; // realm_http_transport_t is a shared_ptr
2✔
200
    return config;
2✔
201
}
2✔
202

203
RLM_API void realm_app_config_set_base_url(realm_app_config_t* config, const char* base_url) noexcept
204
{
2✔
205
    config->base_url = std::string(base_url);
2✔
206
}
2✔
207

208
RLM_API void realm_app_config_set_default_request_timeout(realm_app_config_t* config, uint64_t ms) noexcept
209
{
2✔
210
    config->default_request_timeout_ms = ms;
2✔
211
}
2✔
212

213
RLM_API void realm_app_config_set_platform_version(realm_app_config_t* config, const char* platform_version) noexcept
214
{
2✔
215
    config->device_info.platform_version = std::string(platform_version);
2✔
216
}
2✔
217

218
RLM_API void realm_app_config_set_sdk_version(realm_app_config_t* config, const char* sdk_version) noexcept
219
{
2✔
220
    config->device_info.sdk_version = std::string(sdk_version);
2✔
221
}
2✔
222

223
RLM_API void realm_app_config_set_sdk(realm_app_config_t* config, const char* sdk) noexcept
224
{
2✔
225
    config->device_info.sdk = std::string(sdk);
2✔
226
}
2✔
227

228
RLM_API void realm_app_config_set_device_name(realm_app_config_t* config, const char* device_name) noexcept
229
{
2✔
230
    config->device_info.device_name = std::string(device_name);
2✔
231
}
2✔
232

233
RLM_API void realm_app_config_set_device_version(realm_app_config_t* config, const char* device_version) noexcept
234
{
2✔
235
    config->device_info.device_version = std::string(device_version);
2✔
236
}
2✔
237

238
RLM_API void realm_app_config_set_framework_name(realm_app_config_t* config, const char* framework_name) noexcept
239
{
2✔
240
    config->device_info.framework_name = std::string(framework_name);
2✔
241
}
2✔
242

243
RLM_API void realm_app_config_set_framework_version(realm_app_config_t* config,
244
                                                    const char* framework_version) noexcept
245
{
2✔
246
    config->device_info.framework_version = std::string(framework_version);
2✔
247
}
2✔
248

249
RLM_API void realm_app_config_set_bundle_id(realm_app_config_t* config, const char* bundle_id) noexcept
250
{
2✔
251
    config->device_info.bundle_id = std::string(bundle_id);
2✔
252
}
2✔
253

254
RLM_API void realm_app_config_set_base_file_path(realm_app_config_t* config, const char* path) noexcept
255
{
4✔
256
    config->base_file_path = path;
4✔
257
}
4✔
258

259
RLM_API void realm_app_config_set_metadata_mode(realm_app_config_t* config,
260
                                                realm_sync_client_metadata_mode_e mode) noexcept
261
{
8✔
262
    config->metadata_mode = app::AppConfig::MetadataMode(mode);
8✔
263
}
8✔
264

265
RLM_API void realm_app_config_set_metadata_encryption_key(realm_app_config_t* config, const uint8_t key[64]) noexcept
266
{
2✔
267
    config->custom_encryption_key = std::vector<char>(key, key + 64);
2✔
268
}
2✔
269

270
RLM_API void realm_app_config_set_security_access_group(realm_app_config_t* config, const char* group) noexcept
271
{
4✔
272
    config->security_access_group = group;
4✔
273
}
4✔
274

275
RLM_API void realm_app_config_set_sync_client_config(realm_app_config_t* config, realm_sync_client_config_t* sync_client_config) noexcept
NEW
276
{
×
NEW
277
    config->sync_client_config = *sync_client_config;
×
NEW
278
}
×
279

280
RLM_API const char* realm_app_credentials_serialize_as_json(realm_app_credentials_t* app_credentials) noexcept
281
{
×
282
    return wrap_err([&] {
×
283
        return duplicate_string(app_credentials->serialize_as_json());
×
284
    });
×
285
}
×
286

287
RLM_API realm_app_t* realm_app_create(const realm_app_config_t* app_config)
288
{
2✔
289
    return wrap_err([&] {
2✔
290
        return new realm_app_t(App::get_app(app::App::CacheMode::Disabled, *app_config));
2✔
291
    });
2✔
292
}
2✔
293

294
RLM_API realm_app_t* realm_app_create_cached(const realm_app_config_t* app_config)
295
{
×
296
    return wrap_err([&] {
×
297
        return new realm_app_t(App::get_app(app::App::CacheMode::Enabled, *app_config));
×
298
    });
×
299
}
×
300

301
RLM_API bool realm_app_get_cached(const char* app_id, const char* base_url, realm_app_t** out_app)
302
{
×
303
    return wrap_err([&] {
×
304
        auto app =
×
305
            App::get_cached_app(std::string(app_id), base_url ? util::some<std::string>(base_url) : util::none);
×
306
        if (out_app) {
×
307
            *out_app = app ? new realm_app_t(app) : nullptr;
×
308
        }
×
309

310
        return true;
×
311
    });
×
312
}
×
313

314
RLM_API void realm_clear_cached_apps(void) noexcept
315
{
×
316
    App::clear_cached_apps();
×
317
}
×
318

319
RLM_API const char* realm_app_get_app_id(const realm_app_t* app) noexcept
320
{
×
321
    return (*app)->app_id().c_str();
×
322
}
×
323

324
RLM_API bool realm_app_update_base_url(realm_app_t* app, const char* base_url,
325
                                       realm_app_void_completion_func_t callback, realm_userdata_t userdata,
326
                                       realm_free_userdata_func_t userdata_free)
327
{
6✔
328
    return wrap_err([&] {
6✔
329
        (*app)->update_base_url(base_url ? base_url : "", make_callback(callback, userdata, userdata_free));
6✔
330
        return true;
6✔
331
    });
6✔
332
}
6✔
333

334
RLM_API char* realm_app_get_base_url(realm_app_t* app) noexcept
335
{
8✔
336
    auto url_stg = (*app)->get_base_url();
8✔
337
    return duplicate_string(url_stg);
8✔
338
}
8✔
339

340
RLM_API realm_user_t* realm_app_get_current_user(const realm_app_t* app) noexcept
341
{
4✔
342
    if (auto user = (*app)->current_user()) {
4✔
343
        return new realm_user_t(user);
4✔
344
    }
4✔
345

346
    return nullptr;
×
347
}
4✔
348

349
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)
350
{
4✔
351
    return wrap_err([&] {
4✔
352
        const auto& users = (*app)->all_users();
4✔
353
        set_out_param(out_n, users.size());
4✔
354
        if (out_users && capacity >= users.size()) {
4✔
355
            OutBuffer<realm_user_t> buf(out_users);
2✔
356
            for (const auto& user : users) {
4✔
357
                buf.emplace(user);
4✔
358
            }
4✔
359
            buf.release(out_n);
2✔
360
        }
2✔
361
        return true;
4✔
362
    });
4✔
363
}
4✔
364

365
RLM_API bool realm_app_log_in_with_credentials(realm_app_t* app, realm_app_credentials_t* credentials,
366
                                               realm_app_user_completion_func_t callback, realm_userdata_t userdata,
367
                                               realm_free_userdata_func_t userdata_free)
368
{
12✔
369
    return wrap_err([&] {
12✔
370
        (*app)->log_in_with_credentials(*credentials, make_callback(callback, userdata, userdata_free));
12✔
371
        return true;
12✔
372
    });
12✔
373
}
12✔
374

375
RLM_API bool realm_app_log_out_current_user(realm_app_t* app, realm_app_void_completion_func_t callback,
376
                                            realm_userdata_t userdata, realm_free_userdata_func_t userdata_free)
377
{
×
378
    return wrap_err([&] {
×
379
        (*app)->log_out(make_callback(callback, userdata, userdata_free));
×
380
        return true;
×
381
    });
×
382
}
×
383

384
namespace {
385
template <typename Fn>
386
auto with_app_user(const realm_user_t* user, Fn&& fn)
387
{
24✔
388
    auto app_user = std::dynamic_pointer_cast<realm::app::User>(*user);
24✔
389
    return wrap_err([&] {
24✔
390
        if (!app_user) {
24!
391
            throw Exception(ErrorCodes::InvalidArgument, "App Services function require a user obtained from an App");
×
392
        }
×
393
        if constexpr (std::is_void_v<decltype(fn(app_user))>) {
24✔
394
            fn(app_user);
12✔
395
            return true;
12✔
396
        }
1✔
397
        else {
2✔
398
            return fn(app_user);
2✔
399
        }
2✔
400
    });
24✔
401
}
24✔
402
} // anonymous namespace
403

404
RLM_API bool realm_app_refresh_custom_data(realm_app_t* app, realm_user_t* user,
405
                                           realm_app_void_completion_func_t callback, realm_userdata_t userdata,
406
                                           realm_free_userdata_func_t userdata_free)
407
{
6✔
408
    return with_app_user(user, [&](auto& user) {
6✔
409
        (*app)->refresh_custom_data(user, make_callback(callback, userdata, userdata_free));
6✔
410
    });
6✔
411
}
6✔
412

413
RLM_API bool realm_app_log_out(realm_app_t* app, realm_user_t* user, realm_app_void_completion_func_t callback,
414
                               realm_userdata_t userdata, realm_free_userdata_func_t userdata_free)
415
{
×
416
    return with_app_user(user, [&](auto& user) {
×
417
        (*app)->log_out(user, make_callback(callback, userdata, userdata_free));
×
418
    });
×
419
}
×
420

421
RLM_API bool realm_app_link_user(realm_app_t* app, realm_user_t* user, realm_app_credentials_t* credentials,
422
                                 realm_app_user_completion_func_t callback, realm_userdata_t userdata,
423
                                 realm_free_userdata_func_t userdata_free)
424
{
2✔
425
    return with_app_user(user, [&](auto& user) {
2✔
426
        (*app)->link_user(user, *credentials, make_callback(callback, userdata, userdata_free));
2✔
427
    });
2✔
428
}
2✔
429

430
RLM_API bool realm_app_switch_user(realm_app_t* app, realm_user_t* user)
431
{
2✔
432
    return with_app_user(user, [&](auto& user) {
2✔
433
        (*app)->switch_user(user);
2✔
434
    });
2✔
435
}
2✔
436

437
RLM_API bool realm_app_remove_user(realm_app_t* app, realm_user_t* user, realm_app_void_completion_func_t callback,
438
                                   realm_userdata_t userdata, realm_free_userdata_func_t userdata_free)
439
{
2✔
440
    return with_app_user(user, [&](auto& user) {
2✔
441
        (*app)->remove_user(user, make_callback(callback, userdata, userdata_free));
2✔
442
    });
2✔
443
}
2✔
444

445
RLM_API bool realm_app_delete_user(realm_app_t* app, realm_user_t* user, realm_app_void_completion_func_t callback,
446
                                   realm_userdata_t userdata, realm_free_userdata_func_t userdata_free)
447
{
2✔
448
    return with_app_user(user, [&](auto& user) {
2✔
449
        (*app)->delete_user(user, make_callback(callback, userdata, userdata_free));
2✔
450
    });
2✔
451
}
2✔
452

453
RLM_API bool realm_app_email_password_provider_client_register_email(realm_app_t* app, const char* email,
454
                                                                     realm_string_t password,
455
                                                                     realm_app_void_completion_func_t callback,
456
                                                                     realm_userdata_t userdata,
457
                                                                     realm_free_userdata_func_t userdata_free)
458
{
10✔
459
    return wrap_err([&] {
10✔
460
        (*app)->provider_client<App::UsernamePasswordProviderClient>().register_email(
10✔
461
            email, from_capi(password), make_callback(callback, userdata, userdata_free));
10✔
462
        return true;
10✔
463
    });
10✔
464
}
10✔
465

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

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

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

501
RLM_API bool realm_app_email_password_provider_client_retry_custom_confirmation(
502
    realm_app_t* app, const char* email, realm_app_void_completion_func_t callback, realm_userdata_t userdata,
503
    realm_free_userdata_func_t userdata_free)
504
{
×
505
    return wrap_err([&] {
×
506
        (*app)->provider_client<App::UsernamePasswordProviderClient>().retry_custom_confirmation(
×
507
            email, make_callback(callback, userdata, userdata_free));
×
508
        return true;
×
509
    });
×
510
}
×
511

512
RLM_API bool realm_app_email_password_provider_client_reset_password(realm_app_t* app, realm_string_t password,
513
                                                                     const char* token, const char* token_id,
514
                                                                     realm_app_void_completion_func_t callback,
515
                                                                     realm_userdata_t userdata,
516
                                                                     realm_free_userdata_func_t userdata_free)
517
{
×
518
    return wrap_err([&] {
×
519
        (*app)->provider_client<App::UsernamePasswordProviderClient>().reset_password(
×
520
            from_capi(password), token, token_id, make_callback(callback, userdata, userdata_free));
×
521
        return true;
×
522
    });
×
523
}
×
524

525
RLM_API bool realm_app_email_password_provider_client_call_reset_password_function(
526
    realm_app_t* app, const char* email, realm_string_t password, const char* serialized_ejson_payload,
527
    realm_app_void_completion_func_t callback, realm_userdata_t userdata, realm_free_userdata_func_t userdata_free)
528
{
×
529
    return wrap_err([&] {
×
530
        bson::BsonArray args = parse_ejson_array(serialized_ejson_payload);
×
531
        (*app)->provider_client<App::UsernamePasswordProviderClient>().call_reset_password_function(
×
532
            email, from_capi(password), args, make_callback(callback, userdata, userdata_free));
×
533
        return true;
×
534
    });
×
535
}
×
536

537
RLM_API bool realm_app_user_apikey_provider_client_create_apikey(const realm_app_t* app, const realm_user_t* user,
538
                                                                 const char* name,
539
                                                                 realm_return_apikey_func_t callback,
540
                                                                 realm_userdata_t userdata,
541
                                                                 realm_free_userdata_func_t userdata_free)
542
{
2✔
543
    return with_app_user(user, [&](auto& user) {
2✔
544
        (*app)->provider_client<App::UserAPIKeyProviderClient>().create_api_key(
2✔
545
            name, user, make_callback(callback, userdata, userdata_free));
2✔
546
    });
2✔
547
}
2✔
548

549
RLM_API bool realm_app_user_apikey_provider_client_fetch_apikey(const realm_app_t* app, const realm_user_t* user,
550
                                                                realm_object_id_t id,
551
                                                                realm_return_apikey_func_t callback,
552
                                                                realm_userdata_t userdata,
553
                                                                realm_free_userdata_func_t userdata_free)
554
{
×
555
    return with_app_user(user, [&](auto& user) {
×
556
        (*app)->provider_client<App::UserAPIKeyProviderClient>().fetch_api_key(
×
557
            from_capi(id), user, make_callback(callback, userdata, userdata_free));
×
558
    });
×
559
}
×
560

561
RLM_API bool realm_app_user_apikey_provider_client_fetch_apikeys(const realm_app_t* app, const realm_user_t* user,
562
                                                                 realm_return_apikey_list_func_t callback,
563
                                                                 realm_userdata_t userdata,
564
                                                                 realm_free_userdata_func_t userdata_free)
565
{
4✔
566
    return with_app_user(user, [&](auto& user) {
4✔
567
        auto cb = [callback, userdata = SharedUserdata{userdata, FreeUserdata(userdata_free)}](
4✔
568
                      std::vector<App::UserAPIKey> apikeys, util::Optional<AppError> error) {
4✔
569
            if (error) {
4✔
570
                realm_app_error_t c_error(to_capi(*error));
2✔
571
                callback(userdata.get(), nullptr, 0, &c_error);
2✔
572
            }
2✔
573
            else {
2✔
574
                std::vector<realm_app_user_apikey_t> c_apikeys;
2✔
575
                c_apikeys.reserve(apikeys.size());
2✔
576
                for (const auto& apikey : apikeys) {
2✔
577
                    c_apikeys.push_back(to_capi(apikey));
2✔
578
                }
2✔
579
                callback(userdata.get(), c_apikeys.data(), c_apikeys.size(), nullptr);
2✔
580
            }
2✔
581
        };
4✔
582

583
        (*app)->provider_client<App::UserAPIKeyProviderClient>().fetch_api_keys(user, std::move(cb));
4✔
584
    });
4✔
585
}
4✔
586

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

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

611
RLM_API bool realm_app_user_apikey_provider_client_disable_apikey(const realm_app_t* app, const realm_user_t* user,
612
                                                                  realm_object_id_t id,
613
                                                                  realm_app_void_completion_func_t callback,
614
                                                                  realm_userdata_t userdata,
615
                                                                  realm_free_userdata_func_t userdata_free)
616
{
×
617
    return with_app_user(user, [&](auto& user) {
×
618
        (*app)->provider_client<App::UserAPIKeyProviderClient>().disable_api_key(
×
619
            from_capi(id), user, make_callback(callback, userdata, userdata_free));
×
620
    });
×
621
}
×
622

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

634
RLM_API bool realm_app_push_notification_client_deregister_device(const realm_app_t* app, const realm_user_t* user,
635
                                                                  const char* service_name,
636
                                                                  realm_app_void_completion_func_t callback,
637
                                                                  realm_userdata_t userdata,
638
                                                                  realm_free_userdata_func_t userdata_free)
639
{
×
640
    return with_app_user(user, [&](auto& user) {
×
641
        (*app)
×
642
            ->push_notification_client(service_name)
×
643
            .deregister_device(user, make_callback(callback, userdata, userdata_free));
×
644
    });
×
645
}
×
646

647
RLM_API bool realm_app_call_function(const realm_app_t* app, const realm_user_t* user, const char* function_name,
648
                                     const char* serialized_ejson_payload, const char* service_name,
649
                                     realm_return_string_func_t callback, realm_userdata_t userdata,
650
                                     realm_free_userdata_func_t userdata_free)
651
{
×
652
    return with_app_user(user, [&](auto& user) {
×
653
        auto cb = [callback, userdata = SharedUserdata{userdata, FreeUserdata(userdata_free)}](
×
654
                      const std::string* reply, util::Optional<AppError> error) {
×
655
            if (error) {
×
656
                realm_app_error_t c_error(to_capi(*error));
×
657
                callback(userdata.get(), nullptr, &c_error);
×
658
            }
×
659
            else {
×
660
                callback(userdata.get(), reply->c_str(), nullptr);
×
661
            }
×
662
        };
×
663
        util::Optional<std::string> service_name_opt =
×
664
            service_name ? util::some<std::string>(service_name) : util::none;
×
665
        (*app)->call_function(user, function_name, serialized_ejson_payload, service_name_opt, std::move(cb));
×
666
    });
×
667
}
×
668

669
RLM_API void realm_app_sync_client_reconnect(realm_app_t* app) noexcept
670
{
×
671
    (*app)->sync_manager()->reconnect();
×
672
}
×
673

674
RLM_API bool realm_app_sync_client_has_sessions(const realm_app_t* app) noexcept
675
{
×
676
    return (*app)->sync_manager()->has_existing_sessions();
×
677
}
×
678

679
RLM_API void realm_app_sync_client_wait_for_sessions_to_terminate(realm_app_t* app) noexcept
680
{
×
681
    (*app)->sync_manager()->wait_for_sessions_to_terminate();
×
682
}
×
683

684
RLM_API char* realm_app_sync_client_get_default_file_path_for_realm(const realm_sync_config_t* config,
685
                                                                    const char* custom_filename)
686
{
×
687
    return wrap_err([&]() -> char* {
×
688
        auto user = std::dynamic_pointer_cast<app::User>(config->user);
×
689
        if (!user) {
×
690
            return nullptr;
×
691
        }
×
692
        util::Optional<std::string> filename =
×
693
            custom_filename ? util::some<std::string>(custom_filename) : util::none;
×
694
        std::string file_path = user->app()->path_for_realm(*config, std::move(filename));
×
695
        return duplicate_string(file_path);
×
696
    });
×
697
}
×
698

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

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

725
RLM_API bool realm_user_log_out(realm_user_t* user)
726
{
×
727
    return with_app_user(user, [&](auto& user) {
×
728
        user->log_out();
×
729
    });
×
730
}
×
731

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

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

751
RLM_API realm_app_t* realm_user_get_app(const realm_user_t* user) noexcept
752
{
×
753
    REALM_ASSERT(user);
×
754
    return with_app_user(user, [&](auto& user) {
×
755
        return new realm_app_t(user->app());
×
756
    });
×
757
}
×
758

759
RLM_API char* realm_user_get_identity(const realm_user_t* user) noexcept
760
{
×
761
    return duplicate_string((*user)->user_id());
×
762
}
×
763

764
RLM_API realm_user_state_e realm_user_get_state(const realm_user_t* user) noexcept
765
{
4✔
766
    return realm_user_state_e((*user)->state());
4✔
767
}
4✔
768

769
RLM_API bool realm_user_is_logged_in(const realm_user_t* user) noexcept
770
{
×
771
    return (*user)->is_logged_in();
×
772
}
×
773

774
RLM_API char* realm_user_get_access_token(const realm_user_t* user)
775
{
×
776
    return wrap_err([&] {
×
777
        return duplicate_string((*user)->access_token());
×
778
    });
×
779
}
×
780

781
RLM_API char* realm_user_get_refresh_token(const realm_user_t* user)
782
{
×
783
    return wrap_err([&] {
×
784
        return duplicate_string((*user)->refresh_token());
×
785
    });
×
786
}
×
787

788
RLM_API realm_app_user_subscription_token_t*
789
realm_sync_user_on_state_change_register_callback(realm_user_t* user, realm_sync_on_user_state_changed_t callback,
790
                                                  realm_userdata_t userdata, realm_free_userdata_func_t userdata_free)
791
{
2✔
792
    return with_app_user(user, [&](auto& user) {
2✔
793
        auto cb = [callback,
2✔
794
                   userdata = SharedUserdata{userdata, FreeUserdata(userdata_free)}](const SyncUser& sync_user) {
6✔
795
            callback(userdata.get(), realm_user_state_e(sync_user.state()));
6✔
796
        };
6✔
797
        auto token = user->subscribe(std::move(cb));
2✔
798
        return new realm_app_user_subscription_token_t{user, std::move(token)};
2✔
799
    });
2✔
800
}
2✔
801

802
RLM_API bool realm_sync_immediately_run_file_actions(realm_app_t* realm_app, const char* sync_path,
803
                                                     bool* did_run) noexcept
804
{
8✔
805
    return wrap_err([&]() {
8✔
806
        *did_run = (*realm_app)->immediately_run_file_actions(sync_path);
8✔
807
        return true;
8✔
808
    });
8✔
809
}
8✔
810

811
#endif // REALM_APP_SERVICES
812

813
#if !REALM_APP_SERVICES
814

815
static void cb_proxy_for_completion(realm_userdata_t userdata, const realm_app_error_t* err)
816
{
817
    SyncUser::CompletionHandler* cxx_cb = static_cast<SyncUser::CompletionHandler*>(userdata);
818
    REALM_ASSERT(cxx_cb);
819
    std::optional<AppError> cxx_err;
820
    if (err) {
821
        std::optional<int> additional_error_code;
822
        if (err->http_status_code) {
823
            additional_error_code = err->http_status_code;
824
        }
825
        cxx_err =
826
            AppError(ErrorCodes::Error(err->error), err->message, err->link_to_server_logs, additional_error_code);
827
    }
828
    (*cxx_cb)(cxx_err);
829
    delete cxx_cb;
830
}
831

832
struct CAPIAppUser : SyncUser {
833
    void* m_userdata = nullptr;
834
    realm_free_userdata_func_t m_free = nullptr;
835
    const std::string m_app_id;
836
    const std::string m_user_id;
837
    realm_user_get_access_token_cb_t m_access_token_cb = nullptr;
838
    realm_user_get_refresh_token_cb_t m_refresh_token_cb = nullptr;
839
    realm_user_state_cb_t m_state_cb = nullptr;
840
    realm_user_access_token_refresh_required_cb_t m_atrr_cb = nullptr;
841
    realm_user_get_sync_manager_cb_t m_sync_manager_cb = nullptr;
842
    realm_user_request_log_out_cb_t m_request_log_out_cb = nullptr;
843
    realm_user_request_refresh_location_cb_t m_request_refresh_location_cb = nullptr;
844
    realm_user_request_access_token_cb_t m_request_access_token_cb = nullptr;
845
    realm_user_track_realm_cb_t m_track_realm_cb = nullptr;
846
    realm_user_create_file_action_cb_t m_create_fa_cb = nullptr;
847

848
    CAPIAppUser(const char* app_id, const char* user_id)
849
        : m_app_id(app_id)
850
        , m_user_id(user_id)
851
    {
852
    }
853
    CAPIAppUser(CAPIAppUser&& other)
854
        : m_userdata(std::exchange(other.m_userdata, nullptr))
855
        , m_free(std::exchange(other.m_free, nullptr))
856
        , m_app_id(std::move(other.m_app_id))
857
        , m_user_id(std::move(other.m_user_id))
858
        , m_access_token_cb(std::move(other.m_access_token_cb))
859
        , m_refresh_token_cb(std::move(other.m_refresh_token_cb))
860
        , m_state_cb(std::move(other.m_state_cb))
861
        , m_atrr_cb(std::move(other.m_atrr_cb))
862
        , m_sync_manager_cb(std::move(other.m_sync_manager_cb))
863
        , m_request_log_out_cb(std::move(other.m_request_log_out_cb))
864
        , m_request_refresh_location_cb(std::move(other.m_request_refresh_location_cb))
865
        , m_request_access_token_cb(std::move(other.m_request_access_token_cb))
866
        , m_track_realm_cb(std::move(other.m_track_realm_cb))
867
        , m_create_fa_cb(std::move(other.m_create_fa_cb))
868
    {
869
    }
870

871
    ~CAPIAppUser()
872
    {
873
        if (m_free)
874
            m_free(m_userdata);
875
    }
876
    std::string user_id() const noexcept override
877
    {
878
        return m_user_id;
879
    }
880
    std::string app_id() const noexcept override
881
    {
882
        return m_app_id;
883
    }
884
    std::string access_token() const override
885
    {
886
        return m_access_token_cb(m_userdata);
887
    }
888
    std::string refresh_token() const override
889
    {
890
        return m_refresh_token_cb(m_userdata);
891
    }
892
    State state() const override
893
    {
894
        return State(m_state_cb(m_userdata));
895
    }
896
    bool access_token_refresh_required() const override
897
    {
898
        return m_atrr_cb(m_userdata);
899
    }
900
    SyncManager* sync_manager() override
901
    {
902
        auto value = m_sync_manager_cb(m_userdata);
903
        if (value && value->get()) {
904
            return (value->get());
905
        }
906
        return nullptr;
907
    }
908
    void request_log_out() override
909
    {
910
        m_request_log_out_cb(m_userdata);
911
    }
912
    void request_refresh_location(CompletionHandler&& callback) override
913
    {
914
        auto unscoped_cb = new CompletionHandler(std::move(callback));
915
        m_request_refresh_location_cb(m_userdata, cb_proxy_for_completion, unscoped_cb);
916
    }
917
    void request_access_token(CompletionHandler&& callback) override
918
    {
919
        auto unscoped_cb = new CompletionHandler(std::move(callback));
920
        m_request_access_token_cb(m_userdata, cb_proxy_for_completion, unscoped_cb);
921
    }
922
    void track_realm(std::string_view path) override
923
    {
924
        if (m_track_realm_cb) {
925
            m_track_realm_cb(m_userdata, path.data());
926
        }
927
    }
928
    std::string create_file_action(SyncFileAction a, std::string_view path,
929
                                   std::optional<std::string> recovery_dir) override
930
    {
931

932
        if (m_create_fa_cb) {
933
            return m_create_fa_cb(m_userdata, realm_sync_file_action_e(a), path.data(),
934
                                  recovery_dir ? recovery_dir->data() : nullptr);
935
        }
936
        return "";
937
    }
938
};
939

940
RLM_API realm_user_t* realm_user_new(realm_sync_user_create_config_t c) noexcept
941
{
942
    // optional to provide:
943
    // m_userdata
944
    // m_free
945
    // m_track_realm_cb
946
    // m_create_fa_cb
947

948
    REALM_ASSERT(c.app_id);
949
    REALM_ASSERT(c.user_id);
950
    REALM_ASSERT(c.access_token_cb);
951
    REALM_ASSERT(c.refresh_token_cb);
952
    REALM_ASSERT(c.state_cb);
953
    REALM_ASSERT(c.atrr_cb);
954
    REALM_ASSERT(c.sync_manager_cb);
955
    REALM_ASSERT(c.request_log_out_cb);
956
    REALM_ASSERT(c.request_refresh_location_cb);
957
    REALM_ASSERT(c.request_access_token_cb);
958

959
    return wrap_err([&]() {
960
        auto capi_user = std::make_shared<CAPIAppUser>(c.app_id, c.user_id);
961
        capi_user->m_userdata = c.userdata;
962
        capi_user->m_free = c.free_func;
963
        capi_user->m_access_token_cb = c.access_token_cb;
964
        capi_user->m_refresh_token_cb = c.refresh_token_cb;
965
        capi_user->m_state_cb = c.state_cb;
966
        capi_user->m_atrr_cb = c.atrr_cb;
967
        capi_user->m_sync_manager_cb = c.sync_manager_cb;
968
        capi_user->m_request_log_out_cb = c.request_log_out_cb;
969
        capi_user->m_request_refresh_location_cb = c.request_refresh_location_cb;
970
        capi_user->m_request_access_token_cb = c.request_access_token_cb;
971
        capi_user->m_track_realm_cb = c.track_realm_cb;
972
        capi_user->m_create_fa_cb = c.create_fa_cb;
973

974
        return new realm_user_t(std::move(capi_user));
975
    });
976
}
977

978
RLM_API realm_sync_manager_t* realm_sync_manager_create(const realm_sync_client_config_t* config)
979
{
980
    return wrap_err([&]() {
981
        auto manager = SyncManager::create(*config);
982
        return new realm_sync_manager_t(std::move(manager));
983
    });
984
}
985

986
RLM_API void realm_sync_manager_set_route(const realm_sync_manager_t* manager, const char* route, bool is_verified)
987
{
988
    REALM_ASSERT(manager);
989
    (*manager)->set_sync_route(route, is_verified);
990
}
991
#endif // #!REALM_APP_SERVICES
992

993
#if REALM_APP_SERVICES
994

995
namespace {
996
template <typename T>
997
util::Optional<T> convert_to_optional(T data)
998
{
×
999
    return data ? util::Optional<T>(data) : util::Optional<T>();
×
1000
}
×
1001

1002
template <typename T>
1003
util::Optional<T> convert_to_optional_bson(realm_string_t doc)
1004
{
×
1005
    if (doc.data == nullptr || doc.size == 0) {
×
1006
        return util::Optional<T>();
×
1007
    }
×
1008
    return util::Optional<T>(static_cast<T>(bson::parse({doc.data, doc.size})));
×
1009
}
×
1010

1011
template <typename T>
1012
T convert_to_bson(realm_string_t doc)
1013
{
×
1014
    auto res = convert_to_optional_bson<T>(doc);
×
1015
    return res ? *res : T();
×
1016
}
×
1017

1018
MongoCollection::FindOptions to_mongodb_collection_find_options(const realm_mongodb_find_options_t* options)
1019
{
×
1020
    MongoCollection::FindOptions mongodb_options;
×
1021
    mongodb_options.projection_bson = convert_to_optional_bson<bson::BsonDocument>(options->projection_bson);
×
1022
    mongodb_options.sort_bson = convert_to_optional_bson<bson::BsonDocument>(options->sort_bson);
×
1023
    mongodb_options.limit = convert_to_optional(options->limit);
×
1024
    return mongodb_options;
×
1025
}
×
1026

1027
MongoCollection::FindOneAndModifyOptions
1028
to_mongodb_collection_find_one_and_modify_options(const realm_mongodb_find_one_and_modify_options_t* options)
1029
{
×
1030
    MongoCollection::FindOneAndModifyOptions mongodb_options;
×
1031
    mongodb_options.projection_bson = convert_to_optional_bson<bson::BsonDocument>(options->projection_bson);
×
1032
    mongodb_options.sort_bson = convert_to_optional_bson<bson::BsonDocument>(options->sort_bson);
×
1033
    mongodb_options.upsert = options->upsert;
×
1034
    mongodb_options.return_new_document = options->return_new_document;
×
1035
    return mongodb_options;
×
1036
}
×
1037

1038
void handle_mongodb_collection_result(util::Optional<bson::Bson> bson, util::Optional<AppError> app_error,
1039
                                      UserdataPtr data, realm_mongodb_callback_t callback)
1040
{
×
1041
    if (app_error) {
×
1042
        auto error = to_capi(*app_error);
×
1043
        callback(data.get(), {nullptr, 0}, &error);
×
1044
    }
×
1045
    else if (bson) {
×
1046
        const auto& bson_data = bson->to_string();
×
1047
        callback(data.get(), {bson_data.c_str(), bson_data.size()}, nullptr);
×
1048
    }
×
1049
}
×
1050
} // anonymous namespace
1051

1052
RLM_API realm_mongodb_collection_t* realm_mongo_collection_get(realm_user_t* user, const char* service,
1053
                                                               const char* database, const char* collection)
1054
{
×
1055
    REALM_ASSERT(user);
×
1056
    REALM_ASSERT(service);
×
1057
    REALM_ASSERT(database);
×
1058
    REALM_ASSERT(collection);
×
1059
    return with_app_user(user, [&](auto& user) {
×
1060
        auto col = user->mongo_client(service).db(database).collection(collection);
×
1061
        return new realm_mongodb_collection_t(col);
×
1062
    });
×
1063
}
×
1064

1065
RLM_API bool realm_mongo_collection_find(realm_mongodb_collection_t* collection, realm_string_t filter_ejson,
1066
                                         const realm_mongodb_find_options_t* options, realm_userdata_t data,
1067
                                         realm_free_userdata_func_t delete_data, realm_mongodb_callback_t callback)
1068
{
×
1069
    REALM_ASSERT(collection);
×
1070
    REALM_ASSERT(options);
×
1071
    return wrap_err([&] {
×
1072
        collection->find_bson(convert_to_bson<bson::BsonDocument>(filter_ejson),
×
1073
                              to_mongodb_collection_find_options(options),
×
1074
                              [=](util::Optional<bson::Bson> bson, util::Optional<AppError> app_error) {
×
1075
                                  handle_mongodb_collection_result(bson, app_error, {data, delete_data}, callback);
×
1076
                              });
×
1077
        return true;
×
1078
    });
×
1079
}
×
1080

1081
RLM_API bool realm_mongo_collection_find_one(realm_mongodb_collection_t* collection, realm_string_t filter_ejson,
1082
                                             const realm_mongodb_find_options_t* options, realm_userdata_t data,
1083
                                             realm_free_userdata_func_t delete_data,
1084
                                             realm_mongodb_callback_t callback)
1085
{
×
1086
    REALM_ASSERT(collection);
×
1087
    REALM_ASSERT(options);
×
1088
    return wrap_err([&] {
×
1089
        collection->find_one_bson(
×
1090
            convert_to_bson<bson::BsonDocument>(filter_ejson), to_mongodb_collection_find_options(options),
×
1091
            [=](util::Optional<bson::Bson> bson, util::Optional<AppError> app_error) {
×
1092
                handle_mongodb_collection_result(bson, app_error, {data, delete_data}, callback);
×
1093
            });
×
1094
        return true;
×
1095
    });
×
1096
}
×
1097

1098
RLM_API bool realm_mongo_collection_aggregate(realm_mongodb_collection_t* collection, realm_string_t filter_ejson,
1099
                                              realm_userdata_t data, realm_free_userdata_func_t delete_data,
1100
                                              realm_mongodb_callback_t callback)
1101
{
×
1102
    REALM_ASSERT(collection);
×
1103
    return wrap_err([&] {
×
1104
        collection->aggregate_bson(
×
1105
            convert_to_bson<bson::BsonArray>(filter_ejson),
×
1106
            [=](util::Optional<bson::Bson> bson, util::Optional<AppError> app_error) {
×
1107
                handle_mongodb_collection_result(bson, app_error, {data, delete_data}, callback);
×
1108
            });
×
1109
        return true;
×
1110
    });
×
1111
}
×
1112

1113
RLM_API bool realm_mongo_collection_count(realm_mongodb_collection_t* collection, realm_string_t filter_ejson,
1114
                                          int64_t limit, realm_userdata_t data,
1115
                                          realm_free_userdata_func_t delete_data, realm_mongodb_callback_t callback)
1116
{
×
1117
    REALM_ASSERT(collection);
×
1118
    return wrap_err([&] {
×
1119
        collection->count_bson(convert_to_bson<bson::BsonDocument>(filter_ejson), limit,
×
1120
                               [=](util::Optional<bson::Bson> bson, util::Optional<app::AppError> app_error) {
×
1121
                                   handle_mongodb_collection_result(bson, app_error, {data, delete_data}, callback);
×
1122
                               });
×
1123
        return true;
×
1124
    });
×
1125
}
×
1126

1127
RLM_API bool realm_mongo_collection_insert_one(realm_mongodb_collection_t* collection, realm_string_t filter_ejson,
1128
                                               realm_userdata_t data, realm_free_userdata_func_t delete_data,
1129
                                               realm_mongodb_callback_t callback)
1130
{
×
1131
    REALM_ASSERT(collection);
×
1132
    return wrap_err([&] {
×
1133
        collection->insert_one_bson(
×
1134
            convert_to_bson<bson::BsonDocument>(filter_ejson),
×
1135
            [=](util::Optional<bson::Bson> bson, util::Optional<AppError> app_error) {
×
1136
                handle_mongodb_collection_result(bson, app_error, {data, delete_data}, callback);
×
1137
            });
×
1138
        return true;
×
1139
    });
×
1140
}
×
1141

1142
RLM_API bool realm_mongo_collection_insert_many(realm_mongodb_collection_t* collection, realm_string_t filter_ejson,
1143
                                                realm_userdata_t data, realm_free_userdata_func_t delete_data,
1144
                                                realm_mongodb_callback_t callback)
1145
{
×
1146
    REALM_ASSERT(collection);
×
1147
    return wrap_err([&] {
×
1148
        collection->insert_many_bson(
×
1149
            convert_to_bson<bson::BsonArray>(filter_ejson),
×
1150
            [=](util::Optional<bson::Bson> bson, util::Optional<AppError> app_error) {
×
1151
                handle_mongodb_collection_result(bson, app_error, {data, delete_data}, callback);
×
1152
            });
×
1153
        return true;
×
1154
    });
×
1155
}
×
1156

1157
RLM_API bool realm_mongo_collection_delete_one(realm_mongodb_collection_t* collection, realm_string_t filter_ejson,
1158
                                               realm_userdata_t data, realm_free_userdata_func_t delete_data,
1159
                                               realm_mongodb_callback_t callback)
1160
{
×
1161
    REALM_ASSERT(collection);
×
1162
    return wrap_err([&] {
×
1163
        collection->delete_one_bson(
×
1164
            convert_to_bson<bson::BsonDocument>(filter_ejson),
×
1165
            [=](util::Optional<bson::Bson> bson, util::Optional<AppError> app_error) {
×
1166
                handle_mongodb_collection_result(bson, app_error, {data, delete_data}, callback);
×
1167
            });
×
1168
        return true;
×
1169
    });
×
1170
}
×
1171

1172
RLM_API bool realm_mongo_collection_delete_many(realm_mongodb_collection_t* collection, realm_string_t filter_ejson,
1173
                                                realm_userdata_t data, realm_free_userdata_func_t delete_data,
1174
                                                realm_mongodb_callback_t callback)
1175
{
×
1176
    REALM_ASSERT(collection);
×
1177
    return wrap_err([&] {
×
1178
        collection->delete_many_bson(
×
1179
            convert_to_bson<bson::BsonDocument>(filter_ejson),
×
1180
            [=](util::Optional<bson::Bson> bson, util::Optional<AppError> app_error) {
×
1181
                handle_mongodb_collection_result(bson, app_error, {data, delete_data}, callback);
×
1182
            });
×
1183
        return true;
×
1184
    });
×
1185
}
×
1186

1187
RLM_API bool realm_mongo_collection_update_one(realm_mongodb_collection_t* collection, realm_string_t filter_ejson,
1188
                                               realm_string_t update_ejson, bool upsert, realm_userdata_t data,
1189
                                               realm_free_userdata_func_t delete_data,
1190
                                               realm_mongodb_callback_t callback)
1191
{
×
1192
    REALM_ASSERT(collection);
×
1193
    return wrap_err([&] {
×
1194
        const auto& bson_filter = convert_to_bson<bson::BsonDocument>(filter_ejson);
×
1195
        const auto& bson_update = convert_to_bson<bson::BsonDocument>(update_ejson);
×
1196
        collection->update_one_bson(
×
1197
            bson_filter, bson_update, upsert,
×
1198
            [=](util::Optional<bson::Bson> bson, util::Optional<AppError> app_error) {
×
1199
                handle_mongodb_collection_result(bson, app_error, {data, delete_data}, callback);
×
1200
            });
×
1201
        return true;
×
1202
    });
×
1203
}
×
1204

1205
RLM_API bool realm_mongo_collection_update_many(realm_mongodb_collection_t* collection, realm_string_t filter_ejson,
1206
                                                realm_string_t update_ejson, bool upsert, realm_userdata_t data,
1207
                                                realm_free_userdata_func_t delete_data,
1208
                                                realm_mongodb_callback_t callback)
1209
{
×
1210
    REALM_ASSERT(collection);
×
1211
    return wrap_err([&] {
×
1212
        const auto& bson_filter = convert_to_bson<bson::BsonDocument>(filter_ejson);
×
1213
        const auto& bson_update = convert_to_bson<bson::BsonDocument>(update_ejson);
×
1214
        collection->update_many_bson(
×
1215
            bson_filter, bson_update, upsert,
×
1216
            [=](util::Optional<bson::Bson> bson, util::Optional<AppError> app_error) {
×
1217
                handle_mongodb_collection_result(bson, app_error, {data, delete_data}, callback);
×
1218
            });
×
1219
        return true;
×
1220
    });
×
1221
}
×
1222

1223
RLM_API bool realm_mongo_collection_find_one_and_update(realm_mongodb_collection_t* collection,
1224
                                                        realm_string_t filter_ejson, realm_string_t update_ejson,
1225
                                                        const realm_mongodb_find_one_and_modify_options_t* options,
1226
                                                        realm_userdata_t data, realm_free_userdata_func_t delete_data,
1227
                                                        realm_mongodb_callback_t callback)
1228
{
×
1229
    REALM_ASSERT(collection);
×
1230
    return wrap_err([&] {
×
1231
        const auto& bson_filter = convert_to_bson<bson::BsonDocument>(filter_ejson);
×
1232
        const auto& bson_update = convert_to_bson<bson::BsonDocument>(update_ejson);
×
1233
        collection->find_one_and_update_bson(
×
1234
            bson_filter, bson_update, to_mongodb_collection_find_one_and_modify_options(options),
×
1235
            [=](util::Optional<bson::Bson> bson, util::Optional<AppError> app_error) {
×
1236
                handle_mongodb_collection_result(bson, app_error, {data, delete_data}, callback);
×
1237
            });
×
1238
        return true;
×
1239
    });
×
1240
}
×
1241

1242
RLM_API bool realm_mongo_collection_find_one_and_replace(
1243
    realm_mongodb_collection_t* collection, realm_string_t filter_ejson, realm_string_t replacement_ejson,
1244
    const realm_mongodb_find_one_and_modify_options_t* options, realm_userdata_t data,
1245
    realm_free_userdata_func_t delete_data, realm_mongodb_callback_t callback)
1246
{
×
1247
    REALM_ASSERT(collection);
×
1248
    return wrap_err([&] {
×
1249
        const auto& filter_bson = convert_to_bson<bson::BsonDocument>(filter_ejson);
×
1250
        const auto& replacement_bson = convert_to_bson<bson::BsonDocument>(replacement_ejson);
×
1251
        collection->find_one_and_replace_bson(
×
1252
            filter_bson, replacement_bson, to_mongodb_collection_find_one_and_modify_options(options),
×
1253
            [=](util::Optional<bson::Bson> bson, util::Optional<AppError> app_error) {
×
1254
                handle_mongodb_collection_result(bson, app_error, {data, delete_data}, callback);
×
1255
            });
×
1256
        return true;
×
1257
    });
×
1258
}
×
1259

1260
RLM_API bool realm_mongo_collection_find_one_and_delete(realm_mongodb_collection_t* collection,
1261
                                                        realm_string_t filter_ejson,
1262
                                                        const realm_mongodb_find_one_and_modify_options_t* options,
1263
                                                        realm_userdata_t data, realm_free_userdata_func_t delete_data,
1264
                                                        realm_mongodb_callback_t callback)
1265
{
×
1266
    REALM_ASSERT(collection);
×
1267
    return wrap_err([&] {
×
1268
        const auto& bson_filter = convert_to_bson<bson::BsonDocument>(filter_ejson);
×
1269
        collection->find_one_and_delete_bson(
×
1270
            bson_filter, to_mongodb_collection_find_one_and_modify_options(options),
×
1271
            [=](util::Optional<bson::Bson> bson, util::Optional<AppError> app_error) {
×
1272
                handle_mongodb_collection_result(bson, app_error, {data, delete_data}, callback);
×
1273
            });
×
1274
        return true;
×
1275
    });
×
1276
}
×
1277

1278
#endif // REALM_APP_SERVICES
1279

1280
} // namespace realm::c_api
1281

1282
#if REALM_APP_SERVICES
1283
// definitions outside the c_api namespace
1284
realm_app_user_subscription_token::~realm_app_user_subscription_token()
1285
{
2✔
1286
    user->unsubscribe(token);
2✔
1287
}
2✔
1288
#endif
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