Skip to content

API Reference ​

This section is the canonical source for protocol and endpoint definitions.

Start Here ​

For lifecycle, configuration, executable Go examples, and transaction ownership, start with Embedding NornicDB. This reference defines the lower-level contracts used by that guide.

Find by Interface ​

Cypher ​

HTTP (Neo4j-compatible + Nornic extensions) ​

Bolt ​

GraphQL ​

Embedded Go storage and atomic writes ​

Local Cypher writes through cypher.NewStorageExecutor(engine) require a transaction-capable storage owner before any mutation or WRITE procedure callback runs. A custom storage.Engine exposing only the required interface can serve read-only statements that need no transaction; writes return the same “engine does not support transactions” error as BEGIN. There is no direct-write fallback. The existing transaction-storage requirement error for WITH EMBEDDING remains unchanged.

Native MemoryEngine and BadgerEngine provide BeginTransaction() (*storage.BadgerTransaction, error). A transparent adapter can retain the existing storage.EngineUnwrapper contract so capability and namespace discovery reach that owner. An adapter that changes mutation semantics must preserve those semantics in the transaction owner; exposing an inner engine is not a substitute for making its writes atomic. Custom independent backends without a compatible transaction owner must not accept local Cypher writes.

For example, a namespaced native engine supports atomic statements directly:

go
engine := storage.NewMemoryEngine()
defer engine.Close()
scoped := storage.NewNamespacedEngine(engine, "tenant")
executor := cypher.NewStorageExecutor(scoped)
_, err := executor.Execute(ctx, "CREATE (:Document {id: 'one'})", nil)

Resolved remote/Fabric statements retain their existing delegated coordinator. Nested procedure statements reuse their admitted statement transaction; this requirement does not add a second transaction around a delegated owner.

Embedded Go query readers (v1.4.4 migration) ​

The query reader APIs take the operation's context directly. Existing Go callers must add ctx to cypher.QueryPermissionRequirements(ctx, query), executor.ResultColumns(ctx, query, scope, cypher25), cypher.TransactionDatabaseError(ctx, databases, txDB, target, query) and analyzer.Analyze(ctx, query). This preserves request cancellation through the same owners used during execution; HTTP, Bolt and CLI protocol behavior is unchanged. See Embedded Go statement effects for the analysis result and effect-method migration. Permission requirements are an intermediate result: use AuthorizeQuery for an actual authorization decision rather than treating canceled classification as a grant.

RegisteredProceduresForCalls(ctx, query) replaces RegisteredProcedureForCall and returns all registered declarations from grammar-owned CALL clauses, including nested calls. Callers selecting one declaration must check the returned slice. Strings and comments do not add calls. No procedure handler is exposed.

NewStorageExecutor(store) retains environment-derived cache defaults. Replace NewStorageExecutorWithQueryCachePolicy(store, entries, ttl) with NewStorageExecutor(store, cypher.QueryCachePolicy{MaxEntries: entries, TTL: ttl}). Zero entries disables caching; non-positive TTL retains the configured/default lifetime. For example:

go
executor := cypher.NewStorageExecutor(store, cypher.QueryCachePolicy{
    MaxEntries: 100,
    TTL: time.Minute,
})
columns, err := executor.ResultColumns(ctx, "RETURN 1 AS value",
    resultmetadata.KnownScope(nil), false)

Embedded Go stored values (v1.4.4 migration) ​

Stored entity properties use their persisted representation when returned to Go callers, including immediately after a write. Integer properties fitting a signed 64-bit integer are int64; larger uint64 values retain their unsigned type. For example, replace node.Properties["age"].(int) with node.Properties["age"].(int64). Homogeneous property lists can be typed slices, such as []int64, rather than []any. Caller-owned input maps retain their values.

Hidden records still occupy their storage IDs. Recreating a stored node ID fails with storage.ErrAlreadyExists. Retrying the identical hidden relationship is a no-op that preserves its stored body; reusing its ID for another relationship is rejected. Deleting a node also removes its hidden relationships. An update to a node already deleted in the same transaction leaves it deleted.

The Badger cache helper now takes an optional type on the existing API: replace engine.InvalidateEdgeTypeCacheForType(typeName) with engine.InvalidateEdgeTypeCache(typeName). Calling engine.InvalidateEdgeTypeCache() still invalidates every type; an explicitly empty type remains a no-op. HTTP and Bolt contracts are unchanged.

Embedded Go role metadata (v1.4.4 migration) ​

auth.ReadRoleCatalog(roles, entitlements) is the role metadata snapshot owner. Replace roles.AllRoles() with auth.ReadRoleCatalog(roles, nil).RoleNames, and replace entitlements.All() with auth.ReadRoleCatalog(nil, entitlements).EntitlementOverrides. Supply both stores to obtain both views. Each supplied store is read under its own read lock; returned slices and maps are independent. Overrides contain stored IDs; continue using auth.PermissionsForRole for effective permissions. HTTP response shapes and permissions remain unchanged.

Common Questions ​

Embedded Go statement effects (v1.4.4 migration) ​

cypher.QueryAnalyzer.Analyze(ctx, statement) now returns (*QueryInfo, error). Handle its error before using the result. Replace info.IsWriteQuery with info.Writes() and info.IsReadOnly with info.ReadOnly(). These methods consume resolved grammar and registered-procedure effects, refreshed when the procedure registry changes; text-shape hints are not effect decisions. Runtime statement text remains conservative in these methods. Result-cache eligibility separately resolves its bound text and parameters through the canonical execution policy.

fabric.NewFabricPlanner(catalog, effects) requires a fabric.StatementEffectReader. Pass the canonical analyzer rather than a keyword classifier:

go
analyzer := cypher.NewQueryAnalyzer(1000)
planner := fabric.NewFabricPlanner(catalog, func(ctx context.Context, query string) (bool, error) {
    info, err := analyzer.Analyze(ctx, query)
    if err != nil {
        return false, err
    }
    return info.Writes(), nil
})

A missing effect reader fails planning. Fragment planning propagates reader and cancellation errors. storage.QueryAnalyzer.AnalyzeQuery(query, writes) now takes the caller's resolved writes flag; it extracts routing hints without separately classifying the statement. HTTP/Bolt syntax and stored formats are unchanged.

Analytics privacy