diff --git a/test/datalevin/main_test.cljc b/test/datalevin/main_test.cljc index 8ec658c6..9d16f384 100644 --- a/test/datalevin/main_test.cljc +++ b/test/datalevin/main_test.cljc @@ -5,10 +5,13 @@ [datalevin.interpret :as i] [datalevin.lmdb :as l] [datalevin.test.core :as tdc :refer [db-fixture]] + [taoensso.nippy :as nippy] [clojure.test :refer [deftest testing is use-fixtures]] [clojure.test.check.generators :as gen] - [clojure.string :as s]) - (:import [java.util UUID Date Arrays])) + [clojure.string :as s] + [clojure.edn :as edn]) + (:import [java.util UUID Date Arrays] + [java.net URL])) (use-fixtures :each db-fixture) @@ -141,85 +144,134 @@ (u/delete-files src-dir) (u/delete-files dest-dir))) + +;; some constructors and methods to accompany a #url +;; tagged literal - including nippy (de)serialization + +(defn ->url [s] (URL. s)) + +(defmethod print-method URL [url writer] + (doto writer + (.write "#url ") + (.write "\"") + (.write (.toString url)) + (.write "\""))) + +(defmethod print-dup URL [url writer] + (doto writer + (.write "#url ") + (.write "\"") + (.write (.toString url)) + (.write "\""))) + +(nippy/extend-freeze + URL :java.net/URL + [url data-output] + (.writeUTF data-output (pr-str url))) + +(nippy/extend-thaw + :java.net/URL + [data-input] + (edn/read-string + {:readers {'url datalevin.main-test/->url}} + (.readUTF data-input))) + (deftest dump-load-datalog-test - (let [analyzer (i/inter-fn [^String text] - (map-indexed (fn [i ^String t] - [t i (.indexOf text t)]) - (s/split text #"\s"))) - schema {:a/string {:db/valueType :db.type/string - :db/fulltext true} - :a/keyword {:db/valueType :db.type/keyword} - :a/symbol {:db/valueType :db.type/symbol} - :a/boolean {:db/valueType :db.type/boolean} - :a/long {:db/valueType :db.type/long} - :a/double {:db/valueType :db.type/double} - :a/float {:db/valueType :db.type/float} - :a/ref {:db/valueType :db.type/ref} - :a/instant {:db/valueType :db.type/instant} - :a/uuid {:db/valueType :db.type/uuid} - :a/bytes {:db/valueType :db.type/bytes}} - opts {:auto-entity-time? true - :search-engine {:analyzer analyzer}} - src-dir (u/tmp-dir (str "src-dump-dl-" (UUID/randomUUID))) - conn (d/create-conn src-dir schema opts) - dest-dir (u/tmp-dir (str "dest-load-dl-" (UUID/randomUUID))) - dl-file (str (u/tmp-dir) "dl") - s "The quick brown fox jumps over the lazy dog" - now (Date.) - uuid (UUID/randomUUID) - bs (.getBytes ^String s) - vs (repeatedly 10 #(gen/generate gen/any-printable-equatable 1000)) - txs (into [{:db/id -1 - :hello "Datalevin"} - {:a/keyword :something/nice - :a/symbol 'wonderful/life - :a/string s} - {:a/boolean true - :a/long 42} - {:a/double (double 3.141592) - :a/float (float 2.71828) - :a/ref -1} - {:a/instant now - :a/uuid uuid - :a/bytes bs}] - (mapv (fn [a v] {a v}) - (repeat :large/random) - vs))] - (d/transact! conn txs) - (is (= (d/q '[:find ?v . - :in $ ?q - :where [(fulltext $ ?q) [[?e ?a ?v]]]] - (d/db conn) "brown fox") s)) - (d/close conn) - (sut/dump src-dir dl-file nil false true false) - (sut/load dest-dir dl-file nil true) - (let [conn1 (d/create-conn dest-dir nil opts)] + ;; rebinding *datalevin-data-readers* to ensure support for + ;; reading in custom tagged literals works + ;; (removing the custom ->url reader will cause the tests to fail) + (binding [sut/*datalevin-data-readers* + (merge sut/datalevin-data-readers + {'url datalevin.main-test/->url})] + + (let [analyzer (i/inter-fn [^String text] + (map-indexed (fn [i ^String t] + [t i (.indexOf text t)]) + (s/split text #"\s"))) + schema {:a/string {:db/valueType :db.type/string + :db/fulltext true} + :a/keyword {:db/valueType :db.type/keyword} + :a/symbol {:db/valueType :db.type/symbol} + :a/boolean {:db/valueType :db.type/boolean} + :a/long {:db/valueType :db.type/long} + :a/double {:db/valueType :db.type/double} + :a/float {:db/valueType :db.type/float} + :a/ref {:db/valueType :db.type/ref} + :a/instant {:db/valueType :db.type/instant} + :a/uuid {:db/valueType :db.type/uuid} + :a/bytes {:db/valueType :db.type/bytes}} + opts {:auto-entity-time? true + :search-engine {:analyzer analyzer}} + src-dir (u/tmp-dir (str "src-dump-dl-" (UUID/randomUUID))) + conn (d/create-conn src-dir schema opts) + dest-dir (u/tmp-dir (str "dest-load-dl-" (UUID/randomUUID))) + dl-file (str (u/tmp-dir) "dl") + s "The quick brown fox jumps over the lazy dog" + now (Date.) + uuid (UUID/randomUUID) + bs (.getBytes ^String s) + vs (repeatedly 10 #(gen/generate gen/any-printable-equatable 1000)) + txs (into [{:db/id -1 + :hello "Datalevin"} + {:a/keyword :something/nice + :a/symbol 'wonderful/life + :a/string s} + {:a/boolean true + :a/long 42} + {:a/double (double 3.141592) + :a/float (float 2.71828) + :a/ref -1} + {:a/instant now + :a/uuid uuid + :a/bytes bs} + ;; reading from string to replicate the error + ;; case where a tagged literal is not available + ;; on the project classpath + (clojure.edn/read-string + {:readers + {'url datalevin.main-test/->url}} + "{:a/url #url \"https://wikipedia.org\" + :a/string \"def\"}")] + (mapv (fn [a v] {a v}) + (repeat :large/random) + vs))] + (d/transact! conn txs) (is (= (d/q '[:find ?v . :in $ ?q :where [(fulltext $ ?q) [[?e ?a ?v]]]] - (d/db conn1) "brown fox") s)) - - (is (= (d/q '[:find ?v . :where [_ :hello ?v]] @conn1) "Datalevin" )) - (is (= (d/q '[:find ?v . :where [_ :a/keyword ?v]] @conn1) - :something/nice)) - (is (= (d/q '[:find ?v . :where [_ :a/symbol ?v]] @conn1) - 'wonderful/life)) - (is (= (d/q '[:find ?v . :where [_ :a/string ?v]] @conn1) s)) - (is (= (d/q '[:find ?v . :where [_ :a/boolean ?v]] @conn1) true)) - (is (= (d/q '[:find ?v . :where [_ :a/long ?v]] @conn1) 42)) - (is (= (d/q '[:find ?v . :where [_ :a/double ?v]] @conn1) - (double 3.141592))) - (is (= (d/q '[:find ?v . :where [_ :a/float ?v]] @conn1) - (float 2.71828))) - (is (= (d/q '[:find ?v . :where [_ :a/ref ?v]] @conn1) - (d/q '[:find ?e . :where [?e :hello]] @conn1))) - (is (= (d/q '[:find ?v . :where [_ :a/instant ?v]] @conn1) now)) - (is (= (d/q '[:find ?v . :where [_ :a/uuid ?v]] @conn1) uuid)) - (is (Arrays/equals - ^bytes (d/q '[:find ?v . :where [_ :a/bytes ?v]] @conn1) - ^bytes bs)) - (is (= (set - (d/q '[:find [?v ...] :where [_ :large/random ?v]] @conn1)) - (set vs))) - (d/close conn1) - (u/delete-files (str (u/tmp-dir) "dl"))))) + (d/db conn) "brown fox") s)) + (d/close conn) + (sut/dump src-dir dl-file nil false true false) + (sut/load dest-dir dl-file nil true) + (let [conn1 (d/create-conn dest-dir nil opts)] + (is (= (d/q '[:find ?v . + :in $ ?q + :where [(fulltext $ ?q) [[?e ?a ?v]]]] + (d/db conn1) "brown fox") s)) + + (is (= (d/q '[:find ?v . :where [_ :hello ?v]] @conn1) "Datalevin" )) + (is (= (d/q '[:find ?v . :where [_ :a/keyword ?v]] @conn1) + :something/nice)) + (is (= (d/q '[:find ?v . :where [_ :a/symbol ?v]] @conn1) + 'wonderful/life)) + (is (= (d/q '[:find ?v . :where [_ :a/string ?v]] @conn1) s)) + (is (= (d/q '[:find ?v . :where [_ :a/boolean ?v]] @conn1) true)) + (is (= (d/q '[:find ?v . :where [_ :a/long ?v]] @conn1) 42)) + (is (= (d/q '[:find ?v . :where [_ :a/double ?v]] @conn1) + (double 3.141592))) + (is (= (d/q '[:find ?v . :where [_ :a/float ?v]] @conn1) + (float 2.71828))) + (is (= (d/q '[:find ?v . :where [_ :a/ref ?v]] @conn1) + (d/q '[:find ?e . :where [?e :hello]] @conn1))) + (is (= (d/q '[:find ?v . :where [_ :a/instant ?v]] @conn1) now)) + (is (= (d/q '[:find ?v . :where [_ :a/uuid ?v]] @conn1) uuid)) + (is (= (d/q '[:find ?v . :where [_ :a/url ?v]] @conn1) + (->url "https://wikipedia.org"))) + (is (Arrays/equals + ^bytes (d/q '[:find ?v . :where [_ :a/bytes ?v]] @conn1) + ^bytes bs)) + (is (= (set + (d/q '[:find [?v ...] :where [_ :large/random ?v]] @conn1)) + (set vs))) + (d/close conn1) + (u/delete-files (str (u/tmp-dir) "dl"))))))