返回 DeepSeek-Reasonix
topic_cursor.go
根目录 / internal / sessioncatalog / topic_cursor.go
1 package sessioncatalog
2
3 // TopicSortKeyAfterCursor reports whether a topic key belongs after an
4 // exclusive ListTopics cursor under the catalog's canonical ordering.
5 func TopicSortKeyAfterCursor(encoded string, pinned bool, activity int64, topicID string) (bool, error) {
6 return TopicSortKeyAfterCursorBound(encoded, "", pinned, activity, topicID)
7 }
8
9 // TopicSortKeyAfterCursorBound also rejects a cursor produced for a different
10 // filtered list. Metadata fallback uses this to share the catalog cursor
11 // contract without exposing cursor internals outside this package.
12 func TopicSortKeyAfterCursorBound(encoded, expectedBinding string, pinned bool, activity int64, topicID string) (bool, error) {
13 cursor, err := decodeCursor(encoded)
14 if err != nil {
15 return false, err
16 }
17 if cursor == nil {
18 return true, nil
19 }
20 if cursor.ManualOrder {
21 return false, errCursorSortModeChanged
22 }
23 if cursor.Binding != expectedBinding {
24 return false, errCursorSortModeChanged
25 }
26 pinnedValue := 0
27 if pinned {
28 pinnedValue = 1
29 }
30 return pinnedValue < cursor.Pinned ||
31 pinnedValue == cursor.Pinned && activity < cursor.Activity ||
32 pinnedValue == cursor.Pinned && activity == cursor.Activity && topicID > cursor.TopicID, nil
33 }
34
35 // TopicSortKeyAfterOrderedCursor is the manual-order counterpart used by the
36 // metadata continuity path. Its comparison exactly matches ListTopics SQL.
37 func TopicSortKeyAfterOrderedCursor(encoded string, pinned bool, sortOrder int, activity int64, topicID string) (bool, error) {
38 return TopicSortKeyAfterOrderedCursorBound(encoded, "", pinned, sortOrder, activity, topicID)
39 }
40
41 // TopicSortKeyAfterOrderedCursorBound is the bound manual-order counterpart.
42 func TopicSortKeyAfterOrderedCursorBound(encoded, expectedBinding string, pinned bool, sortOrder int, activity int64, topicID string) (bool, error) {
43 cursor, err := decodeCursor(encoded)
44 if err != nil {
45 return false, err
46 }
47 if cursor == nil {
48 return true, nil
49 }
50 if !cursor.ManualOrder {
51 return false, errCursorSortModeChanged
52 }
53 if cursor.Binding != expectedBinding {
54 return false, errCursorSortModeChanged
55 }
56 pinnedValue := 0
57 if pinned {
58 pinnedValue = 1
59 }
60 manualSortOrder := int64(sortOrder)
61 if sortOrder < 0 {
62 manualSortOrder = unrankedTopicSortOrder
63 }
64 return pinnedValue < cursor.Pinned ||
65 pinnedValue == cursor.Pinned && manualSortOrder > cursor.SortOrder ||
66 pinnedValue == cursor.Pinned && manualSortOrder == cursor.SortOrder && activity < cursor.Activity ||
67 pinnedValue == cursor.Pinned && manualSortOrder == cursor.SortOrder && activity == cursor.Activity && topicID > cursor.TopicID, nil
68 }
69
69 lines GO