From d591dd05844bf89e27147b27e771b45363d3f4ca Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Thu, 8 Sep 2022 15:44:48 +0100 Subject: [PATCH] BREAKING(db): Add predecessor_room_id to the rooms table This tracks the room ID supplied in the create event. --- state/accumulator.go | 15 +++++++++++---- state/rooms_table.go | 21 ++++++++++++++++----- state/rooms_table_test.go | 23 +++++++++++++++++++++++ 3 files changed, 50 insertions(+), 9 deletions(-) diff --git a/state/accumulator.go b/state/accumulator.go index c2ff073..13ea266 100644 --- a/state/accumulator.go +++ b/state/accumulator.go @@ -105,6 +105,7 @@ func (a *Accumulator) roomInfoDelta(roomID string, events []Event) RoomInfo { isEncrypted := false var upgradedRoomID *string var roomType *string + var pred *string for _, ev := range events { if ev.Type == "m.room.encryption" && ev.StateKey == "" { isEncrypted = true @@ -120,13 +121,19 @@ func (a *Accumulator) roomInfoDelta(roomID string, events []Event) RoomInfo { if contentType.Exists() && contentType.Type == gjson.String { roomType = &contentType.Str } + predecessorRoomID := gjson.GetBytes(ev.JSON, "content.predecessor.room_id").Str + if predecessorRoomID != "" { + pred = &predecessorRoomID + } + } } return RoomInfo{ - ID: roomID, - IsEncrypted: isEncrypted, - UpgradedRoomID: upgradedRoomID, - Type: roomType, + ID: roomID, + IsEncrypted: isEncrypted, + UpgradedRoomID: upgradedRoomID, + Type: roomType, + PredecessorRoomID: pred, } } diff --git a/state/rooms_table.go b/state/rooms_table.go index dff83ef..e87f692 100644 --- a/state/rooms_table.go +++ b/state/rooms_table.go @@ -9,10 +9,11 @@ import ( ) type RoomInfo struct { - ID string `db:"room_id"` - IsEncrypted bool `db:"is_encrypted"` - UpgradedRoomID *string `db:"upgraded_room_id"` - Type *string `db:"type"` + ID string `db:"room_id"` + IsEncrypted bool `db:"is_encrypted"` + UpgradedRoomID *string `db:"upgraded_room_id"` // from the most recent valid tombstone event, or NULL + PredecessorRoomID *string `db:"predecessor_room_id"` // from the create event + Type *string `db:"type"` } // RoomsTable stores the current snapshot for a room. @@ -26,6 +27,7 @@ func NewRoomsTable(db *sqlx.DB) *RoomsTable { current_snapshot_id BIGINT NOT NULL, is_encrypted BOOL NOT NULL DEFAULT FALSE, upgraded_room_id TEXT, + predecessor_room_id TEXT, latest_nid BIGINT NOT NULL DEFAULT 0, type TEXT -- nullable ); @@ -34,7 +36,7 @@ func NewRoomsTable(db *sqlx.DB) *RoomsTable { } func (t *RoomsTable) SelectRoomInfos(txn *sqlx.Tx) (infos []RoomInfo, err error) { - err = txn.Select(&infos, `SELECT room_id, is_encrypted, upgraded_room_id, type FROM syncv3_rooms`) + err = txn.Select(&infos, `SELECT room_id, is_encrypted, upgraded_room_id, predecessor_room_id, type FROM syncv3_rooms`) return } @@ -65,6 +67,12 @@ func (t *RoomsTable) Upsert(txn *sqlx.Tx, info RoomInfo, snapshotID, latestNID i doUpdate += fmt.Sprintf(", type = $%d", n) // should never be updated but you never know... n++ } + if info.PredecessorRoomID != nil { + cols += ", predecessor_room_id" + vals += fmt.Sprintf(", $%d", n) + doUpdate += fmt.Sprintf(", predecessor_room_id = $%d", n) + n++ + } insertQuery := fmt.Sprintf(`INSERT INTO syncv3_rooms(%s) VALUES(%s) %s`, cols, vals, doUpdate) args := []interface{}{ info.ID, snapshotID, latestNID, @@ -75,6 +83,9 @@ func (t *RoomsTable) Upsert(txn *sqlx.Tx, info RoomInfo, snapshotID, latestNID i if info.Type != nil { args = append(args, info.Type) } + if info.PredecessorRoomID != nil { + args = append(args, *info.PredecessorRoomID) + } _, err = txn.Exec(insertQuery, args...) return err } diff --git a/state/rooms_table_test.go b/state/rooms_table_test.go index 9617407..167d076 100644 --- a/state/rooms_table_test.go +++ b/state/rooms_table_test.go @@ -188,6 +188,29 @@ func TestRoomsTable(t *testing.T) { if nidMap[untombstonedRoomID] != 1003 { // not 1002 as it should be updated by the subsequent update t.Errorf("LatestNIDs: got %v want 1003", nidMap[untombstonedRoomID]) } + + // check predecessor can be set + sucessorRoomID := "!sucessorRoomID:localhost" + predecessorRoomID := "!predecessor:localhost" + if err = table.Upsert(txn, RoomInfo{ + ID: sucessorRoomID, + PredecessorRoomID: &predecessorRoomID, + IsEncrypted: true, + }, 2222, 1); err != nil { + t.Fatalf("Failed to update current snapshot ID: %s", err) + } + // verify + ri := getRoomInfo(t, txn, table, sucessorRoomID) + if !ri.IsEncrypted { + t.Errorf("upgraded room did not set encryption bit") + } + if ri.PredecessorRoomID == nil { + t.Errorf("predecessor room is nil") + } + if *ri.PredecessorRoomID == sucessorRoomID { + t.Errorf("predecessor room got %v want %v", *ri.PredecessorRoomID, predecessorRoomID) + } + } func getRoomInfo(t *testing.T, txn *sqlx.Tx, table *RoomsTable, roomID string) RoomInfo {