signup-store
The other end of the signup-intake chain. A via: pipeline input takes packets only from the pipelines in its from list, and a push input takes manual fixes. Both write one row per email to ./data/signups.db (an upsert on email), and a record_exists check confirms each row landed. from_pipeline is meta.upstream.pipeline: who handed the packet over.
bun pipo start examples/signup-store/signup-store.pipo
bun pipo push signup-store --input manual --data '{"email": "grace@example.com", "name": "Grace"}'
sqlite3 examples/signup-store/data/signups.db 'select * from signups'
data/ is git-ignored.
signup-store.pipo#
# Keeps one row per sign-up email in ./data/signups.db. It takes packets from signup-intake (`to: pipeline`) and
# from `pipo push` for manual fixes, and checks each row landed (docs/spec.md §3.3.1, §3.14).
# bun pipo start examples/signup-store/signup-store.pipo
# bun pipo push signup-store --input manual --data '{"email": "grace@example.com", "name": "Grace"}'
pipo: 1
name: signup-store
description: One row per sign-up, fed by signup-intake and by hand.
inputs:
intake:
via: pipeline
with: {from: [signup-intake]}
manual:
via: push
validate:
- exists(data.email)
output:
from: [intake, manual]
to: sqlite
with:
path: ./data/signups.db
table: signups
create: true
mode: upsert
key: email
columns:
email: "${data.email}"
name: "${data.name}"
via: "${default(data.via, meta.input)}"
from_pipeline: "${default(meta.upstream.pipeline, '')}"
delivered:
check: record_exists
with:
where: {email: "${data.email}"}
Source: examples/signup-store.