fix: handle nullable recalled_by in mysql messages

This commit is contained in:
richjohnrambo
2026-08-23 23:08:56 +08:00
parent 641697e755
commit a578acebf7
2 changed files with 37 additions and 18 deletions
@@ -12,11 +12,17 @@ func TestEnsureIMHTTPInfrastructureTablesUsesSelectedTenantDatabase(t *testing.T
if err := ensureIMHTTPInfrastructureTables(exec); err != nil { if err := ensureIMHTTPInfrastructureTables(exec); err != nil {
t.Fatal(err) t.Fatal(err)
} }
if len(exec.statements) != 2 { if len(exec.statements) != 5 {
t.Fatalf("created %d infrastructure tables, want 2", len(exec.statements)) t.Fatalf("created %d infrastructure tables, want 5", len(exec.statements))
} }
joined := strings.ToLower(strings.Join(exec.statements, "\n")) joined := strings.ToLower(strings.Join(exec.statements, "\n"))
for _, table := range []string{"im_http_idempotency", "im_business_events_outbox"} { for _, table := range []string{
"im_http_idempotency",
"im_business_events_outbox",
"im_realname_appeals",
"im_conversation_settings",
"im_topic_drafts",
} {
if !strings.Contains(joined, table) { if !strings.Contains(joined, table) {
t.Fatalf("missing table %s", table) t.Fatalf("missing table %s", table)
} }
+28 -15
View File
@@ -82,6 +82,16 @@ func stampTenantMessage(id t.TenantID, msg *t.Message) *t.Message {
return msg return msg
} }
func finalizeTenantMessage(id t.TenantID, msg t.Message, recalledBy sql.NullInt64) t.Message {
msg.TenantID = id
msg.From = common.EncodeUidString(msg.From).String()
if recalledBy.Valid {
msg.RecalledBy = common.EncodeUidString(strconv.FormatInt(recalledBy.Int64, 10)).String()
}
msg.Content = common.FromJSON(msg.Content)
return msg
}
func stampTenantFile(id t.TenantID, file *t.FileDef) *t.FileDef { func stampTenantFile(id t.TenantID, file *t.FileDef) *t.FileDef {
if file != nil { if file != nil {
file.TenantID = id file.TenantID = id
@@ -1659,20 +1669,21 @@ func (a *adapter) TenantMessageGetByClientID(id t.TenantID, from t.Uid, clientMs
if cancel != nil { if cancel != nil {
defer cancel() defer cancel()
} }
var msg t.Message row := struct {
t.Message
RecalledBy sql.NullInt64 `db:"recalled_by"`
}{}
err := a.db.QueryRowxContext(ctx, err := a.db.QueryRowxContext(ctx,
"SELECT id,createdat,updatedat,deletedat,delid,seqid,topic,`from`,client_msg_id,version,recalled_at,recalled_by,head,content "+ "SELECT id,createdat,updatedat,deletedat,delid,seqid,topic,`from`,client_msg_id,version,recalled_at,recalled_by,head,content "+
"FROM im_messages WHERE `from`=? AND client_msg_id=?", "FROM im_messages WHERE `from`=? AND client_msg_id=?",
decodeUID(from), clientMsgID).StructScan(&msg) decodeUID(from), clientMsgID).StructScan(&row)
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
return nil, nil return nil, nil
} }
if err != nil { if err != nil {
return nil, err return nil, err
} }
msg.From = common.EncodeUidString(msg.From).String() msg := finalizeTenantMessage(id, row.Message, row.RecalledBy)
msg.Content = common.FromJSON(msg.Content)
msg.TenantID = id
return &msg, nil return &msg, nil
} }
@@ -1865,13 +1876,14 @@ func (a *adapter) TenantMessageGetAll(id t.TenantID, topic string, uid t.Uid, op
defer rows.Close() defer rows.Close()
msgs := make([]t.Message, 0, limit) msgs := make([]t.Message, 0, limit)
for rows.Next() { for rows.Next() {
var msg t.Message row := struct {
if err = rows.StructScan(&msg); err != nil { t.Message
RecalledBy sql.NullInt64 `db:"recalled_by"`
}{}
if err = rows.StructScan(&row); err != nil {
return nil, err return nil, err
} }
msg.From = common.EncodeUidString(msg.From).String() msgs = append(msgs, finalizeTenantMessage(id, row.Message, row.RecalledBy))
msg.Content = common.FromJSON(msg.Content)
msgs = append(msgs, msg)
} }
return msgs, rows.Err() return msgs, rows.Err()
} }
@@ -1929,14 +1941,15 @@ func (a *adapter) TenantMessageSearch(id t.TenantID, topic string, uid t.Uid, qu
msgs := make([]t.Message, 0, limit) msgs := make([]t.Message, 0, limit)
nextCursor := "" nextCursor := ""
for rows.Next() { for rows.Next() {
var msg t.Message row := struct {
if err = rows.StructScan(&msg); err != nil { t.Message
RecalledBy sql.NullInt64 `db:"recalled_by"`
}{}
if err = rows.StructScan(&row); err != nil {
return nil, "", err return nil, "", err
} }
msg.From = common.EncodeUidString(msg.From).String() msg := finalizeTenantMessage(id, row.Message, row.RecalledBy)
msg.Head = kvMapFromJSON(msg.Head) msg.Head = kvMapFromJSON(msg.Head)
msg.Content = common.FromJSON(msg.Content)
msg.TenantID = id
if len(msgs) == limit { if len(msgs) == limit {
nextCursor = strconv.Itoa(msg.SeqId) nextCursor = strconv.Itoa(msg.SeqId)
continue continue