Mediator

Attention

This repository contains only empty, unusable prototypes, and is very much all vaporware!

Most of the files are from my base project skeleton.

This also means that the documentation talks mostly about desired behavior, where to aim and where to work towards, not about existing working code.

Mediator

One who negotiates between parties seeking mutual agreement.

An embedded, immutable, syncable relational database inspired by SQLite, PouchDB, Git, Datomic and Mentat.

Introduction

Mediator is a database for building local-first client-side applications that want to sync the data between application instances.

It represents data as immutable 5-tuple facts, each called a datom. Those facts live in a accumulate-only ever-growing DAG, similar to Git’s DAG.

CLI example usage:

$ mediator shell my-database-1.db

# Insert the schema and data of an attribute
mediator> .tx [{:db/ident               :person/name
                :db/type                :db.type/string
                :db/cardinality         :db.cardinality/one
                :db/conflict-resolution :db.conflict-resolution/none}]
mediator> .tx [{:person/name "euandreh"}]
mediator> .query {:find [?name]
                  :in [[?e :person/name ?name]]}
#{{:person/name "euandreh"}}

# Clone the database to another instance and sync changes
$ mediator clone my-database-1.db my-database-2.db
$ mediator shell my-database-2.db '.tx [{:person/name "Eu, Andreh"}]'
$ mediator sync my-database-1.db my-database-2.db
$ mediator shell my-database-1.db '.query {:find [?name]
                                           :in [[?e :person/name ?name]]}'
#{{:person/name "Eu, Andreh"}}

# Sync conflicting changes
$ mediator shell my-database-1.db '.tx [{:person/name "name on db instance 1"}]'
$ mediator shell my-database-2.db '.tx [{:person/name "name on db instance 2"}]'
$ mediator sync my-database-1.db my-database-2.db
$ mediator shell my-database-1.db '.query {:find [?name]
                                           :in [[?e :person/name ?name]]}'
#{{:person/name "name on db instance 1"}
  {:person/name "name on db instance 2"}}

Suitability

There are a few good reasons not to use Mediator:

centralized database

If your program has a small database locally but sends data to a big remote database, than Mediator isn’t a good solution.

Mediator works best with the full data history available, so it can provide temporal queries and conflict resolution.

PouchDB solves this better: you can store offline data locally and have a small database, and replicate many different instances to a single big CouchDB cluster.

The price you pay of not having a central database is that there won’t be any global view of the data, and conflict resolution becomes a major issue.

no history

If the data you’re storing has no historical value, than you would be better of with SQLite/IndexedDB: both are older, more stable, more reliable and allow you to save storage by updating data in place.

Much like how Git keeps the full revision history of files, Mediator keeps the full revision history of data it stores. Even though attributes may be marked with :db/no-history, Mediator’s goal is to store valuable data, which could benefits from the historical archive.

no offline support

Offline support is first class for Mediator. If you want to store data for a local cache, or to make your program offline-friendly, use SQLite/IndexedDB instead: both allow you to store temporary data locally so it can be sent upstream when connectivity is regained.

Mediator is meant to work fully offline, for how long your application is disconnected, giving you tools to work with the complexity that arises from that.

storage constraint

If you have constrained storage and can’t afford storing the history of your data, then probably Mediator isn’t a good solution either.

Storage usage is something to always be aware of and a big bottleneck, since a Mediator database only grows in size.

Otherwise if your program wants:

  • in-process data storage,

  • full offline support,

  • historical data,

  • syncing across instances,

  • conflict resolution tools,

than Mediator might be a good fit.

Todo

Add note on using Mediator on the server.