lucienne-0.0.1: Lucienne/Database.hs
module Lucienne.Database
( addUser, deleteUser, users, usernameExists, userByNameAndPassword, changePassword
, addFeed, feedExists, feedsByUser, feedById, deleteFeedById
, addFeedItems, upsertFeedItem, feedItems, feedItemsByFeedId, feedItemById, feedItemExists
, deleteMarkedFeedItems, deleteFeedItemsByFeedId
, countUsers)
where
import Data.Maybe (isJust)
import Control.Applicative ((<$>))
import Data.CompactString.UTF8 (CompactString)
import Data.Bson ((=:),ObjectId)
import Database.MongoDB (Document,Value)
import qualified Database.MongoDB as DB
import Lucienne.ConnectionReader (ConnectionReader,accessDb)
import Lucienne.DatabaseAble (DatabaseAble(..))
import Lucienne.Model.Util (showValue,objectId,readObjectId)
import Lucienne.Model.User (User,name)
import qualified Lucienne.Model.User as U
import Lucienne.Model.Feed (Feed)
import qualified Lucienne.Model.Feed as F
import Lucienne.Model.FeedItem (FeedItem)
import qualified Lucienne.Model.FeedItem as FI
type Collection = CompactString
userCollection = "users"
feedCollection = "feeds"
feedItemCollection = "feedItems"
addUser :: User -> ConnectionReader String
addUser user =
showValue <$> addDatabaseAble userCollection user
deleteUser :: User -> ConnectionReader ()
deleteUser user =
let deleteFeedItemsQuery = FI.feedItemsQuery (name user)
deleteFeedsQuery = F.feedsQuery (name user)
deleteUserQuery = U.userByNameQuery (name user)
in do
deleteDocuments feedItemCollection deleteFeedItemsQuery
deleteDocuments feedCollection deleteFeedsQuery
deleteDocuments userCollection deleteUserQuery
addFeed :: Feed -> ConnectionReader ObjectId
addFeed feed =
objectId <$> addDatabaseAble feedCollection feed
addFeedItems :: [FeedItem] -> ConnectionReader [ObjectId]
addFeedItems items =
map objectId <$> addDatabaseAbles feedItemCollection items
upsertFeedItem :: FeedItem -> ConnectionReader ()
upsertFeedItem = upsertDatabaseAble feedItemCollection
users :: ConnectionReader [User]
users = do
users <- readDocuments userCollection [] [] []
return $ map fromDocument users
usernameExists :: String -> ConnectionReader Bool
usernameExists = querySucceeds userCollection . U.userByNameQuery
userByNameAndPassword :: String -> String -> ConnectionReader (Maybe User)
userByNameAndPassword name password = do
user <- readDocument userCollection (U.userByNameAndPasswordQuery name password) []
return $ fmap fromDocument user
changePassword :: User -> String -> ConnectionReader ()
changePassword user = upsertDatabaseAble userCollection . U.changePassword user
feedExists :: User -> String -> ConnectionReader Bool
feedExists user url =
querySucceeds feedCollection $ F.feedByUrlQuery (name user) url
feedsByUser :: User -> ConnectionReader [Feed]
feedsByUser user = do
docs <- readDocuments feedCollection (F.feedsQuery $ name user) [] []
return $ map fromDocument docs
feedById :: User -> String -> ConnectionReader (Maybe Feed)
feedById user feedId =
let queryDocument = F.feedByIdQuery (name user) (readObjectId feedId)
in do
feed <- readDocument feedCollection queryDocument []
return $ fmap fromDocument feed
deleteFeedById :: User -> ObjectId -> ConnectionReader ()
deleteFeedById user feedId =
let queryDocument = F.feedByIdQuery (name user) feedId
in
deleteDocuments feedCollection queryDocument
feedItemsByFeedId :: User -> String -> ConnectionReader [FeedItem]
feedItemsByFeedId user feedId =
let queryDocument = FI.feedItemsByFeedIdQuery (name user) feedId
in do
docs <- readDocuments feedItemCollection queryDocument FI.feedItemHeaderProjector FI.feedItemsSort
return $ map fromDocument docs
feedItems :: User -> ConnectionReader [FeedItem]
feedItems user =
let queryDocument = FI.readableFeedItemsQuery $ name user
in do
docs <- readDocuments feedItemCollection queryDocument FI.feedItemHeaderProjector FI.feedItemsSort
return $ map fromDocument docs
feedItemById :: User -> String -> ConnectionReader (Maybe FeedItem)
feedItemById user feedItemId =
let queryDocument = FI.feedItemByIdQuery (name user) feedItemId
in do
item <- readDocument feedItemCollection queryDocument []
return $ fmap fromDocument item
feedItemExists :: ObjectId -> String -> String -> ConnectionReader Bool
feedItemExists feedId title url =
let queryDocument = FI.feedItemExistsQuery feedId title url
in
querySucceeds feedItemCollection queryDocument
deleteMarkedFeedItems :: ObjectId -> [String] -> [String] -> ConnectionReader ()
deleteMarkedFeedItems feedId titlesToRemain urlsToRemain =
let queryDocument = FI.deleteMarkedFeedItemsQuery feedId titlesToRemain urlsToRemain
in
deleteDocuments feedItemCollection queryDocument
deleteFeedItemsByFeedId :: ObjectId -> ConnectionReader ()
deleteFeedItemsByFeedId feedId =
let queryDocument = FI.deleteFeedItemsByFeedIdQuery feedId
in
deleteDocuments feedItemCollection queryDocument
countUsers :: ConnectionReader Int
countUsers = countDocuments userCollection
readDocument :: Collection -> Document -> Document -> ConnectionReader (Maybe Document)
readDocument collection queryDocument projector =
let query = (DB.select queryDocument collection) {DB.project = projector}
in
accessDb $ DB.findOne query
readDocuments :: Collection -> Document -> Document -> Document -> ConnectionReader [Document]
readDocuments collection queryDocument projector sort =
let query = (DB.select queryDocument collection) {DB.project = projector, DB.sort = sort}
in
accessDb $ DB.find query >>= DB.rest
countDocuments :: Collection -> ConnectionReader Int
countDocuments = accessDb . DB.count . DB.select []
addDatabaseAble :: (DatabaseAble a) => Collection -> a -> ConnectionReader Value
addDatabaseAble collection =
accessDb . DB.insert collection . toDocument
addDatabaseAbles :: (DatabaseAble a) => Collection -> [a] -> ConnectionReader [Value]
addDatabaseAbles collection =
accessDb . DB.insertMany collection . map toDocument
upsertDatabaseAble :: (DatabaseAble a) => Collection -> a -> ConnectionReader ()
upsertDatabaseAble collection =
accessDb . DB.save collection . toDocument
deleteDocuments :: Collection -> Document -> ConnectionReader ()
deleteDocuments collection queryDocument =
accessDb $ DB.delete $ DB.select queryDocument collection
-- |Returns @True@ when at least on result was found
querySucceeds :: Collection -> Document -> ConnectionReader Bool
querySucceeds collection queryDocument =
let query = (DB.select queryDocument collection) {DB.project = [ "_id" =: (1::Int) ]}
in
isJust <$> (accessDb $ DB.findOne query)