Hi everyone! I am learning datascript and I am a bit stuck at recursion; for my test I have a simple comments tree, each comment has a parent (except the root) and I would like to get, with one query, the root comments with their children, like ["author" "text" [["author1" "reply1" ["sub-author" "sub-reply" []] {"author2" "reply2" []]] Test setup:
(def schema
{:comment/id {:db/unique :db.unique/identity}
:comment/parent {:db/valueType :db.type/ref
:db/cardinality :db.cardinality/one}})
(defn add-mock-data! []
(let [comment1 (random-uuid)
comment2 (random-uuid)
comment3 (random-uuid)]
(d/transact! db
[{:comment/id comment1
:comment/author "reviewer"
:comment/created-at "2020-08-17T08:41:12Z"
:comment/text "Comment by reviewer"}
{:comment/id comment2
:comment/parent {:comment/id comment1}
:comment/author "author"
:comment/created-at "2020-08-18T08:41:12Z"
:comment/text "Author's reply"}
{:comment/id comment3
:comment/parent {:comment/id comment2}
:comment/author "reviewer"
:comment/created-at "2020-08-18T09:11:02Z"
:comment/text "Reviewer's reply"}
])))
Query:
(d/q '[:find ?author ?text (pull ?cc [:comment/author :comment/text])
:where
[?c :comment/id ?id]
[?c :comment/author ?author]
[?c :comment/text ?text]
[?cc :comment/parent ?cp]
[?cp :comment/id ?id]
]
@db)
Result:
0. [ "reviewer" "Comment by reviewer" { :comment/author "author", :comment/text "Author's reply" } ]
1. [ "author" "Author's reply" { :comment/author "reviewer", :comment/text "Reviewer's reply" } ]
What is missing so far is getting only root comment but I think it is trivial, but what I can't really get is how to generate, recursively, the list of replies 😞 ideas?to start, I think that I need to get a vector/list of children instead now I am getting [comment child] for each comment; I have tried to simplify the query to make it easier to reason about it:
(d/q '[:find ?author ?text ?cc
:in $ %
:where
[?c :comment/author ?author]
[?c :comment/text ?text]
(children ?c ?cc)
]
@db '[[(children ?c ?cc)
[?cc :comment/parent ?c]]])
quick update, as mentioned, starting with root comments is easy, filter by comments with no :coment/parent, here is the new query:
(d/q '[:find ?author ?text ?cc
:in $ %
:where
[?c :comment/author ?author]
[?c :comment/text ?text]
[(missing? $ ?c :comment/parent)]
(children ?c ?cc)
]
@db '[[(children ?c ?cc)
[?cc :comment/parent ?c]
(children ?cc ?ccc)]
[(children ?c ?cc)
[?cc :comment/parent ?c]]])
still struggling to find a way to get a list of children, hoping I just need to refine my search keywords 🙂