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

JSON serialization for collection in mixed #1520

Closed
wants to merge 48 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
02bb301
Add support for collections in mixed properties
rorbech Jun 20, 2023
cd3ed42
Add nested RealmAny collection support
rorbech Jun 27, 2023
b1f5b2d
Dynamic API for nested collections in RealmAny
rorbech Jun 29, 2023
65256b0
Merge branch 'main' into cr/collections-in-mixed
rorbech Jun 29, 2023
14c44c8
Add convenience methods to create set, list and dictionaries
rorbech Jul 25, 2023
ddc590f
Query and object notification tests
rorbech Jul 26, 2023
f99a006
Merge branch 'main' into cr/collections-in-mixed
rorbech Aug 3, 2023
61ccde7
Update test
rorbech Aug 3, 2023
8f422a6
Notification test for set
rorbech Aug 3, 2023
ee01946
Minor adjustments
rorbech Aug 7, 2023
84c93a1
Additional tests
rorbech Aug 7, 2023
8f98c22
Merge branch 'main' into cr/collections-in-mixed
rorbech Aug 16, 2023
88b8c58
Notification tests for nested lists and dictionaries
rorbech Aug 16, 2023
3b4212f
Fixed notification and overwrite tests
rorbech Aug 22, 2023
5345436
Add tests for collection operations with unmanaged entities
rorbech Aug 23, 2023
d88c0e0
Remove non-primitive converters and use explicit operators instead
rorbech Aug 25, 2023
6d0ab0f
More test fixes
rorbech Aug 27, 2023
01ee687
Fix caching of imported object in RealmAny
rorbech Aug 27, 2023
bd29c94
Linting
rorbech Aug 27, 2023
4894d4a
Added Kotlin Native implementation
rorbech Aug 28, 2023
36b6705
Inline realm object helper methods
rorbech Aug 28, 2023
b570421
Add mapping of new core error code
rorbech Aug 28, 2023
009dc2b
Merge branch 'main' into cr/collections-in-mixed
rorbech Aug 29, 2023
871819b
Minor cleanup and docs
rorbech Aug 29, 2023
7d28860
Fix json style object schema for sync support
rorbech Aug 29, 2023
620e2a7
Minor updates
rorbech Aug 30, 2023
5a69035
Update core reference with latest fixes
rorbech Aug 30, 2023
84e8c91
Comments
rorbech Aug 30, 2023
bbf93f4
Core issue reference for access to collections through results
rorbech Aug 30, 2023
0bee4f1
Add suggested workaround for serialization of collections in RealmAny
rorbech Aug 30, 2023
6b3d872
Update CHANGELOG.md
rorbech Sep 4, 2023
e9d4782
Merge branch 'main' into cr/collection-in-mixed-serialization
rorbech Sep 4, 2023
619d499
Updates according to review comments
rorbech Sep 4, 2023
a61e9e2
More updates according to review comments
rorbech Sep 4, 2023
1af3d75
Merge remote-tracking branch 'origin/cr/collections-in-mixed' into cr…
rorbech Sep 5, 2023
d7a30b7
Update CHANGELOG
rorbech Sep 5, 2023
7256bea
Remove new line in CHANGELOG
rorbech Sep 5, 2023
554d236
Add support for iterating collections from map values accessor
rorbech Sep 5, 2023
a442cab
More review feedback
rorbech Sep 5, 2023
14501d3
Fix macos tests
rorbech Sep 5, 2023
b168fde
Updates according to review comments
rorbech Sep 8, 2023
37b5b0f
Updates according to review comments
rorbech Sep 11, 2023
b5883e3
Merge branch 'main' into cr/collections-in-mixed
rorbech Sep 11, 2023
0878d57
More docs
rorbech Sep 11, 2023
4981609
Fix test
rorbech Sep 11, 2023
fb619c6
Updates according to review comments
rorbech Sep 11, 2023
801ff1d
Simple JSON serialization of RealmAny
rorbech Sep 14, 2023
2023660
Remove unused imports
rorbech Sep 14, 2023
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
6 changes: 4 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
## 1.12.0-SNAPSHOT (YYYY-MM-DD)

This release will bump the Realm file format from version 23 to 24. Opening a file with an older format will automatically upgrade it. Downgrading to a previous file format is not possible.

### Breaking Changes
* None.

### Enhancements
* None.
* Support for RealmLists, RealmSets and RealmDictionaries in `RealmAny`. This is only supported in the local database, Device Sync support will come in a future release. (Issue [#1434](https://github.com/realm/realm-kotlin/issues/1434))

### Fixed
* None.
Expand All @@ -24,7 +26,7 @@
* Minimum Android SDK: 16.

### Internal
* None.
* Updated to Realm Core `next-major`, commit 0da737b699bf4bcfc1a3772385cd49cd9eb9cad9.


## 1.11.1 (2023-09-07)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ expect enum class ErrorCode : CodeDescription {
RLM_ERR_MAINTENANCE_IN_PROGRESS,
RLM_ERR_USERPASS_TOKEN_INVALID,
RLM_ERR_INVALID_SERVER_RESPONSE,
REALM_ERR_APP_SERVER_ERROR,
RLM_ERR_APP_SERVER_ERROR,
RLM_ERR_CALLBACK,
RLM_ERR_UNKNOWN;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,4 +95,7 @@ expect enum class ValueType {
RLM_TYPE_OBJECT_ID,
RLM_TYPE_LINK,
RLM_TYPE_UUID,
RLM_TYPE_LIST,
RLM_TYPE_SET,
RLM_TYPE_DICTIONARY,
}
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,9 @@ expect object RealmInterop {
isDefault: Boolean
)
fun realm_set_embedded(obj: RealmObjectPointer, key: PropertyKey): RealmObjectPointer
fun realm_set_set(obj: RealmObjectPointer, key: PropertyKey): RealmSetPointer
fun realm_set_list(obj: RealmObjectPointer, key: PropertyKey): RealmListPointer
fun realm_set_dictionary(obj: RealmObjectPointer, key: PropertyKey): RealmMapPointer
fun realm_object_add_int(obj: RealmObjectPointer, key: PropertyKey, value: Long)
fun <T> realm_object_get_parent(
obj: RealmObjectPointer,
Expand All @@ -300,10 +303,19 @@ expect object RealmInterop {
fun realm_get_backlinks(obj: RealmObjectPointer, sourceClassKey: ClassKey, sourcePropertyKey: PropertyKey): RealmResultsPointer
fun realm_list_size(list: RealmListPointer): Long
fun MemAllocator.realm_list_get(list: RealmListPointer, index: Long): RealmValue
fun realm_list_get_set(list: RealmListPointer, index: Long): RealmSetPointer
fun realm_list_get_list(list: RealmListPointer, index: Long): RealmListPointer
fun realm_list_get_dictionary(list: RealmListPointer, index: Long): RealmMapPointer
fun realm_list_add(list: RealmListPointer, index: Long, transport: RealmValue)
fun realm_list_insert_embedded(list: RealmListPointer, index: Long): RealmObjectPointer
// Returns the element previously at the specified position
fun realm_list_set(list: RealmListPointer, index: Long, inputTransport: RealmValue)
fun realm_list_insert_set(list: RealmListPointer, index: Long): RealmSetPointer
fun realm_list_insert_list(list: RealmListPointer, index: Long): RealmListPointer
fun realm_list_insert_dictionary(list: RealmListPointer, index: Long): RealmMapPointer
fun realm_list_set_set(list: RealmListPointer, index: Long): RealmSetPointer
fun realm_list_set_list(list: RealmListPointer, index: Long): RealmListPointer
fun realm_list_set_dictionary(list: RealmListPointer, index: Long): RealmMapPointer

// Returns the newly inserted element as the previous embedded element is automatically delete
// by this operation
Expand Down Expand Up @@ -335,10 +347,23 @@ expect object RealmInterop {
dictionary: RealmMapPointer,
mapKey: RealmValue
): RealmValue
fun realm_dictionary_find_set(
dictionary: RealmMapPointer,
mapKey: RealmValue
): RealmSetPointer
fun realm_dictionary_find_list(
dictionary: RealmMapPointer,
mapKey: RealmValue
): RealmListPointer
fun realm_dictionary_find_dictionary(
dictionary: RealmMapPointer,
mapKey: RealmValue
): RealmMapPointer
fun MemAllocator.realm_dictionary_get(
dictionary: RealmMapPointer,
pos: Int
): Pair<RealmValue, RealmValue>

fun MemAllocator.realm_dictionary_insert(
dictionary: RealmMapPointer,
mapKey: RealmValue,
Expand All @@ -360,6 +385,9 @@ expect object RealmInterop {
dictionary: RealmMapPointer,
mapKey: RealmValue
): RealmValue
fun realm_dictionary_insert_set(dictionary: RealmMapPointer, mapKey: RealmValue): RealmSetPointer
fun realm_dictionary_insert_list(dictionary: RealmMapPointer, mapKey: RealmValue): RealmListPointer
fun realm_dictionary_insert_dictionary(dictionary: RealmMapPointer, mapKey: RealmValue): RealmMapPointer
fun realm_dictionary_get_keys(dictionary: RealmMapPointer): RealmResultsPointer
fun realm_dictionary_resolve_in(
dictionary: RealmMapPointer,
Expand Down Expand Up @@ -424,6 +452,9 @@ expect object RealmInterop {

// FIXME OPTIMIZE Get many
fun MemAllocator.realm_results_get(results: RealmResultsPointer, index: Long): RealmValue
fun realm_results_get_set(results: RealmResultsPointer, index: Long): RealmSetPointer
fun realm_results_get_list(results: RealmResultsPointer, index: Long): RealmListPointer
fun realm_results_get_dictionary(results: RealmResultsPointer, index: Long): RealmMapPointer
fun realm_results_delete_all(results: RealmResultsPointer)

fun realm_get_object(realm: RealmPointer, link: Link): RealmObjectPointer
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ actual enum class ErrorCode(override val description: String, override val nativ
RLM_ERR_MAINTENANCE_IN_PROGRESS("MaintenanceInProgress", realm_errno_e.RLM_ERR_MAINTENANCE_IN_PROGRESS),
RLM_ERR_USERPASS_TOKEN_INVALID("UserpassTokenInvalid", realm_errno_e.RLM_ERR_USERPASS_TOKEN_INVALID),
RLM_ERR_INVALID_SERVER_RESPONSE("InvalidServerResponse", realm_errno_e.RLM_ERR_INVALID_SERVER_RESPONSE),
REALM_ERR_APP_SERVER_ERROR("AppServerError", realm_errno_e.RLM_ERR_APP_SERVER_ERROR),
RLM_ERR_APP_SERVER_ERROR("AppServerError", realm_errno_e.RLM_ERR_APP_SERVER_ERROR),
RLM_ERR_CALLBACK("Callback", realm_errno_e.RLM_ERR_CALLBACK),
RLM_ERR_UNKNOWN("Unknown", realm_errno_e.RLM_ERR_UNKNOWN);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package io.realm.kotlin.internal.interop

import io.realm.kotlin.internal.interop.Constants.ENCRYPTION_KEY_LENGTH
import io.realm.kotlin.internal.interop.RealmInterop.cptr
import io.realm.kotlin.internal.interop.sync.ApiKeyWrapper
import io.realm.kotlin.internal.interop.sync.AuthProvider
import io.realm.kotlin.internal.interop.sync.CoreConnectionState
Expand Down Expand Up @@ -463,6 +464,19 @@ actual object RealmInterop {
return LongPointerWrapper(realmc.realm_set_embedded(obj.cptr(), key.key))
}

actual fun realm_set_set(obj: RealmObjectPointer, key: PropertyKey): RealmSetPointer {
realmc.realm_set_set(obj.cptr(), key.key)
return realm_get_set(obj, key)
}
actual fun realm_set_list(obj: RealmObjectPointer, key: PropertyKey): RealmListPointer {
realmc.realm_set_list(obj.cptr(), key.key)
return realm_get_list(obj, key)
}
actual fun realm_set_dictionary(obj: RealmObjectPointer, key: PropertyKey): RealmMapPointer {
realmc.realm_set_dictionary(obj.cptr(), key.key)
return realm_get_dictionary(obj, key)
}

actual fun realm_object_add_int(obj: RealmObjectPointer, key: PropertyKey, value: Long) {
realmc.realm_object_add_int(obj.cptr(), key.key, value)
}
Expand Down Expand Up @@ -519,6 +533,13 @@ actual object RealmInterop {
realmc.realm_list_get(list.cptr(), index, struct)
return RealmValue(struct)
}
actual fun realm_list_get_set(list: RealmListPointer, index: Long): RealmSetPointer =
LongPointerWrapper(realmc.realm_list_get_set(list.cptr(), index))
actual fun realm_list_get_list(list: RealmListPointer, index: Long): RealmListPointer =
LongPointerWrapper(realmc.realm_list_get_list(list.cptr(), index))

actual fun realm_list_get_dictionary(list: RealmListPointer, index: Long): RealmMapPointer =
LongPointerWrapper(realmc.realm_list_get_dictionary(list.cptr(), index))

actual fun realm_list_add(list: RealmListPointer, index: Long, transport: RealmValue) {
realmc.realm_list_insert(list.cptr(), index, transport.value)
Expand All @@ -527,6 +548,24 @@ actual object RealmInterop {
actual fun realm_list_insert_embedded(list: RealmListPointer, index: Long): RealmObjectPointer {
return LongPointerWrapper(realmc.realm_list_insert_embedded(list.cptr(), index))
}
actual fun realm_list_insert_set(list: RealmListPointer, index: Long): RealmSetPointer {
return LongPointerWrapper(realmc.realm_list_insert_set(list.cptr(), index))
}
actual fun realm_list_insert_list(list: RealmListPointer, index: Long): RealmListPointer {
return LongPointerWrapper(realmc.realm_list_insert_list(list.cptr(), index))
}
actual fun realm_list_insert_dictionary(list: RealmListPointer, index: Long): RealmMapPointer {
return LongPointerWrapper(realmc.realm_list_insert_dictionary(list.cptr(), index))
}
actual fun realm_list_set_set(list: RealmListPointer, index: Long): RealmSetPointer {
return LongPointerWrapper(realmc.realm_list_set_set(list.cptr(), index))
}
actual fun realm_list_set_list(list: RealmListPointer, index: Long): RealmListPointer {
return LongPointerWrapper(realmc.realm_list_set_list(list.cptr(), index))
}
actual fun realm_list_set_dictionary(list: RealmListPointer, index: Long): RealmMapPointer {
return LongPointerWrapper(realmc.realm_list_set_dictionary(list.cptr(), index))
}

actual fun realm_list_set(
list: RealmListPointer,
Expand Down Expand Up @@ -683,6 +722,25 @@ actual object RealmInterop {
realmc.realm_dictionary_find(dictionary.cptr(), mapKey.value, struct, found)
return RealmValue(struct)
}
actual fun realm_dictionary_find_set(
dictionary: RealmMapPointer,
mapKey: RealmValue
): RealmSetPointer {
return LongPointerWrapper(realmc.realm_dictionary_get_set(dictionary.cptr(), mapKey.value))
}

actual fun realm_dictionary_find_list(
dictionary: RealmMapPointer,
mapKey: RealmValue
): RealmListPointer {
return LongPointerWrapper(realmc.realm_dictionary_get_list(dictionary.cptr(), mapKey.value))
}
actual fun realm_dictionary_find_dictionary(
dictionary: RealmMapPointer,
mapKey: RealmValue
): RealmMapPointer {
return LongPointerWrapper(realmc.realm_dictionary_get_dictionary(dictionary.cptr(), mapKey.value))
}

actual fun MemAllocator.realm_dictionary_get(
dictionary: RealmMapPointer,
Expand Down Expand Up @@ -751,6 +809,17 @@ actual object RealmInterop {
}
)
}
actual fun realm_dictionary_insert_set(dictionary: RealmMapPointer, mapKey: RealmValue): RealmSetPointer {
return LongPointerWrapper(realmc.realm_dictionary_insert_set(dictionary.cptr(), mapKey.value))
}

actual fun realm_dictionary_insert_list(dictionary: RealmMapPointer, mapKey: RealmValue): RealmListPointer {
return LongPointerWrapper(realmc.realm_dictionary_insert_list(dictionary.cptr(), mapKey.value))
}

actual fun realm_dictionary_insert_dictionary(dictionary: RealmMapPointer, mapKey: RealmValue): RealmMapPointer {
return LongPointerWrapper(realmc.realm_dictionary_insert_dictionary(dictionary.cptr(), mapKey.value))
}

actual fun realm_dictionary_get_keys(dictionary: RealmMapPointer): RealmResultsPointer {
val size = LongArray(1)
Expand Down Expand Up @@ -886,15 +955,20 @@ actual object RealmInterop {
val deletionCount = LongArray(1)
val modificationCount = LongArray(1)
val movesCount = LongArray(1)
// Not exposed in SDK yet, but could be used to provide optimized notifications when
// collections are cleared.
// https://github.com/realm/realm-kotlin/issues/1498
val collectionWasCleared = BooleanArray(1)
val collectionWasDeleted = BooleanArray(1)

realmc.realm_collection_changes_get_num_changes(
change.cptr(),
deletionCount,
insertionCount,
modificationCount,
movesCount,
collectionWasCleared
collectionWasCleared,
collectionWasDeleted,
)

val insertionIndices: LongArray = initIndicesArray(insertionCount)
Expand Down Expand Up @@ -978,24 +1052,31 @@ actual object RealmInterop {
val deletions = longArrayOf(0)
val insertions = longArrayOf(0)
val modifications = longArrayOf(0)
val collectionWasDeleted = BooleanArray(1)
realmc.realm_dictionary_get_changes(
change.cptr(),
deletions,
insertions,
modifications
modifications,
collectionWasDeleted,
)

val deletionStructs = realmc.new_valueArray(deletions[0].toInt())
val insertionStructs = realmc.new_valueArray(insertions[0].toInt())
val modificationStructs = realmc.new_valueArray(modifications[0].toInt())
// Not exposed in SDK yet, but could be used to provide optimized notifications when
// collections are cleared.
// https://github.com/realm/realm-kotlin/issues/1498
val collectionWasCleared = booleanArrayOf(false)
realmc.realm_dictionary_get_changed_keys(
change.cptr(),
deletionStructs,
deletions,
insertionStructs,
insertions,
modificationStructs,
modifications
modifications,
collectionWasCleared
)

// TODO optimize - integrate within mem allocator?
Expand Down Expand Up @@ -1768,6 +1849,15 @@ actual object RealmInterop {
return RealmValue(value)
}

actual fun realm_results_get_set(results: RealmResultsPointer, index: Long): RealmSetPointer =
LongPointerWrapper(realmc.realm_results_get_set(results.cptr(), index))

actual fun realm_results_get_list(results: RealmResultsPointer, index: Long): RealmListPointer =
LongPointerWrapper(realmc.realm_results_get_list(results.cptr(), index))

actual fun realm_results_get_dictionary(results: RealmResultsPointer, index: Long): RealmMapPointer =
LongPointerWrapper(realmc.realm_results_get_dictionary(results.cptr(), index))

actual fun realm_get_object(realm: RealmPointer, link: Link): RealmObjectPointer {
return LongPointerWrapper(realmc.realm_get_object(realm.cptr(), link.classKey.key, link.objKey))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@ actual enum class ValueType(override val nativeValue: Int) : NativeEnumerated {
RLM_TYPE_DECIMAL128(realm_value_type_e.RLM_TYPE_DECIMAL128),
RLM_TYPE_OBJECT_ID(realm_value_type_e.RLM_TYPE_OBJECT_ID),
RLM_TYPE_LINK(realm_value_type_e.RLM_TYPE_LINK),
RLM_TYPE_UUID(realm_value_type_e.RLM_TYPE_UUID);
RLM_TYPE_UUID(realm_value_type_e.RLM_TYPE_UUID),
RLM_TYPE_LIST(realm_value_type_e.RLM_TYPE_LIST),
RLM_TYPE_SET(realm_value_type_e.RLM_TYPE_SET),
RLM_TYPE_DICTIONARY(realm_value_type_e.RLM_TYPE_DICTIONARY);

companion object {
fun from(nativeValue: Int): ValueType = values().find {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ actual enum class ErrorCode(
RLM_ERR_MAINTENANCE_IN_PROGRESS("MaintenanceInProgress", realm_errno.RLM_ERR_MAINTENANCE_IN_PROGRESS),
RLM_ERR_USERPASS_TOKEN_INVALID("UserpassTokenInvalid", realm_errno.RLM_ERR_USERPASS_TOKEN_INVALID),
RLM_ERR_INVALID_SERVER_RESPONSE("InvalidServerResponse", realm_errno.RLM_ERR_INVALID_SERVER_RESPONSE),
REALM_ERR_APP_SERVER_ERROR("AppServerError", realm_errno.RLM_ERR_APP_SERVER_ERROR),
RLM_ERR_APP_SERVER_ERROR("AppServerError", realm_errno.RLM_ERR_APP_SERVER_ERROR),
RLM_ERR_CALLBACK("Callback", realm_errno.RLM_ERR_CALLBACK),
RLM_ERR_UNKNOWN("Unknown", realm_errno.RLM_ERR_UNKNOWN);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,11 @@ actual enum class ValueType(
RLM_TYPE_DECIMAL128(realm_value_type_e.RLM_TYPE_DECIMAL128),
RLM_TYPE_OBJECT_ID(realm_value_type_e.RLM_TYPE_OBJECT_ID),
RLM_TYPE_LINK(realm_value_type_e.RLM_TYPE_LINK),
RLM_TYPE_UUID(realm_value_type_e.RLM_TYPE_UUID);
RLM_TYPE_UUID(realm_value_type_e.RLM_TYPE_UUID),
RLM_TYPE_SET(realm_value_type_e.RLM_TYPE_SET),
RLM_TYPE_LIST(realm_value_type_e.RLM_TYPE_LIST),
RLM_TYPE_DICTIONARY(realm_value_type_e.RLM_TYPE_DICTIONARY),
;

companion object {
fun from(nativeValue: realm_value_type): ValueType = values().find {
Expand Down
Loading