Skip to content
Kristian Mandrup edited this page Feb 29, 2016 · 19 revisions

The data model in both Datascript and Datomic is based around atomic facts called datoms. A datom is a 4-tuple consisting of:

  • Entity ID
  • Attribute
  • Value
  • Transaction ID

Setup

To use Datascript, first require the namespaces you need such as datascript.core and datascript.db etc. Then optionally define your database schema and populate it with intial datoms using d/datom as shown below.

(ns ds.core
  (:require [datascript.core :as d]
            [datascript.db :as db]))

;; define schema
(def schema { :aka { :db/cardinality :db.cardinality/many }})

;; populate db with initial datoms
(def datoms #{(d/datom 1 :age  17)
              (d/datom 1 :name "Ivan")})

Indexes

When you create the database, you can use :db/index to create indexes for attributes, such as for age in this example: { :age { :db/index true } }. Then when you add atoms such as [:db/add 1 :age 44] they will be indexed accordingly.

See index tests for more examples.

(deftest test-datom-index
  (let [db (-> (d/empty-db { :age  { :db/index true } })
               (d/db-with [ [:db/add 1 :name "Petr"]
                            [:db/add 1 :age 44]
                            [:db/add 2 :name "Ivan"]
                            [:db/add 2 :age 25]
                            [:db/add 3 :name "Sergey"]
                            [:db/add 3 :age 11] ]))]
  ))

Connect

d/create-conn can be used to create a connection to a DB (or schema). Examples taken from conn tests where you can find more usage examples.

(deftest test-conn
  (let [conn (d/create-conn)]

(deftest test-conn-schema
  (let [conn (d/create-conn {:aka { :db/cardinality :db.cardinality/many }})]

Entities

Entities are identified using db/id such as for the datom {:db/id 1, :name "Ivan"}. You can then get an entity by its identity, such as 1 using (d/entity db 1). In the example below we store the entity in the local var e and then test the name of the entity with (is (= (:name e) "Ivan"))

See entity tests for more examples.

(deftest test-entity
  (let [db (-> (d/empty-db)
               (d/db-with [{:db/id 1, :name "Ivan", :age 19}
                           {:db/id 2, :name "Katerina", :sex "female"}]))
        e  (d/entity db 1)]
    (is (= (:name e) "Ivan"))

Queries

For queries you can either use d/q or q/pull just like in Datomic.

Datalog queries in-depth: query and pull

d/q

;; query
(deftest test-joins
  (let [db (-> (d/empty-db)
               (d/db-with [ { :db/id 1, :name  "Ivan", :age   15 }
                            { :db/id 2, :name  "Petr", :age   37 }
                            { :db/id 3, :name  "Ivan", :age   37 }
                            { :db/id 4, :age 15 }]))]
    (is (= (d/q '[:find ?e
                  :where [?e :name]] db)
           #{[1] [2] [3]}))

d/pull

;; define schema
(def ^:private test-schema
  {:name   { :db/valueType :db.type/string }})

;; datoms for DB
(def test-datoms
  (->>
    [[1 :name  "Petr"]]))

;; initialize db with datoms and schema
(def ^:private test-db (d/init-db test-datoms test-schema))

(deftest test-pull-attr-spec
  (is (= {:name "Petr"}
         ;; make a pull query from test-db 
         (d/pull test-db '[:name] 1)))

Filter

d/filter can be used to filter a database, given a filter function such as remove-pass or remove-ivan as shown below.

(deftest test-filter-db
  (let [db (-> (d/empty-db {:aka { :db/cardinality :db.cardinality/many }})
               (d/db-with [{:db/id 1
                            :name  "Petr"
                            :email "[email protected]"
                            :aka   ["I" "Great"]
                            :password "<SECRET>"}

        remove-pass (fn [_ datom] (not= :password (:a datom)))
        remove-ivan (fn [_ datom] (not= 2 (:e datom)))

      (d/filter db remove-pass) #{}
      (d/filter db remove-ivan) #{["<SECRET>"] ["<UNKWOWN>"]}

Transactions

d/transact! is used to transact on a connection, such as adding new datoms via db/add

(deftest test-transact!
  (let [conn (d/create-conn {:aka { :db/cardinality :db.cardinality/many }})]
    (d/transact! conn [[:db/add 1 :name "Ivan"]])

More to follow...

Clone this wiki locally