diff --git a/.babelrc b/.babelrc new file mode 100644 index 00000000..d707934a --- /dev/null +++ b/.babelrc @@ -0,0 +1,27 @@ +{ + "env": { + "production": { + "presets": ["react", "react-optimize"] + }, + "development": { + "presets": ["react"] + }, + "test": { + "presets": ["react"] + } + }, + "only": [ + "test/js/**" + ], + "plugins": [ + "transform-es2015-destructuring", + "transform-es2015-parameters", + "transform-es2015-modules-commonjs", + "transform-async-to-generator", + "transform-object-rest-spread", + "transform-class-properties", + "transform-runtime" + ], + "sourceMaps": "inline", + "retainLines": true +} diff --git a/.gitignore b/.gitignore index 76f17ade..d7fe2318 100644 --- a/.gitignore +++ b/.gitignore @@ -22,11 +22,8 @@ pom.xml pom.xml.asc /.cljs_node_repl/ /.cljs_rhino_repl/ -/release-browser -/release-browser/datomish.js -/release-browser/datomish.bare.js -/release-node -/release-node/datomish.js -/release-node/datomish.bare.js -/addon/datomish-test.xpi -/addon/datomish.js +/addon/built/index.js +/addon/node_modules/ +/addon/release/datomish-test.xpi +/addon/release/datomish.js +/addon/release/index.js diff --git a/README.md b/README.md index d9db9546..77f90f5a 100644 --- a/README.md +++ b/README.md @@ -88,6 +88,24 @@ brew install rlwrap Run `lein cljsbuild auto advanced` to generate JavaScript into `target/`. +To build for a browser, into `release-browser`: + +``` +lein cljsbuild once release-browser +``` + +To build for node, into `release-node`: + +``` +lein cljsbuild once release-node +``` + +To package or install a JAR for node, modifying the source path appropriately (make sure you clean up swap or temp files in `src`!): + +``` +lein with-profile node jar +``` + ### Starting a ClojureScript REPL from the terminal ``` diff --git a/addon/.babelrc b/addon/.babelrc new file mode 100644 index 00000000..a0dc53f5 --- /dev/null +++ b/addon/.babelrc @@ -0,0 +1,6 @@ +{ + "presets": ["es2015"], + "plugins": [ + "transform-async-to-generator" + ] +} diff --git a/addon/CREDITS b/addon/CREDITS new file mode 100644 index 00000000..359a4f89 --- /dev/null +++ b/addon/CREDITS @@ -0,0 +1,3 @@ +Icon file is "Line Graph" by Cris Dobbins, from The Noun Project. + +https://thenounproject.com/term/line-graph/145324/ diff --git a/addon/build.sh b/addon/build.sh new file mode 100755 index 00000000..925bc6c3 --- /dev/null +++ b/addon/build.sh @@ -0,0 +1,3 @@ +cp ../target/release-browser/datomish.js release/ +node_modules/.bin/webpack -p +cat src/wrapper.prefix built/index.js > release/index.js diff --git a/addon/index.js b/addon/index.js deleted file mode 100644 index 765cb243..00000000 --- a/addon/index.js +++ /dev/null @@ -1,15 +0,0 @@ -var self = require("sdk/self"); - -console.log("Datomish Test"); -console.log("This: " + this); - -var datomish = require("datomish.js"); -datomish.open("/tmp/foobar.db").then(function (db) { - console.log("Got " + db); - try { - db.close(); - console.log("Closed."); - } catch (e) { - console.log("Couldn't close: " + e); - } -}); diff --git a/addon/package.json b/addon/package.json index 6a190546..c2e4d9f0 100644 --- a/addon/package.json +++ b/addon/package.json @@ -1,15 +1,23 @@ { - "title": "Datomish Test", - "name": "datomish-test", - "version": "0.0.1", - "description": "An example add-on that loads Datomish on top of Sqlite.jsm.", + "name": "datomish-example", + "version": "1.0.0", + "description": "A test add-on for Datomish and Firefox.", "main": "index.js", - "author": "Richard Newman ", - "engines": { - "firefox": ">=48.0a1" + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" }, + "author": "", "license": "MPL-2.0", - "keywords": [ - "jetpack" - ] + "devDependencies": { + "babel": "^6.5.2", + "babel-cli": "^6.14.0", + "babel-core": "^6.14.0", + "babel-loader": "^6.2.5", + "babel-plugin-transform-async-to-generator": "^6.8.0", + "babel-preset-es2015": "^6.14.0", + "webpack": "^1.13.2" + }, + "dependencies": { + "babel-polyfill": "^6.13.0" + } } diff --git a/addon/README.md b/addon/release/README.md similarity index 100% rename from addon/README.md rename to addon/release/README.md diff --git a/addon/release/data/datomish-48.png b/addon/release/data/datomish-48.png new file mode 100644 index 00000000..42b9cb67 Binary files /dev/null and b/addon/release/data/datomish-48.png differ diff --git a/addon/release/package.json b/addon/release/package.json new file mode 100644 index 00000000..6a190546 --- /dev/null +++ b/addon/release/package.json @@ -0,0 +1,15 @@ +{ + "title": "Datomish Test", + "name": "datomish-test", + "version": "0.0.1", + "description": "An example add-on that loads Datomish on top of Sqlite.jsm.", + "main": "index.js", + "author": "Richard Newman ", + "engines": { + "firefox": ">=48.0a1" + }, + "license": "MPL-2.0", + "keywords": [ + "jetpack" + ] +} diff --git a/addon/release/run.sh b/addon/release/run.sh new file mode 100755 index 00000000..40114394 --- /dev/null +++ b/addon/release/run.sh @@ -0,0 +1 @@ +jpm run -b /Applications/FirefoxNightly.app/ diff --git a/addon/src/index.js b/addon/src/index.js new file mode 100644 index 00000000..d0cb6142 --- /dev/null +++ b/addon/src/index.js @@ -0,0 +1,92 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +var self = require("sdk/self"); +var buttons = require('sdk/ui/button/action'); +var tabs = require('sdk/tabs'); + +var datomish = require("datomish.js"); + +var schema = { + "name": "pages", + "attributes": [ + {"name": "page/url", + "type": "string", + "cardinality": "one", + "unique": "identity", + "doc": "A page's URL."}, + {"name": "page/title", + "type": "string", + "cardinality": "one", + "fulltext": true, + "doc": "A page's title."}, + {"name": "page/content", + "type": "string", + "cardinality": "one", // Simple for now. + "fulltext": true, + "doc": "A snapshot of the page's content. Should be plain text."}, + ] +}; + +async function initDB(path) { + let db = await datomish.open(path); + await db.ensureSchema(schema); + return db; +} + +async function findURLs(db) { + let query = `[:find ?page ?url ?title :in $ :where [?page :page/url ?url][(get-else $ ?page :page/title "") ?title]]`; + let options = new Object(); + options["limit"] = 10; + return datomish.q(db.db(), query, options); +} + +async function findPagesMatching(db, string) { + let query = + `[:find ?url ?title + :in $ ?str + :where + [(fulltext $ :any ?str) [[?page]]] + [?page :page/url ?url] + [(get-else $ ?page :page/title "") ?title]]`; + return datomish.q(db.db(), query, {"limit": 10, "inputs": {"str": string}}); +} + +async function savePage(db, url, title, content) { + let datom = {"db/id": 55, "page/url": url}; + if (title) { + datom["page/title"] = title; + } + if (content) { + datom["page/content"] = content; + } + let txResult = await db.transact([datom]); + return txResult; +} + +async function handleClick(state) { + let db = await datomish.open("/tmp/testing.db"); + await db.ensureSchema(schema); + + let txResult = await savePage(db, tabs.activeTab.url, tabs.activeTab.title, "Content goes here"); + + console.log("Transaction returned " + JSON.stringify(txResult)); + console.log("Transaction instant: " + txResult.txInstant); + + let results = await findURLs(db); + results = results.map(r => r[1]); + + console.log("Query results: " + JSON.stringify(results)); + + let pages = await findPagesMatching(db, "goes"); + + console.log("Pages: " + JSON.stringify(pages)); + await db.close(); +} + +var button = buttons.ActionButton({ + id: "datomish-save", + label: "Save Page", + icon: "./datomish-48.png", + onClick: handleClick +}); diff --git a/addon/src/wrapper.prefix b/addon/src/wrapper.prefix new file mode 100644 index 00000000..f69c8236 --- /dev/null +++ b/addon/src/wrapper.prefix @@ -0,0 +1,4 @@ +// Monkeypatch. +var { setTimeout } = require("sdk/timers"); +this.setTimeout = setTimeout; + diff --git a/addon/webpack.config.js b/addon/webpack.config.js new file mode 100644 index 00000000..f82bede4 --- /dev/null +++ b/addon/webpack.config.js @@ -0,0 +1,21 @@ + +module.exports = { + entry: ['babel-polyfill', './src/index.js'], + output: { + filename: 'built/index.js' + }, + target: 'webworker', + externals: { + 'datomish.js': 'commonjs datomish.js', + 'sdk/self': 'commonjs sdk/self', + 'sdk/ui/button/action': 'commonjs sdk/ui/button/action', + 'sdk/tabs': 'commonjs sdk/tabs' + }, + module: { + loaders: [{ + test: /\.js?$/, + exclude: /(node_modules)|(wrapper.prefix)/, + loader: 'babel' + }] + } +} diff --git a/package.json b/package.json index 9e2570e9..696f3d89 100644 --- a/package.json +++ b/package.json @@ -7,13 +7,32 @@ "version": "0.1.0-SNAPSHOT", "description": "A persistent, embedded knowledge base inspired by Datomic and DataScript.", "dependencies": { - "promise-sqlite": "1.2.1", + "promise-sqlite": "1.3.0", "source-map-support": "ncalexan/node-source-map-support#fileUrls-plus", - "sqlite3": "mossop/node-sqlite3#v3.1.4.1", + "sqlite3": "3.1.4", "thenify-all": "^1.6.0", "ws": "1.1.1" }, + "scripts": { + "test": "babel-node test/js/tests.js" + }, "devDependencies": { + "babel-cli": "^6.14.0", + "babel-core": "6.14.0", + "babel-eslint": "6.1.2", + "babel-loader": "6.2.5", + "babel-plugin-transform-async-to-generator": "6.8.0", + "babel-plugin-transform-class-properties": "6.11.5", + "babel-plugin-transform-es2015-destructuring": "6.9.0", + "babel-plugin-transform-es2015-modules-commonjs": "6.11.5", + "babel-plugin-transform-es2015-parameters": "6.11.4", + "babel-plugin-transform-object-rest-spread": "6.8.0", + "babel-plugin-transform-runtime": "6.12.0", + "babel-polyfill": "6.13.0", + "babel-preset-react": "6.11.1", + "babel-preset-react-optimize": "1.0.1", + "babel-register": "6.14.0", + "babel-runtime": "6.11.6", "tmp": "0.0.28" }, "repository": { @@ -27,5 +46,7 @@ }, "homepage": "https://github.com/mozilla/datomish#readme", "main": "./datomish.js", - "files": ["datomish.js"] + "files": [ + "datomish.js" + ] } diff --git a/project.clj b/project.clj index bf0b92a6..e1f2b6f5 100644 --- a/project.clj +++ b/project.clj @@ -1,4 +1,4 @@ -(defproject datomish "0.1.0-SNAPSHOT" +(defproject datomish "0.1.1-SNAPSHOT" :description "A persistent, embedded knowledge base inspired by Datomic and DataScript." :url "https://github.com/mozilla/datomish" :license {:name "Mozilla Public License Version 2.0" @@ -12,26 +12,35 @@ [jamesmacaulay/cljs-promises "0.1.0"]] ;; The browser will never require from the .JAR anyway. - :source-paths ["src/common" "src/node"] + :source-paths [ + "src/common" + ;; Can't be enabled by default: layers on top of cljsbuild! + ;; Instead, add the :node profile: + ;; lein with-profile node install + ;"src/node" + ] :cljsbuild {:builds { :release-node { - :source-paths ["src/node" "src/common"] + :source-paths ["src/common" "src/node"] :assert false :compiler { + ;; :externs specified in deps.cljs. :elide-asserts true :hashbang false :language-in :ecmascript5 :language-out :ecmascript5 :optimizations :advanced - :output-dir "release-node" - :output-to "release-node/datomish.bare.js" + :output-dir "target/release-node" + :output-to "target/release-node/datomish.bare.js" :output-wrapper false :parallel-build true - :pretty-print false + :pretty-print true + :pseudo-names true + :static-fns true :target :nodejs } :notify-command ["release-node/wrap_bare.sh"]} @@ -46,17 +55,17 @@ ;; There's no point in generating a source map -- it'll be wrong ;; due to wrapping. { - :source-paths ["src/browser" "src/common"] + :source-paths ["src/common" "src/browser"] :assert false :compiler { :elide-asserts true - :externs ["src/browser/externs.js"] + :externs ["src/browser/externs/datomish.js"] :language-in :ecmascript5 :language-out :ecmascript5 :optimizations :advanced - :output-dir "release-browser" - :output-to "release-browser/datomish.bare.js" + :output-dir "target/release-browser" + :output-to "target/release-browser/datomish.bare.js" :output-wrapper false :parallel-build true :preloads [datomish.preload] @@ -66,24 +75,9 @@ } :notify-command ["release-browser/wrap_bare.sh"]} - :advanced - {:source-paths ["src/node" "src/common"] - :compiler - { - :language-in :ecmascript5 - :language-out :ecmascript5 - :output-dir "target/advanced" - :output-to "target/advanced/datomish.js" - :optimizations :advanced - :parallel-build true - :pretty-print true - :source-map "target/advanced/datomish.js.map" - :target :nodejs - }} - :test { - :source-paths ["src/node" "src/common" "test"] + :source-paths ["src/common" "src/node" "test"] :compiler { :language-in :ecmascript5 @@ -98,7 +92,8 @@ }} }} - :profiles {:dev {:dependencies [[cljsbuild "1.1.3"] + :profiles {:node {:source-paths ["src/common" "src/node"]} + :dev {:dependencies [[cljsbuild "1.1.3"] [tempfile "0.2.0"] [com.cemerick/piggieback "0.2.1"] [org.clojure/tools.nrepl "0.2.10"] @@ -114,26 +109,5 @@ :doo {:build "test"} - :clean-targets ^{:protect false} - [ - "target" - "release-node/cljs/" - "release-node/cljs_promises/" - "release-node/clojure/" - "release-node/datascript/" - "release-node/datomish/" - "release-node/honeysql/" - "release-node/taoensso/" - "release-node/datomish.bare.js" - "release-node/datomish.js" - "release-browser/cljs/" - "release-browser/cljs_promises/" - "release-browser/clojure/" - "release-browser/datascript/" - "release-browser/datomish/" - "release-browser/honeysql/" - "release-browser/taoensso/" - "release-browser/datomish.bare.js" - "release-browser/datomish.js" - ] + :clean-targets ^{:protect false} ["target"] ) diff --git a/release-browser/test_include_node.js b/release-browser/test_include_node.js deleted file mode 100644 index 683261cd..00000000 --- a/release-browser/test_include_node.js +++ /dev/null @@ -1,2 +0,0 @@ -var d = require('./datomish'); -console.log(d.q("[:find ?e ?v :where [?e \"name\" ?v] {:x :y}]")); diff --git a/release-browser/wrap_bare.sh b/release-browser/wrap_bare.sh index 6d5ae26a..ff03a0d4 100755 --- a/release-browser/wrap_bare.sh +++ b/release-browser/wrap_bare.sh @@ -2,6 +2,6 @@ set -e -(cat release-browser/wrapper.prefix; cat release-browser/datomish.bare.js; cat release-browser/wrapper.suffix) > release-browser/datomish.js +(cat release-browser/wrapper.prefix; cat target/release-browser/datomish.bare.js; cat release-browser/wrapper.suffix) > target/release-browser/datomish.js -echo "Packed release-browser/datomish.js" +echo "Packed target/release-browser/datomish.js" diff --git a/release-node/test_include_node.js b/release-node/test_include_node.js index 683261cd..2abc19d9 100644 --- a/release-node/test_include_node.js +++ b/release-node/test_include_node.js @@ -1,2 +1,2 @@ -var d = require('./datomish'); +var d = require('../target/release-node/datomish'); console.log(d.q("[:find ?e ?v :where [?e \"name\" ?v] {:x :y}]")); diff --git a/release-node/wrap_bare.sh b/release-node/wrap_bare.sh index 13707e8f..50e0916e 100755 --- a/release-node/wrap_bare.sh +++ b/release-node/wrap_bare.sh @@ -2,6 +2,6 @@ set -e -(cat release-node/wrapper.prefix && cat release-node/datomish.bare.js && cat release-node/wrapper.suffix) > release-node/datomish.js +(cat release-node/wrapper.prefix && cat target/release-node/datomish.bare.js && cat release-node/wrapper.suffix) > target/release-node/datomish.js -echo "Packed release-node/datomish.js" +echo "Packed target/release-node/datomish.js" diff --git a/src/browser/datomish/cljify.cljs b/src/browser/datomish/cljify.cljs new file mode 100644 index 00000000..7c02f5bb --- /dev/null +++ b/src/browser/datomish/cljify.cljs @@ -0,0 +1,47 @@ +(ns datomish.cljify) + +(defn cljify + "Does what `(js->clj o :keywordize-keys true) is supposed to do, but works + in environments with more than one context (e.g., web browsers). + + See . + + Note that Date instances are passed through." + [o] + (cond + (nil? o) + nil + + ;; Primitives. + (or + (true? o) + (false? o) + (number? o) + (string? o) + ;; Dates are passed through. + (not (nil? (aget (aget o "__proto__") "getUTCMilliseconds")))) + o + + ;; Array. + (.isArray js/Array o) + (let [n (.-length o)] + (loop [i 0 + acc (transient [])] + (if (< i n) + (recur (inc i) (conj! acc (cljify (aget o i)))) + (persistent! acc)))) + + ;; Object. + (not (nil? (aget (aget o "__proto__") "hasOwnProperty"))) + (let [a (.keys js/Object o) + n (.-length a)] + (loop [i 0 + acc (transient {})] + (if (< i n) + (let [key (aget a i)] + (recur (inc i) (assoc! acc + (keyword key) + (cljify (aget o key))))) + (persistent! acc)))) + + :else o)) diff --git a/src/browser/externs.js b/src/browser/externs/datomish.js similarity index 74% rename from src/browser/externs.js rename to src/browser/externs/datomish.js index a39b1a03..f6356568 100644 --- a/src/browser/externs.js +++ b/src/browser/externs/datomish.js @@ -1,3 +1,11 @@ +var Object = {}; +Object.keys = function (object) {}; +Object.__proto__ = {}; +Object.hasOwnProperty = function () {}; +var Array = {}; +Array.length = 0; +Array.isArray = function () {}; + var SqliteStatic = {}; /** diff --git a/src/common/datomish/db.cljc b/src/common/datomish/db.cljc index 16b74700..5fd28115 100644 --- a/src/common/datomish/db.cljc +++ b/src/common/datomish/db.cljc @@ -713,6 +713,10 @@ Returns a transduced channel of [result err] pairs. Closes the channel when fully consumed." [db find options] + (let [unexpected (seq (clojure.set/difference (set (keys options)) #{:limit :order-by :inputs}))] + (when unexpected + (raise "Unexpected options: " unexpected {:bad-options unexpected}))) + (let [{:keys [limit order-by inputs]} options parsed (query/parse find) context (-> db diff --git a/src/common/datomish/js.cljs b/src/common/datomish/js.cljs index c67f7854..0c7ab46b 100644 --- a/src/common/datomish/js.cljs +++ b/src/common/datomish/js.cljs @@ -5,43 +5,78 @@ (ns datomish.js (:refer-clojure :exclude []) (:require-macros - [datomish.pair-chan :refer [go-pair !]] [cljs.reader] [cljs-promises.core :refer [promise]] + [datomish.cljify :refer [cljify]] [datomish.db :as db] [datomish.db-factory :as db-factory] [datomish.pair-chan] + [datomish.promises :refer [take-pair-as-promise!]] [datomish.sqlite :as sqlite] + [datomish.simple-schema :as simple-schema] [datomish.js-sqlite :as js-sqlite] [datomish.transact :as transact])) -(defn- take-pair-as-promise! [ch] - ;; Just like take-as-promise!, but aware that it's handling a pair channel. - (promise - (fn [resolve reject] - (letfn [(split-pair [[v e]] - (if e - (reject e) - (resolve v)))] - (cljs.core.async/take! ch split-pair))))) ;; Public API. +(defn ^:export db [conn] + (transact/db conn)) + +(defn ^:export q [db find options] + (let [find (cljs.reader/read-string find) + opts (cljify options)] + (take-pair-as-promise! + (db/js))) + +(defn ^:export ensure-schema [conn simple-schema] + (let [simple-schema (cljify simple-schema) + datoms (simple-schema/simple-schema->schema simple-schema)] + (println "Transacting schema datoms" (pr-str datoms)) + (take-pair-as-promise! + (transact/js))) + +(def js->tx-data cljify) + +(def ^:export tempid (partial db/id-literal :db.part/user)) + +(defn ^:export transact [conn tx-data] + ;; Expects a JS array as input. + (try + (let [tx-data (js->tx-data tx-data)] + (println "Transacting:" (pr-str tx-data)) + (go-promise clj->js + (let [tx-result (js - {:conn c - :close (fn [] (db/close-db db)) - :toString (fn [] (str "#")) - :path path})))))) - -(defn ^:export q [query & sources] - (let [query (cljs.reader/read-string query)] - (clj->js query))) + (go-promise clj->js + (let [conn (js (cljify x))) + :db (fn [] (transact/db c)) + :ensureSchema (fn [simple-schema] (ensure-schema c simple-schema)) + :transact (fn [tx-data] (transact c tx-data)) + :close (fn [] (db/close-db db)) + :toString (fn [] (str "#")) + :path path})))) diff --git a/src/common/datomish/promises.cljc b/src/common/datomish/promises.cljc new file mode 100644 index 00000000..feee3d27 --- /dev/null +++ b/src/common/datomish/promises.cljc @@ -0,0 +1,30 @@ +(ns datomish.promises + #?(:cljs + (:require-macros + [datomish.pair-chan :refer [go-pair Schema {:schema (validate-schema schema) :rschema (rschema schema)})) + diff --git a/src/common/datomish/simple_schema.cljc b/src/common/datomish/simple_schema.cljc new file mode 100644 index 00000000..2bba32d7 --- /dev/null +++ b/src/common/datomish/simple_schema.cljc @@ -0,0 +1,66 @@ +;; This Source Code Form is subject to the terms of the Mozilla Public +;; License, v. 2.0. If a copy of the MPL was not distributed with this +;; file, You can obtain one at http://mozilla.org/MPL/2.0/. + +(ns datomish.simple-schema + #?(:cljs + (:require-macros + [datomish.pair-chan :refer [go-pair !]]]) + #?@(:cljs [[datomish.pair-chan] + [cljs.core.async :as a :refer [chan !]]]))) + +(defn- name->ident [name] + (when-not (and (string? name) + (not (empty? name))) + (raise "Invalid name " name {:error :invalid-name :name name})) + (keyword name)) + +(defn simple-schema-attributes->schema-parts [attrs] + (let [{:keys [cardinality type name unique doc fulltext]} attrs + value-type (when type (keyword (str "db.type/" type)))] + + (when-not (and value-type + (contains? ds/value-type-map value-type)) + (raise "Invalid type " type {:error :invalid-type :type type})) + + (let [unique + (case unique + "identity" :db.unique/identity + "value" :db.unique/value + nil nil + (raise "Invalid unique " unique + {:error :invalid-unique :unique unique})) + + cardinality + (case cardinality + "one" :db.cardinality/one + "many" :db.cardinality/many + nil nil + (raise "Invalid cardinality " cardinality + {:error :invalid-cardinality :cardinality cardinality}))] + + (util/assoc-if + {:db/valueType value-type + :db/ident (name->ident name) + :db/id (db/id-literal :db.part/user) + :db.install/_attribute :db.part/db} + :db/doc doc + :db/unique unique + :db/fulltext fulltext + :db/cardinality cardinality)))) + +(defn simple-schema->schema [simple-schema] + (let [{:keys [name attributes]} simple-schema] + (map simple-schema-attributes->schema-parts attributes))) + diff --git a/src/node/datomish/cljify.cljs b/src/node/datomish/cljify.cljs new file mode 100644 index 00000000..3ef64a3f --- /dev/null +++ b/src/node/datomish/cljify.cljs @@ -0,0 +1,7 @@ +(ns datomish.cljify) + +(defn cljify + "In node, equivalent to `(js->clj o :keywordize-keys true). + See ." + [o] + (js->clj o :keywordize-keys true)) diff --git a/src/node/datomish/core.cljs b/src/node/datomish/core.cljs index 61e7b573..7b77da5a 100644 --- a/src/node/datomish/core.cljs +++ b/src/node/datomish/core.cljs @@ -5,9 +5,6 @@ (ns datomish.core (:require [cljs.nodejs :as nodejs])) -(nodejs/enable-util-print!) - -(defn -main [& args] - (println "Hello world!")) - +(defn -main [& args]) (set! *main-cli-fn* -main) +(nodejs/enable-util-print!) diff --git a/src/node/datomish/promise_sqlite.cljs b/src/node/datomish/promise_sqlite.cljs index 539fd5da..ddf6c1c3 100644 --- a/src/node/datomish/promise_sqlite.cljs +++ b/src/node/datomish/promise_sqlite.cljs @@ -5,6 +5,7 @@ (ns datomish.promise-sqlite (:require [datomish.sqlite :as s] + [datomish.cljify :refer [cljify]] [cljs-promises.async] [cljs.nodejs :as nodejs])) @@ -20,7 +21,7 @@ (-each [db sql bindings row-cb] (let [cb (fn [row] - (row-cb (js->clj row :keywordize-keys true)))] + (row-cb (cljify row)))] (cljs-promises.async/pair-port (.each (.-db db) sql (or (clj->js bindings) #js []) (when row-cb cb))))) diff --git a/src/node/deps.cljs b/src/node/deps.cljs new file mode 100644 index 00000000..c41ac085 --- /dev/null +++ b/src/node/deps.cljs @@ -0,0 +1 @@ +{:externs ["externs/datomish.js"]} diff --git a/src/node/externs/datomish.js b/src/node/externs/datomish.js new file mode 100644 index 00000000..5bfb1525 --- /dev/null +++ b/src/node/externs/datomish.js @@ -0,0 +1,13 @@ +var sqlite = {}; + +sqlite.DB = {}; + +/** + * @return {Promise} + */ +sqlite.DB.open = function (path, options) {}; + +var DBVal = {}; +DBVal.run = function (sql, bindings) {}; +DBVal.close = function () {}; +DBVal.each = function (sql, bindings, cb) {}; diff --git a/test/datomish/db_test.cljc b/test/datomish/db_test.cljc index 2d972461..1dea8c66 100644 --- a/test/datomish/db_test.cljc +++ b/test/datomish/db_test.cljc @@ -13,6 +13,7 @@ [datomish.db.debug :refer [schema in)) + expected))))) + + #_ (time (t/run-tests)) diff --git a/test/js/tests.js b/test/js/tests.js new file mode 100644 index 00000000..e69b55c5 --- /dev/null +++ b/test/js/tests.js @@ -0,0 +1,46 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +var datomish = require("../../target/release-node/datomish.js"); + +var schema = { + "name": "pages", + "attributes": [ + {"name": "page/url", + "type": "string", + "cardinality": "one", + "unique": "identity", + "doc": "A page's URL."}, + {"name": "page/title", + "type": "string", + "cardinality": "one", + "doc": "A page's title."}, + {"name": "page/starred", + "type": "boolean", + "cardinality": "one", + "doc": "Whether the page is starred."}, + {"name": "page/visit", + "type": "ref", + "cardinality": "many", + "doc": "A visit to the page."} + ] +}; + +async function testOpen() { + let db = await datomish.open("/tmp/testing.db"); + await db.ensureSchema(schema); + let txResult = await db.transact([{"db/id": 55, + "page/url": "http://foo.com/bar", + "page/starred": true}]); + console.log("Transaction returned " + JSON.stringify(txResult)); + console.log("Transaction instant: " + txResult.txInstant); + let results = await datomish.q(db.db(), "[:find ?url :in $ :where [?e :page/url ?url]]") + results = results.map(r => r[0]); + console.log("Query results: " + JSON.stringify(results)); + await db.close(); +} + +testOpen() +.then((r) => console.log("Done.")) +.catch((e) => console.log("Failure: " + e.stack));