@@ -20,14 +20,19 @@ package io.realm.kotlin.test.mongodb.common
2020import  io.realm.kotlin.Realm 
2121import  io.realm.kotlin.RealmConfiguration 
2222import  io.realm.kotlin.VersionId 
23+ import  io.realm.kotlin.entities.JsonStyleRealmObject 
2324import  io.realm.kotlin.entities.sync.BinaryObject 
2425import  io.realm.kotlin.entities.sync.ChildPk 
2526import  io.realm.kotlin.entities.sync.ParentPk 
2627import  io.realm.kotlin.entities.sync.SyncObjectWithAllTypes 
2728import  io.realm.kotlin.entities.sync.flx.FlexChildObject 
2829import  io.realm.kotlin.entities.sync.flx.FlexEmbeddedObject 
2930import  io.realm.kotlin.entities.sync.flx.FlexParentObject 
31+ import  io.realm.kotlin.ext.asFlow 
32+ import  io.realm.kotlin.ext.asRealmObject 
3033import  io.realm.kotlin.ext.query 
34+ import  io.realm.kotlin.ext.realmAnyDictionaryOf 
35+ import  io.realm.kotlin.ext.realmAnyListOf 
3136import  io.realm.kotlin.internal.interop.ErrorCode 
3237import  io.realm.kotlin.internal.interop.RealmInterop 
3338import  io.realm.kotlin.internal.platform.fileExists 
@@ -56,6 +61,7 @@ import io.realm.kotlin.query.RealmResults
5661import  io.realm.kotlin.schema.RealmClass 
5762import  io.realm.kotlin.schema.RealmSchema 
5863import  io.realm.kotlin.schema.ValuePropertyType 
64+ import  io.realm.kotlin.test.mongodb.TEST_APP_FLEX 
5965import  io.realm.kotlin.test.mongodb.TestApp 
6066import  io.realm.kotlin.test.mongodb.asTestApp 
6167import  io.realm.kotlin.test.mongodb.common.utils.assertFailsWithMessage 
@@ -70,6 +76,9 @@ import io.realm.kotlin.test.util.receiveOrFail
7076import  io.realm.kotlin.test.util.trySendOrFail 
7177import  io.realm.kotlin.test.util.use 
7278import  io.realm.kotlin.types.BaseRealmObject 
79+ import  io.realm.kotlin.types.RealmAny 
80+ import  io.realm.kotlin.types.RealmDictionary 
81+ import  io.realm.kotlin.types.RealmList 
7382import  kotlinx.atomicfu.atomic 
7483import  kotlinx.coroutines.Dispatchers 
7584import  kotlinx.coroutines.async 
@@ -707,6 +716,213 @@ class SyncedRealmTests {
707716        }
708717    }
709718
719+     @Test
720+     fun  roundtripCollectionsInMixed () =  runBlocking {
721+         val  (email1, password1) =  randomEmail() to " password1234" 
722+         val  (email2, password2) =  randomEmail() to " password1234" 
723+         val  app =  TestApp (this ::class .simpleName, appName =  TEST_APP_FLEX )
724+         val  user1 =  app.createUserAndLogIn(email1, password1)
725+         val  user2 =  app.createUserAndLogIn(email2, password2)
726+ 
727+         //  Create object with all types
728+         val  selector =  ObjectId ().toString()
729+ 
730+         createFlexibleSyncConfig(
731+             user =  user1,
732+             initialSubscriptions =  { realm -> 
733+                 realm.query<JsonStyleRealmObject >(" selector = $0"  , selector).subscribe()
734+             }
735+         ).let  { config -> 
736+             Realm .open(config).use { realm -> 
737+                 realm.write {
738+                     val  child =  (
739+                         JsonStyleRealmObject ().apply  {
740+                             this .id =  " CHILD" 
741+                             this .selector =  selector
742+                         }
743+                         )
744+ 
745+                     copyToRealm(
746+                         JsonStyleRealmObject ().apply  {
747+                             this .id =  " PARENT" 
748+                             this .selector =  selector
749+                             value =  realmAnyDictionaryOf(
750+                                 " primitive"   to 1 ,
751+                                 //  List with nested dictionary
752+                                 " list"   to realmAnyListOf(1 , " Realm"  , child, realmAnyDictionaryOf(" listkey1"   to 1 , " listkey2"   to " Realm"  , " listkey3"   to child)),
753+                                 " dictionary"   to realmAnyDictionaryOf(" dictkey1"   to 1 , " dictkey2"   to " Realm"  , " dictkey3"   to child, " dictkey4"   to realmAnyListOf(1 , 2 , 3 ))
754+                             )
755+                         }
756+                     )
757+                 }
758+                 realm.syncSession.uploadAllLocalChangesOrFail()
759+             }
760+         }
761+         createFlexibleSyncConfig(
762+             user =  user2,
763+             initialSubscriptions =  { realm -> 
764+                 realm.query<JsonStyleRealmObject >(" selector = $0"  , selector).subscribe()
765+             }
766+         ).let  { config -> 
767+             Realm .open(config).use { realm -> 
768+                 realm.syncSession.downloadAllServerChanges(10 .seconds)
769+                 val  flow =  realm.query<JsonStyleRealmObject >(" _id = $0"  , " PARENT"  ).asFlow()
770+                 val  parent =  withTimeout(10 .seconds) {
771+                     flow.first {
772+                         it.list.size >=  1 
773+                     }.list[0 ]
774+                 }
775+                 parent.let  {
776+                     val  value =  it.value!! .asDictionary()
777+                     assertEquals(RealmAny .Companion .create(1 ), value[" primitive"  ])
778+                     value[" list"  ]!! .asList().let  {
779+                         assertEquals(1 , it[0 ]!! .asInt())
780+                         assertEquals(" Realm"  , it[1 ]!! .asString())
781+                         assertEquals(" CHILD"  , it[2 ]!! .asRealmObject<JsonStyleRealmObject >().id)
782+                         it[3 ]!! .asDictionary().let  { dict -> 
783+                             assertEquals(1 , dict[" listkey1"  ]!! .asInt())
784+                             assertEquals(" Realm"  , dict[" listkey2"  ]!! .asString())
785+                             assertEquals(" CHILD"  , dict[" listkey3"  ]!! .asRealmObject<JsonStyleRealmObject >().id)
786+                         }
787+                         assertEquals(" CHILD"  , it[2 ]!! .asRealmObject<JsonStyleRealmObject >().id)
788+                     }
789+                     value[" dictionary"  ]!! .asDictionary().let  {
790+                         assertEquals(1 , it[" dictkey1"  ]!! .asInt())
791+                         assertEquals(" Realm"  , it[" dictkey2"  ]!! .asString())
792+                         assertEquals(" CHILD"  , it[" dictkey3"  ]!! .asRealmObject<JsonStyleRealmObject >().id)
793+                         it[" dictkey4"  ]!! .asList().let  {
794+                             assertEquals(realmAnyListOf(1 , 2 , 3 ).asList(), it)
795+                         }
796+                     }
797+                 }
798+             }
799+         }
800+     }
801+ 
802+     @Test
803+     fun  collectionsInMixed_asFlow () =  runBlocking {
804+         val  (email1, password1) =  randomEmail() to " password1234" 
805+         val  (email2, password2) =  randomEmail() to " password1234" 
806+         val  app =  TestApp (this ::class .simpleName, appName =  TEST_APP_FLEX )
807+         val  user1 =  app.createUserAndLogIn(email1, password1)
808+         val  user2 =  app.createUserAndLogIn(email2, password2)
809+ 
810+         //  Create object with all types
811+         val  selector =  ObjectId ().toString()
812+ 
813+         val  updateChannel =  TestChannel <JsonStyleRealmObject >()
814+ 
815+         val  configWriter =  createFlexibleSyncConfig(
816+             user =  user1,
817+             initialSubscriptions =  { realm -> 
818+                 realm.query<JsonStyleRealmObject >(" selector = $0"  , selector).subscribe()
819+             }
820+         )
821+         val  configReader =  createFlexibleSyncConfig(
822+             user =  user2,
823+             initialSubscriptions =  { realm -> 
824+                 realm.query<JsonStyleRealmObject >(" selector = $0"  , selector).subscribe()
825+             },
826+         ) {
827+             this .waitForInitialRemoteData(10 .seconds)
828+         }
829+         Realm .open(configWriter).use { writerRealm -> 
830+             val  source =  writerRealm.write {
831+                 copyToRealm(
832+                     JsonStyleRealmObject ().apply  {
833+                         this .selector =  selector
834+                         value =  realmAnyDictionaryOf(
835+                             //  List with nested dictionary
836+                             " list"   to realmAnyListOf(
837+                                 1 ,
838+                                 " Realm"  ,
839+                                 realmAnyDictionaryOf(" listkey1"   to 1 )
840+                             ),
841+                             //  Dictionary with nested list
842+                             " dictionary"   to realmAnyDictionaryOf(
843+                                 " dictkey1"   to 1 ,
844+                                 " dictkey2"   to " Realm"  ,
845+                                 " dictkey3"   to realmAnyListOf(1 , 2 , 3 )
846+                             )
847+                         )
848+                     }
849+                 )
850+             }
851+             writerRealm.syncSession.uploadAllLocalChangesOrFail()
852+ 
853+             Realm .open(configReader).use { readerRealm -> 
854+                 val  reader =  readerRealm.query<JsonStyleRealmObject >(" selector = $0"  , selector).find().single()
855+                 val  listener =  async {
856+                     reader.asFlow().collect {
857+                         updateChannel.trySendOrFail(it.obj!! )
858+                     }
859+                 }
860+                 //  Flush initial event from channel
861+                 updateChannel.receiveOrFail()
862+ 
863+                 //  List add
864+                 writerRealm.write {
865+                     findLatest(source)!! .run  {
866+                         value!! .asDictionary()[" list"  ]!! .asList().add(RealmAny .Companion .create(6 ))
867+                     }
868+                 }
869+                 updateChannel.receiveOrFail().run  {
870+                     val  updatedList =  value!! .asDictionary()[" list"  ]!! .asList()
871+                     assertEquals(4 , updatedList.size)
872+                     assertEquals(1 , updatedList[0 ]!! .asInt())
873+                     assertEquals(" Realm"  , updatedList[1 ]!! .asString())
874+                     assertIs<RealmDictionary <RealmAny >>(updatedList[2 ]!! .asDictionary())
875+                     assertEquals(6 , updatedList[3 ]!! .asInt())
876+                 }
877+ 
878+                 //  List removal
879+                 writerRealm.write {
880+                     findLatest(source)!! .run  {
881+                         value!! .asDictionary()[" list"  ]!! .asList().removeAt(1 )
882+                     }
883+                 }
884+                 updateChannel.receiveOrFail().run  {
885+                     val  updatedList =  value!! .asDictionary()[" list"  ]!! .asList()
886+                     assertEquals(3 , updatedList.size)
887+                     assertEquals(1 , updatedList[0 ]!! .asInt())
888+                     assertIs<RealmDictionary <RealmAny >>(updatedList[1 ]!! .asDictionary())
889+                     assertEquals(6 , updatedList[2 ]!! .asInt())
890+                 }
891+ 
892+                 //  Dictionary add
893+                 writerRealm.write {
894+                     findLatest(source)!! .run  {
895+                         value!! .asDictionary()[" dictionary"  ]!! .asDictionary()[" dictkey4"  ] =  RealmAny .Companion .create(6 )
896+                     }
897+                 }
898+                 updateChannel.receiveOrFail().run  {
899+                     val  updatedDictionary =  value!! .asDictionary()[" dictionary"  ]!! .asDictionary()
900+                     assertEquals(4 , updatedDictionary.size)
901+                     assertEquals(1 , updatedDictionary[" dictkey1"  ]!! .asInt())
902+                     assertEquals(" Realm"  , updatedDictionary[" dictkey2"  ]!! .asString())
903+                     assertIs<RealmList <RealmAny >>(updatedDictionary[" dictkey3"  ]!! .asList())
904+                     assertEquals(6 , updatedDictionary[" dictkey4"  ]!! .asInt())
905+                 }
906+ 
907+                 //  Dictionary removal
908+                 writerRealm.write {
909+                     findLatest(source)!! .run  {
910+                         value!! .asDictionary()[" dictionary"  ]!! .asDictionary().remove(" dictkey3"  )
911+                     }
912+                 }
913+                 updateChannel.receiveOrFail().run  {
914+                     val  updatedDictionary =  value!! .asDictionary()[" dictionary"  ]!! .asDictionary()
915+                     assertEquals(3 , updatedDictionary.size)
916+                     assertEquals(1 , updatedDictionary[" dictkey1"  ]!! .asInt())
917+                     assertEquals(" Realm"  , updatedDictionary[" dictkey2"  ]!! .asString())
918+                     assertEquals(6 , updatedDictionary[" dictkey4"  ]!! .asInt())
919+                 }
920+ 
921+                 listener.cancel()
922+             }
923+         }
924+     }
925+ 
710926    //  After https://github.com/realm/realm-core/pull/5784 was merged, ObjectStore will now
711927    //  return the full on-disk schema from ObjectStore, but for typed Realms the user visible schema
712928    //  should still only return classes and properties that was defined by the user.
0 commit comments