synopsys
Version:
Synopsys is proof of concept datastore service. It stores facts in terms of entity attribute value triples and allows clients to subscribe to _(datomic inspired)_ queries pushing updates to them when new transactions affect results.
133 lines (108 loc) • 4.29 kB
Markdown
# Synopsys
Synopsys is proof of concept datastore service. It stores facts in terms of entity attribute value triples and allows clients to subscribe to _(datomic inspired)_ queries pushing updates to them when new transactions affect results.

## Usage
### Start
You can start a storage service by running following command in your terminal
```
npm start
```
ℹ️ You can optionally configure port service is going to listen to and path where the data will be persisted via `PORT` and `STORE` environment variables.
```
PORT=8080 STORE=/tmp/synopsys npm start
```
### Transact
You can submit transaction to the store via HTTP PATCH request in [DAG-JSON] format.
```js
const demoTransact = async (url = '///localhost:8080/') => {
const groceries = {"/":"bafyr4iceqxmgq2pgahy5dkztvrqj65ljzebwpg6ytv6nio3ilyq6rymcy4"}
const milk = {"/":"bafyr4ifmahtfsopilbtqutqsjjmbyfsid5nggvd7uozbceydeiwkpjs75y"}
const eggs = {"/":"bafyr4ibll3abnnvtuk6uiakfogixv46r72p2s5lvtbkuqzyd2vfhl5t25u"}
const bread = {"/":"bafyr4igxo65tssyr4y2wpkjxsphkmlxfnbhmesgusaboeagt5hiykq6xte"}
const chores = {"/":"bafyr4iathncq5urfqnwbrg2xxudqxanmtmjqobcd2tdps7ogrnoz6su3bu"}
const dishes = {"/":"bafyr4igg7h46r2koxaslitrd4uhkttfzgr55cm5kziajtrqvyvcqnu2mvq"}
const laundry = {"/":"bafyr4iaafoljbvwcx4ogb5rftzpampyf7vw6ffgnqmffbu562hpoei676e"}
const response = await fetch('///localhost:8080/', {
method: 'PATCH',
body: JSON.stringify([
{ Assert: [groceries, 'name', 'Groceries'] },
{ Assert: [groceries, 'todo', milk] },
{ Assert: [milk, 'title', 'Buy Milk'] },
{ Assert: [groceries, 'todo', eggs] },
{ Assert: [eggs, 'title', 'Buy Eggs'] },
{ Assert: [groceries, 'todo', bread] },
{ Assert: [bread, 'title', 'Buy Bread'] },
{ Assert: [bread, 'done', true] },
{ Assert: [chores, 'name', 'Chores'] },
{ Assert: [chores, 'todo', laundry] },
{ Assert: [laundry, 'title', 'Do Laundry'] },
{ Assert: [chores, 'todo', dishes] },
{ Assert: [dishes, 'title', 'Do Dishes'] },
])
})
return await response.json()
```
Running `demoTransact()` in your browser you should get commit info like the one below. It tells you what was the merkle root of the store before this transaction and what is it after.
```json
{
"ok": {
"before": { "id": "NcuV3vKyQgcxiZDMdE37fv" },
"after": { "id": "Kize9wmtPCCVp1xL9wPPwd" }
}
}
```
### Query
You can subscribe to a query and receive updates on transactions affecting it. To do that you can submit query via HTTP PUT request in [DAG-JSON] format. You will get a HTTP 303 redirect to the [`EventSource`] URL where updates will be delivered.
```js
const demoQuery = async function* (url = '///localhost:8080/') {
const request = await fetch('///localhost:8080', {
method: "PUT",
body: JSON.stringify({
select: {
id: "?list",
name: "?name",
todo: [{
"id": "?item",
"title": "?title",
"completed": "?done"
}]
},
where: [
{ Case: ["?list", "name", "?name"] },
{ Case: ["?list", "todo", "?item"] },
{ Case: ["?item", "title", "?title"] },
{
Or: [
{ Case: ["?item", "done", "?done"] },
{
And: [
{ Not: { Case: ["?item", "done", "?done"] } },
{ "Is": ["?done", false] }
]
}
]
}
]
})
})
const reader = request.body.getReader()
const utf8 = new TextDecoder()
while (true) {
const read = await reader.read()
if (read.done) {
break
} else {
const [id, event, data] =
utf8.decode(read.value).split('\n')
yield {
id: id.slice('id:'.length),
event: event.slice('event:'.length),
data: JSON.parse(data.slice('data:'.length))
}
}
}
}
```
ℹ️ You could also use [`EventSource`] API instead of following HTTP redirect. In that case you could pass `redirect: "manual"` to `fetch` request and then derive subscription URL locally from your query via `DB.Link.of(query)` function.
[DAG-JSON]:https://ipld.io/specs/codecs/dag-json/spec/
[`EventSource`]:https://developer.mozilla.org/en-US/docs/Web/API/EventSource