You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
145 lines
5.6 KiB
145 lines
5.6 KiB
(ns blog.db
|
|
(:require ["pg" :refer [Client]]
|
|
[cljs.core.async :refer [go, take!, put!, >!, chan]]
|
|
[cljs.core.async.interop :refer-macros [<p!]]
|
|
[cljs.core :refer [clj->js js->clj]]
|
|
[blog.env :as env]))
|
|
|
|
(defn create-client
|
|
"Create a new client for Postgres using enviroment variables."
|
|
[]
|
|
(->> (env/get-database-credentials)
|
|
(cljs.core/clj->js)
|
|
(new Client)))
|
|
|
|
(defn connect-client
|
|
"Connect a client to the database"
|
|
[client]
|
|
(. client connect))
|
|
|
|
(defn create-tables
|
|
[client]
|
|
(. client query "CREATE TABLE IF NOT EXISTS articles (id SERIAL PRIMARY KEY, title VARCHAR(255) NOT NULL, content TEXT NOT NULL, created TIMESTAMP DEFAULT CURRENT_TIMESTAMP);"))
|
|
|
|
(defn get-articles
|
|
"Reads all articles and returns via channel. It gets and returns the same channel."
|
|
[client channel]
|
|
(go
|
|
(try
|
|
(let [res (<p! (. client query "select id, title, content, created from articles order by created desc"))]
|
|
(>! channel (.-rows res)))
|
|
(catch js/Error err (js/console.log (ex-cause err)))))
|
|
channel)
|
|
|
|
(defn get-articles-briefly
|
|
"Reads all articles and returns via channel. It gets and returns the same channel. The content will be brief (<=60 characters)."
|
|
[client channel]
|
|
(go
|
|
(try
|
|
(let [res (<p! (. client query
|
|
(str "select id, title, "
|
|
"substr(content, 0, 60) content, "
|
|
"length(content) content_length, "
|
|
"created from articles "
|
|
"order by created desc")))]
|
|
(>! channel (.-rows res)))
|
|
(catch js/Error err (js/console.log (ex-cause err)))))
|
|
channel)
|
|
|
|
(defn search-articles-briefly
|
|
"Search all articles by titles and contents and returns via channel. It gets and returns the same channel. The content will be brief (<=60 characters)."
|
|
[client search channel]
|
|
(go
|
|
(try
|
|
(let [res (<p! (.query client
|
|
(str "select id, title, "
|
|
"substr(content, 0, 60) content, "
|
|
"length(content) content_length, "
|
|
"created from articles "
|
|
"where title like $1 "
|
|
"or content like $1 "
|
|
"order by created desc")
|
|
(clj->js [(str "%" search "%")])))]
|
|
(>! channel (.-rows res)))
|
|
(catch js/Error err (js/console.log (ex-cause err)))))
|
|
channel)
|
|
|
|
(defn get-article
|
|
"Reads an article with the id and returns via channel. It gets and returns the same channel. Empty collection if not found."
|
|
[client id channel]
|
|
(go
|
|
(try
|
|
(let [res (<p! (.query client
|
|
"select id, title, content, created from articles where id=$1"
|
|
(clj->js [id])))]
|
|
(>! channel (-> (.-rows res)
|
|
(js->clj :keywordize-keys true)
|
|
(first))))
|
|
(catch js/Error err (js/console.log (ex-cause err)))))
|
|
channel)
|
|
|
|
(defn get-article-briefly
|
|
"Reads an article with the id and returns via channel. It gets and returns the same channel. Empty collection if not found. The content will be brief (<=60 characters)."
|
|
[client id channel]
|
|
(go
|
|
(try
|
|
(let [res (<p! (.query client
|
|
(str "select id, title,"
|
|
"substr(content, 0, 60) content,"
|
|
"length(content) content_length,"
|
|
"created from articles"
|
|
"where id=$1")
|
|
(clj->js [id])))]
|
|
(>! channel (-> (.-rows res)
|
|
(js->clj :keywordize-keys true)
|
|
(first))))
|
|
(catch js/Error err (js/console.log (ex-cause err)))))
|
|
channel)
|
|
|
|
(defn insert-article
|
|
"Insert an article and return the id via channel. It gets and returns the same channel."
|
|
[client title content channel]
|
|
(go
|
|
(try
|
|
(let [res (<p! (.query client
|
|
"insert into articles(title, content) values($1, $2) returning id;"
|
|
(clj->js [title content])))]
|
|
(>! channel (-> (.-rows res)
|
|
(js->clj :keywordize-keys true)
|
|
(first)
|
|
(:id))))
|
|
(catch js/Error err (js/console.log (ex-cause err)))))
|
|
channel)
|
|
|
|
(defn update-article
|
|
"Update an article and return the id via channel. The timestamp for created will be updated to current timestamp. It gets and returns the same channel."
|
|
[client {:keys [id title content]} channel]
|
|
(go
|
|
(try
|
|
(let [res (<p! (.query client
|
|
(str "update articles "
|
|
"set title = $2,"
|
|
"content = $3,"
|
|
"created = CURRENT_TIMESTAMP "
|
|
"where id = $1;")
|
|
(clj->js [id title content])))]
|
|
(>! channel (-> id)))
|
|
(catch js/Error err (js/console.log (ex-cause err)))))
|
|
channel)
|
|
|
|
(defn delete-article
|
|
"Delete an article and return the id via channel. It gets and returns the same channel."
|
|
[client id channel]
|
|
(go
|
|
(try
|
|
(let [res (<p! (.query client
|
|
"delete from articles where id = $1 returning id;"
|
|
(clj->js [id])))]
|
|
(>! channel (-> (.-rows res)
|
|
(js->clj :keywordize-keys true)
|
|
(first)
|
|
(:id))))
|
|
(catch js/Error err (js/console.log (ex-cause err)))))
|
|
channel)
|
|
|