From aed85dc3a7166d79a4d328a0596c6417bf5c827e Mon Sep 17 00:00:00 2001 From: Dachary Date: Tue, 1 Aug 2023 12:11:32 -0400 Subject: [PATCH 1/7] (DOCSP-31728): Swift: Add the first two Swift SDK curated examples (#2929) ## Pull Request Info ### Jira - https://jira.mongodb.org/browse/DOCSP-31728 ### Staged Changes - [Swift SDK landing page](https://docs-mongodbcom-staging.corp.mongodb.com/realm/docsworker-xlarge/DOCSP-31728/sdk/swift/) ### Reminder Checklist If your PR modifies the docs, you might need to also update some corresponding pages. Check if completed or N/A. - [x] Create Jira ticket for corresponding docs-app-services update(s), if any - [x] Checked/updated Admin API - [x] Checked/updated CLI reference ### Review Guidelines [REVIEWING.md](https://github.com/mongodb/docs-realm/blob/master/REVIEWING.md) --- .../General_CLOUD_Mobility10x.png | Bin 0 -> 20695 bytes .../Technical_ATLAS_AsymmetricSync10x.png | Bin 0 -> 21011 bytes source/sdk/swift.txt | 26 ++++++++++++++++++ 3 files changed, 26 insertions(+) create mode 100644 source/images/icons/branding_2023/General_CLOUD_Mobility10x.png create mode 100644 source/images/icons/branding_2023/Technical_ATLAS_AsymmetricSync10x.png diff --git a/source/images/icons/branding_2023/General_CLOUD_Mobility10x.png b/source/images/icons/branding_2023/General_CLOUD_Mobility10x.png new file mode 100644 index 0000000000000000000000000000000000000000..166f07c6e6ee790291bbc15d955341921ed5ed32 GIT binary patch literal 20695 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 literal 0 HcmV?d00001 diff --git a/source/images/icons/branding_2023/Technical_ATLAS_AsymmetricSync10x.png b/source/images/icons/branding_2023/Technical_ATLAS_AsymmetricSync10x.png new file mode 100644 index 0000000000000000000000000000000000000000..58280dd057f852867e80ff7a40f7040e0ea78773 GIT binary patch literal 21011 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 literal 0 HcmV?d00001 diff --git a/source/sdk/swift.txt b/source/sdk/swift.txt index dd5da6dc46e..19ae85476fe 100644 --- a/source/sdk/swift.txt +++ b/source/sdk/swift.txt @@ -251,3 +251,29 @@ Recommended Reading :icon-alt: Tutorial Icon Get started with Realm for SwiftUI. + +Example Projects +---------------- + +.. card-group:: + :columns: 3 + :style: extra-compact + + .. card:: + :headline: Analytics/Telemetrics Data + :cta: Example app + :url: https://github.com/realm/realm-swift-samples/blob/main/AnalyticsTelemetricsData/README.md + :icon: /images/icons/branding_2023/Technical_ATLAS_AsymmetricSync10x.png + :icon-alt: Asymmetric Sync icon + + Take sensor readings, push data to Atlas, and display the results in + Atlas Charts or a time series collection. + + .. card:: + :headline: Connection State Change & Error Handling + :cta: Example app + :url: https://github.com/realm/realm-swift-samples/blob/main/SyncConnectionStateErrorReset/README.md + :icon: /images/icons/branding_2023/General_CLOUD_Mobility10x.png + :icon-alt: Cloud Mobile Transfer Icon + + Learn best practices around handling Sync errors and client resets. From 6f8d782a2bbc3f976c97505af16880d5108b6b4a Mon Sep 17 00:00:00 2001 From: Dachary Date: Tue, 1 Aug 2023 16:37:33 -0400 Subject: [PATCH 2/7] (DOCSP-31531): NET SDK Migrate PBS to FS updates (#2916) ## Pull Request Info ### Jira - https://jira.mongodb.org/browse/DOCSP-31531 ### Staged Changes - [Sync Data](https://docs-mongodbcom-staging.corp.mongodb.com/realm/docsworker-xlarge/DOCSP-31531/sdk/dotnet/sync/): Remove PBS info - [Configure & Open a Synced Realm](https://docs-mongodbcom-staging.corp.mongodb.com/realm/docsworker-xlarge/DOCSP-31531/sdk/dotnet/sync/configure-and-open-a-synced-realm/): Remove PBS info to new PBS page. Add new Flexible Sync code examples for opening a realm. The other examples on this page should also be updated to show FS instead of PBS, but aren't necessarily a blocker for this PR. - [Partition-Based Sync](https://docs-mongodbcom-staging.corp.mongodb.com/realm/docsworker-xlarge/DOCSP-31531/sdk/dotnet/sync/partition-based-sync/): New page with moved PBS content and new migration info ### Reminder Checklist If your PR modifies the docs, you might need to also update some corresponding pages. Check if completed or N/A. - [x] Create Jira ticket for corresponding docs-app-services update(s), if any - [x] Checked/updated Admin API - [x] Checked/updated CLI reference ### Review Guidelines [REVIEWING.md](https://github.com/mongodb/docs-realm/blob/master/REVIEWING.md) --- .../dotnet/Examples/ClientResetExamples.cs | 20 ++- .../dotnet/Examples/FlexibleSyncExamples.cs | 88 ++++++++++ .../dotnet/Examples/OpenARealmExamples.cs | 4 +- ...es.snippet.open-a-flexible-synced-realm.cs | 2 - ...cExamples.snippet.open-fs-realm-offline.cs | 22 +++ ...xibleSyncExamples.snippet.open-fs-realm.cs | 21 +++ ...snippet.open-synced-realm-synchronously.cs | 2 +- ...RealmExamples.snippet.open-synced-realm.cs | 2 +- source/sdk/dotnet/sync.txt | 42 ++--- .../configure-and-open-a-synced-realm.txt | 50 ++---- source/sdk/dotnet/sync/flexible-sync.txt | 3 + .../sdk/dotnet/sync/partition-based-sync.txt | 165 ++++++++++++++++++ source/sdk/dotnet/sync/sync-progress.txt | 2 +- 13 files changed, 341 insertions(+), 82 deletions(-) delete mode 100644 source/examples/generated/dotnet-flexible-sync/FlexibleSyncExamples.snippet.open-a-flexible-synced-realm.cs create mode 100644 source/examples/generated/dotnet-flexible-sync/FlexibleSyncExamples.snippet.open-fs-realm-offline.cs create mode 100644 source/examples/generated/dotnet-flexible-sync/FlexibleSyncExamples.snippet.open-fs-realm.cs create mode 100644 source/sdk/dotnet/sync/partition-based-sync.txt diff --git a/examples/dotnet/Examples/ClientResetExamples.cs b/examples/dotnet/Examples/ClientResetExamples.cs index c7fd1d43db7..ab5e4a9c333 100644 --- a/examples/dotnet/Examples/ClientResetExamples.cs +++ b/examples/dotnet/Examples/ClientResetExamples.cs @@ -33,7 +33,7 @@ public async Task TestDiscardUnsyncedChangesHandler() { // :remove-start: app = App.Create(myRealmAppId); - user = await app.LogInAsync(Credentials.Anonymous()); + user = await app.LogInAsync(Credentials.Anonymous(false)); // :remove-end: var config = new FlexibleSyncConfiguration(user); config.ClientResetHandler = new DiscardUnsyncedChangesHandler() @@ -55,12 +55,17 @@ public async Task TestDiscardUnsyncedChangesHandler() // Automatic reset failed; handle the reset manually here } }; - - //:remove-start: - config.Schema = new[] { typeof(Examples.Models.Plant) }; - //:remove-end: - var realm = await Realm.GetInstanceAsync(config); + try + { + var realm = await Realm.GetInstanceAsync(config); + } + catch (Exception ex) + { + Console.WriteLine($@"Error creating or opening the + realm file. {ex.Message}"); + } // :snippet-end: + await user.LogOutAsync(); } public async Task TestManualClientReset() @@ -85,9 +90,6 @@ public async Task TestManualClientReset() var fsConfig = new FlexibleSyncConfiguration(fsUser); fsConfig.ClientResetHandler = new ManualRecoveryHandler(HandleClientResetError); - //:remove-start: - fsConfig.Schema = new[] { typeof(User) }; - //:remove-end: var fsrealm = await Realm.GetInstanceAsync(fsConfig); } diff --git a/examples/dotnet/Examples/FlexibleSyncExamples.cs b/examples/dotnet/Examples/FlexibleSyncExamples.cs index ab8cd0a43eb..209faf7dd2e 100644 --- a/examples/dotnet/Examples/FlexibleSyncExamples.cs +++ b/examples/dotnet/Examples/FlexibleSyncExamples.cs @@ -87,7 +87,95 @@ public async Task TestUseFlexibleSync() // remove all subscriptions, including named subscriptions realm.Subscriptions.RemoveAll(true); }); + } + + [Test] + public async Task TestOpenFSRealm() + { + // :snippet-start: open-fs-realm + // :replace-start: { + // "terms": { + // "Config.FSAppId": "\"myRealmAppId\"", + // "Credentials.Anonymous(false)": "Credentials.Anonymous()"} + // } + var app = App.Create(Config.FSAppId); + var user = await app.LogInAsync(Credentials.Anonymous(false)); + Realm realm; + + var config = new FlexibleSyncConfiguration(user) + { + PopulateInitialSubscriptions = (realm) => + { + var allTasks = realm.All(); + realm.Subscriptions.Add(allTasks, new SubscriptionOptions { Name = "allTasks" }); + } + }; + try + { + realm = await Realm.GetInstanceAsync(config); + // :remove-start: + var session = realm.SyncSession; + Assert.NotNull(session); + // :remove-end: + } + catch (Exception ex) + { + Console.WriteLine($@"Error creating or opening the + realm file. {ex.Message}"); + } + // :replace-end: + // :snippet-end: + await user.LogOutAsync(); + } + [Test] + public async Task TestOpenFSRealmOffline() + { + // :snippet-start: open-fs-realm-offline + // :replace-start: { + // "terms": { + // "Config.FSAppId": "\"myRealmAppId\"", + // "Credentials.Anonymous(false)": "Credentials.Anonymous()" + // } + // } + var app = App.Create(Config.FSAppId); + // :remove-start: + // Another app.CurrentUser was carrying over into this test + // causing issues with opening the FS realm. This resolves the + // test failure but there should probably be stronger cleanup + // between tests to negate the need for this. + if (app.CurrentUser != null) { + await app.RemoveUserAsync(app.CurrentUser); + await app.LogInAsync(Credentials.Anonymous(false)); + }; + // :remove-end: + Realms.Sync.User user; + FlexibleSyncConfiguration config; + Realm realm; + + if (app.CurrentUser == null) + { + // App must be online for user to authenticate + user = await app.LogInAsync(Credentials.Anonymous(false)); + config = new FlexibleSyncConfiguration(user); + realm = Realm.GetInstance(config); + // Go on to add or update subscriptions and use the realm + // :remove-start: + var session = realm.SyncSession; + Assert.NotNull(session); + // :remove-end: + } + else + { + // This works whether online or offline + // It requires a user to have been previously authenticated + user = app.CurrentUser; + config = new FlexibleSyncConfiguration(user); + realm = Realm.GetInstance(config); + // Go on to add or update subscriptions and use the realm + } + // :replace-end: + // :snippet-end: } [Test] diff --git a/examples/dotnet/Examples/OpenARealmExamples.cs b/examples/dotnet/Examples/OpenARealmExamples.cs index cf4168828af..9233a969e50 100644 --- a/examples/dotnet/Examples/OpenARealmExamples.cs +++ b/examples/dotnet/Examples/OpenARealmExamples.cs @@ -44,7 +44,7 @@ public async Task Setup() //realm = await Realm.GetInstanceAsync(config); // :uncomment-end: } - catch (RealmFileAccessErrorException ex) + catch (Exception ex) { Console.WriteLine($@"Error creating or opening the realm file. {ex.Message}"); @@ -58,7 +58,7 @@ public async Task Setup() // :snippet-start: open-synced-realm-synchronously // :uncomment-start: - // var synchronousRealm = await Realm.GetInstanceAsync(config); + // var synchronousRealm = Realm.GetInstance(config); // :uncomment-end: // :snippet-end: diff --git a/source/examples/generated/dotnet-flexible-sync/FlexibleSyncExamples.snippet.open-a-flexible-synced-realm.cs b/source/examples/generated/dotnet-flexible-sync/FlexibleSyncExamples.snippet.open-a-flexible-synced-realm.cs deleted file mode 100644 index 61692915070..00000000000 --- a/source/examples/generated/dotnet-flexible-sync/FlexibleSyncExamples.snippet.open-a-flexible-synced-realm.cs +++ /dev/null @@ -1,2 +0,0 @@ -var config = new FlexibleSyncConfiguration(app.CurrentUser); -var realm = Realm.GetInstance(config); diff --git a/source/examples/generated/dotnet-flexible-sync/FlexibleSyncExamples.snippet.open-fs-realm-offline.cs b/source/examples/generated/dotnet-flexible-sync/FlexibleSyncExamples.snippet.open-fs-realm-offline.cs new file mode 100644 index 00000000000..a2685bd622c --- /dev/null +++ b/source/examples/generated/dotnet-flexible-sync/FlexibleSyncExamples.snippet.open-fs-realm-offline.cs @@ -0,0 +1,22 @@ +var app = App.Create("myRealmAppId"); +Realms.Sync.User user; +FlexibleSyncConfiguration config; +Realm realm; + +if (app.CurrentUser == null) +{ + // App must be online for user to authenticate + user = await app.LogInAsync(Credentials.Anonymous()); + config = new FlexibleSyncConfiguration(user); + realm = Realm.GetInstance(config); + // Go on to add or update subscriptions and use the realm +} +else +{ + // This works whether online or offline + // It requires a user to have been previously authenticated + user = app.CurrentUser; + config = new FlexibleSyncConfiguration(user); + realm = Realm.GetInstance(config); + // Go on to add or update subscriptions and use the realm +} diff --git a/source/examples/generated/dotnet-flexible-sync/FlexibleSyncExamples.snippet.open-fs-realm.cs b/source/examples/generated/dotnet-flexible-sync/FlexibleSyncExamples.snippet.open-fs-realm.cs new file mode 100644 index 00000000000..437d06eb7aa --- /dev/null +++ b/source/examples/generated/dotnet-flexible-sync/FlexibleSyncExamples.snippet.open-fs-realm.cs @@ -0,0 +1,21 @@ +var app = App.Create("myRealmAppId"); +var user = await app.LogInAsync(Credentials.Anonymous()); +Realm realm; + +var config = new FlexibleSyncConfiguration(user) +{ + PopulateInitialSubscriptions = (realm) => + { + var allTasks = realm.All(); + realm.Subscriptions.Add(allTasks, new SubscriptionOptions { Name = "allTasks" }); + } +}; +try +{ + realm = await Realm.GetInstanceAsync(config); +} +catch (Exception ex) +{ + Console.WriteLine($@"Error creating or opening the + realm file. {ex.Message}"); +} diff --git a/source/examples/generated/dotnet/OpenARealmExamples.snippet.open-synced-realm-synchronously.cs b/source/examples/generated/dotnet/OpenARealmExamples.snippet.open-synced-realm-synchronously.cs index 8d4579f3d86..30d0e27f7f6 100644 --- a/source/examples/generated/dotnet/OpenARealmExamples.snippet.open-synced-realm-synchronously.cs +++ b/source/examples/generated/dotnet/OpenARealmExamples.snippet.open-synced-realm-synchronously.cs @@ -1 +1 @@ -var synchronousRealm = await Realm.GetInstanceAsync(config); +var synchronousRealm = Realm.GetInstance(config); diff --git a/source/examples/generated/dotnet/OpenARealmExamples.snippet.open-synced-realm.cs b/source/examples/generated/dotnet/OpenARealmExamples.snippet.open-synced-realm.cs index 2462e462de2..934196e19e0 100644 --- a/source/examples/generated/dotnet/OpenARealmExamples.snippet.open-synced-realm.cs +++ b/source/examples/generated/dotnet/OpenARealmExamples.snippet.open-synced-realm.cs @@ -5,7 +5,7 @@ { realm = await Realm.GetInstanceAsync(config); } -catch (RealmFileAccessErrorException ex) +catch (Exception ex) { Console.WriteLine($@"Error creating or opening the realm file. {ex.Message}"); diff --git a/source/sdk/dotnet/sync.txt b/source/sdk/dotnet/sync.txt index b0803d67440..2a6a8798b4f 100644 --- a/source/sdk/dotnet/sync.txt +++ b/source/sdk/dotnet/sync.txt @@ -18,43 +18,13 @@ Sync Data Between Devices - .NET SDK Check Upload & Download Progress Convert Between Non-Synced Realms and Synced Realms Stream Data to Atlas - -Overview --------- + Partition-Based Sync Atlas Device Sync automatically synchronizes data between client applications and an :ref:`Atlas App Services backend `. When a client device is online, Sync asynchronously synchronizes data in a background thread between the device and your backend App. -When you use Sync in your client application, your implementation must match -the Sync Mode you select in your backend App configuration. The Sync Mode -options are: - -- Partition-Based Sync -- Flexible Sync - -You can only use one Sync Mode for your application. You cannot mix -Partition-Based Sync and Flexible Sync within the same App. - -.. seealso:: - - :ref:`enable-realm-sync` - -.. _dotnet-partition-based-sync-fundamentals: - -Partition-Based Sync --------------------- - -When you select :ref:`Partition-Based Sync ` for your -backend App configuration, your client implementation must include a -partition value. This is the value of the :ref:`partition key -` field you select when you configure Partition-Based Sync. - -The partition value determines which data the client application can access. - -You pass in the partition value when you open a synced realm. - .. _dotnet-flexible-sync-fundamentals: Flexible Sync @@ -84,6 +54,14 @@ To use Flexible Sync in your client application, open a synced realm with a Flexible Sync configuration. Then, manage subscriptions to determine which documents to sync. +.. tip:: + + Device Sync supports two Sync Modes: Flexible Sync, and the older + Partition-Based Sync. If your App Services backend uses Partition-Based + Sync, refer to :ref:`dotnet-partition-based-sync`. + + We recommend using Flexible Sync. + Group Updates for Improved Performance ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -98,3 +76,5 @@ In this scenario, you can maximize sync performance by using :ref:`Data Ingest ` to stream data from the client application to a Flexible Sync-enabled Atlas App Services App. + + diff --git a/source/sdk/dotnet/sync/configure-and-open-a-synced-realm.txt b/source/sdk/dotnet/sync/configure-and-open-a-synced-realm.txt index 170e6947e0b..427fd93aa0f 100644 --- a/source/sdk/dotnet/sync/configure-and-open-a-synced-realm.txt +++ b/source/sdk/dotnet/sync/configure-and-open-a-synced-realm.txt @@ -101,45 +101,32 @@ With cached credentials, you can: - Open a synced realm after downloading changes from your App. This requires the user to have an active internet connection. -.. _dotnet-flexible-sync-open-realm: - -Open a Synced Realm with a Flexible Sync Configuration -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -When you use Flexible Sync, pass the current user to a -:dotnet-sdk:`FlexibleSyncConfiguration ` -object to open a synced realm. - -.. literalinclude:: /examples/generated/dotnet-flexible-sync/FlexibleSyncExamples.snippet.open-a-flexible-synced-realm.cs - :language: csharp - -.. important:: Flexible Sync Requires a Subscription - - You can't use a Flexible Sync realm until you add at least one subscription. - To learn how to add subscriptions, see: :ref:``. - .. _dotnet-open-a-synced-realm: -.. _dotnet-partition-sync-open-realm: +.. _dotnet-flexible-sync-open-realm: -Open a Partition-Based Sync Realm While Online -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Open a Synced Realm While Online +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The steps for opening a synced realm while online are: 1. Your app code walks the user through :ref:`authenticating `. #. Create a - :dotnet-sdk:`PartitionSyncConfiguration ` - object that includes the :ref:`partition name ` and - the :dotnet-sdk:`User ` object. + :dotnet-sdk:`FlexibleSyncConfiguration ` + object that includes :dotnet-sdk:`User ` + object. #. Open a synced realm by calling the :dotnet-sdk:`GetInstanceAsync() ` - method, passing in the ``PartitionSyncConfiguration`` object. + method. + +#. If your FlexibleSyncConfiguration did not contain + :ref:`initial subscriptions `, + :ref:`add a subscription `. The following code demonstrates these steps: -.. literalinclude:: /examples/generated/dotnet/OpenARealmExamples.snippet.open-synced-realm.cs +.. literalinclude:: /examples/generated/dotnet-flexible-sync/FlexibleSyncExamples.snippet.open-fs-realm.cs :language: csharp In the above example, the code shows how to open the realm *asynchronously* @@ -151,15 +138,8 @@ method: .. literalinclude:: /examples/generated/dotnet/OpenARealmExamples.snippet.open-synced-realm-synchronously.cs :language: csharp -.. seealso:: - - :ref:`Partitions ` - - :ref:`Partition Strategies ` - - -Open a Partition-Based Sync Realm While Offline -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Open a Synced Realm While Offline +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Once a user authenticates, the ``User`` object persists on the device until the user logs off. This allows your app to @@ -171,7 +151,7 @@ The following code shows how to check if there is an existing ``User`` object. If none is found, it uses the process outlined about to obtain a user. If the device already has a ``user``, it opens the synced realm with that user: -.. literalinclude:: /examples/generated/dotnet/OpenARealmExamples.snippet.check-if-offline.cs +.. literalinclude:: /examples/generated/dotnet-flexible-sync/FlexibleSyncExamples.snippet.open-fs-realm-offline.cs :language: csharp Configuring Timeouts with AppConfiguration diff --git a/source/sdk/dotnet/sync/flexible-sync.txt b/source/sdk/dotnet/sync/flexible-sync.txt index a3d5903eb7b..b820645dca0 100644 --- a/source/sdk/dotnet/sync/flexible-sync.txt +++ b/source/sdk/dotnet/sync/flexible-sync.txt @@ -106,6 +106,8 @@ You must have at least one subscription before you can read from or write to the realm. You can create one or more initial subscriptions when you configure Flexible Sync, or you can add subscriptions after initialization. +.. _dotnet-initial-subscriptions: + Bootstrap the Realm with Initial Subscriptions `````````````````````````````````````````````` @@ -120,6 +122,7 @@ queries you want to use to bootstrap the realm, as shown in the following exampl .. literalinclude:: /examples/generated/dotnet/FlexibleSyncExamples.snippet.bootstrap-a-subscription.cs :language: csharp +.. _dotnet-add-subscription-to-set: Add a Subscription `````````````````` diff --git a/source/sdk/dotnet/sync/partition-based-sync.txt b/source/sdk/dotnet/sync/partition-based-sync.txt new file mode 100644 index 00000000000..861961b5ca2 --- /dev/null +++ b/source/sdk/dotnet/sync/partition-based-sync.txt @@ -0,0 +1,165 @@ +.. _dotnet-partition-based-sync: + +=============================== +Partition-Based Sync - .NET SDK +=============================== + +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + +Partition-Based Sync is an older mode for using Atlas Device Sync with the +Realm .NET SDK. We recommend using :ref:`Flexible Sync ` +for new apps. The information on this page is for users who are still +using Partition-Based Sync. + +.. tip:: + + Realm .NET SDK v11.1.0 and newer supports the ability to migrate from + Partition-Based Sync to Flexible Sync. For more information, refer to: + :ref:`dotnet-migrate-pbs-to-fs`. We recommend you migrate your older + Partition-Based Sync apps to use Flexible Sync. + +.. _dotnet-partition-based-sync-fundamentals: + +Partition Value +--------------- + +When you select :ref:`Partition-Based Sync ` for your +backend App configuration, your client implementation must include a +partition value. This is the value of the :ref:`partition key +` field you select when you configure Partition-Based Sync. + +The partition value determines which data the client application can access. +You pass in the partition value when you open a synced realm. + +.. _dotnet-partition-sync-open-realm: + +Open a Partition-Based Sync Realm While Online +---------------------------------------------- + +The steps for opening a synced realm while online are: + +1. Your app code walks the user through :ref:`authenticating `. + +#. Create a + :dotnet-sdk:`PartitionSyncConfiguration ` + object that includes the :ref:`partition value ` and + the :dotnet-sdk:`User ` object. + +#. Open a synced realm by calling the + :dotnet-sdk:`GetInstanceAsync() ` + method, passing in the ``PartitionSyncConfiguration`` object. + +The following code demonstrates these steps: + +.. literalinclude:: /examples/generated/dotnet/OpenARealmExamples.snippet.open-synced-realm.cs + :language: csharp + +In the above example, the code shows how to open the realm *asynchronously* +by calling ``GetInstanceAsync()``. You can also open a realm *synchronously* +by calling the +:dotnet-sdk:`GetInstance() ` +method: + +.. literalinclude:: /examples/generated/dotnet/OpenARealmExamples.snippet.open-synced-realm-synchronously.cs + :language: csharp + +.. seealso:: + + :ref:`Partitions ` + + :ref:`Partition Strategies ` + + +Open a Partition-Based Sync Realm While Offline +----------------------------------------------- + +Once a user authenticates, the ``User`` object persists on the device until the +user logs off. This allows your app to +:ref:`retrieve an existing user ` and open a +synced realm in an offline state. Changes that occur while offline will be +synced by the SDK once the device reconnects to your App. + +The following code shows how to check if there is an existing ``User`` object. +If none is found, it uses the process outlined about to obtain a user. If the +device already has a ``user``, it opens the synced realm with that user: + +.. literalinclude:: /examples/generated/dotnet/OpenARealmExamples.snippet.check-if-offline.cs + :language: csharp + +.. _dotnet-migrate-pbs-to-fs: + +Migrate from Partition-Based Sync to Flexible Sync +-------------------------------------------------- + +You can migrate your App Services Device Sync Mode from Partition-Based Sync +to Flexible Sync. Migrating is an automatic process that does not require +any changes to your application code. Automatic migration requires Realm +.NET SDK version 11.1.0 or newer. + +Migrating enables you to keep your existing App Services users and +authentication configuration. Flexible Sync provides more versatile permissions +configuration options and more granular data synchronization. + +For more information about how to migrate your App Services App from +Partition-Based Sync to Flexible Sync, refer to :ref:`Migrate Device Sync Modes +`. + +.. _dotnet-update-client-code-after-pbs-to-fs-migration: + +Updating Client Code After Migration +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The automatic migration from Partition-Based Sync to Flexible Sync does not +require any changes to your client code. However, to support this +functionality, Realm automatically handles the differences between the two +Sync Modes by: + +- Automatically creating Flexible Sync subscriptions for each object type + where ``partitionKey == partitionValue``. +- Injecting a ``partitionKey`` field into every object if one does not already + exist. This is required for the automatic Flexible Sync subscription. + +If you need to make updates to your client code after migration, consider +updating your client codebase to remove hidden migration functionality. +You might want update your client codebase when: + +- You add a new model or change a model in your client codebase +- You add or change functionality that involves reading or writing Realm objects +- You want to implement more fine-grained control over what data you sync + +Make these changes to convert your Partition-Based Sync client code to use +Flexible Sync: + +- Change your + :dotnet-sdk:`PartitionSyncConfiguration ` + to a + :dotnet-sdk:`FlexibleSyncConfiguration `. +- Add relevant properties to your object models to use in your Flexible Sync + subscriptions. For example, you might add an ``ownerId`` property to enable + a user to sync only their own data. +- Remove automatic Flexible Sync subscriptions and manually create the + relevant subscriptions. + +For examples of Flexible Sync permissions strategies, including examples of +how to model data for these strategies, refer to :ref:`flexible-sync-permissions-guide`. + +Remove and Manually Create Subscriptions +```````````````````````````````````````` + +When you migrate from Partition-Based Sync to Flexible Sync, Realm +automatically creates hidden Flexible Sync subscriptions for your app. The +next time you add or change subscriptions, we recommend that you: + +1. :ref:`Remove the automatically-generated subscriptions `. +2. :ref:`Manually add the relevant subscriptions in your client codebase + `. + +This enables you to see all of your subscription logic together in your +codebase for future iteration and debugging. + +For more information about the automatically-generated Flexible Sync +subscriptions, refer to :ref:`realm-sync-migrate-client`. diff --git a/source/sdk/dotnet/sync/sync-progress.txt b/source/sdk/dotnet/sync/sync-progress.txt index be3bd380c24..0081e2de3b5 100644 --- a/source/sdk/dotnet/sync/sync-progress.txt +++ b/source/sdk/dotnet/sync/sync-progress.txt @@ -125,4 +125,4 @@ object, and checking the Sync status: .. literalinclude:: /examples/generated/dotnet/ProgressNotifications.snippet.connection-state.cs :language: csharp - + \ No newline at end of file From c41cba191446c378e37d0526abeb45ae113d135f Mon Sep 17 00:00:00 2001 From: cbullinger <115956901+cbullinger@users.noreply.github.com> Date: Thu, 3 Aug 2023 08:02:52 -0400 Subject: [PATCH 3/7] DOCSP-30340: Update Relationships - Kotlin SDK page (#2931) ## Pull Request Info Move embedded object content from [Relationships](https://www.mongodb.com/docs/realm/sdk/kotlin/realm-database/schemas/relationships/#define-an-embedded-object) page to respective CRUD pages ### Jira - https://jira.mongodb.org/browse/DOCSP-30340 ### Staged Changes - [Relationships](https://docs-mongodbcom-staging.corp.mongodb.com/realm/docsworker-xlarge/docsp-30340-relationships/sdk/kotlin/realm-database/schemas/relationships/) - [Define an Object Model](https://docs-mongodbcom-staging.corp.mongodb.com/realm/docsworker-xlarge/docsp-30340-relationships/sdk/kotlin/realm-database/schemas/define-realm-object-model/) - [Create](https://docs-mongodbcom-staging.corp.mongodb.com/realm/docsworker-xlarge/docsp-30340-relationships/sdk/kotlin/realm-database/crud/create/) - [Read](https://docs-mongodbcom-staging.corp.mongodb.com/realm/docsworker-xlarge/docsp-30340-relationships/sdk/kotlin/realm-database/crud/read/) - [Update](https://docs-mongodbcom-staging.corp.mongodb.com/realm/docsworker-xlarge/docsp-30340-relationships/sdk/kotlin/realm-database/crud/update/) - [Delete](https://docs-mongodbcom-staging.corp.mongodb.com/realm/docsworker-xlarge/docsp-30340-relationships/sdk/kotlin/realm-database/crud/delete/) ### Reminder Checklist If your PR modifies the docs, you might need to also update some corresponding pages. Check if completed or N/A. - [x] Create Jira ticket for corresponding docs-app-services update(s), if any - [x] Checked/updated Admin API - [x] Checked/updated CLI reference ### Review Guidelines [REVIEWING.md](https://github.com/mongodb/docs-realm/blob/master/REVIEWING.md) --- .../sdk/kotlin/realm-database/crud/create.txt | 17 +++- .../sdk/kotlin/realm-database/crud/delete.txt | 28 ++++++- .../sdk/kotlin/realm-database/crud/read.txt | 29 +++++-- .../sdk/kotlin/realm-database/crud/update.txt | 71 ++++++++++------ .../schemas/define-realm-object-model.txt | 46 ++++++---- .../realm-database/schemas/relationships.txt | 84 +------------------ 6 files changed, 144 insertions(+), 131 deletions(-) diff --git a/source/sdk/kotlin/realm-database/crud/create.txt b/source/sdk/kotlin/realm-database/crud/create.txt index 9c08b981836..bd603154c47 100644 --- a/source/sdk/kotlin/realm-database/crud/create.txt +++ b/source/sdk/kotlin/realm-database/crud/create.txt @@ -45,6 +45,21 @@ To persist a new object to a realm: .. literalinclude:: /examples/generated/kotlin/CRUDTest.snippet.create-a-new-object.kt :language: kotlin +.. tip:: + + You can also upsert into a realm using specific criteria. See + :ref:`Upsert a Realm Object `. + +Create an Embedded Object +------------------------- + +To create an :ref:`embedded object `, assign an instance of the +`EmbeddedRealmObject <{+kotlin-local-prefix+}io.realm.kotlin.types/-embedded-realm-object/index.html>`__ +to a parent object's property: + +.. literalinclude:: /examples/generated/kotlin/DataTypesTest.snippet.create-embedded-object.kt + :language: kotlin + Create an Object with a Dictionary Property ------------------------------------------- @@ -80,7 +95,7 @@ For more information, see :ref:`Asymmetric Objects `. You must create an `AsymmetricRealmObject <{+kotlin-sync-prefix+}io.realm.kotlin.types/-asymmetric-realm-object/index.html>`__ using the `insert() <{+kotlin-sync-prefix+}io.realm.kotlin.mongodb.ext/insert.html>`__ -extension method within a write transaction. +extension method within a write transaction: .. literalinclude:: /examples/generated/kotlin/AsymmetricSyncTest.snippet.create-asymmetric-object.kt :language: kotlin diff --git a/source/sdk/kotlin/realm-database/crud/delete.txt b/source/sdk/kotlin/realm-database/crud/delete.txt index e6712d71d3a..6b6f0202cd8 100644 --- a/source/sdk/kotlin/realm-database/crud/delete.txt +++ b/source/sdk/kotlin/realm-database/crud/delete.txt @@ -19,8 +19,8 @@ To delete a realm file, refer to :ref:`Delete a Realm `. .. _kotlin-delete-an-object: -Delete an Object ----------------- +Delete a Single Object +---------------------- To delete an object from a realm: @@ -110,3 +110,27 @@ entries in a few ways: .. literalinclude:: /examples/generated/kotlin/DeleteTest.snippet.delete-realm-dictionary.kt :language: kotlin + +Delete an Embedded Object +------------------------- + +.. warning:: Realm Uses Cascading Deletes for Embedded Objects + + When you delete a Realm object, Realm automatically deletes any + embedded objects referenced by that object. + If you want the referenced objects to persist after the deletion of the + parent object, use a regular Realm object with a :ref:`to-one relationship + ` instead. + +You can delete an +`EmbeddedRealmObject.parent() <{+kotlin-local-prefix+}io.realm.kotlin.ext/parent.html>`__ +directly or through the parent object. + +To delete only an embedded object, you can fetch and delete a specific +embedded object or clear the parent's reference to the embedded object, +which also deletes the embedded object instance. + +Deleting the parent object automatically deletes all of its embedded objects. + +.. literalinclude:: /examples/generated/kotlin/DataTypesTest.snippet.delete-embedded-object.kt + :language: kotlin diff --git a/source/sdk/kotlin/realm-database/crud/read.txt b/source/sdk/kotlin/realm-database/crud/read.txt index 20d81dac652..fb7f80d915a 100644 --- a/source/sdk/kotlin/realm-database/crud/read.txt +++ b/source/sdk/kotlin/realm-database/crud/read.txt @@ -21,10 +21,13 @@ Read Realm Objects - Kotlin SDK <{+kotlin-local-prefix+}io.realm.kotlin.query/-realm-element-query/as-flow.html>`__ in time-sensitive environments. +Find Objects +------------ + .. _kotlin-find-object-by-primary-key: Find Object by Primary Key --------------------------- +~~~~~~~~~~~~~~~~~~~~~~~~~~ To find an object with a specific primary key value, open a realm and query the primary key field for the desired primary key value @@ -38,7 +41,7 @@ Specify the object type as a type parameter passed to :file:`query()`: .. _kotlin-find-objects-of-a-type: Find Objects of a Type ----------------------- +~~~~~~~~~~~~~~~~~~~~~~ To find all objects of a type, open a realm and pass the type as a type parameter to `realm.query() @@ -47,8 +50,19 @@ and pass the type as a type parameter to `realm.query() .. literalinclude:: /examples/generated/kotlin/CRUDTest.snippet.find-all-objects-of-a-type.kt :language: kotlin +Find an Embedded Object +~~~~~~~~~~~~~~~~~~~~~~~ + +You can query an :ref:`embedded object ` directly or +through the parent object. You can also use the +`EmbeddedRealmObject.parent() <{+kotlin-local-prefix+}io.realm.kotlin.ext/parent.html>`__ +method to access the parent of the embedded object. + +.. literalinclude:: /examples/generated/kotlin/DataTypesTest.snippet.query-embedded-objects.kt + :language: kotlin + Read an Object with a Dictionary Property -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ You can iterate and check the values of a `RealmDictionary <{+kotlin-local-prefix+}io.realm.kotlin.types/-realm-dictionary/index.html>`__ @@ -57,10 +71,13 @@ as you would a Kotlin Map. .. literalinclude:: /examples/generated/kotlin/ReadTest.snippet.read-realm-dictionary.kt :language: kotlin +Filter Data +----------- + .. _kotlin-filter-data: Filter Results --------------- +~~~~~~~~~~~~~~ Filter results to retrieve a specific segment of objects with `realm.query() @@ -79,7 +96,7 @@ For more information on constructing queries, refer to the .. _kotlin-filter-fts: Filter with Full-Text Search ----------------------------- +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ You can use Realm Query Language (RQL) to query on properties that have :ref:`Full-Text Search Indexes ` (FTS) on them. @@ -96,7 +113,7 @@ In the following example, we query the ``Book.genre`` field: :language: kotlin Full-Text Search Tokenizer Details -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +`````````````````````````````````` Full-Text Search (FTS) indexes support: diff --git a/source/sdk/kotlin/realm-database/crud/update.txt b/source/sdk/kotlin/realm-database/crud/update.txt index 94566b53012..041e01d5e62 100644 --- a/source/sdk/kotlin/realm-database/crud/update.txt +++ b/source/sdk/kotlin/realm-database/crud/update.txt @@ -50,10 +50,53 @@ as you would a Kotlin Map. .. literalinclude:: /examples/generated/kotlin/UpdateTest.snippet.update-realm-dictionary.kt :language: kotlin +Update an Embedded Object Property +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To update a property in an +`EmbeddedRealmObject <{+kotlin-local-prefix+}io.realm.kotlin.types/-embedded-realm-object/index.html>`__, +fetch the object and reassign the embedded object properties in a write +transaction: + +.. literalinclude:: /examples/generated/kotlin/DataTypesTest.snippet.update-embedded-object.kt + :language: kotlin + +.. _kotlin-update-collection: + +Update a Collection +------------------- + +To update a collection of objects in a realm: + +1. Query a realm for a collection of objects + with `realm.query() + <{+kotlin-local-prefix+}io.realm.kotlin.query/-realm-query/query.html>`__. + +#. Open a write transaction with `realm.write() + <{+kotlin-local-prefix+}io.realm.kotlin/-realm/write.html>`__ or + `realm.writeBlocking() + <{+kotlin-local-prefix+}io.realm.kotlin/-realm/write-blocking.html>`__. + +#. Update elements of the set of `RealmResults + <{+kotlin-local-prefix+}io.realm.kotlin.query/-realm-results/index.html>`__ + returned by the query. + +.. literalinclude:: /examples/generated/kotlin/CRUDTest.snippet.update-a-collection.kt + :language: kotlin + +Overwrite an Embedded Object +---------------------------- + +To overwrite an embedded object, assign a new embedded object instance to the +property in a write transaction: + +.. literalinclude:: /examples/generated/kotlin/DataTypesTest.snippet.overwrite-embedded-object.kt + :language: kotlin + .. _kotlin-upsert-an-object: -Upsert Objects --------------- +Upsert a Realm Object +--------------------- The **upsert** operation either inserts a new instance of an object or updates an existing object that meets certain criteria. @@ -82,27 +125,3 @@ to use when you upsert an object with an existing primary key: .. literalinclude:: /examples/generated/kotlin/UpdateTest.snippet.upsert-an-object.kt :language: kotlin - -.. _kotlin-update-collection: - -Update a Collection -------------------- - -To update a collection of objects in a realm: - -1. Query a realm for a collection of objects - with `realm.query() - <{+kotlin-local-prefix+}io.realm.kotlin.query/-realm-query/query.html>`__. - -#. Open a write transaction with `realm.write() - <{+kotlin-local-prefix+}io.realm.kotlin/-realm/write.html>`__ or - `realm.writeBlocking() - <{+kotlin-local-prefix+}io.realm.kotlin/-realm/write-blocking.html>`__. - -#. Update elements of the set of `RealmResults - <{+kotlin-local-prefix+}io.realm.kotlin.query/-realm-results/index.html>`__ - returned by the query. - -.. literalinclude:: /examples/generated/kotlin/CRUDTest.snippet.update-a-collection.kt - :language: kotlin - \ No newline at end of file diff --git a/source/sdk/kotlin/realm-database/schemas/define-realm-object-model.txt b/source/sdk/kotlin/realm-database/schemas/define-realm-object-model.txt index 6532e31d494..75d02c6319c 100644 --- a/source/sdk/kotlin/realm-database/schemas/define-realm-object-model.txt +++ b/source/sdk/kotlin/realm-database/schemas/define-realm-object-model.txt @@ -50,6 +50,23 @@ Realm Schema .. include:: /includes/realm-schema.rst +Property Annotations +~~~~~~~~~~~~~~~~~~~~ + +Annotations add functionality to properties in your Realm object models. +You can use annotations for things like marking a property as nullable, setting a primary key, ignoring a property, and more. + +To learn more about the available property annotations, refer to :ref:`Property Annotations `. + +Relationship Properties +~~~~~~~~~~~~~~~~~~~~~~~ + +You can define relationships between Realm objects in your schema. +The Realm Kotlin SDK supports to-one relationships, to-many relationships, +inverse relationships, and embedding objects within other objects. + +To learn more about how to define relationships in your Realm object schema, refer to :ref:`Relationships `. + .. _kotlin-define-a-new-object-type: Define a New Object Type @@ -59,8 +76,6 @@ To define a Realm object type: 1. Create a uniquely named Kotlin class that implements the `RealmObject <{+kotlin-local-prefix+}io.realm.kotlin.types/-realm-object/index.html>`__ - or - `EmbeddedRealmObject <{+kotlin-local-prefix+}io.realm.kotlin.types/-embedded-realm-object/index.html>`__ interface. #. Add fields to your class. You can add any :ref:`supported data types ` as a field in your class. @@ -81,23 +96,26 @@ when you :ref:`open the realm `. .. literalinclude:: /examples/generated/kotlin/SchemaTest.snippet.open-with-class.kt :language: kotlin :emphasize-lines: 2 - -Add Property Annotations -~~~~~~~~~~~~~~~~~~~~~~~~ + +.. _kotlin-define-embedded-object: -Use annotations to add functionality to properties in your Realm object models. -You can use annotations for things like marking a property as nullable, setting a primary key, ignoring a property, and more. +Define an Embedded Object +------------------------- -To learn more about the available property annotations, refer to :ref:`Property Annotations `. +To define an :ref:`embedded object `, derive a class from +`EmbeddedRealmObject <{+kotlin-local-prefix+}io.realm.kotlin.types/-embedded-realm-object/index.html>`__: -Define Relationship Properties -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.. literalinclude:: /examples/generated/kotlin/DataTypesTest.snippet.embedded-object-model.kt + :language: kotlin -You can define relationships between Realm objects in your schema. -The Realm Kotlin SDK supports to-one relationships, to-many relationships, -inverse relationships, and embedding objects within other objects. +Once your embedded object class is defined, you must include its schema in the +realm's +`configuration <{+kotlin-local-prefix+}io.realm.kotlin/-realm-configuration/index.html>`__ +to use it in your realm instance: -To learn more about how to define relationships in your Realm object schema, refer to :ref:`Relationships `. +.. literalinclude:: /examples/generated/kotlin/DataTypesTest.snippet.open-realm-embedded-object.kt + :language: kotlin + :emphasize-lines: 3 Define an Asymmetric Object --------------------------- diff --git a/source/sdk/kotlin/realm-database/schemas/relationships.txt b/source/sdk/kotlin/realm-database/schemas/relationships.txt index 97105365be0..1ae5b9481ce 100644 --- a/source/sdk/kotlin/realm-database/schemas/relationships.txt +++ b/source/sdk/kotlin/realm-database/schemas/relationships.txt @@ -146,91 +146,11 @@ Because of this, embedded objects have the following constraints: - You cannot reassign an embedded object to a different parent object. - You cannot link to an embedded object from multiple parent objects. +To define an embedded object, refer to :ref:`Define an Embedded Object `. + .. tip:: Embedded Object Types are Reusable and Composable You can use the same embedded object type in multiple parent object types, and you can embed objects inside other embedded objects. You can even recursively reference an embedded object type as an optional property in its own definition. - -Define an Embedded Object -~~~~~~~~~~~~~~~~~~~~~~~~~ - -To define an embedded object, derive a class from -`EmbeddedRealmObject <{+kotlin-local-prefix+}io.realm.kotlin.types/-embedded-realm-object/index.html>`__: - -.. literalinclude:: /examples/generated/kotlin/DataTypesTest.snippet.embedded-object-model.kt - :language: kotlin - -Once your embedded object class is defined, you must include its schema in the -realm's -`configuration <{+kotlin-local-prefix+}io.realm.kotlin/-realm-configuration/index.html>`__ -to use it in your realm instance: - -.. literalinclude:: /examples/generated/kotlin/DataTypesTest.snippet.open-realm-embedded-object.kt - :language: kotlin - :emphasize-lines: 3 - -Create an Embedded Object -~~~~~~~~~~~~~~~~~~~~~~~~~ - -To create an embedded object, assign an instance of the embedded object -to a parent object's property: - -.. literalinclude:: /examples/generated/kotlin/DataTypesTest.snippet.create-embedded-object.kt - :language: kotlin - - -Update Embedded Object Properties -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -To update a property in an embedded object, fetch the object and reassign the -embedded object properties in a write transaction: - -.. literalinclude:: /examples/generated/kotlin/DataTypesTest.snippet.update-embedded-object.kt - :language: kotlin - - -Overwrite an Embedded Object -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -To overwrite an embedded object, assign a new embedded object instance to the -property in a write transaction: - -.. literalinclude:: /examples/generated/kotlin/DataTypesTest.snippet.overwrite-embedded-object.kt - :language: kotlin - - -Query an Embedded Object -~~~~~~~~~~~~~~~~~~~~~~~~ - -You can query the embedded object directly or through the parent object. -You can also use the -`EmbeddedRealmObject.parent() <{+kotlin-local-prefix+}io.realm.kotlin.ext/parent.html>`__ -method to access the parent of the embedded object. - -.. literalinclude:: /examples/generated/kotlin/DataTypesTest.snippet.query-embedded-objects.kt - :language: kotlin - - -Delete an Embedded Object -~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. warning:: Realm Uses Cascading Deletes for Embedded Objects - - When you delete a Realm object, Realm automatically deletes any - embedded objects referenced by that object. - If you want the referenced objects to persist after the deletion of the - parent object, use a regular Realm object with a :ref:`to-one relationship - ` instead. - -You can delete an embedded object directly or through the parent object. - -To delete only an embedded object, you can fetch and delete a specific embedded object -or clear the parent's reference to the embedded object, which also deletes -the embedded object instance. - -Deleting the parent object automatically deletes all of its embedded objects. - -.. literalinclude:: /examples/generated/kotlin/DataTypesTest.snippet.delete-embedded-object.kt - :language: kotlin From 2ab4a7595f63aedab715fba3eb201129b7cf389d Mon Sep 17 00:00:00 2001 From: cbullinger <115956901+cbullinger@users.noreply.github.com> Date: Thu, 3 Aug 2023 13:47:07 -0400 Subject: [PATCH 4/7] DOCSP-30337: Add Manage Sync Session - Kotlin SDK page (#2932) ## Pull Request Info Add new Manage Sync Session page for Kotlin (progress listener added in https://github.com/realm/realm-kotlin/pull/1118) > NOTE: Kotlin SDK doesn't currently support progress listener for Flexible Sync; only supported for PBS ### Jira - https://jira.mongodb.org/browse/DOCSP-30337 ### Staged Changes - [Manage Sync Session](https://docs-mongodbcom-staging.corp.mongodb.com/realm/docsworker-xlarge/docsp-30337-manage-sync-sessions/sdk/kotlin/sync/manage-sync-session/) - new page - [Partition-Based Sync](https://docs-mongodbcom-staging.corp.mongodb.com/realm/docsworker-xlarge/docsp-30337-manage-sync-sessions/sdk/kotlin/sync/partition-based-sync/#check-upload---download-progress-for-a-sync-session) - updated page ### Reminder Checklist If your PR modifies the docs, you might need to also update some corresponding pages. Check if completed or N/A. - [x] Create Jira ticket for corresponding docs-app-services update(s), if any - [x] Checked/updated Admin API - [x] Checked/updated CLI reference ### Review Guidelines [REVIEWING.md](https://github.com/mongodb/docs-realm/blob/master/REVIEWING.md) --- .../realm/realmkmmapp/ManageSyncSession.kt | 211 ++++++++++++++++++ ...cSession.snippet.get-network-connection.kt | 4 + ...sion.snippet.monitor-network-connection.kt | 6 + ...ageSyncSession.snippet.monitor-progress.kt | 8 + ...geSyncSession.snippet.pause-resume-sync.kt | 16 ++ ...yncSession.snippet.wait-upload-download.kt | 14 ++ source/sdk/kotlin/sync.txt | 1 + .../sdk/kotlin/sync/manage-sync-session.txt | 109 +++++++++ .../sdk/kotlin/sync/partition-based-sync.txt | 40 +++- 9 files changed, 407 insertions(+), 2 deletions(-) create mode 100644 examples/kotlin/shared/src/commonTest/kotlin/com/mongodb/realm/realmkmmapp/ManageSyncSession.kt create mode 100644 source/examples/generated/kotlin/ManageSyncSession.snippet.get-network-connection.kt create mode 100644 source/examples/generated/kotlin/ManageSyncSession.snippet.monitor-network-connection.kt create mode 100644 source/examples/generated/kotlin/ManageSyncSession.snippet.monitor-progress.kt create mode 100644 source/examples/generated/kotlin/ManageSyncSession.snippet.pause-resume-sync.kt create mode 100644 source/examples/generated/kotlin/ManageSyncSession.snippet.wait-upload-download.kt create mode 100644 source/sdk/kotlin/sync/manage-sync-session.txt diff --git a/examples/kotlin/shared/src/commonTest/kotlin/com/mongodb/realm/realmkmmapp/ManageSyncSession.kt b/examples/kotlin/shared/src/commonTest/kotlin/com/mongodb/realm/realmkmmapp/ManageSyncSession.kt new file mode 100644 index 00000000000..e44ed406f7c --- /dev/null +++ b/examples/kotlin/shared/src/commonTest/kotlin/com/mongodb/realm/realmkmmapp/ManageSyncSession.kt @@ -0,0 +1,211 @@ +package com.mongodb.realm.realmkmmapp + +import io.realm.kotlin.Realm +import io.realm.kotlin.ext.query +import io.realm.kotlin.internal.platform.runBlocking +import io.realm.kotlin.mongodb.App +import io.realm.kotlin.mongodb.Credentials +import io.realm.kotlin.mongodb.sync.* +import io.realm.kotlin.mongodb.syncSession +import io.realm.kotlin.types.RealmInstant +import io.realm.kotlin.types.RealmObject +import io.realm.kotlin.types.annotations.PrimaryKey +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.launch +import org.mongodb.kbson.BsonObjectId +import org.mongodb.kbson.ObjectId +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertTrue +import kotlin.time.Duration.Companion.minutes + + +// :replace-start: { +// "terms": { +// "SyncTask": "Task" +// } +// } +class ManageSyncSession : RealmTest() { + + class SyncTask : RealmObject { + @PrimaryKey + var _id: ObjectId = BsonObjectId() + var taskName: String = "" + var assignee: String? = null + var completed: Boolean = false + var progressMinutes: Int = 0 + var dueDate: RealmInstant? = null + } + + val app = App.create(yourFlexAppId) + val credentials = Credentials.anonymous(reuseExisting = false) + @Test + fun waitForChangesUploadAndDownload() { + runBlocking { + val user = app.login(credentials) + val config = SyncConfiguration.Builder(user, setOf(SyncTask::class)) + .initialSubscriptions { it.query().subscribe() } + .build() + val realm = Realm.open(config) + Log.v("Successfully opened realm: ${realm.configuration}") + // :snippet-start: wait-upload-download + // Wait to download all pending changes from Atlas + realm.syncSession.downloadAllServerChanges(1.minutes) + + // Add data locally + realm.write { + this.copyToRealm(SyncTask().apply { + taskName = "Review proposal" + assignee = "Emma" + progressMinutes = 0 + }) + } + + val upload = // :remove: + // Wait for local changes to be uploaded to Atlas + realm.syncSession.uploadAllLocalChanges(1.minutes) + // :snippet-end: + assertTrue(upload) + realm.write { + val tasks = query().find() + delete(tasks) + assertEquals(0, tasks.size) + } + realm.syncSession.uploadAllLocalChanges() + user.remove() + realm.close() + } + } + + @Test + fun pauseResumeSyncSession() { + runBlocking { + val user = app.login(credentials) + val config = SyncConfiguration.Builder(user, setOf(SyncTask::class)) + .initialSubscriptions { it.query().subscribe() } + .build() + val realm = Realm.open(config) + Log.v("Successfully opened realm: ${realm.configuration}") + // :snippet-start: pause-resume-sync + // Pause the sync session + // Data that you write while session is paused does not sync to Atlas + realm.syncSession.pause() + assertEquals(SyncSession.State.PAUSED, realm.syncSession.state) // :remove: + + // Add data locally + realm.write { + this.copyToRealm(SyncTask().apply { + taskName = "Submit expense report" + assignee = "Kevin" + progressMinutes = 0 + }) + } + + // Resume sync session + // Local changes now sync to Atlas + realm.syncSession.resume() + // :snippet-end: + assertEquals(SyncSession.State.ACTIVE, realm.syncSession.state) + realm.write { + val tasks = query().find() + delete(tasks) + assertEquals(0, tasks.size) + } + realm.syncSession.uploadAllLocalChanges() + user.remove() + realm.close() + } + } + + @Test + fun monitorSyncProgress() { + /* + NOTE: Kotlin does not currently support progress listeners for Flexible Sync + Requires PBS + */ + runBlocking { + val app1 = App.create(yourAppId) + val user = app1.login(credentials) + val config = SyncConfiguration.Builder(user, PARTITION, setOf(SyncTask::class)) + .name(PARTITION) + .build() + val realm = Realm.open(config) + Log.v("Successfully opened realm: ${realm.configuration}") + + realm.write { + this.copyToRealm(SyncTask().apply { + taskName = "Schedule appointment" + assignee = "Jane" + progressMinutes = 0 + }) + } + // :snippet-start: monitor-progress + val stream = realm.syncSession.progressAsFlow( + Direction.UPLOAD, ProgressMode.CURRENT_CHANGES + ) + stream.collect { progress -> + if (progress.transferableBytes == progress.transferredBytes) { + Log.i("Upload complete") + } + } + // :snippet-end: + assertTrue(stream.first().isTransferComplete) + realm.write { + val tasks = query().find() + delete(tasks) + assertEquals(0, tasks.size) + } + realm.syncSession.uploadAllLocalChanges() + user.remove() + realm.close() + } + } + + @Test + fun monitorNetworkConnection() { + runBlocking { + val user = app.login(credentials) + val config = SyncConfiguration.Builder(user, setOf(SyncTask::class)) + .initialSubscriptions { it.query().subscribe() } + .build() + val realm = Realm.open(config) + Log.v("Successfully opened realm: ${realm.configuration}") + // :snippet-start: get-network-connection + if (realm.syncSession.connectionState == ConnectionState.CONNECTED) { + Log.i("Connected to network") + // ... do something + } + // :snippet-end: + val flow = CoroutineScope(Dispatchers.Default).launch { + // :snippet-start: monitor-network-connection + val connectionFlow = realm.syncSession.connectionStateAsFlow() + connectionFlow.collect { ConnectionStateChange -> + if (ConnectionStateChange.newState == ConnectionState.CONNECTED) { + Log.i("Connected to Atlas Device Sync server") + } + } + // :snippet-end: + assertEquals(ConnectionState.CONNECTED, realm.syncSession.connectionState) + } + realm.write { + this.copyToRealm(SyncTask().apply { + taskName = "Do a thing" + assignee = "Me" + progressMinutes = 0 + }) + } + realm.write { + val tasks = query().find() + delete(tasks) + assertEquals(0, tasks.size) + } + realm.syncSession.uploadAllLocalChanges() + flow.cancel() + user.remove() + realm.close() + } + } +} +// :replace-end: \ No newline at end of file diff --git a/source/examples/generated/kotlin/ManageSyncSession.snippet.get-network-connection.kt b/source/examples/generated/kotlin/ManageSyncSession.snippet.get-network-connection.kt new file mode 100644 index 00000000000..a33f6b28742 --- /dev/null +++ b/source/examples/generated/kotlin/ManageSyncSession.snippet.get-network-connection.kt @@ -0,0 +1,4 @@ +if (realm.syncSession.connectionState == ConnectionState.CONNECTED) { + Log.i("Connected to network") + // ... do something +} diff --git a/source/examples/generated/kotlin/ManageSyncSession.snippet.monitor-network-connection.kt b/source/examples/generated/kotlin/ManageSyncSession.snippet.monitor-network-connection.kt new file mode 100644 index 00000000000..909db332499 --- /dev/null +++ b/source/examples/generated/kotlin/ManageSyncSession.snippet.monitor-network-connection.kt @@ -0,0 +1,6 @@ +val connectionFlow = realm.syncSession.connectionStateAsFlow() +connectionFlow.collect { ConnectionStateChange -> + if (ConnectionStateChange.newState == ConnectionState.CONNECTED) { + Log.i("Connected to Atlas Device Sync server") + } +} diff --git a/source/examples/generated/kotlin/ManageSyncSession.snippet.monitor-progress.kt b/source/examples/generated/kotlin/ManageSyncSession.snippet.monitor-progress.kt new file mode 100644 index 00000000000..220386c04c2 --- /dev/null +++ b/source/examples/generated/kotlin/ManageSyncSession.snippet.monitor-progress.kt @@ -0,0 +1,8 @@ +val stream = realm.syncSession.progressAsFlow( + Direction.UPLOAD, ProgressMode.CURRENT_CHANGES +) +stream.collect { progress -> + if (progress.transferableBytes == progress.transferredBytes) { + Log.i("Upload complete") + } +} diff --git a/source/examples/generated/kotlin/ManageSyncSession.snippet.pause-resume-sync.kt b/source/examples/generated/kotlin/ManageSyncSession.snippet.pause-resume-sync.kt new file mode 100644 index 00000000000..ac5012fe19a --- /dev/null +++ b/source/examples/generated/kotlin/ManageSyncSession.snippet.pause-resume-sync.kt @@ -0,0 +1,16 @@ +// Pause the sync session +// Data that you write while session is paused does not sync to Atlas +realm.syncSession.pause() + +// Add data locally +realm.write { + this.copyToRealm(Task().apply { + taskName = "Submit expense report" + assignee = "Kevin" + progressMinutes = 0 + }) +} + +// Resume sync session +// Local changes now sync to Atlas +realm.syncSession.resume() diff --git a/source/examples/generated/kotlin/ManageSyncSession.snippet.wait-upload-download.kt b/source/examples/generated/kotlin/ManageSyncSession.snippet.wait-upload-download.kt new file mode 100644 index 00000000000..e21a96368b1 --- /dev/null +++ b/source/examples/generated/kotlin/ManageSyncSession.snippet.wait-upload-download.kt @@ -0,0 +1,14 @@ +// Wait to download all pending changes from Atlas +realm.syncSession.downloadAllServerChanges(1.minutes) + +// Add data locally +realm.write { + this.copyToRealm(Task().apply { + taskName = "Review proposal" + assignee = "Emma" + progressMinutes = 0 + }) +} + +// Wait for local changes to be uploaded to Atlas +realm.syncSession.uploadAllLocalChanges(1.minutes) diff --git a/source/sdk/kotlin/sync.txt b/source/sdk/kotlin/sync.txt index e96856daa79..9e9491d9e78 100644 --- a/source/sdk/kotlin/sync.txt +++ b/source/sdk/kotlin/sync.txt @@ -11,6 +11,7 @@ Device Sync - Kotlin SDK Configure & Open a Synced Realm Manage Subscriptions Write to a Synced Realm + Manage Sync Session Handle Sync Errors Set the Client Log Level Stream Data to Atlas diff --git a/source/sdk/kotlin/sync/manage-sync-session.txt b/source/sdk/kotlin/sync/manage-sync-session.txt new file mode 100644 index 00000000000..bcd1d1e22d3 --- /dev/null +++ b/source/sdk/kotlin/sync/manage-sync-session.txt @@ -0,0 +1,109 @@ +.. _kotlin-manage-sync-session: + +================================== +Manage a Sync Session - Kotlin SDK +================================== + +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + +When you use :ref:`Flexible Sync `, the Realm Kotlin SDK syncs +data with Atlas in the background using a sync session. The sync session starts +whenever you open a synced realm. + +The sync session manages the following: + +- Uploading and downloading changes to the realm +- Pausing and resuming sync +- Monitoring network connectivity + +You can access the `SyncSession <{+kotlin-sync-prefix+}io.realm.kotlin.mongodb.sync/-sync-session/index.html>`__ +of any synced realm through the `realm.syncSession <{+kotlin-sync-prefix+}io.realm.kotlin.Realm/syncSession.html>`__ +property. + +Prerequisites +------------- + +Before you can manage your sync session state, you must perform the following: + +#. :ref:`Configure Flexible Sync on the Atlas App Services backend `. +#. :ref:`Authenticate a user ` in your client app. +#. :ref:`Open the synced realm `. + +.. _kotlin-sync-wait-for-changes: + +Wait for Changes to Upload and Download +--------------------------------------- + +To asynchronously wait for all changes to upload to Atlas from your synced realm, +call +`uploadAllLocalChanges <{+kotlin-sync-prefix+}io.realm.kotlin.mongodb.sync/-sync-session/upload-all-local-changes.html>`__. +This method returns ``true`` when all changes have been uploaded. + +To asynchronously wait for all changes on Atlas to download from the Device Sync +server to your synced realm, call +`downloadAllServerChanges <{+kotlin-sync-prefix+}io.realm.kotlin.mongodb.sync/-sync-session/download-all-server-changes.html>`__. +This method returns ``true`` when all changes have been downloaded. + +You can also include an optional ``timeout`` parameter to either method to +determine the maximum amount of time before returning ``false``. Note that +the upload or download continues in the background even after returning ``false``. + +The following example demonstrates calling both methods with a timeout defined: + +.. literalinclude:: /examples/generated/kotlin/ManageSyncSession.snippet.wait-upload-download.kt + :language: kotlin + +.. _kotlin-pause-resume-sync: + +Pause and Resume a Sync Session +------------------------------- + +To pause syncing for a session, call +`syncSession.pause() <{+kotlin-sync-prefix+}io.realm.kotlin.mongodb.sync/-sync-session/pause.html>`__. +The realm will not sync changes with Atlas while the session is paused. + +To resume syncing a changes, call +`syncSession.resume() <{+kotlin-sync-prefix+}io.realm.kotlin.mongodb.sync/-sync-session/resume.html>`__. + +You must manually call ``syncSession.pause()`` and ``syncSession.resume()`` for +each realm whose Sync session you want to pause and restart. +The sync state of one session has no impact on other open sessions. + +The following code block demonstrates calling these methods: + +.. literalinclude:: /examples/generated/kotlin/ManageSyncSession.snippet.pause-resume-sync.kt + :language: kotlin + +When to Pause a Sync Session +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. include:: /includes/when-to-pause-sync.rst + +.. _kotlin-monitor-network-connection: + +Monitor Network Connection +-------------------------- + +You can get the state of the current network connection by checking the +`SyncSession.connectionState <{+kotlin-sync-prefix+}io.realm.kotlin.mongodb.sync/-sync-session/connection-state.html>`__ property. +This returns a `ConnectionState <{+kotlin-sync-prefix+}io.realm.kotlin.mongodb.sync/-connection-state/index.html>`__ +enum value that indicates the state of the network connection. The possible +states are: +``CONNECTED``, ``DISCONNECTED``, or ``CONNECTING``. + +.. literalinclude:: /examples/generated/kotlin/ManageSyncSession.snippet.get-network-connection.kt + :language: kotlin + +Monitor the state of the network connection with +`connectionStateAsFlow <{+kotlin-sync-prefix+}io.realm.kotlin.mongodb.sync/-sync-session/connection-state-as-flow.html>`__. +This property returns a Flow of +`ConnectionStateChange <{+kotlin-sync-prefix+}io.realm.kotlin.mongodb.sync/-connection-state-change/index.html>`__ +objects that updates when the network connection changes. You can access the +new and old ``ConnectionState`` from ``ConnectionStateChange``. + +.. literalinclude:: /examples/generated/kotlin/ManageSyncSession.snippet.monitor-network-connection.kt + :language: kotlin diff --git a/source/sdk/kotlin/sync/partition-based-sync.txt b/source/sdk/kotlin/sync/partition-based-sync.txt index e32041ca7b2..0b90c11bd97 100644 --- a/source/sdk/kotlin/sync/partition-based-sync.txt +++ b/source/sdk/kotlin/sync/partition-based-sync.txt @@ -48,7 +48,6 @@ an instance of the realm: .. literalinclude:: /examples/generated/kotlin/SyncTest.snippet.open-a-synced-realm.kt :language: kotlin - :copyable: false Configure a Partition-Based Sync Realm -------------------------------------- @@ -59,7 +58,44 @@ To adjust specific configuration settings, use the options provided by .. literalinclude:: /examples/generated/kotlin/SyncTest.snippet.configure-a-synced-realm.kt :language: kotlin - :copyable: false + +Check Upload & Download Progress for a Sync Session +--------------------------------------------------- + +.. note:: + + The ``progressAsFlow()`` listener in the Kotlin SDK is only currently + available for realms using Partition-Based Sync. The Kotlin SDK does not + yet support progress listeners for Flexible Sync. + +You can monitor the upload and download progress of a sync session. The sync +session starts when you open a synced realm. For more information, refer to +:ref:`Manage a Sync Session `. + +To monitor Sync upload and download progress, call +`SyncSession.progressAsFlow() <{+kotlin-sync-prefix+}io.realm.kotlin.mongodb.sync/-sync-session/progress-as-flow.html>`__ + +This method returns a Flow of +`Progress <{+kotlin-sync-prefix+}io.realm.kotlin.mongodb.sync/-progress/index.html>`__ +events. ``Progress`` provides the total +number of transferrable bytes and the remaining bytes to be transferred. + +``syncSession.progressAsFlow()`` takes two arguments: + +- A `Direction <{+kotlin-sync-prefix+}io.realm.kotlin.mongodb.sync/-direction/index.html>`__ + enum that can be set to ``UPLOAD`` or ``DOWNLOAD``. + This specifies that the progress stream tracks uploads or downloads. + +- A `ProgressMode <{+kotlin-sync-prefix+}io.realm.kotlin.mongodb.sync/-progress-mode/index.html>`__ + enum that can be set to either: + + - ``INDEFINITELY``: Sets notifications to continue until the callback is + unregistered. + - ``CURRENT_CHANGES``: Sets notifications to continue until only the currently + transferable bytes are synced. + +.. literalinclude:: /examples/generated/kotlin/ManageSyncSession.snippet.monitor-progress.kt + :language: kotlin .. _kotlin-migrate-pbs-to-fs: From 4d74aeb8c8cdcaaa994ff2dcb01275441aa50a9e Mon Sep 17 00:00:00 2001 From: Dachary Date: Thu, 3 Aug 2023 17:32:41 -0400 Subject: [PATCH 5/7] (DOCSP-29747): C++: Remove unnecessary page headers, Key Concept verbiage (#2934) ## Pull Request Info ### Jira - https://jira.mongodb.org/browse/DOCSP-29747 ### Staged Changes - [Staged C++ Docs](https://docs-mongodbcom-staging.corp.mongodb.com/realm/docsworker-xlarge/DOCSP-29747/sdk/cpp/) ### Reminder Checklist If your PR modifies the docs, you might need to also update some corresponding pages. Check if completed or N/A. - [x] Create Jira ticket for corresponding docs-app-services update(s), if any - [x] Checked/updated Admin API - [x] Checked/updated CLI reference ### Review Guidelines [REVIEWING.md](https://github.com/mongodb/docs-realm/blob/master/REVIEWING.md) --- .../sdk/cpp/app-services/connect-to-app.txt | 7 ++---- source/sdk/cpp/application-services.txt | 3 --- source/sdk/cpp/crud/create.txt | 5 +--- source/sdk/cpp/crud/delete.txt | 4 +-- source/sdk/cpp/crud/filter-data.txt | 3 --- source/sdk/cpp/crud/read.txt | 14 ++++------- source/sdk/cpp/crud/threading.txt | 3 --- source/sdk/cpp/crud/update.txt | 25 ++++++------------- source/sdk/cpp/manage-users.txt | 3 --- source/sdk/cpp/model-data/object-models.txt | 10 ++++---- source/sdk/cpp/model-data/relationships.txt | 6 ++--- source/sdk/cpp/model-data/supported-types.txt | 9 +++---- .../configure-and-open-a-realm.txt | 8 +++--- source/sdk/cpp/sync.txt | 9 ++++--- source/sdk/cpp/sync/sync-subscriptions.txt | 7 ++---- 15 files changed, 41 insertions(+), 75 deletions(-) diff --git a/source/sdk/cpp/app-services/connect-to-app.txt b/source/sdk/cpp/app-services/connect-to-app.txt index 92c03b26c8c..ee08b045331 100644 --- a/source/sdk/cpp/app-services/connect-to-app.txt +++ b/source/sdk/cpp/app-services/connect-to-app.txt @@ -10,9 +10,6 @@ Connect to App Services - C++ SDK Preview :depth: 2 :class: singlecol -Overview --------- - The App client is the Atlas App Services backend interface. It provides access to authentication and Atlas Functions. @@ -20,8 +17,8 @@ Some of your App Services App's features are associated with user accounts. For need to :ref:`authenticate a user ` before you can access your App's functions. -Before You Begin ----------------- +Prerequisites +------------- #. :ref:`Create an App Services app ` diff --git a/source/sdk/cpp/application-services.txt b/source/sdk/cpp/application-services.txt index a980c1e7929..e71bc7987d6 100644 --- a/source/sdk/cpp/application-services.txt +++ b/source/sdk/cpp/application-services.txt @@ -16,9 +16,6 @@ Application Services - C++ SDK Preview :depth: 2 :class: singlecol -Overview --------- - Realm SDKs let you connect your client apps to the Atlas App Services backend. The SDKs provide the functionality needed to authenticate users with any of the built-in :ref:`authentication diff --git a/source/sdk/cpp/crud/create.txt b/source/sdk/cpp/crud/create.txt index 4a0856948a0..ac4fb4da364 100644 --- a/source/sdk/cpp/crud/create.txt +++ b/source/sdk/cpp/crud/create.txt @@ -12,11 +12,8 @@ CRUD - Create - C++ SDK Preview .. _cpp-write-transactions: -Key Concept: Transactions -------------------------- - Write Transactions -~~~~~~~~~~~~~~~~~~ +------------------ Realm uses a highly efficient storage engine to persist objects. You can **create** objects in a realm, diff --git a/source/sdk/cpp/crud/delete.txt b/source/sdk/cpp/crud/delete.txt index 85b4911b3f6..30b66d534a5 100644 --- a/source/sdk/cpp/crud/delete.txt +++ b/source/sdk/cpp/crud/delete.txt @@ -16,8 +16,8 @@ Delete Realm Objects -------------------- Deleting Realm Objects must occur within write transactions. For -more information about write trasactions, see: :ref:`Key Concept: -Transactions `. +more information about write trasactions, see: :ref:`Write Transactions +`. Delete an Object ~~~~~~~~~~~~~~~~ diff --git a/source/sdk/cpp/crud/filter-data.txt b/source/sdk/cpp/crud/filter-data.txt index abb1829849d..0f623a95b6c 100644 --- a/source/sdk/cpp/crud/filter-data.txt +++ b/source/sdk/cpp/crud/filter-data.txt @@ -11,9 +11,6 @@ Filter Data - C++ SDK Preview :depth: 3 :class: singlecol -Overview --------- - To filter data in your realm, you can leverage Realm's query engine. diff --git a/source/sdk/cpp/crud/read.txt b/source/sdk/cpp/crud/read.txt index 00837fc4aef..26c9c39c9d5 100644 --- a/source/sdk/cpp/crud/read.txt +++ b/source/sdk/cpp/crud/read.txt @@ -1,4 +1,5 @@ .. _cpp-crud-read: +.. _cpp-read-from-realm: ============================= CRUD - Read - C++ SDK Preview @@ -10,11 +11,6 @@ CRUD - Read - C++ SDK Preview :depth: 2 :class: singlecol -.. _cpp-read-from-realm: - -Key Concept: Read from Realm ----------------------------- - A read from a realm generally consists of the following steps: @@ -29,7 +25,7 @@ results of the associated query. .. _cpp-realm-read-characteristics: Read Characteristics -~~~~~~~~~~~~~~~~~~~~ +-------------------- Design your app's data access patterns around these three key read characteristics to read data as efficiently as possible. @@ -37,7 +33,7 @@ read characteristics to read data as efficiently as possible. .. _cpp-results-are-not-copies: Results Are Not Copies -`````````````````````` +~~~~~~~~~~~~~~~~~~~~~~ Results to a query are not copies of your data. Modifying the results of a query modifies the data on disk @@ -49,7 +45,7 @@ disk. .. _cpp-lazy-evaluated-results: Results Are Lazy -```````````````` +~~~~~~~~~~~~~~~~ Realm only runs a query when you actually request the results of that query. This lazy evaluation enables you to write @@ -60,7 +56,7 @@ extra work to process the intermediate state. .. _cpp-references-retained: References Are Retained -``````````````````````` +~~~~~~~~~~~~~~~~~~~~~~~ One benefit of Realm's object model is that Realm automatically retains all of an object's diff --git a/source/sdk/cpp/crud/threading.txt b/source/sdk/cpp/crud/threading.txt index 8642e5265e9..3991f27e709 100644 --- a/source/sdk/cpp/crud/threading.txt +++ b/source/sdk/cpp/crud/threading.txt @@ -10,9 +10,6 @@ Threading - C++ SDK Preview :depth: 2 :class: singlecol -Overview --------- - To create performant apps, developers must write thread-safe and maintainable multithreaded code that avoids issues like deadlocking and race conditions. Realm provides tools specifically designed for performant multithreaded apps. diff --git a/source/sdk/cpp/crud/update.txt b/source/sdk/cpp/crud/update.txt index bb7085832c7..ed589aaea46 100644 --- a/source/sdk/cpp/crud/update.txt +++ b/source/sdk/cpp/crud/update.txt @@ -1,4 +1,5 @@ .. _cpp-crud-update: +.. _cpp-update-realm-objects: =============================== CRUD - Update - C++ SDK Preview @@ -10,17 +11,12 @@ CRUD - Update - C++ SDK Preview :depth: 2 :class: singlecol -.. _cpp-update-realm-objects: - -Update Realm Objects --------------------- - Updates to Realm Objects must occur within write transactions. For -more information about write trasactions, see: :ref:`Key Concept: +more information about write trasactions, see: :ref:`Write Transactions `. Update an Object -~~~~~~~~~~~~~~~~ +---------------- You can modify properties of a Realm object inside of a write transaction. @@ -40,8 +36,7 @@ You can modify properties of a Realm object inside of a write transaction. .. include:: /includes/tip-cpp-beta-experimental-features.rst -Model -````` +**Model** This example uses the following model: @@ -83,8 +78,7 @@ write transaction. .. include:: /includes/tip-cpp-beta-experimental-features.rst -Model -````` +**Model** This example uses the following model: @@ -129,8 +123,7 @@ Overwrite an Embedded Object Property .. include:: /includes/tip-cpp-beta-experimental-features.rst -Model -````` +**Model** This example uses the following model: @@ -171,8 +164,7 @@ its ``Dog`` relationship. .. include:: /includes/tip-cpp-beta-experimental-features.rst -Model -````` +**Model** This example uses the following model: @@ -206,8 +198,7 @@ as you would a standard C++ `map Custom User Data -Overview --------- - When you use Atlas App Services to back your client app, you get access to a :ref:`user object `. Use C++ SDK methods with this user object to conveniently: diff --git a/source/sdk/cpp/model-data/object-models.txt b/source/sdk/cpp/model-data/object-models.txt index 2791b3139c7..805789fe839 100644 --- a/source/sdk/cpp/model-data/object-models.txt +++ b/source/sdk/cpp/model-data/object-models.txt @@ -10,15 +10,15 @@ Object Models - C++ SDK Preview :depth: 3 :class: singlecol -.. _cpp-realm-objects: - -Key Concept: Object Types & Schemas ------------------------------------ - Realm applications model data as objects composed of field-value pairs that each contain one or more :ref:`supported ` data types. +.. _cpp-realm-objects: + +Object Types and Schemas +------------------------ + Every Realm object has an *object type* that refers to the object's class. Objects of the same type share an :ref:`object schema ` that defines the properties and relationships of those diff --git a/source/sdk/cpp/model-data/relationships.txt b/source/sdk/cpp/model-data/relationships.txt index a71322c36de..ec0a50a60a8 100644 --- a/source/sdk/cpp/model-data/relationships.txt +++ b/source/sdk/cpp/model-data/relationships.txt @@ -10,9 +10,6 @@ Relationships - C++ SDK Preview :depth: 3 :class: singlecol -Key Concept: Relationships --------------------------- - Realm doesn't use bridge tables or explicit joins to define relationships as you would in a relational database. Realm handles relationships through embedded objects or reference properties to @@ -20,6 +17,9 @@ other Realm objects. You read from and write to these properties directly. This makes querying relationships as performant as querying against any other property. +Relationship Types +------------------ + Realm supports **to-one**, **to-many**, and **inverse** relationships. Realm also provides a special type of object, called an :ref:`embedded object `, that is conceptually diff --git a/source/sdk/cpp/model-data/supported-types.txt b/source/sdk/cpp/model-data/supported-types.txt index d47ece9e93f..889ae283211 100644 --- a/source/sdk/cpp/model-data/supported-types.txt +++ b/source/sdk/cpp/model-data/supported-types.txt @@ -10,16 +10,13 @@ Supported Types - C++ SDK Preview :depth: 2 :class: singlecol -Supported Property Types ------------------------- - The Realm C++ SDK Preview currently supports these property types. Optionals use the class template `std::optional `__. Property Cheat Sheet -~~~~~~~~~~~~~~~~~~~~ +-------------------- .. tabs:: @@ -230,7 +227,7 @@ Property Cheat Sheet .. include:: /includes/tip-cpp-beta-experimental-features.rst Supported Type Implementation Details -````````````````````````````````````` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Some of the supported types above are aliases for: @@ -247,7 +244,7 @@ Some of the supported types above are aliases for: .. _cpp-map: Map/Dictionary -~~~~~~~~~~~~~~ +-------------- The :cpp-sdk:`Map ` is an associative array that contains key-value pairs with unique keys. diff --git a/source/sdk/cpp/realm-files/configure-and-open-a-realm.txt b/source/sdk/cpp/realm-files/configure-and-open-a-realm.txt index a20fac0d854..959f0e93ba2 100644 --- a/source/sdk/cpp/realm-files/configure-and-open-a-realm.txt +++ b/source/sdk/cpp/realm-files/configure-and-open-a-realm.txt @@ -52,8 +52,8 @@ that describe the objects. .. _cpp-realm-file: -Key Concept: Realm Files ------------------------- +Realm Files +----------- Realm stores a binary encoded version of every object and type in a realm in a single ``.realm`` file. The file is located at :ref:`a specific @@ -69,8 +69,8 @@ You can open, view, and edit the contents of these files with .. _cpp-synced-realm: -Key Concept: Synced Realms --------------------------- +Synced Realms +------------- You can configure a realm to automatically synchronize data between many devices that each have their own local copy of the data. Synced realms diff --git a/source/sdk/cpp/sync.txt b/source/sdk/cpp/sync.txt index 09769dfc9fd..75d57395462 100644 --- a/source/sdk/cpp/sync.txt +++ b/source/sdk/cpp/sync.txt @@ -14,8 +14,11 @@ Sync Data Between Devices - C++ SDK Preview Set the Sync Client Log Level Stream Data to Atlas -Overview --------- +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol Atlas Device Sync automatically synchronizes data between client applications and an :ref:`App Services backend `. When a client @@ -33,7 +36,7 @@ only supports Flexible Sync. .. _cpp-flexible-sync-fundamentals: Flexible Sync -~~~~~~~~~~~~~ +------------- When you select :ref:`Flexible Sync ` for your backend App configuration, your client implementation must include subscriptions to diff --git a/source/sdk/cpp/sync/sync-subscriptions.txt b/source/sdk/cpp/sync/sync-subscriptions.txt index 940ddcc7e0c..81fe1e8db90 100644 --- a/source/sdk/cpp/sync/sync-subscriptions.txt +++ b/source/sdk/cpp/sync/sync-subscriptions.txt @@ -11,9 +11,6 @@ Manage Sync Subscriptions - C++ SDK Preview :depth: 3 :class: singlecol -Overview --------- - Flexible Sync uses subscriptions and permissions to determine which data to sync between your Atlas App Services App and your client device. In the client, query subscriptions manage and filter the object types that @@ -21,8 +18,8 @@ can sync to the realm. .. versionchanged:: 0.2.0 app.login and subscriptions.update return std::future instead of std::promise -Before You Begin ----------------- +Prerequisites +------------- To use Flexible Sync in your app, you must: From 710e16c5d558c51e75c438af2f8c3d1df5af0cc1 Mon Sep 17 00:00:00 2001 From: cbullinger <115956901+cbullinger@users.noreply.github.com> Date: Mon, 7 Aug 2023 08:14:04 -0400 Subject: [PATCH 6/7] DOCSP-30338: Remove dupe headings on Kotlin Install page (#2936) ## Pull Request Info Update Kotlin Install page to remove duplicate subheadings in tabbed procedure > NOTE: Confirmed the supported/unsupported environments list is still accurate. ### Jira - https://jira.mongodb.org/browse/DOCSP-30338 ### Staged Changes - [Install - Kotlin SDK](https://docs-mongodbcom-staging.corp.mongodb.com/realm/docsworker-xlarge/BRANCH_NAME/) - updated page ### Reminder Checklist If your PR modifies the docs, you might need to also update some corresponding pages. Check if completed or N/A. - [x] Create Jira ticket for corresponding docs-app-services update(s), if any - [x] Checked/updated Admin API - [x] Checked/updated CLI reference ### Review Guidelines [REVIEWING.md](https://github.com/mongodb/docs-realm/blob/master/REVIEWING.md) --- source/sdk/kotlin/install.txt | 86 +++++++++++++++++------------------ 1 file changed, 41 insertions(+), 45 deletions(-) diff --git a/source/sdk/kotlin/install.txt b/source/sdk/kotlin/install.txt index 2a250e86369..50bd0a90397 100644 --- a/source/sdk/kotlin/install.txt +++ b/source/sdk/kotlin/install.txt @@ -58,15 +58,15 @@ environment Installation ------------ -.. tabs:: +.. procedure:: - .. tab:: Android - :tabid: android + .. step:: Add Realm to the Project - .. procedure:: + .. tabs:: - .. step:: Add Realm to the Project - + .. tab:: Android + :tabid: android + Add :file:`io.realm.kotlin`, specifying the library version and :file:`apply false`, to the list of plugins in your project-level Gradle build file, typically found at :file:`/build.gradle`: @@ -82,14 +82,16 @@ Installation found at :file:`/app/build.gradle`: - Add :file:`io.realm.kotlin` to the list of plugins. - - Add one of the following to the list of dependencies: - - To only use the local realm in your application, add :file:`io.realm.kotlin:library-base` to the dependencies block. - - To use Device Sync in your application, add :file:`io.realm.kotlin:library-sync` to the dependencies block. + - Add the following to the list of dependencies: + + - Add :file:`io.realm.kotlin:library-base` to the dependencies block. + - If using Device Sync in your application, add :file:`io.realm.kotlin:library-sync` to the dependencies block. + - To use coroutines with the SDK, add :file:`org.jetbrains.kotlinx:kotlinx-coroutines-core` to the list of dependencies. .. code-block:: kotlin :caption: Module build.gradle - :emphasize-lines: 4, 12, 13 + :emphasize-lines: 4, 12, 13, 14 plugins { id 'com.android.application' @@ -98,37 +100,27 @@ Installation } android { - // ... build configuration settings - } + // ... build configuration settings + } dependencies { - implementation 'io.realm.kotlin:library-base:{+kotlin-sdk-version+}' // Add to use local realm (no sync) - implementation 'io.realm.kotlin:library-sync:{+kotlin-sdk-version+}'// Add to use Device Sync - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:{+kotlinx-coroutines-version+}' // Add to use coroutines with the SDK - + implementation 'io.realm.kotlin:library-base:{+kotlin-sdk-version+}' + implementation 'io.realm.kotlin:library-sync:{+kotlin-sdk-version+}'// If using Device Sync + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:{+kotlinx-coroutines-version+}' // If using coroutines with the SDK } - .. step:: Sync Gradle Files - - After updating the Gradle configuration, - resolve the dependencies by clicking :guilabel:`File` > - :guilabel:`Sync Project with Gradle Files` in the Android Studio menu bar. - You can now use the Kotlin SDK in your application. - - .. tab:: Kotlin Multiplatform (KMM) - :tabid: kmm + .. tab:: Kotlin Multiplatform (KMM) + :tabid: kmm - .. procedure:: - - .. step:: Add Realm to the Project - Add the following to your app-level Gradle build file, typically found at :file:`/app/build.gradle`: - Add :file:`io.realm.kotlin` to the list of plugins. - - Add one of the following to the list of dependencies: - - To only use the local realm in your application, add :file:`io.realm.kotlin:library-base` to the dependencies block. - - To use Device Sync in your application, add :file:`io.realm.kotlin:library-sync` to the dependencies block. + - Add the following to the list of dependencies: + + - Add :file:`io.realm.kotlin:library-base` to the dependencies block. + - If using Device Sync in your application, add :file:`io.realm.kotlin:library-sync` to the dependencies block. + - To use coroutines with the SDK, add :file:`org.jetbrains.kotlinx:kotlinx-coroutines-core` to the list of dependencies. .. code-block:: kotlin @@ -151,10 +143,10 @@ Installation sourceSets { val commonMain by getting { - dependencies { - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:{+kotlinx-coroutines-version+}") // Add to use coroutines with the SDK - implementation("io.realm.kotlin:library-base:{+kotlin-sdk-version+}") // Add to only use the local database - implementation("io.realm.kotlin:library-sync:{+kotlin-sdk-version+}") // Add to use Device Sync + dependencies { + implementation("io.realm.kotlin:library-base:{+kotlin-sdk-version+}") + implementation("io.realm.kotlin:library-sync:{+kotlin-sdk-version+}") // If using Device Sync + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:{+kotlinx-coroutines-version+}") // If using coroutines with the SDK } } } @@ -168,7 +160,6 @@ Installation .. code-block:: kotlin :copyable: false - // If only using the local database dependencies { compileOnly("io.realm.kotlin:library-base:{+kotlin-sdk-version+}") } @@ -178,12 +169,12 @@ Installation compileOnly("io.realm.kotlin:library-sync:{+kotlin-sdk-version+}") } - .. step:: Sync Gradle Files + .. step:: Sync Gradle Files - After updating the Gradle configuration, - resolve the dependencies by clicking :guilabel:`File` > - :guilabel:`Sync Project with Gradle Files` in the Android Studio menu bar. - You can now use the Kotlin SDK in your application. + After updating the Gradle configuration, + resolve the dependencies by clicking :guilabel:`File` > + :guilabel:`Sync Project with Gradle Files` in the Android Studio menu bar. + You can now use the Kotlin SDK in your application. Supported Target Environments @@ -192,7 +183,10 @@ Supported Target Environments Kotlin Multiplatform supports a `wide range of application environments `__. -The SDK supports the following environments: +Supported Environments +~~~~~~~~~~~~~~~~~~~~~~ + +The Kotlin SDK supports the following environments: - :file:`android` @@ -205,7 +199,10 @@ The SDK supports the following environments: - :file:`macosArm64` - :file:`macosX64` -The SDK does *not* support the following environments: +Unsupported Environments +~~~~~~~~~~~~~~~~~~~~~~~~ + +The Kotlin SDK does *not* support the following environments: - :file:`androidNativeArm32` - :file:`androidNativeArm64` @@ -236,4 +233,3 @@ The SDK does *not* support the following environments: - :file:`watchosSimulatorArm64` - :file:`watchosX86` - :file:`watchosX64` - \ No newline at end of file From 981919e9ee5b5568fad29c4d29b9dcd0b00faaff Mon Sep 17 00:00:00 2001 From: cbullinger <115956901+cbullinger@users.noreply.github.com> Date: Mon, 7 Aug 2023 10:14:11 -0400 Subject: [PATCH 7/7] (DOCSP-30680, DOCSP-31329, & DOCSP-31330): Add Property-Lvl Encryption, User Presence, and Client Reset to Kotlin example cards (#2935) ## Pull Request Info Add example project cards for: - [Property-Level Encryption](https://github.com/realm/realm-kotlin-samples/blob/main/AppServicesUsageSamples/apps/property-encryption/README.md) - [Client Reset and Error Handling](https://github.com/realm/realm-kotlin-samples/blob/main/AppServicesUsageSamples/apps/error-handling/README.md) - [Presence Detection](https://github.com/realm/realm-kotlin-samples/blob/main/AppServicesUsageSamples/apps/presence-detection/README.md) ### Jira - https://jira.mongodb.org/browse/DOCSP-30680 - https://jira.mongodb.org/browse/DOCSP-31329 - https://jira.mongodb.org/browse/DOCSP-31330 ### Staged Changes - [Kotlin SDK landing page](https://docs-mongodbcom-staging.corp.mongodb.com/realm/docsworker-xlarge/docsp-31329-31330-sample-apps/sdk/kotlin/#example-projects) ### Reminder Checklist If your PR modifies the docs, you might need to also update some corresponding pages. Check if completed or N/A. - [x] Create Jira ticket for corresponding docs-app-services update(s), if any - [x] Checked/updated Admin API - [x] Checked/updated CLI reference ### Review Guidelines [REVIEWING.md](https://github.com/mongodb/docs-realm/blob/master/REVIEWING.md) --- .../General_SECURITY_Encryption10x.png | Bin 0 -> 13755 bytes .../Technical_REALM_Offline10x.png | Bin 0 -> 16413 bytes source/images/icons/kotlin_sdk.svg | 45 +++++++----------- source/sdk/kotlin.txt | 39 +++++++++++++++ 4 files changed, 57 insertions(+), 27 deletions(-) create mode 100644 source/images/icons/branding_2023/General_SECURITY_Encryption10x.png create mode 100644 source/images/icons/branding_2023/Technical_REALM_Offline10x.png diff --git a/source/images/icons/branding_2023/General_SECURITY_Encryption10x.png b/source/images/icons/branding_2023/General_SECURITY_Encryption10x.png new file mode 100644 index 0000000000000000000000000000000000000000..1d0d3380a07c1a6e3a9c7dd94f4d152e25ca9f91 GIT binary patch literal 13755 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%0AopaEBUVf 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 - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + diff --git a/source/sdk/kotlin.txt b/source/sdk/kotlin.txt index adb5b98b1b9..fc4ad4b7639 100644 --- a/source/sdk/kotlin.txt +++ b/source/sdk/kotlin.txt @@ -186,3 +186,42 @@ Recommended Reading :icon-alt: Migrate Icon Learn why and how to switch from the Java SDK to the Kotlin SDK. + +Example Projects +---------------- + +Explore engineering and community-provided example projects to learn best +practices and common development patterns for Realm and Atlas App Services +using the Kotlin SDK. + +.. card-group:: + :columns: 3 + :style: extra-compact + + .. card:: + :headline: Property-Level Encryption + :cta: Example project + :url: https://github.com/realm/realm-kotlin-samples/blob/main/AppServicesUsageSamples/apps/property-encryption/README.md + :icon: /images/icons/branding_2023/General_SECURITY_Encryption10x.png + :icon-alt: Encryption Icon + + Enhance user data security with property-level encryption. + + .. card:: + :headline: User's Online State + :cta: Example project + :url: https://github.com/realm/realm-kotlin-samples/blob/main/AppServicesUsageSamples/apps/presence-detection/README.md + :icon: /images/icons/branding_2023/Technical_REALM_Offline10x.png + :icon-alt: Realm Offline Icon + + Detect connectivity and activity of users and devices. + + .. card:: + :headline: Connection State Change & Error Handling + :cta: Example project + :url: https://github.com/realm/realm-kotlin-samples/blob/main/AppServicesUsageSamples/apps/error-handling/README.md + :icon: /images/icons/branding_2023/General_CLOUD_Mobility10x.png + :icon-alt: Cloud Mobile Transfer Icon + + Learn best practices around handling Sync errors and client reset + strategies.