cypher

package
v1.1.3 Latest Latest
Warning

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

Go to latest
Published: May 29, 2026 License: MIT Imports: 53 Imported by: 0

Documentation

Overview

Package cypher implements APOC graph algorithms for Neo4j compatibility.

Package cypher implements APOC community detection algorithms.

Package cypher implements APOC data import/export procedures.

Package cypher - AST builder for structured query representation.

Package cypher - Query result caching for performance optimization.

Package cypher provides composite database command execution.

Package cypher provides Neo4j-compatible Cypher query execution for NornicDB.

This package implements a Cypher query parser and executor that supports the core Neo4j Cypher query language features. It enables NornicDB to be compatible with existing Neo4j applications and tools.

Supported Cypher Features:

  • MATCH: Pattern matching with node and relationship patterns
  • CREATE: Creating nodes and relationships
  • MERGE: Upsert operations with ON CREATE/ON MATCH clauses
  • DELETE/DETACH DELETE: Removing nodes and relationships
  • SET: Updating node and relationship properties
  • REMOVE: Removing properties and labels
  • RETURN: Returning query results
  • WHERE: Filtering with conditions
  • WITH: Passing results between query parts
  • OPTIONAL MATCH: Left outer joins
  • CALL: Procedure calls
  • UNWIND: List expansion

Example Usage:

// Create executor with storage backend
storage := storage.NewMemoryEngine()
executor := cypher.NewStorageExecutor(storage)

// Execute Cypher queries
result, err := executor.Execute(ctx, "CREATE (n:Person {name: 'Alice', age: 30})", nil)
if err != nil {
	log.Fatal(err)
}

// Query with parameters
params := map[string]interface{}{
	"name": "Alice",
	"minAge": 25,
}
result, err = executor.Execute(ctx,
	"MATCH (n:Person {name: $name}) WHERE n.age >= $minAge RETURN n", params)

// Complex query with relationships
result, err = executor.Execute(ctx, `
	MATCH (a:Person)-[r:KNOWS]->(b:Person)
	WHERE a.age > 25
	RETURN a.name, r.since, b.name
	ORDER BY a.age DESC
	LIMIT 10
`, nil)

// Process results
for _, row := range result.Rows {
	// process row (e.g. emit "Row: %v" via the configured logger)
}

Neo4j Compatibility:

The executor aims for high compatibility with Neo4j Cypher:

  • Same syntax and semantics for core operations
  • Parameter substitution with $param syntax
  • Neo4j-style error messages and codes
  • Compatible result format for drivers
  • Support for Neo4j built-in functions

Query Processing Pipeline:

1. **Parsing**: Query is parsed into an AST (Abstract Syntax Tree) 2. **Validation**: Syntax and semantic validation 3. **Parameter Substitution**: Replace $param with actual values 4. **Execution Planning**: Determine optimal execution strategy 5. **Execution**: Execute against storage backend 6. **Result Formatting**: Format results for Neo4j compatibility

Performance Considerations:

  • Pattern matching is optimized for common cases
  • Indexes are used automatically when available
  • Query planning chooses efficient execution paths
  • Bulk operations are optimized for large datasets

Limitations:

Current limitations compared to full Neo4j:

  • No user-defined procedures (CALL is limited to built-ins)
  • No complex path expressions
  • No graph algorithms (shortest path, etc.)
  • No schema constraints (handled by storage layer)
  • No transactions (single-query atomicity only)

ELI12 (Explain Like I'm 12):

Think of Cypher like asking questions about a social network:

  1. **MATCH**: "Find all people named Alice" - like searching through a phone book for everyone with a specific name.

  2. **CREATE**: "Add a new person named Bob" - like writing a new entry in the phone book.

  3. **Relationships**: "Find who Alice knows" - like following the lines between people on a friendship map.

  4. **WHERE**: "Find people older than 25" - like adding a filter to only show certain results.

  5. **RETURN**: "Show me their names and ages" - like deciding which information to display from your search.

The Cypher executor is like a smart assistant that understands these questions and knows how to find the answers in your data!

Package cypher implements EXPLAIN and PROFILE query execution modes.

EXPLAIN shows the query execution plan without executing the query. PROFILE executes the query and shows the plan with runtime statistics.

ELI12 (Explain Like I'm 12)

Imagine you're planning a trip. EXPLAIN is like looking at the map and saying "I'll take this road, then that highway" without actually driving. PROFILE is like actually driving the route and noting "that road took 10 minutes, the highway took 20 minutes, I passed 50 cars."

Neo4j Compatibility

This implementation matches Neo4j's execution modes: - EXPLAIN: Returns plan without execution - PROFILE: Returns plan with actual execution statistics

Cypher function implementations for NornicDB.

This file holds the public expression-evaluation entrypoints. The heavy implementation is split across `functions_eval_part*.go`.

Package cypher provides index hint support for Neo4j-compatible query optimization.

Index hints allow users to specify which indexes should be used during query execution, overriding the query planner's automatic index selection.

Supported Hint Types

  • USING INDEX variable:Label(property) - Force use of a specific property index
  • USING SCAN variable:Label - Force a label scan instead of index lookup
  • USING JOIN ON variable - Force specific join strategy (planned)

Neo4j Compatibility

This implementation follows Neo4j's index hint syntax:

MATCH (n:Person)
USING INDEX n:Person(name)
WHERE n.name = 'Alice'
RETURN n

Multiple hints can be specified:

MATCH (a:Person)-[:KNOWS]->(b:Person)
USING INDEX a:Person(name)
USING INDEX b:Person(email)
WHERE a.name = 'Alice' AND b.email = 'bob@example.com'
RETURN a, b

ELI12 (Explain Like I'm 12)

Imagine you have a huge phone book (database). Normally, the database decides the fastest way to find someone - maybe by their name index, or by scanning. Index hints are like saying "I KNOW the name index is best - use that one!" It's like telling a librarian exactly which catalog to use.

Kalman filter Cypher functions for NornicDB.

These functions expose the Kalman filter implementations as database-callable functions, enabling users to apply signal filtering and prediction directly in their Cypher queries. Perfect for real-time time series analysis.

Overview

Kalman filters are optimal state estimators that combine noisy measurements with predictions to produce smooth, accurate estimates. They're widely used in aerospace, robotics, finance, and signal processing.

Available Filters

Three filter types are available, each suited for different use cases:

  • kalman.* - Basic scalar filter for noise smoothing
  • kalman.velocity.* - 2-state filter tracking position AND velocity (trends)
  • kalman.adaptive.* - Auto-switching filter that picks the best mode

State Management

Users store the filter state as a JSON string in a node property. The state is passed to each function call and an updated state is returned. This allows the database to remain stateless while users maintain their own filter state.

Real-World Example: News Sentiment → Stock Prediction

An LLM watches the Associated Press news feed in real-time, scoring each headline's market sentiment (-1.0 to +1.0). The Kalman filter smooths these noisy signals to predict stock movements:

// Step 1: Create a stock tracker with Kalman filtering
CREATE (s:Stock {
    symbol: "AAPL",
    kalmanState: kalman.velocity.init()  // Track trends
})

// Step 2: LLM processes AP news headline and scores sentiment
// (This happens in your application code, score passed as parameter)
// headline: "Apple announces record iPhone sales in China"
// $sentimentScore = 0.72  (positive)

// Step 3: Process the sentiment score through Kalman filter
MATCH (s:Stock {symbol: "AAPL"})
WITH s, kalman.velocity.process($sentimentScore, s.kalmanState) AS result
SET s.kalmanState = result.state,
    s.sentiment = result.value,
    s.momentum = result.velocity,
    s.lastUpdate = timestamp()
RETURN result.value AS smoothedSentiment,
       result.velocity AS sentimentTrend

// Step 4: Predict sentiment 5 time-steps ahead
MATCH (s:Stock {symbol: "AAPL"})
RETURN s.symbol,
       s.sentiment AS currentSentiment,
       s.momentum AS trend,
       kalman.velocity.predict(s.kalmanState, 5) AS predictedSentiment,
       CASE
           WHEN s.momentum > 0.1 THEN "BULLISH"
           WHEN s.momentum < -0.1 THEN "BEARISH"
           ELSE "NEUTRAL"
       END AS signal

// Step 5: Find stocks with strongest momentum
MATCH (s:Stock)
WHERE s.kalmanState IS NOT NULL
RETURN s.symbol, s.sentiment, s.momentum
ORDER BY abs(s.momentum) DESC
LIMIT 10

Why Kalman Filtering Works for This

Individual news headlines are noisy - one bad headline doesn't mean the stock will crash. The Kalman filter:

  • Smooths out noise from individual headlines
  • Tracks the TREND (velocity) of sentiment over time
  • Predicts where sentiment is heading
  • Adapts to changing conditions automatically

ELI12 (Explain Like I'm 12)

Imagine you're trying to guess tomorrow's weather by asking 10 friends. Some say "sunny", some say "rainy" - it's confusing! The Kalman filter is like having a really smart friend who:

  • Remembers what everyone said yesterday
  • Notices if opinions are trending toward "sunny" or "rainy"
  • Doesn't freak out when one person gives a weird answer
  • Uses all this to make a better prediction than any single friend

For stocks: news headlines are like those friends - some are right, some are wrong, some are noise. Kalman helps you see the real trend!

Other Use Cases

  • IoT sensor smoothing (temperature, pressure, GPS)
  • User behavior prediction (session length, click rates)
  • Memory decay tracking (see NornicDB's knowledge-layer scoring system)
  • Query latency monitoring
  • Any noisy time series data!

Package cypher — RISK-1 corrected op_type classifier (Plan 04-03-02).

Closed-enum classifier {read, write, schema, admin, fabric, parse_error} for the MET-09 op_type label on the Cypher metric catalog (pkg/observability/catalog_cypher.go AllowedCypherOpTypes).

RISK-1 correction (RESEARCH RISK-1): the original CONTEXT D-04 wording named a `plan.Root.Op` chokepoint that does NOT exist on the normal-path executor — `*ExecutionPlan` is built ONLY on EXPLAIN/PROFILE; normal Execute uses QueryAnalyzer.Analyze() *QueryInfo. This file's classifier reads the actual normal-path classifier surface (*QueryInfo flags), NOT the non-existent plan field.

Three observation sites use this classifier (see executor.go):

  1. Admin dispatch (Site 1) — emits op_type="admin" BEFORE Analyze() is called for SHOW DATABASES, CREATE/DROP DATABASE, ALTER DATABASE etc. Caller passes isAdmin=true.
  2. Parse error (Site 2) — emits op_type="parse_error" at validateSyntax() err path. Caller bypasses this function entirely (or passes nil info) and emits parse_error directly. The defensive nil-info branch below surfaces parse_error as a safety net.
  3. Normal path (Site 3) — after analyzer.Analyze() returns *QueryInfo, before execute. Caller passes (info, isFabric, false) and the function returns one of read|write|schema|fabric.

AGENTS.md §4 functional pattern: pure function, no side effects, no observability imports. Pkg/cypher remains a leaf consumer of pkg/observability; the OBSERVATION call lives in executor.go at the chokepoints — this is the CLASSIFIER.

Package cypher provides optimized query executors for specific patterns.

These executors implement specialized algorithms that are significantly faster than generic traversal for certain query patterns. Each executor is designed for a specific pattern detected by DetectQueryPattern(ctx, ).

Performance characteristics:

  • MutualRelationship: O(E) instead of O(N * D²)
  • IncomingCountAgg: O(E) instead of O(N * separate_calls)
  • EdgePropertyAgg: O(E) single-pass accumulation
  • LargeResultSet: Batch node lookups, pre-allocation

Package cypher provides parallel query execution support for NornicDB.

Parallel execution significantly improves query performance on large datasets by distributing work across multiple CPU cores. This is especially beneficial for:

  • Filtering large node sets (WHERE clauses)
  • Aggregation operations (COUNT, SUM, AVG, COLLECT)
  • Relationship traversal
  • UNION queries (parallel branch execution)

Neo4j Compatibility

Neo4j Enterprise uses parallel execution for query processing. This implementation brings similar capabilities to NornicDB, enabling comparable performance for analytical workloads.

Configuration

Parallel execution can be configured via ParallelConfig:

config := cypher.ParallelConfig{
    Enabled:      true,
    MaxWorkers:   8,           // Use 8 cores max
    MinBatchSize: 500,         // Parallelize when >500 items
}

ELI12 (Explain Like I'm 12)

Imagine you have 1000 books to check for a specific word. Instead of checking one by one, you get 4 friends to help. Each friend takes 250 books and checks them at the same time. That's parallel execution - doing work simultaneously!

Package cypher provides Cypher query parsing and execution for NornicDB.

Package cypher: D-04b deterministic plan-tree hash for slow-query log + Phase 6 span attribution.

PlanHash returns a 16-character lowercase hex digest of the bound execution plan computed via FNV-1a 64-bit (stdlib hash/fnv). The canonical form walks PlanOperator.OperatorType, .Description, .Identifiers, .Arguments, and .Children; argument values are restricted to a stable known type set (string|int64|float64|bool) — see W4 below — so the hash is deterministic across map iteration order, Go versions, and process restarts.

Why fixed 16-char hex?

  • 64-bit FNV-1a is non-cryptographic but stable across stdlib versions.
  • 16 hex chars is enough collision resistance for plan-class fingerprinting (~4e9 plans before 50% collision probability via the birthday bound).
  • Phase 6 (TRC-04) will reuse this exact function for the nornicdb.cypher.plan span attribute; operators correlate slow-query log records with traces via plan_hash equality.

W4 canonical-form pin (Pitfall 8): Arguments map values are restricted to string|int64|float64|bool. Other types contribute a single 0x00 nil byte to the canonical form — see the type switch default branch comment marked "TODO: PlanHash arg type expansion". Phase 2 ships these four types because they are what the executor actually emits; future expansion (e.g., time.Duration) requires an explicit canonical-form change AND a new TestPlanHash_Stability golden value to flag the schema bump.

Package cypher - Query analysis and AST capture.

Package cypher provides query pattern detection for optimization routing.

This file identifies query patterns that can be executed more efficiently than the generic traversal algorithm. Pattern detection happens BEFORE execution, allowing the executor to route to specialized implementations.

Supported patterns:

  • Mutual Relationship: (a)-[:TYPE]->(b)-[:TYPE]->(a) - cycle back to start
  • Incoming Count Aggregation: MATCH (x)<-[:TYPE]-(y) RETURN x, count(y)
  • Edge Property Aggregation: RETURN avg(r.prop), count(r) GROUP BY node
  • Large Result Set: Any traversal with LIMIT > 100

Package cypher: D-04 query literal redactor for slow-query log emission (LOG-08).

RedactLiterals walks the Cypher token stream, replacing STRING_LITERAL, INTEGER, and FLOAT tokens with the constant RedactedPlaceholder. Identifiers, keywords, and parameter REFERENCES ($name) are preserved verbatim because parameter VALUES bind separately at execution time and never appear as inline literals in the query text.

The redactor is invoked at every log emission site that includes raw query text — currently the slow-query log (D-04c) — so PII stored in literal values (names, emails, passwords) cannot leak through unauthenticated /metrics or operator log surfaces. Phase 6 (TRC-04) calls this same helper before attaching query text to the nornicdb.cypher.plan span.

On parse/lex failure the redactor returns RedactedPlaceholder (fail-closed per RESEARCH Pattern 5 line 660) — better to lose query readability than leak partial literal content from a half-tokenized input.

Package cypher - Pre-compiled regex patterns for performance.

This file contains all regex patterns used in hot paths, pre-compiled at package init time. Moving regex compilation from function calls to package initialization provides 5-10x performance improvements for operations that use these patterns repeatedly.

Performance Impact:

  • Schema DDL operations: 5-10x faster (9 patterns)
  • APOC path operations: 8-15x faster (8 patterns)
  • Duration parsing: 3-5x faster (2 patterns)

Schema command parsing and execution for Cypher.

This file implements Neo4j schema management commands:

  • CREATE CONSTRAINT
  • CREATE INDEX
  • CREATE RANGE INDEX
  • CREATE FULLTEXT INDEX
  • CREATE VECTOR INDEX

Package cypher - Optimized string-based pattern matching for hot paths.

This file provides fast string-based alternatives to regex patterns for operations that are called on every query. These functions are 5-10x faster than their regex equivalents.

Performance comparison (benchmark on M1 Mac):

  • splitByKeyword vs regex Split: ~8x faster
  • extractLimitSkip vs regex FindStringSubmatch: ~6x faster
  • extractParameter vs regex FindAllStringSubmatch: ~5x faster

Package cypher - Transaction support for Cypher queries.

Implements BEGIN/COMMIT/ROLLBACK for Neo4j-compatible transaction control.

Package cypher provides Cypher query execution for NornicDB.

Index

Constants

View Source
const RedactedPlaceholder = "<REDACTED>"

RedactedPlaceholder is the sentinel substituted for every redacted literal. Stable string contract: operators searching slow-query logs grep for it.

View Source
const VarLengthUnboundedMaxHops = 1 << 24 // ~16.7M

VarLengthUnboundedMaxHops is the depth cap applied when a variable-length relationship pattern is written without an explicit upper bound — for example `[*]`, `[*..]`, or `[*N..]`. The previous defaults (10 and 100) were surprising in practice: BFS traversals silently returned no rows on graphs whose actual diameter exceeded the cap. This sentinel is large enough that it acts effectively unbounded for any realistic graph (BFS terminates when the frontier is exhausted) while still keeping the field a plain int so all downstream `>=` comparisons stay correct.

Variables

View Source
var PluginFunctionLookup func(name string) (handler interface{}, found bool)

PluginFunctionLookup is a callback to look up functions from loaded plugins. Set by pkg/nornicdb during database initialization. Returns the function handler and true if found, nil and false otherwise.

Functions

func ApplyIndexHint

func ApplyIndexHint(store storage.Engine, schema *storage.SchemaManager, hint IndexHint, propertyValue interface{}) ([]*storage.Node, error)

ApplyIndexHint attempts to use the specified index for node lookup. Returns nodes matching the index lookup, or nil if index doesn't exist.

Parameters:

  • storage: The storage engine to query
  • schema: The schema manager for index lookup
  • hint: The index hint to apply
  • propertyValue: The value to look up in the index

Returns:

  • Matching nodes if index exists and value found
  • nil, nil if index doesn't exist (fall back to scan)
  • nil, error if lookup fails

func ClearUserProcedures

func ClearUserProcedures()

ClearUserProcedures resets user-defined procedures (primarily for tests/reload paths).

func ContainsKeyword

func ContainsKeyword(s, keyword string) bool

ContainsKeyword checks if a query contains a keyword (case-insensitive). Respects word boundaries.

func ExtractLimit

func ExtractLimit(query string) (int, bool)

ExtractLimit extracts the LIMIT value from a query string. Returns the value and true if found, or 0 and false if not found. This is ~6x faster than regex FindStringSubmatch.

Example:

ExtractLimit("MATCH (n) RETURN n LIMIT 10")
// Returns: 10, true

func ExtractLimitString

func ExtractLimitString(query string) string

ExtractLimitString extracts the LIMIT value as a string (for compatibility). Returns empty string if not found.

func ExtractParameters

func ExtractParameters(query string) []string

ExtractParameters finds all parameter references ($name) in a query string. Returns a slice of parameter names (without the $ prefix). This is ~5x faster than regex FindAllStringSubmatch.

Example:

ExtractParameters("MATCH (n) WHERE n.name = $name AND n.age > $minAge")
// Returns: ["name", "minAge"]

func ExtractSkip

func ExtractSkip(query string) (int, bool)

ExtractSkip extracts the SKIP value from a query string. Returns the value and true if found, or 0 and false if not found.

Example:

ExtractSkip("MATCH (n) RETURN n SKIP 5 LIMIT 10")
// Returns: 5, true

func ExtractSkipString

func ExtractSkipString(query string) string

ExtractSkipString extracts the SKIP value as a string (for compatibility). Returns empty string if not found.

func FindKeywordIndex

func FindKeywordIndex(s, keyword string) int

FindKeywordIndex finds the position of a keyword in a query (case-insensitive). Returns -1 if not found. Respects word boundaries. This is faster than using regexp for simple keyword detection.

func GetAuthTokenFromContext

func GetAuthTokenFromContext(ctx context.Context) string

GetAuthTokenFromContext extracts forwarded Authorization token from context.

func GetCachedRegex

func GetCachedRegex(pattern string) (*regexp.Regexp, error)

GetCachedRegex returns a compiled regex for the pattern, using cache if available. This avoids re-compiling the same pattern on every =~ comparison.

func GetUseDatabaseFromContext

func GetUseDatabaseFromContext(ctx context.Context) string

GetUseDatabaseFromContext extracts the database name from :USE command if present in context. Returns empty string if no :USE command was found.

func IsRetrySafeMergeCommitQuery added in v1.1.0

func IsRetrySafeMergeCommitQuery(info *QueryInfo) bool

IsRetrySafeMergeCommitQuery reports whether a query's write shape is limited to a MERGE commit race that can be retried safely. MERGE may be combined with MATCH, OPTIONAL MATCH, SET, WITH, UNWIND, and RETURN, but side-effecting clauses such as CREATE, DELETE, REMOVE, FOREACH, LOAD CSV, or CALL make the statement non-retryable.

func ParseAggregationProperty

func ParseAggregationProperty(expr string) (variable, property string)

ParseAggregationProperty is a convenience function that returns just the variable and property. Returns ("", "") if not a valid aggregation with a property. This provides compatibility with the regex match[1], match[2] pattern.

func ParseKnowledgePolicyDDL added in v1.1.0

func ParseKnowledgePolicyDDL(stmt string) (interface{}, bool, error)

ParseKnowledgePolicyDDL attempts to parse a knowledge-layer DDL statement. Returns (command, true, nil) on success, (nil, false, nil) if the input is not a knowledge-layer DDL statement, or (nil, false, err) on parse error.

func PlanHash added in v1.1.0

func PlanHash(plan *ExecutionPlan) string

PlanHash returns the 16-char hex FNV-1a digest of the canonical form of plan.

Nil safety: PlanHash(nil) and PlanHash(&ExecutionPlan{Root: nil}) both return "0000000000000000" — the zero placeholder operators expect when the executor emits a slow-query log without a populated plan tree (e.g., normal-mode queries that don't run EXPLAIN/PROFILE).

func RedactLiterals added in v1.1.0

func RedactLiterals(query string) string

RedactLiterals returns the input query with literal tokens replaced by RedactedPlaceholder. STRING_LITERAL, INTEGER, and FLOAT token types are the redaction target set; all other tokens are emitted as their original text. Empty queries and parse failures return RedactedPlaceholder (fail-closed).

Performance: this is NOT on the production hot path — it fires only on the slow-query log emission path (cypher.duration_ms >= SlowQueryThreshold), so per-call cost (~1 lexer pass) is acceptable.

func RegisterUserProcedure

func RegisterUserProcedure(spec ProcedureSpec, handler ProcedureHandler) error

RegisterUserProcedure registers a user-defined procedure into the global registry.

func ReplaceParameters

func ReplaceParameters(query string, replacer func(paramName string) string) string

ReplaceParameters replaces all parameter references with their values. The replacer function receives the parameter name (without $) and returns the replacement string. This is ~5x faster than regex ReplaceAllStringFunc.

Example:

ReplaceParameters("WHERE n.name = $name", func(param string) string {
    return fmt.Sprintf("'%s'", params[param])
})

func SetParallelConfig

func SetParallelConfig(config ParallelConfig)

SetParallelConfig updates the parallel execution configuration.

func SplitByCreate

func SplitByCreate(s string) []string

SplitByCreate splits by "CREATE " keyword. Convenience wrapper for hot path.

func SplitByKeyword

func SplitByKeyword(s, keyword string) []string

SplitByKeyword splits a string by a keyword (case-insensitive), respecting word boundaries. This is ~8x faster than regexp.MustCompile(`(?i)\bKEYWORD\s+`).Split().

Example:

SplitByKeyword("MATCH (a) MATCH (b)", "MATCH")
// Returns: ["", "(a) ", "(b)"]

func SplitByMatch

func SplitByMatch(s string) []string

SplitByMatch splits by "MATCH " keyword. Convenience wrapper for hot path.

func ValidateIndexHints

func ValidateIndexHints(schema *storage.SchemaManager, hints []IndexHint) error

ValidateIndexHints checks if all specified index hints can be satisfied. Returns an error if any hint references a non-existent index.

Parameters:

  • schema: The schema manager to validate against
  • hints: The index hints to validate

Returns:

  • nil if all hints are valid
  • Error describing which hint cannot be satisfied

func WithAuthToken

func WithAuthToken(ctx context.Context, authToken string) context.Context

WithAuthToken stores an Authorization header token on context for execution paths that need to forward caller identity across remote constituents.

func WithTemporalViewport

func WithTemporalViewport(ctx context.Context, viewport TemporalViewport) context.Context

Types

type AST

type AST struct {
	Clauses    []ASTClause
	RawQuery   string
	QueryType  QueryType
	IsReadOnly bool
	IsCompound bool
}

AST represents a complete parsed query.

type ASTBinaryExpr

type ASTBinaryExpr struct {
	Left     ASTExpression
	Operator string
	Right    ASTExpression
}

ASTBinaryExpr represents a binary operation.

type ASTBuilder

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

ASTBuilder builds Abstract Syntax Trees from Cypher queries. This is separate from QueryAnalyzer to allow lazy AST building only when needed.

Usage:

builder := NewASTBuilder()
ast, err := builder.Build("MATCH (n:Person) WHERE n.age > 21 RETURN n.name")
if err != nil {
    // handle error
}
// ast.Clauses contains structured representation

func NewASTBuilder

func NewASTBuilder() *ASTBuilder

NewASTBuilder creates a new AST builder.

func (*ASTBuilder) Build

func (b *ASTBuilder) Build(cypher string) (*AST, error)

Build parses a Cypher query into an AST.

type ASTCall

type ASTCall struct {
	Procedure string
	Arguments []ASTExpression
	RawArgs   string
	Yield     []string
}

ASTCall represents a CALL clause.

type ASTCaseExpr

type ASTCaseExpr struct {
	Input   *ASTExpression
	Whens   []ASTCaseWhen
	Default *ASTExpression
}

ASTCaseExpr represents a CASE expression.

type ASTCaseWhen

type ASTCaseWhen struct {
	Condition ASTExpression
	Result    ASTExpression
}

ASTCaseWhen represents a WHEN clause in CASE.

type ASTClause

type ASTClause struct {
	Type     ASTClauseType
	RawText  string // Original text of the clause
	StartPos int    // Position in original query
	EndPos   int    // End position in original query

	// Parsed content (populated based on clause type)
	Match   *ASTMatch
	Create  *ASTCreate
	Merge   *ASTMerge
	Delete  *ASTDelete
	Set     *ASTSet
	Remove  *ASTRemove
	Return  *ASTReturn
	With    *ASTWith
	Where   *ASTWhere
	Unwind  *ASTUnwind
	OrderBy *ASTOrderBy
	Limit   *int64
	Skip    *int64
	Call    *ASTCall
}

ASTClause represents a parsed clause with its content.

type ASTClauseType

type ASTClauseType int

ASTClauseType identifies the clause type.

const (
	ASTClauseMatch ASTClauseType = iota
	ASTClauseOptionalMatch
	ASTClauseCreate
	ASTClauseMerge
	ASTClauseDelete
	ASTClauseDetachDelete
	ASTClauseSet
	ASTClauseRemove
	ASTClauseReturn
	ASTClauseWith
	ASTClauseWhere
	ASTClauseUnwind
	ASTClauseOrderBy
	ASTClauseLimit
	ASTClauseSkip
	ASTClauseCall
	ASTClauseUnion
	ASTClauseForeach
)

type ASTCreate

type ASTCreate struct {
	Patterns []ASTPattern
}

ASTCreate represents a CREATE clause.

type ASTDelete

type ASTDelete struct {
	Variables []string
	Detach    bool
}

ASTDelete represents a DELETE clause.

type ASTExprType

type ASTExprType int

ASTExprType identifies expression types.

const (
	ASTExprLiteral ASTExprType = iota
	ASTExprVariable
	ASTExprProperty
	ASTExprFunction
	ASTExprBinary
	ASTExprUnary
	ASTExprList
	ASTExprMap
	ASTExprParameter
	ASTExprCase
)

type ASTExpression

type ASTExpression struct {
	Type    ASTExprType
	RawText string

	// Different expression types populate different fields
	Literal   interface{} // For literals
	Variable  string      // For variable references
	Property  *ASTPropertyAccess
	Function  *ASTFunctionCall
	Binary    *ASTBinaryExpr
	Unary     *ASTUnaryExpr
	List      []ASTExpression
	Map       map[string]ASTExpression
	Parameter string // For $param
	Case      *ASTCaseExpr
}

ASTExpression represents an expression.

type ASTFunctionCall

type ASTFunctionCall struct {
	Name      string
	Arguments []ASTExpression
	Distinct  bool
}

ASTFunctionCall represents a function call.

type ASTMatch

type ASTMatch struct {
	Patterns []ASTPattern
	Optional bool
}

ASTMatch represents a MATCH clause.

type ASTMerge

type ASTMerge struct {
	Pattern  ASTPattern
	OnCreate []ASTSetItem
	OnMatch  []ASTSetItem
}

ASTMerge represents a MERGE clause.

type ASTNode

type ASTNode struct {
	Variable   string
	Labels     []string
	Properties map[string]ASTExpression
	RawProps   string
}

ASTNode represents a node in a pattern.

type ASTOrderBy

type ASTOrderBy struct {
	Items []ASTOrderItem
}

ASTOrderBy represents ORDER BY.

type ASTOrderItem

type ASTOrderItem struct {
	Expression ASTExpression
	Descending bool
	RawText    string
}

ASTOrderItem represents a single ORDER BY item.

type ASTPattern

type ASTPattern struct {
	Nodes         []ASTNode
	Relationships []ASTRelationship
	RawText       string
}

ASTPattern represents a graph pattern.

type ASTPropertyAccess

type ASTPropertyAccess struct {
	Variable string
	Property string
}

ASTPropertyAccess represents property access (n.name).

type ASTRelationship

type ASTRelationship struct {
	Variable   string
	Type       string
	Direction  EdgeDirection
	Properties map[string]ASTExpression
	MinHops    *int
	MaxHops    *int
}

ASTRelationship represents a relationship in a pattern.

type ASTRemove

type ASTRemove struct {
	Items []ASTRemoveItem
}

ASTRemove represents a REMOVE clause.

type ASTRemoveItem

type ASTRemoveItem struct {
	Variable string
	Property string   // For property removal
	Labels   []string // For label removal
}

ASTRemoveItem represents a property or label removal.

type ASTReturn

type ASTReturn struct {
	Items    []ASTReturnItem
	Distinct bool
}

ASTReturn represents a RETURN clause.

type ASTReturnItem

type ASTReturnItem struct {
	Expression ASTExpression
	Alias      string
	RawText    string
}

ASTReturnItem represents an item in RETURN.

type ASTSet

type ASTSet struct {
	Items []ASTSetItem
}

ASTSet represents a SET clause.

type ASTSetItem

type ASTSetItem struct {
	Variable string
	Property string
	Value    ASTExpression
	RawValue string // Original value text for complex expressions
}

ASTSetItem represents a single SET assignment.

type ASTUnaryExpr

type ASTUnaryExpr struct {
	Operator string
	Operand  ASTExpression
}

ASTUnaryExpr represents a unary operation.

type ASTUnwind

type ASTUnwind struct {
	Expression ASTExpression
	Variable   string
	RawExpr    string
}

ASTUnwind represents an UNWIND clause.

type ASTWhere

type ASTWhere struct {
	Condition ASTExpression
	RawText   string
}

ASTWhere represents a WHERE clause.

type ASTWith

type ASTWith struct {
	Items    []ASTReturnItem
	Distinct bool
}

ASTWith represents a WITH clause.

type AggregateResult

type AggregateResult struct {
	Count   int64
	Sum     float64
	Values  []interface{} // For COLLECT
	Min     interface{}
	Max     interface{}
	HasData bool
}

AggregateResult holds partial aggregation results from a worker.

type AggregationResult

type AggregationResult struct {
	Function string // COUNT, SUM, AVG, MIN, MAX, COLLECT
	Variable string // The variable name (e.g., "n")
	Property string // The property name (e.g., "age"), empty for COUNT(n) or COUNT(*)
	Distinct bool   // True if DISTINCT was specified
	IsStar   bool   // True if COUNT(*)
}

AggregationResult holds the parsed components of an aggregation expression.

func ParseAggregation

func ParseAggregation(expr string) *AggregationResult

ParseAggregation parses an aggregation expression like "COUNT(n.prop)" or "SUM(DISTINCT n.age)". This replaces 8 separate regex patterns with one unified parser (~5x faster).

Returns nil if the expression is not a valid aggregation.

Example:

ParseAggregation("COUNT(n.age)") → {Function: "COUNT", Variable: "n", Property: "age"}
ParseAggregation("SUM(DISTINCT x.value)") → {Function: "SUM", Variable: "x", Property: "value", Distinct: true}
ParseAggregation("COUNT(*)") → {Function: "COUNT", IsStar: true}

type AlterDecayProfileCmd added in v1.1.0

type AlterDecayProfileCmd struct {
	Name    string
	Updates map[string]interface{}
}

type AlterPromotionPolicyCmd added in v1.1.0

type AlterPromotionPolicyCmd struct {
	Name    string
	Updates map[string]interface{}
}

type AlterPromotionProfileCmd added in v1.1.0

type AlterPromotionProfileCmd struct {
	Name    string
	Updates map[string]interface{}
}

type Clause

type Clause interface {
	// contains filtered or unexported methods
}

Clause represents a query clause.

type ClauseType

type ClauseType int

ClauseType represents the type of a Cypher clause

const (
	ClauseUnknown ClauseType = iota
	ClauseMatch
	ClauseCreate
	ClauseMerge
	ClauseDelete
	ClauseSet
	ClauseRemove
	ClauseReturn
	ClauseWith
	ClauseUnwind
	ClauseCall
	ClauseForeach
	ClauseLoadCSV
	ClauseShow
	ClauseDrop
	ClauseOptionalMatch
)

type Comparison

type Comparison struct {
	Left     Expression
	Operator string
	Right    Expression
}

Comparison represents a comparison expression.

type CreateClause

type CreateClause struct {
	Pattern Pattern
}

CreateClause represents a CREATE clause.

type CreateDecayProfileBindingCmd added in v1.1.0

type CreateDecayProfileBindingCmd struct {
	Binding knowledgepolicy.DecayProfileBinding
}

type CreateDecayProfileBundleCmd added in v1.1.0

type CreateDecayProfileBundleCmd struct {
	Bundle knowledgepolicy.DecayProfileBundle
}

type CreatePromotionPolicyCmd added in v1.1.0

type CreatePromotionPolicyCmd struct {
	Policy knowledgepolicy.PromotionPolicyDef
}

type CreatePromotionProfileCmd added in v1.1.0

type CreatePromotionProfileCmd struct {
	Profile knowledgepolicy.PromotionProfileDef
}

type CypherDuration

type CypherDuration struct {
	Years   int64 // Calendar years
	Months  int64 // Calendar months
	Days    int64 // Calendar days
	Hours   int64 // Clock hours
	Minutes int64 // Clock minutes
	Seconds int64 // Clock seconds
	Nanos   int64 // Sub-second precision (nanoseconds)
}

CypherDuration represents a Neo4j-compatible duration type.

This type stores time intervals with separate components for calendar units (years, months, days) and clock units (hours, minutes, seconds).

Calendar units are stored separately because they have variable lengths:

  • A year can be 365 or 366 days
  • A month can be 28-31 days

Clock units have fixed lengths and are stored precisely.

Fields

  • Years: Number of years (calendar unit)
  • Months: Number of months (calendar unit)
  • Days: Number of days (calendar unit)
  • Hours: Number of hours (clock unit)
  • Minutes: Number of minutes (clock unit)
  • Seconds: Number of seconds (clock unit)
  • Nanos: Nanoseconds for sub-second precision

Example

dur := &CypherDuration{
    Years: 1, Months: 6, Days: 15,
    Hours: 2, Minutes: 30, Seconds: 45,
}
_ = dur.String() // serializes as P1Y6M15DT2H30M45S

ELI12

Think of CypherDuration like a time capsule with two compartments:

  1. Calendar compartment: "How many birthdays/months/days to skip?" (Years, Months, Days - these depend on the calendar)

  2. Clock compartment: "How much to move the clock hands?" (Hours, Minutes, Seconds - these are always the same length)

We keep them separate because months aren't all the same length! February has 28-29 days, while January has 31.

func (*CypherDuration) String

func (d *CypherDuration) String() string

String returns the duration in ISO 8601 format.

The format is: P[n]Y[n]M[n]DT[n]H[n]M[n]S

Only non-zero components are included. If no components are present, returns "PT0S" (zero duration).

Example

dur := &CypherDuration{Days: 5, Hours: 2}
_ = dur.String() // serializes as "P5DT2H"

zeroDur := &CypherDuration{}
_ = zeroDur.String() // serializes as "PT0S"

func (*CypherDuration) ToTimeDuration

func (d *CypherDuration) ToTimeDuration() time.Duration

ToTimeDuration converts to Go's time.Duration.

Note: This only converts the clock components (hours, minutes, seconds, nanos). Calendar components (years, months, days) are converted to their approximate durations which may not be accurate for actual date arithmetic.

For precise date calculations, use AddDurationToDate instead.

Example

dur := &CypherDuration{Hours: 2, Minutes: 30}
goDur := dur.ToTimeDuration()
_ = goDur // formats as 2h30m0s

func (*CypherDuration) TotalDays

func (d *CypherDuration) TotalDays() float64

TotalDays returns the approximate total number of days.

Note: This is an approximation because it assumes:

  • 1 year = 365.25 days (average accounting for leap years)
  • 1 month = 30.4375 days (365.25 / 12)

For precise date calculations, use the individual components with AddDurationToDate instead.

Example

dur := &CypherDuration{Years: 1}
_ = dur.TotalDays() // returns ~365.25

func (*CypherDuration) TotalSeconds

func (d *CypherDuration) TotalSeconds() float64

TotalSeconds returns the approximate total number of seconds.

Note: This is an approximation for the calendar components. See TotalDays for the assumptions used.

Example

dur := &CypherDuration{Hours: 2, Minutes: 30}
_ = dur.TotalSeconds() // returns 9000

type DatabaseInfoInterface

type DatabaseInfoInterface interface {
	Name() string
	Type() string
	Status() string
	IsDefault() bool
	CreatedAt() time.Time
}

DatabaseInfoInterface provides database metadata without importing multidb.

type DatabaseManagerInterface

type DatabaseManagerInterface interface {
	CreateDatabase(name string) error
	DropDatabase(name string) error
	ListDatabases() []DatabaseInfoInterface
	Exists(name string) bool
	CreateAlias(alias, databaseName string) error
	DropAlias(alias string) error
	ListAliases(databaseName string) map[string]string
	ResolveDatabase(nameOrAlias string) (string, error)
	SetDatabaseLimits(databaseName string, limits interface{}) error
	GetDatabaseLimits(databaseName string) (interface{}, error)
	// Composite database methods
	CreateCompositeDatabase(name string, constituents []interface{}) error
	DropCompositeDatabase(name string) error
	AddConstituent(compositeName string, constituent interface{}) error
	RemoveConstituent(compositeName string, alias string) error
	GetCompositeConstituents(compositeName string) ([]interface{}, error)
	ListCompositeDatabases() []DatabaseInfoInterface
	IsCompositeDatabase(name string) bool
	// GetStorageForUse returns the storage engine for a database, supporting
	// composite databases. authToken is forwarded for remote constituents.
	GetStorageForUse(name string, authToken string) (interface{}, error)
}

DatabaseManagerInterface is a minimal interface to avoid import cycles with multidb package. This allows the executor to call database management operations without directly depending on the multidb package.

type DeleteClause

type DeleteClause struct {
	Variables []string
	Detach    bool
}

DeleteClause represents a DELETE clause.

type DropDecayProfileCmd added in v1.1.0

type DropDecayProfileCmd struct {
	Name     string
	IfExists bool
}

type DropPromotionPolicyCmd added in v1.1.0

type DropPromotionPolicyCmd struct {
	Name     string
	IfExists bool
}

type DropPromotionProfileCmd added in v1.1.0

type DropPromotionProfileCmd struct {
	Name     string
	IfExists bool
}

type EdgeDirection

type EdgeDirection int

EdgeDirection represents edge direction.

const (
	EdgeBoth EdgeDirection = iota
	EdgeOutgoing
	EdgeIncoming
)

type EdgeFilterFunc

type EdgeFilterFunc func(edge *storage.Edge) bool

EdgeFilterFunc tests whether an edge matches filter criteria.

type EdgePattern

type EdgePattern struct {
	Variable   string
	Type       string
	Direction  EdgeDirection
	Properties map[string]any
	MinHops    *int
	MaxHops    *int
}

EdgePattern represents an edge in a pattern.

type EmbeddingChunk

type EmbeddingChunk struct {
	ID        string    `cypher:"id" json:"id"`
	ParentID  string    `cypher:"parent_id" json:"parent_id"`
	Index     int       `cypher:"chunk_index" json:"chunk_index"`
	Text      string    `cypher:"text" json:"text"`
	Embedding []float32 `cypher:"embedding" json:"embedding"`
}

EmbeddingChunk represents a chunk with embedding data.

type ExecuteResult

type ExecuteResult struct {
	Columns  []string
	Rows     [][]interface{}
	Stats    *QueryStats
	Metadata map[string]interface{} // Additional result metadata (e.g., execution plan)
}

ExecuteResult holds execution results in Neo4j-compatible format.

type ExecutionMode

type ExecutionMode string

ExecutionMode represents how a query should be executed

const (
	ModeNormal  ExecutionMode = "normal"
	ModeExplain ExecutionMode = "EXPLAIN"
	ModeProfile ExecutionMode = "PROFILE"
)

type ExecutionPlan

type ExecutionPlan struct {
	// Root operator of the plan
	Root *PlanOperator `json:"root"`

	// Query being explained/profiled
	Query string `json:"query"`

	// Execution mode (EXPLAIN or PROFILE)
	Mode ExecutionMode `json:"mode"`

	// Total statistics (only for PROFILE)
	TotalDBHits int64         `json:"totalDbHits,omitempty"`
	TotalTime   time.Duration `json:"totalTime,omitempty"`
	TotalRows   int64         `json:"totalRows,omitempty"`
}

ExecutionPlan represents the complete query execution plan

type Executor

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

Executor executes Cypher queries.

func NewExecutor

func NewExecutor() *Executor

NewExecutor creates a new Cypher executor.

func (*Executor) Execute

func (e *Executor) Execute(ctx context.Context, cypher string, params map[string]any) (*Result, error)

Execute executes a Cypher query.

type Expression

type Expression interface {
	// contains filtered or unexported methods
}

Expression represents a Cypher expression.

type FastRPConfig

type FastRPConfig struct {
	EmbeddingDimension         int
	IterationWeights           []float64
	PropertyRatio              float64
	FeatureProperties          []string
	RelationshipWeightProperty string
	RandomSeed                 int64
	NormalizationStrength      float64
}

FastRPConfig holds configuration for FastRP

type FilterFunc

type FilterFunc func(node *storage.Node) bool

FilterFunc is a function that tests whether a node matches filter criteria.

type FunctionCall

type FunctionCall struct {
	Name string
	Args []Expression
}

FunctionCall represents a function call.

type GraphProjection

type GraphProjection struct {
	Name              string
	NodeLabels        []string
	RelationshipTypes []string
	NodeCount         int
	RelationshipCount int
	NodeIDs           []string                      // All node IDs in projection
	NodeProperties    map[string]map[string]any     // nodeID -> properties
	Adjacency         map[string][]string           // nodeID -> neighbor IDs
	EdgeWeights       map[string]map[string]float64 // source -> target -> weight
	CreatedAt         time.Time
}

GraphProjection holds an in-memory graph projection for GDS algorithms

type HotPathTrace

type HotPathTrace struct {
	OuterIndexTopK              bool
	OuterScanFallbackUsed       bool
	FabricBatchedApplyRows      bool
	SimpleMatchLimitFastPath    bool
	CompoundQueryFastPath       bool
	TraversalStartSeedTopK      bool
	TraversalEndSeedTopK        bool
	UnwindSimpleMergeBatch      bool
	UnwindMergeChainBatch       bool
	UnwindFixedChainLinkBatch   bool
	UnwindMultiMatchCreateBatch bool
	CallTailTraversalFastPath   bool
	MergeSchemaLookupUsed       bool
	MergeScanFallbackUsed       bool
}

HotPathTrace records which key query hot paths were used for the most recent Execute call.

type IndexHint

type IndexHint struct {
	Type       IndexHintType
	Variable   string   // The variable name (e.g., "n" in "n:Person")
	Label      string   // The label (e.g., "Person")
	Property   string   // The property for index hints (e.g., "name")
	Properties []string // Multiple properties for composite hints
}

IndexHint represents a parsed index hint from a Cypher query.

Example:

USING INDEX n:Person(name)
→ IndexHint{Type: HintIndex, Variable: "n", Label: "Person", Property: "name"}

func ParseIndexHints

func ParseIndexHints(query string) ([]IndexHint, string)

ParseIndexHints extracts all index hints from a Cypher query.

Parameters:

  • query: The full Cypher query string

Returns:

  • Slice of parsed IndexHint structs
  • The query with hints removed (for further processing)

Example:

query := "MATCH (n:Person) USING INDEX n:Person(name) WHERE n.name = 'Alice' RETURN n"
hints, cleanQuery := ParseIndexHints(query)
// hints = [{Type: HintIndex, Variable: "n", Label: "Person", Property: "name"}]
// cleanQuery = "MATCH (n:Person)  WHERE n.name = 'Alice' RETURN n"

func (*IndexHint) String

func (h *IndexHint) String() string

String returns a human-readable representation of the hint.

type IndexHintContext

type IndexHintContext struct {
	Hints      []IndexHint
	HintsByVar map[string][]IndexHint // Variable -> hints for that variable
}

IndexHintContext holds index hints for a query execution.

func NewIndexHintContext

func NewIndexHintContext(hints []IndexHint) *IndexHintContext

NewIndexHintContext creates a new context from parsed hints.

func (*IndexHintContext) GetHintsForVariable

func (ctx *IndexHintContext) GetHintsForVariable(variable string) []IndexHint

GetHintsForVariable returns all hints for a specific variable.

func (*IndexHintContext) HasIndexHint

func (ctx *IndexHintContext) HasIndexHint(variable, label, property string) bool

HasIndexHint checks if there's an index hint for a variable/label/property combination.

func (*IndexHintContext) ShouldForceScan

func (ctx *IndexHintContext) ShouldForceScan(variable, label string) bool

ShouldForceScan checks if a label scan should be forced for a variable.

type IndexHintType

type IndexHintType int

IndexHintType represents the type of index hint.

const (
	// HintIndex forces use of a specific property index.
	HintIndex IndexHintType = iota
	// HintScan forces a label scan instead of index lookup.
	HintScan
	// HintJoin forces a specific join strategy.
	HintJoin
)

type InferenceManager

type InferenceManager interface {
	Generate(ctx context.Context, prompt string, params heimdall.GenerateParams) (string, error)
	Chat(ctx context.Context, req heimdall.ChatRequest) (*heimdall.ChatResponse, error)
}

InferenceManager is the minimal LLM contract used by Cypher db.infer. It mirrors Heimdall manager methods to keep adapters thin.

type KalmanAdaptiveProcessResult

type KalmanAdaptiveProcessResult struct {
	Value float64 `json:"value"`
	Mode  string  `json:"mode"`
	State string  `json:"state"`
}

KalmanAdaptiveProcessResult is the result of kalman.adaptive.process()

type KalmanAdaptiveState

type KalmanAdaptiveState struct {
	// Underlying basic filter state
	Basic KalmanState `json:"basic"`
	// Underlying velocity filter state
	Velocity KalmanVelocityState `json:"velocity"`
	// Current mode: "basic" or "velocity"
	Mode string `json:"mode"`
	// Observations since last switch
	SinceSwitch int `json:"ss"`
	// Trend detection threshold
	TrendThreshold float64 `json:"tt"`
	// Stability threshold
	StabilityThreshold float64 `json:"st"`
	// Switch hysteresis count
	Hysteresis int `json:"hy"`
	// Total observations
	Observations int `json:"n"`
	// Last filtered value
	LastFiltered float64 `json:"lf"`
	// Trend score (running velocity estimate)
	TrendScore float64 `json:"ts"`
}

KalmanAdaptiveState represents the serializable state of an adaptive filter.

type KalmanProcessResult

type KalmanProcessResult struct {
	Value float64 `json:"value"`
	State string  `json:"state"`
}

KalmanProcessResult is the result of kalman.process()

type KalmanState

type KalmanState struct {
	// Current state estimate
	X float64 `json:"x"`
	// Previous state (for velocity calculation)
	LastX float64 `json:"lx"`
	// Estimate covariance (uncertainty)
	P float64 `json:"p"`
	// Kalman gain
	K float64 `json:"k"`
	// Setpoint error factor
	E float64 `json:"e"`
	// Process noise (scaled)
	Q float64 `json:"q"`
	// Measurement noise
	R float64 `json:"r"`
	// Variance scale for adaptive R
	VarianceScale float64 `json:"vs"`
	// Number of observations processed
	Observations int `json:"n"`
}

KalmanState represents the serializable state of a basic Kalman filter. This is stored as JSON in a node property and passed to kalman.* functions.

type KalmanVelocityProcessResult

type KalmanVelocityProcessResult struct {
	Value    float64 `json:"value"`
	Velocity float64 `json:"velocity"`
	State    string  `json:"state"`
}

KalmanVelocityProcessResult is the result of kalman.velocity.process()

type KalmanVelocityState

type KalmanVelocityState struct {
	// Position estimate
	Pos float64 `json:"pos"`
	// Velocity estimate
	Vel float64 `json:"vel"`
	// 2x2 Covariance matrix [p00, p01, p10, p11]
	P [4]float64 `json:"p"`
	// Position process noise
	QPos float64 `json:"qp"`
	// Velocity process noise
	QVel float64 `json:"qv"`
	// Measurement noise
	R float64 `json:"r"`
	// Time step
	Dt float64 `json:"dt"`
	// Number of observations
	Observations int `json:"n"`
}

KalmanVelocityState represents the serializable state of a 2-state Kalman filter. Tracks both position and velocity for trend prediction.

type Literal

type Literal struct {
	Value any
}

Literal represents a literal value.

type MapFunc

type MapFunc func(node *storage.Node) interface{}

MapFunc transforms a node into a result value.

type MatchClause

type MatchClause struct {
	Pattern  Pattern
	Optional bool
	Where    *WhereClause
}

MatchClause represents a MATCH clause.

type MemoryEdge

type MemoryEdge struct {
	ID          string    `cypher:"id" json:"id"`
	Source      string    `cypher:"source" json:"source"`
	Target      string    `cypher:"target" json:"target"`
	Type        string    `cypher:"type" json:"type"`
	Weight      float64   `cypher:"weight" json:"weight"`
	Decay       float64   `cypher:"decay" json:"decay"`
	CreatedAt   time.Time `cypher:"created_at" json:"created_at"`
	LastUpdated time.Time `cypher:"last_updated" json:"last_updated"`
}

MemoryEdge represents an edge between memory nodes with decay.

type MemoryNode

type MemoryNode struct {
	ID          string    `cypher:"id" json:"id"`
	Title       string    `cypher:"title" json:"title"`
	Content     string    `cypher:"content" json:"content"`
	Type        string    `cypher:"type" json:"type"`
	Tags        []string  `cypher:"tags" json:"tags"`
	Weight      float64   `cypher:"weight" json:"weight"`
	Decay       float64   `cypher:"decay" json:"decay"`
	CreatedAt   time.Time `cypher:"created_at" json:"created_at"`
	UpdatedAt   time.Time `cypher:"updated_at" json:"updated_at"`
	LastAccess  time.Time `cypher:"last_access" json:"last_access"`
	AccessCount int64     `cypher:"access_count" json:"access_count"`
}

MemoryNode represents a memory/knowledge node with decay support.

type NodeCount

type NodeCount struct {
	Label string `cypher:"label" json:"label"`
	Count int64  `cypher:"count" json:"count"`
}

NodeCount represents a count aggregation result.

type NodeMutatedCallback

type NodeMutatedCallback func(nodeID string)

StorageExecutor executes Cypher queries against a storage backend.

The StorageExecutor provides the main interface for executing Cypher queries in NornicDB. It handles query parsing, validation, parameter substitution, and execution against the underlying storage engine.

Key features:

  • Neo4j-compatible Cypher syntax support
  • Parameter substitution with $param syntax
  • Query validation and error reporting
  • Optimized execution planning
  • Thread-safe concurrent execution

Example:

storage := storage.NewMemoryEngine()
executor := cypher.NewStorageExecutor(storage)

// Simple node creation
result, _ := executor.Execute(ctx, "CREATE (n:Person {name: 'Alice'})", nil)

// Parameterized query
params := map[string]interface{}{"name": "Bob", "age": 30}
result, _ = executor.Execute(ctx,
	"CREATE (n:Person {name: $name, age: $age})", params)

// Complex pattern matching
result, _ = executor.Execute(ctx, `
	MATCH (a:Person)-[:KNOWS]->(b:Person)
	WHERE a.age > 25
	RETURN a.name, b.name
`, nil)

Thread Safety:

The executor is thread-safe and can handle concurrent queries.

NodeMutatedCallback is called when a node is created or mutated via Cypher (CREATE, MERGE, SET, REMOVE, or procedures that update nodes). This allows external systems (like the embed queue) to be notified so embeddings can be (re)generated.

type NodePattern

type NodePattern struct {
	Variable   string
	Labels     []string
	Properties map[string]any
}

NodePattern represents a node in a pattern.

type OrderItem

type OrderItem struct {
	Expression Expression
	Descending bool
}

OrderItem represents an ORDER BY item.

type ParallelConfig

type ParallelConfig struct {
	// Enabled enables/disables parallel execution globally
	Enabled bool

	// MaxWorkers is the maximum number of goroutines to use
	// Default: runtime.NumCPU()
	MaxWorkers int

	// MinBatchSize is the minimum number of items before parallelizing
	// Below this threshold, sequential execution is used (overhead not worth it)
	// Default: 1000
	MinBatchSize int
}

ParallelConfig controls parallel execution behavior.

func DefaultParallelConfig

func DefaultParallelConfig() ParallelConfig

DefaultParallelConfig returns the default parallel execution configuration.

func GetParallelConfig

func GetParallelConfig() ParallelConfig

GetParallelConfig returns the current parallel execution configuration.

type Parameter

type Parameter struct {
	Name string
}

Parameter represents a query parameter ($name).

type Parser

type Parser struct{}

Parser parses Cypher queries into AST.

func NewParser

func NewParser() *Parser

NewParser creates a new Cypher parser.

func (*Parser) Parse

func (p *Parser) Parse(cypher string) (*Query, error)

Parse parses a Cypher query string into a Query AST.

type PathContext

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

PathContext holds node/relationship mappings for expression evaluation

type PathResult

type PathResult struct {
	Nodes         []*storage.Node
	Relationships []*storage.Edge
	Length        int
}

PathResult represents a path through the graph

type Pattern

type Pattern struct {
	Nodes []NodePattern
	Edges []EdgePattern
}

Pattern represents a graph pattern.

type PatternInfo

type PatternInfo struct {
	Pattern      QueryPattern
	RelType      string   // Relationship type for the pattern (e.g., "FOLLOWS")
	StartVar     string   // Start node variable (e.g., "a")
	EndVar       string   // End node variable (e.g., "b")
	RelVar       string   // Relationship variable (e.g., "r")
	AggFunctions []string // Aggregation functions used (e.g., ["count", "avg"])
	AggProperty  string   // Property being aggregated (e.g., "rating")
	Limit        int      // LIMIT value if present
	GroupByVars  []string // Variables in implicit GROUP BY
}

PatternInfo contains details about a detected pattern

func DetectQueryPattern

func DetectQueryPattern(ctx context.Context, query string) PatternInfo

DetectQueryPattern analyzes a Cypher query and returns pattern info

func (PatternInfo) IsOptimizable

func (p PatternInfo) IsOptimizable() bool

IsOptimizable returns true if the pattern can be optimized

func (PatternInfo) NeedsRelationshipTypeScan

func (p PatternInfo) NeedsRelationshipTypeScan() bool

NeedsRelationshipTypeScan returns true if the optimization needs all edges of a type

type PlanOperator

type PlanOperator struct {
	// Operator type (e.g., "NodeByLabelScan", "Filter", "Expand")
	OperatorType string `json:"operatorType"`

	// Human-readable description
	Description string `json:"description"`

	// Operator-specific arguments
	Arguments map[string]interface{} `json:"arguments,omitempty"`

	// Variables introduced by this operator
	Identifiers []string `json:"identifiers,omitempty"`

	// Child operators (execution flows bottom-up)
	Children []*PlanOperator `json:"children,omitempty"`

	// Cost estimation (for EXPLAIN and PROFILE)
	EstimatedRows int64 `json:"estimatedRows"`

	// Actual statistics (only for PROFILE)
	ActualRows int64         `json:"rows,omitempty"`
	DBHits     int64         `json:"dbHits,omitempty"`
	Time       time.Duration `json:"time,omitempty"`
}

PlanOperator represents a single operator in the execution plan

type ProcedureColumn

type ProcedureColumn struct {
	Name string
	Type string
}

ProcedureColumn defines one YIELD column in canonical metadata.

type ProcedureHandler

type ProcedureHandler func(ctx context.Context, exec *StorageExecutor, cypher string, args []interface{}) (*ExecuteResult, error)

ProcedureHandler executes a registered procedure.

type ProcedureMode

type ProcedureMode string

ProcedureMode represents Neo4j-compatible procedure execution mode.

const (
	ProcedureModeRead  ProcedureMode = "READ"
	ProcedureModeWrite ProcedureMode = "WRITE"
	ProcedureModeDBMS  ProcedureMode = "DBMS"
)

type ProcedureParam

type ProcedureParam struct {
	Name     string
	Type     string
	Optional bool
}

ProcedureParam defines one procedure argument in canonical metadata.

type ProcedureRegistry

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

func NewProcedureRegistry

func NewProcedureRegistry() *ProcedureRegistry

func (*ProcedureRegistry) ClearUser

func (r *ProcedureRegistry) ClearUser()

func (*ProcedureRegistry) Get

func (r *ProcedureRegistry) Get(name string) (registeredProcedure, bool)

func (*ProcedureRegistry) List

func (r *ProcedureRegistry) List() []ProcedureSpec

func (*ProcedureRegistry) ListBuiltIns

func (r *ProcedureRegistry) ListBuiltIns() []ProcedureSpec

func (*ProcedureRegistry) RegisterBuiltIn

func (r *ProcedureRegistry) RegisterBuiltIn(spec ProcedureSpec, handler ProcedureHandler) error

func (*ProcedureRegistry) RegisterUser

func (r *ProcedureRegistry) RegisterUser(spec ProcedureSpec, handler ProcedureHandler) error

type ProcedureSpec

type ProcedureSpec struct {
	Name          string
	Signature     string
	Description   string
	Mode          ProcedureMode
	WorksOnSystem bool
	Params        []ProcedureParam
	Returns       []ProcedureColumn
	MinArgs       int
	MaxArgs       int
}

ProcedureSpec is the canonical contract for built-in and user-defined procedures.

func ListRegisteredProcedures

func ListRegisteredProcedures() []ProcedureSpec

ListRegisteredProcedures returns built-in and user-registered procedures.

type PropertyAccess

type PropertyAccess struct {
	Variable string
	Property string
}

PropertyAccess represents property access (e.g., n.name).

type Query

type Query struct {
	Type       QueryType
	Clauses    []Clause
	Parameters map[string]any
}

Query represents a parsed Cypher query.

type QueryAnalyzer

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

QueryAnalyzer extracts query metadata with caching.

func NewQueryAnalyzer

func NewQueryAnalyzer(maxSize int) *QueryAnalyzer

NewQueryAnalyzer creates a new query analyzer with cache.

func (*QueryAnalyzer) Analyze

func (a *QueryAnalyzer) Analyze(cypher string) *QueryInfo

Analyze extracts query information, using cache when available.

func (*QueryAnalyzer) CacheSize

func (a *QueryAnalyzer) CacheSize() int

CacheSize returns current cache size.

func (*QueryAnalyzer) ClearCache

func (a *QueryAnalyzer) ClearCache()

ClearCache clears the analysis cache.

type QueryCache

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

QueryCache provides LRU (Least Recently Used) caching for Cypher query results with automatic TTL (Time To Live) expiration.

The cache improves performance by storing results of expensive read-only queries and returning them instantly on subsequent identical requests. It automatically handles cache invalidation when write operations occur.

Features:

  • LRU eviction when cache is full (keeps most recently used)
  • TTL-based expiration for time-sensitive data
  • Thread-safe concurrent access
  • Automatic invalidation on writes (CREATE, DELETE, SET, etc.)
  • Hit/miss statistics for monitoring

Example 1 - Basic Caching:

cache := NewQueryCache(1000) // Store up to 1000 query results

// First query - cache miss, executes and stores
result1, found := cache.Get("MATCH (n) RETURN count(n)", nil)
// found == false, executes query

cache.Put("MATCH (n) RETURN count(n)", nil, result1, 5*time.Minute)

// Second query - cache hit, instant return
result2, found := cache.Get("MATCH (n) RETURN count(n)", nil)
// found == true, returns cached result (10-100x faster!)

Example 2 - With Parameters:

params := map[string]interface{}{"name": "Alice", "minAge": 25}
cypher := "MATCH (n:Person {name: $name}) WHERE n.age >= $minAge RETURN n"

// Parameters are part of cache key
result, found := cache.Get(cypher, params)
if !found {
	result = executeQuery(cypher, params)
	cache.Put(cypher, params, result, 1*time.Minute)
}

Example 3 - Cache Invalidation:

// Read queries use cache
cache.Get("MATCH (n:User) RETURN n.name", nil)

// Write query invalidates entire cache
executor.Execute(ctx, "CREATE (n:User {name: 'Bob'})", nil)
cache.Invalidate() // All cached results cleared

// Next query will be cache miss
cache.Get("MATCH (n:User) RETURN n.name", nil) // Re-executes

ELI12 (Explain Like I'm 12):

Imagine you're doing math homework and your friend asks "What's 127 × 384?" You grab your calculator and spend 30 seconds calculating: 48,768.

Five minutes later, they ask the SAME question again. Instead of using your calculator again, you just look at your paper where you wrote the answer: 48,768. That's caching! You remembered the answer from before.

But what if you're told "new homework sheet" (a write operation)? You erase your paper because those old answers might not be right anymore. That's cache invalidation.

The QueryCache does this for database queries - it remembers answers to questions it's seen before, so it can reply instantly without doing all the work again!

Performance Impact:

  • Cache hits are 10-100x faster than executing queries
  • Reduces database load for read-heavy workloads
  • Memory usage: ~1KB per cached query result

Thread Safety:

All methods are thread-safe and can be called from multiple goroutines.

func NewQueryCache

func NewQueryCache(maxSize int) *QueryCache

NewQueryCache creates a new query cache with the specified maximum size.

The cache uses LRU (Least Recently Used) eviction - when full, it removes the oldest unused entries to make room for new ones.

Parameters:

  • maxSize: Maximum number of query results to cache (recommended: 100-10000)

Returns:

  • *QueryCache ready for use

Example:

// Small cache for testing
cache := NewQueryCache(100)

// Production cache for high-traffic application
cache := NewQueryCache(10000)

// Memory-constrained environment
cache := NewQueryCache(50)

Memory Usage:

  • Approximately maxSize * 1KB for typical queries
  • 1000 entries ≈ 1MB memory
  • 10000 entries ≈ 10MB memory

func (*QueryCache) Get

func (qc *QueryCache) Get(cypher string, params map[string]interface{}) (*ExecuteResult, bool)

Get retrieves a cached query result if it exists and hasn't expired.

The method checks both existence and TTL expiration. If found and valid, it moves the entry to the front of the LRU list (marking it as recently used) and increments the hit counter. Otherwise, it increments the miss counter.

Parameters:

  • cypher: The Cypher query string
  • params: Query parameters (can be nil). Different params = different cache entry.

Returns:

  • *ExecuteResult: The cached result if found and valid
  • bool: true if cache hit, false if cache miss

Example 1 - Simple Usage:

result, found := cache.Get("MATCH (n) RETURN n.name", nil)
if found {
	// cache hit — return the cached result
	return result
}
// cache miss — execute the query and Put() the result into the cache

Example 2 - With Parameters:

params := map[string]interface{}{"id": "user-123"}
result, found := cache.Get("MATCH (n:User {id: $id}) RETURN n", params)

Example 3 - Pattern for Query Execution:

func (e *Executor) ExecuteWithCache(cypher string, params map[string]interface{}) (*ExecuteResult, error) {
	// Try cache first
	if result, found := e.cache.Get(cypher, params); found {
		return result, nil
	}

	// Cache miss - execute query
	result, err := e.executeQuery(cypher, params)
	if err != nil {
		return nil, err
	}

	// Store in cache for next time
	e.cache.Put(cypher, params, result, 5*time.Minute)
	return result, nil
}

Thread Safety:

Safe to call concurrently from multiple goroutines.

func (*QueryCache) Invalidate

func (qc *QueryCache) Invalidate()

Invalidate clears all cached query results.

This method is called after write operations (CREATE, DELETE, SET, REMOVE, MERGE) to ensure cached results don't become stale. It removes all entries from the cache.

Future Enhancement: Smart invalidation that only removes entries affected by specific labels or patterns, rather than clearing the entire cache.

Example 1 - After Write Operations:

// Execute write query
_, err := executor.Execute(ctx, "CREATE (n:User {name: 'Bob'})", nil)
if err == nil {
	cache.Invalidate() // Clear cache so old counts/results are refreshed
}

Example 2 - Manual Cache Reset:

// Clear cache after bulk import
importUsers(dataFile)
cache.Invalidate() // Force all queries to re-execute with new data

Example 3 - Integration Pattern:

func (e *Executor) Execute(ctx context.Context, cypher string) (*ExecuteResult, error) {
	// Check if query modifies data
	if isWriteQuery(cypher) {
		defer e.cache.Invalidate() // Clear cache after write
	}

	// Try cache for read queries
	if isReadQuery(cypher) {
		if result, found := e.cache.Get(cypher, nil); found {
			return result, nil
		}
	}

	return e.executeQuery(ctx, cypher)
}

ELI12:

Imagine you have a notebook with answers to questions about your toy collection. You write "I have 10 cars" in the notebook. Later, you get 3 new cars as gifts. Now your notebook is WRONG - it still says 10! So you erase the ENTIRE notebook and start fresh. Next time someone asks, you'll count again and get the right answer: 13 cars.

That's what Invalidate does - it erases all the old answers because something changed, and the old answers might be wrong now.

Thread Safety:

Safe to call concurrently from multiple goroutines.

func (*QueryCache) Put

func (qc *QueryCache) Put(cypher string, params map[string]interface{}, result *ExecuteResult, ttl time.Duration)

Put stores a query result in the cache with the specified TTL (Time To Live).

If the cache is at capacity, the least recently used entry is evicted first (LRU eviction policy). The new entry is added to the front of the LRU list.

Parameters:

  • cypher: The Cypher query string
  • params: Query parameters (can be nil)
  • result: The query result to cache
  • ttl: How long the result stays valid (e.g., 5*time.Minute)

Example 1 - Basic Caching:

result, err := executor.Execute(ctx, "MATCH (n:User) RETURN count(n)", nil)
if err == nil {
	cache.Put("MATCH (n:User) RETURN count(n)", nil, result, 5*time.Minute)
}

Example 2 - Different TTLs for Different Queries:

// Fast-changing data - short TTL
cache.Put("MATCH (n:ActiveSession) RETURN n", nil, result, 30*time.Second)

// Stable data - longer TTL
cache.Put("MATCH (n:Country) RETURN n.name", nil, result, 1*time.Hour)

// Very stable reference data
cache.Put("MATCH (n:Constant) RETURN n", nil, result, 24*time.Hour)

Example 3 - Pattern After Query Execution:

result, err := executeQuery(cypher, params)
if err != nil {
	return nil, err
}

// Cache successful results
if isReadOnlyQuery(cypher) {
	cache.Put(cypher, params, result, 5*time.Minute)
}
return result, nil

ELI12:

When you learn a new fact, you write it in your notebook with a date. Later, if someone asks you that fact, you check your notebook first instead of looking it up again. The TTL is like saying "this fact is only good for 1 hour" - after that, you need to check the source again.

Thread Safety:

Safe to call concurrently from multiple goroutines.

func (*QueryCache) Stats

func (qc *QueryCache) Stats() (hits, misses int64, size int)

Stats returns cache performance statistics for monitoring.

Returns:

  • hits: Number of successful cache retrievals
  • misses: Number of cache misses (not found or expired)
  • size: Current number of cached entries

Example 1 - Monitoring Cache Performance:

hits, misses, size := cache.Stats()
hitRate := float64(hits) / float64(hits+misses) * 100
// emit hit-rate metric e.g. "Cache hit rate: 87.50% (450/1000 entries)"

Example 2 - Prometheus Metrics:

func collectMetrics() {
	hits, misses, size := cache.Stats()
	prometheus.CacheHits.Set(float64(hits))
	prometheus.CacheMisses.Set(float64(misses))
	prometheus.CacheSize.Set(float64(size))
}

Example 3 - Auto-Tuning Cache Size:

hits, misses, size := cache.Stats()
hitRate := float64(hits) / float64(hits+misses)

if hitRate < 0.5 && size == maxSize {
	// Low hit rate and cache is full — emit a structured warning so
	// operators can react (e.g. via the package logger).
}

ELI12:

Imagine you're playing a video game and trying to remember enemy patterns. - Hits: Times you remembered correctly and didn't get hit - Misses: Times you forgot and had to learn again - Size: How many patterns you have memorized right now

If your hit rate is 80%, that means 8 out of 10 times you remembered!

Thread Safety:

Safe to call concurrently from multiple goroutines.

type QueryEmbedder

type QueryEmbedder interface {
	Embed(ctx context.Context, text string) ([]float32, error)
	ChunkText(text string, maxTokens, overlap int) ([]string, error)
}

QueryEmbedder generates embeddings for search queries. This is a minimal interface to avoid import cycles with embed package.

type QueryInfo

type QueryInfo struct {
	// Query type flags - set during analysis
	HasMatch         bool
	HasOptionalMatch bool
	HasCreate        bool
	HasMerge         bool
	HasDelete        bool
	HasDetachDelete  bool
	HasSet           bool
	HasRemove        bool
	HasReturn        bool
	HasWith          bool
	HasUnwind        bool
	HasCall          bool
	HasExplain       bool
	HasProfile       bool
	HasShow          bool
	HasSchema        bool
	HasUnion         bool
	HasForeach       bool
	HasLoadCSV       bool
	HasShortestPath  bool
	HasOrderBy       bool
	HasLimit         bool
	HasSkip          bool
	HasAggregation   bool // COUNT, SUM, AVG, etc. (cached with conservative TTL)

	// First clause type for routing
	FirstClause ClauseType

	// Derived properties
	IsReadOnly      bool
	IsWriteQuery    bool
	IsSchemaQuery   bool
	IsCompoundQuery bool

	// Labels mentioned (for cache invalidation)
	Labels []string

	// Relationship types mentioned
	RelationshipTypes []string

	// The parsed AST clauses (if full parsing done)
	Clauses []Clause

	// Original query (normalized)
	NormalizedQuery string
	// contains filtered or unexported fields
}

QueryInfo contains analyzed metadata extracted during query parsing. This is populated once and cached to avoid repeated string parsing.

func (*QueryInfo) GetAST

func (info *QueryInfo) GetAST() *AST

GetAST returns the structured AST for the query. The AST is lazily built on first call and cached for subsequent calls. This is useful for LLM features that need structured query representation.

func (*QueryInfo) HasAST

func (info *QueryInfo) HasAST() bool

HasAST returns true if the AST has already been built.

type QueryPattern

type QueryPattern int

QueryPattern identifies optimizable query structures

const (
	// PatternGeneric is the default - use standard execution
	PatternGeneric QueryPattern = iota

	// PatternMutualRelationship detects (a)-[:T]->(b)-[:T]->(a) cycles
	// Optimized via single-pass edge set intersection
	PatternMutualRelationship

	// PatternIncomingCountAgg detects MATCH (x)<-[:T]-(y) RETURN x, count(y)
	// Optimized via single-pass edge counting
	PatternIncomingCountAgg

	// PatternOutgoingCountAgg detects MATCH (x)-[:T]->(y) RETURN x, count(y)
	// Optimized via single-pass edge counting
	PatternOutgoingCountAgg

	// PatternEdgePropertyAgg detects avg/sum/count on edge properties
	// Optimized via single-pass accumulation
	PatternEdgePropertyAgg

	// PatternLargeResultSet detects queries returning many rows (LIMIT > 100)
	// Optimized via batch node lookups and pre-allocation
	PatternLargeResultSet
)

func (QueryPattern) String

func (p QueryPattern) String() string

String returns a human-readable pattern name

type QueryPlanCache

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

QueryPlanCache caches parsed query ASTs to skip repeated parsing. Parsing can take 10-20% of query execution time for simple queries.

The cache uses a normalized query string (whitespace collapsed, case normalized) as the key, so "MATCH (n) RETURN n" and "match (n) return n" share the cache.

Example:

planCache := NewQueryPlanCache(500)

// First execution parses and caches
plan, found := planCache.Get("MATCH (n:User) RETURN n")
if !found {
    plan = parser.Parse("MATCH (n:User) RETURN n")
    planCache.Put("MATCH (n:User) RETURN n", plan)
}

// Second execution uses cached plan (skip parsing!)
plan, found = planCache.Get("MATCH (n:User) RETURN n")
// found == true

func NewQueryPlanCache

func NewQueryPlanCache(maxSize int) *QueryPlanCache

NewQueryPlanCache creates a new query plan cache.

func (*QueryPlanCache) Clear

func (pc *QueryPlanCache) Clear()

Clear empties the plan cache.

func (*QueryPlanCache) Get

func (pc *QueryPlanCache) Get(cypher string) ([]Clause, QueryType, bool)

Get retrieves a cached query plan.

func (*QueryPlanCache) Put

func (pc *QueryPlanCache) Put(cypher string, clauses []Clause, queryType QueryType)

Put stores a parsed query plan.

func (*QueryPlanCache) SetCypherMetrics added in v1.1.0

func (pc *QueryPlanCache) SetCypherMetrics(m *observability.CypherMetrics)

SetCypherMetrics installs the Plan 04-03 CypherMetrics bag for planner- specific observation per CONTEXT D-12a. Nil-safe (nil bag → no observation).

func (*QueryPlanCache) Stats

func (pc *QueryPlanCache) Stats() (hits, misses int64, size int)

Stats returns plan cache statistics.

type QueryStats

type QueryStats struct {
	NodesCreated         int `json:"nodes_created"`
	NodesDeleted         int `json:"nodes_deleted"`
	RelationshipsCreated int `json:"relationships_created"`
	RelationshipsDeleted int `json:"relationships_deleted"`
	PropertiesSet        int `json:"properties_set"`
	LabelsAdded          int `json:"labels_added"`
}

QueryStats holds query execution statistics.

type QueryType

type QueryType int

QueryType represents the type of Cypher query.

const (
	QueryMatch QueryType = iota
	QueryCreate
	QueryMerge
	QueryDelete
	QuerySet
	QueryReturn
	QueryWith
)

type RelationshipPattern

type RelationshipPattern struct {
	Variable   string   // r in [r:TYPE]
	Types      []string // TYPE in [r:TYPE|OTHER]
	Direction  string   // "outgoing" (-[r]->), "incoming" (<-[r]-), "both" (-[r]-)
	MinHops    int      // min in [*min..max]
	MaxHops    int      // max in [*min..max]
	Properties map[string]interface{}
}

RelationshipPattern represents a parsed relationship pattern

type Result

type Result struct {
	Columns []string
	Rows    []map[string]any
}

Result holds query results.

func (*Result) RowCount

func (r *Result) RowCount() int

RowCount returns the number of rows.

type ReturnClause

type ReturnClause struct {
	Items   []ReturnItem
	OrderBy []OrderItem
	Skip    *int
	Limit   *int
}

ReturnClause represents a RETURN clause.

type ReturnItem

type ReturnItem struct {
	Expression Expression
	Alias      string
}

ReturnItem represents an item in a RETURN clause.

type SearchResult

type SearchResult struct {
	ID         string  `cypher:"id" json:"id"`
	Score      float64 `cypher:"score" json:"score"`
	Title      string  `cypher:"title" json:"title"`
	Content    string  `cypher:"content" json:"content"`
	Similarity float64 `cypher:"similarity" json:"similarity"`
}

SearchResult represents a search result with score.

type SetClause

type SetClause struct {
	Items []SetItem
}

SetClause represents a SET clause.

type SetItem

type SetItem struct {
	Variable string
	Property string
	Value    Expression
}

SetItem represents a SET operation.

type ShapeCapture

type ShapeCapture struct {
	Name  string
	Value any
}

type ShapeCaptures

type ShapeCaptures struct {
	Ordered []ShapeCapture
	ByName  map[string]any
}

func NewShapeCaptures

func NewShapeCaptures() ShapeCaptures

func (*ShapeCaptures) Add

func (c *ShapeCaptures) Add(name string, value any)

func (ShapeCaptures) Any

func (c ShapeCaptures) Any(name string) any

func (ShapeCaptures) Get

func (c ShapeCaptures) Get(name string) (any, bool)

func (ShapeCaptures) Int

func (c ShapeCaptures) Int(name string) int

func (ShapeCaptures) String

func (c ShapeCaptures) String(name string) string

type ShapeKind

type ShapeKind string

type ShapeMatch

type ShapeMatch struct {
	Kind     ShapeKind
	Captures ShapeCaptures
	Probe    ShapeProbe
}

type ShapeProbe

type ShapeProbe struct {
	Matcher         string
	Matched         bool
	RejectReason    string
	NormalizedQuery string
	CapturedFields  map[string]string
}

type ShortestPathQuery

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

ShortestPathQuery represents a parsed shortest path query

type ShowDecayProfilesCmd added in v1.1.0

type ShowDecayProfilesCmd struct{}

type ShowPromotionPoliciesCmd added in v1.1.0

type ShowPromotionPoliciesCmd struct{}

type ShowPromotionProfilesCmd added in v1.1.0

type ShowPromotionProfilesCmd struct{}

type SmartQueryCache

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

SmartQueryCache extends QueryCache with label-aware invalidation. Instead of clearing the entire cache on any write, it tracks which labels each cached query depends on and only invalidates affected entries.

Performance:

  • Writes to :User only invalidate queries touching :User
  • Queries on :Product remain cached when :User is modified
  • Reduces cache misses by 50-80% in multi-label workloads

Example:

cache := NewSmartQueryCache(1000)

// Cache query for User nodes
cache.PutWithLabels("MATCH (n:User) RETURN n", nil, result, 5*time.Minute, []string{"User"})

// This invalidates only User-related queries
cache.InvalidateLabels([]string{"User"})

// Product queries remain cached!
result, found := cache.Get("MATCH (n:Product) RETURN n", nil)

func NewSmartQueryCache

func NewSmartQueryCache(maxSize int) *SmartQueryCache

NewSmartQueryCache creates a cache with label-aware invalidation.

func (*SmartQueryCache) Get

func (sc *SmartQueryCache) Get(cypher string, params map[string]interface{}) (*ExecuteResult, bool)

Get retrieves a cached result (same as QueryCache).

func (*SmartQueryCache) Invalidate

func (sc *SmartQueryCache) Invalidate()

Invalidate clears the entire cache (fallback for complex operations).

func (*SmartQueryCache) InvalidateLabels

func (sc *SmartQueryCache) InvalidateLabels(labels []string)

InvalidateLabels removes only cache entries that depend on the given labels. This is much more efficient than full invalidation for multi-label workloads. Also invalidates queries with NO labels (like "MATCH (n) RETURN count(n)") since they match all nodes and are affected by any label change.

func (*SmartQueryCache) Put

func (sc *SmartQueryCache) Put(cypher string, params map[string]interface{}, result *ExecuteResult, ttl time.Duration)

Put stores a result, auto-extracting labels from the query.

func (*SmartQueryCache) PutWithLabels

func (sc *SmartQueryCache) PutWithLabels(cypher string, params map[string]interface{}, result *ExecuteResult, ttl time.Duration, labels []string)

PutWithLabels stores a result with associated labels for smart invalidation.

func (*SmartQueryCache) SetCacheMetrics added in v1.1.0

func (sc *SmartQueryCache) SetCacheMetrics(m *observability.CacheMetrics)

SetCacheMetrics installs the Plan 04-03 D-12a cross-cutting cache bag for query-result observation. Nil-safe (nil bag → no observation). Per CONTEXT D-12 the closed `cache` enum binds to "query_result" here.

func (*SmartQueryCache) Stats

func (sc *SmartQueryCache) Stats() (hits, misses int64, size int, smartInvals, fullInvals int64)

Stats returns cache statistics including smart invalidation metrics.

type StorageExecutor

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

func NewStorageExecutor

func NewStorageExecutor(store storage.Engine) *StorageExecutor

NewStorageExecutor creates a new Cypher executor with the given storage backend.

The executor is initialized with a parser and connected to the storage engine. It's ready to execute Cypher queries immediately after creation.

Parameters:

  • store: Storage engine to execute queries against (required)

Returns:

  • StorageExecutor ready for query execution

Example:

// Create storage and executor
storage := storage.NewMemoryEngine()
executor := cypher.NewStorageExecutor(storage)

// Executor is ready for queries
result, err := executor.Execute(ctx, "MATCH (n) RETURN count(n)", nil)

func (*StorageExecutor) BatchGetNodes

func (e *StorageExecutor) BatchGetNodes(ids []storage.NodeID) map[storage.NodeID]*storage.Node

BatchGetNodes retrieves multiple nodes in a single operation Used for large result set optimization

func (*StorageExecutor) ClearQueryCaches added in v1.1.0

func (e *StorageExecutor) ClearQueryCaches()

ClearQueryCaches clears executor-local caches that can retain stale read results.

func (*StorageExecutor) CypherMetrics added in v1.1.0

func (e *StorageExecutor) CypherMetrics() *observability.CypherMetrics

CypherMetrics returns the injected metrics bag (or nil if unset). Exposed so cloned executors can re-inject when constructed via newTxScopedExecutor outside the cloneWithStorage pathway.

func (*StorageExecutor) Database added in v1.1.0

func (e *StorageExecutor) Database() string

Database returns the configured database label value used for tenant-tagged Cypher metric observations (D-08).

func (*StorageExecutor) Execute

func (e *StorageExecutor) Execute(ctx context.Context, cypher string, params map[string]interface{}) (result *ExecuteResult, retErr error)

Execute parses and executes a Cypher query with optional parameters.

This is the main entry point for Cypher query execution. The method handles the complete query lifecycle: parsing, validation, parameter substitution, execution planning, and result formatting.

Parameters:

  • ctx: Context for cancellation and timeouts
  • cypher: Cypher query string
  • params: Optional parameters for $param substitution

Returns:

  • ExecuteResult with columns and rows
  • Error if query parsing or execution fails

Example:

// Simple query without parameters
result, err := executor.Execute(ctx, "MATCH (n:Person) RETURN n.name", nil)
if err != nil {
	log.Fatal(err)
}

// Parameterized query
params := map[string]interface{}{
	"name": "Alice",
	"minAge": 25,
}
result, err = executor.Execute(ctx, `
	MATCH (n:Person {name: $name})
	WHERE n.age >= $minAge
	RETURN n.name, n.age
`, params)

// Process results
// emit "Columns: %v" via the configured logger
for _, row := range result.Rows {
	// process row (e.g. emit "Row: %v" via the configured logger)
}

Supported Query Types:

Core Clauses:
- MATCH: Pattern matching and traversal
- OPTIONAL MATCH: Left outer joins (returns nulls for no matches)
- CREATE: Node and relationship creation
- MERGE: Upsert operations with ON CREATE SET / ON MATCH SET
- DELETE / DETACH DELETE: Node and relationship deletion
- SET: Property updates
- REMOVE: Property and label removal

Projection & Chaining:
- RETURN: Result projection with expressions, aliases, aggregations
- WITH: Query chaining and intermediate aggregation
- UNWIND: List expansion into rows

Filtering & Ordering:
- WHERE: Filtering conditions (=, <>, <, >, <=, >=, IS NULL, IS NOT NULL, IN, CONTAINS, STARTS WITH, ENDS WITH, AND, OR, NOT)
- ORDER BY: Result sorting (ASC/DESC)
- SKIP / LIMIT: Pagination

Aggregation Functions:
- COUNT, SUM, AVG, MIN, MAX, COLLECT

Procedures & Functions:
- CALL: Procedure invocation (db.labels, db.propertyKeys, db.index.vector.*, etc.)
- CALL {}: Subquery execution with UNION support

Advanced:
- UNION / UNION ALL: Query composition
- FOREACH: Iterative updates
- LOAD CSV: Data import
- EXPLAIN / PROFILE: Query analysis
- SHOW: Schema introspection

Path Functions:
- shortestPath / allShortestPaths

Error Handling:

Returns detailed error messages for syntax errors, type mismatches,
and execution failures with Neo4j-compatible error codes.

func (*StorageExecutor) ExecuteOptimized

func (e *StorageExecutor) ExecuteOptimized(ctx context.Context, query string, patternInfo PatternInfo) (*ExecuteResult, bool)

ExecuteOptimized attempts to execute a query using an optimized path. Returns (result, true) if optimization was applied, (nil, false) otherwise.

func (*StorageExecutor) Flush

func (e *StorageExecutor) Flush() error

Flush persists all pending writes to storage. This implements FlushableExecutor for Bolt-level deferred commits.

func (*StorageExecutor) GetDefaultEmbeddingDimensions

func (e *StorageExecutor) GetDefaultEmbeddingDimensions() int

GetDefaultEmbeddingDimensions returns the configured default embedding dimensions. Returns 1024 as fallback if not configured.

func (*StorageExecutor) GetEmbedder

func (e *StorageExecutor) GetEmbedder() QueryEmbedder

GetEmbedder returns the query embedder if set. This allows copying the embedder to namespaced executors for GraphQL.

func (*StorageExecutor) GetInferenceManager

func (e *StorageExecutor) GetInferenceManager() InferenceManager

GetInferenceManager returns the configured inference manager.

func (*StorageExecutor) GetVectorRegistry

func (e *StorageExecutor) GetVectorRegistry() *vectorspace.IndexRegistry

GetVectorRegistry exposes the current registry (for tests and adapters).

func (*StorageExecutor) InvalidateEntityCaches added in v1.1.0

func (e *StorageExecutor) InvalidateEntityCaches(entityID string, tokens []string)

InvalidateEntityCaches evicts targeted cache entries affected by a specific entity state change.

func (*StorageExecutor) LastHotPathTrace

func (e *StorageExecutor) LastHotPathTrace() HotPathTrace

LastHotPathTrace returns a snapshot of the latest per-query hot path trace.

func (*StorageExecutor) Logger added in v1.1.0

func (e *StorageExecutor) Logger() *slog.Logger

Logger returns the bound *slog.Logger. Exposed so transient executors (e.g., per-transaction sessions cloned from a base) can inherit the configured logger without re-threading from main.

func (*StorageExecutor) SetCacheMetrics added in v1.1.0

func (e *StorageExecutor) SetCacheMetrics(m *observability.CacheMetrics)

SetCacheMetrics installs the Plan 04-01 cross-cutting CacheMetrics bag for D-12a query-result cache observation. Routes the bag into the owned SmartQueryCache so cache_hits_total{cache="query_result"} + cache_misses_total + cache_evictions_total emit on every Get/Put/Evict.

Nil-safe; mirrors SetCypherMetrics shape.

func (*StorageExecutor) SetCypherMetrics added in v1.1.0

func (e *StorageExecutor) SetCypherMetrics(m *observability.CypherMetrics, database string)

SetCypherMetrics installs the Plan 04-03 CypherMetrics typed bag (MET-08) and the database label value passed on tenant-tagged families when D-08 tenantLabelsEnabled=true. Mirrors the SetLogger / SetSlowQueryThreshold non-breaking pattern (D-01 non-breaking ctor).

Also propagates the bag into the executor's owned planCache so the planner_cache_{hits,misses,size} families fire from QueryPlanCache.Get/Put without callers having to reach into private fields.

Nil-safe: passing m=nil leaves observation as a no-op so tests and alternate constructors that don't wire metrics don't have to. The three observation chokepoints in Execute() guard on m == nil.

Cloned executors inherit metrics + database via cloneWithStorage so the bag flows through per-query / per-tx scoped clones.

func (*StorageExecutor) SetDatabaseManager

func (e *StorageExecutor) SetDatabaseManager(dbManager DatabaseManagerInterface)

SetDatabaseManager sets the database manager for system commands. When set, enables CREATE DATABASE, DROP DATABASE, and SHOW DATABASES commands.

Example:

executor := cypher.NewStorageExecutor(storage)
executor.SetDatabaseManager(dbManager)
// Now CREATE DATABASE, DROP DATABASE, SHOW DATABASES work

func (*StorageExecutor) SetDefaultEmbeddingDimensions

func (e *StorageExecutor) SetDefaultEmbeddingDimensions(dims int)

SetDefaultEmbeddingDimensions sets the default dimensions for vector indexes. This is used when CREATE VECTOR INDEX doesn't specify dimensions in OPTIONS.

func (*StorageExecutor) SetDeferFlush

func (e *StorageExecutor) SetDeferFlush(enabled bool)

SetDeferFlush enables/disables deferred flush mode. When enabled, writes are not auto-flushed - the Bolt layer calls Flush().

func (*StorageExecutor) SetEmbedder

func (e *StorageExecutor) SetEmbedder(embedder QueryEmbedder)

SetEmbedder sets the query embedder for server-side embedding. When set, db.index.vector.queryNodes can accept string queries which are automatically embedded before search.

Example:

executor := cypher.NewStorageExecutor(storage)
executor.SetEmbedder(embedder)

// Now vector search accepts both:
// CALL db.index.vector.queryNodes('idx', 10, [0.1, 0.2, ...])  // Vector
// CALL db.index.vector.queryNodes('idx', 10, 'search query')   // String (auto-embedded)

func (*StorageExecutor) SetInferenceManager

func (e *StorageExecutor) SetInferenceManager(mgr InferenceManager)

SetInferenceManager sets the inference manager used by db.infer.

func (*StorageExecutor) SetLogger added in v1.1.0

func (e *StorageExecutor) SetLogger(logger *slog.Logger)

SetLogger installs the structured slog.Logger used for slow-query and operational records. D-01 non-breaking: NewStorageExecutor's signature is unchanged; callers (cmd/nornicdb/main.go) call SetLogger after construction so the *slog.Logger from observability.NewLogger flows through.

Discard-fallback: passing nil installs a slog.Logger backed by io.Discard so subsequent log emissions cannot panic. The "component" attribute is pre-bound here (not per-call) to honor the RESEARCH "Per-call .With() allocation" anti-pattern.

func (*StorageExecutor) SetNodeMutatedCallback

func (e *StorageExecutor) SetNodeMutatedCallback(cb NodeMutatedCallback)

SetNodeMutatedCallback sets a callback that is invoked when nodes are created or mutated (CREATE, MERGE, SET, REMOVE, or procedures that update nodes). This allows the embed queue to be notified so embeddings can be (re)generated.

Example:

executor := cypher.NewStorageExecutor(storage)
executor.SetNodeMutatedCallback(func(nodeID string) {
    embedQueue.Enqueue(nodeID)
})

func (*StorageExecutor) SetSearchService

func (e *StorageExecutor) SetSearchService(svc *search.Service)

SetSearchService sets the unified search service used by Cypher procedures. When set, db.index.vector.queryNodes will delegate to search.Service.

func (*StorageExecutor) SetSlowQueryThreshold added in v1.1.0

func (e *StorageExecutor) SetSlowQueryThreshold(d time.Duration)

SetSlowQueryThreshold configures the D-04c slow-query emission gate. Zero or negative durations disable slow-query logging entirely. Threaded from cfg.Logging.SlowQueryThreshold at the bootstrap site.

func (*StorageExecutor) SetVectorRegistry

func (e *StorageExecutor) SetVectorRegistry(reg *vectorspace.IndexRegistry)

SetVectorRegistry allows wiring a shared index registry (e.g., per database). Defaults to an internal registry when not set.

func (*StorageExecutor) SlowQueryThreshold added in v1.1.0

func (e *StorageExecutor) SlowQueryThreshold() time.Duration

SlowQueryThreshold returns the configured slow-query emission gate. Exposed so cloned executors inherit the threshold from their base.

type TemporalViewport

type TemporalViewport struct {
	Mode TemporalViewportMode
	AsOf time.Time
}

func AsOfTemporalViewport

func AsOfTemporalViewport(asOf time.Time) TemporalViewport

func CurrentTemporalViewport

func CurrentTemporalViewport() TemporalViewport

func TemporalViewportFromContext

func TemporalViewportFromContext(ctx context.Context) (TemporalViewport, bool)

func (TemporalViewport) Enabled

func (v TemporalViewport) Enabled() bool

type TemporalViewportMode

type TemporalViewportMode int
const (
	TemporalViewportLive TemporalViewportMode = iota
	TemporalViewportAsOf
)

type TransactionCapableEngine

type TransactionCapableEngine interface {
	BeginTransaction() (*storage.BadgerTransaction, error)
}

TransactionCapableEngine is an engine that supports ACID transactions. Used for type assertion to wrap implicit writes in rollback-capable transactions.

type TransactionContext

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

TransactionContext holds the active transaction for a Cypher session.

type TraversalContext

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

TraversalContext holds state during graph traversal

type TraversalMatch

type TraversalMatch struct {
	StartNode    nodePatternInfo
	EndNode      nodePatternInfo
	Relationship RelationshipPattern
	// For chained patterns like (a)-[:R1]->(b)-[:R2]->(c), we store intermediate segments
	IntermediateNodes []nodePatternInfo
	Segments          []TraversalSegment // All segments in the chain
	IsChained         bool               // True if this is a multi-segment pattern
	PathVariable      string             // Variable name for path assignment (e.g., "path" in "path = (a)-[r]-(b)")
	TraversalLimit    int                // Early traversal cap for LIMIT-only shapes (0 = disabled)
}

TraversalMatch represents a parsed traversal pattern

type TraversalSegment

type TraversalSegment struct {
	FromNode     nodePatternInfo
	ToNode       nodePatternInfo
	Relationship RelationshipPattern
}

TraversalSegment represents one segment in a chained pattern

type TypedExecuteResult

type TypedExecuteResult[T any] struct {
	Columns []string
	Rows    []T
	Stats   *QueryStats
}

TypedExecuteResult wraps query results with typed row access.

func TypedExecute

func TypedExecute[T any](ctx context.Context, exec *StorageExecutor, cypher string, params map[string]interface{}) (*TypedExecuteResult[T], error)

TypedExecute executes a Cypher query and decodes results into typed structs. This is a top-level function (not a method) to avoid polluting the executor interface.

Usage:

result, err := TypedExecute[MemoryNode](ctx, executor, "MATCH (n:Memory) RETURN n", nil)
for _, node := range result.Rows {
    // print or process node.Title, node.Content
}

func (*TypedExecuteResult[T]) Count

func (r *TypedExecuteResult[T]) Count() int

Count returns the number of rows.

func (*TypedExecuteResult[T]) First

func (r *TypedExecuteResult[T]) First() (T, bool)

First returns the first row or zero value if empty.

func (*TypedExecuteResult[T]) IsEmpty

func (r *TypedExecuteResult[T]) IsEmpty() bool

IsEmpty returns true if no rows were returned.

type WhereClause

type WhereClause struct {
	Expression Expression
}

WhereClause represents a WHERE clause.

type WorkerPool

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

WorkerPool manages a pool of worker goroutines for parallel execution.

func NewWorkerPool

func NewWorkerPool(numWorkers int) *WorkerPool

NewWorkerPool creates a new worker pool with the specified number of workers.

func (*WorkerPool) Start

func (p *WorkerPool) Start()

Start starts the worker goroutines.

func (*WorkerPool) Stop

func (p *WorkerPool) Stop()

Stop stops the worker pool and waits for all jobs to complete.

func (*WorkerPool) Submit

func (p *WorkerPool) Submit(job func())

Submit submits a job to the worker pool.

func (*WorkerPool) Wait

func (p *WorkerPool) Wait()

Wait waits for all submitted jobs to complete.

Source Files

Directories

Path Synopsis
Package antlr provides ANTLR-based Cypher parsing for NornicDB.
Package antlr provides ANTLR-based Cypher parsing for NornicDB.
Package testutil provides shared test utilities for the NornicDB Cypher package.
Package testutil provides shared test utilities for the NornicDB Cypher package.

Jump to

Keyboard shortcuts

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