tonsky/datascript

Query doesn't work under advanced optimizations

lilactown opened this issue · 12 comments

       (ds/q '[:find ?tx ?id ?v ?ts
               :where
               [?e :entry/value ?v ?tx]
               [?e :entry/id ?id ?tx]
               [?e :entry/ts ?ts ?tx]]
             app-db)

☝️ this query doesn't work under advanced optimizations. any ideas why?

#datascript/DB {:schema nil, :datoms [[1 :entry/id 15 536870914] [1 :entry/ts 1557849697260 536870914] [1 :entry/value {:value 1, :meta nil} 536870914]]}

is the DB for instance and that query returns #{[nil nil nil nil]}

Works for me on

[org.clojure/clojure       "1.10.0"]
[org.clojure/clojurescript "1.10.520"]

what version of compiler are you on?

This was due to missing externs while using shadow-cljs. thheller pointed me to #216; adding :externs ["datascript/externs.js"] to :compiler-options map in my shadow-cljs.edn fixed the issue for now.

Is there some place we can note this, if we can't remove the need for externs to be present under advanced optimizations?

Well the idea of externs is that they are absolutely required. Why else have them?

I'm not sure I understand. My point was that I had no idea that adding the externs to my project config was necessary. I was thinking that we could add a note to the installation instructions.

Totally! shadow-cljs README should mention this for all CLJS projects!

Confirming as well that this query


(d/q '[:find [?e ...]
         :in $ ?attribute
         :where
          ;[?e :event/name] ;; I USED TO HAVE TO DO THIS
          [?e ?attribute]  ;; BUT NOW I CAN INSTEAD DO THIS
          [?e :event/active true]] ds attribute))

WORKS just by adding this to my shadow-cljs.edn file

...
 :compiler-options {:infer-externs :auto
                      :externs ["datascript/externs.js"]} ;; <--- just add this in

I added a section under the wiki Tips & Tricks section.

Hi,

I followed this issue and add those two :compiler-options to shadow-cljs config and found a datascript is not defined error.
It turns out the compiled prod.js defines datascript with datascript={} instead of var datascript={}.

Since my build target is :esm, having datascript={} kind of expression will cause the datascript is not defined error.

My solution is to add :prepend-js "if(window)window.datascript={};" to shadow-cljs.edn like bellow.

{:target :esm
 ...
 :compiler-options {:infer-externs :auto
                    :externs ["datascript/externs.js"]}
 :modules {:app {:exports ...
                 :prepend-js "if(window)window.datascript={};"}

Just put it here in case someone encounters the same problem.

@yqrashawn I am not familiar with how shadow processes externs. Does it simply prepends them? Do you think externs bundled with DataScript should be changed (e.g. datascript -> global.datascript?)

I'm not familiar with closure compiler. I tried this in externs.js file. It's not work. Closure compiler still compiles it to ;datascript={} in the outmost scope of a ESM js file.

I guess closure compiler don't know about that user is going to use the file in as a ESM file, only shadow-cljs knows about it.

if (global) global.datascript = datascript
else if (window) window.datascript = datascript
else {
  var datascript = {}
}

@yqrashawn Thanks for the snippet. I wasn't able to use it in :prepend-js as I get this error - https://github.com/google/closure-compiler/wiki/FAQ#i-got-a-partial-alias-created-for-namespace-error--what-do-i-do . I was able to use your snippet with :prepend e.g.:

:prepend "if (global) { global.datascript = datascript } else if (window) { window.datascript = datascript } else { var datascript = {}}"

if (window) or if (global) doesn't work if window or global does not exit, it will simply throw if those symbols don't resolve to anything in the JS environment.

The test should be globalThis.window or something, but since globalThis is already the global object, you could use that directly.