DataFn
@datafn/server

Execution Engine

Query and mutation execution internals.

DataStore Interface

The execution engine operates through a DataStore abstraction. Two implementations are provided:

DbDataStore

Wraps a database adapter (@superfunctions/db Adapter) for persistent storage. All operations pass through the adapter's query builder.

MemoryStore

In-memory implementation using Map<string, Map<string, Record>>. Used for testing and local-only mode.

Query Execution

Planning and Classification

Queries are classified by type to optimize execution:

ClassificationConditionStrategy
Find by IDfilter.id.$eq presentDirect record lookup.
PushdownDatabase adapter availableTranslate DFQL to SQL and execute at the database level.
Memory scanNo adapter or pushdown not possibleLoad all records, apply filters in-memory.

Pushdown Query Execution

When a database adapter is available, the query engine pushes as much work as possible to the database:

  • Filters -- translated to SQL WHERE clauses.
  • Sort -- translated to SQL ORDER BY.
  • Limit/Cursor -- translated to SQL LIMIT/OFFSET or keyset pagination.
  • Aggregations -- translated to SQL aggregate functions (COUNT, SUM, AVG, MIN, MAX).

Fields and operators not supported by pushdown fall back to in-memory evaluation after the database query returns.

Mutation Execution

Flow

  1. Guard evaluation -- check field-level constraints (required, readonly, enum, min/max, pattern, unique).
  2. Relation handling -- for mutations with relation payloads, normalize and execute join table operations.
  3. Store operation -- execute the create/update/delete against the data store.
  4. Change tracking -- record the mutation in the __datafn_changes internal table with a monotonic sequence number.

Capability-enabled operations (trash, restore, archive, unarchive, share, unshare) flow through the same execution path with additional capability checks and field injection/stripping rules.

Guard Store

Validates field constraints at mutation time:

  • Required -- non-null check on insert.
  • Readonly -- reject updates to readonly fields.
  • Unique -- check for existing records with the same value (scoped to namespace).
  • Enum -- value must be in the allowed set.
  • Min/Max -- numeric range validation.
  • MinLength/MaxLength -- string length validation.
  • Pattern -- regex validation.

Change Tracking

The ChangeTrackingService records every mutation as a change entry:

{
  serverSeq: number;    // Monotonic sequence
  resource: string;
  action: "insert" | "merge" | "replace" | "delete";
  recordId: string;
  data: Record<string, unknown>;
  timestamp: number;
  namespace: string;
}

Changes are stored in the __datafn_changes internal table and queried by the pull handler.

Sequence Store

Generates monotonic sequence numbers for change tracking. Multiple backends:

ImplementationBackendDescription
RedisSequenceStoreRedisAtomic INCR on a Redis key. Highest throughput.
KVSequenceStoreKV Storeincr() on a KV key.
DatabaseSequenceStoreDatabaseRow-level locking with SELECT ... FOR UPDATE.
Combined sequence chainPrimary + database chainCoordinates primary sequence allocation with database continuity.

The createSequenceStore factory selects the implementation based on dbMapping.serverseq:

const store = createSequenceStore({
  db,
  redis,
  kvStore,
  dbMapping: { serverseq: "redis" },
});

Internal Tables

The execution engine manages two internal tables:

TablePurpose
__datafn_changesChange tracking entries for sync pull.
__datafn_idempotencyIdempotency records for mutation deduplication.

These tables are automatically created by the database adapter and are transparent to application code.