fix(store): 修正邻接查询、GC 竞态、备份权限与设置解析,新增 OpenData 纯数据打开

邻接查询 tie-break 与 pinned 排序键与列表序对齐,补表驱动测试(round2 P1-1); GC DELETE 带条件复查,防 SELECT 与 DELETE 间恢复/引用竞态(P2-6); 备份经 umask 收紧创建即 0600,消除 chmod 前暴露窗口(P2-7); page_size 改 strconv.Atoi 全文解析,拒部分解析脏值(P2-13); OpenData 不迁移、不做版本守卫(D6/P1-5)。
This commit is contained in:
2026-09-08 17:32:47 +08:00
parent a885b52f18
commit 132c4a1ba2
5 changed files with 162 additions and 26 deletions
+12 -9
View File
@@ -183,23 +183,26 @@ func (s *Store) ListPublicNotes(page, pageSize int, tag string) ([]Note, int, er
return out, total, rows.Err()
}
// AdjacentPublicNote 返回公开序列中与 n 相邻的上一篇/下一篇
// (按列表序 updated_at DESC, id DESC)。仅返回 slug 与 title。
// AdjacentPublicNote 返回公开列表中与 n 相邻的上一篇/下一篇。
// 列表序为 pinned DESC, updated_at DESC, id DESC(notes.go ListPublicNotes),
// prev = 列表中紧邻 n 之前的一篇(元组 (pinned, updated_at, id) 字典序更大侧的最小项),
// next = 紧邻之后的一篇(字典序更小侧的最大项)。仅返回 slug 与 title。
func (s *Store) AdjacentPublicNote(n *Note, dir string) (slug, title string, err error) {
p := boolToInt(n.Pinned)
var q string
switch dir {
case "prev": // 列表中更早的一篇
case "prev": // 列表中位于 n 之前的一篇
q = `SELECT slug, title FROM notes WHERE ` + PublicNoteFilter + `
AND (updated_at > ? OR (updated_at = ? AND id < ?))
ORDER BY updated_at ASC, id DESC LIMIT 1`
case "next": // 列表中更新的一篇
AND (pinned > ? OR (pinned = ? AND (updated_at > ? OR (updated_at = ? AND id > ?))))
ORDER BY pinned ASC, updated_at ASC, id ASC LIMIT 1`
case "next": // 列表中位于 n 之后的一篇
q = `SELECT slug, title FROM notes WHERE ` + PublicNoteFilter + `
AND (updated_at < ? OR (updated_at = ? AND id > ?))
ORDER BY updated_at DESC, id ASC LIMIT 1`
AND (pinned < ? OR (pinned = ? AND (updated_at < ? OR (updated_at = ? AND id < ?))))
ORDER BY pinned DESC, updated_at DESC, id DESC LIMIT 1`
default:
return "", "", fmt.Errorf("dir 必须为 prev|next")
}
row := s.db.QueryRow(q, n.UpdatedAt, n.UpdatedAt, n.ID)
row := s.db.QueryRow(q, p, p, n.UpdatedAt, n.UpdatedAt, n.ID)
if err := row.Scan(&slug, &title); err != nil {
if errors.Is(err, sql.ErrNoRows) {
return "", "", nil