- 只翻注释/文档字符串:剥离注释后代码行逐字节不变(机械校验只剩 4 条行尾注释的翻译,代码前缀全等) - 交叉引用(design/16 §4.6、D4/B3、0010 迁移文件名)逐字保留 - 保留未译技术词:DDL/rowid/LIKE/LEFT JOIN/DTO/rune/WS/actor 及全部标识符与表名 - 顺带副作用:store.go、session_persona_test.go 由注释文字改变而变得 gofmt 干净(未运行 gofmt -w)
45 lines
1.7 KiB
Go
45 lines
1.7 KiB
Go
package history
|
||
|
||
import (
|
||
"context"
|
||
"fmt"
|
||
)
|
||
|
||
// ListAfter 按最旧优先返回 sessionID 中严格新于 after(created_at > after)的
|
||
// 至多 limit 条消息,用于前向增量追赶:重连的客户端传入自己已见过的最新
|
||
// createdAt,只拉取错过的部分,无论有多少条("before" 游标只能向后走,无法
|
||
// 恢复大于一页的空洞)。platform 非空时把该页进一步限制为携带该来源平台的
|
||
// 消息,与 List 完全一致。rowid 打破 created_at 的并列,使同一毫秒写入的
|
||
// 消息保持插入顺序。返回切片非 nil;limit 钳制到 [1, maxPageLimit]。
|
||
func (s *Store) ListAfter(ctx context.Context, sessionID string, after int64, limit int, platform string) ([]Message, error) {
|
||
limit = clampLimit(limit)
|
||
query := `SELECT id, session_id, role, content, mode, mood, image, thinking, platform, device_id, sender_name, adapter_id, persona_id, created_at
|
||
FROM chat_messages WHERE session_id = ? AND created_at > ?`
|
||
args := []any{sessionID, after}
|
||
if platform != "" {
|
||
query += ` AND platform = ?`
|
||
args = append(args, platform)
|
||
}
|
||
query += ` ORDER BY created_at ASC, rowid ASC LIMIT ?`
|
||
args = append(args, limit)
|
||
|
||
rows, err := s.db.QueryContext(ctx, query, args...)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("history: list after %s: %w", sessionID, err)
|
||
}
|
||
defer func() { _ = rows.Close() }()
|
||
|
||
msgs := make([]Message, 0)
|
||
for rows.Next() {
|
||
m, err := scanMessage(rows)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("history: scan list after %s: %w", sessionID, err)
|
||
}
|
||
msgs = append(msgs, m)
|
||
}
|
||
if err := rows.Err(); err != nil {
|
||
return nil, fmt.Errorf("history: iterate list after %s: %w", sessionID, err)
|
||
}
|
||
return msgs, nil
|
||
}
|