MemoryStore
Store in process memory, the reference implementation of the storage contract. The store
make builds keeps what the contract leaves to storage: each commit’s entries as one batch per
log, the slice each idempotency key wrote, and the position an append expected. It runs over a
Binding: how to read committed state and the live transaction, how to open one, and the locks
that order a log’s writers. bind makes one connection’s binding over a Database of this
process, which several connections may share as hosts share one system, and layer gives a store
over a database of its own. A host whose memory storage keeps more than logs, such as records
committed beside them, provides Binding over that storage instead.
Since v0.2.0
Constructors
Section titled “Constructors”One connection’s binding over database, as one host’s connection to a shared system: this
connection’s transactions wait for each other, and another connection’s writer is contention.
A standalone append waits only for its log’s other writers, on any connection.
Signature
declare const bind: (database: Database) => Effect.Effect<Binding["Service"]>Since v0.2.0
Logs with nothing stored.
Signature
declare const empty: () => SpaceSince v0.2.0
The key of a keyed append’s slice in Space.appends: its log and idempotency key, unambiguous
whatever either contains.
Signature
declare const keyOf: (logId: string, key: string) => stringSince v0.2.0
The store over the caller’s Binding: appends inside a transaction or alone, reads of committed
batches or the transaction’s own, and waiting for appends. Store.make checks every input first.
Signature
declare const make: Effect.Effect< { readonly getAppend: ( logId: LogEntry.LogId, key: Store.IdempotencyKey ) => Effect.Effect<Option.Option<Store.AppendReceipt>, StoreError.StoreError> readonly transaction: <A, E, R>( program: Effect.Effect<A, E, R> ) => Effect.Effect<A, E | StoreError.StoreError | Store.CommitUncertain, Exclude<R, Store.Transaction>> readonly append: ( request: Store.AppendInput ) => Effect.Effect<ReadonlyArray<Store.Entry>, StoreError.StoreError | Store.CommitUncertain> readonly getEntry: ( logId: LogEntry.LogId, entryId: LogEntry.EntryId ) => Effect.Effect<Option.Option<Store.Entry>, StoreError.StoreError> readonly get: ( logId: LogEntry.LogId, commitId: Commit.CommitId ) => Effect.Effect<Option.Option<Store.Batch>, StoreError.StoreError> readonly head: (logId: LogEntry.LogId) => Effect.Effect<Option.Option<LogEntry.Position>, StoreError.StoreError> readonly read: ( logId: LogEntry.LogId, options: Store.ReadOptions ) => Effect.Effect<ReadonlyArray<Store.Batch>, StoreError.StoreError> readonly readEntries: ( logId: LogEntry.LogId, options: Store.EntriesOptions ) => Effect.Effect<ReadonlyArray<Store.Entry>, StoreError.StoreError> readonly waitForAppend: ( logId: LogEntry.LogId, after: Option.Option<LogEntry.Position> ) => Effect.Effect<void, StoreError.StoreError> }, never, Binding>Since v0.2.0
makeDatabase
Section titled “makeDatabase”A database with nothing stored and no connection.
Signature
declare const makeDatabase: Effect.Effect<Database, never, never>Since v0.2.0
Layers
Section titled “Layers”Provide Store.Store in process memory, over a database of its own with one connection. Nothing
survives the layer.
Example (Typed logs in memory)
import { Entry, Log, MemoryStore } from "@amends-dev/log"import { Effect, Layer, Schema } from "effect"
const program = Effect.gen(function* () { const logs = yield* Log.Log const steps = logs.open({ id: Entry.LogId.make("steps"), schema: Schema.String }) yield* steps.append("started") return yield* steps.read({ limit: 10 })})
program.pipe(Effect.provide(Log.layer.pipe(Layer.provide(MemoryStore.layer))))Signature
declare const layer: Layer.Layer<Store.Store, never, never>Since v0.2.0
Models
Section titled “Models”Append (interface)
Section titled “Append (interface)”The slice of a batch one keyed append wrote: its commit, and where in the batch its entries begin and how many there are. The store returns it as the append’s receipt.
Signature
export interface Append { readonly commitId: Commit.CommitId readonly firstIndex: number readonly entryCount: number}Since v0.2.0
Batch (interface)
Section titled “Batch (interface)”One commit’s entries in one log, at one position. Stored batches are never changed: a commit’s further appends to the log replace its batch with a longer one in the transaction’s snapshot.
Signature
export interface Batch { readonly position: LogEntry.Position readonly commitId: Commit.CommitId readonly entries: ReadonlyArray<Store.Entry>}Since v0.2.0
Database (interface)
Section titled “Database (interface)”Logs in this process’s memory that several connections share, as hosts share one system: the
committed state, which connection’s transaction is writing, the logs’ locks, and the signal
waiting readers take. makeDatabase makes an empty one, and bind connects to it.
Signature
export interface Database { /** Committed state, replaced as each transaction commits. */ committed: Space /** The connection whose transaction is writing, if any. */ writer: object | undefined /** Each log's writer lock, created on first use. */ readonly locks: Map<string, Semaphore.Semaphore> /** Completed, and replaced, whenever a commit appends. */ appended: Deferred.Deferred<void> /** Issue an identifier unique within this database, for commits and entries. */ readonly nextId: (prefix: string) => string}Since v0.2.0
Session (interface)
Section titled “Session (interface)”One open transaction as the store sees it: the commit it records, its snapshot of the logs, which its appends change and a commit makes committed, the logs it holds, what to run once it commits, and whether it is still open. A binding opens one for each transaction.
Signature
export interface Session { /** The commit it records; the snapshot's record of it counts the entries appended so far. */ readonly commit: Commit.Commit /** Its snapshot of the logs, which its appends change and a commit makes committed. */ readonly logs: Space /** Logs it holds against their other writers; the binding releases them when it ends. */ readonly held: Set<string> /** What `afterCommit` asked to run once it commits, in order. */ readonly afterCommit: Array<Effect.Effect<void>> /** Cleared when it ends, so a handle kept past it fails. */ active: boolean}Since v0.2.0
Space (interface)
Section titled “Space (interface)”The logs’ stored state. Stored values never change: writes replace values rather than edit them, so a copy of these maps is an isolated snapshot, which is how a transaction stages its writes.
Signature
export interface Space { /** Every commit to the logs by ID, with its entry count. */ readonly commits: Map<string, Commit.Commit> /** Each log's batches in position order. */ readonly batches: Map<string, ReadonlyArray<Batch>> /** Keyed append slices by log and key, as `keyOf` joins them. */ readonly appends: Map<string, Append>}Since v0.2.0
Services
Section titled “Services”Binding (class)
Section titled “Binding (class)”What the store runs over: how it reads committed state and the live transaction, how it opens
one, and the locks that order a log’s writers. bind makes one over a Database; a host whose
memory storage keeps more than logs provides one over that storage.
Signature
declare class BindingSince v0.2.0
Transforming
Section titled “Transforming”commit
Section titled “commit”Committed state once a transaction’s snapshot lands: the logs it held replace the committed ones, other logs keep what their own writers committed meanwhile, and keys and commits combine.
Signature
declare const commit: (current: Space, staged: Space, held: ReadonlySet<string>) => SpaceSince v0.2.0
An isolated snapshot: every map is copied, and the values they hold never change.
Signature
declare const copy: (space: Space) => SpaceSince v0.2.0