Fork me on GitHub
#datascript
<
2017-01-31
>
eslachance01:01:59

Alright little logistics issue here. Same thing as yesterday really I'm looking to insert one row, get the reference, and insert that reference into a second insert. But apparently when I insert the reference, something is expanding it? Wondering if it's in my code or what... I don't like pasting big code but here it is because I'm not sure where the issue is:

(defn insert! [data, type]
          (let [inserts (into {:db/id -1}
                              (filter some? (map (fn [[k v]] [(keyword type (name k)) v]) data)))
                result (d/transact! conn [inserts])]
            (ffirst (:tx-data result))
            ))

(defn MESSAGE_CREATE [data]
  (let [message (dissoc data :mentions :attachments :author :mention_roles :embeds)
        user-ref (insert! (message :author) "user")]
    (prn (str "Inserting reference " user-ref " as an author to the message " (message :id)))
    (insert! (assoc message :author {:db/id user-ref}) "message")
    ))

mruzekw01:01:10

Can’t you just use temp ids like -1 -2?

eslachance01:01:22

Isn't that what I'm doing?

mruzekw01:01:33

Looking closer...

mruzekw01:01:37

Oh I see it now

eslachance01:01:39

user-ref returns the DB ID actually

eslachance01:01:06

And I cannot do this in one query - there might be many references in some of those inserts

mruzekw01:01:10

I see, I’m no expert, sorry! Hopefully someone else will chime in

eslachance01:01:23

I'm sure someone will come around ^_^

eslachance01:01:52

I'd rather not ping tonsky so I'll keep hacking at it in the meantime

eslachance05:01:55

Update: I've resolved that issue at least.

Niki05:01:42

@adamfrey is it possible for you to share the entire project? I’d like to investigate

Niki05:01:34

there might be issues with advanced compilations (and there certainly were at the start of the project), but we’ve been using DataScript ever since in both :none and :advanced without any problems

Niki05:01:33

@eslachance proper way to extract ids from transact! results is to use

(let [res (d/transact! [{:db/id -1, :attr/... }])
      tempids (:tempids res)
      entity-id (get tempids -1)]
  entity-id)

Niki05:01:29

when you specify data for transact!, you use temprory ids (negative numbers). In the result it’ll return map with tempids, which maps your negative numbers to real database ids that were assigned during that transaction

Niki05:01:07

that way even if you transact multiple entities in a single transaction, you can always figure out which was resolved to what

Niki05:01:15

also (not sure if that’s relevant to your case or not), in a single transaction you can use same negative number multiple times (e.g. for specifying references from one entity to another) and it’ll be resolved to the same entity id

Niki05:01:56

use of (ffirst (:tx-data result)) is not reliable, although it’ll work in current version

Niki05:01:04

and to reference something in a transaction, specify its id, not {:db/id id} map

Niki05:01:59

(d/transact! conn [{:db/id 1}])
(d/transact! conn [{:db/id 2, :author 1}]) ;; correct
(d/transact! conn [{:db/id 2, :author {:db/id 1}}]) ;; incorrect

eslachance06:01:48

ffirst didn't work on inserting data that did not result in the DB changing, so I switched it to this (my insert function):

(defn insert! [data, type]
          (let [inserts (into {:db/id -1}
                              (filter some? (map (fn [[k v]] (if (some? v) [(keyword type (name k)) v])) data)))
                result (d/transact! conn [inserts])]
            (d/resolve-tempid conn (:tempids result) (d/tempid (keyword "db.part" type) -1))
            ))

eslachance06:01:56

Which works fine

eslachance06:01:00

Would (get (:tempids result) -1) be better then? It's certainly more... clean and short 😄

eslachance06:01:56

Also I guess using 1 only works if the schema sets that field as a ref

eslachance06:01:07

which it is: :message/author {:db/type :db.type/ref}

eslachance06:01:58

Awesome! Thank you very much! I got this working in at least a basic manner, I'm super happy 😄

Niki06:01:07

d/tempid was added for Datomic compatibility. Better to get rid of it

Niki06:01:18

it just ignores partition argument anyways

eslachance06:01:44

Is it normal that (ffirst (:tx-data result)) returned nil if the transaction didn't change anything?

Niki06:01:49

resolve-tempids was probably added for JS API

Niki06:01:04

anyways, (get (:tempids result) -1) is idiomatic

Niki06:01:25

> Is it normal that (ffirst (:tx-data result)) returned nil if the transaction didn't change anything? yes. Tx-data only contains actual DB changes

Niki06:01:48

> Also I guess using 1 only works if the schema sets that field as a ref if you want references, you have to mark it in schema anyways

Niki06:01:53

no way around it

Niki06:01:27

if you don’t, and you inserts something like :author {:db/id 1} it’ll store an actual map

eslachance06:01:48

oh that's why it was expanding it, heh.

eslachance06:01:56

I have to admit when my friend @oahner was explaining datascript to me 2 days ago, it pretty much blew my mind. I'm hooked.

Niki06:01:56

it won’t have any special meaning except as :author {:x :y}

Niki06:01:33

these things might sound counter-intuitive at first, but once you get it, it’ll all make sense

Niki06:01:50

Datomic (and DataScript) API are pretty nice to work with

eslachance06:01:53

I've done some SQL, and I understand javascript Map() and references so it actually makes a lot of sense.

Niki06:01:14

maybe a little bit non-traditional so that first encounter is not as smooth as other SQL storage

eslachance06:01:39

It's just a question of getting the syntax right and that's mostly because of my beginner's level with clojure

Niki06:01:59

best way to understand it is to remember that under the hood everything is stored as tuples of [entity id, attribute, value, transaction id]

eslachance06:01:19

Actually my friend equated it more to nosql with a single table but arbitrary keys

Niki06:01:19

everything else builds on that

Niki06:01:35

e.g. transacting maps is just a syntax sugar that gets expanded into list of tuples

Niki06:01:05

> Actually my friend equated it more to nosql with a single table but arbitrary keys some similarities, yes

eslachance06:01:09

It just blows my mind that people are counting query times in nanoseconds in clojure 😄

eslachance06:01:20

It was a generalization really

Niki06:01:41

although ahead-of-time schema is still needed (always for Datomic, for all non-trivial attributes in DataScript)

eslachance06:01:13

A bit of order in discord is great. Overall, I'm getting used to it pretty fast.

eslachance06:01:08

Now I just need to do the boring job of processing every packet coming from Discord, separating it into entities and inserting them as they come in.

eslachance06:01:15

I'm off to bed though, so thanks again and good night!

adamfrey14:01:48

@tonsky here’s a stripped down version of my codebase with the pseudo-names problem: https://github.com/AdamFrey/datascript-pseudo-names-bug

Drew Verlee16:01:21

I just recently started using datascript. I wanted to include the attrs in the find clause, but i get an error which i dont understand.

(query '[:find ?time ?attr ?type ?data
            :where
            [?e ?a]
            [?a :db/attr ?attr]
            [?e :type ?type]
            [?e :data ?data]
            [?e :time ?time]])
Error: Expected number or lookup ref for entity id, got :data Any ideas on what im supposed to do differently?

Drew Verlee16:01:22

Actual a better question, would be how to do a group by in datascript. As thats why im trying to include the attr in the output.

danielstockton19:01:11

@drewverlee If you want to group by without including the attributes in the resultset, look at the :with clause: http://docs.datomic.com/query.html

danielstockton19:01:53

I think the error comes from the first two where clauses, using ?a in attribute position and then in entity position. I don't think attributes are entityids in datascript, like they are in datomic, they are simply keywords...

adamfrey22:01:11

I’m seeing transactions come in to my d/listen! listener in the wrong order when another listener commits a transaction. Here’s the output from both listeners printing (:tx-data tx-report)

"listener 1" [#datascript/Datom [0 :modal/open :new-outing t true]]
;; inside listener 1 - transacts [[:db/add 0 :modal/open :sign-up]]
"listener 1" [#datascript/Datom [0 :modal/open :new-outing t false] <#C07V8N22C|datascript>/Datom [0 :modal/open :sign-up t true]]
"listener 2" [#datascript/Datom [0 :modal/open :new-outing t false] <#C07V8N22C|datascript>/Datom [0 :modal/open :sign-up t true]]
"listener 2" [#datascript/Datom [0 :modal/open :new-outing t true]]

adamfrey22:01:19

this looks like the behavior of a stack. Is this expected behavior? It caught me by surprise.