Today I am taking a break from the books, even though I just started Clojure for the Brave and True. The expectation is to get a basic understanding of Datalog by going through some chapters of https://learndatalogtoday.com in the hope that it will help me research our first Athens issue as a cohort.
Once that is done, I will use that knowledge to look into that issue. We're 3 looking into it at the moment, and I'd like us to move forward at the same time. Time difference and time available to look into it might be an issue but if we're diligent we will all get something out of it.
[:find ?e
:where
[?e :movie/year 1987]]
[:find ?e ?title
:where
[?e :movie/title ?title]]
[:find ?name
:where
[?e :person/name ?name]]
[:find ?title
:where
[?m :movie/year 1985]
[?m :movie/title ?title]]
[:find ?year
:where
[?m :movie/title "Alien"]
[?m :movie/year ?year]]
Exercise 2: Who directed RoboCop? You will need to use [ :movie/director ] to find the director for a movie.
[:find ?name
:where
[?m :movie/title "RoboCop"]
[?m :movie/director ?n]
[?n :person/name ?name]]
[:find ?name
:where
[?e :person/name "Arnold Schwarzenegger"]
[?m :movie/cast ?e]
[?m :movie/director ?d]
[?d :person/name ?name]]
[:find ?title
:in $ ?year
:where
[?m :movie/year ?year]
[?m :movie/title ?title]]
[:find ?title ?year
:in $ [?title ...]
:where
[?m :movie/title ?title]
[?m :movie/year ?year]]
####### Exercise 2: Find all movie ?titles where the ?actor and the ?director has worked together
[:find ?title
:in $ ?actor ?director
:where
[?d :person/name ?director]
[?a :person/name ?actor]
[?m :movie/director ?d]
[?m :movie/cast ?a]
[?m :movie/title ?title]]
Exercise 3: Write a query that, given an actor name and a relation with movie-title/rating, finds the movie titles and corresponding rating for which that actor was a cast member.
[:find ?title ?rating
:in $ ?actor [[?title ?rating]]
:where
[?a :person/name ?actor]
[?m :movie/cast ?a]
[?m :movie/title ?title]]
[:find ?attr
:in $ ?title
:where
[?m :movie/title ?title]
[?m ?a]
[?a :db/ident ?attr]]
Exercise 1: Find the names of all people associated with a particular movie (i.e. both the actors and the directors)
[:find ?name
:in $ ?title [?attr ...]
:where
[?m :movie/title ?title]
[?m ?attr ?p]
[?p :person/name ?name]]
Exercise 2: Find all available attributes, their type and their cardinality. This is essentially a query to find the schema of the database. To find all installed attributes you must use the :db.install/attribute attribute. You will also need to use the :db/valueType and :db/cardinality attributes as well as :db/ident.
[:find ?attr ?type ?card
:where
[_ :db.install/attribute ?a]
[?a :db/valueType ?t]
[?a :db/cardinality ?c]
[?t :db/ident ?type]
[?c :db/ident ?card]
[?a :db/ident ?attr]]
Exercise 3: When was the seed data imported into the database? Grab the transaction of any datom in the database, e.g., [_ :movie/title _ ?tx] and work from there.
[:find ?inst
:where
[_ :movie/title _ ?tx]
[?tx :db/txInstant ?inst]]
[:find ?title
:in $ ?year
:where
[?m :movie/title ?title]
[?m :movie/year ?y]
[(>= ?year ?y)]]
[:find ?actor
:where
[?d :person/name "Danny Glover"]
[?d :person/born ?dannybirth]
[?cast :person/born ?byear]
[_ :movie/cast ?cast]
[(< ?byear ?dannybirth)]
[?cast :person/name ?actor]]
[:find ?title
:in $ ?year ?rating [[?title ?r]]
:where
[?m :movie/year ?myear]
[(>= ?myear ?year)]
[(> ?r ?rating)]
[?m :movie/title ?title]]
Exercise 0: Find people by age. Use the function tutorial.fns/age to find the age given a birthday and a date representing "today".
[:find ?name
:in $ ?age ?today
:where
[?p :person/name ?name]
[?p :person/born ?born]
[(tutorial.fns/age ?born ?today) ?age]]
[:find ?name ?age
:in $ ?today
:where
[?p :person/name ?name]
[?b :person/name "Bruce Willis"]
[?b :person/born ?bruceborn]
[?p :person/born ?born]
[(> ?born ?bruceborn)]
[(tutorial.fns/age ?born ?today) ?age]]
Exercise 2: The birthday paradox states that in a room of 23 people there is a 50% chance that someone has the same birthday. Write a query to find who has the same birthday. Use the < predicate on the names to avoid duplicate answers.
[:find ?name-1 ?name-2
:where
[?p1 :person/name ?name-1]
[?p2 :person/name ?name-2]
[?p1 :person/born ?born-1]
[?p2 :person/born ?born-2]
[(.getMonth ?born-1) ?m]
[(.getMonth ?born-2) ?m]
[(.getDate ?born-1) ?d]
[(.getDate ?born-2) ?d]
[(< ?name-1 ?name-2)]]
The current code for indenting a node is living in events.cljs
.
(reg-event-fx
:indent
(fn [_ [_ uid]]
(let [block (get-block [:block/uid uid])
parent (get-parent [:block/uid uid])
older-sib (->> parent
:block/children
(filter #(= (dec (:block/order block)) (:block/order %)))
first
:db/id
get-block)
new-block {:db/id (:db/id block) :block/order (count (:block/children older-sib))}
reindex-blocks (->> (d/q '[:find ?ch ?new-o
:in $ % ?p ?at
:where (dec-after ?p ?at ?ch ?new-o)]
@db/dsdb rules (:db/id parent) (:block/order block))
(map (fn [[id order]] {:db/id id :block/order order})))]
{:transact [[:db/retract (:db/id parent) :block/children (:db/id block)]
{:db/id (:db/id older-sib) :block/children [new-block]} ;; becomes child of older sibling block — same parent but order-1
{:db/id (:db/id parent) :block/children reindex-blocks}]}))) ;; reindex parent
In the let statement several things are computed: block
and parent
are self-explanatory, older-sib
is the node above at the same level, new-block
is where the block will be post indent, and reindex-blocks
will make sure the order is right after the block has moved. But all this doesn't matter because if the block doesn't have any older siblings, we can just not run the transact.
We don't even have to evaluate the let itself. The code becomes:
(fn [_ [_ uid]]
(let [block (get-block [:block/uid uid])
parent (get-parent [:block/uid uid])]
+ (if (= (:block/order block) 0)
+ {}
(let [older-sib (->> parent
:block/children
(filter #(= (dec (:block/order block)) (:block/order %)))
first
:db/id
get-block)
All in all, I didn't need to study datalog at all for this issue but it will be useful for the future. Still I feel like I will be able to get back to the solutions to these exercises, and use them as reference in the future.
Understanding the issue was possible with the basic knowledge of clojure that I have acquired in the past 10 days or so (it feels great!). Let's end the day with a tally of what I completed:
- First 7 chapters of Learn Datalog Today, with all its exercises
- Identified half of the solution for our first collaborative issue in the Athens codebase