storage

package
v0.4.0 Latest Latest
Warning

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

Go to latest
Published: May 5, 2026 License: MIT Imports: 13 Imported by: 0

Documentation

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.

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.

Types

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 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 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
}

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)
	Limit                int   // max results (0 = default 1000)
}

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)
	GetEdgesBetween(ctx context.Context, nodeIDs []string) ([]*Edge, error)
	CountEdges(ctx context.Context, nodeID string) (inbound int, outbound int, err error)
	CountAllEdges(ctx context.Context) (int, 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
	DeleteEmbedding(ctx context.Context, nodeID string) error
	AllEmbeddings(ctx context.Context) (map[string][]float32, error)
	GetEmbeddingsBatch(ctx context.Context, 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)

	// 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) (map[string][]float32, error)

AllEmbeddings returns all stored embeddings as (nodeID, vector) pairs.

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) 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) EndSession

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

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) GetEdge

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

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, offset, limit int) (map[string][]float32, error)

GetEmbeddingsBatch returns a paginated batch of embeddings.

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)

func (*Store) GetNodeByKey

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

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) 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) 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) LogAccess

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

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

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.

func (*Store) SaveEmbedding

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

SaveEmbedding stores a vector embedding for a node.

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).

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) 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.

Jump to

Keyboard shortcuts

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