Compare commits

...

3 commits

2 changed files with 86 additions and 12 deletions

View file

@ -8,6 +8,9 @@
[datomish.pair-chan :refer [go-pair <?]] [datomish.pair-chan :refer [go-pair <?]]
[datomish.promises :refer [go-promise]]) [datomish.promises :refer [go-promise]])
(:require (:require
[datomish.util
:as util
:refer-macros [raise raise-str cond-let]]
[cljs.core.async :as a :refer [take! <! >!]] [cljs.core.async :as a :refer [take! <! >!]]
[cljs.reader] [cljs.reader]
[cljs-promises.core :refer [promise]] [cljs-promises.core :refer [promise]]
@ -27,9 +30,29 @@
(def ^:export db d/db) (def ^:export db d/db)
(defn- cljify-options [options]
;; Step one: basic parsing.
(let [o (cljify options)]
;; Step two: convert `order-by` into keywords.
(if-let [ord (:order-by o)]
(assoc o
:order-by
(map
(fn [[var dir]]
[(keyword var)
(case dir
"asc" :asc
"desc" :desc
nil :asc
:default
(raise "Unexpected order-by direction " dir
{:direction dir}))])
ord))
o)))
(defn ^:export q [db find options] (defn ^:export q [db find options]
(let [find (cljs.reader/read-string find) (let [find (cljs.reader/read-string find)
opts (cljify options)] opts (cljify-options options)]
(take-pair-as-promise! (take-pair-as-promise!
(d/<q db find opts) (d/<q db find opts)
clj->js))) clj->js)))
@ -37,7 +60,6 @@
(defn ^:export ensure-schema [conn simple-schema] (defn ^:export ensure-schema [conn simple-schema]
(let [simple-schema (cljify simple-schema) (let [simple-schema (cljify simple-schema)
datoms (simple-schema/simple-schema->schema simple-schema)] datoms (simple-schema/simple-schema->schema simple-schema)]
(println "Transacting schema datoms" (pr-str datoms))
(take-pair-as-promise! (take-pair-as-promise!
(d/<transact! (d/<transact!
conn conn
@ -53,13 +75,20 @@
(try (try
(let [tx-data (js->tx-data tx-data)] (let [tx-data (js->tx-data tx-data)]
(go-promise clj->js (go-promise clj->js
(let [tx-result (<? (d/<transact! conn tx-data))] (let [tx-result (<? (d/<transact! conn tx-data))
(select-keys tx-result tempids (:tempids tx-result)
[:tempids to-return (select-keys tx-result
:added-idents [:tempids
:added-attributes :added-idents
:tx :added-attributes
:txInstant])))) :tx
:txInstant])
jsified (clj->js to-return)]
;; The tempids map isn't enough for a JS caller to look up one of
;; these objects, so we need a lookup function.
(aset jsified "tempid" (fn [t] (get tempids t)))
jsified)))
(catch js/Error e (catch js/Error e
(println "Error in transact:" e)))) (println "Error in transact:" e))))
@ -81,7 +110,11 @@
:q (fn [find opts] (q (d/db c) find opts)) :q (fn [find opts] (q (d/db c) find opts))
:close (fn [] (db/close-db db)) :close (fn [] (db/close-db db))
;; So you can generate keywords for binding in `:inputs`.
:keyword keyword
;; Some helpers for testing the bridge. ;; Some helpers for testing the bridge.
:println (fn [& xs] (apply println xs))
:equal = :equal =
:idx (fn [tempid] (:idx tempid)) :idx (fn [tempid] (:idx tempid))
:cljify cljify :cljify cljify

View file

@ -21,7 +21,9 @@ var schema = {
async function testOpen() { async function testOpen() {
// Open a database. // Open a database.
let db = await datomish.open("/tmp/testing.db"); let path = "/tmp/testing" + Date.now() + ".db";
console.log("Opening " + path);
let db = await datomish.open(path);
// Make sure we have our current schema. // Make sure we have our current schema.
await db.ensureSchema(schema); await db.ensureSchema(schema);
@ -39,7 +41,7 @@ async function testOpen() {
// A simple query. // A simple query.
let results = await db.q("[:find [?url ...] :in $ :where [?e :page/url ?url]]"); let results = await db.q("[:find [?url ...] :in $ :where [?e :page/url ?url]]");
console.log("Query results: " + JSON.stringify(results)); console.log("Known URLs: " + JSON.stringify(results));
// Let's extend our schema. In the real world this would typically happen // Let's extend our schema. In the real world this would typically happen
// across releases. // across releases.
@ -56,7 +58,7 @@ async function testOpen() {
await db.transact([ await db.transact([
{"db/id": datomish.tempid(), {"db/id": datomish.tempid(),
"page/url": "https://mozilla.org/", "page/url": "https://mozilla.org/",
"page/visitedAt": (new Date())} "page/visitedAt": new Date()}
]); ]);
// When did we most recently visit this page? // When did we most recently visit this page?
@ -69,6 +71,45 @@ async function testOpen() {
{"inputs": {"url": "https://mozilla.org/"}})); {"inputs": {"url": "https://mozilla.org/"}}));
console.log("Most recent visit: " + date); console.log("Most recent visit: " + date);
// Add some more data about a couple of pages.
let start = Date.now();
let lr = datomish.tempid();
let reddit = datomish.tempid();
let res = await db.transact([
{"db/id": reddit,
"page/url": "http://reddit.com/",
"page/title": "Reddit",
"page/visitedAt": new Date(start)},
{"db/id": lr,
"page/url": "https://longreads.com/",
"page/title": "Longreads: The best longform stories on the web",
"page/visitedAt": (new Date(start + 100))},
// Two visits each.
{"db/id": lr,
"page/visitedAt": (new Date(start + 200))},
{"db/id": reddit,
"page/visitedAt": (new Date(start + 300))}
]);
// These are our new persistent IDs. We can use these directly in later
// queries or transactions
lr = res.tempid(lr);
reddit = res.tempid(reddit);
console.log("Persistent IDs are " + lr + ", " + reddit + ".");
// A query with a limit and order-by. Because we limit to 2, and order
// by most recent visit date first, we won't get mozilla.org in our results.
let recent = await db.q(
`[:find ?url (max ?date)
:in $
:where
[?page :page/url ?url]
[?page :page/visitedAt ?date]]`,
{"limit": 2, "order-by": [["_max_date", "desc"]]});
console.log("Recently visited: " + JSON.stringify(recent));
// Close: we're done! // Close: we're done!
await db.close(); await db.close();
} }