102 lines
4.7 KiB
Org Mode
102 lines
4.7 KiB
Org Mode
#+TITLE: Datalog DSL Guide
|
|
|
|
* Intro to datalog
|
|
This is a short guide on writing common datalog queries to allow you to query databases like datascript, datalevin, datahike datomic & xtdb.
|
|
|
|
These examples are all aimed at datascript which is a browser client side database allowing interactivity int the examples.
|
|
|
|
You can find some further guides and information on the subject at these locations.
|
|
https://max-datom.com/
|
|
http://www.learndatalogtoday.org/
|
|
https://www.youtube.com/watch?v=oo-7mN9WXTw
|
|
|
|
Blog of the dev who makes datascript
|
|
https://tonsky.me/blog/the-web-after-tomorrow/
|
|
|
|
** Entities Attributes & values
|
|
|
|
Before getting started with data log it vital to understand data is stored as a list of values, the entity id which is a way to look up and group related attributes, attributes are the name of the thing you want to store so =:user/name= for example and the value to store under this name, the entity id will be generated when inserting data.
|
|
|
|
Sometimes the database may store other details like transaction time and revoked data dependant on the characteristics of the underlying database.
|
|
|
|
This is an example of how a EAV triplet would be represented.
|
|
#+BEGIN EXAMPLE
|
|
[1 | :user/name | "Daisy"]
|
|
#+END_EXAMPLE
|
|
|
|
This is an example of how a EAVT quadruplet would be represented, T in this instance is the Transaction ID if multiple values are inserted at once they would have the same transaction ID.
|
|
#+BEGIN EXAMPLE
|
|
[1 | :user/name | "Daisy" | 100]
|
|
#+END_EXAMPLE
|
|
|
|
** Creating a DATABASE
|
|
Datalog databases can be schema less but a lot of the power comes from creating a schema specifying uniqueness and relations on the stored fields.
|
|
|
|
You can create a new database using create-conn as below then empty hash map is simply a blank schema,
|
|
#+BEGIN_SRC clojurescript :results verbatim :tangle ./src/test.cljs
|
|
(def demo-conn (d/create-conn {}))
|
|
|
|
@demo-conn
|
|
#+END_SRC
|
|
|
|
|
|
Using the connection we can just start inserting data, using standard hash maps and lists structures, we always specify the attribute and the value when transacting.
|
|
#+BEGIN_SRC clojurescript :results verbatim :tangle ./src/test.cljs
|
|
(def demo-conn (d/create-conn {}))
|
|
|
|
(d/transact!
|
|
demo-conn
|
|
[{:user/name "Brooke" :user/img "me.jpg"}
|
|
{:user/name "Kalvin" :user/img "you.jpg"}])
|
|
|
|
@demo-conn
|
|
#+END_SRC
|
|
|
|
*** Creating a Schema
|
|
Not all datalog databases let you create a schema, but datascript does this allows us to add constraints and relations between the stored data.
|
|
|
|
In this example we are saying =:user/name= is unique and =:user/rooms= has a many to one relationship, when we later transact data it will use the constraints to stop things like duplicates from being created.
|
|
#+BEGIN_SRC clojurescript :results verbatim :tangle ./src/test.cljs
|
|
(def schema {:user/name {:db/unique :db.unique/identity}
|
|
:user/rooms {:db/cardinality :db.cardinality/many
|
|
:db/valueType :db.type/ref}})
|
|
(def demo-conn (d/create-conn schema))
|
|
#+END_SRC
|
|
|
|
|
|
** Transacting data
|
|
Transacting this data would mean Brooke would be inserted once but the image will be updated to =you.jpg=
|
|
#+BEGIN_SRC clojurescript :results verbatim :tangle ./src/test.cljc
|
|
(str (d/transact! demo-conn [{:user/name "Brooke" :user/img "you.jpg"}]))
|
|
#+END_SRC
|
|
|
|
** Querying the databases
|
|
There are three types of queries in datalog entity lookup's pulling a tree of data or querying with =d/q=.
|
|
|
|
*** Looking up an entity
|
|
=d/entity= is used to find the entity id, using any unique piece of data for example the user =Brooke= exists once so the entity db/id will be returned which can be used for further queries.
|
|
#+BEGIN_SRC clojurescript :results verbatim :tangle ./src/test.cljc
|
|
(d/entity @demo-conn [:user/name "Brooke"])
|
|
#+END_SRC
|
|
|
|
*** Pull a tree of data
|
|
Pull is used with entity id's once you know the entity you can specify what data you want to view ='[*]= being the most common looking up all keys, you can also specify the attributes your interested in looking up including there relations to make a more specific view.
|
|
#+BEGIN_SRC clojurescript :results verbatim :tangle ./src/test.cljc
|
|
(d/pull @demo-conn '[*] 1)
|
|
(d/pull @demo-conn '[:user/name :user/rooms] 1)
|
|
#+END_SRC
|
|
|
|
*** Querying your dataset
|
|
Querying in datalog is all about binding variables to your entities attributes and values which you can use in you conditions or to return in the result set.
|
|
|
|
In this example we return the user-id and user/name in the find clause which we looked up in the where clause by finding all attributes =:user/name= the binding the entity id and username to variables on each match to display in the find clause.
|
|
|
|
#+BEGIN_SRC clojurescript :results verbatim :tangle ./src/test.cljc
|
|
(d/q '[:find ?user-entity ?user-name :where
|
|
[?user-entity :user/name ?user-name]] @demo-conn)
|
|
#+END_SRC
|
|
|
|
|
|
|
|
Write some more as needed better examples in the src code.
|