From 10d853c522a36a24b1b340caeab4adfecd9360f1 Mon Sep 17 00:00:00 2001 From: cbullinger Date: Tue, 19 Sep 2023 10:54:36 -0400 Subject: [PATCH] Fix failing tests --- .../mongodb/realm/realmkmmapp/CreateTest.kt | 4 +- .../mongodb/realm/realmkmmapp/DataTypes.kt | 54 +----- .../com/mongodb/realm/realmkmmapp/Schema.kt | 42 +++-- .../mongodb/realm/realmkmmapp/SchemaTest.kt | 158 +++++++++++++++++- ...nippet.define-realm-dictionary-property.kt | 4 +- ...chemaTest.snippet.timestamp-workaround.kt} | 0 .../realm-database/open-and-close-a-realm.txt | 2 + .../realm-database/schemas/relationships.txt | 2 - .../schemas/supported-types.txt | 2 +- 9 files changed, 199 insertions(+), 69 deletions(-) rename source/examples/generated/kotlin/{DataTypes.snippet.timestamp-workaround.kt => SchemaTest.snippet.timestamp-workaround.kt} (100%) diff --git a/examples/kotlin/shared/src/commonTest/kotlin/com/mongodb/realm/realmkmmapp/CreateTest.kt b/examples/kotlin/shared/src/commonTest/kotlin/com/mongodb/realm/realmkmmapp/CreateTest.kt index fe45682f8a..12b32c7f3a 100644 --- a/examples/kotlin/shared/src/commonTest/kotlin/com/mongodb/realm/realmkmmapp/CreateTest.kt +++ b/examples/kotlin/shared/src/commonTest/kotlin/com/mongodb/realm/realmkmmapp/CreateTest.kt @@ -78,7 +78,7 @@ class CreateTest: RealmTest() { val config = RealmConfiguration.Builder( schema = setOf(RealmDictionary_Frog::class) // Pass the defined class as the object schema ) - .directory("/tmp/") // default location for jvm is... in the project root + .inMemory() .build() val realm = Realm.open(config) Log.v("Successfully opened realm: ${realm.configuration.name}") @@ -114,7 +114,7 @@ class CreateTest: RealmTest() { val config = RealmConfiguration.Builder( schema = setOf(RealmDictionary_Frog::class) // Pass the defined class as the object schema ) - .directory("/tmp/") // default location for jvm is... in the project root + .inMemory() .build() val realm = Realm.open(config) Log.v("Successfully opened realm: ${realm.configuration.name}") diff --git a/examples/kotlin/shared/src/commonTest/kotlin/com/mongodb/realm/realmkmmapp/DataTypes.kt b/examples/kotlin/shared/src/commonTest/kotlin/com/mongodb/realm/realmkmmapp/DataTypes.kt index 3360cd5d20..37ff6f38d0 100644 --- a/examples/kotlin/shared/src/commonTest/kotlin/com/mongodb/realm/realmkmmapp/DataTypes.kt +++ b/examples/kotlin/shared/src/commonTest/kotlin/com/mongodb/realm/realmkmmapp/DataTypes.kt @@ -5,10 +5,10 @@ import io.realm.kotlin.ext.* import io.realm.kotlin.internal.platform.runBlocking import io.realm.kotlin.query.RealmResults import io.realm.kotlin.types.* -import kotlinx.datetime.Instant import org.mongodb.kbson.Decimal128 import org.mongodb.kbson.ObjectId import kotlin.test.* + class CustomObjectType : RealmObject { var uuid: RealmUUID = RealmUUID.random() } @@ -172,51 +172,6 @@ class RealmSupportedTypes : RealmObject { // :snippet-end: } -// :snippet-start: timestamp-workaround -// model class that stores an Instant (kotlinx-datetime) field as a RealmInstant via a conversion -class RealmInstantConversion : RealmObject { - private var _timestamp: RealmInstant = RealmInstant.from(0, 0) - public var timestamp: Instant - get() { - return _timestamp.toInstant() - } - set(value) { - _timestamp = value.toRealmInstant() - } -} - -fun RealmInstant.toInstant(): Instant { - val sec: Long = this.epochSeconds - // The value always lies in the range `-999_999_999..999_999_999`. - // minus for timestamps before epoch, positive for after - val nano: Int = this.nanosecondsOfSecond - - return if (sec >= 0) { // For positive timestamps, conversion can happen directly - Instant.fromEpochSeconds(sec, nano.toLong()) - } else { - // For negative timestamps, RealmInstant starts from the higher value with negative - // nanoseconds, while Instant starts from the lower value with positive nanoseconds - // TODO This probably breaks at edge cases like MIN/MAX - Instant.fromEpochSeconds(sec - 1, 1_000_000 + nano.toLong()) - } -} - -fun Instant.toRealmInstant(): RealmInstant { - val sec: Long = this.epochSeconds - // The value is always positive and lies in the range `0..999_999_999`. - val nano: Int = this.nanosecondsOfSecond - - return if (sec >= 0) { // For positive timestamps, conversion can happen directly - RealmInstant.from(sec, nano) - } else { - // For negative timestamps, RealmInstant starts from the higher value with negative - // nanoseconds, while Instant starts from the lower value with positive nanoseconds - // TODO This probably breaks at edge cases like MIN/MAX - RealmInstant.from(sec + 1, -1_000_000 + nano) - } -} -// :snippet-end: - class SupportedDataTypesTest : RealmTest() { @Test fun populateEnumPropertiesTest() { @@ -362,6 +317,7 @@ class SupportedDataTypesTest : RealmTest() { realm.close() } } + @Test fun populateBSONPropertiesWithValuesTest() { runBlocking { @@ -393,6 +349,7 @@ class SupportedDataTypesTest : RealmTest() { realm.close() } } + @Test fun populateRealmDefaultPropertiesTest() { runBlocking { @@ -421,10 +378,12 @@ class SupportedDataTypesTest : RealmTest() { realm.close() } } + @Test fun populateRealmPropertiesWithValuesTest() { runBlocking { val config = RealmConfiguration.Builder(setOf(RealmSupportedTypes::class, CustomObjectType::class)) + .name("populatePropertiesWithValues.realm") .inMemory() .build() val realm = Realm.open(config) @@ -477,6 +436,7 @@ class SupportedDataTypesTest : RealmTest() { realm.close() } } + @Test fun populateRealmObjectDefaultPropertiesTest() { runBlocking { @@ -509,10 +469,12 @@ class SupportedDataTypesTest : RealmTest() { realm.close() } } + @Test fun populateRealmObjectPropertiesWithValuesTest() { runBlocking { val config = RealmConfiguration.Builder(setOf(EmbeddedObjectType::class, AnotherCustomObjectType::class, CustomObjectType::class)) + .name("populateObjectPropertiesWithValues.realm") .inMemory() .build() val realm = Realm.open(config) diff --git a/examples/kotlin/shared/src/commonTest/kotlin/com/mongodb/realm/realmkmmapp/Schema.kt b/examples/kotlin/shared/src/commonTest/kotlin/com/mongodb/realm/realmkmmapp/Schema.kt index 472c863e32..b829d04c6e 100644 --- a/examples/kotlin/shared/src/commonTest/kotlin/com/mongodb/realm/realmkmmapp/Schema.kt +++ b/examples/kotlin/shared/src/commonTest/kotlin/com/mongodb/realm/realmkmmapp/Schema.kt @@ -13,13 +13,16 @@ import org.mongodb.kbson.ObjectId // "terms": { // "ExampleRealmObject_": "", // "RealmList_": "", +// "ExampleRealmDictionary_": "", // "RealmDictionary_": "", +// "ExampleRealmSet_": "", // "RealmSet_": "" // } // } /* ** Define Realm Object Model page examples ** +* Tested in SchemaTest.kt file */ // :snippet-start: define-realm-object @@ -74,43 +77,62 @@ class RealmList_Pond : RealmObject { } // :snippet-end: -/* -Tested in Create, Read, Update, and Delete.kt files - */ + // :snippet-start: define-a-realm-set // RealmSet can be any supported primitive or // BSON type or a RealmObject -class RealmSet_Frog : RealmObject { +class ExampleRealmSet_Frog : RealmObject { var _id: ObjectId = ObjectId() var name: String = "" // Set of RealmObject type (CANNOT be nullable) - var favoriteSnacks: RealmSet = realmSetOf() + var favoriteSnacks: RealmSet = realmSetOf() // Set of primitive type (can be nullable) var favoriteWeather: RealmSet = realmSetOf() } -class RealmSet_Snack : RealmObject { +class ExampleRealmSet_Snack : RealmObject { var _id: ObjectId = ObjectId() var name: String = "" } // :snippet-end: - /* Tested in Create, Read, Update, and Delete.kt files */ +class RealmSet_Frog : RealmObject { + var _id: ObjectId = ObjectId() + var name: String = "" + + var favoriteSnacks: RealmSet = realmSetOf() +} + +class RealmSet_Snack : RealmObject { + var _id: ObjectId = ObjectId() + var name: String = "" +} + // :snippet-start: define-realm-dictionary-property // RealmDictionary can be any supported // primitive or BSON types, a RealmObject, or // an EmbeddedRealmObject -class RealmDictionary_Frog : RealmObject { +class ExampleRealmDictionary_Frog : RealmObject { var _id: ObjectId = ObjectId() var name: String = "" // Dictionary of RealmObject type (value MUST be nullable) - var favoriteFriendsByForest: RealmDictionary = realmDictionaryOf() + var favoriteFriendsByPond: RealmDictionary = realmDictionaryOf() // Dictionary of EmbeddedRealmObject type (value MUST be nullable) - var favoriteForestsByForest: RealmDictionary = realmDictionaryOf() + var favoriteTreesInForest: RealmDictionary = realmDictionaryOf() // Dictionary of primitive type (value can be nullable) var favoritePondsByForest: RealmDictionary = realmDictionaryOf() } // :snippet-end: +/* +Tested in Create, Read, Update, and Delete.kt files + */ +class RealmDictionary_Frog : RealmObject { + var _id: ObjectId = ObjectId() + var name: String = "" + var favoriteFriendsByForest: RealmDictionary = realmDictionaryOf() + var favoritePondsByForest: RealmDictionary = realmDictionaryOf() +} + // :replace-end: diff --git a/examples/kotlin/shared/src/commonTest/kotlin/com/mongodb/realm/realmkmmapp/SchemaTest.kt b/examples/kotlin/shared/src/commonTest/kotlin/com/mongodb/realm/realmkmmapp/SchemaTest.kt index 0915c35491..ade84c2f78 100644 --- a/examples/kotlin/shared/src/commonTest/kotlin/com/mongodb/realm/realmkmmapp/SchemaTest.kt +++ b/examples/kotlin/shared/src/commonTest/kotlin/com/mongodb/realm/realmkmmapp/SchemaTest.kt @@ -9,16 +9,15 @@ import io.realm.kotlin.ext.realmListOf import io.realm.kotlin.ext.realmSetOf import io.realm.kotlin.internal.platform.runBlocking import io.realm.kotlin.query.RealmResults -import io.realm.kotlin.types.RealmList -import io.realm.kotlin.types.RealmObject -import io.realm.kotlin.types.RealmSet -import io.realm.kotlin.types.RealmUUID +import io.realm.kotlin.types.* import io.realm.kotlin.types.annotations.Ignore import io.realm.kotlin.types.annotations.Index import io.realm.kotlin.types.annotations.PersistedName import io.realm.kotlin.types.annotations.PrimaryKey +import kotlinx.datetime.Instant import org.mongodb.kbson.ObjectId import kotlin.test.Test +import kotlin.test.assertEquals // :replace-start: { // "terms": { @@ -110,6 +109,51 @@ class PersistedName_Cat : RealmObject { } // :snippet-end: +// :snippet-start: timestamp-workaround +// model class that stores an Instant (kotlinx-datetime) field as a RealmInstant via a conversion +class RealmInstantConversion : RealmObject { + private var _timestamp: RealmInstant = RealmInstant.from(0, 0) + public var timestamp: Instant + get() { + return _timestamp.toInstant() + } + set(value) { + _timestamp = value.toRealmInstant() + } +} + +fun RealmInstant.toInstant(): Instant { + val sec: Long = this.epochSeconds + // The value always lies in the range `-999_999_999..999_999_999`. + // minus for timestamps before epoch, positive for after + val nano: Int = this.nanosecondsOfSecond + + return if (sec >= 0) { // For positive timestamps, conversion can happen directly + Instant.fromEpochSeconds(sec, nano.toLong()) + } else { + // For negative timestamps, RealmInstant starts from the higher value with negative + // nanoseconds, while Instant starts from the lower value with positive nanoseconds + // TODO This probably breaks at edge cases like MIN/MAX + Instant.fromEpochSeconds(sec - 1, 1_000_000 + nano.toLong()) + } +} + +fun Instant.toRealmInstant(): RealmInstant { + val sec: Long = this.epochSeconds + // The value is always positive and lies in the range `0..999_999_999`. + val nano: Int = this.nanosecondsOfSecond + + return if (sec >= 0) { // For positive timestamps, conversion can happen directly + RealmInstant.from(sec, nano) + } else { + // For negative timestamps, RealmInstant starts from the higher value with negative + // nanoseconds, while Instant starts from the lower value with positive nanoseconds + // TODO This probably breaks at edge cases like MIN/MAX + RealmInstant.from(sec + 1, -1_000_000 + nano) + } +} +// :snippet-end: + class SchemaTest: RealmTest() { @Test fun createUUIDTypes() { @@ -143,10 +187,112 @@ class SchemaTest: RealmTest() { _id = RealmUUID.from("46423f1b-ce3e-4a7e-812f-004cf9c42d76") }) } - realm.close() } } -} + + /* + ** Test objects defined in Schema.kt ** + */ + @Test + fun createRealmObjectsTest() { + runBlocking { + val config = RealmConfiguration.Builder(setOf(ExampleRealmObject_Frog::class, ExampleRealmSet_Frog::class, ExampleRealmSet_Snack::class, ExampleRealmDictionary_Frog::class, ExampleRealmObject_Forest::class, RealmList_Frog::class, RealmList_Pond::class)) + .inMemory() + .build() + val realm = Realm.open(config) + Log.v("Successfully opened realm: ${realm.configuration.name}") + + realm.write { + deleteAll() + + // create basic frog object + val frogID = ObjectId() + copyToRealm(ExampleRealmObject_Frog().apply { + name = "Kermit" + _id = frogID + age = 12 + species = "bullfrog" + owner = "Gonzo" + }) + val frog = query().find().first() + assertEquals("Kermit", frog.name) + assertEquals(frogID, frog._id) + delete(frog) + assertEquals(0, query().find().size) + + // create realm list object + copyToRealm(RealmList_Frog().apply { + name = "Timerk" + favoritePonds.add(RealmList_Pond().apply { + name = "Pond1" + }) + favoritePonds.add(RealmList_Pond().apply { + name = "Pond2" + }) + favoriteForests.add(ExampleRealmObject_Forest().apply { + name = "Forest1" + }) + favoriteForests.add(ExampleRealmObject_Forest().apply { + name = "Forest2" + }) + favoriteWeather.add("rain") + favoriteWeather.add("snow") + }) + val realmListFrog = query().find().first() + assertEquals("Timerk", realmListFrog.name) + assertEquals(2, realmListFrog.favoritePonds.size) + assertEquals(2, realmListFrog.favoriteForests.size) + assertEquals(2, realmListFrog.favoriteWeather.size) + delete(realmListFrog) + assertEquals(0, query().find().size) + + // create realm set object + copyToRealm(ExampleRealmSet_Frog().apply { + name = "Kermit2" + favoriteSnacks.add(ExampleRealmSet_Snack().apply { + name = "some flies" + }) + favoriteSnacks.add(ExampleRealmSet_Snack().apply { + name = "some worms" + }) + favoriteWeather.add("rain") + }) + val realmSetFrog = query().find().first() + assertEquals("Kermit2", realmSetFrog.name) + assertEquals(2, realmSetFrog.favoriteSnacks.size) + assertEquals(1, realmSetFrog.favoriteWeather.size) + delete(realmSetFrog) + assertEquals(0, query().find().size) + + // create realm dictionary object + val frog3Id = ObjectId() + copyToRealm(ExampleRealmDictionary_Frog().apply { + name = "Kermit3" + _id = frog3Id + favoriteFriendsByPond["Pond1"] = ExampleRealmDictionary_Frog().apply { + name = "Frog1" + } + favoriteTreesInForest["Forest1"] = ExampleRealmObject_Forest().apply { + name = "Tree1" + } + favoritePondsByForest["Forest2"] = "Pond1" + + }) + val realmDictionaryFrog = query().find().first() + assertEquals("Kermit3", realmDictionaryFrog.name) + assertEquals(frog3Id, realmDictionaryFrog._id) + assertEquals(1, realmDictionaryFrog.favoriteFriendsByPond.size) + assertEquals("Frog1", realmDictionaryFrog.favoriteFriendsByPond["Pond1"]?.name) + assertEquals(1, realmDictionaryFrog.favoriteTreesInForest.size) + assertEquals("Tree1", realmDictionaryFrog.favoriteTreesInForest["Forest1"]?.name) + assertEquals(1, realmDictionaryFrog.favoritePondsByForest.size) + assertEquals("Pond1", realmDictionaryFrog.favoritePondsByForest["Forest2"]) + delete(query().find()) + assertEquals(0, query().find().size) + + } + } +}} // :replace-end: \ No newline at end of file diff --git a/source/examples/generated/kotlin/Schema.snippet.define-realm-dictionary-property.kt b/source/examples/generated/kotlin/Schema.snippet.define-realm-dictionary-property.kt index cef4298a39..d1faf292f5 100644 --- a/source/examples/generated/kotlin/Schema.snippet.define-realm-dictionary-property.kt +++ b/source/examples/generated/kotlin/Schema.snippet.define-realm-dictionary-property.kt @@ -5,9 +5,9 @@ class Frog : RealmObject { var _id: ObjectId = ObjectId() var name: String = "" // Dictionary of RealmObject type (value MUST be nullable) - var favoriteFriendsByForest: RealmDictionary = realmDictionaryOf() + var favoriteFriendsByPond: RealmDictionary = realmDictionaryOf() // Dictionary of EmbeddedRealmObject type (value MUST be nullable) - var favoriteForestsByForest: RealmDictionary = realmDictionaryOf() + var favoriteTreesInForest: RealmDictionary = realmDictionaryOf() // Dictionary of primitive type (value can be nullable) var favoritePondsByForest: RealmDictionary = realmDictionaryOf() } diff --git a/source/examples/generated/kotlin/DataTypes.snippet.timestamp-workaround.kt b/source/examples/generated/kotlin/SchemaTest.snippet.timestamp-workaround.kt similarity index 100% rename from source/examples/generated/kotlin/DataTypes.snippet.timestamp-workaround.kt rename to source/examples/generated/kotlin/SchemaTest.snippet.timestamp-workaround.kt diff --git a/source/sdk/kotlin/realm-database/open-and-close-a-realm.txt b/source/sdk/kotlin/realm-database/open-and-close-a-realm.txt index 5ea4dd82e1..6dc7f99a32 100644 --- a/source/sdk/kotlin/realm-database/open-and-close-a-realm.txt +++ b/source/sdk/kotlin/realm-database/open-and-close-a-realm.txt @@ -21,6 +21,8 @@ that you use in your application as well as additional metadata that describe those objects. Each Realm object type has an object schema based on your :ref:`defined object model `. +.. _kotlin-realm-schema: + A **realm schema** is a list of the valid object schemas that a realm may contain. You specify the schema when you open the realm. If a realm already contains data when you open it, Realm diff --git a/source/sdk/kotlin/realm-database/schemas/relationships.txt b/source/sdk/kotlin/realm-database/schemas/relationships.txt index 824917a2fd..28d502c738 100644 --- a/source/sdk/kotlin/realm-database/schemas/relationships.txt +++ b/source/sdk/kotlin/realm-database/schemas/relationships.txt @@ -130,8 +130,6 @@ post belongs to like any other ``RealmResults``. .. literalinclude:: /examples/generated/kotlin/SchemaTest.snippet.inverse-relationship-post.kt :language: kotlin -.. _kotlin-embedded-objects: - Embedded Objects ---------------- diff --git a/source/sdk/kotlin/realm-database/schemas/supported-types.txt b/source/sdk/kotlin/realm-database/schemas/supported-types.txt index 35e7edb68a..bb0c929dbe 100644 --- a/source/sdk/kotlin/realm-database/schemas/supported-types.txt +++ b/source/sdk/kotlin/realm-database/schemas/supported-types.txt @@ -307,7 +307,7 @@ If you need timestamp data in a form other than ``RealmInstant``, you can add conversion code to your model class based on the following example: -.. literalinclude:: /examples/generated/kotlin/DataTypes.snippet.timestamp-workaround.kt +.. literalinclude:: /examples/generated/kotlin/SchemaTest.snippet.timestamp-workaround.kt :language: kotlin .. _kotlin-realmany: