From 9f747bbc939af5b4c8b59d4bf251a5cef2dfba35 Mon Sep 17 00:00:00 2001 From: pat killean Date: Mon, 9 Dec 2024 21:55:44 -0400 Subject: [PATCH 1/2] cljs compilation fixes --- .gitignore | 1 + .../native-image-tests/run-bb-pod-tests.clj | 1 + bb/src/tools/test.clj | 8 +- deps.edn | 14 +++- shadow-cljs.edn | 9 +++ src/datahike/api.cljc | 27 ++++--- src/datahike/api/specification.cljc | 2 +- src/datahike/array.cljc | 51 ++++++++----- src/datahike/config.cljc | 26 ++++--- src/datahike/connector.cljc | 36 ++++----- src/datahike/datom.cljc | 13 ++-- src/datahike/db.cljc | 25 +++--- src/datahike/db/search.cljc | 4 +- src/datahike/db/transaction.cljc | 27 +++---- src/datahike/gc.cljc | 6 +- src/datahike/impl/entity.cljc | 8 +- src/datahike/index.cljc | 3 +- src/datahike/index/interface.cljc | 3 +- src/datahike/index/persistent_set.cljc | 18 +++-- src/datahike/integration_test.cljc | 5 +- src/datahike/lru.cljc | 11 ++- src/datahike/middleware/utils.cljc | 17 +++-- src/datahike/pull_api.cljc | 3 +- src/datahike/query.cljc | 18 +++-- src/datahike/query_stats.cljc | 4 +- src/datahike/readers.cljc | 1 + src/datahike/schema.cljc | 24 ++++-- src/datahike/schema_cache.cljc | 3 +- src/datahike/store.cljc | 76 ++++++++++--------- src/datahike/tools.cljc | 12 +-- src/datahike/writer.cljc | 39 +++++----- src/datahike/writing.cljc | 22 ++++-- test/datahike/cljs_compilation_test.cljs | 45 +++++++++++ 33 files changed, 347 insertions(+), 215 deletions(-) create mode 100644 shadow-cljs.edn create mode 100644 test/datahike/cljs_compilation_test.cljs diff --git a/.gitignore b/.gitignore index 5d7a0dc72..b5002becd 100644 --- a/.gitignore +++ b/.gitignore @@ -36,3 +36,4 @@ dhi dhi.build_artifacts.txt trace.edn tmp.edn +.shadow-cljs \ No newline at end of file diff --git a/bb/resources/native-image-tests/run-bb-pod-tests.clj b/bb/resources/native-image-tests/run-bb-pod-tests.clj index 119e1a93f..a84fdb4ab 100755 --- a/bb/resources/native-image-tests/run-bb-pod-tests.clj +++ b/bb/resources/native-image-tests/run-bb-pod-tests.clj @@ -85,6 +85,7 @@ [?e :age ?a]] (d/db conn))))) (let [timestamp (Date.)] + (Thread/sleep 1) (d/transact conn {:tx-data [{:db/id 3 :age 25}]}) (d/transact conn [{:name "FOO" :age "BAR"}]) (testing "pull" diff --git a/bb/src/tools/test.clj b/bb/src/tools/test.clj index dec4734b1..33c51e860 100644 --- a/bb/src/tools/test.clj +++ b/bb/src/tools/test.clj @@ -58,12 +58,17 @@ (defn specs [] (kaocha "--focus" "specs" "--plugin" "kaocha.plugin/orchestra")) +(defn cljs-compile-test [] + (p/shell "clj -M:cljs -m shadow.cljs.devtools.cli compile :comptest") + (p/shell "node target/out/comptest.js")) + (defn all [config] (kaocha "--skip" "specs") (specs) (back-compat config) (native-image) - (bb-pod)) + (bb-pod) + (cljs-compile-test)) (defn -main [config & args] (if (seq args) @@ -72,5 +77,6 @@ "bb-pod" (bb-pod) "back-compat" (back-compat config) "specs" (specs) + "cljs" (cljs-compile-test) (apply kaocha "--focus" args)) (all config))) diff --git a/deps.edn b/deps.edn index a8f511588..b7b7dce2f 100644 --- a/deps.edn +++ b/deps.edn @@ -4,10 +4,11 @@ io.replikativ/hitchhiker-tree {:mvn/version "0.2.222" :exclusions [org.clojure/clojurescript]} io.replikativ/konserve {:mvn/version "0.7.319" - :exclusions [org.clojure/clojurescript]} + :exclusions [org.clojure/clojurescript + org.clojars.mmb90/cljs-cache]} io.replikativ/superv.async {:mvn/version "0.3.48" :exclusions [org.clojure/clojurescript]} - io.replikativ/datalog-parser {:mvn/version "0.2.29"} + io.replikativ/datalog-parser {:mvn/version "0.2.30"} io.replikativ/zufall {:mvn/version "0.2.9"} persistent-sorted-set/persistent-sorted-set {:mvn/version "0.3.0"} environ/environ {:mvn/version "1.2.0"} @@ -18,7 +19,10 @@ metosin/spec-tools {:mvn/version "0.10.6"} mvxcvi/clj-cbor {:mvn/version "1.1.1"} org.babashka/http-client {:mvn/version "0.3.11"} - metosin/jsonista {:mvn/version "0.3.7"}} + metosin/jsonista {:mvn/version "0.3.7"} + pkpkpk/cljs-cache {:git/url "https://github.com/pkpkpk/cljs-cache" + :git/tag "datahike-fix" + :git/sha "a0e7298fb90daadbf4dcf12ae996396e68cb1f3e"}} :paths ["src" "target/classes" "resources"] @@ -32,7 +36,9 @@ :1.10 {:override-deps {org.clojure/clojure {:mvn/version "1.10.0"}}} - :cljs {:extra-deps {org.clojure/clojurescript {:mvn/version "1.11.121"}}} + :cljs {:extra-deps {org.clojure/clojurescript {:mvn/version "1.11.132"} + thheller/shadow-cljs {:mvn/version "2.28.20"}} + :extra-paths ["test"]} :dev {:extra-paths ["dev" "benchmark/src"] :extra-deps {org.clojure/tools.namespace {:mvn/version "1.4.4"} diff --git a/shadow-cljs.edn b/shadow-cljs.edn new file mode 100644 index 000000000..83a0e2108 --- /dev/null +++ b/shadow-cljs.edn @@ -0,0 +1,9 @@ +{:deps true + :src-paths ["src" "test"] + :builds {:comptest + {:target :node-script + :output-to "target/out/comptest.js" + :main datahike.cljs-compilation-test/-main + :compiler-options {:infer-externs true + :warnings {:fn-deprecated false + :protocol-multiple-impls false}}}}} diff --git a/src/datahike/api.cljc b/src/datahike/api.cljc index 72ada20fa..2841cbfcb 100644 --- a/src/datahike/api.cljc +++ b/src/datahike/api.cljc @@ -1,13 +1,14 @@ (ns datahike.api "Public API for datahike. Expanded from api.specification." (:refer-clojure :exclude [filter]) + #?(:cljs (:require-macros [datahike.api :refer [emit-api]])) (:require [datahike.connector :as dc] [datahike.config :as config] [datahike.api.specification :refer [api-specification spec-args->argslist]] [datahike.api.impl] [clojure.spec.alpha :as s] [datahike.writer :as dw] - [datahike.http.writer] + #?(:clj [datahike.http.writer]) [datahike.writing :as writing] [datahike.constants :as const] [datahike.core :as dcore] @@ -25,12 +26,18 @@ [datahike.db HistoricalDB AsOfDB SinceDB FilteredDB] [datahike.impl.entity Entity]))) -(doseq [[n {:keys [args ret fn doc impl]}] api-specification] - (eval - `(s/fdef ~n :args ~args :ret ~ret ~@(when fn [:fn fn]))) - (eval - `(def - ~(with-meta n - {:arglists `(spec-args->argslist (quote ~args)) - :doc doc}) - ~impl))) +(defmacro ^:private emit-api [] + `(do + ~@(reduce + (fn [acc [n {:keys [args ret fn doc impl]}]] + (conj acc + `(s/fdef ~n :args ~args :ret ~ret ~@(when fn [:fn fn])) + `(def + ~(with-meta n + {:arglists `(spec-args->argslist (quote ~args)) + :doc doc}) + ~impl))) + () + (into (sorted-map) api-specification)))) + +(emit-api) \ No newline at end of file diff --git a/src/datahike/api/specification.cljc b/src/datahike/api/specification.cljc index a6186f804..b3f449d73 100644 --- a/src/datahike/api/specification.cljc +++ b/src/datahike/api/specification.cljc @@ -857,7 +857,7 @@ Returns the key under which this listener is registered. See also [[unlisten]]." gc-storage {:args (s/alt :with-date (s/cat :conn spec/SConnection :remove-before spec/time-point?) :no-date (s/cat :conn spec/SConnection)) - :ret set? + :ret any? :doc "Invokes garbage collection on the store of connection by whitelisting currently known branches. All db snapshots on these branches before remove-before date will also be erased (defaults to beginning of time [no erasure]). The branch heads will diff --git a/src/datahike/array.cljc b/src/datahike/array.cljc index 33d679dd5..676f99f4b 100644 --- a/src/datahike/array.cljc +++ b/src/datahike/array.cljc @@ -1,5 +1,6 @@ (ns ^:no-doc datahike.array #?(:clj (:require [hitchhiker.tree.node :as n])) + #?(:cljs (:require [goog.array])) #?(:clj (:import [java.util Arrays]))) #?(:clj @@ -36,26 +37,35 @@ (recur (inc i#))))))) `(array-compare ~a ~b)))) -#?(:clj (defn compare-arrays - "Compare two arrays a and b element-wise in ascending order. If one array is a - prefix of another then it comes first." - [a b] - (if (not (and (bytes? a) (bytes? b))) - (try - (compare a b) - (catch ClassCastException _ - (- (n/-order-on-edn-types a) - (n/-order-on-edn-types b)))) - (raw-array-compare a b)))) +#?(:cljs + (defn bytes? [x] + (and (instance? js/ArrayBuffer (.-buffer x)) + (number? (.-byteLength x))))) -#?(:clj (defn string-from-bytes - "Represents a byte array as a string. Two byte arrays are said to be equal iff their corresponding values after applying this function are equal. That way, we rely on the equality and hash code implementations of the String class to compare byte arrays." - [x] - (let [n (alength x) - dst (char-array n)] - (dotimes [i n] - (aset dst i (char (aget x i)))) - (String. dst)))) +(defn compare-arrays + "Compare two arrays a and b element-wise in ascending order. If one array is a +prefix of another then it comes first." + [a b] + #?(:cljs (goog.array/compare3 a b) + :clj + (if (not (and (bytes? a) (bytes? b))) + (try + (compare a b) + (catch ClassCastException _ + (- (n/-order-on-edn-types a) + (n/-order-on-edn-types b)))) + (raw-array-compare a b)))) + +(defn string-from-bytes + "Represents a byte array as a string. Two byte arrays are said to be equal iff their corresponding values after applying this function are equal. That way, we rely on the equality and hash code implementations of the String class to compare byte arrays." + [x] + #?(:cljs (.decode (js/TextDecoder. "utf8") x) + :clj + (let [n (alength x) + dst (char-array n)] + (dotimes [i n] + (aset dst i (char (aget x i)))) + (String. dst)))) (defrecord WrappedBytes [string-repr]) @@ -75,4 +85,5 @@ #?(:clj (and (bytes? a) (bytes? b) (zero? (compare-arrays a b))) - :cljs (zero? (compare-arrays a b))))) + :cljs (or (identical? a b) + (zero? (compare-arrays a b)))))) diff --git a/src/datahike/config.cljc b/src/datahike/config.cljc index ad1c413d0..d8d8716e0 100644 --- a/src/datahike/config.cljc +++ b/src/datahike/config.cljc @@ -7,7 +7,8 @@ [datahike.tools :as dt] [datahike.store :as ds] [datahike.index :as di]) - (:import [java.net URI])) + (:import #?(:clj [java.net URI] + :cljs [goog.Uri]))) ;; global (def ^:dynamic *schema-meta-cache-size* (env :schema-meta-cache-size 1024)) @@ -83,7 +84,7 @@ :path path :host host :port port - :id (str (java.util.UUID/randomUUID))} + :id (str #?(:clj (java.util.UUID/randomUUID) :cljs (random-uuid)))} :level {:path path} :file {:path path})) :index index @@ -101,19 +102,20 @@ (defn int-from-env [key default] (try - (Integer/parseInt (get env key (str default))) - (catch Exception _ default))) + (#?(:clj Integer/parseInt :cljs js/parseInt) (get env key (str default))) + (catch #?(:clj Exception :cljs js/Error) _ default))) (defn bool-from-env [key default] (try - (Boolean/parseBoolean (get env key default)) - (catch Exception _ default))) + #?(:clj (Boolean/parseBoolean (get env key default)) + :cljs (= "true" (get env key default))) + (catch #?(:clj Exception :cljs js/Error) _ default))) (defn map-from-env [key default] (try (edn/read-string (get env key (str default))) - (catch Exception _ default))) + (catch #?(:clj Exception :cljs js/Error) _ default))) (defn validate-config-attribute [attribute value config] (when-not (s/valid? attribute value) @@ -167,7 +169,7 @@ (keyword "datahike.index" (:datahike-index env)) *default-index*) config {:store store-config - :initial-tx (:datahike-intial-tx env) + :initial-tx (:datahike-initial-tx env) :keep-history? (bool-from-env :datahike-keep-history *default-keep-history?*) :attribute-refs? (bool-from-env :datahike-attribute-refs *default-attribute-refs?*) :schema-flexibility (keyword (:datahike-schema-flexibility env *default-schema-flexibility*)) @@ -191,7 +193,8 @@ (when (and attribute-refs? (= :read schema-flexibility)) (throw (ex-info "Attribute references cannot be used with schema-flexibility ':read'." config))) (if (string? initial-tx) - (update merged-config :initial-tx (fn [path] (-> path slurp read-string))) + #?(:clj (update merged-config :initial-tx (fn [path] (-> path slurp read-string))) + :cljs (throw (ex-info ":initial-tx from path is not supported in cljs at this time" merged-config))) merged-config)))) ;; deprecation begin @@ -207,10 +210,11 @@ :opt-un [::username ::password ::path ::host ::port])) (defn uri->config [uri] - (let [base-uri (URI. uri) + (let [base-uri (#?(:clj URI. :cljs goog.Uri.) uri) _ (when-not (= (.getScheme base-uri) "datahike") (throw (ex-info "URI scheme is not datahike conform." {:uri uri}))) - sub-uri (URI. (.getSchemeSpecificPart base-uri)) + sub-uri #?(:clj (URI. (.getSchemeSpecificPart base-uri)) + :cljs (goog.Uri. (.getScheme base-uri))) backend (keyword (.getScheme sub-uri)) [username password] (when-let [user-info (.getUserInfo sub-uri)] (str/split user-info #":")) diff --git a/src/datahike/connector.cljc b/src/datahike/connector.cljc index 5d0194f14..035e7f9dc 100644 --- a/src/datahike/connector.cljc +++ b/src/datahike/connector.cljc @@ -11,7 +11,7 @@ [taoensso.timbre :as log] [clojure.spec.alpha :as s] [clojure.data :refer [diff]]) - (:import [clojure.lang IDeref IAtom IMeta ILookup IRef])) + #?(:clj (:import [clojure.lang IDeref IAtom IMeta ILookup IRef]))) ;; connection @@ -22,25 +22,25 @@ (deftype Connection [wrapped-atom] IDeref - (deref [conn] (deref-conn conn)) + (#?(:clj deref :cljs -deref) [conn] (deref-conn conn)) ;; These interfaces should not be used from the outside, they are here to keep ;; the internal interfaces lean and working. ILookup - (valAt [c k] (if (= k :wrapped-atom) wrapped-atom nil)) - IAtom - (swap [_ f] (swap! wrapped-atom f)) - (swap [_ f arg] (swap! wrapped-atom f arg)) - (swap [_ f arg1 arg2] (swap! wrapped-atom f arg1 arg2)) - (swap [_ f arg1 arg2 args] (apply swap! wrapped-atom f arg1 arg2 args)) - (compareAndSet [_ oldv newv] (compare-and-set! wrapped-atom oldv newv)) - (reset [_ newval] (reset! wrapped-atom newval)) - + (#?(:clj valAt :cljs -lookup) [c k] (if (= k :wrapped-atom) wrapped-atom nil)) IMeta - (meta [_] (meta wrapped-atom)) - - IRef ;; TODO This is unoffically supported, it triggers watches on each update, not on commits. For proper listeners use the API. - (addWatch [_ key f] (add-watch wrapped-atom key f)) - (removeWatch [_ key] (remove-watch wrapped-atom key))) + (#?(:clj meta :cljs -meta) [_] (meta wrapped-atom)) + #?(:cljs IAtom) + #?@(:clj + [IAtom + (swap [_ f] (swap! wrapped-atom f)) + (swap [_ f arg] (swap! wrapped-atom f arg)) + (swap [_ f arg1 arg2] (swap! wrapped-atom f arg1 arg2)) + (swap [_ f arg1 arg2 args] (apply swap! wrapped-atom f arg1 arg2 args)) + (compareAndSet [_ oldv newv] (compare-and-set! wrapped-atom oldv newv)) + (reset [_ newval] (reset! wrapped-atom newval)) + IRef ;; TODO This is unofficially supported, it triggers watches on each update, not on commits. For proper listeners use the API. + (addWatch [_ key f] (add-watch wrapped-atom key f)) + (removeWatch [_ key] (remove-watch wrapped-atom key))])) (defn connection? [x] (instance? Connection x)) @@ -139,11 +139,11 @@ (dissoc :writer :store-cache-size :search-cache-size))) (extend-protocol PConnector - String + #?(:clj String :cljs string) (-connect [uri] (-connect (dc/uri->config uri))) - clojure.lang.IPersistentMap + #?(:clj clojure.lang.IPersistentMap :cljs PersistentArrayMap) (-connect [raw-config] (let [config (dissoc (dc/load-config raw-config) :initial-tx :remote-peer :name) _ (log/debug "Using config " (update-in config [:store] dissoc :password)) diff --git a/src/datahike/datom.cljc b/src/datahike/datom.cljc index 8d6690864..ca64495d5 100644 --- a/src/datahike/datom.cljc +++ b/src/datahike/datom.cljc @@ -1,8 +1,10 @@ (ns ^:no-doc datahike.datom + #?(:cljs (:require-macros [datahike.datom :refer [combine-cmp]])) (:require [clojure.walk] [clojure.data] + [datahike.constants :refer [tx0]] [datahike.tools :refer [combine-hashes]] - [datahike.constants :refer [tx0]])) + #?(:cljs [goog.array :as garray]))) (declare hash-datom equiv-datom seq-datom nth-datom assoc-datom val-at-datom) @@ -147,7 +149,8 @@ :v (datom (.-e d) (.-a d) v (datom-tx d) (datom-added d)) :tx (datom (.-e d) (.-a d) (.-v d) v (datom-added d)) :added (datom (.-e d) (.-a d) (.-v d) (datom-tx d) v) - (throw (IllegalArgumentException. (str "invalid key for #datahike/Datom: " k))))) + (throw (#?(:clj IllegalArgumentException. :cljs js/Error.) + (str "invalid key for #datahike/Datom: " k))))) ;; printing and reading ;; #datomic/DB {:schema , :datoms } @@ -243,13 +246,13 @@ (.compareTo ^Comparable a1 a2))) (defn- class-name [x] - (let [c (class x)] - (.getName ^Class c))) + #?(:clj (.getName (class x)) + :cljs (type x))) (defn- safe-compare [a b] (try (compare a b) - (catch Exception _e + (catch #?(:clj Exception :cljs js/Error) _e (compare (class-name a) (class-name b))))) diff --git a/src/datahike/db.cljc b/src/datahike/db.cljc index a3511afd7..4d8b1803c 100644 --- a/src/datahike/db.cljc +++ b/src/datahike/db.cljc @@ -18,7 +18,7 @@ [taoensso.timbre :refer [warn]]) #?(:cljs (:require-macros [datahike.db :refer [defrecord-updatable]] [datahike.datom :refer [combine-cmp datom]] - [datahike.tools :refer [case-tree raise]])) + [datahike.tools :refer [raise]])) (:refer-clojure :exclude [seqable?]) #?(:clj (:import [clojure.lang AMapEntry ITransientCollection IEditableCollection IPersistentCollection Seqable IHashEq Associative IKeywordLookup ILookup] @@ -109,9 +109,7 @@ #?(:clj (defn- make-record-updatable-cljs [name fields & impls] - `(do - (defrecord ~name ~fields) - (extend-type ~name ~@impls)))) + `(defrecord ~name ~fields ~@impls))) #?(:clj (defmacro defrecord-updatable [name fields & impls] @@ -359,13 +357,13 @@ ICounted (-count [db] (count (dbi/datoms db :eavt []))) IPrintWithWriter (-pr-writer [db w opts] (pr-db db w opts)) - IEmptyableCollection (-empty [_] (throw (js/Error. "-empty is not supported on FilteredDB"))) IEmptyableCollection (-empty [_] (throw (js/Error. "-empty is not supported on FilteredDB"))) ILookup (-lookup ([_ _] (throw (js/Error. "-lookup is not supported on FilteredDB"))) ([_ _ _] (throw (js/Error. "-lookup is not supported on FilteredDB")))) - IAssociative (-contains-key? [_ _] (throw (js/Error. "-contains-key? is not supported on FilteredDB"))) + IAssociative + (-contains-key? [_ _] (throw (js/Error. "-contains-key? is not supported on FilteredDB"))) (-assoc [_ _ _] (throw (js/Error. "-assoc is not supported on FilteredDB")))] :clj @@ -435,13 +433,13 @@ ICounted (-count [db] (count (dbi/datoms db :eavt []))) IPrintWithWriter (-pr-writer [db w opts] (pr-db db w opts)) - IEmptyableCollection (-empty [_] (throw (js/Error. "-empty is not supported on HistoricalDB"))) IEmptyableCollection (-empty [_] (throw (js/Error. "-empty is not supported on HistoricalDB"))) ILookup (-lookup ([_ _] (throw (js/Error. "-lookup is not supported on HistoricalDB"))) ([_ _ _] (throw (js/Error. "-lookup is not supported on HistoricalDB")))) - IAssociative (-contains-key? [_ _] (throw (js/Error. "-contains-key? is not supported on HistoricalDB"))) + IAssociative + (-contains-key? [_ _] (throw (js/Error. "-contains-key? is not supported on HistoricalDB"))) (-assoc [_ _ _] (throw (js/Error. "-assoc is not supported on HistoricalDB")))] :clj [IPersistentCollection @@ -501,13 +499,13 @@ ICounted (-count [db] (count (dbi/datoms db :eavt []))) IPrintWithWriter (-pr-writer [db w opts] (pr-db db w opts)) - IEmptyableCollection (-empty [_] (throw (js/Error. "-empty is not supported on AsOfDB"))) IEmptyableCollection (-empty [_] (throw (js/Error. "-empty is not supported on AsOfDB"))) ILookup (-lookup ([_ _] (throw (js/Error. "-lookup is not supported on AsOfDB"))) ([_ _ _] (throw (js/Error. "-lookup is not supported on AsOfDB")))) - IAssociative (-contains-key? [_ _] (throw (js/Error. "-contains-key? is not supported on AsOfDB"))) + IAssociative + (-contains-key? [_ _] (throw (js/Error. "-contains-key? is not supported on AsOfDB"))) (-assoc [_ _ _] (throw (js/Error. "-assoc is not supported on AsOfDB")))] :clj [IPersistentCollection @@ -568,13 +566,13 @@ ICounted (-count [db] (count (dbi/datoms db :eavt []))) IPrintWithWriter (-pr-writer [db w opts] (pr-db db w opts)) - IEmptyableCollection (-empty [_] (throw (js/Error. "-empty is not supported on SinceDB"))) IEmptyableCollection (-empty [_] (throw (js/Error. "-empty is not supported on SinceDB"))) ILookup (-lookup ([_ _] (throw (js/Error. "-lookup is not supported on SinceDB"))) ([_ _ _] (throw (js/Error. "-lookup is not supported on SinceDB")))) - IAssociative (-contains-key? [_ _] (throw (js/Error. "-contains-key? is not supported on SinceDB"))) + IAssociative + (-contains-key? [_ _] (throw (js/Error. "-contains-key? is not supported on SinceDB"))) (-assoc [_ _ _] (throw (js/Error. "-assoc is not supported on SinceDB")))] :clj [IPersistentCollection @@ -872,9 +870,6 @@ :temporal-aevt aevt :temporal-avet avet})))))) -(defn get-max-tx [eavt] - (transduce (map (fn [^Datom d] (datom-tx d))) max tx0 (di/-all eavt))) - (defn ^DB init-db ([datoms] (init-db datoms nil nil nil)) ([datoms schema] (init-db datoms schema nil nil)) diff --git a/src/datahike/db/search.cljc b/src/datahike/db/search.cljc index 4789d374b..bad164f2f 100644 --- a/src/datahike/db/search.cljc +++ b/src/datahike/db/search.cljc @@ -1,6 +1,8 @@ (ns datahike.db.search + #?(:cljs (:require-macros [datahike.db.search :refer [lookup-strategy]])) (:require - [clojure.core.cache.wrapped :as cw] + #?(:clj [clojure.core.cache.wrapped :as cw] + :cljs [cljs.cache.wrapped :as cw]) [datahike.array :refer [a=]] [datahike.constants :refer [e0 tx0 emax txmax]] [datahike.datom :refer [datom datom-tx datom-added type-hint-datom]] diff --git a/src/datahike/db/transaction.cljc b/src/datahike/db/transaction.cljc index 5c9fbf3dc..6d9fe2bc2 100644 --- a/src/datahike/db/transaction.cljc +++ b/src/datahike/db/transaction.cljc @@ -14,9 +14,10 @@ [me.tonsky.persistent-sorted-set.arrays :as arrays]) #?(:cljs (:require-macros [datahike.datom :refer [datom]] [datahike.tools :refer [raise]])) - #?(:clj (:import [java.util Date] + #?(:clj (:import [clojure.lang ExceptionInfo] [datahike.datom Datom] - [datahike.db HistoricalDB]))) + [datahike.db HistoricalDB] + [java.util Date]))) (defn validate-datom [db ^Datom datom] (when (and (datom-added datom) @@ -135,8 +136,7 @@ (if-not (schema v-ident) (let [err-msg (str "Schema with attribute " v-ident " does not exist") err-map {:error :retract/schema :attribute v-ident}] - (throw #?(:clj (ex-info err-msg err-map) - :cljs (error err-msg err-map)))) + (throw (ex-info err-msg err-map))) (-> (assoc-in db [:schema e] (dissoc (schema v-ident) a-ident)) (update-in [:schema] #(dissoc % v-ident)) (update-in [:ident-ref-map] #(dissoc % v-ident)) @@ -147,8 +147,7 @@ (update-in db [:schema e] #(dissoc % a-ident v-ident))) (let [err-msg (str "Schema with entity id " e " does not exist") err-map {:error :retract/schema :entity-id e :attribute a :value e}] - (throw #?(:clj (ex-info err-msg err-map) - :cljs (error err-msg err-map)))))))) + (throw (ex-info err-msg err-map))))))) ;; In context of `with-datom` we can use faster comparators which ;; do not check for nil (~10-15% performance gain in `transact`) @@ -250,7 +249,7 @@ ;; Optimistic removal of the schema entry (because we don't know whether it is already present or not) schema? (try (-> db (remove-schema datom) update-rschema) - (catch clojure.lang.ExceptionInfo _e + (catch ExceptionInfo _e db)) keep-history? (update-in [:temporal-eavt] #(di/-temporal-upsert % datom :eavt op-count old-datom)) @@ -444,12 +443,14 @@ (transact-tx-data report' es)))) (defn assert-preds [db [_ e _ preds]] - (reduce - (fn [coll pred] - (if ((resolve pred) db e) - coll - (conj coll pred))) - #{} preds)) + #?(:cljs (throw (ex-info "tx predicate resolution is not supported in cljs at this time" {:e e :preds preds})) + :clj + (reduce + (fn [coll pred] + (if ((resolve pred) db e) + coll + (conj coll pred))) + #{} preds))) (def builtin-op? #{:db.fn/call diff --git a/src/datahike/gc.cljc b/src/datahike/gc.cljc index 2791df98e..2ced82e48 100644 --- a/src/datahike/gc.cljc +++ b/src/datahike/gc.cljc @@ -7,7 +7,7 @@ [superv.async :refer [Entity equiv-entity lookup-entity touch) @@ -46,7 +46,7 @@ (defn- js-seq [e] (touch e) (for [[a v] @(.-cache e)] - (if (db/multival? (.-db e) a) + (if (dbu/multival? (.-db e) a) [a (multival->js v)] [a v])))) @@ -60,7 +60,7 @@ ;; js/map interface (keys [this] - (es6-iterator (c/keys this))) + (es6-iterator (cljs.core/keys this))) (entries [this] (es6-entries-iterator (js-seq this))) (values [this] @@ -83,7 +83,7 @@ (.call f use-as-this v a this))) ;; js fallbacks - (key_set [this] (to-array (c/keys this))) + (key_set [this] (to-array (cljs.core/keys this))) (entry_set [this] (to-array (map to-array (js-seq this)))) (value_set [this] (to-array (map second (js-seq this)))) diff --git a/src/datahike/index.cljc b/src/datahike/index.cljc index 5c5516286..cc271f632 100644 --- a/src/datahike/index.cljc +++ b/src/datahike/index.cljc @@ -1,7 +1,8 @@ (ns ^:no-doc datahike.index + (:refer-clojure :exclude [-persistent! -flush -count -seq]) (:require [datahike.index.interface :as di] [datahike.index.persistent-set] - [datahike.index.hitchhiker-tree])) + #?(:clj [datahike.index.hitchhiker-tree]))) ;; Aliases for protocol functions diff --git a/src/datahike/index/interface.cljc b/src/datahike/index/interface.cljc index 0e89e77c4..66e2a31ee 100644 --- a/src/datahike/index/interface.cljc +++ b/src/datahike/index/interface.cljc @@ -1,5 +1,6 @@ (ns datahike.index.interface - "All the functions in this namespace must be implemented for each index type") + "All the functions in this namespace must be implemented for each index type" + #?(:cljs (:refer-clojure :exclude [-seq -count -persistent! -flush]))) (defprotocol IIndex (-all [index] "Returns a sequence of all datoms in the index") diff --git a/src/datahike/index/persistent_set.cljc b/src/datahike/index/persistent_set.cljc index 2c16931c3..0337443bb 100644 --- a/src/datahike/index/persistent_set.cljc +++ b/src/datahike/index/persistent_set.cljc @@ -1,8 +1,11 @@ (ns ^:no-doc datahike.index.persistent-set + #?(:cljs (:require-macros [datahike.index.persistent-set :refer [generate-slice-comparator-constructor]])) (:require [me.tonsky.persistent-sorted-set :as psset] [me.tonsky.persistent-sorted-set.arrays :as arrays] - [clojure.core.cache :as cache] - [clojure.core.cache.wrapped :as wrapped] + #?@(:clj [[clojure.core.cache :as cache] + [clojure.core.cache.wrapped :as wrapped]] + :cljs [[cljs.cache :as cache] + [cljs.cache.wrapped :as wrapped]]) [datahike.datom :as dd :refer [index-type->cmp-quick]] [datahike.constants :refer [tx0 txmax]] [datahike.index.interface :as di :refer [IIndex]] @@ -162,7 +165,7 @@ (psset/walk-addresses pset (fn [address] (swap! addresses conj address))) @addresses)) -(extend-type PersistentSortedSet +(extend-type #?(:clj PersistentSortedSet :cljs psset/BTSet) IIndex (-slice [^PersistentSortedSet pset from to index-type] (psset/slice pset from to (slice-comparator-constructor index-type from to))) @@ -268,10 +271,11 @@ ;; temporary import from psset until public (defn- map->settings ^Settings [m] - (Settings. - (int (or (:branching-factor m) 0)) - nil ;; weak ref default - )) + #?(:cljs m + :clj (Settings. + (int (or (:branching-factor m) 0)) + nil ;; weak ref default + ))) (defmethod di/add-konserve-handlers :datahike.index/persistent-set [config store] ;; deal with circular reference between storage and store diff --git a/src/datahike/integration_test.cljc b/src/datahike/integration_test.cljc index fadbf2277..dd73739e4 100644 --- a/src/datahike/integration_test.cljc +++ b/src/datahike/integration_test.cljc @@ -1,8 +1,7 @@ (ns ^:no-doc datahike.integration-test "This namespace is the minimum test a Datahike backend needs to pass for compatibility assessment." - (:require [datahike.api :as d] - #?(:clj [clojure.test :refer :all] - :cljs [cljs.test :refer :all :include-macros true]))) + (:require [clojure.test :refer [is]] + [datahike.api :as d])) (defn integration-test-fixture [config] (d/delete-database config) diff --git a/src/datahike/lru.cljc b/src/datahike/lru.cljc index 6eb5d3328..9d07275e3 100644 --- a/src/datahike/lru.cljc +++ b/src/datahike/lru.cljc @@ -1,6 +1,7 @@ (ns ^:no-doc datahike.lru - (:require [clojure.core.cache :refer [defcache CacheProtocol]] - clojure.data.priority-map)) + (:require [#?(:clj clojure.core.cache :cljs cljs.cache) :refer [defcache CacheProtocol]] + #?(:clj clojure.data.priority-map + :cljs tailrecursion.priority-map))) (declare assoc-lru cleanup-lru) @@ -119,7 +120,8 @@ this)) (seed [_ base] (LRUDatomCache. base - (into (clojure.data.priority-map/priority-map) + (into #?(:clj (clojure.data.priority-map/priority-map) + :cljs (tailrecursion.priority-map/priority-map)) (map #(vector % 0) (keys base))) (into {} @@ -140,4 +142,5 @@ [base & {threshold :threshold :or {threshold 32}}] {:pre [(number? threshold) (< 0 threshold) (map? base)]} - (atom (clojure.core.cache/seed (LRUDatomCache. {} (clojure.data.priority-map/priority-map) {} 0 0 threshold) base))) + #?(:clj (atom (clojure.core.cache/seed (LRUDatomCache. {} (clojure.data.priority-map/priority-map) {} 0 0 threshold) base)) + :cljs (atom (cljs.cache/seed (LRUDatomCache. {} (tailrecursion.priority-map/priority-map) {} 0 0 threshold) base)))) diff --git a/src/datahike/middleware/utils.cljc b/src/datahike/middleware/utils.cljc index 5d5c56660..203d3aaa8 100644 --- a/src/datahike/middleware/utils.cljc +++ b/src/datahike/middleware/utils.cljc @@ -3,10 +3,13 @@ (defn apply-middlewares "Combines a list of middleware functions into one." [middlewares handler] - (reduce - (fn [acc f-sym] - (if-let [f (resolve f-sym)] - (f acc) - (throw (ex-info "Invalid middleware.😱" {:fn f-sym})))) - handler - middlewares)) + #?(:cljs (throw (ex-info "middleware resolution is not supported in cljs at this time" {:middlewares middlewares + :handler handler})) + :clj + (reduce + (fn [acc f-sym] + (if-let [f (resolve f-sym)] + (f acc) + (throw (ex-info "Invalid middleware.😱" {:fn f-sym})))) + handler + middlewares))) diff --git a/src/datahike/pull_api.cljc b/src/datahike/pull_api.cljc index 90b6cf9fb..7d7bd7730 100644 --- a/src/datahike/pull_api.cljc +++ b/src/datahike/pull_api.cljc @@ -2,8 +2,7 @@ (:require [datahike.db.utils :as dbu] [datahike.db.interface :as dbi] - [datalog.parser.pull :as dpp]) - #?@(:cljs [datalog.parser.pull :refer [PullSpec]]) + [datalog.parser.pull :as dpp #?@(:cljs [:refer [PullSpec]])]) #?(:clj (:import [datahike.datom Datom] diff --git a/src/datahike/query.cljc b/src/datahike/query.cljc index 73a3527c4..67314880c 100644 --- a/src/datahike/query.cljc +++ b/src/datahike/query.cljc @@ -1,4 +1,5 @@ (ns ^:no-doc datahike.query + #?(:cljs (:require-macros [datahike.query :refer [basic-index-selector make-vec-lookup-ref-replacer some-of substitution-expansion]])) (:require [#?(:cljs cljs.reader :clj clojure.edn) :as edn] [clojure.set :as set] @@ -32,7 +33,7 @@ [java.lang.reflect Method] [java.util Date Map HashSet HashSet]))) -(set! *warn-on-reflection* true) +#?(:clj (set! *warn-on-reflection* true)) ;; ---------------------------------------------------------------------------- @@ -312,7 +313,7 @@ true (map vector (cons x more) more)) :cljs (apply >= x more))) - Object ;; default + #?(:clj Object :cljs object) ;; default (-strictly-decreasing? [x more] (reduce (fn [res [v1 s2]] (if (neg? (compare v1 s2)) res (reduced false))) @@ -1162,8 +1163,8 @@ (fn [x] (contains? s x)))) (defn extend-predicate [predicate feature-extractor features] - {:pre [(or (set? features) - (instance? HashSet features))]} + {:pre [#?(:clj (or (set? features) (instance? HashSet features)) + :cljs (set? features))]} (let [this-pred (predicate-from-set features)] (if (nil? feature-extractor) predicate @@ -1302,7 +1303,10 @@ (defmacro make-vec-lookup-ref-replacer [range-length] (let [inds (gensym) replacer (gensym) - tuple (gensym)] + tuple (gensym) + ex-sym# (if (get-in &env [:ns]) + 'js/Error + Exception)] `(fn tree-fn# [~replacer ~inds] ~(dt/range-subset-tree range-length inds @@ -1312,7 +1316,7 @@ ~(mapv (fn [index i] `(~replacer ~index (nth ~tuple ~i))) pinds (range)) - (catch Exception e# nil)))))))) + (catch ~ex-sym# e# nil)))))))) (def vec-lookup-ref-replacer (make-vec-lookup-ref-replacer 5)) @@ -1514,7 +1518,7 @@ step) datoms (try (backend-fn e a v tx added?) - (catch Exception e + (catch #?(:clj Exception :cljs js/Error) e (throw e)))] (reduce inner-step dst diff --git a/src/datahike/query_stats.cljc b/src/datahike/query_stats.cljc index dd1ab1fc0..ecaec3442 100644 --- a/src/datahike/query_stats.cljc +++ b/src/datahike/query_stats.cljc @@ -2,8 +2,8 @@ (:require [clojure.set :as set] [datahike.tools :as dt])) -(defn round [^long precision ^java.math.BigDecimal x] - #?(:clj (with-precision precision x) +(defn round [precision x] + #?(:clj (with-precision ^long precision ^java.math.BigDecimal x) :cljs (let [y (Math/pow 10 precision)] (/ (.round js/Math (* y x)) y)))) diff --git a/src/datahike/readers.cljc b/src/datahike/readers.cljc index 80344baa5..e81e31ad3 100644 --- a/src/datahike/readers.cljc +++ b/src/datahike/readers.cljc @@ -2,6 +2,7 @@ (:require [datahike.connections :refer [get-connection *connections*]] [datahike.writing :as dw] [datahike.datom :refer [datom] :as dd] + #?(:cljs [datahike.db :refer [HistoricalDB AsOfDB SinceDB]]) [datahike.impl.entity :as de] [datahike.core :refer [init-db] :as dc] [datahike.tools :refer [raise]] diff --git a/src/datahike/schema.cljc b/src/datahike/schema.cljc index 50cbd82b0..e3c488987 100644 --- a/src/datahike/schema.cljc +++ b/src/datahike/schema.cljc @@ -1,21 +1,31 @@ (ns ^:no-doc datahike.schema (:require [clojure.spec.alpha :as s] [datahike.datom]) - (:import [datahike.datom Datom])) + #?(:clj (:import [datahike.datom Datom]))) -(s/def :db.type/id #(or (= (class %) java.lang.Long) string?)) +(s/def :db.type/id #?(:clj #(or (= (class %) java.lang.Long) string?) + :cljs #(or (and (number? %) + (js/Number.isSafeInteger %)) + string?))) ;; db types -(s/def :db.type/bigdec decimal?) -(s/def :db.type/bigint integer?) +(s/def :db.type/bigdec #?(:cljs (complement any?) ; feels more appropriate than hiding key -pat + :clj decimal?)) +(s/def :db.type/bigint #?(:clj integer? + :cljs #(or (integer? %) + (= js/BigInt (type %))))) (s/def :db.type/boolean boolean?) -(s/def :db.type/bytes bytes?) +(s/def :db.type/bytes #?(:clj bytes? + :cljs #(and (some->> (.-buffer %) (instance? js/ArrayBuffer)) + (some->> (.-byteLength %) (number?))))) (s/def :db.type/double double?) (s/def :db.type/float float?) (s/def :db.type/number number?) -(s/def :db.type/instant #(= (class %) java.util.Date)) +(s/def :db.type/instant #?(:clj #(= (class %) java.util.Date) + :cljs inst?)) (s/def :db.type/keyword keyword?) -(s/def :db.type/long #(= (class %) java.lang.Long)) +(s/def :db.type/long #?(:clj #(= (class %) java.lang.Long) + :cljs #(js/Number.isSafeInteger %))) (s/def :db.type/ref :db.type/id) (s/def :db.type/string string?) (s/def :db.type/symbol symbol?) diff --git a/src/datahike/schema_cache.cljc b/src/datahike/schema_cache.cljc index 234d1385d..9e3ac9df2 100644 --- a/src/datahike/schema_cache.cljc +++ b/src/datahike/schema_cache.cljc @@ -1,5 +1,6 @@ (ns datahike.schema-cache - (:require [clojure.core.cache.wrapped :as cw] + (:require #?(:clj [clojure.core.cache.wrapped :as cw] + :cljs [cljs.cache.wrapped :as cw]) [datahike.config :as dc] [datahike.store :as ds])) diff --git a/src/datahike/store.cljc b/src/datahike/store.cljc index 573c8d6c2..858e6131c 100644 --- a/src/datahike/store.cljc +++ b/src/datahike/store.cljc @@ -1,12 +1,13 @@ (ns ^:no-doc datahike.store (:require [clojure.spec.alpha :as s] - [konserve.filestore :as fs] + #?(:clj [konserve.filestore :as fs]) [konserve.memory :as mem] [environ.core :refer [env]] [datahike.index :as di] [datahike.tools :as dt] [konserve.cache :as kc] - [clojure.core.cache :as cache] + #?(:clj [clojure.core.cache :as cache] + :cljs [cljs.cache :as cache]) [taoensso.timbre :refer [info]] [zufall.core :refer [rand-german-mammal]]) #?(:clj (:import [java.nio.file Paths]))) @@ -29,7 +30,7 @@ :backend) (defmethod empty-store :default [{:keys [backend]}] - (throw (IllegalArgumentException. (str "Can't create a store with scheme: " backend)))) + (throw (#?(:clj IllegalArgumentException. :cljs js/Error.) (str "Can't create a store with scheme: " backend)))) (defmulti delete-store "Deletes an existing store" @@ -37,7 +38,7 @@ :backend) (defmethod delete-store :default [{:keys [backend]}] - (throw (IllegalArgumentException. (str "Can't delete a store with scheme: " backend)))) + (throw (#?(:clj IllegalArgumentException. :cljs js/Error.) (str "Can't delete a store with scheme: " backend)))) (defmulti connect-store "Makes a connection to an existing store" @@ -45,7 +46,7 @@ :backend) (defmethod connect-store :default [{:keys [backend]}] - (throw (IllegalArgumentException. (str "Can't connect to store with scheme: " backend)))) + (throw (#?(:clj IllegalArgumentException. :cljs js/Error.) (str "Can't connect to store with scheme: " backend)))) (defmulti release-store "Releases the connection to an existing store (optional)." @@ -109,33 +110,38 @@ (defmethod config-spec :mem [_config] ::mem) ;; file - -(defmethod store-identity :file [config] - [:file (:scope config) (:path config)]) - -(defmethod empty-store :file [{:keys [path config]}] - (fs/connect-fs-store path :opts {:sync? true} :config config)) - -(defmethod delete-store :file [{:keys [path]}] - (fs/delete-store path)) - -(defmethod connect-store :file [{:keys [path config]}] - (fs/connect-fs-store path :opts {:sync? true} :config config)) - -(defn- get-working-dir [] - (.toString (.toAbsolutePath (Paths/get "" (into-array String []))))) - -(defmethod default-config :file [config] - (merge - {:path (:datahike-store-path env (str (get-working-dir) "/datahike-db-" (rand-german-mammal))) - :scope (dt/get-hostname)} - config)) - -(s/def :datahike.store.file/path string?) -(s/def :datahike.store.file/backend #{:file}) -(s/def :datahike.store.file/scope string?) -(s/def ::file (s/keys :req-un [:datahike.store.file/backend - :datahike.store.file/path - :datahike.store.file/scope])) - -(defmethod config-spec :file [_] ::file) +#?(:clj + (defmethod store-identity :file [config] + [:file (:scope config) (:path config)])) + +#?(:clj + (defmethod empty-store :file [{:keys [path config]}] + (fs/connect-fs-store path :opts {:sync? true} :config config))) + +#?(:clj + (defmethod delete-store :file [{:keys [path]}] + (fs/delete-store path))) + +#?(:clj + (defmethod connect-store :file [{:keys [path config]}] + (fs/connect-fs-store path :opts {:sync? true} :config config))) + +#?(:clj + (defn- get-working-dir [] + (.toString (.toAbsolutePath (Paths/get "" (into-array String [])))))) + +#?(:clj + (defmethod default-config :file [config] + (merge + {:path (:datahike-store-path env (str (get-working-dir) "/datahike-db-" (rand-german-mammal))) + :scope (dt/get-hostname)} + config))) + +#?(:clj (s/def :datahike.store.file/path string?)) +#?(:clj (s/def :datahike.store.file/backend #{:file})) +#?(:clj (s/def :datahike.store.file/scope string?)) +#?(:clj (s/def ::file (s/keys :req-un [:datahike.store.file/backend + :datahike.store.file/path + :datahike.store.file/scope]))) + +#?(:clj (defmethod config-spec :file [_] ::file)) diff --git a/src/datahike/tools.cljc b/src/datahike/tools.cljc index 20256056e..10a0b70ab 100644 --- a/src/datahike/tools.cljc +++ b/src/datahike/tools.cljc @@ -1,4 +1,5 @@ (ns ^:no-doc datahike.tools + #?(:cljs (:require-macros [datahike.tools :refer [raise]])) (:require [superv.async :refer [throw-if-exception-]] [clojure.core.async.impl.protocols :as async-impl] @@ -68,8 +69,7 @@ (let [msgs (butlast fragments) data (last fragments)] (list `(log/log! :error :p ~fragments ~{:?line (:line (meta &form))}) - `(throw #?(:clj (ex-info (str ~@(map (fn [m#] (if (string? m#) m# (list 'pr-str m#))) msgs)) ~data) - :cljs (error (str ~@(map (fn [m#] (if (string? m#) m# (list 'pr-str m#))) msgs)) ~data)))))) + `(throw (ex-info (str ~@(map (fn [m#] (if (string? m#) m# (list 'pr-str m#))) msgs)) ~data))))) ;; adapted from https://clojure.atlassian.net/browse/CLJ-2766 #?(:clj @@ -128,8 +128,8 @@ :konserve/version konserve-version :hitchhiker.tree/version hitchhiker-tree-version :persistent.set/version persistent-set-version - :datahike/id (UUID/randomUUID) - :datahike/created-at (Date.)}) + :datahike/id #?(:clj (UUID/randomUUID) :cljs (random-uuid)) + :datahike/created-at #?(:clj (Date.) :cljs (js/Date.))}) (defn deep-merge "Recursively merges maps together. If all the maps supplied have nested maps @@ -169,9 +169,9 @@ (defn get-hostname [] #?(:clj (.getHostAddress (InetAddress/getLocalHost)) - :cljs (raise "Not supported yet." {:type :hostname-not-supported-yet}))) + :cljs "" #_(raise "Not supported." {:type :hostname-not-supported}))) -(def datahike-logo (slurp (io/resource "datahike-logo.txt"))) +#?(:clj (def datahike-logo (slurp (io/resource "datahike-logo.txt")))) (defmacro with-destructured-vector [v & var-expr-pairs] {:pre [(even? (count var-expr-pairs))]} diff --git a/src/datahike/writer.cljc b/src/datahike/writer.cljc index b0a14742d..1d4ef3153 100644 --- a/src/datahike/writer.cljc +++ b/src/datahike/writer.cljc @@ -5,8 +5,9 @@ [datahike.writing :as w] [datahike.gc :as gc] [datahike.tools :as dt :refer [throwable-promise get-time-ms]] - [clojure.core.async :refer [chan close! promise-chan put! go go-loop ! poll! buffer timeout]]) - (:import [clojure.core.async.impl.channels ManyToManyChannel])) + [clojure.core.async :refer [chan close! promise-chan put! go go-loop ! poll! buffer timeout]] + #?(:cljs [cljs.core.async.impl.channels :refer [ManyToManyChannel]])) + #?(:clj (:import [clojure.core.async.impl.channels ManyToManyChannel]))) (defn chan? [x] (instance? ManyToManyChannel x)) @@ -43,7 +44,7 @@ commit-queue-buffer (buffer commit-queue-size) commit-queue (chan commit-queue-buffer)] [transaction-queue commit-queue - (thread-try + (#?(:clj thread-try :cljs try) S (do ;; processing loop @@ -68,18 +69,20 @@ (apply op-fn old args) ;; Only catch ExceptionInfo here (intentionally rejected transactions). ;; Any other exceptions should crash the writer and signal the supervisor. - (catch Exception e + (catch #?(:clj Exception :cljs js/Error) e (log/error "Error during invocation" invocation e args) ;; take a guess that a NPE was triggered by an invalid connection ;; short circuit on errors - (put! callback - (if (= (type e) NullPointerException) - (ex-info "Null pointer encountered in invocation. Connection may have been invalidated, e.g. through db deletion, and needs to be released everywhere." - {:type :writer-error-during-invocation - :invocation invocation - :connection connection - :error e}) - e)) + #?(:cljs (put! callback e) + :clj + (put! callback + (if (= (type e) NullPointerException) + (ex-info "Null pointer encountered in invocation. Connection may have been invalidated, e.g. through db deletion, and needs to be released everywhere." + {:type :writer-error-during-invocation + :invocation invocation + :connection connection + :error e}) + e))) :error))] (cond (chan? res) ;; async op, run in parallel in background, no sequential commit handling needed @@ -123,7 +126,7 @@ (assoc-in [:tx-meta :db/commitId] commit-id) (assoc :db-after commit-db))] (put! callback tx-report)))) - (catch Exception e + (catch #?(:clj Exception :cljs js/Error) e (doseq [[_ callback] txs] (put! callback e)) (log/error "Writer thread shutting down because of commit error." e) @@ -178,14 +181,14 @@ (defmethod create-database :self [& args] (let [p (throwable-promise)] - (deliver p (apply w/create-database args)) + (#?(:clj deliver :cljs put!) p (apply w/create-database args)) p)) (defmulti delete-database backend-dispatch) (defmethod delete-database :self [& args] (let [p (throwable-promise)] - (deliver p (apply w/delete-database args)) + (#?(:clj deliver :cljs put!) p (apply w/delete-database args)) p)) (defn transact! @@ -199,7 +202,7 @@ (when (map? tx-report) ;; not error (doseq [[_ callback] (some-> (:listeners (meta connection)) (deref))] (callback tx-report))) - (deliver p tx-report))) + (#?(:clj deliver :cljs put!) p tx-report))) p)) (defn load-entities [connection entities] @@ -209,7 +212,7 @@ (let [tx-report (config uri) opts)) + #?(:clj String :cljs string) + (-create-database #?(:clj [uri & opts] :cljs [uri opts]) + (-create-database (dc/uri->config uri) opts)) (-delete-database [uri] (-delete-database (dc/uri->config uri))) @@ -189,7 +195,7 @@ (-database-exists? [uri] (-database-exists? (dc/uri->config uri))) - clojure.lang.IPersistentMap + #?(:clj clojure.lang.IPersistentMap :cljs PersistentArrayMap) (-database-exists? [config] (let [config (dc/load-config config) store-config (:store config) @@ -203,7 +209,7 @@ (ds/release-store store-config raw-store) false)))) - (-create-database [config & deprecated-config] + (-create-database [config deprecated-config] (let [{:keys [keep-history?] :as config} (dc/load-config config deprecated-config) store-config (:store config) store (ds/add-cache-and-handlers (ds/empty-store store-config) config) diff --git a/test/datahike/cljs_compilation_test.cljs b/test/datahike/cljs_compilation_test.cljs new file mode 100644 index 000000000..42f4a6d21 --- /dev/null +++ b/test/datahike/cljs_compilation_test.cljs @@ -0,0 +1,45 @@ +(ns datahike.cljs-compilation-test + (:require [clojure.test :refer [deftest is] :as t] + [datahike.api :as d] + datahike.api.impl + datahike.api.specification + datahike.array + datahike.config + datahike.connector + datahike.connections + datahike.constants + datahike.core + datahike.datom + datahike.db + datahike.db.interface + datahike.db.search + datahike.db.transaction + datahike.db.utils + datahike.gc + datahike.impl.entity + datahike.index + datahike.index.interface + datahike.index.persistent-set + datahike.index.utils + datahike.integration-test + datahike.lru + datahike.middleware.utils + datahike.pull-api + datahike.query + datahike.readers + datahike.schema + datahike.schema-cache + datahike.spec + datahike.store + datahike.transit + datahike.tools + datahike.writing + datahike.writer)) + +(deftest sanity-test + (is (fn? d/q))) + +;clj -M:cljs -m shadow.cljs.devtools.cli compile :comptest && node target/out/comptest.js +(defn -main [] + (let [summary (clojure.test/run-tests)] + (js/process.exit (if (t/successful? summary) 0 1)))) \ No newline at end of file From 2da3900add18bea4cc7af4940cf7267f45de7cb8 Mon Sep 17 00:00:00 2001 From: pat killean Date: Wed, 11 Dec 2024 17:17:31 -0400 Subject: [PATCH 2/2] cljs-cache via mvn --- deps.edn | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/deps.edn b/deps.edn index b7b7dce2f..053e40612 100644 --- a/deps.edn +++ b/deps.edn @@ -20,9 +20,7 @@ mvxcvi/clj-cbor {:mvn/version "1.1.1"} org.babashka/http-client {:mvn/version "0.3.11"} metosin/jsonista {:mvn/version "0.3.7"} - pkpkpk/cljs-cache {:git/url "https://github.com/pkpkpk/cljs-cache" - :git/tag "datahike-fix" - :git/sha "a0e7298fb90daadbf4dcf12ae996396e68cb1f3e"}} + com.github.pkpkpk/cljs-cache {:mvn/version "1.0.21"}} :paths ["src" "target/classes" "resources"]