Datomic & Datalog Basics

Clojure Vienna Meetup 18.2.2020

Dieter Komendera @kommen

Setup

{:deps
 {org.clojure/clojure {:mvn/version "1.10.1"}
  org.clojure/core.async {:mvn/version "0.7.559"}
  com.datomic/datomic-free {:mvn/version "0.9.5697"}}}
deps.edn
Extensible Data Notation

Architecture: Deconstructed Database

EAV

[entity attrbibute value]
[112341235234 :meetup/name "Clojure Vienna"]
[112341235234 :meetup/location "Valutico office"]
[112341235234 :meetup/date #inst "2020-02-18T20:00:00.000Z"]
Extensible Data Notation

Connecting

(require
 '[datomic.api :as d])
(def db-uri "datomic:mem://cljvie")
(d/create-database db-uri)
(def conn (d/connect db-uri))
4.0s
Clojure
user/conn

Transacting

Transacting Schema

(def schema
  [{:db/ident :meetup/name
    :db/valueType :db.type/string
    :db/cardinality :db.cardinality/one}
   
   {:db/ident :meetup/location
    :db/valueType :db.type/string
    :db/cardinality :db.cardinality/one}
   
   {:db/ident :meetup/date
    :db/valueType :db.type/instant
    :db/cardinality :db.cardinality/one}])
@(d/transact conn schema)
 
1.6s
Clojure

Transacting "Data"

(def data-vector
  [[:db/add "cljvie" :meetup/name "Clojure Vienna"]
   [:db/add "cljvie" :meetup/location "Valutico office"]
   [:db/add "cljvie" :meetup/date #inst "2020-02-18T20:00:00.000Z"]])
(def data-map
  [{:meetup/name "Clojure Vienna"
    :meetup/location "Valutico office"
    :meetup/date #inst "2020-02-18T20:00:00.000Z"}])
(def r @(d/transact conn data-vector))
(into {} (:tempids r))
0.2s
Clojure
Map {"cljvie": 17592186045418}

Query

(def db1 (d/db conn))
(into [] (d/q '[:find ?e ?n :where [?e :meetup/name ?n]] db1))
0.2s
Clojure
Vector(1) [Vector(2)]
(def cljvie-id
  (d/q '[:find ?e . :where [?e :meetup/name "Clojure Vienna"]] db1))
cljvie-id
0.1s
Clojure
17592186045418

Entities

(def e (d/entity db1 cljvie-id))
0.1s
Clojure
user/e
(:meetup/location e)
0.0s
Clojure
"Valutico office"
(into {} e)
0.1s
Clojure
Map {:meetup/name: "Clojure Vienna", :meetup/location: "Valutico office", :meetup/date: #inst "2020-02-18T20:00:00.000Z"}

Pull Syntax

(d/pull db1 '[:db/id :meetup/date] cljvie-id)
0.1s
Clojure
Map {:db/id: 17592186045418, :meetup/date: #inst "2020-02-18T20:00:00.000Z"}

Retracting

(def retract-cljvie
  [[:db/retract cljvie-id :meetup/date #inst "2020-02-18T20:00:00.000Z"]])
(def db2 (:db-after @(d/transact conn retract-cljvie)))
0.1s
Clojure
user/db2
(d/pull db1 '[:db/id :meetup/date] cljvie-id)
0.1s
Clojure
Map {:db/id: 17592186045418, :meetup/date: #inst "2020-02-18T20:00:00.000Z"}
(d/pull db2 '[:db/id :meetup/date :meetup/name] cljvie-id)
0.1s
Clojure
Map {:db/id: 17592186045418, :meetup/name: "Clojure Vienna"}
@(d/transact
  conn
  [[:db/add cljvie-id :meetup/date #inst "2020-03-19T20:00:00.000Z"]])
1.1s
Clojure
(def db3
  (:db-after
   @(d/transact
     conn
     [[:db/add cljvie-id :meetup/date #inst "2020-04-21T20:00:00.000Z"]])))
0.0s
Clojure
user/db3

History

(def history-db (d/history db3))
(into [] (d/q '[:find ?date :in $ ?cljvie-id :where [?cljv-id :meetup/date ?date]] history-db cljvie-id))
0.1s
Clojure
Vector(3) [Vector(1), Vector(1), Vector(1)]
(d/pull db3 '[:db/id :meetup/date] cljvie-id)
0.0s
Clojure
Map {:db/id: 17592186045418, :meetup/date: #inst "2020-04-21T20:00:00.000Z"}

Refs

(def more-schema
  [{:db/ident :person/name
    :db/valueType :db.type/string
    :db/cardinality :db.cardinality/one}
   
   {:db/ident :meetup/attendee
    :db/valueType :db.type/ref
    :db/cardinality :db.cardinality/many}])
(def more-data
  [{:db/id "dieter1"
    :person/name "Dieter"}
   
   {:db/id "markus1"
    :person/name "Markus"}
   
   [:db/add cljvie-id :meetup/attendee "dieter1"]
   [:db/add cljvie-id :meetup/attendee "markus1"]])
   
@(d/transact conn more-schema)
@(d/transact conn more-data)
  
1.1s
Clojure

(into
 []
 (d/q '[:find ?n :where [?m :meetup/name "Clojure Vienna"]
                        [?m :meetup/attendee ?p]
                        [?p :person/name ?n]]
      (d/db conn)))
0.1s
Clojure
Vector(2) [Vector(1), Vector(1)]
Runtimes (1)