The classical Create-Read-Update-Delete operations on data are a bit different using Datomic since it never overwrites or deletes data. Facts are only asserted or retracted in Datomic.

Molecule tries to bridge the vocabulary between these two worlds.

Transactions return TxReport

All transactional operations on molecules return a TxReport with information about the transaction like what data was transacted and what entities were created and a timestamp of the transaction:

val tx: TxReport = Person.name("Fred").likes("pizza").age(38).save

// Entity id created - useful when we know one entity was created
val fredId: Long = tx.eid // (same as tx.eids.head)

// Entities id created
val entities: Seq[Long] = tx.eids

// Transaction time `t` (a sequential number created internally by Datomic identifying the tx)
val txT: Date = tx.t

// Transaction time as `Date`
val txTime: Date = tx.inst

// Transaction entity id
val txEntityId: Long = tx.tx

// Transaction Entity
val txEntity: datomicEntity = tx.txE

Async API

All getters and operators below have an asynchronous equivalent. Synchronous getters/operators shown for brevity.


In Molecule you can either save a populated molecule or insert multiple tuples of data that match an “insert-moleceule”


3 facts asserted for a new entity:

Person.name("Fred").likes("pizza").age(38).save // or saveAsync

More on save


3 facts asserted for each of 3 new entities:

Person.name.age.likes insert List( // or insertAsync
  ("Fred", 38, "pizza"),
  ("Lisa", 7, "sushi"),
  ("Ben", 5, "pizza")

More on insert

Read / get

To read data from the database we call get on a molecule


Person.name.age.likes.get === List( // or getAsync
  ("Fred", 38, "pizza"),
  ("Lisa", 7, "sushi"),
  ("Ben", 5, "pizza")

More on get

Time getters

Since data is only appended in Datomic we can also go back in time to look at our data!

<molecule>.getAsOf(t)      // or getAsynAsOf(t)
<molecule>.getSince(t)     // or getAsyncSince(t)
<molecule>.getWith(txData) // or getAsyncWith(txData)
<molecule>.getHistory      // or getAsyncHistory

These are such cool features that we have a whole section about time

“Update” (retract + assert)

In Datomic an update retracts the old fact and asserts the new fact.

For convenience, Molecule lets you think in terms of a classical “update” although two operations are performed in the background. The old fact is still in the database and available with the time getters.


Person(fredId).likes("pasta").update // Retracts "pizza" and Asserts "pasta"

// Current value is now "pasta"
Person(fredId).likes.get.head === "pasta"

More on update

Retract (“delete”)

As mentioned, data is not deleted in Datomic. So it would be outright wrong to say that we “delete” data. Therefore, Molecule uses the Datomic terminology of “retracting” data which is like saying “this is no longer valid”. Retracted data is no longer showing up when we query with get but it will be visible with the time getters.

To retract individual attribute values of an entity we apply an empty value and update:

// Retract what Fred likes by applying an empty value

// Fred now doesn't have any preference (but his old preference is still in history)
Person(fred).name.likes$.get.head === ("Fred", None)

retract entity

We can retract an entity (a group of facts with a common entity id) by calling retract on a Long entity id:


// Fred is retracted from current view (but still in history)
Person(fredId).name.likes.get === Nil

More on retract


Create / Save…