aboutsummaryrefslogtreecommitdiff
#lang typed/racket
(require "../entities/article.rkt")
(require typed/db)

(module untyped-db-ops racket
  (require db
           db/util/datetime
           "../entities/article.rkt")

  (provide fetch-article
           fetch-latest-articles
           fetch-article-tags
           fetch-article-taggings
           insert-article-tagging
           delete-article-tagging
           fetch-article-hashes
           update-article
           insert-article)

  (define (fetch-article conn article-id)
    (match-let ([(vector timestamp hash source title body)
                 (query-row conn "SELECT timestamp, hash, source, title, body FROM diary.articles WHERE article_id = $1" article-id)])
      (make-article article-id (sql-datetime->srfi-date timestamp) hash source title body)))

  (define (fetch-latest-articles conn limit)
    (define article-list
      (for/list ([(article-id timestamp hash source title body)
                  (in-query conn "
SELECT article_id, timestamp, hash, source, title, body FROM diary.articles ORDER BY timestamp DESC LIMIT $1
"
                            limit)])
        (make-article article-id (sql-datetime->srfi-date timestamp) hash source title body)))
    (define article-tags
      (for/hash ([(article-id l)
                  (in-query conn
                            "
SELECT article_id, name FROM diary.tags
  JOIN diary.article_taggings USING (tag_id)
 WHERE article_id = any ($1)
"
                            (map article-id article-list)
                            #:group #("article_id"))])
        (values article-id (vector->list (car l)))))
    (map (lambda (article)
           (cond
             [(hash-ref article-tags (article-id article) #f)
              => (curry article->article-with-tags article)]
             [else
              (article->article-with-tags article '())]))
         article-list))

  (define (fetch-article-tags conn article-id)
    (for/list ([tag (in-query conn "
SELECT name FROM diary.tags
  JOIN diary.article_taggings USING (tag_id)
 WHERE article_id = $1
 ORDER BY name
"
                              article-id)])
      tag))

  (define (delete-article-tagging conn article_id tag_id)
    (query-exec conn
                "
DELETE FROM diary.article_taggings
WHERE article_id = $1
  AND tag_id = $2
"
                article_id
                tag_id))

  (define (fetch-article-taggings conn article-id)
    (for/set ([tag-id (in-query conn "SELECT tag_id FROM diary.article_taggings WHERE article_id = $1" article-id)])
      tag-id))

  (define (insert-article-tagging conn article_id tag_id)
    (query-exec conn
                "
INSERT INTO diary.article_taggings(article_id, tag_id)
VALUES($1, $2)
"
                article_id
                tag_id))

  (define (insert-tag conn name)
    (query-value conn
                 "
INSERT INTO diary.tags(name)
VALUES($1)
RETURNING tag_id
"
                 name))

  (define (fetch-article-hashes conn)
    (for/hash ([(article-id hash)
                (in-query conn "SELECT article_id, hash FROM diary.articles")])
      (values article-id hash)))

  (define (insert-article conn article)
    (query-exec conn
                "
INSERT INTO diary.articles(article_id, timestamp, hash, source, title, body)
VALUES($1, $2, $3, $4, $5, $6)
"
                (article-id article)
                (srfi-date->sql-timestamp-tz (article-timestamp article))
                (article-hash article)
                (article-source article)
                (article-title article)
                (article-body article)))

  (define (update-article conn article)
    (query-exec conn
                "
UPDATE diary.articles
   SET timestamp = $2,
       hash = $3,
       source = $4,
       title = $5,
       body = $6
 WHERE article_id = $1
       AND hash <> $3
"
                (article-id article)
                (srfi-date->sql-timestamp-tz (article-timestamp article))
                (article-hash article)
                (article-source article)
                (article-title article)
                (article-body article))))

(require/typed/provide (submod "." untyped-db-ops)
  [fetch-article (-> Connection String Article)]
  [fetch-latest-articles (-> Connection Natural (Listof Article-With-Tags))]
  [fetch-article-tags (-> Connection String (Listof String))]
  [fetch-article-hashes (-> Connection (Immutable-HashTable String String))]
  [fetch-article-taggings (-> Connection String (Setof Integer))]
  [insert-article-tagging (-> Connection String Integer Void)]
  [delete-article-tagging (-> Connection String Integer Void)]
  [update-article (-> Connection Article Void)]
  [insert-article (-> Connection Article Void)])