access_tracking.go raw
1 package neo4j
2
3 import (
4 "context"
5 "fmt"
6 "time"
7 )
8
9 // RecordEventAccess updates access tracking for an event in Neo4j.
10 // This creates or updates an AccessTrack node for the event.
11 func (n *N) RecordEventAccess(serial uint64, connectionID string) error {
12 cypher := `
13 MERGE (a:AccessTrack {serial: $serial})
14 ON CREATE SET a.lastAccess = $now, a.count = 1
15 ON MATCH SET a.lastAccess = $now, a.count = a.count + 1`
16
17 params := map[string]any{
18 "serial": int64(serial), // Neo4j uses int64
19 "now": time.Now().Unix(),
20 }
21
22 _, err := n.ExecuteWrite(context.Background(), cypher, params)
23 if err != nil {
24 return fmt.Errorf("failed to record event access: %w", err)
25 }
26
27 return nil
28 }
29
30 // GetEventAccessInfo returns access information for an event.
31 func (n *N) GetEventAccessInfo(serial uint64) (lastAccess int64, accessCount uint32, err error) {
32 cypher := "MATCH (a:AccessTrack {serial: $serial}) RETURN a.lastAccess AS lastAccess, a.count AS count"
33 params := map[string]any{"serial": int64(serial)}
34
35 result, err := n.ExecuteRead(context.Background(), cypher, params)
36 if err != nil {
37 return 0, 0, fmt.Errorf("failed to get event access info: %w", err)
38 }
39
40 ctx := context.Background()
41 if result.Next(ctx) {
42 record := result.Record()
43 if record != nil {
44 if la, found := record.Get("lastAccess"); found {
45 if v, ok := la.(int64); ok {
46 lastAccess = v
47 }
48 }
49 if c, found := record.Get("count"); found {
50 if v, ok := c.(int64); ok {
51 accessCount = uint32(v)
52 }
53 }
54 }
55 }
56
57 return lastAccess, accessCount, nil
58 }
59
60 // GetLeastAccessedEvents returns event serials sorted by coldness.
61 func (n *N) GetLeastAccessedEvents(limit int, minAgeSec int64) (serials []uint64, err error) {
62 cutoffTime := time.Now().Unix() - minAgeSec
63
64 cypher := `
65 MATCH (a:AccessTrack)
66 WHERE a.lastAccess < $cutoff
67 RETURN a.serial AS serial, a.lastAccess AS lastAccess, a.count AS count
68 ORDER BY (a.lastAccess + a.count * 3600) ASC
69 LIMIT $limit`
70
71 params := map[string]any{
72 "cutoff": cutoffTime,
73 "limit": limit,
74 }
75
76 result, err := n.ExecuteRead(context.Background(), cypher, params)
77 if err != nil {
78 return nil, fmt.Errorf("failed to get least accessed events: %w", err)
79 }
80
81 ctx := context.Background()
82 for result.Next(ctx) {
83 record := result.Record()
84 if record != nil {
85 if s, found := record.Get("serial"); found {
86 if v, ok := s.(int64); ok {
87 serials = append(serials, uint64(v))
88 }
89 }
90 }
91 }
92
93 return serials, nil
94 }
95