start using db2 in view use-case
This commit is contained in:
parent
7d497191cb
commit
d3babebcc4
3 changed files with 58 additions and 27 deletions
|
|
@ -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)))
|
||||||
|
|
|
||||||
|
|
@ -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))
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue