Why Datomic rocks, in code snippets (2017)
1. Datomic has a reference type
This is what makes Datomic simple and easy. First-class reference type means you can walk to anything you need. Datomic is naturally graph-shaped, graphs are meant to be walked.
The entity API
d/entityis supposed to evoke feelings of programming directly with Clojure values like sets and maps. This property of Datomic is called database as a value.
RDBMS resultsets are table-shaped, so you can't naturally walk them. First you need to deal with the foreign key joins, cartesian products, sparse resultsets, many-to-many join tables. Its your job to translate cartesian soup into Clojure sets and maps. The popular Clojure SQL libraries don't even seem to help you with this: HugSQL, HoneySQL. Where are the sets and the maps? How do I walk them? It turns out that mapping tables to sets and maps is part of an abstraction-resistant class of problems.
Also, RDBMS requires you to fetch up front the data you might need, so you feel pressure to batch into a small number of monster queries, adding boilerplate and incidental complexity.
2. You can mix your application code and your database code
The following Datomic Peer query calls into Clojure functions from inside a database query.
This is fast and idiomatic. Here is a more advanced example.
To do that in RDBMS you'd need to do a lot of service/database round trips over network (or stored procedures). This property of Datomic is called code/data locality and it makes possible to do functional programming – to code with pure functions and
reduce– inside your database programs.
The fact that this works gives a major hint as to how Datomic works. My
user/matchesfunction was defined at a REPL, it is only available right here inside my process, which means the Datomic query engine is also running in my process. The datalog query engine is known as the Datomic Peer library, it really is just a function, a jar file running in your REPL. 🤯
3. Schema can be queried
4. No need to batch queries, so you can spread them over many functions
We can use functions to build little query abstractions:
Splitting queries into functions works because these queries can be done independently, it is not idiomatic to batch them all into one monster query. These functions are silly, but they make the below more readable:
5. Walk the database as if it were a local data structure
You can use complex functions inside your queries, like Loom, a general purpose graph library for Clojure that doesn't know anything of Datomic, it predates Datomic by two years.
To do this in RDBMS you'd need a crazy complicated stored procedure. The Datomic solution is general purpose and beautiful and abstract.
*The above uses the Entity API which is only available for Datomic Peer, but Stu says support for instrumenting the classpath of Cloud nodes with application jars is a development priority. As of this writing, Datomic Cloud is three months old.
6. Datomic can query N databases at the same time, in the same query
Hyperfiddle uses color to distinguish data from two databases.
This query is efficient! It works because Datomic databases are logs and logs can be interleaved. Nobody is really talking about it yet but this one is the real game changer:
Datomic solves data silos.