start using db2 in view use-case

This commit is contained in:
Travis Shears 2026-03-10 14:19:16 +01:00
parent 7d497191cb
commit d3babebcc4
Signed by: travisshears
GPG key ID: CB9BF1910F3F7469
3 changed files with 58 additions and 27 deletions

View file

@ -38,12 +38,7 @@
{:status 200 {:status 200
:body (snippets.use-cases.view/view-snippets {:limit limit-num :skip skip-num})}) :body (snippets.use-cases.view/view-snippets {:limit limit-num :skip skip-num})})
{:status 200 {:status 200
:body (snippets.use-cases.view/view-snippets)})) :body (snippets.use-cases.view/view-snippets nil)}))
(defn handle-view-snippet [{params :query-params}]
(let [id (get params "id")]
{:status 200
:body (snippets.use-cases.view/view-snippet id)}))
(defn handle-delete-snippet [{params :query-params}] (defn handle-delete-snippet [{params :query-params}]
(let [id (get params "id")] (let [id (get params "id")]
@ -82,7 +77,6 @@
["/snippet-by-slug" {:get handle-view-snippet-by-slug}] ["/snippet-by-slug" {:get handle-view-snippet-by-slug}]
["/snippets" {:get handle-view-snippets}] ["/snippets" {:get handle-view-snippets}]
["/snippet" {:post handle-create-snippet ["/snippet" {:post handle-create-snippet
:get handle-view-snippet
:patch handle-edit-snippet :patch handle-edit-snippet
:delete handle-delete-snippet}]]) :delete handle-delete-snippet}]])
(rr/create-default-handler))) (rr/create-default-handler)))

View file

@ -7,20 +7,21 @@
;; Initialize the Datomic Local client ;; Initialize the Datomic Local client
;; :system "dev" groups your databases in the "dev" system ;; :system "dev" groups your databases in the "dev" system
;; In production, you'd set :storage-dir to a persistent path ;; In production, you'd set :storage-dir to a persistent path
;; TODO: add save file location for prod
(def client (d/client {:server-type :datomic-local (def client (d/client {:server-type :datomic-local
:system "dev"})) :system "dev"}))
(def db-name "snippets") (def db-name "snippets")
;; Create the database if it doesn't exist ;; Create the database if it doesn't exist
(defn ensure-db (defn- ensure-db
"Check if db exists, create it if not." "Check if db exists, create it if not."
[] []
(d/create-database client {:db-name db-name}) (d/create-database client {:db-name db-name})
(t/log! {:level :info} "Snippets database created if needed")) (t/log! {:level :info} "Snippets database created if needed"))
;; Get a connection to the database ;; Get a connection to the database
(defn get-conn [] (defn- get-conn []
(d/connect client {:db-name db-name})) (d/connect client {:db-name db-name}))
;; Define the schema for snippets ;; Define the schema for snippets
@ -43,18 +44,20 @@
:db/valueType :db.type/instant :db/valueType :db.type/instant
:db/cardinality :db.cardinality/one}]) :db/cardinality :db.cardinality/one}])
(defn ensure-schema (defn- ensure-schema
"Transact the schema if it doesn't exist. Call this once on startup." "Transact the schema if it doesn't exist. Call this once on startup."
[] []
(let [conn (get-conn)] (let [conn (get-conn)]
(d/transact conn {:tx-data snippet-schema}) (d/transact conn {:tx-data snippet-schema})
(t/log! {:level :info} "Snippet schema created if needed"))) (t/log! {:level :info} "Snippet schema created if needed")))
(defn start-up-check [] (defn start-up-check
"Should be run at startup to ensure the database and schema are created."
[]
(ensure-db) (ensure-db)
(ensure-schema)) (ensure-schema))
(defn snippet-to-entity (defn- snippet-to-entity
"Convert a snippet map to a Datomic DB entity." "Convert a snippet map to a Datomic DB entity."
[snippet] [snippet]
{:snippet/title (:title snippet) {:snippet/title (:title snippet)
@ -63,6 +66,26 @@
:snippet/tags (:tags snippet) :snippet/tags (:tags snippet)
:snippet/pub-date (:pub-date snippet)}) :snippet/pub-date (:pub-date snippet)})
(defn- entity-to-snippet
"Convert a Datomic DB entity to a snippet map."
[entity]
{:title (:snippet/title entity)
:slug (:snippet/slug entity)
:markdown (:snippet/markdown entity)
:tags (:snippet/tags entity)
:pub-date (:snippet/pub-date entity)})
(defn- wrap-snippet-return
"Wraps an fn that returns snippet, snippet[], or nil; converting the entity to a snippet map."
[snippet-fn]
(fn [& args]
(let [res (apply snippet-fn args)]
(cond
(nil? res) nil
:else (if (sequential? res)
(map entity-to-snippet res)
(entity-to-snippet res))))))
;; create ;; create
(def create-schema (def create-schema
"Malli schema for a valid snippet entity creation." "Malli schema for a valid snippet entity creation."
@ -73,12 +96,12 @@
[:snippet/tags [:vector :string]] [:snippet/tags [:vector :string]]
[:snippet/pub-date [:fn #(instance? java.util.Date %)]]]) [:snippet/pub-date [:fn #(instance? java.util.Date %)]]])
(defn valid-create? (defn- valid-create?
"Check if a snippet map is a valid Datomic entity." "Check if a snippet map is a valid Datomic entity."
[entity] [entity]
(m/validate create-schema entity)) (m/validate create-schema entity))
(defn put-snippets (defn- put-snippets
"Create new snippets in the database." "Create new snippets in the database."
[snippets] [snippets]
(t/log! {:level :info, :data {:slugs (map :slug snippets)}} "Saving new snippets to db") (t/log! {:level :info, :data {:slugs (map :slug snippets)}} "Saving new snippets to db")
@ -88,8 +111,11 @@
(d/transact conn {:tx-data entities}) (d/transact conn {:tx-data entities})
(throw (ex-info "Invalid snippet entity" {:entities entities}))))) (throw (ex-info "Invalid snippet entity" {:entities entities})))))
(def create-snippets
(wrap-snippet-return put-snippets))
;; read ;; read
(defn get-snippet-by-slug (defn- get-snippet-by-slug-from-db
"Get a single snippet by its slug." "Get a single snippet by its slug."
[slug] [slug]
(let [conn (get-conn) (let [conn (get-conn)
@ -99,6 +125,9 @@
:where [?e :snippet/slug ?slug]]] :where [?e :snippet/slug ?slug]]]
(ffirst (d/q query db slug)))) (ffirst (d/q query db slug))))
(def get-snippet-by-slug
(wrap-snippet-return get-snippet-by-slug-from-db))
;; update ;; update
(def update-schema (def update-schema
"Malli schema for a valid update to a snippet entity." "Malli schema for a valid update to a snippet entity."
@ -108,14 +137,14 @@
[:snippet/markdown {:optional true} :string] [:snippet/markdown {:optional true} :string]
[:snippet/tags {:optional true} [:vector :string]]]) [:snippet/tags {:optional true} [:vector :string]]])
(defn to-update [patch] (defn- to-update [patch]
(cond-> {} (cond-> {}
(some? (:title patch)) (assoc :snippet/title (:title patch)) (some? (:title patch)) (assoc :snippet/title (:title patch))
(some? (:slug patch)) (assoc :snippet/slug (:slug patch)) (some? (:slug patch)) (assoc :snippet/slug (:slug patch))
(some? (:markdown patch)) (assoc :snippet/markdown (:markdown patch)) (some? (:markdown patch)) (assoc :snippet/markdown (:markdown patch))
(some? (:tags patch)) (assoc :snippet/tags (:tags patch)))) (some? (:tags patch)) (assoc :snippet/tags (:tags patch))))
(defn patch-snippet (defn- patch-snippet-in-db
"Update specific fields of a snippet." "Update specific fields of a snippet."
[slug raw-patch] [slug raw-patch]
(let [conn (get-conn) (let [conn (get-conn)
@ -129,7 +158,9 @@
(let [tx-data [(merge {:db/id eid} patch)]] (let [tx-data [(merge {:db/id eid} patch)]]
(d/transact conn {:tx-data tx-data})))) (d/transact conn {:tx-data tx-data}))))
(defn list-snippets (def update-snippet (wrap-snippet-return patch-snippet-in-db))
(defn list-snippets-in-db
"List all the snippets" "List all the snippets"
[] []
(let [conn (get-conn) (let [conn (get-conn)
@ -140,12 +171,13 @@
(->> (d/q query db) (->> (d/q query db)
(map first)))) (map first))))
(def list-snippets (wrap-snippet-return list-snippets-in-db))
(defn delete-snippet-by-slug (defn delete-snippet-by-slug
"Soft delete a snippet (retract its entity)." "Soft delete a snippet (retract its entity)."
[slug] [slug]
(t/log! {:level :info, :data {:slug slug}} "Retracting snippet") (t/log! {:level :info, :data {:slug slug}} "Retracting snippet")
(let [conn (get-conn) (let [conn (get-conn)
db (d/db conn)
eid (:db/id (get-snippet-by-slug slug))] eid (:db/id (get-snippet-by-slug slug))]
(when (nil? eid) (when (nil? eid)
(throw (ex-info "Snippet not found" {:slug slug}))) (throw (ex-info "Snippet not found" {:slug slug})))
@ -161,7 +193,7 @@
[?e :snippet/tags ?tag]]] [?e :snippet/tags ?tag]]]
(d/q query db))) (d/q query db)))
(defn get-snippets-by-tag (defn get-snippets-by-tag-in-db
"Get all snippets that have a specific tag." "Get all snippets that have a specific tag."
[tag] [tag]
(let [conn (get-conn) (let [conn (get-conn)
@ -172,3 +204,5 @@
[?e :snippet/tags ?tag]] [?e :snippet/tags ?tag]]
results (d/q query db tag)] results (d/q query db tag)]
(mapv first results))) (mapv first results)))
(def get-snippets-by-tag (wrap-snippet-return get-snippets-by-tag-in-db))

View file

@ -1,7 +1,7 @@
(ns snippets.use-cases.view (ns snippets.use-cases.view
(:require (:require
[taoensso.telemere :as t] [taoensso.telemere :as t]
[snippets.infra.db :as db])) [snippets.infra.db2 :as db]))
(defn serialize-snippet (defn serialize-snippet
"Converts snippet pub-date to ISO-8601 string for EDN serialization" "Converts snippet pub-date to ISO-8601 string for EDN serialization"
@ -9,12 +9,15 @@
(when snippet (when snippet
(assoc snippet :pub-date (.toString (:pub-date snippet))))) (assoc snippet :pub-date (.toString (:pub-date snippet)))))
(defn view-snippet [key] (defn view-snippets [options]
(t/log! {:level :info, :data {:key key}} "Viewing snippet by id") (if (nil? options)
(serialize-snippet (db/get-snippet-by-id key))) (map serialize-snippet (db/list-snippets))
(let [limit (:limit options)
(defn view-snippets [& args] skip (:skip options)]
(map serialize-snippet (db/list-snippets args))) (->> (db/list-snippets)
(drop skip)
(take limit)
(map serialize-snippet)))))
(defn view-tags [] (defn view-tags []
(t/log! {:level :info} "Viewing tags") (t/log! {:level :info} "Viewing tags")