2018-08-02 23:59:08 +03:00
|
|
|
{-# Language NoImplicitPrelude #-}
|
|
|
|
{-# Language DeriveGeneric #-}
|
|
|
|
{-# Language OverloadedStrings #-}
|
2018-08-03 23:36:38 +03:00
|
|
|
{-# Language DuplicateRecordFields #-}
|
2018-08-04 22:05:41 +03:00
|
|
|
{-# Language GeneralizedNewtypeDeriving #-}
|
2018-08-02 23:59:08 +03:00
|
|
|
module Database.Schema where
|
|
|
|
|
|
|
|
import ClassyPrelude
|
|
|
|
import Database.Selda.Generic
|
2018-08-03 23:36:38 +03:00
|
|
|
import Database.Selda
|
|
|
|
import Database.Selda.Backend
|
2018-08-02 23:59:08 +03:00
|
|
|
|
2018-08-04 22:05:41 +03:00
|
|
|
import Data.Aeson
|
|
|
|
import Web.HttpApiData
|
|
|
|
|
2018-08-04 21:30:08 +03:00
|
|
|
-- | User type
|
2018-08-04 22:05:41 +03:00
|
|
|
newtype PlainPassword = PlainPassword Text deriving (Show, ToJSON, FromJSON, ToHttpApiData, FromHttpApiData, Eq)
|
|
|
|
newtype HashedPassword = HashedPassword {unHashed :: ByteString}
|
|
|
|
data NoPassword = NoPassword
|
|
|
|
|
|
|
|
newtype Email = Email { unEmail :: Text } deriving (Show, ToJSON, FromJSON, ToHttpApiData, FromHttpApiData)
|
|
|
|
|
|
|
|
newtype Username = Username { unUsername :: Text } deriving (Show, ToJSON, FromJSON, ToHttpApiData, FromHttpApiData)
|
|
|
|
|
|
|
|
instance SqlType HashedPassword where
|
|
|
|
mkLit = LCustom . LBlob . unHashed
|
|
|
|
fromSql (SqlBlob x) = HashedPassword x
|
|
|
|
fromSql _ = error "fromSql: Bad hash"
|
|
|
|
defaultValue = mkLit (HashedPassword "") -- Makes no sense
|
|
|
|
|
|
|
|
instance SqlType Email where
|
|
|
|
mkLit = LCustom . LText . unEmail
|
|
|
|
fromSql (SqlString x) = Email x
|
|
|
|
fromSql _ = error "fromSql: Bad email"
|
|
|
|
defaultValue = mkLit (Email "")
|
|
|
|
|
|
|
|
instance SqlType Username where
|
|
|
|
mkLit = LCustom . LText . unUsername
|
|
|
|
fromSql (SqlString x) = Username x
|
|
|
|
fromSql _ = error "fromSql: Bad username"
|
|
|
|
defaultValue = mkLit (Username "")
|
|
|
|
|
2018-08-06 00:09:41 +03:00
|
|
|
newtype UserID = UserID {unUserID :: Int} deriving (Show)
|
|
|
|
|
2018-08-08 22:21:15 +03:00
|
|
|
newtype BookID = BookID {unBookID :: Int} deriving (Show, ToJSON, FromJSON, FromHttpApiData, Eq, Ord)
|
2018-08-06 00:09:41 +03:00
|
|
|
|
2018-08-14 00:03:52 +03:00
|
|
|
newtype ChannelID = ChannelID {unChannelID :: Int} deriving (Show, ToHttpApiData, FromHttpApiData)
|
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
|
|
|
|
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
|
|
|
|
fromSql _ = error "fromSql: Bad bookid"
|
|
|
|
defaultValue = mkLit (BookID (-1))
|
|
|
|
instance SqlType ChannelID where
|
|
|
|
mkLit = LCustom . LInt . unChannelID
|
|
|
|
fromSql (SqlInt x) = ChannelID x
|
|
|
|
fromSql _ = error "fromSql: Bad channelid"
|
|
|
|
defaultValue = mkLit (ChannelID (-1))
|
|
|
|
instance SqlType TagID where
|
|
|
|
mkLit = LCustom . LInt . unTagID
|
|
|
|
fromSql (SqlInt x) = TagID x
|
|
|
|
fromSql _ = error "fromSql: Bad tagid"
|
|
|
|
defaultValue = mkLit (TagID (-1))
|
|
|
|
|
|
|
|
data User pass = User { identifier :: UserID
|
2018-08-04 22:05:41 +03:00
|
|
|
, email :: Email
|
|
|
|
, username :: Username
|
2018-08-03 23:36:38 +03:00
|
|
|
, role :: Role
|
|
|
|
, password :: pass }
|
2018-08-02 23:59:08 +03:00
|
|
|
deriving (Show, Generic)
|
|
|
|
|
2018-08-04 22:05:41 +03:00
|
|
|
data Role = UserRole | AdminRole deriving (Show, Read, Enum, Bounded, Typeable, Generic)
|
|
|
|
|
|
|
|
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-08-07 22:27:05 +03: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
|
|
|
|
, title :: Maybe Text
|
2018-08-08 21:58:36 +03:00
|
|
|
, description :: Maybe Text
|
|
|
|
, 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-08-04 21:30:08 +03:00
|
|
|
fromSql _ = error "fromSql: Not a valid hash digest"
|
|
|
|
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-08-04 21:30:08 +03:00
|
|
|
, tag :: Text
|
2018-08-06 00:09:41 +03:00
|
|
|
, owner :: UserID }
|
2018-08-04 21:30:08 +03:00
|
|
|
deriving (Show, Generic)
|
|
|
|
|
2018-08-15 22:25:38 +03:00
|
|
|
data Visibility = Public | Private | Followers
|
|
|
|
deriving (Show, Read, Generic)
|
|
|
|
|
|
|
|
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-08-04 21:30:08 +03:00
|
|
|
, channel :: Text
|
2018-08-15 22:25:38 +03:00
|
|
|
, 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-08-06 00:09:41 +03: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-08-07 22:27:05 +03: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)
|