The reactive core: registry, invalidation, recomputation.
One engine wraps one backend connection. Writes go through exec! or transact!; the backend's preupdate hook materializes raw events into :pending on the writing thread (cheap swap!s only - the writer is never blocked); when the statement leaves the connection in autocommit mode a flush is scheduled off the writer. The flush resolves positional rows to column names (off-writer, as required
Scheduling is injectable; by default flushes go to a single background thread on the JVM and a microtask on JS, so watchers fire away from whichever thread wrote. Ordering within an engine is preserved: flushes drain until :pending is empty.
DDL (create/alter/drop through exec!) is not tracked by deps; it clears the column-name cache and re-derives every query's profile before the next recompute pass.
The registry maps id -> {:sql :params :deps :stmt :result :last}; :result is the deref-able, watchable atom returned by register!.
The reactive core: registry, invalidation, recomputation.
One engine wraps one backend connection. Writes go through exec!
or transact!; the backend's preupdate hook materializes raw events
into :pending on the writing thread (cheap swap!s only - the
writer is never blocked); when the statement leaves the connection
in autocommit mode a flush is scheduled off the writer. The flush
resolves positional rows to column names (off-writer, as required
- that needs a prepared statement), coalesces, matches against
registered deps, re-runs affected queries and resets only those
result atoms whose realized rows actually changed. sync! runs the
same flush synchronously for deterministic callers (tests).
Scheduling is injectable; by default flushes go to a single
background thread on the JVM and a microtask on JS, so watchers
fire away from whichever thread wrote. Ordering within an engine
is preserved: flushes drain until :pending is empty.
DDL (create/alter/drop through exec!) is not tracked by deps; it
clears the column-name cache and re-derives every query's profile
before the next recompute pass.
The registry maps id -> {:sql :params :deps :stmt :result :last};
:result is the deref-able, watchable atom returned by register!.(close! eng)Finalize every statement and close the backend, under the flush lock - finalizing under a concurrent flush's feet is a native use-after-free - and closed-marked first so already-scheduled flushes become no-ops. The engine is unusable afterwards.
Finalize every statement and close the backend, under the flush lock - finalizing under a concurrent flush's feet is a native use-after-free - and closed-marked first so already-scheduled flushes become no-ops. The engine is unusable afterwards.
(create b & {:keys [schedule]})Wire a backend into an engine: installs the event subscription and returns the engine (an atom). :schedule overrides flush dispatch (tests capture instead of run).
Wire a backend into an engine: installs the event subscription and returns the engine (an atom). :schedule overrides flush dispatch (tests capture instead of run).
(exec! eng sql)(exec! eng sql params)Run one statement through the backend and schedule a flush when it committed (autocommit). Exactly one statement.
Run one statement through the backend and schedule a flush when it committed (autocommit). Exactly one statement.
(flush! eng)Drain pending events: resolve names, coalesce, match, recompute affected queries, deliver changed results. Runs to completion (drains anything appended meanwhile). Throws when re-entered from a watcher - write via exec!, not by flushing recursively.
Drain pending events: resolve names, coalesce, match, recompute affected queries, deliver changed results. Runs to completion (drains anything appended meanwhile). Throws when re-entered from a watcher - write via exec!, not by flushing recursively.
(note-external-write! eng sql)For statement layers driving the same connection outside exec! (the next.jdbc adapter): after the statement completed, run the DDL/savepoint bookkeeping and schedule a flush when it left autocommit. Rollback statements need nothing here - the engine's rollback hook discards pending events.
For statement layers driving the same connection outside exec! (the next.jdbc adapter): after the statement completed, run the DDL/savepoint bookkeeping and schedule a flush when it left autocommit. Rollback statements need nothing here - the engine's rollback hook discards pending events.
(register! eng sql params)Compile and run a query once; returns its result atom (deref for rows, watch for changes, pass to unregister! when done). Deps are derived at registration via sqldeps over the backend's EQP tables and column schema - bare references in multi-table scopes bind to the table that uniquely declares them.
Compile and run a query once; returns its result atom (deref for rows, watch for changes, pass to unregister! when done). Deps are derived at registration via sqldeps over the backend's EQP tables and column schema - bare references in multi-table scopes bind to the table that uniquely declares them.
(sync! eng)Deterministic flush (see flush!). Takes the flush lock, so it waits out any in-flight scheduled flush rather than racing it.
Deterministic flush (see flush!). Takes the flush lock, so it waits out any in-flight scheduled flush rather than racing it.
(transact! eng stmts)Run statements as one transaction: [sql & params] vectors or bare sql strings. Flushes once after COMMIT; ROLLBACK on any failure (the rollback hook then discards pending events).
Run statements as one transaction: [sql & params] vectors or bare sql strings. Flushes once after COMMIT; ROLLBACK on any failure (the rollback hook then discards pending events).
(unregister! eng result)Retire a registered query's result atom: finalizes its statement. Atoms carry no metadata, so the entry is found by identity.
Retire a registered query's result atom: finalizes its statement. Atoms carry no metadata, so the entry is found by identity.
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |