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