Skip to content

Commit

Permalink
Don't mix reads and writes in firestore
Browse files Browse the repository at this point in the history
  • Loading branch information
dcadenas committed Oct 15, 2024
1 parent cc28151 commit a976c16
Showing 1 changed file with 19 additions and 7 deletions.
26 changes: 19 additions & 7 deletions service/adapters/firestore/repository_event.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,12 +128,16 @@ func (e *EventRepository) saveUnderEvents(event domain.Event) error {

// DeleteByPublicKey deletes all events and associated notifications for a given public key.
func (e *EventRepository) DeleteByPublicKey(ctx context.Context, pubkey domain.PublicKey) error {
eventsQuery := e.client.Collection(collectionEvents).Where(eventFieldPublicKey, "==", pubkey.Hex())
notificationsToDelete := make(map[*firestore.DocumentRef][]*firestore.DocumentRef)

eventsDocs := e.tx.Documents(eventsQuery)
eventsQuery := e.client.Collection(collectionEvents).Where(eventFieldPublicKey, "==", pubkey.Hex())
eventsIter := eventsQuery.Documents(ctx)

// Collect event references and their associated notifications first to
// avoid mixing reads and writes in the same transaction and avoid the
// firestore error "read after write in transaction"
for {
eventDoc, err := eventsDocs.Next()
eventDoc, err := eventsIter.Next()
if err == iterator.Done {
break
}
Expand All @@ -142,23 +146,31 @@ func (e *EventRepository) DeleteByPublicKey(ctx context.Context, pubkey domain.P
}

notificationsCollection := eventDoc.Ref.Collection(collectionEventsNotifications)
notificationsDocs := e.tx.Documents(notificationsCollection)
notificationsIter := notificationsCollection.Documents(ctx)

var notificationRefs []*firestore.DocumentRef
for {
notificationDoc, err := notificationsDocs.Next()
notificationDoc, err := notificationsIter.Next()
if err == iterator.Done {
break
}
if err != nil {
return errors.Wrap(err, "error fetching notification document")
}
notificationRefs = append(notificationRefs, notificationDoc.Ref)
}

notificationsToDelete[eventDoc.Ref] = notificationRefs
}

if err := e.tx.Delete(notificationDoc.Ref); err != nil {
for eventRef, notificationRefs := range notificationsToDelete {
for _, notificationRef := range notificationRefs {
if err := e.tx.Delete(notificationRef); err != nil {
return errors.Wrap(err, "error deleting notification document")
}
}

if err := e.tx.Delete(eventDoc.Ref); err != nil {
if err := e.tx.Delete(eventRef); err != nil {
return errors.Wrap(err, "error deleting event document")
}
}
Expand Down

0 comments on commit a976c16

Please sign in to comment.