bend-kit-commands Releases (5): 0.4.0.0 0x44a014634a1ce42bf4fee9edf6084000 indexed https://jend.leeeet.dev/files.txt?path=bend-kit-commands@0.4.0.0 0.3.0.0 0x39ec4020f3aa445e09b8a0b891ecd097 unindexed https://jend.leeeet.dev/files.txt?path=bend-kit-commands@0.3.0.0 0.2.0.1 0xa1e169a6235d40fa5888b83468e4c857 unindexed https://jend.leeeet.dev/files.txt?path=bend-kit-commands@0.2.0.1 0.2.0.0 0x468826758535b2e25c0a91592fca5812 unindexed https://jend.leeeet.dev/files.txt?path=bend-kit-commands@0.2.0.0 0.1.0.0 0xe3a1ac19beda1ba63efb12ba6625121d unindexed https://jend.leeeet.dev/files.txt?path=bend-kit-commands@0.1.0.0 Definitions (59): Commands.Outcome (https://jend.leeeet.dev/definition.txt?path=bend-kit-commands@0.4.0.0/commands.bend&name=Outcome) type Outcome<-R: Type> is Type: Accepted{result: R} Refused{result: R} Commands.Record (https://jend.leeeet.dev/definition.txt?path=bend-kit-commands@0.4.0.0/commands.bend&name=Record) # What the store keeps for one command id: its payload, its outcome, and when it was recorded. type Record<-P: Type, -R: Type> is Type: Record{payload: P, outcome: Outcome, at: U32} Commands.Reply (https://jend.leeeet.dev/definition.txt?path=bend-kit-commands@0.4.0.0/commands.bend&name=Reply) type Reply<-R: Type> is Type: Fresh{outcome: Outcome} Replayed{outcome: Outcome} Conflict{} Commands.Decision (https://jend.leeeet.dev/definition.txt?path=bend-kit-commands@0.4.0.0/commands.bend&name=Decision) # The domain's answer to a new command. type Decision<-S: Type, -R: Type, -E: Type> is Type: Accept{state: S, result: R, effects: List} Refuse{result: R} Commands.Step (https://jend.leeeet.dev/definition.txt?path=bend-kit-commands@0.4.0.0/commands.bend&name=Step) # Write: commit the state, the record, and the effects together. Note: commit only the record. Keep: write nothing. type Step<-S: Type, -P: Type, -R: Type, -E: Type> is Type: Write{state: S, record: Record, reply: Reply, effects: List} Note{record: Record, reply: Reply} Keep{reply: Reply} Commands.accepted (https://jend.leeeet.dev/definition.txt?path=bend-kit-commands@0.4.0.0/commands.bend&name=accepted) def accepted(-S: Type, -P: Type, -R: Type, -E: Type, rr: R & R, s2: S, p: P, at: U32, es: List) -> Step: Commands.refused (https://jend.leeeet.dev/definition.txt?path=bend-kit-commands@0.4.0.0/commands.bend&name=refused) def refused(-S: Type, -P: Type, -R: Type, -E: Type, rr: R & R, p: P, at: U32) -> Step: Commands.decided (https://jend.leeeet.dev/definition.txt?path=bend-kit-commands@0.4.0.0/commands.bend&name=decided) def decided(~S: Type, ~P: Type, ~R: Type, ~E: Type, ~dup_r: R -> R & R, d: Decision, p: P, at: U32) -> Step: Commands.fresh (https://jend.leeeet.dev/definition.txt?path=bend-kit-commands@0.4.0.0/commands.bend&name=fresh) def fresh( ~S: Type, ~P: Type, ~R: Type, ~E: Type, ~dup_r: R -> R & R, ~decide: S -> P -> Decision, pp: P & P, s: S, at: U32 ) -> Step: Commands.replayed (https://jend.leeeet.dev/definition.txt?path=bend-kit-commands@0.4.0.0/commands.bend&name=replayed) def replayed(-R: Type, same: Bool, o: Outcome) -> Reply: Commands.step (https://jend.leeeet.dev/definition.txt?path=bend-kit-commands@0.4.0.0/commands.bend&name=step) # One command, given the record that the store holds for its id and the domain state s. # dup_p and dup_r copy a payload and a result: a new command's payload goes to decide and to the record. def step( ~S: Type, ~P: Type, ~R: Type, ~E: Type, ~eq: P -> P -> Bool, ~dup_p: P -> P & P, ~dup_r: R -> R & R, ~decide: S -> P -> Decision, found: Maybe>, s: S, p: P, at: U32 ) -> Step: Commands.Run (https://jend.leeeet.dev/definition.txt?path=bend-kit-commands@0.4.0.0/commands.bend&name=Run) def Run(-A: Type) -> Type: Commands.Run.pure (https://jend.leeeet.dev/definition.txt?path=bend-kit-commands@0.4.0.0/commands.bend&name=Run.pure) def Run.pure(-A: Type, x: A) -> Run(A): Commands.Run.fail (https://jend.leeeet.dev/definition.txt?path=bend-kit-commands@0.4.0.0/commands.bend&name=Run.fail) def Run.fail(-A: Type, e: U32 & String) -> Run(A): Commands.Run.next (https://jend.leeeet.dev/definition.txt?path=bend-kit-commands@0.4.0.0/commands.bend&name=Run.next) def Run.next(-A: Type, -B: Type, r: Result<&1, &1, U32 & String, A>, f: A -> Run(B)) -> Run(B): Commands.Run.bind (https://jend.leeeet.dev/definition.txt?path=bend-kit-commands@0.4.0.0/commands.bend&name=Run.bind) def Run.bind(-A: Type, -B: Type, m: Run(A), f: A -> Run(B)) -> Run(B): Commands.first (https://jend.leeeet.dev/definition.txt?path=bend-kit-commands@0.4.0.0/commands.bend&name=first) # r's value, unless r or then z failed. def first(-A: Type, r: Result<&1, &1, U32 & String, A>, z: Result<&1, &1, U32 & String, Unit>) -> Result<&1, &1, U32 & String, A>: Commands.unit (https://jend.leeeet.dev/definition.txt?path=bend-kit-commands@0.4.0.0/commands.bend&name=unit) def unit(-A: Type, r: Result<&1, &1, U32 & String, A>) -> Result<&1, &1, U32 & String, Unit>: Commands.exec (https://jend.leeeet.dev/definition.txt?path=bend-kit-commands@0.4.0.0/commands.bend&name=exec) # Steps a statement and ignores any row, then resets it, also after a failed step. def exec(+stmt: U32) -> Run(Unit): Commands.once.run (https://jend.leeeet.dev/definition.txt?path=bend-kit-commands@0.4.0.0/commands.bend&name=once.run) def once.run(-A: Type, +s: U32, body: U32 -> Run(A)) -> Run(A): Commands.once (https://jend.leeeet.dev/definition.txt?path=bend-kit-commands@0.4.0.0/commands.bend&name=once) # Prepares one statement, runs body on it, and finalizes it, also after body fails. def once(-A: Type, +db: U32, text: String, body: U32 -> Run(A)) -> Run(A): Commands.sql (https://jend.leeeet.dev/definition.txt?path=bend-kit-commands@0.4.0.0/commands.bend&name=sql) def sql(+db: U32, text: String) -> Run(Unit): Commands.blob.of (https://jend.leeeet.dev/definition.txt?path=bend-kit-commands@0.4.0.0/commands.bend&name=blob.of) def blob.of(lw: U32 & Array) -> Bytes.Bytes: Commands.column (https://jend.leeeet.dev/definition.txt?path=bend-kit-commands@0.4.0.0/commands.bend&name=column) def column(+s: U32, i: U32) -> Run(Bytes.Bytes): Commands.bind (https://jend.leeeet.dev/definition.txt?path=bend-kit-commands@0.4.0.0/commands.bend&name=bind) def bind(+s: U32, i: U32, b: Bytes.Bytes) -> Run(Unit): Commands.same.of (https://jend.leeeet.dev/definition.txt?path=bend-kit-commands@0.4.0.0/commands.bend&name=same.of) def same.of(r: Bytes.Bytes & Bytes.Bytes & Bool) -> Bool: Commands.same (https://jend.leeeet.dev/definition.txt?path=bend-kit-commands@0.4.0.0/commands.bend&name=same) # The payload comparison that handle gives step: every byte, NUL included. def same(a: Bytes.Bytes, b: Bytes.Bytes) -> Bool: Commands.Row (https://jend.leeeet.dev/definition.txt?path=bend-kit-commands@0.4.0.0/commands.bend&name=Row) # A row of the store's key-value table. Read: Some is the value, None means no row. Written: Some puts the value, None deletes the row. type Row is Type: Row{key: Bytes.Bytes, value: Maybe} Commands.Store (https://jend.leeeet.dev/definition.txt?path=bend-kit-commands@0.4.0.0/commands.bend&name=Store) # A database and its prepared statements. One Store serves one task at a time. type Store is Data: Store{db: U32, begin: U32, commit: U32, rollback: U32, find: U32, read: U32, save: U32, del: U32, keep: U32, emit: U32} Commands.open (https://jend.leeeet.dev/definition.txt?path=bend-kit-commands@0.4.0.0/commands.bend&name=open) # Opens or creates the tables at path. # wait is how many ms a write waits for another connection's transaction before it fails with SQLITE_BUSY (5). def open(path: String, wait: U32) -> Run(Store): Commands.close (https://jend.leeeet.dev/definition.txt?path=bend-kit-commands@0.4.0.0/commands.bend&name=close) def close(st: Store) -> Run(Unit): Commands.outcome (https://jend.leeeet.dev/definition.txt?path=bend-kit-commands@0.4.0.0/commands.bend&name=outcome) def outcome(accepted: Bool, r: Bytes.Bytes) -> Outcome: Commands.seen.row (https://jend.leeeet.dev/definition.txt?path=bend-kit-commands@0.4.0.0/commands.bend&name=seen.row) def seen.row(row: Bool, +find: U32) -> Run(Maybe>): Commands.seen.get (https://jend.leeeet.dev/definition.txt?path=bend-kit-commands@0.4.0.0/commands.bend&name=seen.get) # The record for id, if the store holds one. def seen.get(+find: U32, id: String) -> Run(Maybe>): Commands.row.of (https://jend.leeeet.dev/definition.txt?path=bend-kit-commands@0.4.0.0/commands.bend&name=row.of) def row.of(row: Bool, +read: U32) -> Run(Maybe): Commands.row.get (https://jend.leeeet.dev/definition.txt?path=bend-kit-commands@0.4.0.0/commands.bend&name=row.get) # The value at key k, if a row holds it. def row.get(+read: U32, k: Bytes.Bytes) -> Run(Maybe): Commands.row.at (https://jend.leeeet.dev/definition.txt?path=bend-kit-commands@0.4.0.0/commands.bend&name=row.at) def row.at(+read: U32, kk: Bytes.Bytes & Bytes.Bytes) -> Run(Row): Commands.rows.get (https://jend.leeeet.dev/definition.txt?path=bend-kit-commands@0.4.0.0/commands.bend&name=rows.get) # One row for each key, in order. def rows.get(ks: List, +read: U32) -> Run(List): Commands.seen.put.row (https://jend.leeeet.dev/definition.txt?path=bend-kit-commands@0.4.0.0/commands.bend&name=seen.put.row) def seen.put.row(+keep: U32, id: String, p: Bytes.Bytes, kind: U32, r: Bytes.Bytes, at: U32) -> Run(Unit): Commands.seen.put.of (https://jend.leeeet.dev/definition.txt?path=bend-kit-commands@0.4.0.0/commands.bend&name=seen.put.of) def seen.put.of(o: Outcome, +keep: U32, id: String, p: Bytes.Bytes, at: U32) -> Run(Unit): Commands.seen.put (https://jend.leeeet.dev/definition.txt?path=bend-kit-commands@0.4.0.0/commands.bend&name=seen.put) def seen.put(rec: Record, +keep: U32, id: String) -> Run(Unit): Commands.outbox.put (https://jend.leeeet.dev/definition.txt?path=bend-kit-commands@0.4.0.0/commands.bend&name=outbox.put) def outbox.put(es: List, +emit: U32, +id: String) -> Run(Unit): Commands.row.put (https://jend.leeeet.dev/definition.txt?path=bend-kit-commands@0.4.0.0/commands.bend&name=row.put) def row.put(v: Maybe, +save: U32, +del: U32, k: Bytes.Bytes) -> Run(Unit): Commands.rows.put (https://jend.leeeet.dev/definition.txt?path=bend-kit-commands@0.4.0.0/commands.bend&name=rows.put) # Writes the rows in order, so a later row for a key wins. def rows.put(rs: List, +save: U32, +del: U32) -> Run(Unit): Commands.written (https://jend.leeeet.dev/definition.txt?path=bend-kit-commands@0.4.0.0/commands.bend&name=written) # Applies a step inside the open transaction, then commits it. def written( w: Step, Bytes.Bytes, Bytes.Bytes, Bytes.Bytes>, +commit: U32, +save: U32, +del: U32, +keep: U32, +emit: U32, +id: String ) -> Run(Reply): Commands.handle.new (https://jend.leeeet.dev/definition.txt?path=bend-kit-commands@0.4.0.0/commands.bend&name=handle.new) def handle.new( ~keys: Bytes.Bytes -> List, ~decide: List -> Bytes.Bytes -> Decision, Bytes.Bytes, Bytes.Bytes>, pp: Bytes.Bytes & Bytes.Bytes, +read: U32, at: U32, +commit: U32, +save: U32, +del: U32, +keep: U32, +emit: U32, +id: String ) -> Run(Reply): Commands.handle.found (https://jend.leeeet.dev/definition.txt?path=bend-kit-commands@0.4.0.0/commands.bend&name=handle.found) # A duplicate reads no rows: step ignores them when found is Some. def handle.found( ~keys: Bytes.Bytes -> List, ~decide: List -> Bytes.Bytes -> Decision, Bytes.Bytes, Bytes.Bytes>, found: Maybe>, +read: U32, payload: Bytes.Bytes, at: U32, +commit: U32, +save: U32, +del: U32, +keep: U32, +emit: U32, +id: String ) -> Run(Reply): Commands.handle.txn (https://jend.leeeet.dev/definition.txt?path=bend-kit-commands@0.4.0.0/commands.bend&name=handle.txn) def handle.txn( ~keys: Bytes.Bytes -> List, ~decide: List -> Bytes.Bytes -> Decision, Bytes.Bytes, Bytes.Bytes>, st: Store, +id: String, payload: Bytes.Bytes, at: U32 ) -> Run(Reply): Commands.handle.end (https://jend.leeeet.dev/definition.txt?path=bend-kit-commands@0.4.0.0/commands.bend&name=handle.end) # On failure, resets the read statements and rolls back. Rollback errors are ignored: the transaction may not have started. def handle.end(r: Result<&1, &1, U32 & String, Reply>, st: Store) -> Run(Reply): Commands.handle (https://jend.leeeet.dev/definition.txt?path=bend-kit-commands@0.4.0.0/commands.bend&name=handle) # Runs one command in one transaction: find its record, read the rows that keys names, decide, and commit rows, record, and effects. # at is the record's time for prune, in seconds. decide sees the committed rows, one for each key in order, and the payload. def handle( ~keys: Bytes.Bytes -> List, ~decide: List -> Bytes.Bytes -> Decision, Bytes.Bytes, Bytes.Bytes>, +st: Store, id: String, payload: Bytes.Bytes, at: U32 ) -> Run(Reply): Commands.get (https://jend.leeeet.dev/definition.txt?path=bend-kit-commands@0.4.0.0/commands.bend&name=get) # The committed value at key k. def get(st: Store, k: Bytes.Bytes) -> Run(Maybe): Commands.prune.run (https://jend.leeeet.dev/definition.txt?path=bend-kit-commands@0.4.0.0/commands.bend&name=prune.run) def prune.run(+s: U32, before: U32) -> Run(Unit): Commands.prune (https://jend.leeeet.dev/definition.txt?path=bend-kit-commands@0.4.0.0/commands.bend&name=prune) # Forgets every record made before the time before. A later retry of a forgotten id runs as a new command. def prune(st: Store, before: U32) -> Run(Unit): Commands.Pending (https://jend.leeeet.dev/definition.txt?path=bend-kit-commands@0.4.0.0/commands.bend&name=Pending) # An undelivered effect: its sequence number, its command id, and the effect. type Pending is Type: Pending{seq: U32, id: String, effect: Bytes.Bytes} Commands.outbox.row (https://jend.leeeet.dev/definition.txt?path=bend-kit-commands@0.4.0.0/commands.bend&name=outbox.row) def outbox.row(row: Bool, +s: U32) -> Run(Maybe): Commands.outbox.first (https://jend.leeeet.dev/definition.txt?path=bend-kit-commands@0.4.0.0/commands.bend&name=outbox.first) def outbox.first(+s: U32) -> Run(Maybe): Commands.outbox.next (https://jend.leeeet.dev/definition.txt?path=bend-kit-commands@0.4.0.0/commands.bend&name=outbox.next) # The oldest undelivered effect. def outbox.next(st: Store) -> Run(Maybe): Commands.outbox.ack.run (https://jend.leeeet.dev/definition.txt?path=bend-kit-commands@0.4.0.0/commands.bend&name=outbox.ack.run) def outbox.ack.run(+s: U32, seq: U32) -> Run(Unit): Commands.outbox.ack (https://jend.leeeet.dev/definition.txt?path=bend-kit-commands@0.4.0.0/commands.bend&name=outbox.ack) # Removes a delivered effect. Deliver before ack: a crash between them delivers the effect again. def outbox.ack(st: Store, seq: U32) -> Run(Unit):