• Stars
    star
    130
  • Rank 277,575 (Top 6 %)
  • Language
    Clojure
  • License
    MIT License
  • Created almost 9 years ago
  • Updated almost 2 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Mocking and forking Datomic Peer connections in-memory.

datomock

Mocking and forking Datomic connections in-memory.

Clojars Project

Notes:

  • This library is not an in-memory re-implementation of Datomic - just a thin wrapper on top of the Datomic Peer Library. All the heavy lifting is done by Datomic's 'speculative writes' (a.k.a db.with(tx)) and Clojure's managed references (atoms)
  • Only for Peers, not Clients.

Project maturity: beta quality. Note that you will probably not need to use this library in production.

Usage

(require '[datomic.api :as d])
(require '[datomock.core :as dm])

(def my-conn (d/connect "datomic:mem://hello-world"))

;; ... create a mock connection from a Database value:
(def starting-point-db (d/db my-conn))
(def mocked-conn (dm/mock-conn starting-point-db))

;; which is essentially the same as: 
(def mocked-conn (dm/fork-conn my-conn))

;; dm/fork-conn is likely what you'll use most.

Rationale and semantics

Mocked connections use Datomic's speculative writes (db.with()) and Clojure's managed references to emulate a Datomic connection locally.

The main benefit is the ability to 'fork' Datomic connections. More precisely, if conn1 is forked from conn2:

  • at the time of forking, conn1 and conn2 hold the same database value;
  • subsequent writes to conn1 will leave conn2 unaffected
  • subsequent writes to conn2 will leave conn1 unaffected

Because Datomic database values are persistent data structures, forking is extremely cheap in both space and time.

Applications

  • Write expressive tests: write tests as a tree of scenarios exploring various alternatives. In particular, this makes it very easy to write system-level tests that run fast. Forget about setup and teardown phases: they are respectively replaced by forking and garbage-collection.
  • Cheap, safe debugging: instantly reproduce your production environment on your local machine. Save and re-use as many checkpoints of your state as you need as you debug. Dry-run data patches and migrations safely before committing them to production.
  • Explore new database schemas: in particular, you can experiment with changes to your database schema without committing to them.
  • Staging environments / QA / CI: want one staging environment (Peer) for each pull-request on your app? Just have each of them use an in-memory fork of a shared database (or even your production database).
  • Ephemeral demos: want to let people experiment with your app without accumulating their manual changes? Just have them work on a fork, and discard it afterwards.
  • Ephemeral dev environments: similarly, it's usually better to always work on the same data when developing, and have the manual changes you've made while experimented be discarded at the end of the session.

Useful links:

How it works

Essentially, by putting a Datomic Database value in a Clojure Managed Reference (currently an Atom, may evolve to use an Agent instead) and using db.with() to update the state of that reference.

That's it, you now know how to re-implement Datomock yourself!

Actually, there are a few additional complications to make this work smoothly:

  • Log: the reference needs to hold not only a Database Value, but also a Log Value (for some strange reason, in Datomic, Log Values are not part of Database values).
  • Futures-based API: to match the interface of Datomic Connections, the library needs to provide a Futures-based API, which requires some additional work on top of Clojure references.
  • txReportQueue: the library needs to provide an implementation of that as well.

Mocked connections vs datomic:mem

How is this different than using Datomic memory databases, as in (d/connect "datomic:mem://my-db") ?

Mocked connections differ from Datomic's memory connections in several ways:

  • you create a memory connection from scratch, whereas you create a mocked connection from a starting-point database value
  • a mocked connection is not accessible via a global URI

Compatibility notes

This library requires Datomic 0.9.4470 or higher, in order to provide an implementation of the most recent methods of datomic.Connection.

However, if you need to work with a lower version, forking this library and removing the implementation of the syncSchema(), syncExcise() and syncIndex() should work just fine.

This library works with Datomic 1.0.6527, but mock connections do not support transaction io-stats. A call like (d/transact mock-conn :io-context true) will not include an :io-stats key in the result. Query io-stats are supported insofar as return value shapes will be correct, but the underlying Datomic mem database doesn't provide any useful information in :io-stats :reads.

License

Copyright © 2016 Valentin Waeselynck and contributors.

Distributed under the MIT License.

More Repositories

1

scope-capture

Project your Clojure(Script) REPL into the same context as your code when it ran
Clojure
574
star
2

supdate

Clojure's update with superpowers.
Clojure
204
star
3

datofu

there's a :db/fn for that
Clojure
129
star
4

reagent-phonecat-tutorial

The official AngularJS 'Phonecat' tutorial ported to ClojureScript + React (Reagent).
Clojure
60
star
5

datalog-rules

Utilities for managing Datalog rulesets from Clojure
Clojure
48
star
6

reagent-phonecat

(MOVED) - The official AngularJS 'Phonecat' tutorial ported to a ClojureScript + Reagent stack.
Clojure
33
star
7

scope-capture-nrepl

nREPL middleware for scope-capture
Clojure
30
star
8

promise-dag

Chain promises declaratively using high-level graphs. Tiny, portable, dependency-free.
JavaScript
25
star
9

datascript-declarative-model-example

Clojure
22
star
10

mapdag

Map computations expressed as dependency graphs of named steps. Includes high-performance execution strategies for the JVM.
Clojure
8
star
11

reagent-pluggable-components-poc

Clojure
4
star
12

xml-pull

Pulling nested Clojure data structures from XML documents, declaratively and efficiently.
Clojure
4
star
13

m12

Environment for experimenting a 12-digits notation for music
Clojure
4
star
14

d2q-examples

Examples of using d2q in combination with various data storages / backends.
Clojure
3
star
15

Graph-Theory-Bondy-Murty-2008-study-notes

Study notes and some exercise hints / solutions for the classic "Graph Theory" textbook by Bondy and Murty.
3
star
16

val-on-programming

Source for the 'Val on Programming' blog
HTML
2
star
17

clj-inline-caching

Clojure
1
star
18

onodrim

enhanced Datomic entities
Clojure
1
star
19

ecolog10

On the use of logarithmic representations for planning GHG emissions reductions
Clojure
1
star
20

advent-of-code-2017

Clojure
1
star
21

vvvvalvalval.github.io

My blog on programming
HTML
1
star
22

software-notions-checklist

A checklist for programmers who don't know what they don't know.
JavaScript
1
star
23

reddit_bots

Clojure
1
star
24

breakform

DEPRECATED use scope-capture instead - Easier REPL-based debugging by saving and restoring snapshots of the local environment
Clojure
1
star
25

clojure-kata-compute-graph

A Clojure kata: implementing a library for expressing computations as a dependency graph.
Clojure
1
star