From d07b34b850b2ab381ae258771a4a56c84a5f53c6 Mon Sep 17 00:00:00 2001 From: max Date: Wed, 15 Jul 2026 11:15:42 +0200 Subject: [PATCH 1/4] Drop `clojure.data/diff`; remove dead code and unused dependencies. Mirrors the dbval minimalism pass: - `clojure.data/diff` would have to realize both databases entirely in memory; the `Diff` extension now throws an informative exception (and is kept only so diff does not fall back to diffing the record fields). Its comparators were also silently broken: they still compared UUID entity ids with `Integer/compare`. - Remove `query_v3`, the datom comparators (`cmp-datoms-*`, `defcomp`, `combine-cmp`, `diff-sorted`, `cmp`, `value-cmp`), `case-tree`/ `case-pick`/`vpred`, the dead `-search` bindings, the mutable `idx` field on `Datom`, and the broken `core/settings`. - Drop `nippy` (never used) and `persistent-sorted-set` (its array helpers are now the tiny `slateval.arrays` namespace). - `empty-db` docstring now documents `:db-file`/`:object-store-url` instead of persistent-sorted-set options. Co-Authored-By: Claude Fable 5 --- deps.edn | 4 +- src/slateval/arrays.clj | 19 + src/slateval/core.cljc | 17 +- src/slateval/db.cljc | 218 +------ src/slateval/pull_api.cljc | 3 +- src/slateval/query.cljc | 2 +- src/slateval/query_v3.cljc | 975 ------------------------------- test/slateval/test.cljc | 1 - test/slateval/test/db.cljc | 22 +- test/slateval/test/issues.cljc | 17 +- test/slateval/test/query_v3.cljc | 23 - 11 files changed, 60 insertions(+), 1241 deletions(-) create mode 100644 src/slateval/arrays.clj delete mode 100644 src/slateval/query_v3.cljc delete mode 100644 test/slateval/test/query_v3.cljc diff --git a/deps.edn b/deps.edn index 66acd8d..82a52e6 100644 --- a/deps.edn +++ b/deps.edn @@ -1,8 +1,6 @@ {:deps - {persistent-sorted-set/persistent-sorted-set {:mvn/version "0.3.0"} - io.github.tonsky/extend-clj {:mvn/version "0.1.0"} + {io.github.tonsky/extend-clj {:mvn/version "0.1.0"} org.foundationdb/fdb-java {:mvn/version "7.3.47"} - com.taoensso/nippy {:mvn/version "3.6.0"} io.slatedb/slatedb-uniffi {:mvn/version "0.14.1"} com.yetanalytics/colossal-squuid {:mvn/version "0.1.5" :exclusions diff --git a/src/slateval/arrays.clj b/src/slateval/arrays.clj new file mode 100644 index 0000000..534a34d --- /dev/null +++ b/src/slateval/arrays.clj @@ -0,0 +1,19 @@ +(ns ^:no-doc slateval.arrays + "Object-array helpers. Replaces me.tonsky.persistent-sorted-set.arrays, + which was slateval's last use of the persistent-sorted-set library." + (:refer-clojure :exclude [array? make-array aget aset aclone])) + +(defn array? [x] + (some-> ^Object x class .isArray)) + +(defn make-array ^objects [n] + (object-array n)) + +(defn aget [^objects a ^long i] + (clojure.core/aget a i)) + +(defn aset [^objects a ^long i v] + (clojure.core/aset a i v)) + +(defn aclone ^objects [^objects a] + (clojure.core/aclone a)) diff --git a/src/slateval/core.cljc b/src/slateval/core.cljc index 46acc2b..62fb409 100644 --- a/src/slateval/core.cljc +++ b/src/slateval/core.cljc @@ -9,8 +9,7 @@ [slateval.query :as dq] [slateval.impl.entity :as de] [slateval.util :as util] - [com.yetanalytics.squuid :as squuid] - [me.tonsky.persistent-sorted-set :as set]) + [com.yetanalytics.squuid :as squuid]) #?(:clj (:import [slateval.db Datom DB FilteredDB] @@ -161,12 +160,12 @@ ``` Options are: - - :branching-factor , default 512. B-tree max node length - :ref-type :strong | :soft | :weak, default :soft. How will nodes that are already - stored on disk be referenced. Soft or weak means they might be unloaded - from memory under memory pressure and later fetched from storage again. - :storage . Will be used to store this db later with `(d/store db)`" + + :db-file Path of this database inside the object store. + Defaults to a fresh temporary path. + :object-store-url URL of the object store backing this database + (e.g. \"file:///\" or an s3:// URL). Defaults to the + local filesystem." ([] (db/empty-db nil {})) ([schema] @@ -682,5 +681,3 @@ "Returns time that was used in [[squuid]] call, in milliseconds, rounded to the closest second." util/squuid-time-millis) -(defn settings [db] - (set/settings (:eavt db))) diff --git a/src/slateval/db.cljc b/src/slateval/db.cljc index cdbf2b9..cb2e312 100644 --- a/src/slateval/db.cljc +++ b/src/slateval/db.cljc @@ -8,15 +8,13 @@ #?(:clj [slateval.inline :refer [update]]) [slateval.lru :as lru] [slateval.util :as util] - [me.tonsky.persistent-sorted-set :as set] - [me.tonsky.persistent-sorted-set.arrays :as arrays] - [taoensso.nippy :as nippy] + [slateval.arrays :as arrays] [com.yetanalytics.squuid :as squuid]) #?(:clj (:import clojure.lang.IFn$OOL java.util.concurrent.CompletableFuture [io.slatedb.uniffi Db DbBuilder ObjectStore DbIterator KeyValue WriteBatch KeyRange ScanOptions IterationOrder DurabilityLevel])) - #?(:cljs (:require-macros [slateval.db :refer [case-tree combine-cmp defn+ defcomp defrecord-updatable int-compare validate-attr validate-val]])) + #?(:cljs (:require-macros [slateval.db :refer [defn+ defrecord-updatable int-compare validate-attr validate-val]])) (:refer-clojure :exclude [seqable? #?(:clj update)])) #?(:clj (set! *warn-on-reflection* true)) @@ -182,17 +180,13 @@ (defprotocol IDatom (datom-tx [this]) - (datom-added [this]) - (datom-get-idx [this]) - (datom-set-idx [this value])) + (datom-added [this])) -(deftype Datom #?(:clj [e a v tx added ^:unsynchronized-mutable ^int idx ^:unsynchronized-mutable ^int _hash] - :cljs [e a v tx added ^:mutable ^number idx ^:mutable ^number _hash]) +(deftype Datom #?(:clj [e a v tx added ^:unsynchronized-mutable ^int _hash] + :cljs [e a v tx added ^:mutable ^number _hash]) IDatom (datom-tx [d] tx) (datom-added [d] added) - (datom-get-idx [_] idx) - (datom-set-idx [_ value] (set! idx (int value))) #?@(:cljs [IHash @@ -259,9 +253,9 @@ #?(:cljs (goog/exportSymbol "slateval.db.Datom" Datom)) (defn ^Datom datom - ([e a v] (Datom. e a v tx0 true 0 0)) - ([e a v tx] (Datom. e a v tx true 0 0)) - ([e a v tx added] (Datom. e a v tx (boolean added) 0 0))) + ([e a v] (Datom. e a v tx0 true 0)) + ([e a v tx] (Datom. e a v tx true 0)) + ([e a v tx added] (Datom. e a v tx (boolean added) 0))) (defn datom? [x] (instance? Datom x)) @@ -347,42 +341,6 @@ ;; datom cmp macros/funcs ;; -#?(:clj - (defmacro combine-cmp [& comps] - (loop [comps (reverse comps) - res (num 0)] - (if (not-empty comps) - (recur - (next comps) - `(let [c# ~(first comps)] - (if (== 0 c#) - ~res - c#))) - res)))) - -#?(:clj - (defn- -case-tree [queries variants] - (if queries - (let [v1 (take (/ (count variants) 2) variants) - v2 (drop (/ (count variants) 2) variants)] - (list 'if (first queries) - (-case-tree (next queries) v1) - (-case-tree (next queries) v2))) - (first variants)))) - -#?(:clj - (defmacro case-tree [qs vs] - (-case-tree qs vs))) - -(defn cmp - #?(:clj - {:inline - (fn [x y] - `(let [x# ~x y# ~y] - (if (nil? x#) 0 (if (nil? y#) 0 (long (compare x# y#))))))}) - ^long [x y] - (if (nil? x) 0 (if (nil? y) 0 (long (compare x y))))) - (defn class-identical? #?(:clj {:inline (fn [x y] `(identical? (class ~x) (class ~y)))}) [x y] @@ -466,128 +424,6 @@ (class-compare x y) (throw e))))) -(defn value-cmp - #?(:clj - {:inline - (fn [x y] - `(let [x# ~x y# ~y] - (if (nil? x#) 0 (if (nil? y#) 0 (value-compare x# y#)))))}) - ^long [x y] - (if (nil? x) - 0 - (if (nil? y) - 0 - (value-compare x y)))) - -;; Slower cmp-* fns allows for datom fields to be nil. -;; Such datoms come from slice method where they are used as boundary markers. - -#?(:clj - (defmacro defcomp [sym [arg1 arg2] & body] - (let [a1 (with-meta arg1 {}) - a2 (with-meta arg2 {})] - `(if-cljs - (defn ~sym [~arg1 ~arg2] - ~@body) - (def ~sym - (reify - java.util.Comparator - (compare [_# ~a1 ~a2] - (let [~arg1 ~arg1 ~arg2 ~arg2] - ~@body)) - clojure.lang.IFn - (invoke [this# ~a1 ~a2] - (.compare this# ~a1 ~a2)) - IFn$OOL - (invokePrim [this# ~a1 ~a2] - (.compare this# ~a1 ~a2)))))))) - -(defcomp cmp-datoms-eavt ^long [^Datom d1, ^Datom d2] - (combine-cmp - (int-compare (.-e d1) (.-e d2)) - (cmp (.-a d1) (.-a d2)) - (value-cmp (.-v d1) (.-v d2)) - (int-compare (datom-tx d1) (datom-tx d2)))) - -(defcomp cmp-datoms-aevt ^long [^Datom d1, ^Datom d2] - (combine-cmp - (cmp (.-a d1) (.-a d2)) - (int-compare (.-e d1) (.-e d2)) - (value-cmp (.-v d1) (.-v d2)) - (int-compare (datom-tx d1) (datom-tx d2)))) - -(defcomp cmp-datoms-avet ^long [^Datom d1, ^Datom d2] - (combine-cmp - (cmp (.-a d1) (.-a d2)) - (value-cmp (.-v d1) (.-v d2)) - (int-compare (.-e d1) (.-e d2)) - (int-compare (datom-tx d1) (datom-tx d2)))) - -;; fast versions without nil checks - -(defn- cmp-attr-quick - #?(:clj - {:inline - (fn [a1 a2] - `(long (.compareTo ~(with-meta a1 {:tag "Comparable"}) ~a2)))}) - ^long [a1 a2] - ;; either both are keywords or both are strings - #?(:cljs - (if (keyword? a1) - (-compare a1 a2) - (garray/defaultCompare a1 a2)) - :clj - (.compareTo ^Comparable a1 a2))) - -(defcomp cmp-datoms-eav-quick ^long [^Datom d1, ^Datom d2] - (combine-cmp - (int-compare (.-e d1) (.-e d2)) - (cmp-attr-quick (.-a d1) (.-a d2)) - (value-compare (.-v d1) (.-v d2)))) - -(defcomp cmp-datoms-eavt-quick ^long [^Datom d1, ^Datom d2] - (combine-cmp - (int-compare (.-e d1) (.-e d2)) - (cmp-attr-quick (.-a d1) (.-a d2)) - (value-compare (.-v d1) (.-v d2)) - (int-compare (datom-tx d1) (datom-tx d2)))) - -(defcomp cmp-datoms-aevt-quick ^long [^Datom d1, ^Datom d2] - (combine-cmp - (cmp-attr-quick (.-a d1) (.-a d2)) - (int-compare (.-e d1) (.-e d2)) - (value-compare (.-v d1) (.-v d2)) - (int-compare (datom-tx d1) (datom-tx d2)))) - -(defcomp cmp-datoms-avet-quick ^long [^Datom d1, ^Datom d2] - (combine-cmp - (cmp-attr-quick (.-a d1) (.-a d2)) - (value-compare (.-v d1) (.-v d2)) - (int-compare (.-e d1) (.-e d2)) - (int-compare (datom-tx d1) (datom-tx d2)))) - -(defn- diff-sorted [a b cmp] - (loop [only-a [] - only-b [] - both [] - a a - b b] - (cond - (empty? a) [(not-empty only-a) (not-empty (into only-b b)) (not-empty both)] - (empty? b) [(not-empty (into only-a a)) (not-empty only-b) (not-empty both)] - :else - (let [first-a (first a) - first-b (first b) - diff (try - (cmp first-a first-b) - (catch #?(:clj ClassCastException :cljs js/Error) _ - :incomparable))] - (cond - (= diff :incomparable) (recur (conj only-a first-a) (conj only-b first-b) both (next a) (next b)) - (== diff 0) (recur only-a only-b (conj both first-a) (next a) (next b)) - (< diff 0) (recur (conj only-a first-a) only-b both (next a) b) - (> diff 0) (recur only-a (conj only-b first-b) both a (next b))))))) - ;; ---------------------------------------------------------------------------- #?(:clj (declare hash-db) @@ -677,15 +513,6 @@ (update :aevt persistent!) (update :avet persistent!))) -#?(:clj - (defn vpred [v] - (cond - (string? v) (fn [x] (if (string? x) (.equals ^String v x) false)) - (int? v) (fn [x] (if (int? x) (= (long v) (long x)) false)) - (keyword? v) (fn [x] (.equals ^Object v x)) - (nil? v) (fn [x] (nil? x)) - :else (fn [x] (= v x))))) - (defn ^com.apple.foundationdb.tuple.Tuple tuple "Turns the `components` into a `com.apple.foundationdb.tuple.Tuple`." [& components] @@ -873,14 +700,6 @@ {:tuple tuple} e))))) -(defn case-pick - [case datom] - (into [] - (map (fn [component] - (get datom - (keyword component)))) - case)) - (declare slice) (defn datoms-filter @@ -1177,9 +996,6 @@ ISearch (-search [db pattern] (let [[e a v tx] pattern - pred #?(:clj (vpred v) - :cljs #(= v %)) - multival? (contains? (-attrs-by db :db.cardinality/many) a) index (pattern->order db pattern) [begin end] (apply tuple-range @@ -1310,21 +1126,13 @@ clojure.data/EqualityPartition (equality-partition [x] :slateval/db) + ;; Implemented only to throw: without this extension `clojure.data/diff` + ;; would fall back to its default map implementation and diff the DB + ;; record's fields (:conn, :max-tx, ...), silently producing nonsense. clojure.data/Diff (diff-similar [a b] - (diff-sorted (-datoms a - :eavt - nil - nil - nil - nil) - (-datoms b - :eavt - nil - nil - nil - nil) - cmp-datoms-eav-quick))) + (throw (UnsupportedOperationException. + "clojure.data/diff is not supported on slateval databases, since it would realize both databases entirely in memory")))) (defn db? [x] #?(:clj diff --git a/src/slateval/pull_api.cljc b/src/slateval/pull_api.cljc index 42830d8..c363d28 100644 --- a/src/slateval/pull_api.cljc +++ b/src/slateval/pull_api.cljc @@ -4,8 +4,7 @@ [slateval.pull-parser :as dpp] [slateval.db :as db #?@(:cljs [:refer [DB]])] [slateval.lru :as lru] - [slateval.util :as util] - [me.tonsky.persistent-sorted-set :as set]) + [slateval.util :as util]) #?(:clj (:import [clojure.lang ISeq] diff --git a/src/slateval/query.cljc b/src/slateval/query.cljc index d817d37..8a5f534 100644 --- a/src/slateval/query.cljc +++ b/src/slateval/query.cljc @@ -6,7 +6,7 @@ [clojure.walk :as walk] [slateval.built-ins :as built-ins] [slateval.db :as db] - [me.tonsky.persistent-sorted-set.arrays :as da] + [slateval.arrays :as da] [slateval.lru :as lru] [slateval.impl.entity :as de] [slateval.parser :as dp #?@(:cljs [:refer [BindColl BindIgnore BindScalar BindTuple Constant diff --git a/src/slateval/query_v3.cljc b/src/slateval/query_v3.cljc deleted file mode 100644 index ca47134..0000000 --- a/src/slateval/query_v3.cljc +++ /dev/null @@ -1,975 +0,0 @@ -(ns ^:no-doc slateval.query-v3 - (:require - [clojure.set :as set] - [slateval.built-ins :as built-ins] - [slateval.core :as d] - [slateval.db :as db] - [slateval.query :as dq] - [slateval.lru :as lru] - [me.tonsky.persistent-sorted-set.arrays :as da] - [slateval.parser :as dp #?@(:cljs [:refer [BindColl BindIgnore BindScalar BindTuple - Constant DefaultSrc Pattern RulesVar SrcVar Variable - Not Or And Predicate PlainSymbol]])] - [slateval.util :as util]) - #?(:clj - (:import - [slateval.parser - BindColl BindIgnore BindScalar BindTuple - Constant DefaultSrc Pattern RulesVar SrcVar Variable - Not Or And Predicate PlainSymbol] - [clojure.lang IReduceInit Counted] - [slateval.db Datom]))) - -(declare resolve-clauses collect-rel-xf collect-to) - -(def ^:const lru-cache-size 100) - -(defn mapa [f coll] - (to-array (map f coll))) - -(defn arange [start end] - (to-array (range start end))) - -(defn subarr [arr start end] - (da/acopy arr start end (da/make-array (- end start)) 0)) - -(defn concatv [& xs] - (into [] cat xs)) - -(defn zip - ([a b] (map vector a b)) - ([a b & rest] (apply map vector a b rest))) - -(defn has? [coll el] - (some #(= el %) coll)) - -(defprotocol NativeColl - (-native-coll [_])) - -(defn native-coll [xs] - (if (satisfies? NativeColl xs) - (-native-coll xs) - xs)) - -(defn fast-map [] - #?(:clj - (let [m (java.util.HashMap.)] - (reify - NativeColl - (-native-coll [_] m) - - clojure.lang.IEditableCollection - (asTransient [this] this) - - clojure.lang.ITransientAssociative - (assoc [this k v] (.put m k v) this) - - clojure.lang.ITransientCollection - (persistent [this] this) - - clojure.lang.IPersistentCollection - clojure.lang.Counted - (count [_] (.size m)) - - clojure.lang.ILookup - (valAt [_ k] (.get m k)) - (valAt [_ k nf] (or (.get m k) nf)))) - :cljs {})) - -(defn fast-arr [] - #?(:clj - (let [l (java.util.ArrayList.)] - (reify - NativeColl - (-native-coll [_] l) - - clojure.lang.IEditableCollection - (asTransient [this] this) - - clojure.lang.ITransientCollection - (conj [this v] (.add l v) this) - (persistent [this] this) - - clojure.lang.IPersistentCollection - clojure.lang.Counted - (count [_] (.size l)) - - clojure.lang.IReduceInit - (reduce [_ f s] - (loop [i 0 - res s] - (if (< i (.size l)) - (recur (inc i) (f res (.get l i))) - res))))) - :cljs - (let [arr (da/array)] - (reify - NativeColl - (-native-coll [_] arr) - - IEditableCollection - (-as-transient [this] this) - - ITransientCollection - (-conj! [this v] (.push arr v) this) - (-persistent! [this] this) - - ICounted - (-count [_] (alength arr)) - - IReduce - (-reduce [_ f s] - (loop [i 0 - res s] - (if (< i (alength arr)) - (recur (inc i) (f res (aget arr i))) - res))))))) - -(defn fast-set [] - #?(:clj - (let [set (java.util.HashSet.)] - (reify - NativeColl - (-native-coll [_] set) - - clojure.lang.IEditableCollection - (asTransient [this] this) - - clojure.lang.ITransientCollection - (conj [this v] (.add set v) this) - (persistent [this] this) - - clojure.lang.IPersistentCollection - clojure.lang.IPersistentSet - (contains [_ k] (.contains set k)) - - clojure.lang.Counted - (count [_] (.size set)) - - clojure.lang.IReduceInit - (reduce [_ f s] - (let [iter (.iterator set)] - (loop [acc s] - (if (.hasNext iter) - (recur (f acc (.next iter))) - acc)))))) - :cljs #{})) - -;; (defrecord Context [rels consts sources rules default-source-symbol]) - -(def empty-context {:empty? true}) - -(defprotocol IRelation - (-project [_ syms]) - (-alter-coll [_ f]) - (-symbols [_]) - (-arity [_]) - (-fold [_ f init]) - (-size [_]) - (-getter [_ symbol]) - (-indexes [_ symbols]) - (-copy-tuple [_ tuple idxs target target-idxs]) - (-union [_ rel])) - -;; (defn- #?@(:clj [^long hash-arr] -;; :cljs [^number hash-arr]) [arr] -;; (let [count (int (da/alength arr))] -;; (loop [n (int 0) -;; hash-code (int 1)] -;; (if (== n count) -;; (mix-collection-hash hash-code n) -;; (recur (inc n) -;; #?(:clj (unchecked-add-int -;; (unchecked-multiply-int 31 hash-code) -;; (hash (da/aget arr n))) -;; :cljs (bit-or (+ (imul 31 hash-code) -;; (hash (da/aget arr n))) -;; 0))))))) - -;; (declare equiv-tuple) - -;; (deftype Tuple [arr hash] -;; #?@( -;; :cljs [ -;; Object (equiv [this other] (equiv-tuple this other)) -;; IHash (-hash [_] hash) -;; IEquiv (-equiv [this other] (equiv-tuple this other)) ] -;; :clj [ -;; Object -;; (hashCode [_] -;; (java.util.Arrays/hashCode ^{:tag "[[Ljava.lang.Object;"} arr)) -;; (equals [this other] -;; (java.util.Arrays/equals ^{:tag "[[Ljava.lang.Object;"} arr -;; ^{:tag "[[Ljava.lang.Object;"} (.-arr ^Tuple other))) -;; ])) - -;; (defn equiv-tuple [^Tuple t ^Tuple o] -;; (boolean -;; (and -;; (== (da/alength (.-arr t)) -;; (da/alength (.-arr o))) -;; (loop [i 0] -;; (cond -;; (== i (da/alength (.-arr t))) true -;; (not= (da/aget (.-arr t) i) (da/aget (.-arr o) i)) false -;; :else (recur (inc i))))))) - -;; (defn tuple [arr] -;; (->Tuple arr (hash-arr arr))) - -;;; ArrayRelation - -(defn pr-rel [rel ^java.io.Writer w] - (doto w - (.write "#") - (.write #?(:clj (.getSimpleName ^Class (class rel)) - :cljs (str (type rel)))) - (.write "{:symbols ") - (.write (pr-str (-symbols rel))) - (.write ", :coll ") - (.write (pr-str (persistent! (-fold rel #(conj! %1 (seq %2)) (transient []))))) - (.write "}"))) - -(deftype ArrayRelation [offset-map coll] - IRelation - (-project [_ syms] - (ArrayRelation. (select-keys offset-map syms) coll)) - (-alter-coll [_ f] - (ArrayRelation. offset-map (f coll))) - (-symbols [_] (keys offset-map)) - (-arity [_] (count offset-map)) - (-fold [_ f init] (reduce f init coll)) - (-size [_] (count coll)) - (-getter [_ symbol] - (let [idx (offset-map symbol)] - (fn [tuple] - (da/aget tuple idx)))) - (-indexes [_ syms] - (mapa offset-map syms)) - (-copy-tuple [_ tuple idxs target target-idxs] - (dotimes [i (da/alength idxs)] - (da/aset target (da/aget target-idxs i) (da/aget tuple (da/aget idxs i))))) - (-union [_ rel] - (assert (instance? ArrayRelation rel)) - (assert (= offset-map (:offset-map rel))) - (ArrayRelation. offset-map (concat coll (:coll rel))))) - -#?(:clj - (defmethod print-method ArrayRelation [rel w] - (pr-rel rel w))) - -(defn array-rel [symbols coll] - (->ArrayRelation (zipmap symbols (range)) coll)) - - -;;; CollRelation - -(deftype CollRelation [offset-map coll] - IRelation - (-project [_ syms] - (CollRelation. (select-keys offset-map syms) coll)) - (-alter-coll [_ f] - (CollRelation. offset-map (f coll))) - (-symbols [_] (keys offset-map)) - (-arity [_] (count offset-map)) - (-fold [_ f init] (reduce f init coll)) - (-size [_] (count coll)) ;; (if (instance? Iter coll) (btset/est-count coll) (count coll)) - (-getter [_ symbol] - (let [idx (offset-map symbol)] - (fn [tuple] - (nth tuple idx)))) - (-indexes [_ syms] - (mapa offset-map syms)) - (-copy-tuple [_ tuple idxs target target-idxs] - (dotimes [i (da/alength idxs)] - (da/aset target (da/aget target-idxs i) (nth tuple (da/aget idxs i))))) - (-union [_ rel] - (assert (instance? CollRelation rel)) - (assert (= offset-map (:offset-map rel))) - (CollRelation. offset-map (concat coll (:coll rel))))) - -(defn coll-rel [symbols coll] - (let [offset-map (reduce-kv - (fn [acc e i] - (cond - (instance? BindScalar e) - (assoc acc (get-in e [:variable :symbol]) i) - (instance? Variable e) - (assoc acc (:symbol e) i) - (and (symbol? e) - (not= '_ e)) - (assoc acc e i) - :else acc)) - {} - (zipmap symbols (range)))] - (->CollRelation offset-map coll))) - -#?(:clj - (defmethod print-method CollRelation [rel w] - (pr-rel rel w))) - - -;;; ProdRelation - -;; (deftype ProdRelation [rel1 rel2] -;; IRelation -;; (-symbols [_] (concatv (-symbols rel1) (-symbols rel2))) -;; (-arity [_] (+ (-arity rel1) (-arity rel2))) -;; (-fold [_ f init] -;; (-fold rel1 -;; (fn [acc t1] -;; (-fold rel2 -;; (fn [acc t2] -;; (f acc (da/array t1 t2))) -;; acc)) -;; init)) - -;; (-size [_] -;; (* (-size rel1) (-size rel2))) -;; (-getter [_ symbol] -;; (if (some #{symbol} (-symbols rel1)) -;; (let [getter (-getter rel1 symbol)] -;; (fn [tuple] -;; (getter (da/aget tuple 0)))) -;; (let [getter (-getter rel2 symbol)] -;; (fn [tuple] -;; (getter (da/aget tuple 1)))))) -;; (-indexes [_ syms] -;; (let [[syms1 syms2] (split-with (set (-symbols rel1)) syms)] -;; [(-indexes rel1 syms1) -;; (count syms1) -;; (-indexes rel2 syms2) -;; (count syms2)])) -;; (-copy-tuple [_ tuple idxs target target-idxs] -;; (let [[idxs1 arity1 idxs2 arity2] idxs -;; target-idxs1 (subarr target-idxs 0 arity1) -;; target-idxs2 (subarr target-idxs arity1 (da/alength target-idxs))] -;; (-copy-tuple rel1 (da/aget tuple 0) idxs1 target target-idxs1) -;; (-copy-tuple rel2 (da/aget tuple 1) idxs2 target target-idxs2)))) - -;; (def prod-rel ->ProdRelation) - - -;;; SingletonRelation - -(deftype SingletonRelation [] - IRelation - (-symbols [_] []) - (-arity [_] 0) - (-fold [_ f init] (f init (to-array []))) - (-size [_] 1) - (-indexes [_ _] (to-array [])) - (-copy-tuple [_ _ _ _ _])) - -(def singleton-rel ->SingletonRelation) - -;;; cartesian product - -(defn- join-tuples [rel1 t1 idxs1 - rel2 t2 idxs2 - arity - target-idxs1 target-idxs2] - (let [arr (da/make-array arity)] - (-copy-tuple rel1 t1 idxs1 arr target-idxs1) - (-copy-tuple rel2 t2 idxs2 arr target-idxs2) - arr)) - -(defn product [rel1 rel2] - (let [idxs1 (-indexes rel1 (-symbols rel1)) - idxs2 (-indexes rel2 (-symbols rel2)) - arity1 (-arity rel1) - arity2 (-arity rel2) - arity (+ arity1 arity2) - target-idxs1 (arange 0 arity1) - target-idxs2 (arange arity1 arity) - coll (-fold rel1 - (fn [acc t1] - (-fold rel2 - (fn [acc t2] - (conj! acc (join-tuples rel1 t1 idxs1 - rel2 t2 idxs2 - arity - target-idxs1 - target-idxs2))) - acc)) - (fast-arr))] - (array-rel - (concatv (-symbols rel1) (-symbols rel2)) - (persistent! coll)))) - -(defn product-all [rels] - (reduce product rels)) ;; TODO check for empty rels - - -;; hash-join - -(defn- key-fn [rel syms] - (let [arity (count syms)] - (if (== arity 1) - (-getter rel (first syms)) - (let [idxs (-indexes rel syms) - target-idxs (arange 0 arity)] - (fn [t] - (let [arr (da/make-array arity)] - (-copy-tuple rel t idxs arr target-idxs) - (vec arr))))))) - -(defn hash-map-rel [rel syms] - (let [key-fn (key-fn rel syms)] - (->> - (-fold rel - (fn [hash t] - (let [key (key-fn t) - old (get hash key)] - (if (nil? old) - (assoc! hash key (conj! (fast-arr) t)) - (do (conj! old t) hash)))) - (transient (fast-map))) - (persistent!)))) - -(defn hash-join [rel1 hash1 join-syms rel2] - (let [syms1 (-symbols rel1) - syms2 (-symbols rel2) - keep-syms2 (remove (set syms1) syms2) - key-fn2 (key-fn rel2 join-syms) - idxs1 (-indexes rel1 syms1) - idxs2 (-indexes rel2 keep-syms2) - full-syms (concatv syms1 keep-syms2) - arity1 (count syms1) - arity2 (count keep-syms2) - arity (+ arity1 arity2) - target-idxs1 (arange 0 arity1) - target-idxs2 (arange arity1 arity) - - coll (-fold rel2 ;; iterate over rel2 - (fn [acc t2] - (let [tuples1 (get hash1 (key-fn2 t2))] - (if (nil? tuples1) - acc - (reduce (fn [acc t1] - (conj! acc (join-tuples rel1 t1 idxs1 - rel2 t2 idxs2 - arity - target-idxs1 - target-idxs2))) - acc (persistent! tuples1))))) - (fast-arr))] - (array-rel full-syms (persistent! coll)))) - - -;; Bindings - -(defn- bind! [tuples binding source indexes] - (condp instance? binding - - BindIgnore - tuples - - BindScalar - (let [symbol (get-in binding [:variable :symbol]) - idx (get indexes symbol)] - (run! #(da/aset % idx source) tuples) - tuples) - - BindColl - (if (not (db/seqable? source)) - (util/raise "Cannot bind value " source " to collection " (dp/source binding) - {:error :query/binding, :value source, :binding (dp/source binding)}) - (let [inner-binding (:binding binding)] - (case (count source) - 0 [] - 1 (bind! tuples inner-binding (first source) indexes) - (into [] ;; TODO fast-arr - (comp (map #(bind! tuples inner-binding % indexes)) - cat - (map da/aclone)) - source)))) - - BindTuple - (let [bindings (:bindings binding)] - (when-not (db/seqable? source) - (util/raise "Cannot bind value " source " to tuple " (dp/source binding) - {:error :query/binding, :value source, :binding (dp/source binding)})) - (when (< (count source) (count bindings)) - (util/raise "Not enough elements in a collection " source " to bind tuple " (dp/source binding) - {:error :query/binding, :value source, :binding (dp/source binding)})) - (reduce (fn [ts [b s]] - (bind! ts b s indexes)) - tuples - (zip bindings source))) - - :else - (util/raise "Unknown binding form " (dp/source binding) - {:error :query/binding, :value source, :binding (dp/source binding)}))) - -(defn bind [binding source] - (let [syms (map :symbol (dp/collect-vars-distinct binding)) - indexes (zipmap syms (range)) - tuples (bind! [(da/make-array (count syms))] binding source indexes)] - (array-rel syms tuples))) - -(defn- rel->consts [rel] - {:pre [(== (-size rel) 1)]} - (let [tuple (-fold rel (fn [_ t] t) nil)] - (into {} - (map #(vector % ((-getter rel %) tuple)) (-symbols rel))))) - -(defn- resolve-in [context [binding value]] - (cond - (and (instance? BindScalar binding) - (instance? SrcVar (:variable binding))) - (update-in context [:sources] assoc (get-in binding [:variable :symbol]) value) - ;; (and (instance? BindScalar binding) - ;; (instance? RulesVar (:variable binding))) - ;; (assoc context :rules (parse-rules value)) - :else - (let [rel (bind binding value)] - (if (== 1 (-size rel)) - (update-in context [:consts] merge (rel->consts rel)) - (update-in context [:rels] conj rel))))) - -(defn resolve-ins [context bindings values] - (when (not= (count bindings) (count values)) - (util/raise "Wrong number of arguments for bindings " (mapv dp/source bindings) - ", " (count bindings) " required, " (count values) " provided" - {:error :query/binding, :binding (mapv dp/source bindings)})) - (reduce resolve-in context (zip bindings values))) - - -;;; Resolution - -(defprotocol IClause - (-resolve-clause [clause context])) - -(defn get-source [context source] - (let [symbol (cond - (instance? SrcVar source) (:symbol source) - (instance? DefaultSrc source) (:default-source-symbol context) - :else (util/raise "Source expected, got " source))] - (or (get (:sources context) symbol) - (util/raise "Source " symbol " is not defined" - {:error :query/where, :symbol symbol})))) - - -;; Patterns - -(defn resolve-pattern-db [db clause] - ;; TODO optimize with bound attrs min/max values here - (let [pattern (:pattern clause) - search-pattern (mapv #(when (instance? Constant %) (:value %)) pattern) - datoms (db/-search db search-pattern)] - (coll-rel (:pattern clause) datoms))) - -(defn- matches-pattern? [idxs tuple] ;; TODO handle repeated vars - ;; (when-not (db/seqable? tuple) - ;; (util/raise "Cannot match pattern " (dp/source clause) " because tuple is not a collection: " tuple - ;; {:error :query/where, :value tuple, :binding (dp/source clause)})) - ;; (when (< (count tuple) (count (:pattern clause))) - ;; (util/raise "Not enough elements in a relation tuple " tuple " to match " (dp/source clause) - ;; {:error :query/where, :value tuple, :binding (dp/source clause)})) - (reduce-kv - (fn [_ i v] - (if (not= (nth tuple i) v) ;; nth? - (reduced false) - true)) - true - idxs)) - -(defn resolve-pattern-coll [coll clause] - (when-not (db/seqable? coll) - (util/raise "Cannot match by pattern " (dp/source clause) " because source is not a collection: " coll - {:error :query/where, :value coll, :binding (dp/source clause)})) - (let [pattern (:pattern clause) - idxs (->> (map #(when (instance? Constant %1) [%2 (:value %1)]) pattern (range)) - (remove nil?) - (into {})) - data (filter #(matches-pattern? idxs %) coll)] - (coll-rel pattern data))) - -(defn clause-syms [clause] - (into #{} (map :symbol) (dp/collect #(instance? Variable %) clause #{}))) - -(defn substitute-constants [clause context] - (let [syms (clause-syms clause) - consts (:consts context)] - (if (some #(contains? consts %) syms) - (dp/postwalk - clause - (fn [form] - (if (instance? Variable form) - (let [sym (:symbol form)] - (if-let [subs (get (:consts context) (:symbol form))] - (Constant. subs) - form)) - form))) - clause))) - -(defn related-rels [context syms] - (let [syms (set syms)] - (->> (:rels context) - (filter #(some syms (-symbols %)))))) - -(defn extract-rels [context syms] - (let [syms (set syms) - rels (:rels context) - related? #(some syms (-symbols %)) - related (filter related? rels)] - (if (empty? related) - [nil context] - (let [unrelated (remove related? rels)] - [related (assoc context :rels unrelated)])))) - -(defn join-unrelated [context rel] - (case (long (-size rel)) - 0 empty-context - 1 (update context :consts merge (rel->consts rel)) - (update context :rels conj rel))) - -(defn hash-join-rel [context rel] - (if (== 0 (-size rel)) - empty-context - (let [syms (set (-symbols rel)) - [related-rels context*] (extract-rels context syms)] - (if (empty? related-rels) - (join-unrelated context rel) - (let [related-rel (product-all related-rels) - join-syms (set/intersection syms (set (-symbols related-rel))) - hash (hash-map-rel related-rel join-syms) - ;; TODO choose between hash-join and lookup-join - rel* (hash-join related-rel hash join-syms rel)] - (join-unrelated context* rel*)))))) - -(defn resolve-pattern [context clause] - (let [clause* (substitute-constants clause context) - rel (let [source (get-source context (:source clause))] - (if (satisfies? db/ISearch source) - (resolve-pattern-db source clause*) - (resolve-pattern-coll source clause*)))] - (hash-join-rel context rel))) - -(defn project-rel [rel syms] - (let [rel-syms (set (-symbols rel)) - syms (set syms)] - (cond - (set/subset? rel-syms syms) rel - (empty? (set/intersection rel-syms syms)) nil - :else (-project rel syms)))) - -(defn project-context [context syms] - (assoc context - :consts (select-keys (:consts context) syms) - :rels (into [] - (comp (map #(project-rel % syms)) - (remove nil?)) - (:rels context)))) - -(defn collect-opt - "Collects values if only one symbol, vecs if many (compatible with key-fn)" - [context syms] - (if (== 1 (count syms)) - (let [sym (first syms)] - (if-let [val (get (:consts context) sym)] - (into (fast-set) [val]) - (let [rel (first (related-rels context [sym])) - getter (-getter rel sym)] - (->> (fast-set) - (transient) - (-fold rel - (fn [set tuple] - (conj! set (getter tuple)))) - (persistent!))))) - (collect-to context syms (fast-set) [(map vec)]))) - -(defn subtract-from-rel [rel syms exclude-key-set] - (let [key-fn1 (key-fn rel syms) - pred (fn [t1] (contains? exclude-key-set (key-fn1 t1)))] - (-alter-coll rel #(into (fast-arr) (remove pred) %)))) - -(defn subtract-contexts [context1 context2 syms] - (if (:empty? context2) ;; empty context2 means there’s nothing to subtract - context1 - ;; ignoring constants inherited from context1 - (let [syms* (set/difference syms (keys (:consts context1)))] - (if (empty? syms*) ;; join happened by constants only - empty-context ;; context2 is not-empty, meaning it satisfied constans, - ;; meaning we proved constants in context1 do not match - (let [[rels1 context1*] (extract-rels context1 syms*) - rel1 (product-all rels1) - set2 (collect-opt context2 syms*) - rel1* (subtract-from-rel rel1 syms* set2)] - (join-unrelated context1* rel1*)))))) - -(defn upd-default-source [context clause] - (let [source (:source clause)] - (if (instance? SrcVar source) - (assoc context :default-source-symbol (:symbol source)) - context))) - -(defn check-bound [context syms form] - (let [context-syms (-> #{} - (into (keys (:consts context))) - (into (mapcat -symbols) (:rels context)) - (into (keys (:sources context))))] - (when-not (set/subset? syms context-syms) - (let [missing (set/difference (set syms) context-syms)] - (throw (ex-info (str "Insufficient bindings: " missing " not bound in " form) - {:error :query/where - :form form - :vars missing})))))) - - -(defn resolve-not [context clause] - (let [{:keys [source vars clauses]} clause - syms (into #{} (map :symbol) vars) - _ (check-bound context syms (dp/source clause)) - context* (-> context - (project-context syms) ;; sub-context will only see symbols Not is joined by - (upd-default-source clause) - (resolve-clauses clauses))] - (subtract-contexts context context* syms))) - -(defn resolve-or [context clause] - (let [{:keys [source rule-vars clauses]} clause - {:keys [required free]} rule-vars - _ (check-bound context (map :symbol required) (dp/source clause)) - syms (into #{} (map :symbol) (concat required free)) - context* (-> context - (project-context syms) - (upd-default-source clause)) - contexts (->> clauses - (map #(-resolve-clause % context*)) - (remove :empty?))] - (if (empty? contexts) - empty-context ;; everything resolved to empty rel, short-circuit - (let [non-consts (set/difference syms (set (keys (:consts context))))] - (if (empty? non-consts) - context ;; join was by constants only, nothing changes - (let [arrays (map #(collect-to % non-consts (fast-arr)) contexts) - rel (array-rel non-consts (into (first arrays) cat (next arrays)))] - (hash-join-rel context rel))))))) - -(defn collect-args! [context args target form] - (let [consts (:consts context) - sources (:sources context)] - (doseq [[arg i] (zip args (range)) - :let [sym (:symbol arg)]] - (cond - (instance? Variable arg) - (when (contains? consts sym) - (da/aset target i (get consts sym))) - (instance? SrcVar arg) - (if (contains? sources sym) - (da/aset target i (get sources sym)) - (throw (ex-info (str "Unbound source variable: " sym " in " form) - { :error :query/where, :form form, :var sym}))) - (instance? Constant arg) - (da/aset target i (:value arg)))))) - -(defn get-f [context fun form] - (let [sym (:symbol fun)] - (if (instance? PlainSymbol fun) - (or (get built-ins/query-fns sym) - (throw (ex-info (str "Unknown built-in " sym " in " form) - {:error :query/where, :form form, :var sym}))) - (or (get (:consts context) sym) ;; variable then - (throw (ex-info (str "Unknown function " sym " in " form) - {:error :query/where, :form form, :var sym})))))) - -(defn resolve-predicate [context clause] - (let [{fun :fn, args :args} clause - form (dp/source clause) - f (get-f context fun form) - args-arr (da/make-array (count args)) - _ (collect-args! context args args-arr form) - consts (:consts context) - sym+idx (for [[arg i] (zip args (range)) - :when (instance? Variable arg) - :let [sym (:symbol arg)] - :when (not (contains? consts sym))] - [sym i]) - args-syms (map first sym+idx) - args-idxs (mapa second sym+idx) - _ (check-bound context args-syms form)] - (if (empty? args-syms) ;; only constants - (if (apply f (vec args-arr)) - context - empty-context) - (let [[rels context*] (extract-rels context args-syms)] - (if (== 1 (count rels)) - (let [rel (first rels) - idxs (-indexes rel args-syms) - pred (fn [tuple] - (-copy-tuple rel tuple idxs args-arr args-idxs) - (apply f (vec args-arr))) - rel* (-alter-coll rel #(filterv pred %))] - (join-unrelated context* rel*)) - (let [prod-syms (mapcat -symbols rels) - prod-sym+idx (zip prod-syms (range)) - xfs (map #(collect-rel-xf prod-sym+idx %) rels) - prod-rel (array-rel prod-syms []) - - idxs (-indexes prod-rel args-syms) - pred (fn [tuple] - (-copy-tuple prod-rel tuple idxs args-arr args-idxs) - (apply f (vec args-arr))) - - array (into (fast-arr) - (apply comp (concat xfs [(filter pred)])) - [(da/make-array (count prod-syms))]) - prod-rel* (array-rel prod-syms array)] - (join-unrelated context* prod-rel*))))))) - - -(extend-protocol IClause - Pattern - (-resolve-clause [clause context] - (resolve-pattern context clause)) - Not - (-resolve-clause [clause context] - (resolve-not context clause)) - Or - (-resolve-clause [clause context] - (resolve-or context clause)) - And - (-resolve-clause [clause context] - (resolve-clauses context (:clauses clause))) - Predicate - (-resolve-clause [clause context] - (resolve-predicate context clause))) - -(defn println-context [context] - (print "{:rels") - (if (empty? (:rels context)) - (println " []") - (doseq [rel (:rels context)] - (println " " rel))) - (println " :consts" (:consts context) "}")) - - -(defn resolve-clauses [context clauses] - (reduce (fn [context clause] - (let [context* (-resolve-clause clause context)] - (if (:empty? context*) - (reduced context*) - (do - ;; (println (dp/source clause) "=>") - ;; (println-context context*) - context*)))) - context clauses)) - -(defn collect-consts [syms-indexed specimen consts] - (doseq [[sym i] syms-indexed] - (when (contains? consts sym) - (let [val (get consts sym)] - (da/aset specimen i val))))) - - -(defn collect-rel-xf [syms-indexed rel] - (let [sym+idx (for [[sym i] syms-indexed - :when (has? (-symbols rel) sym)] - [sym i]) - idxs (-indexes rel (map first sym+idx)) - target-idxs (mapa second sym+idx)] - (fn [rf] - (fn - ([] (rf)) - ([result] (rf result)) - ([result specimen] - (-fold rel - (fn [acc tuple] - (let [t (da/aclone specimen)] - (-copy-tuple rel tuple idxs t target-idxs) - (rf acc t))) - result)))))) - -(defn collect-to - ([context syms acc] - (collect-to context syms acc [] (da/make-array (count syms)))) - ([context syms acc xfs] - (collect-to context syms acc xfs (da/make-array (count syms)))) - ([context syms acc xfs specimen] - ;; TODO don't collect if array-rel and matches symbols - (if (:empty? context) - acc - (let [syms-indexed (vec (zip syms (range))) - _ (collect-consts syms-indexed specimen (:consts context)) - related-rels (related-rels context syms) - xfs (-> (map #(collect-rel-xf syms-indexed %) related-rels) - (concat xfs))] - (into acc (apply comp xfs) [specimen]))))) - - -;; Query - -(def query-cache (lru/cache lru-cache-size)) - -(defn q [q & inputs] - (let [parsed-q (lru/-get query-cache q #(dp/parse-query q)) - context {:rels [] - :consts {} - :sources {} - :rules {} - :default-source-symbol '$} - context (resolve-ins context (:qin parsed-q) inputs) - context (resolve-clauses context (:qwhere parsed-q)) - syms (concat (dp/find-vars (:qfind parsed-q)) - (map :symbol (:qwith parsed-q)))] - (native-coll (collect-to context syms (fast-set) [(map vec)])))) - - -(comment - (t/test-ns 'slateval.test.query-v3) - - (let [query '[:find ?lid ?status ?starttime ?endtime (min ?paid) (distinct ?studentinfo) ?lgid - :in $ ?tid ?week ?list - :where [?lid :lesson/teacherid ?tid] - [?lid :lesson/week ?week] - [?lid :lesson/lessongroupid ?lgid] - [?eid :enrollment/lessongroup_id ?lgid] - [?eid :enrollment/student_id ?sid] - [?iid :invoice/enrollment_id ?eid] - [?sid :student/firstname ?fname] - [?sid :student/lastname ?lname] - [?iid :invoice/paid ?paid] - [?lid :lesson/status ?status] - [?lid :lesson/starttime ?starttime] - [?lid :lesson/endtime ?endtime] - [(?list ?sid ?fname ?lname) ?studentinfo]] - parsed (dp/parse-query query)] - (perf/minibench "postwalk" - (dp/postwalk parsed identity)) - (perf/minibench "parse-query" - (dp/parse-query query)) - (perf/minibench "substitute-constants" - (substitute-constants (first (:where parsed)) {:consts {'?tid 7}}))) - - (defn random-man [] - {:name (rand-nth ["Ivan" "Petr" "Sergei" "Oleg" "Yuri" "Dmitry" "Fedor" "Denis"]) - :last-name (rand-nth ["Ivanov" "Petrov" "Sidorov" "Kovalev" "Kuznetsov" "Voronoi"]) - :sex (rand-nth [:male :female]) - :age (rand-int 10) - :salary (rand-int 100000)}) - - (defn bench [name q & args] - (println "\n---\n") - (perf/minibench (str "OLD " name) (apply d/q q args)) - (perf/minibench (str "NEW " name) (apply slateval.query-v3/q q args)) - nil) - - (do - #_(require '[slateval.query-v3 :as q] :reload) - - (def db (d/db-with (d/empty-db) (repeatedly 10000 random-man))) - - (bench "q2 const" - '[:find ?e - :where [?e :name "Ivan"] - [?e :age 1]] - db) - - #_(bench "q2 const in" - '[:find ?e - :in $ ?n - :where [?e :name "Ivan"] - [?e :age ?n]] - db 1))) diff --git a/test/slateval/test.cljc b/test/slateval/test.cljc index 5af7663..89f942a 100644 --- a/test/slateval/test.cljc +++ b/test/slateval/test.cljc @@ -32,7 +32,6 @@ slateval.test.query-pull slateval.test.query-return-map slateval.test.query-rules - slateval.test.query-v3 slateval.test.time-travel slateval.test.transact slateval.test.tuples diff --git a/test/slateval/test/db.cljc b/test/slateval/test/db.cljc index 2d2bfbc..d98a081 100644 --- a/test/slateval/test/db.cljc +++ b/test/slateval/test/db.cljc @@ -3,7 +3,8 @@ [clojure.data] [clojure.test :as t :refer [is are deftest testing]] [slateval.core :as d] - [slateval.db :as db :refer [defrecord-updatable]])) + [slateval.db :as db :refer [defrecord-updatable]] + [slateval.test.core])) ;; ;; verify that defrecord-updatable works with compiler/core macro configuration @@ -42,18 +43,15 @@ (subs (str (d/squuid)) 0 8))))) (deftest test-diff - ;; With UUIDs, comparing datoms across different databases doesn't make sense - ;; since entity IDs are random. Test diff within same database evolution instead. + ;; clojure.data/diff is deliberately unsupported: slateval databases may + ;; not fit into memory, and a diff would have to realize both sides + ;; entirely. The DB record still extends clojure.data/Diff, but only to + ;; throw — otherwise diff would fall back to clojure.data's default map + ;; implementation and diff the record's fields. (let [tx1 (d/with (d/empty-db) [{:db/id "e1" :a 1 :b 2}]) db1 (:db-after tx1) e1 (get (:tempids tx1) "e1") db2 (d/db-with db1 [[:db/retract e1 :b 2] - [:db/add e1 :c 3]]) - [only-db1 only-db2 common] (clojure.data/diff db1 db2)] - ;; Verify diff returns something sensible - the databases differ - (is (some? only-db1)) - (is (some? only-db2)) - ;; db1 has the :b datom that db2 doesn't have - (is (some #(= :b (:a %)) only-db1)) - ;; db2 has the :c datom that db1 doesn't have - (is (some #(= :c (:a %)) only-db2)))) + [:db/add e1 :c 3]])] + (is (thrown-msg? "clojure.data/diff is not supported on slateval databases, since it would realize both databases entirely in memory" + (clojure.data/diff db1 db2))))) diff --git a/test/slateval/test/issues.cljc b/test/slateval/test/issues.cljc index deac840..8dca85e 100644 --- a/test/slateval/test/issues.cljc +++ b/test/slateval/test/issues.cljc @@ -1,7 +1,9 @@ (ns slateval.test.issues (:require + [clojure.data] [slateval.core :as ds] - [clojure.test :as t :refer [is are deftest testing]])) + [clojure.test :as t :refer [is are deftest testing]] + [slateval.test.core])) (deftest ^{:doc "CLJS `apply` + `vector` will hold onto mutable array of arguments directly"} issue-262 @@ -27,18 +29,15 @@ (deftest ^{:doc "Can't diff databases with different types of the same attribute"} issue-369 - ;; Use fixed UUID for deterministic testing + ;; The original issue is moot: clojure.data/diff is deliberately + ;; unsupported on slateval databases (see slateval.test.db/test-diff). (let [eid #uuid "22222222-2222-2222-2222-222222222222" db1 (-> (ds/empty-db) (ds/db-with [[:db/add eid :attr :aa]])) db2 (-> (ds/empty-db) - (ds/db-with [[:db/add eid :attr "aa"]])) - [only-in-db1 only-in-db2 _common] (clojure.data/diff db1 db2)] - ;; Check that diff produces datoms with correct attribute values - (t/is (= 1 (count only-in-db1))) - (t/is (= :aa (:v (first only-in-db1)))) - (t/is (= 1 (count only-in-db2))) - (t/is (= "aa" (:v (first only-in-db2)))))) + (ds/db-with [[:db/add eid :attr "aa"]]))] + (t/is (thrown-msg? "clojure.data/diff is not supported on slateval databases, since it would realize both databases entirely in memory" + (clojure.data/diff db1 db2))))) (deftest ^{:doc "Expose a schema as a part of the public API."} issue-381 diff --git a/test/slateval/test/query_v3.cljc b/test/slateval/test/query_v3.cljc deleted file mode 100644 index 9d7f94f..0000000 --- a/test/slateval/test/query_v3.cljc +++ /dev/null @@ -1,23 +0,0 @@ -(ns slateval.test.query-v3 - (:require - [clojure.test :as t :refer [is are deftest testing]] - [slateval.core :as d] - [slateval.db :as db] - [slateval.query-v3 :as dq] - [slateval.test.core :as tdc]) - #?(:clj - (:import - [clojure.lang ExceptionInfo]))) - -(deftest test-validation - (are [q ins msg] (thrown-with-msg? ExceptionInfo msg (apply dq/q q ins)) - '[:find ?a :in $ ?a] [0] #"Wrong number of arguments for bindings \[\$ \?a\], 2 required, 1 provided" - '[:find ?a :in $ :where [?a]] [0 1] #"Wrong number of arguments for bindings \[\$\], 1 required, 2 provided" - '[:find ?a :where [?a]] [0 1] #"Wrong number of arguments for bindings \[\$\], 1 required, 2 provided" - - '[:find ?a :where [?a 1]] [:a] #"Cannot match by pattern \[\?a 1\] because source is not a collection: :a")) - -#_(deftest test-query - (is (= (dq/q '[:find ?a :where [?a ?a]] - [[1 2] [3 3] [4 5] [6 6]]) - #{[3] [6]}))) From 264d006eee9af2685f227e502f1484f869be7fd4 Mon Sep 17 00:00:00 2001 From: max Date: Wed, 15 Jul 2026 11:17:17 +0200 Subject: [PATCH 2/4] Remove Datomic-compat shims hollowed out by UUID entity ids. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `tempid` and `resolve-tempid` had no callers; `d/db` and `transact` stay. The Datascript `squuid` implementation is removed — entity and transaction ids use com.yetanalytics/colossal-squuid (`gen-id`). Co-Authored-By: Claude Fable 5 --- src/slateval/core.cljc | 31 ----------------------- src/slateval/util.cljc | 51 +------------------------------------- test/slateval/test/db.cljc | 15 ----------- 3 files changed, 1 insertion(+), 96 deletions(-) diff --git a/src/slateval/core.cljc b/src/slateval/core.cljc index 62fb409..5d19023 100644 --- a/src/slateval/core.cljc +++ b/src/slateval/core.cljc @@ -591,26 +591,6 @@ ;; Datomic compatibility layer -(defn tempid - "Allocates and returns a unique temporary id. Returns a random UUID, or :db/current-tx for the tx partition. - - Exists for Datomic API compatibility. Prefer using (gen-id) or UUIDs directly." - ([part] - (if (= part :db.part/tx) - :db/current-tx - (gen-id))) - ([part x] - (if (= part :db.part/tx) - :db/current-tx - x))) - -(defn resolve-tempid - "Does a lookup in tempids map, returning the UUID that was assigned to a tempid. - - Exists for Datomic API compatibility. Prefer using map lookup directly if possible." - [_db tempids tempid] - (get tempids tempid)) - (defn ^DB db "Returns the underlying immutable database value from a connection. @@ -669,15 +649,4 @@ (future-call #(transact! conn tx-data tx-meta)))) -;; squuid - -(def ^{:arglists '([] [msec])} squuid - "Generates a UUID that grow with time. Such UUIDs will always go to the end of the index and that will minimize insertions in the middle. - - Consist of 64 bits of current UNIX timestamp (in seconds) and 64 random bits (2^64 different unique values per second)." - util/squuid) - -(def ^{:arglists '([uuid])} squuid-time-millis - "Returns time that was used in [[squuid]] call, in milliseconds, rounded to the closest second." - util/squuid-time-millis) diff --git a/src/slateval/util.cljc b/src/slateval/util.cljc index 449a049..3d1b477 100644 --- a/src/slateval/util.cljc +++ b/src/slateval/util.cljc @@ -1,8 +1,6 @@ (ns slateval.util (:refer-clojure :exclude [find]) - #?(:clj - (:import - [java.util UUID]))) + ) (def ^:dynamic *debug* false) @@ -113,53 +111,6 @@ ([x & more] `(let [x# ~x] (if (nil? x#) (some-of ~@more) x#))))) -(defn- rand-bits [pow] - (rand-int (bit-shift-left 1 pow))) - -#?(:cljs - (defn- to-hex-string [n l] - (let [s (.toString n 16) - c (count s)] - (cond - (> c l) (subs s 0 l) - (< c l) (str (apply str (repeat (- l c) "0")) s) - :else s)))) - -(defn squuid - ([] - (squuid #?(:clj (System/currentTimeMillis) - :cljs (.getTime (js/Date.))))) - ([msec] - #?(:clj - (let [uuid (UUID/randomUUID) - time (int (/ msec 1000)) - high (.getMostSignificantBits uuid) - low (.getLeastSignificantBits uuid) - new-high (bit-or (bit-and high 0x00000000FFFFFFFF) - (bit-shift-left time 32))] - (UUID. new-high low)) - :cljs - (uuid - (str - (-> (int (/ msec 1000)) - (to-hex-string 8)) - "-" (-> (rand-bits 16) (to-hex-string 4)) - "-" (-> (rand-bits 16) (bit-and 0x0FFF) (bit-or 0x4000) (to-hex-string 4)) - "-" (-> (rand-bits 16) (bit-and 0x3FFF) (bit-or 0x8000) (to-hex-string 4)) - "-" (-> (rand-bits 16) (to-hex-string 4)) - (-> (rand-bits 16) (to-hex-string 4)) - (-> (rand-bits 16) (to-hex-string 4))))))) - -(defn squuid-time-millis - "Returns time that was used in [[squuid]] call, in milliseconds, rounded to the closest second." - [uuid] - #?(:clj (-> (.getMostSignificantBits ^UUID uuid) - (bit-shift-right 32) - (* 1000)) - :cljs (-> (subs (str uuid) 0 8) - (js/parseInt 16) - (* 1000)))) - (defn distinct-by [f coll] (->> (reduce diff --git a/test/slateval/test/db.cljc b/test/slateval/test/db.cljc index d98a081..22a8785 100644 --- a/test/slateval/test/db.cljc +++ b/test/slateval/test/db.cljc @@ -26,21 +26,6 @@ (let [h (hash db)] (is (= h @(.-hash db)))))) -(defn- now [] - #?(:clj (System/currentTimeMillis) - :cljs (.getTime (js/Date.)))) - -(deftest test-uuid - (let [now-ms (loop [] - (let [ts (now)] - (if (> (mod ts 1000) 900) ;; sleeping over end of a second - (recur) - ts))) - now (int (/ now-ms 1000))] - (is (= (* 1000 now) (d/squuid-time-millis (d/squuid)))) - (is (not= (d/squuid) (d/squuid))) - (is (= (subs (str (d/squuid)) 0 8) - (subs (str (d/squuid)) 0 8))))) (deftest test-diff ;; clojure.data/diff is deliberately unsupported: slateval databases may From a613581a194e2c760e537270f49cb0b600bd0cb9 Mon Sep 17 00:00:00 2001 From: max Date: Wed, 15 Jul 2026 11:20:27 +0200 Subject: [PATCH 3/4] Remove the ClojureScript/JS variant. The storage layer is SlateDB via its JVM uniffi bindings, so the CLJS variant (disabled since the fork) cannot work without an entirely different backend; git history keeps it recoverable. - Delete `slateval.js`, `deps.cljs`, `externs.js`, `release-js/`, `test/js/`, `slateval.test.cljs` and the cljs/js test+bench scripts. - Strip every `#?`/`#?@` reader conditional (keeping the :clj branches) and rename all `.cljc` sources and tests to `.clj`. - Remove the CLJS-only macro layer: `defn+` (now plain `defn`), `if-cljs`, `cljs-env?`, `patch-tag`; `defrecord-updatable` keeps only its JVM implementation. - Drop the :cljs alias and transit-cljs from deps.edn. Co-Authored-By: Claude Fable 5 --- .github/workflows/build_test.yml | 2 - deps.edn | 10 +- dev/user.clj | 4 +- release-js/README.md | 16 - release-js/package.json | 46 -- release-js/test_include_amd.html | 24 - release-js/test_include_node.js | 6 - release-js/test_include_script.html | 26 - release-js/wrap_bare.sh | 7 - release-js/wrapper.prefix | 43 -- release-js/wrapper.suffix | 6 - script/bench_all.sh | 1 - script/bench_cljs.js | 12 - script/bench_cljs.sh | 5 - script/test_all.sh | 2 - script/test_cljs.js | 32 - script/test_cljs.sh | 6 - script/test_js.js | 23 - script/test_js.sh | 6 - src/deps.cljs | 1 - .../{built_ins.cljc => built_ins.clj} | 4 +- src/slateval/{conn.cljc => conn.clj} | 10 +- src/slateval/{core.cljc => core.clj} | 142 ++--- src/slateval/{datafy.cljc => datafy.clj} | 0 src/slateval/{db.cljc => db.clj} | 433 ++++--------- src/slateval/externs.js | 31 - src/slateval/impl/{entity.cljc => entity.clj} | 111 +--- src/slateval/js.cljs | 165 ----- src/slateval/{lru.cljc => lru.clj} | 16 +- src/slateval/{parser.cljc => parser.clj} | 20 +- src/slateval/{pull_api.cljc => pull_api.clj} | 43 +- .../{pull_parser.cljc => pull_parser.clj} | 8 +- src/slateval/{query.cljc => query.clj} | 124 ++-- src/slateval/{util.cljc => util.clj} | 59 +- test/js/tests.js | 584 ------------------ test/js/underscore-1.6.0.min.js | 6 - test/slateval/{test.cljc => test.clj} | 12 +- test/slateval/test/cljs.cljc | 29 - .../test/{components.cljc => components.clj} | 2 - test/slateval/test/{conn.cljc => conn.clj} | 0 test/slateval/test/{core.cljc => core.clj} | 59 +- .../slateval/test/{datafy.cljc => datafy.clj} | 0 test/slateval/test/{db.cljc => db.clj} | 3 +- .../slateval/test/{entity.cljc => entity.clj} | 5 +- .../test/{explode.cljc => explode.clj} | 5 +- .../slateval/test/{filter.cljc => filter.clj} | 0 test/slateval/test/{ident.cljc => ident.clj} | 0 test/slateval/test/{index.cljc => index.clj} | 0 .../slateval/test/{issues.cljc => issues.clj} | 5 +- .../slateval/test/{listen.cljc => listen.clj} | 0 .../{lookup_refs.cljc => lookup_refs.clj} | 5 +- test/slateval/test/{lru.cljc => lru.clj} | 0 .../slateval/test/{parser.cljc => parser.clj} | 27 +- .../{parser_find.cljc => parser_find.clj} | 3 - .../{parser_query.cljc => parser_query.clj} | 21 +- ..._return_map.cljc => parser_return_map.clj} | 3 - .../{parser_rules.cljc => parser_rules.clj} | 21 +- .../{parser_where.cljc => parser_where.clj} | 55 +- .../test/{pull_api.cljc => pull_api.clj} | 0 .../{pull_parser.cljc => pull_parser.clj} | 8 +- test/slateval/test/{query.cljc => query.clj} | 13 +- ...y_aggregates.cljc => query_aggregates.clj} | 13 +- ...y_find_specs.cljc => query_find_specs.clj} | 0 .../test/{query_fns.cljc => query_fns.clj} | 10 +- .../test/{query_not.cljc => query_not.clj} | 5 +- .../test/{query_or.cljc => query_or.clj} | 5 +- .../test/{query_pull.cljc => query_pull.clj} | 0 ...y_return_map.cljc => query_return_map.clj} | 1 - .../{query_rules.cljc => query_rules.clj} | 9 +- .../{time_travel.cljc => time_travel.clj} | 27 +- .../test/{transact.cljc => transact.clj} | 8 +- .../slateval/test/{tuples.cljc => tuples.clj} | 5 +- .../slateval/test/{upsert.cljc => upsert.clj} | 3 - .../test/{validation.cljc => validation.clj} | 3 - 74 files changed, 432 insertions(+), 1967 deletions(-) delete mode 100644 release-js/README.md delete mode 100644 release-js/package.json delete mode 100644 release-js/test_include_amd.html delete mode 100644 release-js/test_include_node.js delete mode 100644 release-js/test_include_script.html delete mode 100755 release-js/wrap_bare.sh delete mode 100644 release-js/wrapper.prefix delete mode 100644 release-js/wrapper.suffix delete mode 100755 script/bench_cljs.js delete mode 100755 script/bench_cljs.sh delete mode 100644 script/test_cljs.js delete mode 100755 script/test_cljs.sh delete mode 100644 script/test_js.js delete mode 100755 script/test_js.sh delete mode 100644 src/deps.cljs rename src/slateval/{built_ins.cljc => built_ins.clj} (98%) rename src/slateval/{conn.cljc => conn.clj} (94%) rename src/slateval/{core.cljc => core.clj} (95%) rename src/slateval/{datafy.cljc => datafy.clj} (100%) rename src/slateval/{db.cljc => db.clj} (88%) delete mode 100644 src/slateval/externs.js rename src/slateval/impl/{entity.cljc => entity.clj} (57%) delete mode 100644 src/slateval/js.cljs rename src/slateval/{lru.cljc => lru.clj} (76%) rename src/slateval/{parser.cljc => parser.clj} (99%) rename src/slateval/{pull_api.cljc => pull_api.clj} (92%) rename src/slateval/{pull_parser.cljc => pull_parser.clj} (99%) rename src/slateval/{query.cljc => query.clj} (92%) rename src/slateval/{util.cljc => util.clj} (81%) delete mode 100644 test/js/tests.js delete mode 100644 test/js/underscore-1.6.0.min.js rename test/slateval/{test.cljc => test.clj} (76%) delete mode 100644 test/slateval/test/cljs.cljc rename test/slateval/test/{components.cljc => components.clj} (99%) rename test/slateval/test/{conn.cljc => conn.clj} (100%) rename test/slateval/test/{core.cljc => core.clj} (58%) rename test/slateval/test/{datafy.cljc => datafy.clj} (100%) rename test/slateval/test/{db.cljc => db.clj} (92%) rename test/slateval/test/{entity.cljc => entity.clj} (99%) rename test/slateval/test/{explode.cljc => explode.clj} (99%) rename test/slateval/test/{filter.cljc => filter.clj} (100%) rename test/slateval/test/{ident.cljc => ident.clj} (100%) rename test/slateval/test/{index.cljc => index.clj} (100%) rename test/slateval/test/{issues.cljc => issues.clj} (96%) rename test/slateval/test/{listen.cljc => listen.clj} (100%) rename test/slateval/test/{lookup_refs.cljc => lookup_refs.clj} (99%) rename test/slateval/test/{lru.cljc => lru.clj} (100%) rename test/slateval/test/{parser.cljc => parser.clj} (93%) rename test/slateval/test/{parser_find.cljc => parser_find.clj} (98%) rename test/slateval/test/{parser_query.cljc => parser_query.clj} (90%) rename test/slateval/test/{parser_return_map.cljc => parser_return_map.clj} (97%) rename test/slateval/test/{parser_rules.cljc => parser_rules.clj} (96%) rename test/slateval/test/{parser_where.cljc => parser_where.clj} (97%) rename test/slateval/test/{pull_api.cljc => pull_api.clj} (100%) rename test/slateval/test/{pull_parser.cljc => pull_parser.clj} (98%) rename test/slateval/test/{query.cljc => query.clj} (99%) rename test/slateval/test/{query_aggregates.cljc => query_aggregates.clj} (95%) rename test/slateval/test/{query_find_specs.cljc => query_find_specs.clj} (100%) rename test/slateval/test/{query_fns.cljc => query_fns.clj} (98%) rename test/slateval/test/{query_not.cljc => query_not.clj} (98%) rename test/slateval/test/{query_or.cljc => query_or.clj} (99%) rename test/slateval/test/{query_pull.cljc => query_pull.clj} (100%) rename test/slateval/test/{query_return_map.cljc => query_return_map.clj} (99%) rename test/slateval/test/{query_rules.cljc => query_rules.clj} (98%) rename test/slateval/test/{time_travel.cljc => time_travel.clj} (89%) rename test/slateval/test/{transact.cljc => transact.clj} (99%) rename test/slateval/test/{tuples.cljc => tuples.clj} (99%) rename test/slateval/test/{upsert.cljc => upsert.clj} (99%) rename test/slateval/test/{validation.cljc => validation.clj} (98%) diff --git a/.github/workflows/build_test.yml b/.github/workflows/build_test.yml index e08415a..37e2195 100644 --- a/.github/workflows/build_test.yml +++ b/.github/workflows/build_test.yml @@ -25,5 +25,3 @@ jobs: cli: latest lein: latest - run: ./script/test_clj.sh -# - run: ./script/test_cljs.sh -# - run: ./script/test_js.sh diff --git a/deps.edn b/deps.edn index 82a52e6..30ede56 100644 --- a/deps.edn +++ b/deps.edn @@ -10,12 +10,7 @@ } :aliases - {:cljs - {:extra-paths ["test"] - :extra-deps - {org.clojure/clojurescript {:mvn/version "1.11.132"}}} - - :1.9 + {:1.9 {:override-deps {org.clojure/clojure {:mvn/version "1.9.0"}}} @@ -39,8 +34,7 @@ {io.github.tonsky/duti {:git/sha "e36d65296a4f9758664309ec35b00887e88c405a"} metosin/jsonista {:mvn/version "0.3.3"} cheshire/cheshire {:mvn/version "5.10.0"} - com.cognitect/transit-clj {:mvn/version "1.0.324"} - com.cognitect/transit-cljs {:mvn/version "0.8.269"}}} + com.cognitect/transit-clj {:mvn/version "1.0.324"}}} :bench {:extra-paths ["bench"] diff --git a/dev/user.clj b/dev/user.clj index 0ee0e67..c5e125f 100644 --- a/dev/user.clj +++ b/dev/user.clj @@ -11,7 +11,7 @@ duti/-main) (defn test-all [] - (duti/test #"slateval\.test\.(?!cljs).*")) + (duti/test #"slateval\.test\..*")) (defn -test-main [_] - (duti/test-exit #"slateval\.test\.(?!cljs).*")) + (duti/test-exit #"slateval\.test\..*")) diff --git a/release-js/README.md b/release-js/README.md deleted file mode 100644 index 3002937..0000000 --- a/release-js/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# DataScript - -An immutable in-memory database and Datalog query engine for JS engines. - -DataScript is meant to run inside the browser. It is cheap to create, quick to query and ephemeral. You create a database on page load, put some data in it, track changes, do queries and forget about it when the user closes the page. - -DataScript databases are immutable and based on persistent data structures. In fact, they’re more like data structures than databases (think Hashmap). Unlike querying a real SQL DB, when you query DataScript, it all comes down to a Hashmap lookup. Or series of lookups. Or array iteration. There’s no particular overhead to it. You put a little data in it, it’s fast. You put in a lot of data, well, at least it has indexes. That should do better than you filtering an array by hand anyway. The thing is really lightweight. - -The intention with DataScript is to be a basic building block in client-side applications that needs to track a lot of state during their lifetime. There’s a lot of benefits: - -- Central, uniform approach to manage all application state. Clients working with state become decoupled and independent: rendering, server sync, undo/redo do not interfere with each other. -- Immutability simplifies things even in a single-threaded browser environment. Keep track of app state evolution, rewind to any point in time, always render consistent state, sync in background without locking anybody. -- Datalog query engine to answer non-trivial questions about current app state. -- Structured format to track data coming in and out of DB. Datalog queries can be run against it too. - -For more info, check out [project page](https://github.com/tonsky/datascript) diff --git a/release-js/package.json b/release-js/package.json deleted file mode 100644 index d8ec772..0000000 --- a/release-js/package.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "name": "datascript", - "version": "1.7.5", - "description": "Immutable in-memory triplestore with Datalog queries", - "homepage": "https://github.com/tonsky/datascript", - "author": "Nikita Prokopov (https://github.com/tonsky)", - "keywords": [ - "data", - "database", - "triplestore", - "datalog", - "persistent", - "immutable", - "clojure", - "clojurescript" - ], - "contributors": [ - "Nikita Prokopov (https://github.com/tonsky)", - "David Thomas Hume (https://github.com/dthume)", - "montyxcantsin (https://github.com/montyxcantsin)", - "Ben Fleis (https://github.com/benfleis)", - "Gijs Stuurman (https://github.com/thegeez)", - "Yevgeny Armor (https://github.com/izirku)", - "Kevin Lynagh (https://github.com/lynaghk)", - "Bobby Calderwood (https://github.com/bobby)" - ], - "bugs": { - "url": "https://github.com/tonsky/datascript/issues" - }, - "licenses": [ - { - "type": "EPL", - "url": "https://github.com/tonsky/datascript/blob/master/LICENSE" - } - ], - "main": "./datascript.js", - "repository": { - "type": "git", - "url": "git://github.com/tonsky/datascript.git" - }, - "engines": { - "node": ">=0.8.22" - }, - "dependencies": {}, - "files": ["datascript.js"] -} diff --git a/release-js/test_include_amd.html b/release-js/test_include_amd.html deleted file mode 100644 index 8a959ba..0000000 --- a/release-js/test_include_amd.html +++ /dev/null @@ -1,24 +0,0 @@ - - - - DataScript AMD load test - - -

DataScript AMD load test

-

Check the browser console for errors and output.

- - - - - - diff --git a/release-js/test_include_node.js b/release-js/test_include_node.js deleted file mode 100644 index a5680bd..0000000 --- a/release-js/test_include_node.js +++ /dev/null @@ -1,6 +0,0 @@ -var d = require('./datascript'); -var conn = d.create_conn(); -d.transact(conn, [[":db/add", -1, "name", "Ivan"]]); -var res = d.q("[:find ?e ?v :where [?e \"name\" ?v]]", d.db(conn)); -var res_str = JSON.stringify(res); -console.log(res_str); // => [[1, "Ivan"]] diff --git a/release-js/test_include_script.html b/release-js/test_include_script.html deleted file mode 100644 index ff40563..0000000 --- a/release-js/test_include_script.html +++ /dev/null @@ -1,26 +0,0 @@ - - - - DataScript script tag load test - - - -

DataScript script tag load test

-

Check the browser console for errors and output.

- - - - - diff --git a/release-js/wrap_bare.sh b/release-js/wrap_bare.sh deleted file mode 100755 index 05a3204..0000000 --- a/release-js/wrap_bare.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh - -set -e - -(cat release-js/wrapper.prefix; cat release-js/datascript.bare.js; cat release-js/wrapper.suffix) > release-js/datascript.js - -echo "Packed release-js/datascript.js" diff --git a/release-js/wrapper.prefix b/release-js/wrapper.prefix deleted file mode 100644 index 27de4a4..0000000 --- a/release-js/wrapper.prefix +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Datascript v1.7.5 - * - * Copyright 2014-2021 Nikita Prokopov - * - * Licensed under Eclipse Public License; - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://github.com/tonsky/datascript/blob/master/LICENSE - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -(function (definition) { - // This file will function properly as a