init commit
This commit is contained in:
parent
d975bc3d42
commit
0c61609774
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
.clj-kondo
|
||||
.nrepl-port
|
||||
.lsp
|
||||
.cpcache
|
||||
|
22
deps.edn
Normal file
22
deps.edn
Normal file
@ -0,0 +1,22 @@
|
||||
{:deps
|
||||
{compojure/compojure {:mvn/version "1.7.1"}
|
||||
com.datomic/local {:mvn/version "1.0.291"}
|
||||
org.clojure/clojure {:mvn/version "1.12.0"}
|
||||
org.clojure/data.json {:mvn/version "2.5.1"}
|
||||
org.slf4j/slf4j-api {:mvn/version "2.0.17"}
|
||||
org.slf4j/slf4j-simple {:mvn/version "2.0.17"}
|
||||
hiccup/hiccup {:mvn/version "2.0.0-RC1"}
|
||||
ring-logger/ring-logger {:mvn/version "1.1.1"}
|
||||
ring/ring-core {:mvn/version "1.14.2"}
|
||||
ring/ring-json {:mvn/version "0.5.1"}
|
||||
ring/ring-jetty-adapter {:mvn/version "1.14.2"}}
|
||||
:paths [:clj-paths :resource-paths]
|
||||
:aliases
|
||||
{:repl {:extra-paths ["src/dev"]
|
||||
:extra-deps {org.clojure/clojure {:mvn/version "1.12.1"}
|
||||
nrepl/nrepl {:mvn/version "1.3.0"}
|
||||
cider/cider-nrepl {:mvn/version "0.50.2"}}
|
||||
:main-opts ["-m" "nrepl.cmdline",
|
||||
"--middleware" "[cider.nrepl/cider-middleware]"]}
|
||||
:clj-paths ["src"]
|
||||
:resource-paths ["resources"]}}
|
3
restart.sh
Executable file
3
restart.sh
Executable file
@ -0,0 +1,3 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
systemctl restart tbd
|
139
src/ajet/todo/core.clj
Normal file
139
src/ajet/todo/core.clj
Normal file
@ -0,0 +1,139 @@
|
||||
(ns ajet.todo.core
|
||||
(:require
|
||||
[ajet.todo.db :as db]
|
||||
[clojure.data.json :as json]
|
||||
[clojure.pprint :as pprint]
|
||||
[compojure.core :refer [context defroutes DELETE GET let-routes PATCH POST]]
|
||||
[compojure.route :as route]
|
||||
[hiccup2.core :as h]
|
||||
[ring.middleware.content-type :refer [wrap-content-type]]
|
||||
[ring.middleware.json :as rmjson]
|
||||
[ring.middleware.not-modified :refer [wrap-not-modified]]
|
||||
[ring.middleware.params :refer [wrap-params]]
|
||||
[ring.middleware.resource :refer [wrap-resource]]
|
||||
[ring.util.response :refer [response]]))
|
||||
|
||||
(comment
|
||||
(do
|
||||
(defonce printer (bound-fn* pprint/pprint))
|
||||
(add-tap printer))
|
||||
|
||||
(remove-tap printer))
|
||||
|
||||
(defn get-todos [_]
|
||||
(let [res (db/get-all-todos)]
|
||||
(response res)))
|
||||
|
||||
(defn get-todo [id _]
|
||||
(let [res (db/get-todo id)]
|
||||
(response res)))
|
||||
|
||||
(defn add-todo [req]
|
||||
(db/add-todo! (-> req :body :title))
|
||||
{:status 201})
|
||||
|
||||
(defn update-todo [id {{:keys [done]} :body}]
|
||||
(db/set-todo-done! id done))
|
||||
|
||||
(defn delete-todo [id]
|
||||
(db/delete-todo! id)
|
||||
{:status 204})
|
||||
|
||||
(defn page-template [view]
|
||||
(-> [:html
|
||||
[:head
|
||||
[:script {:src "https://cdn.jsdelivr.net/npm/htmx.org@2.0.7/dist/htmx.min.js"}]]
|
||||
[:body view]]
|
||||
h/html
|
||||
str))
|
||||
|
||||
(def hx-app {:hx-swap "outerHTML"
|
||||
:hx-target "#app"})
|
||||
|
||||
(defn render-app [{:keys [show-complete]
|
||||
:or {show-complete true}
|
||||
:as opts}]
|
||||
(-> (let [todos (db/get-all-todos)
|
||||
complete-toggle (if show-complete "hide" "show")]
|
||||
[:div {:id "app"}
|
||||
[:ul
|
||||
(for [{id :id
|
||||
done :todo/done?
|
||||
title :todo/title} todos
|
||||
:when (or show-complete (not done))]
|
||||
[:li
|
||||
[:span {:style (str "text-decoration: " (if done "line-through" "none"))}
|
||||
title]
|
||||
[:input (merge hx-app
|
||||
{:type "checkbox"
|
||||
:checked done
|
||||
:hx-patch (format "/htmx/todo/%s/%s?opts=%s"
|
||||
id
|
||||
(if done "unset" "set")
|
||||
(json/write-str opts))})]])]
|
||||
[:div
|
||||
[:p "settings"]
|
||||
[:button (merge hx-app
|
||||
{:hx-get (format "/htmx/todo/?opts=%s"
|
||||
(-> opts
|
||||
(update :show-complete not)
|
||||
json/write-str))})
|
||||
complete-toggle " done"]]])
|
||||
h/html))
|
||||
|
||||
;; im gonna regert this
|
||||
(defn DRY [req]
|
||||
(-> req
|
||||
:params
|
||||
(get "opts" "{}")
|
||||
json/read-json
|
||||
render-app
|
||||
str))
|
||||
|
||||
(defroutes api-routes
|
||||
(GET "/" []
|
||||
(wrap-params
|
||||
#(-> % :params
|
||||
(get "opts" "{}")
|
||||
json/read-json
|
||||
render-app
|
||||
page-template)))
|
||||
(-> (context "/api/v1" []
|
||||
(context "/todo" []
|
||||
(GET "/" [] get-todos)
|
||||
(POST "/" [] add-todo)
|
||||
(context ["/:id", :id #"[0-9]+"] [id]
|
||||
(let-routes [id (read-string id)]
|
||||
(GET "/" [] (partial get-todo id))
|
||||
(PATCH "/" [] (partial update-todo id))
|
||||
(DELETE "/" [] (delete-todo id)))))
|
||||
|
||||
(GET "/example/math/:x/:y" [x y]
|
||||
(->> (+ (parse-long x)
|
||||
(parse-long y))
|
||||
(hash-map :result)
|
||||
response)))
|
||||
(rmjson/wrap-json-body {:keywords? true})
|
||||
(rmjson/wrap-json-response))
|
||||
|
||||
(wrap-params
|
||||
(context "/htmx/todo" []
|
||||
(GET "/" [] DRY)
|
||||
(POST "/" [] add-todo)
|
||||
(context ["/:id", :id #"[0-9]+"] [id]
|
||||
(let-routes [id (read-string id)]
|
||||
(PATCH "/set" [] (do (db/set-todo-done! id true)
|
||||
DRY))
|
||||
(PATCH "/unset" [] (do (db/set-todo-done! id false)
|
||||
DRY))
|
||||
(DELETE "/" [] (do (delete-todo id)
|
||||
DRY))))))
|
||||
|
||||
(route/not-found (str (h/html [:h2 "Not Found"]))))
|
||||
|
||||
(def app
|
||||
(-> #'api-routes
|
||||
(wrap-resource "public")
|
||||
wrap-content-type
|
||||
wrap-not-modified)) ;; files from resources/public are served
|
||||
|
103
src/ajet/todo/db.clj
Normal file
103
src/ajet/todo/db.clj
Normal file
@ -0,0 +1,103 @@
|
||||
(ns ajet.todo.db
|
||||
(:require [datomic.client.api :as d]))
|
||||
|
||||
(def client (d/client {:server-type :datomic-local
|
||||
:system "dev"}))
|
||||
|
||||
(d/create-database client {:db-name "todos"})
|
||||
(def conn (d/connect client {:db-name "todos"}))
|
||||
|
||||
(comment
|
||||
;; to reset local dev db
|
||||
(try
|
||||
(d/delete-database client {:db-name "todos"})
|
||||
(catch Exception _))
|
||||
|
||||
(do
|
||||
(def todo-schema [{:db/ident :todo/title
|
||||
:db/valueType :db.type/string
|
||||
:db/cardinality :db.cardinality/one
|
||||
:db/unique :db.unique/identity
|
||||
:db/doc "The title of the todo"}
|
||||
|
||||
{:db/ident :todo/done?
|
||||
:db/valueType :db.type/boolean
|
||||
:db/cardinality :db.cardinality/one
|
||||
:db/doc "The completedness of the todo"}])
|
||||
(d/transact conn {:tx-data todo-schema})
|
||||
(def first-todos [{:todo/title "set up git repo"
|
||||
:todo/done? true}
|
||||
{:todo/title "teach jon lisp"
|
||||
:todo/done? false}
|
||||
{:todo/title "finish the todo app"
|
||||
:todo/done? false}
|
||||
{:todo/title "profit?"
|
||||
:todo/done? false}])
|
||||
(d/transact conn {:tx-data first-todos})))
|
||||
|
||||
(defn normalize-todo [[id title done]]
|
||||
{:id id
|
||||
:todo/title title
|
||||
:todo/done? done})
|
||||
|
||||
(defn get-unfinished-todos []
|
||||
(let [db (d/db conn)]
|
||||
(->> db
|
||||
(d/q '[:find ?e ?title
|
||||
:where [?e :todo/title ?title]
|
||||
[?e :todo/done? false]])
|
||||
(map normalize-todo)
|
||||
(map #(assoc % :todo?/done false)))))
|
||||
|
||||
(defn get-all-todos []
|
||||
(let [db (d/db conn)]
|
||||
(->> db
|
||||
(d/q '[:find ?e ?title ?done
|
||||
:where [?e :todo/title ?title]
|
||||
[?e :todo/done? ?done]])
|
||||
(sort-by first)
|
||||
(map normalize-todo))))
|
||||
|
||||
(defn get-todo [id]
|
||||
(let [db (d/db conn)]
|
||||
(some->> (d/q '[:find ?e ?title ?done
|
||||
:in $ ?e
|
||||
:where [?e :todo/title ?title]
|
||||
[?e :todo/done? ?done]]
|
||||
db
|
||||
id)
|
||||
first
|
||||
normalize-todo)))
|
||||
|
||||
(defn get-todo-by-title [title]
|
||||
(let [db (d/db conn)]
|
||||
(some->> (d/q '[:find ?e ?title ?done
|
||||
:in $ ?title
|
||||
:where [?e :todo/title ?title]
|
||||
[?e :todo/done? ?done]]
|
||||
db
|
||||
title)
|
||||
first
|
||||
normalize-todo)))
|
||||
|
||||
(defn add-todo! [title]
|
||||
(d/transact conn {:tx-data [{:todo/title title
|
||||
:todo/done? false}]}))
|
||||
|
||||
(defn set-todo-done! [eid done]
|
||||
(d/transact conn {:tx-data [{:db/id eid
|
||||
:todo/done? done}]}))
|
||||
|
||||
(defn delete-todo! [id]
|
||||
(d/transact conn {:tx-data [[:db/retractEntity id]]}))
|
||||
|
||||
(comment
|
||||
(get-all-todos)
|
||||
(get-unfinished-todos)
|
||||
|
||||
(add-todo! "foo")
|
||||
(def foo-id (-> (get-todo-by-title "foo")
|
||||
:id))
|
||||
(set-todo-done! foo-id true)
|
||||
(delete-todo! foo-id))
|
||||
|
13
src/ajet/todo/server.clj
Normal file
13
src/ajet/todo/server.clj
Normal file
@ -0,0 +1,13 @@
|
||||
(ns ajet.todo.server
|
||||
(:require
|
||||
[ajet.todo.core :as core]
|
||||
[ring.adapter.jetty :refer [run-jetty]]))
|
||||
|
||||
(def port 1738)
|
||||
|
||||
(defn make-server [opts]
|
||||
(run-jetty #'core/app (merge {:join? false, :port port} opts)))
|
||||
|
||||
(defn -main [& _args]
|
||||
(make-server {}))
|
||||
|
11
src/dev/user.clj
Normal file
11
src/dev/user.clj
Normal file
@ -0,0 +1,11 @@
|
||||
(ns user
|
||||
(:require [ajet.todo.server :as server]))
|
||||
|
||||
(defonce server (server/make-server {}))
|
||||
|
||||
(comment
|
||||
server
|
||||
(. server stop)
|
||||
(. server start))
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user