Compare commits
3 commits
master
...
rnewman/or
Author | SHA1 | Date | |
---|---|---|---|
|
630f3e0740 | ||
|
4f10100174 | ||
|
7728648b39 |
2 changed files with 86 additions and 12 deletions
|
@ -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
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue