@@ -877,87 +877,121 @@ void InstructionApplier::operator()(const Instruction::ArrayErase& instr)
877877
878878void InstructionApplier::operator ()(const Instruction::Clear& instr)
879879{
880+ // For collections and nested collections in Mixed, applying a Clear instruction
881+ // implicitly sets the collection type (of the clear instruction) too.
880882 struct ClearResolver : public PathResolver {
881883 ClearResolver (InstructionApplier* applier, const Instruction::Clear& instr)
882884 : PathResolver(applier, instr, " Clear" )
883885 {
886+ switch (instr.collection_type ) {
887+ case Instruction::CollectionType::Single:
888+ break ;
889+ case Instruction::CollectionType::List:
890+ m_collection_type = CollectionType::List;
891+ break ;
892+ case Instruction::CollectionType::Dictionary:
893+ m_collection_type = CollectionType::Dictionary;
894+ break ;
895+ case Instruction::CollectionType::Set:
896+ m_collection_type = CollectionType::Set;
897+ break ;
898+ }
884899 }
885900 void on_list (LstBase& list) override
886901 {
902+ // list property
903+ if (m_collection_type && *m_collection_type != CollectionType::List) {
904+ m_applier->bad_transaction_log (" Clear: Not a List" );
905+ }
887906 list.clear ();
888907 }
889908 Status on_list_index (LstBase& list, uint32_t index) override
890909 {
910+ REALM_ASSERT (m_collection_type);
891911 REALM_ASSERT (dynamic_cast <Lst<Mixed>*>(&list));
892912 auto & mixed_list = static_cast <Lst<Mixed>&>(list);
893913 if (index >= mixed_list.size ()) {
894914 m_applier->bad_transaction_log (" Clear: Index out of bounds (%1 > %2)" , index,
895915 mixed_list.size ()); // Throws
896- return Status::DidNotResolve;
897916 }
898917 auto val = mixed_list.get (index);
899918 if (val.is_type (type_Dictionary)) {
900919 Dictionary d (mixed_list, mixed_list.get_key (index));
901920 d.clear ();
902- return Status::Pending;
903921 }
904- if (val.is_type (type_List)) {
922+ else if (val.is_type (type_List)) {
905923 Lst<Mixed> l (mixed_list, mixed_list.get_key (index));
906924 l.clear ();
907- return Status::Pending;
908925 }
909- m_applier->bad_transaction_log (" Clear: Item (%1) at index %2 is not a collection" , val.get_type (),
910- index); // Throws
911- return Status::DidNotResolve;
926+ else if (val.is_type (type_Set)) {
927+ m_applier->bad_transaction_log (" Clear: Item at index %1 is a Set" ,
928+ index); // Throws
929+ }
930+ mixed_list.set_collection (size_t (index), *m_collection_type);
931+ return Status::Pending;
912932 }
913933 void on_dictionary (Dictionary& dict) override
914934 {
935+ // dictionary property
936+ if (m_collection_type && *m_collection_type != CollectionType::Dictionary) {
937+ m_applier->bad_transaction_log (" Clear: Not a Dictionary" );
938+ }
915939 dict.clear ();
916940 }
917941 Status on_dictionary_key (Dictionary& dict, Mixed key) override
918942 {
943+ REALM_ASSERT (m_collection_type);
919944 auto val = dict.get (key);
920945 if (val.is_type (type_Dictionary)) {
921946 Dictionary d (dict, dict.build_index (key));
922947 d.clear ();
923- return Status::Pending;
924948 }
925- if (val.is_type (type_List)) {
949+ else if (val.is_type (type_List)) {
926950 Lst<Mixed> l (dict, dict.build_index (key));
927951 l.clear ();
928- return Status::Pending;
929952 }
930- m_applier->bad_transaction_log (" Clear: Item (%1) at key '%2' is not a collection" , val.get_type (),
931- key); // Throws
932- return Status::DidNotResolve;
953+ else if (val.is_type (type_Set)) {
954+ m_applier->bad_transaction_log (" Clear: Item at key '%1' is a Set" ,
955+ key); // Throws
956+ }
957+ dict.insert_collection (key.get_string (), *m_collection_type);
958+ return Status::Pending;
933959 }
934960 void on_set (SetBase& set) override
935961 {
962+ // set property
963+ if (m_collection_type && *m_collection_type != CollectionType::Set) {
964+ m_applier->bad_transaction_log (" Clear: Not a Set" );
965+ }
936966 set.clear ();
937967 }
938968 void on_property (Obj& obj, ColKey col_key) override
939969 {
940970 if (col_key.get_type () == col_type_Mixed) {
971+ REALM_ASSERT (m_collection_type);
941972 auto val = obj.get <Mixed>(col_key);
942973 if (val.is_type (type_Dictionary)) {
943974 Dictionary dict (obj, col_key);
944975 dict.clear ();
945- return ;
946976 }
947977 else if (val.is_type (type_List)) {
948978 Lst<Mixed> list (obj, col_key);
949979 list.clear ();
950- return ;
951980 }
952981 else if (val.is_type (type_Set)) {
953- Set<Mixed> set (obj, col_key);
954- set.clear ();
955- return ;
982+ m_applier->bad_transaction_log (" Clear: Mixed property is a Set" ); // Throws
956983 }
984+ obj.set_collection (col_key, *m_collection_type);
985+ return ;
957986 }
958987
959988 PathResolver::on_property (obj, col_key);
960989 }
990+
991+ private:
992+ // The server may not send the type for collection properties (non-Mixed)
993+ // since the clients don't send it either before v13.
994+ std::optional<CollectionType> m_collection_type;
961995 };
962996 ClearResolver (this , instr).resolve ();
963997}
0 commit comments