This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-08-26
Channels
- # announcements (4)
- # babashka (8)
- # beginners (75)
- # calva (26)
- # cider (33)
- # circleci (5)
- # clojure (36)
- # clojure-dev (2)
- # clojure-europe (25)
- # clojure-nl (4)
- # clojure-spec (38)
- # clojure-uk (47)
- # clojurescript (15)
- # cloverage (2)
- # conjure (64)
- # core-async (41)
- # cursive (13)
- # data-science (2)
- # datalog (16)
- # datascript (22)
- # datomic (9)
- # duct (2)
- # emacs (81)
- # figwheel-main (1)
- # fulcro (4)
- # jobs (2)
- # jobs-discuss (29)
- # kaocha (3)
- # meander (11)
- # membrane (21)
- # off-topic (1)
- # portal (1)
- # re-frame (1)
- # reitit (1)
- # releases (2)
- # remote-jobs (31)
- # shadow-cljs (26)
- # specter (5)
- # sql (26)
- # tools-deps (19)
- # vim (12)
is there anything built in to flatten nested data, so when looking up refs in a pull query it returns the refs as sub hashmaps when i have a single key value can i flatten or should I do that afterwards ?
datomic has :xform
option in pull-api, but I don't think that has been ported to datascript. Even so, you would need to apply that to each ref individually. One way is to clojure.walk/postwalk
over the result and replacing all the known refs with their idents. You can either explicitly pass in the refs you need replaced or you can find all the refs automatically by querying the schema (or in the case of datascript - the initial schema map).
Fulcro RAD has some code that could serve as a good starting point (it considers both multiple and single cardinality): https://github.com/fulcrologic/fulcro-rad-datomic/blob/develop/src/main/com/fulcrologic/rad/database_adapters/datomic.clj#L80-L102
I prefer the postwalk approach, because it makes the conversion explicit and doesn't confuse data querying with data mangling 🙂
I'm working with the learndatalog and kristianmandrup's tutorial at https://github.com/kristianmandrup/datascript-tutorial/blob/master/pull_data.md#pull-and-query-combined
The latter says I should be able to (d/pull-many db '[*] (d/q '[:find ?e :where [?e]]))
But there seem to be multiple things wrong with this: 1. You need to pass the db to the query function 2. The result of the query is a set of 1 element vectors that pull-many choke son
This works, but seems like it should be unnecessary (d/pull-many @conn '[*] (flatten (vec (d/q '[:find ?e :where [?e]] @conn))))
1. Yes, you want to learn to pass an immutable db around to queries, not derefing an unkown state conn.
2. You're right about the set of tuples, but there is more sugar syntax: [:find ?e]
vs [:find ?e .]
vs [:find [?e ...]]
(what you're looking for)
3. Fetching all data like this seems like an unusual use-case; and if you want all eids, you can probably just take that straight out of the indices.
😮 I always assumed the ...
in examples was just the author eliding stuff that wasn't important, not that it was literal syntax.
agreed regarding #3, I'm just finding my way around datalog, and after putting stuff in a natural question is how do I get it all out?
but you have given me a few options to look into, think i need to make notes as I go and make a post about these things 🙂
ad 3. that's why it unusual - asking for "all" the data hardly ever comes up in practice; unless you want to serialize/backup/etc, and then it's probably more practical to use d/datoms
d/seek-datoms
d/history
etc.
I ended up specifying each entity in the query instead of using pull inside d/q with the [*] wild card
@U05476190 regarding #1, makes sense and is something I'm already used to when working with state maps, however is it possible to transact in datascript without involving the atom? that is I want a function to take db value, and return an updated db value. datacript's transact!
only operates on a connection.
Does the function also need to query? If not, you're looking at a function signature ala:
(defn update-foo [conn new-foo]
(let [tx-result (d/transact! ...)]
;; return new DB for system to use
(:db-after tx-result))
If the function needs to query the DB before making the update, which version of the DB? You need to make that decision. But if you're interested in the "newest" version (e.g. to increment a value), then you need to move that query logic into a transactor function to avoid race conditions. So the above pattern still applies. If you're working in DataScript in single-threaded JS and you don't care about race conditions, then you're update-foo could just take a conn as an arg, deref
the conn, do the query
, then transact!
, and return :db-after
as before.@U70QFSCG2 have a look at d/with
and d/db-with
. Those both allow you to incorporate new datoms into a database as a pure function of db->db
Does the function also need to query? If not, you're looking at a function signature ala:
(defn update-foo [conn new-foo]
(let [tx-result (d/transact! ...)]
;; return new DB for system to use
(:db-after tx-result))
If the function needs to query the DB before making the update, which version of the DB? You need to make that decision. But if you're interested in the "newest" version (e.g. to increment a value), then you need to move that query logic into a transactor function to avoid race conditions. So the above pattern still applies. If you're working in DataScript in single-threaded JS and you don't care about race conditions, then you're update-foo could just take a conn as an arg, deref
the conn, do the query
, then transact!
, and return :db-after
as before.