Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(DOCSP-26735): C++: Add a Quick Start page #2575

Merged
merged 2 commits into from
Feb 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions examples/cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,15 @@ FetchContent_Declare(

FetchContent_MakeAvailable(Catch2 cpprealm)

# add_executable(examples testHelpers.hpp testHelpersTests.cpp authentication.cpp define-object-model.cpp examples.cpp flexible-sync.cpp supported-types.cpp)
add_executable(examples authentication.cpp define-object-model.cpp examples.cpp filter-data.cpp flexible-sync.cpp supported-types.cpp)
add_executable(examples
authentication.cpp
define-object-model.cpp
examples.cpp
filter-data.cpp
flexible-sync.cpp
quick-start.cpp
supported-types.cpp
)

target_link_libraries(examples PRIVATE Catch2::Catch2WithMain)
target_link_libraries(examples PRIVATE cpprealm)
169 changes: 169 additions & 0 deletions examples/cpp/quick-start.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
#include <catch2/catch_test_macros.hpp>
#include <thread>
#include <future>
#include <string>
// :snippet-start: includes
#include <cpprealm/sdk.hpp>
// :snippet-end:

// :replace-start: {
// "terms": {
// "Local_": "",
// "Sync_": "",
// "userId.c_str()": "userId"
// }
// }

static const std::string APP_ID = "cpp-tester-uliix";

struct Local_Todo : realm::object<Local_Todo> {
realm::persisted<std::string> name;
realm::persisted<std::string> status;

static constexpr auto schema = realm::schema("Local_Todo",
realm::property<&Local_Todo::name>("name"),
realm::property<&Local_Todo::status>("status"));
};

// :snippet-start: model
struct Sync_Todo : realm::object<Sync_Todo> {
realm::persisted<realm::object_id> _id{realm::object_id::generate()};
realm::persisted<std::string> name;
realm::persisted<std::string> status;
// The ownerId property stores the user.identifier() of a
// logged-in user. Omit this property for the non-sync example.
realm::persisted<std::string> ownerId;

static constexpr auto schema = realm::schema("Sync_Todo",
realm::property<&Sync_Todo::_id, true>("_id"),
realm::property<&Sync_Todo::name>("name"),
realm::property<&Sync_Todo::status>("status"),
realm::property<&Sync_Todo::ownerId>("ownerId"));
};
// :snippet-end:

TEST_CASE("local quick start", "[realm][write]") {
// :snippet-start: realm-open
auto realm = realm::open<Local_Todo>();
// :snippet-end:

// :snippet-start: create-todo
auto todo = Local_Todo {
.name = "Create my first todo item",
.status = "In Progress"
};

realm.write([&realm, &todo] {
realm.add(todo);
});
// :snippet-end:

// :snippet-start: get-all-todos
auto todos = realm.objects<Local_Todo>();
// :snippet-end:
CHECK(todos.size() == 1);

// :snippet-start: filter
auto todosInProgress = todos.where([](auto const& todo) {
return todo.status == "In Progress";
});
// :snippet-end:
CHECK(todosInProgress.size() == 1);

// :snippet-start: watch-for-changes
auto token = todo.observe([&](auto&& change) {
try {
if (change.error) {
rethrow_exception(change.error);
}
if (change.is_deleted) {
std::cout << "The object was deleted.\n";
} else {
for (auto& propertyChange : change.property_changes) {
std::cout << "The object's " << propertyChange.name << " property has changed.\n";
CHECK(propertyChange.name == "status"); // :remove:
}
}
} catch (std::exception const& e) {
std::cerr << "Error: " << e.what() << "\n";
}
});
// :snippet-end:

// :snippet-start: modify-write-block
auto todoToUpdate = todosInProgress[0];
realm.write([&realm, &todoToUpdate] {
todoToUpdate.status = "Complete";
});
// :snippet-end:
CHECK(*todoToUpdate.status == "Complete");

// :snippet-start: delete
realm.write([&realm, &todo] {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cbush

If I replace this delete block with this code, instead:

 auto todoToDelete = todos[0];
 realm.write([&realm, &todoToDelete] {
     realm.remove(todoToDelete);
 });

I get this error:

/Users/dachary.carey/workspace/docs-realm/examples/cpp/quick-start.cpp:47: FAILED:
  {Unknown expression after the reported line}
due to unexpected exception with message:
  Index out of range.

I would expect it to work because in line 66 above, we verify that todos contains an item. I am assuming it has failed because of memory/unique_ptr shenanigans between 66 and here, but I could be misinterpreting this entirely.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nothing in your alternate code sticks out as wrong to me. Might be worth bringing this up with the SDK team to see if this is a known issue?

realm.remove(todo);
});
// :snippet-end:
}

TEST_CASE("sync quick start", "[realm][write][sync]") {
// :snippet-start: connect-to-backend
auto app = realm::App(APP_ID);
// :snippet-end:

// :snippet-start: authenticate-user
auto user = app.login(realm::App::credentials::anonymous()).get_future().get();
// :snippet-end:

// :snippet-start: open-synced-realm
auto sync_config = user.flexible_sync_configuration();
auto synced_realm_ref = realm::async_open<Sync_Todo>(sync_config).get_future().get();
auto realm = synced_realm_ref.resolve();
// :remove-start:
// Remove any existing subscriptions before adding the one for this example
auto clearInitialSubscriptions = realm.subscriptions().update([](auto &subs) {
subs.clear();
}).get_future().get();
CHECK(clearInitialSubscriptions == true);
CHECK(realm.subscriptions().size() == 0);
// :remove-end:
// For this example, get the userId for the Flexible Sync query
auto userId = user.identifier();
auto subscriptions = realm.subscriptions();
auto updateSubscriptionSuccess = subscriptions.update([&](realm::mutable_sync_subscription_set &subs) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this work?

Suggested change
auto updateSubscriptionSuccess = subscriptions.update([&](realm::mutable_sync_subscription_set &subs) {
auto updateSubscriptionSuccess = subscriptions.update([&](auto &subs) {

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that works in above where I'm clearing all subscriptions, but when I try to use it with add, I get this error:

/Users/dachary.carey/workspace/docs-realm/examples/cpp/quick-start.cpp:133:14: error: use 'template' keyword to treat 'add' as a dependent template name
        subs.add<Sync_Todo>("todos", [&userId](auto &obj) {
             ^
             template

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, nevermind!

subs.add<Sync_Todo>("todos", [&userId](auto &obj) {
// For this example, get only Sync_Todo items where the ownerId
// property value is equal to the userId of the logged-in user.
return obj.ownerId == userId;
});
}).get_future().get();
// :snippet-end:
CHECK(updateSubscriptionSuccess == true);

// The C++ SDK is currently missing a constructor to store a std::string
// So convert the userId std::string to a character array for persisting.
// TODO: Remove this and use the userId directly when the constructor is added.
// :snippet-start: write-to-synced-realm
auto todo = Sync_Todo {
.name = "Create a Sync todo item",
.status = "In Progress",
.ownerId = userId.c_str()
};

realm.write([&realm, &todo] {
realm.add(todo);
});

auto todos = realm.objects<Sync_Todo>();
// :snippet-end:
CHECK(todos.size() == 1);

// The C++ SDK does not yet expose `waitForUpload` and `waitForDownload`
// so add a delay to prevent the connection from terminating while syncing
sleep(5);
realm.write([&realm, &todo] {
realm.remove(todo);
});
sleep(5);
}

// :replace-end:
1 change: 1 addition & 0 deletions snooty.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ toc_landing_pages = [
# SDKs
"/sdk",
"/sdk/cpp",
"/sdk/cpp/application-services",
"/sdk/cpp/manage-users",
"/sdk/java",
"/sdk/java/api",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
auto user = app.login(realm::App::credentials::anonymous()).get_future().get();
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
auto app = realm::App(APP_ID);
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
auto todo = Todo {
.name = "Create my first todo item",
.status = "In Progress"
};

realm.write([&realm, &todo] {
realm.add(todo);
});
3 changes: 3 additions & 0 deletions source/examples/generated/cpp/quick-start.snippet.delete.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
realm.write([&realm, &todo] {
realm.remove(todo);
});
3 changes: 3 additions & 0 deletions source/examples/generated/cpp/quick-start.snippet.filter.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
auto todosInProgress = todos.where([](auto const& todo) {
return todo.status == "In Progress";
});
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
auto todos = realm.objects<Todo>();
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#include <cpprealm/sdk.hpp>
14 changes: 14 additions & 0 deletions source/examples/generated/cpp/quick-start.snippet.model.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
struct Todo : realm::object<Todo> {
realm::persisted<realm::object_id> _id{realm::object_id::generate()};
realm::persisted<std::string> name;
realm::persisted<std::string> status;
// The ownerId property stores the user.identifier() of a
// logged-in user. Omit this property for the non-sync example.
realm::persisted<std::string> ownerId;

static constexpr auto schema = realm::schema("Todo",
realm::property<&Todo::_id, true>("_id"),
realm::property<&Todo::name>("name"),
realm::property<&Todo::status>("status"),
realm::property<&Todo::ownerId>("ownerId"));
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
auto todoToUpdate = todosInProgress[0];
realm.write([&realm, &todoToUpdate] {
todoToUpdate.status = "Complete";
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
auto sync_config = user.flexible_sync_configuration();
auto synced_realm_ref = realm::async_open<Todo>(sync_config).get_future().get();
auto realm = synced_realm_ref.resolve();
// For this example, get the userId for the Flexible Sync query
auto userId = user.identifier();
auto subscriptions = realm.subscriptions();
auto updateSubscriptionSuccess = subscriptions.update([&](realm::mutable_sync_subscription_set &subs) {
subs.add<Todo>("todos", [&userId](auto &obj) {
// For this example, get only Todo items where the ownerId
// property value is equal to the userId of the logged-in user.
return obj.ownerId == userId;
});
}).get_future().get();
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
auto realm = realm::open<Todo>();
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
auto token = todo.observe([&](auto&& change) {
try {
if (change.error) {
rethrow_exception(change.error);
}
if (change.is_deleted) {
std::cout << "The object was deleted.\n";
} else {
for (auto& propertyChange : change.property_changes) {
std::cout << "The object's " << propertyChange.name << " property has changed.\n";
}
}
} catch (std::exception const& e) {
std::cerr << "Error: " << e.what() << "\n";
}
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
auto todo = Todo {
.name = "Create a Sync todo item",
.status = "In Progress",
.ownerId = userId
};

realm.write([&realm, &todo] {
realm.add(todo);
});

auto todos = realm.objects<Todo>();
4 changes: 2 additions & 2 deletions source/includes/note-unsupported-flex-sync-rql-operators.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
.. note::

Flexible Sync does not support all the query operators available in Realm
Query Language and LINQ. See :ref:`Flexible Sync RQL Limitations
<flexible-sync-rql-limitations>` for details.
Query Language and the SDK's query engine. See :ref:`Flexible Sync RQL
Limitations <flexible-sync-rql-limitations>` for details.
4 changes: 2 additions & 2 deletions source/sdk/cpp.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ C++ SDK (Alpha)

Why Realm Database? </sdk/cpp/realm-database>
Install Realm </sdk/cpp/install>
Quick Start </sdk/cpp/quick-start>
Model Data </sdk/cpp/model-data>
Configure & Open a Realm </sdk/cpp/realm-files/configure-and-open-a-realm>
CRUD </sdk/cpp/crud/>
React to Changes </sdk/cpp/react-to-changes>
Connect to App Services </sdk/cpp/app-services/connect-to-app>
Application Services </sdk/cpp/application-services>
Manage Users </sdk/cpp/manage-users>
Manage Sync Subscriptions </sdk/cpp/sync/sync-subscriptions>
Call an Atlas Function </sdk/cpp/app-services/call-a-function>
GitHub <https://github.com/realm/realm-cpp>
API Reference (Doxygen) <https://www.mongodb.com/docs/realm-sdks/cpp/latest/>

Expand Down
Loading