Skip to content

Your First Stream

Let’s create your first event stream.

Serve

Unlike sqlite, which operates directly on the file system, xs requires a running process to manage access to the local store. This enables features like subscribing to real-time updates from the event stream.

Start an xs store in a dedicated window:

Terminal window
xs serve ./store
13:35:16.868 TRACE event src/main.rs:185 Starting server with path: "./store xs:185
13:35:16.957 INFO read options=ReadOptions { follow: On, tail: false, last_id: None, limit: None } xs::store:174
13:35:16.957 INFO read options=ReadOptions { follow: On, tail: true, last_id: None, limit: None } xs::store:174
13:35:16.963 INFO 5ms insert_frame frame=Frame { id: "03d4por2p16i05i81fjy0fx8u", topic: "xs.start", hash: None, meta: None, ttl: None } xs::store:410
13:35:16.963 0fx8u xs.start
13:35:16.968 INFO read options=ReadOptions { follow: On, tail: false, last_id: None, limit: None } xs::store:174

Client

append command

OK! Let’s append our first event:

Terminal window
"a quick note" | .append notes
───────┬─────────────────────────────────────────────────────
topic │ notes
id │ 03d4q1qhbiv09ovtuhokw5yxv
hash │ sha256-wIcRiyKpOjA1Z8O+wZvoiMXYgGEzPQOhlA8AOptOhBY=
meta │
ttl │ forever
───────┴─────────────────────────────────────────────────────

cat and cas commands

and then cat the stream:

Terminal window
.cat
─#─┬──topic───┬────────────id─────────────┬────────────────────────hash─────────────────────────┬─meta─┬───ttl───
0 │ xs.start │ 03d4q1o70y6ek0ig8hwy9q00n │ │ │
1 │ notes │ 03d4q1qhbiv09ovtuhokw5yxv │ sha256-wIcRiyKpOjA1Z8O+wZvoiMXYgGEzPQOhlA8AOptOhBY= │ │ forever
───┴──────────┴───────────────────────────┴─────────────────────────────────────────────────────┴──────┴─────────

These are the raw frames on the stream. The actually content is stored separately in the Content-Addressable Storage (CAS). You can read more about that here.

We have the full expressiveness of Nushell available to us—for example, we can get the content hash of the last frame on the stream using:

Terminal window
.cat | last | $in.hash
sha256-wIcRiyKpOjA1Z8O+wZvoiMXYgGEzPQOhlA8AOptOhBY=

and then use the .cas command to retrieve the content:

Terminal window
.cat | last | .cas $in.hash
a quick note

We can also retrieve the content for a frame by piping it in its entirety directly to .cas:

Terminal window
.cat | last | .cas
a quick note

head command

Let’s submit another note:

Terminal window
"submit TPS report" | .append notes
.cat
─#─┬──topic───┬────────────id─────────────┬────────────────────────hash─────────────────────────┬─meta─┬───ttl───
0 │ xs.start │ 03d4q1o70y6ek0ig8hwy9q00n │ │ │
1 │ notes │ 03d4q1qhbiv09ovtuhokw5yxv │ sha256-wIcRiyKpOjA1Z8O+wZvoiMXYgGEzPQOhlA8AOptOhBY= │ │ forever
2 │ notes │ 03d4qbrxizqgav09m7hicksb0 │ sha256-KDyb7pypM+8aLiq5obfpCqbMmb6LvvPnCu2+y9eWd0c= │ │ forever
───┴──────────┴───────────────────────────┴─────────────────────────────────────────────────────┴──────┴─────────

We can get the most recent note on the stream using the .head command:

Terminal window
.head notes
───────┬─────────────────────────────────────────────────────
topic │ notes
id │ 03d4qbrxizqgav09m7hicksb0
hash │ sha256-KDyb7pypM+8aLiq5obfpCqbMmb6LvvPnCu2+y9eWd0c=
meta │
ttl │ forever
───────┴─────────────────────────────────────────────────────
Terminal window
.head notes | .cas
submit TPS report

riffing

Finally, let’s pull a list of all our notes.

We can use where to filter the stream for only the notes topic, and then use the each command to pull out the content of each note:

Terminal window
.cat | where topic == "notes" | each {.cas}
───┬───────────────────
0 │ a quick note
1 │ submit TPS report
───┴───────────────────

Fun! 🎉