tonsky / datascript

Immutable database and Datalog query engine for Clojure, ClojureScript and JS
Eclipse Public License 1.0
5.45k stars 302 forks source link

Can't take keys of a db even though it's a map? #393

Closed rgkirch closed 3 years ago

rgkirch commented 3 years ago
(let [db (ds/db-with (ds/empty-db) [{:db/id -1
                                     :my/attr "a"}])]
  (and (map? db) (keys db)))
The result object failed to print. It is available via *1 if you want to interact with it.
The exception was: 
TypeError: me.cljs$core$IMapEntry$_key$arity$1 is not a function
tonsky commented 3 years ago

Wow. Thanks, I’ll take a look

rgkirch commented 3 years ago

Thanks.

tonsky commented 3 years ago

So the problem here is that Clojure expects (seq map) to return Map.Entry sequence. DataScript DB tries to be map and vector at the same time. (seq db) return sequence of datoms, not Map.Entry.

I thought it might be useful, but didn’t know it might cause the clash that you found. I am not sure what’s the good way to fix this would be. There might be clients relying on (seq db) to return datoms now.

rgkirch commented 3 years ago
(let [db (ds/db-with (ds/empty-db) [{:db/id -1
                                     :my/attr "a"}])]
  (or (seq? db) (first db)))

expected: true actual: #datascript/Datom [1 :my/attr "a" 536870913 true]

I was trying to understand what you said when I found more unexpected behavior. Above, (seq? db) returns false even though first and rest work fine.

I think I understand your point but I'm having trouble connecting it to the code; this is on the Entity interface, right?

You're saying that seq is out of line for returning datoms and not map entries but it seems like the db is more akin to a list of datoms than it is to a map. What should keys even return?

My mental model of the db only includes the 3 5-tuple lists (:eavt :aevt :avet) so it doesn't seem like a map at all.

tonsky commented 3 years ago

It only returns map because it’s a record, and all records are map-like. E.g. you can access values by keys: (:eavt db).

seq? return false because it checks if something is already a seq. You probably want seqable?. Not to be confused with sequential? :)

rgkirch commented 3 years ago

Ok, thanks.

I was confused since seq? says Return true if s satisfies ISeq and ISeq is a protocol with -first and -rest. seqable? is true if it satisfies ISeqable and ISeqable is a Protocol for adding the ability to a type to be transformed into a sequence. And then ISequential says that it's a Marker interface indicating a persistent collection of sequential items

That's all pretty confusing but I like your explanation: if seq? is true then it's a sequence, seqable? says that it can become a sequence.

Ok, I see. It's a record of these many things schema eavt aevt avet max-eid max-tx rschema hash and seq defaults to eavt

I issue is that I can't print the db. e.g. I can't use re-frisk since that tries to print everything in my re-frame app db.

How can I fix this in my app? I read about proxy but I don't know how to apply that to solve this issue and it doesn't look like proxy is available in clojurescript.

tonsky commented 3 years ago

I removed ISeqable from DB, now keys should work. Please update to 1.1.0

rgkirch commented 3 years ago

Thank you!

filipesilva commented 3 years ago

Related to https://github.com/thheller/shadow-cljs/issues/858