From a1b9875974b3eb49f9cfff02e5127936a3114af9 Mon Sep 17 00:00:00 2001 From: Dachary Date: Mon, 13 Feb 2023 17:09:58 -0500 Subject: [PATCH] (DOCSP-27496): C++: Add Map docs, clean up embedded object docs (#2578) ## Pull Request Info ### Jira The work for embedded object cleanup was minimal, so I combined it with adding docs for Map - this work is mainly about the Map docs. - https://jira.mongodb.org/browse/DOCSP-27496 - https://jira.mongodb.org/browse/DOCSP-27947 ### Staged Changes - [Supported Data Types](https://docs-mongodbcom-staging.corp.mongodb.com/realm/docsworker-xlarge/DOCSP-27947/sdk/cpp/model-data/supported-types/#map-dictionary): New section for Map, new supported property declaration example of map - [Create](https://docs-mongodbcom-staging.corp.mongodb.com/realm/docsworker-xlarge/DOCSP-27947/sdk/cpp/crud/create/#create-an-object-with-a-map-property): New section for creating an object with a map property - [Read](https://docs-mongodbcom-staging.corp.mongodb.com/realm/docsworker-xlarge/DOCSP-27947/sdk/cpp/crud/read/#read-a-map-property): New section for reading a map property - [Update](https://docs-mongodbcom-staging.corp.mongodb.com/realm/docsworker-xlarge/DOCSP-27947/sdk/cpp/crud/update/#overwrite-an-embedded-object-property): New sections for updating a map property, overwriting an embedded object property - [Delete](https://docs-mongodbcom-staging.corp.mongodb.com/realm/docsworker-xlarge/DOCSP-27947/sdk/cpp/crud/delete/#delete-map-keys-values): New section for deleting a map key ### 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) --- examples/cpp/CMakeLists.txt | 2 +- examples/cpp/define-object-model.cpp | 294 ++++++++++++------ examples/cpp/supported-types.cpp | 40 ++- ...object-model.snippet.create-map-object.cpp | 19 ++ ...-object-model.snippet.delete-map-value.cpp | 3 + ...ine-object-model.snippet.dog-map-model.cpp | 8 + ...-model.snippet.model-with-map-property.cpp | 16 + ...odel.snippet.overwrite-embedded-object.cpp | 14 + ...ne-object-model.snippet.read-map-value.cpp | 15 + ...-object-model.snippet.update-map-value.cpp | 7 + ...ported-types.snippet.required-map-type.cpp | 1 + source/sdk/cpp/crud/create.txt | 24 ++ source/sdk/cpp/crud/delete.txt | 11 + source/sdk/cpp/crud/read.txt | 12 + source/sdk/cpp/crud/update.txt | 37 ++- source/sdk/cpp/model-data/supported-types.txt | 24 ++ 16 files changed, 409 insertions(+), 118 deletions(-) create mode 100644 source/examples/generated/cpp/define-object-model.snippet.create-map-object.cpp create mode 100644 source/examples/generated/cpp/define-object-model.snippet.delete-map-value.cpp create mode 100644 source/examples/generated/cpp/define-object-model.snippet.dog-map-model.cpp create mode 100644 source/examples/generated/cpp/define-object-model.snippet.model-with-map-property.cpp create mode 100644 source/examples/generated/cpp/define-object-model.snippet.overwrite-embedded-object.cpp create mode 100644 source/examples/generated/cpp/define-object-model.snippet.read-map-value.cpp create mode 100644 source/examples/generated/cpp/define-object-model.snippet.update-map-value.cpp create mode 100644 source/examples/generated/cpp/supported-types.snippet.required-map-type.cpp diff --git a/examples/cpp/CMakeLists.txt b/examples/cpp/CMakeLists.txt index 928b5b9752..eacca1b67f 100644 --- a/examples/cpp/CMakeLists.txt +++ b/examples/cpp/CMakeLists.txt @@ -14,7 +14,7 @@ FetchContent_Declare( FetchContent_Declare( cpprealm GIT_REPOSITORY https://github.com/realm/realm-cpp.git - GIT_TAG ab580ca0891e88943960d33f5815cdb0004fc79a + GIT_TAG f5bdef8e958612143dea3615a0ba5d1b9eeddd36 ) FetchContent_MakeAvailable(Catch2 cpprealm) diff --git a/examples/cpp/define-object-model.cpp b/examples/cpp/define-object-model.cpp index 66725858d0..0e279789d7 100644 --- a/examples/cpp/define-object-model.cpp +++ b/examples/cpp/define-object-model.cpp @@ -1,10 +1,12 @@ #include #include +#include #include // :replace-start: { // "terms": { -// "ToOneRelationship_": "" +// "ToOneRelationship_": "", +// "Map_": "" // } // } @@ -51,6 +53,25 @@ struct Employee : realm::object { }; // :snippet-end: +// :snippet-start: model-with-map-property +struct Map_Employee : realm::object { + enum class WorkLocation { + HOME, OFFICE + }; + + realm::persisted _id; + realm::persisted firstName; + realm::persisted lastName; + realm::persisted> locationByDay; + + static constexpr auto schema = realm::schema("Map_Employee", + realm::property<&Map_Employee::_id, true>("_id"), + realm::property<&Map_Employee::firstName>("firstName"), + realm::property<&Map_Employee::lastName>("lastName"), + realm::property<&Map_Employee::locationByDay>("locationByDay")); +}; +// :snippet-end: + // :snippet-start: to-one-relationship struct ToOneRelationship_FavoriteToy : realm::object { realm::persisted _id; @@ -76,30 +97,6 @@ struct ToOneRelationship_Dog : realm::object { }; // :snippet-end: -#if 0 -// Temporarily removing this model as doubles are causing an error -struct GPSCoordinates: realm::object { - realm::persisted latitude; - realm::persisted longitude; - - static constexpr auto schema = realm::schema("GPSCoordinates", - realm::property<&GPSCoordinates::latitude>("latitude"), - realm::property<&GPSCoordinates::longitude>("longitude")); -}; - -struct PointOfInterest : realm::object { - realm::persisted _id; - realm::persisted name; - // To-one relationship objects must be optional - realm::persisted> gpsCoordinates; - - static constexpr auto schema = realm::schema("PointOfInterest", - realm::property<&PointOfInterest::_id, true>("_id"), - realm::property<&PointOfInterest::name>("name"), - realm::property<&PointOfInterest::gpsCoordinates>("gpsCoordinates")); -}; -#endif - // :snippet-start: to-many-relationship struct Company : realm::object { realm::persisted _id; @@ -116,44 +113,6 @@ struct Company : realm::object { }; // :snippet-end: -// struct EmbeddedFoo: realm::embedded_object { -// realm::persisted bar; - -// static constexpr auto schema = realm::schema("EmbeddedFoo", realm::property<&EmbeddedFoo::bar>("bar")); -// }; - -// struct Foo: realm::object { -// realm::persisted bar; -// realm::persisted> foo; - -// realm::persisted bar2; -// realm::persisted> foo2; - -// Foo() = default; -// Foo(const Foo&) = delete; -// static constexpr auto schema = realm::schema("Foo", -// realm::property<&Foo::bar>("bar"), -// realm::property<&Foo::foo>("foo"), -// realm::property<&Foo::bar2>("bar2"), -// realm::property<&Foo::foo2>("foo2")); -// }; -// TEST_CASE("SDK's version of create an embedded object", "[model][write]") { -// auto realm = realm::open(); - -// auto foo = Foo(); -// foo.foo = EmbeddedFoo{.bar=42}; -// realm.write([&foo, &realm]() { -// realm.add(foo); -// }); - -// CHECK(foo.foo->bar == 42); -// EmbeddedFoo e_foo = *(*foo.foo); - -// realm.write([&foo, &realm]() { -// realm.remove(foo); -// }); -// } - TEST_CASE("create an embedded object", "[model][write]") { // :snippet-start: create-embedded-object auto realm = realm::open(); @@ -250,42 +209,6 @@ TEST_CASE("create object with to-one relationship", "[model][write][relationship }); }; -#if 0 -// Temporarily removing this since the related model has been removed -TEST_CASE("create object with to-one relationship", "[model][write][relationship]") { - auto realm = realm::open(); - - auto gpsCoordinates = GPSCoordinates { .latitude = 36.0554, .longitude = 112.1401 }; - auto pointOfInterest = PointOfInterest { .name = "Grand Canyon Village" }; - pointOfInterest.gpsCoordinates = gpsCoordinates; - - realm.write([&realm, &pointOfInterest] { - realm.add(pointOfInterest); - }); - - SECTION("Test code example functions as intended") { - auto pointsOfInterest = realm.objects(); - auto namedGrandCanyonVillage = pointsOfInterest.where([](auto &pointOfInterest) { - return pointOfInterest.name == "Grand Canyon Village"; - }); - CHECK(namedGrandCanyonVillage.size() >= 1); - auto grandCanyonVillage = namedGrandCanyonVillage[0]; - std::cout << "Point of Interest: " << grandCanyonVillage.name << "\n"; - REQUIRE(grandCanyonVillage.name == "Grand Canyon Village"); - auto const &theseGpsCoordinates = *(grandCanyonVillage.gpsCoordinates); - static_assert(std::is_same_v const &>, "Dereference fail!"); // :remove: - auto latitude = *(theseGpsCoordinates->latitude); - static_assert(std::is_same_v, "Dereference fail!"); // :remove: - std::cout << "POI Latitude: " << latitude << "\n"; - REQUIRE(latitude == 36.0554); - } - // Clean up after the test - realm.write([&realm, &pointOfInterest] { - realm.remove(pointOfInterest); - }); -}; -#endif - TEST_CASE("create object with to-many relationship", "[model][write][relationship]") { // :snippet-start: create-object-with-to-many-relationship auto realm = realm::open(); @@ -373,6 +296,7 @@ TEST_CASE("update an embedded object", "[model][update]") { std::cout << "New email address: " << mongoDBPointer.contactDetails->emailAddress << "\n"; // :snippet-end: + CHECK(mongoDBPointer.contactDetails->emailAddress == "info@example.com"); } // Clean up after the test realm.write([&realm, &business] { @@ -380,4 +304,174 @@ TEST_CASE("update an embedded object", "[model][update]") { }); } -// :replace-end: \ No newline at end of file +TEST_CASE("overwrite an embedded object", "[model][update]") { + auto realm = realm::open(); + + auto business = Business { + .name = "MongoDB" + }; + + business.contactDetails = ContactDetails { + .emailAddress = "email@example.com", + .phoneNumber = "123-456-7890" + }; + + realm.write([&realm, &business] { + realm.add(business); + }); + SECTION("This example could fail but we still want to clean up after the test") { + // :snippet-start: overwrite-embedded-object + auto businesses = realm.objects(); + auto mongoDBPointer = businesses[0]; + + realm.write([&realm, &mongoDBPointer] { + auto newContactDetails = ContactDetails { + .emailAddress = "info@example.com", + .phoneNumber = "234-567-8901" + }; + + // Overwrite the embedded object + mongoDBPointer.contactDetails = newContactDetails; + }); + + std::cout << "New email address: " << mongoDBPointer.contactDetails->emailAddress << "\n"; + // :snippet-end: + CHECK(mongoDBPointer.contactDetails->emailAddress == "info@example.com"); + CHECK(mongoDBPointer.contactDetails->phoneNumber == "234-567-8901"); + } + // Clean up after the test + realm.write([&realm, &business] { + realm.remove(business); + }); +} + +TEST_CASE("test enum map object", "[model][write]") { + // :snippet-start: create-map-object + auto realm = realm::open(); + + auto employee = Map_Employee { + ._id = 8675309, + .firstName = "Tommy", + .lastName = "Tutone" + }; + + employee.locationByDay = { + { "Monday", Map_Employee::WorkLocation::HOME }, + { "Tuesday", Map_Employee::WorkLocation::OFFICE }, + { "Wednesday", Map_Employee::WorkLocation::HOME }, + { "Thursday", Map_Employee::WorkLocation::OFFICE } + }; + + realm.write([&realm, &employee] { + realm.add(employee); + employee.locationByDay["Friday"] = Map_Employee::WorkLocation::HOME; + }); + // :snippet-end: + CHECK(employee.locationByDay["Friday"] == Map_Employee::WorkLocation::HOME); + SECTION("Test code example functions as intended") { + // :snippet-start: read-map-value + auto employees = realm.objects(); + auto employeesNamedTommy = employees.where([](auto &employee) { + return employee.firstName == "Tommy"; + }); + REQUIRE(employeesNamedTommy.size() >= 1); // :remove: + auto tommy = employeesNamedTommy[0]; + // You can iterate through keys and values and do something with them + for (auto [k, v] : tommy.locationByDay) { + if (k == "Monday") CHECK(v == Map_Employee::WorkLocation::HOME); + else if (k == "Tuesday") CHECK(v == Map_Employee::WorkLocation::OFFICE); + } + // You can get an iterator for an element matching a key using `find()` + auto tuesdayIterator = tommy.locationByDay.find("Tuesday"); + CHECK(tuesdayIterator != tommy.locationByDay.end()); // :remove: + + // You can access values for keys like any other map type + auto mondayLocation = tommy.locationByDay["Monday"]; + // :snippet-end: + CHECK(tommy.locationByDay["Tuesday"] == Map_Employee::WorkLocation::OFFICE); // :remove: + // :snippet-start: update-map-value + // You can check that a key exists using `find` + auto findTuesday = tommy.locationByDay.find("Tuesday"); + if (findTuesday != tommy.locationByDay.end()) + realm.write([&realm, &tommy] { + tommy.locationByDay["Tuesday"] = Map_Employee::WorkLocation::HOME; + }); + ; + // :snippet-end: + CHECK(tommy.locationByDay["Tuesday"] == Map_Employee::WorkLocation::HOME); + // :snippet-start: delete-map-value + realm.write([&realm, &tommy] { + tommy.locationByDay.erase("Tuesday"); + }); + // :snippet-end: + CHECK(tommy.locationByDay.find("Tuesday") == tommy.locationByDay.end()); + } + // Clean up after test + realm.write([&realm, &employee] { + realm.remove(employee); + }); +} + +// :snippet-start: dog-map-model +struct Map_Dog : realm::object { + realm::persisted name; + realm::persisted> favoriteParkByCity; + + static constexpr auto schema = realm::schema("Map_Dog", + realm::property<&Map_Dog::name>("name"), + realm::property<&Map_Dog::favoriteParkByCity>("favoriteParkByCity")); +}; +// :snippet-end: + +// Note: the below test case was for a "simpler" version of a map +// while trying to debug delete functionality. It's not actually used +// in any of the code examples, although the model above is used on the Supported Types page +TEST_CASE("test string map object", "[model][write]") { + auto realm = realm::open(); + + auto dog = Map_Dog { + .name = "Maui" + }; + + dog.favoriteParkByCity = { + { "Boston", "Fort Point" }, + { "New York", "Central Park" } + }; + + realm.write([&realm, &dog] { + realm.add(dog); + }); + + SECTION("Test code example functions as intended") { + + auto dogs = realm.objects(); + auto dogsNamedMaui = dogs.where([](auto &dog) { + return dog.name == "Maui"; + }); + REQUIRE(dogsNamedMaui.size() >= 1); + auto maui = dogsNamedMaui[0]; + for (auto [k, v] : maui.favoriteParkByCity) { + if (k == "Boston") CHECK(v == "Fort Point"); + else if (k == "New York") CHECK(v == "Central Park"); + } + // Use `find()` for read-only access as `operator[]` could create an entry + auto favoriteBostonPark = maui.favoriteParkByCity.find("Boston"); + CHECK(favoriteBostonPark != maui.favoriteParkByCity.end()); + auto favoriteNewYorkPark = maui.favoriteParkByCity["New York"]; + CHECK(favoriteNewYorkPark == "Central Park"); + realm.write([&realm, &maui] { + maui.favoriteParkByCity["New York"] = "Some other park"; + }); + CHECK(favoriteNewYorkPark == "Some other park"); + realm.write([&realm, &maui] { + maui.favoriteParkByCity.erase("New York"); + }); + CHECK(maui.favoriteParkByCity.find("New York") == maui.favoriteParkByCity.end()); + } + // Clean up after test + realm.write([&realm, &dog] { + realm.remove(dog); + }); +} + +// :replace-end: diff --git a/examples/cpp/supported-types.cpp b/examples/cpp/supported-types.cpp index 051dcbb430..ee61348ebc 100644 --- a/examples/cpp/supported-types.cpp +++ b/examples/cpp/supported-types.cpp @@ -69,6 +69,9 @@ struct AllTypesObject : realm::object { // :snippet-start: required-mixed-type realm::persisted mixedName; // :snippet-end: + // :snippet-start: required-map-type + realm::persisted> mapName; + // :snippet-end: // :snippet-start: required-list realm::persisted> listTypeName; // :snippet-end: @@ -89,6 +92,7 @@ struct AllTypesObject : realm::object { realm::property<&AllTypesObject::uuidName>("uuidName"), realm::property<&AllTypesObject::optUuidName>("optUuidName"), realm::property<&AllTypesObject::mixedName>("mixedName"), + realm::property<&AllTypesObject::mapName>("mapName"), realm::property<&AllTypesObject::listTypeName>("listTypeName")); }; @@ -112,6 +116,7 @@ TEST_CASE("required supported types", "[write]") { realm.write([&realm, &allRequiredTypesObject] { realm.add(allRequiredTypesObject); allRequiredTypesObject.listTypeName.push_back("Rex"); + allRequiredTypesObject.mapName["some key"] = "some value"; }); auto allTypeObjects = realm.objects(); @@ -123,6 +128,7 @@ TEST_CASE("required supported types", "[write]") { REQUIRE(*specificAllTypeObjects.enumName == AllTypesObject::Enum::one); REQUIRE(specificAllTypeObjects.binaryDataName == std::vector{0,1,2}); REQUIRE(*specificAllTypeObjects.mixedName == realm::mixed("mixed data")); + REQUIRE(specificAllTypeObjects.mapName["some key"] == "some value"); REQUIRE(specificAllTypeObjects.listTypeName[0] == "Rex"); realm.write([&realm, &allRequiredTypesObject] { @@ -159,24 +165,26 @@ TEST_CASE("optional supported types", "[write]") { realm.write([&realm, &allRequiredAndOptionalTypesObject] { realm.add(allRequiredAndOptionalTypesObject); allRequiredAndOptionalTypesObject.listTypeName.push_back("Rex"); + allRequiredAndOptionalTypesObject.mapName["some key"] = "some value"; }); - auto allTypeObjects = realm.objects(); - auto specificAllTypeObjects = allTypeObjects[0]; - REQUIRE(specificAllTypeObjects.boolName == true); - REQUIRE(specificAllTypeObjects.intName == 1); - REQUIRE(specificAllTypeObjects.doubleName == 1.1); - REQUIRE(specificAllTypeObjects.stringName == "Fluffy"); - REQUIRE(*specificAllTypeObjects.enumName == AllTypesObject::Enum::one); - REQUIRE(specificAllTypeObjects.binaryDataName == std::vector{0,1,2}); - REQUIRE(*specificAllTypeObjects.mixedName == realm::mixed("mixed data")); - REQUIRE(specificAllTypeObjects.listTypeName[0] == "Rex"); - REQUIRE(specificAllTypeObjects.optBoolName == false); - REQUIRE(*specificAllTypeObjects.optIntName == 42); - REQUIRE(specificAllTypeObjects.optDoubleName == 42.42); - REQUIRE(specificAllTypeObjects.optStringName == "Maui"); - REQUIRE(*specificAllTypeObjects.optEnumName == AllTypesObject::Enum::two); - REQUIRE(*specificAllTypeObjects.optBinaryDataName == std::vector{3,4,5}); + auto allTypeObjects = realm.objects(); + auto specificAllTypeObjects = allTypeObjects[0]; + REQUIRE(specificAllTypeObjects.boolName == true); + REQUIRE(specificAllTypeObjects.intName == 1); + REQUIRE(specificAllTypeObjects.doubleName == 1.1); + REQUIRE(specificAllTypeObjects.stringName == "Fluffy"); + REQUIRE(*specificAllTypeObjects.enumName == AllTypesObject::Enum::one); + REQUIRE(specificAllTypeObjects.binaryDataName == std::vector{0,1,2}); + REQUIRE(*specificAllTypeObjects.mixedName == realm::mixed("mixed data")); + REQUIRE(specificAllTypeObjects.mapName["some key"] == "some value"); + REQUIRE(specificAllTypeObjects.listTypeName[0] == "Rex"); + REQUIRE(specificAllTypeObjects.optBoolName == false); + REQUIRE(*specificAllTypeObjects.optIntName == 42); + REQUIRE(specificAllTypeObjects.optDoubleName == 42.42); + REQUIRE(specificAllTypeObjects.optStringName == "Maui"); + REQUIRE(*specificAllTypeObjects.optEnumName == AllTypesObject::Enum::two); + REQUIRE(*specificAllTypeObjects.optBinaryDataName == std::vector{3,4,5}); realm.write([&realm, &allRequiredAndOptionalTypesObject] { realm.remove(allRequiredAndOptionalTypesObject); diff --git a/source/examples/generated/cpp/define-object-model.snippet.create-map-object.cpp b/source/examples/generated/cpp/define-object-model.snippet.create-map-object.cpp new file mode 100644 index 0000000000..888ba42815 --- /dev/null +++ b/source/examples/generated/cpp/define-object-model.snippet.create-map-object.cpp @@ -0,0 +1,19 @@ +auto realm = realm::open(); + +auto employee = Employee { + ._id = 8675309, + .firstName = "Tommy", + .lastName = "Tutone" +}; + +employee.locationByDay = { + { "Monday", Employee::WorkLocation::HOME }, + { "Tuesday", Employee::WorkLocation::OFFICE }, + { "Wednesday", Employee::WorkLocation::HOME }, + { "Thursday", Employee::WorkLocation::OFFICE } +}; + +realm.write([&realm, &employee] { + realm.add(employee); + employee.locationByDay["Friday"] = Employee::WorkLocation::HOME; +}); diff --git a/source/examples/generated/cpp/define-object-model.snippet.delete-map-value.cpp b/source/examples/generated/cpp/define-object-model.snippet.delete-map-value.cpp new file mode 100644 index 0000000000..27e09b051d --- /dev/null +++ b/source/examples/generated/cpp/define-object-model.snippet.delete-map-value.cpp @@ -0,0 +1,3 @@ +realm.write([&realm, &tommy] { + tommy.locationByDay.erase("Tuesday"); +}); diff --git a/source/examples/generated/cpp/define-object-model.snippet.dog-map-model.cpp b/source/examples/generated/cpp/define-object-model.snippet.dog-map-model.cpp new file mode 100644 index 0000000000..ada5c19d03 --- /dev/null +++ b/source/examples/generated/cpp/define-object-model.snippet.dog-map-model.cpp @@ -0,0 +1,8 @@ +struct Dog : realm::object { + realm::persisted name; + realm::persisted> favoriteParkByCity; + + static constexpr auto schema = realm::schema("Dog", + realm::property<&Dog::name>("name"), + realm::property<&Dog::favoriteParkByCity>("favoriteParkByCity")); +}; diff --git a/source/examples/generated/cpp/define-object-model.snippet.model-with-map-property.cpp b/source/examples/generated/cpp/define-object-model.snippet.model-with-map-property.cpp new file mode 100644 index 0000000000..6ce020a398 --- /dev/null +++ b/source/examples/generated/cpp/define-object-model.snippet.model-with-map-property.cpp @@ -0,0 +1,16 @@ +struct Employee : realm::object { + enum class WorkLocation { + HOME, OFFICE + }; + + realm::persisted _id; + realm::persisted firstName; + realm::persisted lastName; + realm::persisted> locationByDay; + + static constexpr auto schema = realm::schema("Employee", + realm::property<&Employee::_id, true>("_id"), + realm::property<&Employee::firstName>("firstName"), + realm::property<&Employee::lastName>("lastName"), + realm::property<&Employee::locationByDay>("locationByDay")); +}; diff --git a/source/examples/generated/cpp/define-object-model.snippet.overwrite-embedded-object.cpp b/source/examples/generated/cpp/define-object-model.snippet.overwrite-embedded-object.cpp new file mode 100644 index 0000000000..d53ee17160 --- /dev/null +++ b/source/examples/generated/cpp/define-object-model.snippet.overwrite-embedded-object.cpp @@ -0,0 +1,14 @@ +auto businesses = realm.objects(); +auto mongoDBPointer = businesses[0]; + +realm.write([&realm, &mongoDBPointer] { + auto newContactDetails = ContactDetails { + .emailAddress = "info@example.com", + .phoneNumber = "234-567-8901" + }; + + // Overwrite the embedded object + mongoDBPointer.contactDetails = newContactDetails; +}); + +std::cout << "New email address: " << mongoDBPointer.contactDetails->emailAddress << "\n"; diff --git a/source/examples/generated/cpp/define-object-model.snippet.read-map-value.cpp b/source/examples/generated/cpp/define-object-model.snippet.read-map-value.cpp new file mode 100644 index 0000000000..5a5a1b51e4 --- /dev/null +++ b/source/examples/generated/cpp/define-object-model.snippet.read-map-value.cpp @@ -0,0 +1,15 @@ +auto employees = realm.objects(); +auto employeesNamedTommy = employees.where([](auto &employee) { + return employee.firstName == "Tommy"; +}); +auto tommy = employeesNamedTommy[0]; +// You can iterate through keys and values and do something with them +for (auto [k, v] : tommy.locationByDay) { + if (k == "Monday") CHECK(v == Employee::WorkLocation::HOME); + else if (k == "Tuesday") CHECK(v == Employee::WorkLocation::OFFICE); +} +// You can get an iterator for an element matching a key using `find()` +auto tuesdayIterator = tommy.locationByDay.find("Tuesday"); + +// You can access values for keys like any other map type +auto mondayLocation = tommy.locationByDay["Monday"]; diff --git a/source/examples/generated/cpp/define-object-model.snippet.update-map-value.cpp b/source/examples/generated/cpp/define-object-model.snippet.update-map-value.cpp new file mode 100644 index 0000000000..36be76168a --- /dev/null +++ b/source/examples/generated/cpp/define-object-model.snippet.update-map-value.cpp @@ -0,0 +1,7 @@ +// You can check that a key exists using `find` +auto findTuesday = tommy.locationByDay.find("Tuesday"); +if (findTuesday != tommy.locationByDay.end()) + realm.write([&realm, &tommy] { + tommy.locationByDay["Tuesday"] = Employee::WorkLocation::HOME; + }); +; diff --git a/source/examples/generated/cpp/supported-types.snippet.required-map-type.cpp b/source/examples/generated/cpp/supported-types.snippet.required-map-type.cpp new file mode 100644 index 0000000000..3c166088d8 --- /dev/null +++ b/source/examples/generated/cpp/supported-types.snippet.required-map-type.cpp @@ -0,0 +1 @@ +realm::persisted> mapName; diff --git a/source/sdk/cpp/crud/create.txt b/source/sdk/cpp/crud/create.txt index 650356f4cb..dcbe90a93d 100644 --- a/source/sdk/cpp/crud/create.txt +++ b/source/sdk/cpp/crud/create.txt @@ -170,3 +170,27 @@ For more information about modeling a to-many relationship, refer to: .. literalinclude:: /examples/generated/cpp/define-object-model.snippet.to-many-relationship.cpp :language: cpp + +.. _cpp-create-object-map-property: + +Create an Object with a Map Property +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When you create an object that has a :cpp-sdk:`map property +`, you can set the values for +keys in a few ways: + +- Set keys and values on the object and then add the object to the realm +- Set the object's keys and values directly inside a write transaction + +.. literalinclude:: /examples/generated/cpp/define-object-model.snippet.create-map-object.cpp + :language: cpp + +Model +````` + +For more information about supported map data types, refer to: +:ref:`cpp-map`. + +.. literalinclude:: /examples/generated/cpp/define-object-model.snippet.model-with-map-property.cpp + :language: cpp diff --git a/source/sdk/cpp/crud/delete.txt b/source/sdk/cpp/crud/delete.txt index 555ffb8afd..c32f0a1acb 100644 --- a/source/sdk/cpp/crud/delete.txt +++ b/source/sdk/cpp/crud/delete.txt @@ -28,3 +28,14 @@ inside of a write transaction. .. literalinclude:: /examples/generated/cpp/examples.snippet.delete-an-object.cpp :language: cpp + +.. _cpp-delete-map: + +Delete Map Keys/Values +~~~~~~~~~~~~~~~~~~~~~~ + +To delete a :cpp-sdk:`map key `, +pass the key name to ``erase()``: + +.. literalinclude:: /examples/generated/cpp/define-object-model.snippet.delete-map-value.cpp + :language: cpp diff --git a/source/sdk/cpp/crud/read.txt b/source/sdk/cpp/crud/read.txt index bbead1c252..29dc4970c0 100644 --- a/source/sdk/cpp/crud/read.txt +++ b/source/sdk/cpp/crud/read.txt @@ -170,3 +170,15 @@ set, or access the object at a specific index. Additionally, you can iterate through the results, or observe a results set for changes. + +.. _cpp-read-and-iterate-map: + +Read a Map Property +~~~~~~~~~~~~~~~~~~~ + +You can iterate and check the values of a realm :cpp-sdk:`map property +` +as you would a standard C++ `map `__: + +.. literalinclude:: /examples/generated/cpp/define-object-model.snippet.read-map-value.cpp + :language: cpp diff --git a/source/sdk/cpp/crud/update.txt b/source/sdk/cpp/crud/update.txt index 5721dd695f..461398335f 100644 --- a/source/sdk/cpp/crud/update.txt +++ b/source/sdk/cpp/crud/update.txt @@ -52,4 +52,39 @@ This example uses the following model: .. literalinclude:: /examples/generated/cpp/define-object-model.snippet.model-with-embedded-object.cpp :language: cpp -.. TODO: After std::unique_ptr is cleared up in the SDK, update embedded object examples +Overwrite an Embedded Object Property +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To overwrite an embedded object, reassign the embedded object property +to a new instance in a write transaction. + +.. literalinclude:: /examples/generated/cpp/define-object-model.snippet.overwrite-embedded-object.cpp + :language: cpp + +Model +````` + +This example uses the following model: + +.. literalinclude:: /examples/generated/cpp/define-object-model.snippet.model-with-embedded-object.cpp + :language: cpp + +.. _cpp-read-and-iterate-map: + +Update a Map Property +~~~~~~~~~~~~~~~~~~~~~ + +You can update a realm :cpp-sdk:`map property +` +as you would a standard C++ `map `__: + +.. literalinclude:: /examples/generated/cpp/define-object-model.snippet.update-map-value.cpp + :language: cpp + +Model +````` + +This example uses the following model: + +.. literalinclude:: /examples/generated/cpp/define-object-model.snippet.model-with-map-property.cpp + :language: cpp diff --git a/source/sdk/cpp/model-data/supported-types.txt b/source/sdk/cpp/model-data/supported-types.txt index a5a46e9f90..0a27bd95c1 100644 --- a/source/sdk/cpp/model-data/supported-types.txt +++ b/source/sdk/cpp/model-data/supported-types.txt @@ -96,6 +96,11 @@ Property Cheat Sheet :language: cpp :copyable: false - N/A + * - Map + - .. literalinclude:: /examples/generated/cpp/supported-types.snippet.required-map-type.cpp + :language: cpp + :copyable: false + - N/A * - List - .. literalinclude:: /examples/generated/cpp/supported-types.snippet.required-list.cpp :language: cpp @@ -128,3 +133,22 @@ Some of the supported types above are aliases for: `__ to store a ``time_point`` relative to the ``system_clock``: ``>`` + +.. _cpp-map: + +Map/Dictionary +~~~~~~~~~~~~~~ + +The :cpp-sdk:`Map ` is an +associative array that contains key-value pairs with unique keys. + +You can declare a Map as a property of an object: + +.. literalinclude:: /examples/generated/cpp/define-object-model.snippet.dog-map-model.cpp + :language: cpp + +String is the only supported type for a map key, but map values can be: + +- Required versions of any of the SDK's supported data types +- Optional user-defined object links +- Optional embedded objects