storage

package
v0.1.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 11, 2026 License: MIT Imports: 20 Imported by: 0

Documentation

Overview

Package storage is yaad's persistence layer: a CGO-free SQLite store with FTS5 search, prepared-statement caching, and busy-retry, plus the Storage interface the rest of the system depends on.

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrNodeNotFound      = errors.New("node not found")
	ErrEdgeNotFound      = errors.New("edge not found")
	ErrSessionNotFound   = errors.New("session not found")
	ErrCycleDetected     = errors.New("cycle detected")
	ErrDuplicateNode     = errors.New("duplicate node")
	ErrDuplicateEdge     = errors.New("duplicate edge")
	ErrInvalidNodeType   = errors.New("invalid node type")
	ErrInvalidEdgeType   = errors.New("invalid edge type")
	ErrContentTooLong    = errors.New("content exceeds maximum length")
	ErrEmptyContent      = errors.New("content cannot be empty")
	ErrDatabaseLocked    = errors.New("database is locked")
	ErrBatchTooLarge     = errors.New("batch size exceeds database limit")
	ErrVersionNotFound   = errors.New("version not found")
	ErrEmbeddingNotFound = errors.New("embedding not found")
)

Domain-specific errors for the storage layer. Callers should use errors.Is() to check for specific error conditions.

Error return conventions:

  • GetNode, GetEdge: returns the sentinel error wrapped with the ID when not found
  • SearchNodeByHash, GetNodeByKey: returns (nil, nil) when not found (dedup/upsert pattern)

Functions

func ComputeSchemaFingerprint

func ComputeSchemaFingerprint(chunkerVersion, embeddingModel string) string

ComputeSchemaFingerprint returns a hex-encoded 128-bit hash of the chunker version and embedding model, suitable for invalidating all chunks when the indexing pipeline changes. Uses SHA-256 truncated to 16 bytes.

func ComputeSchemaVersion

func ComputeSchemaVersion(chunkerVersion, modelName string) string

ComputeSchemaVersion produces a version string from the chunker version and embedding model name. It is the first 16 hex chars of a SHA-256 hash.

func DecodeVector

func DecodeVector(b []byte) []float32

DecodeVector decodes a byte slice from SQLite BLOB to a float32 slice.

func EncodeVector

func EncodeVector(v []float32) []byte

EncodeVector encodes a float32 slice to a byte slice for SQLite BLOB storage.

func FormatPredictions

func FormatPredictions(predictions []Behavior) string

FormatPredictions formats a list of predicted behaviors into a readable string.

func IsAcyclic

func IsAcyclic(edgeType string) bool

IsAcyclic returns true if the edge type enforces DAG constraint.

Types

type Behavior

type Behavior struct {
	ID         string
	Pattern    string    // what the user tends to do
	Frequency  int       // how many times observed
	LastSeen   time.Time // last time this behavior occurred
	Context    string    // when/where this happens
	Confidence float64   // how confident we are this is a real pattern
}

Behavior represents a tracked user pattern or habit.

type BehaviorTracker

type BehaviorTracker struct {
	// contains filtered or unexported fields
}

BehaviorTracker tracks user behaviors and predicts future actions.

func NewBehaviorTracker

func NewBehaviorTracker() *BehaviorTracker

NewBehaviorTracker creates a new BehaviorTracker.

func (*BehaviorTracker) GetBehaviors

func (bt *BehaviorTracker) GetBehaviors() []Behavior

GetBehaviors returns a copy of all tracked behaviors.

func (*BehaviorTracker) GetTopPatterns

func (bt *BehaviorTracker) GetTopPatterns(limit int) []Behavior

GetTopPatterns returns the most frequent behaviors across all contexts, limited to the given count.

func (*BehaviorTracker) Predict

func (bt *BehaviorTracker) Predict(context string) []Behavior

Predict returns behaviors that match the given context, ranked by a score combining frequency and recency.

func (*BehaviorTracker) Track

func (bt *BehaviorTracker) Track(action, context string)

Track records a user action within a given context. If a matching pattern already exists for the same context, its frequency is incremented and LastSeen is updated. Otherwise a new Behavior entry is created.

type CodeChunkRecord

type CodeChunkRecord struct {
	ID            string `json:"id"`
	Path          string `json:"path"`
	StartLine     int    `json:"start_line"`
	EndLine       int    `json:"end_line"`
	Content       string `json:"content"`
	Symbol        string `json:"symbol"`
	Language      string `json:"language"`
	Tokens        int    `json:"tokens"`
	FileHash      string `json:"file_hash"`
	SchemaVersion string `json:"schema_version"`
	Vector        []byte `json:"vector,omitempty"` // embedding stored as BLOB
}

CodeChunkRecord represents a stored code chunk in the index.

type DoctorStatsResult

type DoctorStatsResult struct {
	TotalNodes    int
	LowConfidence int // nodes with confidence < 0.2
	Pinned        int
	Orphans       int // nodes with zero edges (inbound or outbound)
}

DoctorStatsResult holds aggregated diagnostic counts computed via SQL without loading individual nodes into memory.

type Edge

type Edge struct {
	ID, FromID, ToID, Type, Metadata string
	Acyclic                          bool
	Weight                           float64
	ValidAt                          time.Time // when the fact became true (zero = since creation)
	InvalidAt                        time.Time // when the fact stopped being true (zero = still valid)
	CreatedAt                        time.Time
}

Edge represents a relationship between two nodes in the graph.

type MockStorage

type MockStorage struct {
	// contains filtered or unexported fields
}

MockStorage is a public, concurrency-safe, in-memory implementation of the Storage interface. It is designed for use in unit tests across packages (engine/, cmd/, etc.) without requiring SQLite.

All methods honour the error injected via SetError when non-nil.

func NewMockStorage

func NewMockStorage() *MockStorage

NewMockStorage returns a ready-to-use MockStorage.

func (*MockStorage) AddFileWatch

func (m *MockStorage) AddFileWatch(_ context.Context, filePath, nodeID, gitHash string) error

func (*MockStorage) AddReplayEvent

func (m *MockStorage) AddReplayEvent(_ context.Context, sessionID, data string) error

func (*MockStorage) AllEmbeddings

func (m *MockStorage) AllEmbeddings(_ context.Context, model string) (map[string][]float32, error)

func (*MockStorage) CheckCycle

func (m *MockStorage) CheckCycle(_ context.Context, fromID, toID string) (bool, error)

func (*MockStorage) Close

func (m *MockStorage) Close() error

func (*MockStorage) CountAllEdges

func (m *MockStorage) CountAllEdges(_ context.Context) (int, error)

func (*MockStorage) CountEdges

func (m *MockStorage) CountEdges(_ context.Context, nodeID string) (int, int, error)

func (*MockStorage) CountEdgesBatch

func (m *MockStorage) CountEdgesBatch(_ context.Context, nodeIDs []string) (map[string][2]int, error)

func (*MockStorage) CreateEdge

func (m *MockStorage) CreateEdge(_ context.Context, e *Edge) error

func (*MockStorage) CreateNode

func (m *MockStorage) CreateNode(_ context.Context, n *Node) error

func (*MockStorage) CreateSession

func (m *MockStorage) CreateSession(_ context.Context, sess *Session) error

func (*MockStorage) DeleteEdge

func (m *MockStorage) DeleteEdge(_ context.Context, id string) error

func (*MockStorage) DeleteEmbedding

func (m *MockStorage) DeleteEmbedding(_ context.Context, nodeID string) error

func (*MockStorage) DeleteNode

func (m *MockStorage) DeleteNode(_ context.Context, id string) error

func (*MockStorage) DoctorStats

func (m *MockStorage) DoctorStats(_ context.Context) (DoctorStatsResult, error)

func (*MockStorage) EdgeCount

func (m *MockStorage) EdgeCount() int

EdgeCount returns the number of stored edges (for quick assertions).

func (*MockStorage) EndSession

func (m *MockStorage) EndSession(_ context.Context, id string, summary string) error

func (*MockStorage) FlushAccessLog

func (m *MockStorage) FlushAccessLog(_ context.Context) (int, error)

func (*MockStorage) GetAllEdgesFor

func (m *MockStorage) GetAllEdgesFor(_ context.Context, nodeIDs []string) ([]*Edge, error)

func (*MockStorage) GetAllSignatures

func (m *MockStorage) GetAllSignatures(_ context.Context) (map[string]string, error)

func (*MockStorage) GetEdge

func (m *MockStorage) GetEdge(_ context.Context, id string) (*Edge, error)

func (*MockStorage) GetEdgesBetween

func (m *MockStorage) GetEdgesBetween(_ context.Context, nodeIDs []string) ([]*Edge, error)

func (*MockStorage) GetEdgesFrom

func (m *MockStorage) GetEdgesFrom(_ context.Context, nodeID string) ([]*Edge, error)

func (*MockStorage) GetEdgesTo

func (m *MockStorage) GetEdgesTo(_ context.Context, nodeID string) ([]*Edge, error)

func (*MockStorage) GetEmbedding

func (m *MockStorage) GetEmbedding(_ context.Context, nodeID string) ([]float32, string, error)

func (*MockStorage) GetEmbeddingsBatch

func (m *MockStorage) GetEmbeddingsBatch(_ context.Context, model string, offset, limit int) (map[string][]float32, error)

func (*MockStorage) GetNeighbors

func (m *MockStorage) GetNeighbors(_ context.Context, nodeID string) ([]*Node, error)

func (*MockStorage) GetNode

func (m *MockStorage) GetNode(_ context.Context, id string) (*Node, error)

func (*MockStorage) GetNodeByKey

func (m *MockStorage) GetNodeByKey(_ context.Context, key, project string) (*Node, error)

func (*MockStorage) GetNodesBatch

func (m *MockStorage) GetNodesBatch(_ context.Context, ids []string) ([]*Node, error)

func (*MockStorage) GetReplayEvents

func (m *MockStorage) GetReplayEvents(_ context.Context, sessionID string) ([]*ReplayEvent, error)

func (*MockStorage) GetValidEdgesFrom

func (m *MockStorage) GetValidEdgesFrom(_ context.Context, nodeID string, at time.Time) ([]*Edge, error)

func (*MockStorage) GetValidEdgesTo

func (m *MockStorage) GetValidEdgesTo(_ context.Context, nodeID string, at time.Time) ([]*Edge, error)

func (*MockStorage) GetVersions

func (m *MockStorage) GetVersions(_ context.Context, nodeID string) ([]*NodeVersion, error)

func (*MockStorage) InjectEdges

func (m *MockStorage) InjectEdges(edges ...*Edge)

InjectEdges seeds the mock with pre-built edges (bypasses error check).

func (*MockStorage) InjectNodes

func (m *MockStorage) InjectNodes(nodes ...*Node)

InjectNodes seeds the mock with pre-built nodes (bypasses error check).

func (*MockStorage) InvalidateEdge

func (m *MockStorage) InvalidateEdge(_ context.Context, id string) error

func (*MockStorage) LastUpdated

func (m *MockStorage) LastUpdated(_ context.Context) (time.Time, error)

func (*MockStorage) ListNodes

func (m *MockStorage) ListNodes(_ context.Context, f NodeFilter) ([]*Node, error)

func (*MockStorage) ListSessions

func (m *MockStorage) ListSessions(_ context.Context, project string, limit int) ([]*Session, error)

func (*MockStorage) LoadNodeMetadata

func (m *MockStorage) LoadNodeMetadata(_ context.Context, nodeIDs []string) (map[string]map[string]string, error)

func (*MockStorage) LogAccess

func (m *MockStorage) LogAccess(_ context.Context, nodeID string) error

func (*MockStorage) NodeCount

func (m *MockStorage) NodeCount() int

NodeCount returns the number of stored nodes (for quick assertions).

func (*MockStorage) NodeStats

func (m *MockStorage) NodeStats(_ context.Context) (map[string]int, int, error)

func (*MockStorage) SaveEmbedding

func (m *MockStorage) SaveEmbedding(_ context.Context, nodeID, model string, vector []float32) error

func (*MockStorage) SaveNodeMetadata

func (m *MockStorage) SaveNodeMetadata(_ context.Context, nodeID string, meta map[string]string) error

func (*MockStorage) SaveSignature

func (m *MockStorage) SaveSignature(_ context.Context, nodeID, signature string) error

func (*MockStorage) SaveVersion

func (m *MockStorage) SaveVersion(_ context.Context, nodeID string, content, changedBy, reason string) error

func (*MockStorage) SearchNodeByHash

func (m *MockStorage) SearchNodeByHash(_ context.Context, hash, scope, project string) (*Node, error)

func (*MockStorage) SearchNodes

func (m *MockStorage) SearchNodes(_ context.Context, query string, limit int) ([]*Node, error)

func (*MockStorage) SetError

func (m *MockStorage) SetError(err error)

SetError configures a non-nil error that every method will return. Pass nil to clear the injected error.

func (*MockStorage) String

func (m *MockStorage) String() string

String returns a human-readable summary useful in test failure output.

func (*MockStorage) TopConnected

func (m *MockStorage) TopConnected(_ context.Context, limit int) ([]string, error)

func (*MockStorage) UpdateNode

func (m *MockStorage) UpdateNode(_ context.Context, n *Node) error

func (*MockStorage) UpdateNodeContent

func (m *MockStorage) UpdateNodeContent(_ context.Context, id, newContent string) error

func (*MockStorage) WithTx

func (m *MockStorage) WithTx(_ context.Context, fn func(Storage) error) error

WithTx executes fn with m itself as the "transaction". In-memory maps are already consistent so no real txn boundary is needed.

type Node

type Node struct {
	ID, Type, Content, ContentHash, Summary, Scope, Project, Tags string
	Key                                                           string // optional unique key per project (upsert semantics)
	Pinned                                                        bool   // pinned nodes always appear in context
	Tier                                                          int
	Confidence                                                    float64
	AccessCount                                                   int
	CreatedAt, UpdatedAt, AccessedAt                              time.Time
	SourceSession, SourceAgent                                    string
	Version                                                       int
	Metadata                                                      map[string]string // structured key-value metadata (stored in node_metadata table)
}

Node represents a memory node in the Yaad graph.

type NodeFilter

type NodeFilter struct {
	Type, Scope, Project string
	Tier                 int
	MinConfidence        float64
	SourceSession        string
	Pinned               *bool             // filter by pinned status (nil = no filter)
	Tag                  string            // exact tag match within the CSV tags column (delimiter-aware)
	MetadataFilters      map[string]string // key-value metadata filters (all must match, AND semantics)
	Limit                int               // max results (0 = default 1000)
	Offset               int               // skip first N results (for pagination)
}

NodeFilter specifies criteria for listing nodes.

type NodeVersion

type NodeVersion struct {
	NodeID, Content, ChangedBy, Reason string
	Version                            int
	ChangedAt                          time.Time
}

NodeVersion stores a historical version of a node for audit/rollback.

type ReplayEvent

type ReplayEvent struct {
	ID        int64
	SessionID string
	Data      string // JSON
	CreatedAt time.Time
}

ReplayEvent is a raw tool event stored for session replay.

type Session

type Session struct {
	ID, Project, Summary, Agent string
	StartedAt, EndedAt          time.Time
}

Session tracks a session.

type Storage

type Storage interface {
	// Nodes
	CreateNode(ctx context.Context, n *Node) error
	GetNode(ctx context.Context, id string) (*Node, error)
	GetNodeByKey(ctx context.Context, key, project string) (*Node, error)
	GetNodesBatch(ctx context.Context, ids []string) ([]*Node, error)
	UpdateNode(ctx context.Context, n *Node) error
	UpdateNodeContent(ctx context.Context, id, newContent string) error
	DeleteNode(ctx context.Context, id string) error
	ListNodes(ctx context.Context, f NodeFilter) ([]*Node, error)
	SearchNodes(ctx context.Context, query string, limit int) ([]*Node, error)
	SearchNodeByHash(ctx context.Context, hash, scope, project string) (*Node, error)
	GetNeighbors(ctx context.Context, nodeID string) ([]*Node, error)

	// Edges
	CreateEdge(ctx context.Context, e *Edge) error
	GetEdge(ctx context.Context, id string) (*Edge, error)
	InvalidateEdge(ctx context.Context, id string) error // non-destructive: sets invalid_at = now
	DeleteEdge(ctx context.Context, id string) error
	GetEdgesFrom(ctx context.Context, nodeID string) ([]*Edge, error)
	GetEdgesTo(ctx context.Context, nodeID string) ([]*Edge, error)
	// Point-in-time validity queries: return only edges that were valid at the
	// given instant (valid_at <= at AND (invalid_at IS NULL OR invalid_at > at)).
	// A zero `at` is treated as "now". Default edge readers are unaffected.
	GetValidEdgesFrom(ctx context.Context, nodeID string, at time.Time) ([]*Edge, error)
	GetValidEdgesTo(ctx context.Context, nodeID string, at time.Time) ([]*Edge, error)
	GetEdgesBetween(ctx context.Context, nodeIDs []string) ([]*Edge, error)
	GetAllEdgesFor(ctx context.Context, nodeIDs []string) ([]*Edge, error) // edges where from_id OR to_id in set
	CountEdges(ctx context.Context, nodeID string) (inbound int, outbound int, err error)
	CountEdgesBatch(ctx context.Context, nodeIDs []string) (map[string][2]int, error)
	CountAllEdges(ctx context.Context) (int, error)

	// Stats
	NodeStats(ctx context.Context) (map[string]int, int, error) // nodesByType, totalNodes, err
	DoctorStats(ctx context.Context) (DoctorStatsResult, error) // aggregated diagnostics without loading nodes
	LastUpdated(ctx context.Context) (time.Time, error)
	TopConnected(ctx context.Context, limit int) ([]string, error)

	// Graph queries (encapsulates recursive CTEs)
	CheckCycle(ctx context.Context, fromID, toID string) (bool, error)

	// Sessions
	CreateSession(ctx context.Context, sess *Session) error
	EndSession(ctx context.Context, id string, summary string) error
	ListSessions(ctx context.Context, project string, limit int) ([]*Session, error)

	// Versions
	SaveVersion(ctx context.Context, nodeID string, content, changedBy, reason string) error
	GetVersions(ctx context.Context, nodeID string) ([]*NodeVersion, error)

	// Embeddings
	SaveEmbedding(ctx context.Context, nodeID, model string, vector []float32) error
	GetEmbedding(ctx context.Context, nodeID string) ([]float32, string, error)
	DeleteEmbedding(ctx context.Context, nodeID string) error
	// AllEmbeddings / GetEmbeddingsBatch take a model filter ("" = all models):
	// vectors from different embedding models occupy incompatible spaces and must
	// not be mixed into one similarity comparison.
	AllEmbeddings(ctx context.Context, model string) (map[string][]float32, error)
	GetEmbeddingsBatch(ctx context.Context, model string, offset, limit int) (map[string][]float32, error)

	// Replay
	AddReplayEvent(ctx context.Context, sessionID, data string) error
	GetReplayEvents(ctx context.Context, sessionID string) ([]*ReplayEvent, error)

	// File watch (staleness tracking)
	AddFileWatch(ctx context.Context, filePath, nodeID, gitHash string) error

	// AccessLog: lightweight access tracking (batched flush)
	LogAccess(ctx context.Context, nodeID string) error
	FlushAccessLog(ctx context.Context) (int, error)

	// Metadata: structured key-value metadata per node
	SaveNodeMetadata(ctx context.Context, nodeID string, meta map[string]string) error
	LoadNodeMetadata(ctx context.Context, nodeIDs []string) (map[string]map[string]string, error)

	// Signatures: HMAC integrity signatures for tamper detection
	SaveSignature(ctx context.Context, nodeID, signature string) error
	GetAllSignatures(ctx context.Context) (map[string]string, error)

	// Transactions
	WithTx(ctx context.Context, fn func(Storage) error) error

	Close() error
}

Storage is the persistence interface used by Engine and other packages. All graph-aware queries (recursive CTEs, cycle detection) are encapsulated behind methods so callers never need raw *sql.DB access.

type Store

type Store struct {
	// contains filtered or unexported fields
}

func NewStore

func NewStore(dbPath string) (*Store, error)

func (*Store) AddFileWatch

func (s *Store) AddFileWatch(ctx context.Context, filePath, nodeID, gitHash string) error

func (*Store) AddReplayEvent

func (s *Store) AddReplayEvent(ctx context.Context, sessionID, data string) error

AddReplayEvent stores a tool event for replay.

func (*Store) AllEmbeddings

func (s *Store) AllEmbeddings(ctx context.Context, model string) (map[string][]float32, error)

AllEmbeddings returns all stored embeddings as (nodeID, vector) pairs. When model is non-empty, only that model's embeddings are returned; pass "" to retrieve every model. See GetEmbeddingsBatch for why mixing models is unsafe.

func (*Store) CheckCycle

func (s *Store) CheckCycle(ctx context.Context, fromID, toID string) (bool, error)

CheckCycle uses a recursive CTE to detect if adding from->to would create a cycle among acyclic edges.

func (*Store) Close

func (s *Store) Close() error

func (*Store) CountAllEdges

func (s *Store) CountAllEdges(ctx context.Context) (int, error)

CountAllEdges returns the total number of edges in the graph.

func (*Store) CountEdges

func (s *Store) CountEdges(ctx context.Context, nodeID string) (inbound int, outbound int, err error)

CountEdges returns inbound and outbound edge counts for a node.

func (*Store) CountEdgesBatch

func (s *Store) CountEdgesBatch(ctx context.Context, nodeIDs []string) (map[string][2]int, error)

CountEdgesBatch returns inbound/outbound edge counts for multiple nodes in a single query.

func (*Store) CreateCodeIndex

func (s *Store) CreateCodeIndex(ctx context.Context) error

CreateCodeIndex creates the code_chunks table and its FTS5 virtual table. Safe to call multiple times (uses IF NOT EXISTS).

func (*Store) CreateEdge

func (s *Store) CreateEdge(ctx context.Context, e *Edge) error

func (*Store) CreateNode

func (s *Store) CreateNode(ctx context.Context, n *Node) error

func (*Store) CreateSession

func (s *Store) CreateSession(ctx context.Context, sess *Session) error

func (*Store) DB

func (s *Store) DB() *sql.DB

DB returns the underlying database connection for direct queries.

func (*Store) DeleteChunksByPath

func (s *Store) DeleteChunksByPath(ctx context.Context, path string) error

DeleteChunksByPath removes all code chunks for a given file path.

func (*Store) DeleteEdge

func (s *Store) DeleteEdge(ctx context.Context, id string) error

func (*Store) DeleteEmbedding

func (s *Store) DeleteEmbedding(ctx context.Context, nodeID string) error

DeleteEmbedding removes a vector embedding for a node.

func (*Store) DeleteNode

func (s *Store) DeleteNode(ctx context.Context, id string) error

func (*Store) DiffVersions

func (s *Store) DiffVersions(ctx context.Context, nodeID string, v1, v2 int) (content1, content2 string, err error)

DiffVersions returns the content of two versions for comparison.

func (*Store) DoctorStats

func (s *Store) DoctorStats(ctx context.Context) (DoctorStatsResult, error)

DoctorStats returns aggregated diagnostic counts via SQL without loading individual nodes into memory.

func (*Store) EndSession

func (s *Store) EndSession(ctx context.Context, id string, summary string) error

func (*Store) FillNodeMetadata

func (s *Store) FillNodeMetadata(ctx context.Context, nodes []*Node) error

FillNodeMetadata loads metadata for all given nodes in one batch query and populates each node's Metadata field in-place. No-op for an empty slice.

func (*Store) FindByPrefix

func (s *Store) FindByPrefix(ctx context.Context, prefix string) ([]*Node, error)

FindByPrefix returns nodes whose ID starts with the given prefix. Returns at most 10 results. The prefix must be at least 1 character.

func (*Store) FlushAccessLog

func (s *Store) FlushAccessLog(ctx context.Context) (int, error)

FlushAccessLog aggregates access_log entries into nodes.access_count / accessed_at, then truncates the log. Runs atomically within a transaction.

func (*Store) GetAllEdgesFor

func (s *Store) GetAllEdgesFor(ctx context.Context, nodeIDs []string) ([]*Edge, error)

GetAllEdgesFor returns all edges where from_id OR to_id is in the given set. Used by IntentBFS for batch edge retrieval (avoids N+1 queries).

func (*Store) GetAllSignatures

func (s *Store) GetAllSignatures(ctx context.Context) (map[string]string, error)

func (*Store) GetEdge

func (s *Store) GetEdge(ctx context.Context, id string) (*Edge, error)

GetEdge retrieves an edge by its primary key ID. Returns ErrEdgeNotFound wrapped with the ID when no row is found.

func (*Store) GetEdgesBetween

func (s *Store) GetEdgesBetween(ctx context.Context, nodeIDs []string) ([]*Edge, error)

func (*Store) GetEdgesFrom

func (s *Store) GetEdgesFrom(ctx context.Context, nodeID string) ([]*Edge, error)

func (*Store) GetEdgesTo

func (s *Store) GetEdgesTo(ctx context.Context, nodeID string) ([]*Edge, error)

func (*Store) GetEmbedding

func (s *Store) GetEmbedding(ctx context.Context, nodeID string) ([]float32, string, error)

GetEmbedding retrieves the embedding for a node.

func (*Store) GetEmbeddingsBatch

func (s *Store) GetEmbeddingsBatch(ctx context.Context, model string, offset, limit int) (map[string][]float32, error)

GetEmbeddingsBatch returns a paginated batch of embeddings. When model is non-empty, only embeddings produced by that model are returned — vectors from a different model live in an incompatible vector space and must never be mixed into a single cosine/ANN comparison. Pass "" to retrieve all models (e.g. for maintenance or migration).

func (*Store) GetFileHash

func (s *Store) GetFileHash(ctx context.Context, path string) (string, error)

GetFileHash returns the file hash for the first chunk of the given path.

func (*Store) GetNeighbors

func (s *Store) GetNeighbors(ctx context.Context, nodeID string) ([]*Node, error)

func (*Store) GetNode

func (s *Store) GetNode(ctx context.Context, id string) (*Node, error)

GetNode retrieves a node by its primary key ID. Returns ErrNodeNotFound wrapped with the ID when no row is found.

func (*Store) GetNodeByKey

func (s *Store) GetNodeByKey(ctx context.Context, key, project string) (*Node, error)

GetNodeByKey looks up a node by its unique key within a project. Returns (nil, nil) when no matching node is found (upsert check pattern).

func (*Store) GetNodesBatch

func (s *Store) GetNodesBatch(ctx context.Context, ids []string) ([]*Node, error)

func (*Store) GetNodesByFile

func (s *Store) GetNodesByFile(ctx context.Context, filePath string) ([]*Node, error)

func (*Store) GetReplayEvents

func (s *Store) GetReplayEvents(ctx context.Context, sessionID string) ([]*ReplayEvent, error)

GetReplayEvents returns all events for a session in order.

func (*Store) GetValidEdgesFrom

func (s *Store) GetValidEdgesFrom(ctx context.Context, nodeID string, at time.Time) ([]*Edge, error)

GetValidEdgesFrom returns outbound edges from nodeID that were valid at the given instant: valid_at <= at AND (invalid_at IS NULL OR invalid_at > at). A zero `at` defaults to now, giving a "currently valid" view. This is a point-in-time variant of GetEdgesFrom; the latter is left unchanged so existing callers keep their current behavior.

func (*Store) GetValidEdgesTo

func (s *Store) GetValidEdgesTo(ctx context.Context, nodeID string, at time.Time) ([]*Edge, error)

GetValidEdgesTo is the inbound counterpart of GetValidEdgesFrom.

func (*Store) GetVersions

func (s *Store) GetVersions(ctx context.Context, nodeID string) ([]*NodeVersion, error)

func (*Store) InvalidateEdge

func (s *Store) InvalidateEdge(ctx context.Context, id string) error

func (*Store) InvalidateStaleChunks

func (s *Store) InvalidateStaleChunks(ctx context.Context, currentVersion string) (int, error)

InvalidateStaleChunks deletes all code chunks whose schema_version does not match currentVersion, returning the count of deleted rows.

func (*Store) LastUpdated

func (s *Store) LastUpdated(ctx context.Context) (time.Time, error)

LastUpdated returns the most recent updated_at time across all nodes.

func (*Store) ListIndexedPaths

func (s *Store) ListIndexedPaths(ctx context.Context) ([]string, error)

ListIndexedPaths returns all distinct file paths that have indexed chunks.

func (*Store) ListNodes

func (s *Store) ListNodes(ctx context.Context, f NodeFilter) ([]*Node, error)

func (*Store) ListSessions

func (s *Store) ListSessions(ctx context.Context, project string, limit int) ([]*Session, error)

func (*Store) LoadNodeMetadata

func (s *Store) LoadNodeMetadata(ctx context.Context, nodeIDs []string) (map[string]map[string]string, error)

func (*Store) LogAccess

func (s *Store) LogAccess(ctx context.Context, nodeID string) error

LogAccess records a lightweight access event (INSERT only, no UPDATE churn).

func (*Store) NodeStats

func (s *Store) NodeStats(ctx context.Context) (map[string]int, int, error)

NodeStats returns nodes grouped by type and total count.

func (*Store) RefreshCodeIndex

func (s *Store) RefreshCodeIndex(ctx context.Context, paths []string, hashFn func(string) string) (int, error)

RefreshCodeIndex checks each path for staleness by comparing the current file hash (via hashFn) against the stored hash. Returns the count of stale files.

func (*Store) RollbackToVersion

func (s *Store) RollbackToVersion(ctx context.Context, nodeID string, version int) error

RollbackToVersion restores a node's content to a specific version. All operations run inside a single transaction to prevent concurrent modifications from interleaving between the SELECT and UPDATE.

func (*Store) SaveEmbedding

func (s *Store) SaveEmbedding(ctx context.Context, nodeID, model string, vector []float32) error

SaveEmbedding stores a vector embedding for a node.

Like every other write path it retries on SQLITE_BUSY: embedding writes run outside the engine's write lock and can briefly contend with the async ingestion goroutine for the single SQLite writer.

func (*Store) SaveNodeMetadata

func (s *Store) SaveNodeMetadata(ctx context.Context, nodeID string, meta map[string]string) error

func (*Store) SaveSignature

func (s *Store) SaveSignature(ctx context.Context, nodeID, signature string) error

func (*Store) SaveVersion

func (s *Store) SaveVersion(ctx context.Context, nodeID string, content, changedBy, reason string) error

func (*Store) SearchCodeChunksByLanguage

func (s *Store) SearchCodeChunksByLanguage(ctx context.Context, query string, languages []string, limit int) ([]*CodeChunkRecord, error)

SearchCodeChunksByLanguage performs a full-text search filtered by language. If languages is empty, calls existing SearchCodeChunksFTS. If one language, adds a WHERE language = ? filter. If multiple languages, runs separate queries per language and merges via min-heap.

func (*Store) SearchCodeChunksFTS

func (s *Store) SearchCodeChunksFTS(ctx context.Context, query string, limit int) ([]*CodeChunkRecord, error)

SearchCodeChunksFTS performs a full-text search on code chunks.

func (*Store) SearchCodeChunksHybrid

func (s *Store) SearchCodeChunksHybrid(ctx context.Context, query string, queryVec []float32, limit int, languages []string) ([]*CodeChunkRecord, error)

SearchCodeChunksHybrid performs a hybrid search combining FTS5 ranking with cosine similarity on stored vectors. If languages is non-empty, only chunks in those languages are considered.

func (*Store) SearchNodeByHash

func (s *Store) SearchNodeByHash(ctx context.Context, hash, scope, project string) (*Node, error)

SearchNodeByHash finds a node by content hash + scope + project (dedup check). Returns (nil, nil) when not found — used for dedup checks where "not found" is not an error. SearchNodeByHash looks up a node by content hash within a scope/project. Returns (nil, nil) when no matching node is found (dedup check pattern).

func (*Store) SearchNodes

func (s *Store) SearchNodes(ctx context.Context, query string, limit int) ([]*Node, error)

func (*Store) StoreVector

func (s *Store) StoreVector(ctx context.Context, chunkID string, vec []float32) error

StoreVector saves an embedding vector for a code chunk.

func (*Store) TopConnected

func (s *Store) TopConnected(ctx context.Context, limit int) ([]string, error)

TopConnected returns the content of the most-connected nodes by edge count.

func (*Store) UpdateNode

func (s *Store) UpdateNode(ctx context.Context, n *Node) error

func (*Store) UpdateNodeContent

func (s *Store) UpdateNodeContent(ctx context.Context, id, newContent string) error

func (*Store) UpsertByTopic

func (s *Store) UpsertByTopic(ctx context.Context, n *Node, topicKey string) (*Node, bool, error)

UpsertByTopic updates an existing node if one with the same project+scope+topic_key exists, otherwise creates a new one. Based on Engram's topic dedup approach. topic_key is stored in the Tags field as "topic:<key>".

func (*Store) UpsertCodeChunk

func (s *Store) UpsertCodeChunk(ctx context.Context, chunk *CodeChunkRecord) error

UpsertCodeChunk inserts or replaces a code chunk record and updates the FTS index.

func (*Store) WithTx

func (s *Store) WithTx(ctx context.Context, fn func(Storage) error) error

WithTx runs the given function inside a SQL transaction. If the function returns an error, the transaction is rolled back.

The whole transaction is retried on SQLITE_BUSY. A transaction acquires the single SQLite writer more eagerly than a lone statement, so it can lose a race with the async ingestion goroutine; without retry, correctness-critical transactional writes (e.g. the atomic cycle-check+insert in AddEdge) would fail spuriously under concurrency. Re-running fn is safe because a busy error occurs before commit, so no partial state is visible.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL