Skip to content
This repository has been archived by the owner on Dec 8, 2024. It is now read-only.

Commit

Permalink
Add xtdb-starter demo
Browse files Browse the repository at this point in the history
  • Loading branch information
ggeoffrey committed Jan 29, 2024
1 parent e200f96 commit 184fb00
Show file tree
Hide file tree
Showing 6 changed files with 168 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,6 @@ node_modules
.DS_Store
#src/**/*.js -- for tsc modules only, see https://github.com/hyperfiddle/photon/commit/0aa9b26c35d961151891c1e42ec13fcf52e38fa2
/src-dev/fiddles.cljc
# for xtdb-starter demo:
data
# ---
7 changes: 7 additions & 0 deletions deps.edn
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,13 @@
{:extra-deps
{com.datomic/peer {:mvn/version "1.0.7075"}}}

:xtdb-starter ; process must be started with `XTDB_ENABLE_BYTEUTILS_SHA1=true clj -A:xtdb-starter:...`
{:extra-deps
{com.xtdb/xtdb-core {:mvn/version "1.23.0"}
com.xtdb/xtdb-rocksdb {:mvn/version "1.23.0"}}
:jvm-opts [;; the following option is required for JDK 16 and 17 (https://github.com/xtdb/xtdb/issues/1462)
"--add-opens=java.base/java.util.concurrent=ALL-UNNAMED"]}

:uix-demo
{:extra-deps {com.pitch/uix.core {:mvn/version "1.0.1"}
com.pitch/uix.dom {:mvn/version "1.0.1"}}}
Expand Down
18 changes: 18 additions & 0 deletions src/xtdb_starter/Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
This demo requires an environment variable to be set.

Run a REPL:
```shell
XTDB_ENABLE_BYTEUTILS_SHA1=true clj -A:dev:xtdb-starter
```
At the REPL:
```clojure
(dev/-main)
(dev/load-fiddle! 'xtdb-starter)
```

Build and run for prod:

```shell
clojure -X:build:prod:xtdb-starter build-client :hyperfiddle/domain xtdb-starter
XTDB_ENABLE_BYTEUTILS_SHA1=true clj -M:prod:xtdb-starter -m prod
```
41 changes: 41 additions & 0 deletions src/xtdb_starter/fiddles.cljc
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
(ns xtdb-starter.fiddles
(:require #?(:clj [clojure.java.io :as io])
#?(:clj [xtdb.api :as xt])
[hyperfiddle.electric-dom2 :as dom]
[hyperfiddle.electric :as e]
[xtdb-starter.todo-list :refer [Todo-list]]))

#?(:clj (defonce !xtdb-node (atom nil)))

#?(:clj
(defn start-xtdb! [] ; from XTDB’s getting started: xtdb-in-a-box
(assert (= "true" (System/getenv "XTDB_ENABLE_BYTEUTILS_SHA1"))) ; App must start with this env var set to "true"
(letfn [(kv-store [dir] {:kv-store {:xtdb/module 'xtdb.rocksdb/->kv-store
:db-dir (io/file dir)
:sync? true}})]
(or @!xtdb-node
(reset! !xtdb-node
(xt/start-node
{:xtdb/tx-log (kv-store "data/dev/tx-log")
:xtdb/document-store (kv-store "data/dev/doc-store")
:xtdb/index-store (kv-store "data/dev/index-store")}))))))

(e/defn XTDB-Starter []
(e/server
(if-let [!xtdb (try (e/offload #(start-xtdb!))
(catch hyperfiddle.electric.Pending _
nil))]
(Todo-list. !xtdb)
(e/client
(dom/p (dom/text "XTDB is starting ..."))))))

(e/def fiddles {`XTDB-Starter XTDB-Starter})

(e/defn FiddleMain [ring-request]
(e/client
(binding [dom/node js/document.body]
(XTDB-Starter.))))

(comment
(.close @!xtdb-node)
(reset! !xtdb-node nil))
83 changes: 83 additions & 0 deletions src/xtdb_starter/todo_list.cljc
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
(ns xtdb-starter.todo-list
(:require
#?(:clj [xtdb-starter.xtdb-contrib :as db])
[hyperfiddle.electric :as e]
[hyperfiddle.electric-dom2 :as dom]
[hyperfiddle.electric-ui4 :as ui]
[xtdb.api #?(:clj :as :cljs :as-alias) xt]))

(e/def !xtdb)
(e/def db) ; injected database ref; Electric defs are always dynamic

(e/defn TodoItem [id]
(e/server
(let [e (xt/entity db id)
status (:task/status e)]
(e/client
(dom/div
(ui/checkbox
(case status :active false, :done true)
(e/fn [v]
(e/server
(e/discard
(e/offload
#(xt/submit-tx !xtdb [[:xtdb.api/put
{:xt/id id
:task/description (:task/description e) ; repeat
:task/status (if v :done :active)}]])))))
(dom/props {:id id}))
(dom/label (dom/props {:for id}) (dom/text (e/server (:task/description e)))))))))

(e/defn InputSubmit [F]
; Custom input control using lower dom interface for Enter handling
(e/client
(dom/input (dom/props {:placeholder "Buy milk"})
(dom/on "keydown" (e/fn [e]
(when (= "Enter" (.-key e))
(when-some [v (contrib.str/empty->nil (-> e .-target .-value))]
(new F v)
(set! (.-value dom/node) ""))))))))

(e/defn TodoCreate []
(e/client
(InputSubmit. (e/fn [v]
(e/server
(e/discard
(e/offload
#(xt/submit-tx !xtdb [[:xtdb.api/put
{:xt/id (random-uuid)
:task/description v
:task/status :active}]]))))))))

#?(:clj
(defn todo-records [db]
(->> (xt/q db '{:find [(pull ?e [:xt/id :task/description])]
:where [[?e :task/status]]})
(map first)
(sort-by :task/description)
vec)))

#?(:clj
(defn todo-count [db]
(count (xt/q db '{:find [?e] :in [$ ?status]
:where [[?e :task/status ?status]]}
:active))))

(e/defn Todo-list [!xtdb]
(e/server
(binding [xtdb-starter.todo-list/!xtdb !xtdb
db (new (db/latest-db> !xtdb))]
(e/client
(dom/link (dom/props {:rel :stylesheet :href "/todo-list.css"}))
(dom/h1 (dom/text "minimal todo list"))
(dom/p (dom/text "it's multiplayer, try two tabs"))
(dom/div (dom/props {:class "todo-list"})
(TodoCreate.)
(dom/div {:class "todo-items"}
(e/server
(e/for-by :xt/id [{:keys [xt/id]} (e/offload #(todo-records db))]
(TodoItem. id))))
(dom/p (dom/props {:class "counter"})
(dom/span (dom/props {:class "count"})
(dom/text (e/server (e/offload #(todo-count db)))))
(dom/text " items left")))))))
16 changes: 16 additions & 0 deletions src/xtdb_starter/xtdb_contrib.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
(ns xtdb-starter.xtdb-contrib
(:require [missionary.core :as m]
[xtdb.api :as xt]))

(defn latest-db>
"return flow of latest XTDB tx, but only works for XTDB in-process mode. see
https://clojurians.slack.com/archives/CG3AM2F7V/p1677432108277939?thread_ts=1677430221.688989&cid=CG3AM2F7V"
[!xtdb]
(->> (m/observe (fn [!]
(let [listener (xt/listen !xtdb {::xt/event-type ::xt/indexed-tx :with-tx-ops? true} !)]
#(.close listener))))
(m/reductions {} (xt/latest-completed-tx !xtdb)) ; initial value is the latest known tx, possibly nil
(m/relieve {})
(m/latest (fn [{:keys [:xtdb.api/tx-time] :as ?tx}]
(if tx-time (xt/db !xtdb {::xt/tx-time tx-time})
(xt/db !xtdb))))))

0 comments on commit 184fb00

Please sign in to comment.