@@ -101,6 +101,124 @@ func TestEmptyTypeSchema(t *testing.T) {
101101	x .ParseNamespaceAttr (types [0 ].TypeName )
102102}
103103
104+ func  TestDeleteSetWithVarEdgeCorruptsData (t  * testing.T ) {
105+ 	// Setup temporary directory for Badger DB 
106+ 	dir , err  :=  os .MkdirTemp ("" , "storetest_" )
107+ 	require .NoError (t , err )
108+ 	defer  os .RemoveAll (dir )
109+ 
110+ 	opt  :=  badger .DefaultOptions (dir )
111+ 	ps , err  :=  badger .OpenManaged (opt )
112+ 	require .NoError (t , err )
113+ 	posting .Init (ps , 0 , false )
114+ 	Init (ps )
115+ 
116+ 	// Set schema 
117+ 	schemaTxt  :=  ` 
118+ 		room: string @index(hash) @upsert . 
119+ 		person: string @index(hash) @upsert . 
120+ 		office: uid @reverse @count . 
121+ 	` 
122+ 	err  =  schema .ParseBytes ([]byte (schemaTxt ), 1 )
123+ 	require .NoError (t , err )
124+ 
125+ 	ctx  :=  context .Background ()
126+ 	attrRoom  :=  x .GalaxyAttr ("room" )
127+ 	attrPerson  :=  x .GalaxyAttr ("person" )
128+ 	attrOffice  :=  x .GalaxyAttr ("office" )
129+ 
130+ 	uidRoom  :=  uint64 (1 )
131+ 	uidJohn  :=  uint64 (2 )
132+ 
133+ 	runMutation  :=  func (startTs , commitTs  uint64 , edges  []* pb.DirectedEdge ) {
134+ 		txn  :=  posting .Oracle ().RegisterStartTs (startTs )
135+ 		for  _ , edge  :=  range  edges  {
136+ 			require .NoError (t , runMutation (ctx , edge , txn ))
137+ 		}
138+ 		txn .Update ()
139+ 		writer  :=  posting .NewTxnWriter (ps )
140+ 		require .NoError (t , txn .CommitToDisk (writer , commitTs ))
141+ 		require .NoError (t , writer .Flush ())
142+ 		txn .UpdateCachedKeys (commitTs )
143+ 	}
144+ 
145+ 	// Initial mutation: Set John → Leopard 
146+ 	runMutation (1 , 3 , []* pb.DirectedEdge {
147+ 		{
148+ 			Entity :    uidJohn ,
149+ 			Attr :      attrPerson ,
150+ 			Value :     []byte ("John Smith" ),
151+ 			ValueType : pb .Posting_STRING ,
152+ 			Op :        pb .DirectedEdge_SET ,
153+ 		},
154+ 		{
155+ 			Entity :    uidRoom ,
156+ 			Attr :      attrRoom ,
157+ 			Value :     []byte ("Leopard" ),
158+ 			ValueType : pb .Posting_STRING ,
159+ 			Op :        pb .DirectedEdge_SET ,
160+ 		},
161+ 		{
162+ 			Entity :    uidJohn ,
163+ 			Attr :      attrOffice ,
164+ 			ValueId :   uidRoom ,
165+ 			ValueType : pb .Posting_UID ,
166+ 			Op :        pb .DirectedEdge_SET ,
167+ 		},
168+ 	})
169+ 
170+ 	key  :=  x .DataKey (attrOffice , uidJohn )
171+ 	rollup (t , key , ps , 4 )
172+ 
173+ 	// Second mutation: Remove John from Leopard, assign Amanda 
174+ 	uidAmanda  :=  uint64 (3 )
175+ 
176+ 	runMutation (6 , 8 , []* pb.DirectedEdge {
177+ 		{
178+ 			Entity :    uidJohn ,
179+ 			Attr :      attrOffice ,
180+ 			ValueId :   uidRoom ,
181+ 			ValueType : pb .Posting_UID ,
182+ 			Op :        pb .DirectedEdge_DEL ,
183+ 		},
184+ 		{
185+ 			Entity :    uidAmanda ,
186+ 			Attr :      attrPerson ,
187+ 			Value :     []byte ("Amanda Anderson" ),
188+ 			ValueType : pb .Posting_STRING ,
189+ 			Op :        pb .DirectedEdge_SET ,
190+ 		},
191+ 		{
192+ 			Entity :    uidAmanda ,
193+ 			Attr :      attrOffice ,
194+ 			ValueId :   uidRoom ,
195+ 			ValueType : pb .Posting_UID ,
196+ 			Op :        pb .DirectedEdge_SET ,
197+ 		},
198+ 	})
199+ 
200+ 	// Read and validate: Amanda assigned, John unassigned 
201+ 	txnRead  :=  posting .Oracle ().RegisterStartTs (10 )
202+ 
203+ 	list , err  :=  txnRead .Get (key )
204+ 	require .NoError (t , err )
205+ 
206+ 	uids , err  :=  list .Uids (posting.ListOptions {ReadTs : 10 })
207+ 	require .NoError (t , err )
208+ 
209+ 	// This assertion FAILS in the broken case where both Amanda and John are assigned 
210+ 	require .Equal (t , 0 , len (uids .Uids ), "John should no longer have an office assigned" )
211+ 
212+ 	keyRev  :=  x .ReverseKey (attrOffice , uidRoom )
213+ 	listRev , err  :=  txnRead .Get (keyRev )
214+ 	require .NoError (t , err )
215+ 
216+ 	reverseUids , err  :=  listRev .Uids (posting.ListOptions {ReadTs : 10 })
217+ 	require .NoError (t , err )
218+ 
219+ 	require .Equal (t , []uint64 {uidAmanda }, reverseUids .Uids , "Only Amanda should be assigned on reverse edge" )
220+ }
221+ 
104222func  TestGetScalarList (t  * testing.T ) {
105223	dir , err  :=  os .MkdirTemp ("" , "storetest_" )
106224	x .Check (err )
0 commit comments