Fork me on GitHub
#datomic
<
2019-11-12
>
ssdev00:11:28

Anyone know why if I try to use d/entity I get an error No such var: d/entity?

alexmiller00:11:31

there is no entity in the Client API, maybe you're using that?

ssdev00:11:18

oh. yes I am. so, I would need to just use datomic.api I suppose?

alexmiller00:11:42

kind of depends what you're trying to do

alexmiller00:11:31

are you using on-prem or cloud?

ssdev00:11:49

yeah so, clearly I'm a noob here. I'm trying to get up to speed on datomic cloud. I've managed to create a schema that creates users with first name, last name, user name, email address, and some settings. I'm trying to query for all the settings of a specific user, but what I get back looks like it's the entity id.

ssdev00:11:17

So I was trying to get that setting based on the entity id. But perhaps I'm way off in trying to do that

ssdev00:11:12

I was running this query and hoping to get back the actual settings for a user -

(d/q '[:find ?settings
           :where [?user :user/username ?username]
                  [?user :user/settings ?settings]]
       db "myusername")
instead I get back [[79] [80]]

alexmiller00:11:51

yes, the entity api is only available for peers in Datomic On-prem, so that won't be available. I would recommend looking at the Pull API instead https://docs.datomic.com/cloud/query/query-pull.html

alexmiller00:11:08

that will let you pull back the data for the selected users in the shape you want

ssdev00:11:19

Ok thanks. I'm curious when one should use pull instead of query. Is pull just more commonly used for retrieving multiple nested values?

alexmiller01:11:14

querying will primarily give you back tuples - if that's good, then use that. if you instead wanted more map-like nested data, then use pull

alexmiller01:11:43

and of course you can use them together! which is kind of shown on that page

❤️ 4
ssdev01:11:32

Ok cool. Thanks

thumbnail14:11:16

I noticed that arguments of db fns in our peer server are Java types, where i'd have expected clojure datastructures. Is this deliberate?

favila14:11:23

Example? You mean like ArrayList instead of Vector when returning from an aggregating query?

favila14:11:29

or do you mean something else?

thumbnail14:11:48

Exactly that

favila14:11:04

I think it’s done for efficiency only

favila14:11:12

It’s probably implemented with r/cat

favila14:11:24

(which uses ArrayList underneath)

thumbnail14:11:32

It is also happening for the arguments that are passed into the db-fn.

favila14:11:53

is this client api?

favila14:11:01

or transaction fn?

favila14:11:04

what’s the context?

favila14:11:22

I know seqs sometimes get decoded out of fressian as arraylists

favila14:11:00

but if the query is running using peer api, your inputs are in-process. nothing is getting coerced

favila14:11:16

so in that case it’s likely you really are passing in what you get

thumbnail14:11:01

It’s in regards of a transaction function. So i transact a db/fn into the peer (i think?) which accepts an argument. When i use the client api to invoke that function in a transaction, and check the type of the argument it’s the java equivalent. so a java.util.Arrays$ArrayList for example.

favila14:11:16

It’s the “in a transaction” part

favila14:11:24

your input was serialized and sent to the transactor

favila14:11:34

the function is running on the transactor

favila14:11:02

so a side effect of the serialization/deserialization was a change in type

thumbnail14:11:14

Yes, i figured that was the reason. I’m just curious whether this is considered a bug or is deliberate

thumbnail14:11:58

It caused some confusion on our staging env because our dev-setup uses https://github.com/ComputeSoftware/datomic-client-memdb, which doesn’t have the same side effect

favila14:11:37

Not sure how deliberate it is, but the defaults for fressian are very lazy about preserving types exactly

favila14:11:58

pretty much anything sequential will pop out as an arraylist

thumbnail15:11:31

Hmmm, will keep it in mind then. Is there any way to get the types so that they’ll work properly with clj or should i encode the data myself in that case?

favila15:11:31

you don’t have control over this AFAIK

alexmiller15:11:32

you should be careful with only relying on what's documented in the apis and not necessarily expect any particular concrete types. Java types are used because Datomic apis can be used from other jvm langs (Java, Groovy, etc)

👍 4
Brian17:11:48

Is this valid data for a Datomic Cloud transaction function to return?

[[:db/add 56246616830509142 :tags :untrusted]
 [:db/add 56246616830509142 :tags :verified]
 [:db/retract 56246616830509142 :tags :unknown]]

favila17:11:26

The shape is correct, but validity depends on the schema of :tags

Brian17:11:09

{:db/ident       :tags
      :db/valueType   :db.type/keyword
      :db/cardinality :db.cardinality/many
      :db.attr/preds  'valid-tag?}

favila17:11:59

ok, so the types are valid; now it depends on whether the valid-tag? predicate returns true

Brian17:11:20

I'm very confident that part is working properly as I've plugged things in to test it. The problem I'm now having is:

(let [tx [(list* 'update-tags-tx hash hash-type tags)]]
          tx (d/transact
            conn
            {:tx-data tx}))
is returning count not supported on this type: Keyword. Any ideas?

Brian17:11:07

Just to be thorough:

(def valid-tags #{:trusted :untrusted :unknown :accepted :verified :unauthorized :malicious})

(defn valid-tag? [tags]
  (every? valid-tags [tags]))

Brian17:11:27

One thing I'm noticing is that the tx variable is wrapping the output of update-tags-tx in brackets however the update-tags-tx is returning a [ [...] [...] [...]] already so we're seemingly triply wrapping that which is odd to me but if I don't do that then d/transact yells at me and says it must be a list of a map

Brian17:11:44

This is my transaction function which when I test it at the repl it works totally fine but perhaps there is some count going on in here that I'm missing?

(defn update-tags-tx
  "Transaction function which when given a map of hashes and a set of tags, will find the
  entity who has those hashes and will update that entity's tags"
  [db hash hash-type new-tags]
  (let [eid (ffirst
              (d/q
               '[:find ?e
                 :in $ ?hash ?hash-type
                 :where
                 [?e ?hash-type ?hash]]
               db
               hash
               hash-type))
        current-tags (set (:tags (d/pull db '[:tags] eid)))
        tags-to-add (clojure.set/difference new-tags current-tags)
        tags-to-retract (clojure.set/difference current-tags new-tags)
        tx (mapv (fn [addition] [:db/add eid :tags addition]) tags-to-add)
        retractions (mapv (fn [retract] [:db/retract eid :tags retract]) tags-to-retract)
        tx (reduce
               (fn [state retraction]
                 (conj state retraction))
               tx
               retractions)]
    tx))

favila17:11:03

Isn’t list* not what you want here?

favila17:11:23

Tags is one arg, not & tags

favila17:11:53

Anyway I don’t see a count in there. Does the ex-info data on the exception give clues as to what stage is failing, tx or ensure?

Brian17:11:29

tags referring to the valid-tags? function? I noticed that name was wrong too tag would be what I want. I chose (list* ...) based on https://github.com/Datomic/ion-starter/blob/master/src/datomic/ion/starter.clj#L172 because no variation of https://docs.datomic.com/cloud/transactions/transaction-functions.html#calling worked without errors

johnj17:11:55

what's the common naming style for attrs? some places I see :user/firstName - others :user/first-name ?