ebook-manager/backend/src/Database/Schema.hs

197 lines
7.3 KiB
Haskell
Raw Normal View History

2018-11-12 21:32:42 +02:00
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
2019-01-21 21:47:58 +02:00
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE FlexibleInstances #-}
2018-08-02 23:59:08 +03:00
module Database.Schema where
2018-11-12 21:32:42 +02:00
import ClassyPrelude
import Data.Aeson
import Database.Selda
import Database.Selda.Backend
import Database.Selda.Generic
import qualified Servant.Docs as Docs
2019-01-21 21:47:58 +02:00
import Servant (Capture)
2018-11-12 21:32:42 +02:00
import Web.HttpApiData
2018-08-04 22:05:41 +03:00
2018-08-04 21:30:08 +03:00
-- | User type
2018-10-26 23:47:14 +03:00
newtype PlainPassword = PlainPassword Text deriving (Show, ToJSON, FromJSON, ToHttpApiData, FromHttpApiData, Eq, Generic)
2018-08-04 22:05:41 +03:00
newtype HashedPassword = HashedPassword {unHashed :: ByteString}
data NoPassword = NoPassword
2018-11-12 21:32:42 +02:00
newtype Email = Email { unEmail :: Text } deriving (Show, ToJSON, FromJSON, ToHttpApiData, FromHttpApiData, Generic, Eq, IsString)
newtype Username = Username { unUsername :: Text } deriving (Show, ToJSON, FromJSON, ToHttpApiData, FromHttpApiData, Eq, Generic, IsString)
instance Docs.ToSample Username where
toSamples _ = [("Username", Username "user123")]
instance Docs.ToSample Email where
toSamples _ = [("Email", Email "first.last@example.com")]
2018-08-04 22:05:41 +03:00
2018-11-12 21:32:42 +02:00
instance Docs.ToSample PlainPassword where
toSamples _ = [("Password", PlainPassword "password123")]
2018-08-04 22:05:41 +03:00
instance SqlType HashedPassword where
mkLit = LCustom . LBlob . unHashed
fromSql (SqlBlob x) = HashedPassword x
2018-11-12 21:32:42 +02:00
fromSql _ = error "fromSql: Bad hash"
2018-08-04 22:05:41 +03:00
defaultValue = mkLit (HashedPassword "") -- Makes no sense
instance SqlType Email where
mkLit = LCustom . LText . unEmail
fromSql (SqlString x) = Email x
2018-11-12 21:32:42 +02:00
fromSql _ = error "fromSql: Bad email"
2018-08-04 22:05:41 +03:00
defaultValue = mkLit (Email "")
instance SqlType Username where
mkLit = LCustom . LText . unUsername
fromSql (SqlString x) = Username x
2018-11-12 21:32:42 +02:00
fromSql _ = error "fromSql: Bad username"
2018-08-04 22:05:41 +03:00
defaultValue = mkLit (Username "")
2018-08-06 00:09:41 +03:00
newtype UserID = UserID {unUserID :: Int} deriving (Show)
2018-11-12 21:32:42 +02:00
newtype BookID = BookID {unBookID :: Int} deriving (Show, ToJSON, FromJSON, FromHttpApiData, Eq, Ord, ToHttpApiData, Generic, Num)
2018-08-06 00:09:41 +03:00
2019-01-21 21:47:58 +02:00
instance Docs.ToCapture (Capture "book_id" BookID) where
toCapture _ = Docs.DocCapture "book_id" "The book id"
2018-11-12 21:32:42 +02:00
newtype ChannelID = ChannelID {unChannelID :: Int} deriving (Show, ToHttpApiData, FromHttpApiData, ToJSON, FromJSON, Eq, Generic, Num)
2018-08-06 00:09:41 +03:00
2019-01-21 21:47:58 +02:00
instance Docs.ToCapture (Capture "channel_id" ChannelID) where
toCapture _ = Docs.DocCapture "channel_id" "The channel id"
2018-08-06 00:09:41 +03:00
newtype TagID = TagID {unTagID :: Int} deriving (Show)
instance SqlType UserID where
mkLit = LCustom . LInt . unUserID
fromSql (SqlInt x) = UserID x
2018-11-12 21:32:42 +02:00
fromSql _ = error "fromSql: Bad userid"
2018-08-07 23:25:21 +03:00
sqlType _ = TRowID
2018-08-06 00:09:41 +03:00
defaultValue = mkLit (UserID (-1))
instance SqlType BookID where
mkLit = LCustom . LInt . unBookID
fromSql (SqlInt x) = BookID x
2018-11-12 21:32:42 +02:00
fromSql _ = error "fromSql: Bad bookid"
2018-08-06 00:09:41 +03:00
defaultValue = mkLit (BookID (-1))
instance SqlType ChannelID where
mkLit = LCustom . LInt . unChannelID
fromSql (SqlInt x) = ChannelID x
2018-11-12 21:32:42 +02:00
fromSql _ = error "fromSql: Bad channelid"
2018-08-06 00:09:41 +03:00
defaultValue = mkLit (ChannelID (-1))
instance SqlType TagID where
mkLit = LCustom . LInt . unTagID
fromSql (SqlInt x) = TagID x
2018-11-12 21:32:42 +02:00
fromSql _ = error "fromSql: Bad tagid"
2018-08-06 00:09:41 +03:00
defaultValue = mkLit (TagID (-1))
data User pass = User { identifier :: UserID
2018-11-12 21:32:42 +02:00
, email :: Email
, username :: Username
, role :: Role
, password :: pass }
2018-08-02 23:59:08 +03:00
deriving (Show, Generic)
2018-10-26 23:47:14 +03:00
data Role = UserRole | AdminRole deriving (Show, Read, Enum, Bounded, Typeable, Generic, Eq)
2018-08-04 22:05:41 +03:00
instance ToJSON Role
instance FromJSON Role
2018-08-03 23:36:38 +03:00
instance SqlType Role where
mkLit = LCustom . LText . pack . show
fromSql sql = case sql of
SqlString x -> fromMaybe (error "fromSql: Not a valid role") . readMay . unpack $ x
_ -> error "fromSql: Not a valid role"
defaultValue = mkLit minBound
2018-08-04 22:05:41 +03:00
users :: GenTable (User HashedPassword)
users = genTable "users" [ (email :: User HashedPassword -> Email) :- uniqueGen
2018-08-04 21:30:08 +03:00
, username :- uniqueGen
2018-08-06 00:09:41 +03:00
, (identifier :: User HashedPassword -> UserID) :- autoPrimaryGen ]
2018-08-04 21:30:08 +03:00
-- | Book type
2018-08-08 23:56:16 +03:00
newtype HashDigest = HashDigest { unHex :: ByteString } deriving Show
2018-08-06 00:09:41 +03:00
-- XXX: Add an identifier for the book
2018-11-12 21:32:42 +02:00
data Book = Book { identifier :: BookID
2018-08-07 23:25:21 +03:00
, contentHash :: Maybe HashDigest
2018-08-04 21:30:08 +03:00
, contentType :: Text
2018-11-12 21:32:42 +02:00
, title :: Text
2018-08-08 21:58:36 +03:00
, description :: Maybe Text
2018-11-12 21:32:42 +02:00
, owner :: UserID }
2018-08-04 21:30:08 +03:00
deriving (Show, Generic)
instance SqlType HashDigest where
2018-08-08 23:56:16 +03:00
mkLit = LCustom . LBlob . unHex
fromSql (SqlBlob x) = HashDigest x
2018-11-12 21:32:42 +02:00
fromSql _ = error "fromSql: Not a valid hash digest"
2018-08-04 21:30:08 +03:00
defaultValue = mkLit (HashDigest "") -- Doesn't really make sense
books :: GenTable Book
2018-08-08 21:58:36 +03:00
books = genTable "books" [ (identifier :: Book -> BookID) :- autoPrimaryGen
, (owner :: Book -> UserID) :- fkGen (gen users) userId ]
2018-08-04 21:30:08 +03:00
where
2018-08-05 23:42:37 +03:00
userId :*: _ = selectors (gen users)
2018-08-04 21:30:08 +03:00
-- | Categorizing books
2018-08-06 00:09:41 +03:00
data Tag = Tag { identifier :: TagID
2018-11-12 21:32:42 +02:00
, tag :: Text
, owner :: UserID }
2018-08-04 21:30:08 +03:00
deriving (Show, Generic)
data Visibility = Public | Private | Followers
2018-10-26 23:47:14 +03:00
deriving (Show, Read, Generic, Eq)
instance ToJSON Visibility
instance FromJSON Visibility
instance SqlType Visibility where
mkLit = LCustom . LText . pack . show
fromSql (SqlString x) = fromMaybe (error "fromSql: Not a valid visibility token") . readMay . unpack $ x
fromSql _ = error "fromSql: Not a valid visibility token"
defaultValue = mkLit Private
2018-08-06 00:09:41 +03:00
data Channel = Channel { identifier :: ChannelID
2018-11-12 21:32:42 +02:00
, channel :: Text
, owner :: UserID
, visibility :: Visibility }
2018-08-04 21:30:08 +03:00
deriving (Show, Generic)
tags :: GenTable Tag
2018-08-06 00:09:41 +03:00
tags = genTable "tags" [ (identifier :: Tag -> TagID) :- autoPrimaryGen
, (owner :: Tag -> UserID) :- fkGen (gen users) i ]
2018-08-04 21:30:08 +03:00
where
i :*: _ = selectors (gen users)
channels :: GenTable Channel
2018-08-06 00:09:41 +03:00
channels = genTable "channels" [ (identifier :: Channel -> ChannelID) :- autoPrimaryGen
, (owner :: Channel -> UserID) :- fkGen (gen users) i ]
2018-08-04 21:30:08 +03:00
where
i :*: _ = selectors (gen users)
2018-11-12 21:32:42 +02:00
data BookTag = BookTag { tag :: TagID
2018-08-07 22:27:05 +03:00
, book :: BookID }
2018-08-04 21:30:08 +03:00
deriving (Show, Generic)
2018-08-06 00:09:41 +03:00
data BookChannel = BookChannel { channel :: ChannelID
2018-11-12 21:32:42 +02:00
, book :: BookID }
2018-08-04 21:30:08 +03:00
deriving (Show, Generic)
bookTags :: GenTable BookTag
2018-08-06 00:09:41 +03:00
bookTags = genTable "book_tags" [ (tag :: BookTag -> TagID) :- fkGen (gen tags) i
2018-08-07 22:27:05 +03:00
, (book :: BookTag -> BookID) :- fkGen (gen books) h ]
2018-08-04 21:30:08 +03:00
where
i :*: _ = selectors (gen tags)
h :*: _ = selectors (gen books)
bookChannels :: GenTable BookChannel
2018-08-06 00:09:41 +03:00
bookChannels = genTable "book_channels" [ (channel :: BookChannel -> ChannelID) :- fkGen (gen channels) i
2018-08-07 22:27:05 +03:00
, (book :: BookChannel -> BookID) :- fkGen (gen books) h ]
2018-08-04 21:30:08 +03:00
where
i :*: _ = selectors (gen channels)
h :*: _ = selectors (gen books)