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.

207 lines
7.9 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 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)
(defn get-about
"Reads the about article. It gets and returns the same channel. Empty collection if not found."
[client channel]
(go
(try
(let [res (<p! (.query client
"select id, content, created from about where id=1"))
about (-> (.-rows res)
(js->clj :keywordize-keys true)
(first))]
(>! channel (or about [])))
(catch js/Error err
(do
(>! channel nil)
(js/console.log (ex-cause err))))))
channel)
(defn insert-about
"Insert the about article and return the id via channel. It gets and returns the same channel."
[client channel]
(go
(try
(let [res (<! (.query client
"insert into about(id, content) values(1, 'Please, Change ME!!!') returning id;"))]
(>! channel (-> (.-rows res)
(js->clj :keywordize-keys true)
(first)
(:id))))
(catch js/Error err (js/console.log (ex-cause err)))))
channel)
(defn insert-about-if-not-exist
"Insert the about article if not exist and return the id via channel. It gets and returns the same channel."
[client]
(go
(let [channel (chan)]
(try
(let [about (<! (get-about client channel))]
(if (= about [])
(insert-about client channel))
false)
(catch js/Error err
(do (js/console.log (ex-cause err))
true))))))
(defn update-about
"Update the about 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 content channel]
(go
(try
(let [res (<! (.query client
(str "update about "
"set content = $1,"
"created = CURRENT_TIMESTAMP "
"where id = 1;")
(clj->js [content])))]
(>! channel (-> 1)))
(catch js/Error err (js/console.log (ex-cause err)))))
channel)
(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);")
(. client query "CREATE TABLE IF NOT EXISTS about (id SERIAL PRIMARY KEY, content TEXT NOT NULL, created TIMESTAMP DEFAULT CURRENT_TIMESTAMP);")
(insert-about-if-not-exist client))