#if __GLASGOW_HASKELL__ >= 702
#endif
module Database.MongoDB.Structured.Query (
insert, insert_
, insertMany, insertMany_
, insertAll, insertAll_
, save
, delete, deleteOne
, asc
, desc
, StructuredQuery
, limit
, skip
, sort
, find
, findOne
, fetch
, count
, StructuredSelection
, StructuredSelect(select)
, Selectable(..)
, (.!)
, QueryExp
, (.*)
, (.==), (./=), (.<), (.<=), (.>), (.>=)
, (.&&), (.||), not_
, StructuredCursor
, closeCursor, isCursorClosed
, nextBatch, next, nextN, rest
, module Database.MongoDB.Query
, Value
) where
import qualified Database.MongoDB.Query as M
import Database.MongoDB.Query (Action
, access
, Failure(..)
, ErrorCode
, AccessMode(..)
, GetLastError
, master
, slaveOk
, accessMode
, MonadDB(..)
, Database
, allDatabases
, useDb
, thisDatabase
, Username
, Password
, auth)
import Database.MongoDB.Structured.Types
import Database.MongoDB.Internal.Util
import Data.Bson
import Data.Maybe (fromJust)
import Data.List (sortBy, groupBy)
import Data.Functor
import Data.Word
import Data.CompactString.UTF8 (intercalate)
import Control.Monad
import Control.Monad.IO.Class
import Control.Monad.Trans.Control
import Control.Monad.Base
insert :: (MonadIO' m, Structured a) => a -> Action m Value
insert x = M.insert (collection x) (toBSON x)
insert_ :: (MonadIO' m, Structured a) => a -> Action m ()
insert_ x = insert x >> return ()
insertMany :: (MonadIO' m, Structured a) => [a] -> Action m [Value]
insertMany = insertManyOrAll (M.insertMany)
insertMany_ :: (MonadIO' m, Structured a) => [a] -> Action m ()
insertMany_ ss = insertMany ss >> return ()
insertAll :: (MonadIO' m, Structured a) => [a] -> Action m [Value]
insertAll = insertManyOrAll (M.insertAll)
insertAll_ :: (MonadIO' m, Structured a) => [a] -> Action m ()
insertAll_ ss = insertAll ss >> return ()
insertManyOrAll :: (MonadIO' m, Structured a) =>
(M.Collection -> [Document] -> Action m [Value]) -> [a] -> Action m [Value]
insertManyOrAll insertFunc ss = do
let docs = map (\x -> (collection x, toBSON x)) ss
gdocs = (groupBy (\(a,_) (b,_) -> a == b))
. (sortBy (\(a,_) (b,_) -> compare a b)) $ docs
concat <$> (forM gdocs $ \ds ->
if (null ds)
then return []
else insertFunc (fst . head $ ds) (map snd ds)
)
save :: (MonadIO' m, Structured a) => a -> Action m ()
save x = M.save (collection x) (toBSON x)
delete :: MonadIO m => StructuredSelection -> Action m ()
delete = M.delete . unStructuredSelection
deleteOne :: MonadIO m => StructuredSelection -> Action m ()
deleteOne = M.deleteOne . unStructuredSelection
find :: (Functor m, MonadIO m, MonadBaseControl IO m)
=> StructuredQuery -> Action m StructuredCursor
find q = StructuredCursor <$> (M.find . unStructuredQuery $ q)
findOne :: (MonadIO m, Structured a)
=> StructuredQuery -> Action m (Maybe a)
findOne q = do
res <- M.findOne . unStructuredQuery $ q
return $ res >>= fromBSON
fetch :: (MonadIO m, Functor m, Structured a)
=> StructuredQuery -> Action m a
fetch q = (fromJust . fromBSON) <$> (M.fetch . unStructuredQuery $ q)
count :: (MonadIO' m) => StructuredQuery -> Action m Int
count = M.count . unStructuredQuery
newtype StructuredCursor = StructuredCursor { unStructuredCursor :: M.Cursor }
nextBatch :: (Structured a, Functor m, MonadIO m, MonadBaseControl IO m)
=> StructuredCursor -> Action m [Maybe a]
nextBatch c = (map fromBSON) <$> M.nextBatch (unStructuredCursor c)
next :: (Structured a, MonadIO m, MonadBaseControl IO m)
=> StructuredCursor -> Action m (Either () (Maybe a))
next c = do
res <- M.next (unStructuredCursor c)
case res of
Nothing -> return (Left ())
Just r -> return (Right $ fromBSON r)
nextN :: (Structured a, Functor m, MonadIO m, MonadBaseControl IO m)
=> Int -> StructuredCursor -> Action m [Maybe a]
nextN n c = (map fromBSON) <$> M.nextN n (unStructuredCursor c)
rest :: (Structured a, Functor m, MonadIO m, MonadBaseControl IO m)
=> StructuredCursor -> Action m [Maybe a]
rest c = (map fromBSON) <$> M.rest (unStructuredCursor c)
closeCursor :: (MonadIO m, MonadBaseControl IO m) => StructuredCursor -> Action m ()
closeCursor = M.closeCursor . unStructuredCursor
isCursorClosed :: (MonadIO m, MonadBase IO m) => StructuredCursor -> Action m Bool
isCursorClosed = M.isCursorClosed . unStructuredCursor
newtype StructuredSelection =
StructuredSelection { unStructuredSelection :: M.Selection }
deriving(Eq, Show)
data StructuredQuery = StructuredQuery
{ selection :: StructuredSelection
, skip :: Word32
, limit :: Word32
, sort :: [OrderExp]
}
deriving(Eq, Show)
class StructuredSelect aQorS where
select :: Structured a => QueryExp a -> aQorS
instance StructuredSelect StructuredSelection where
select = StructuredSelection . expToSelection
instance StructuredSelect StructuredQuery where
select x = StructuredQuery (StructuredSelection $ expToSelection x)
0 0 ([])
unStructuredQuery :: StructuredQuery -> M.Query
unStructuredQuery sq = M.Query []
(unStructuredSelection $ selection sq)
[]
(skip sq)
(limit sq)
(expToOrder $ sort sq)
False 0 []
class Val t => Selectable a f t | f -> a, f -> t where
s :: f -> t -> Label
data Nested f f' = Nested Label
(.!) :: (Selectable r f t, Selectable t f' t') => f -> f' -> Nested f f'
(.!) f f' = Nested $ intercalate (u ".") [(s f undefined), (s f' undefined)]
instance (Selectable r f t, Selectable t f' t') =>
Selectable r (Nested f f') t' where
s (Nested l) _ = l
data QueryExp a = StarExp
| EqExp !Label !Value
| LBinExp !UString !Label !Value
| AndExp (QueryExp a) (QueryExp a)
| OrExp (QueryExp a) (QueryExp a)
| NotExp (QueryExp a)
deriving (Eq, Show)
infix 9 .!
infix 4 .==, ./=, .<, .<=, .>, .>=
infixr 3 .&&
infixr 2 .||
(.*) :: (Structured a) => QueryExp a
(.*) = StarExp
(.==) :: (Val t, Selectable a f t) => f -> t -> QueryExp a
(.==) f v = EqExp (s f v) (val v)
(./=) :: (Val t, Selectable a f t) => f -> t -> QueryExp a
(./=) f v = LBinExp (u "$ne") (s f v) (val v)
(.< ) :: (Val t, Selectable a f t) => f -> t -> QueryExp a
(.< ) f v = LBinExp (u "$lt") (s f v) (val v)
(.<=) :: (Val t, Selectable a f t) => f -> t -> QueryExp a
(.<=) f v = LBinExp (u "$lte") (s f v) (val v)
(.> ) :: (Val t, Selectable a f t) => f -> t -> QueryExp a
(.> ) f v = LBinExp (u "$gt") (s f v) (val v)
(.>=) :: (Val t, Selectable a f t) => f -> t -> QueryExp a
(.>=) f v = LBinExp (u "$gte") (s f v) (val v)
(.&&) :: QueryExp a -> QueryExp a -> QueryExp a
(.&&) = AndExp
(.||) :: QueryExp a -> QueryExp a -> QueryExp a
(.||) = OrExp
not_ :: QueryExp a -> QueryExp a
not_ = NotExp
expToSelector :: Structured a => QueryExp a -> M.Selector
expToSelector (StarExp) = [ ]
expToSelector (EqExp l v) = [ l := v ]
expToSelector (LBinExp op l v) = [ l =: [ op := v ]]
expToSelector (AndExp e1 e2) = [ (u "$and") =: [expToSelector e1
, expToSelector e2] ]
expToSelector (OrExp e1 e2) = [ (u "$or") =: [expToSelector e1
, expToSelector e2] ]
expToSelector (NotExp e) = [ (u "$not") =: expToSelector e]
expToSelection :: Structured a => QueryExp a -> M.Selection
expToSelection e = M.Select { M.selector = (expToSelector e)
, M.coll = (collection . c $ e) }
where c :: Structured a => QueryExp a -> a
c _ = undefined
data OrderExp = Desc Label
| Asc Label
deriving(Eq, Show)
asc :: Selectable a f t => f -> OrderExp
asc f = Asc (s f undefined)
desc :: Selectable a f t => f -> OrderExp
desc f = Desc (s f undefined)
expToOrder :: [OrderExp] -> M.Order
expToOrder exps = map _expToLabel exps
where _expToLabel (Desc fieldName) = fieldName := val (1 :: Int)
_expToLabel (Asc fieldName) = fieldName := val (1 :: Int)