module Main where import Test.HUnit hiding (path) import TestUtil import Data.IORef import Data.List (isPrefixOf) import Database.TokyoCabinet.TDB import Database.TokyoCabinet.TDB.Query hiding (new, delete) import qualified Database.TokyoCabinet.TDB.Query as Q (new, delete) dbname :: String dbname = "foo.tct" withOpenedTDB :: String -> (TDB -> IO a) -> IO () withOpenedTDB name action = do h <- new open h name [OWRITER, OCREAT] action h close h return () test_new_delete = do tdb <- new qry <- Q.new tdb Q.delete qry delete tdb samples :: [ (String, AssocList String String) ] samples = [ ("hop" , AssocList [("foo", "1"), ("bar", "abc")]) , ("step", AssocList [("foo", "2"), ("bar", "def")]) , ("jump", AssocList [("foo", "3"), ("bar", "deg")]) ] test_addcond = withoutFile dbname $ \fn -> withOpenedTDB fn $ \tdb -> do all id `fmap` mapM (uncurry $ put tdb) samples @? "put" qry <- Q.new tdb addcond qry "foo" QCNUMGT "1" search qry >>= (["step", "jump"] @=?) qry <- Q.new tdb addcond qry "bar" QCSTRBW "de" search qry >>= (["step", "jump"] @=?) qry <- Q.new tdb addcond qry "bar" QCSTRBW "de" search qry >>= (["step", "jump"] @=?) qry <- Q.new tdb addcond qry "bar" (QCNEGATE QCSTRBW) "de" search qry >>= (["hop"] @=?) qry <- Q.new tdb addcond qry "bar" QCSTRRX ".e." search qry >>= (["step", "jump"] @=?) test_setorder = withoutFile dbname $ \fn -> withOpenedTDB fn $ \tdb -> do all id `fmap` mapM (uncurry $ put tdb) samples @? "put" qry <- Q.new tdb addcond qry "foo" QCNUMGT "0" setorder qry "bar" QOSTRDESC search qry >>= (["jump", "step", "hop"] @=?) qry <- Q.new tdb addcond qry "foo" QCNUMGT "0" setorder qry "bar" QOSTRASC search qry >>= (["hop", "step", "jump"] @=?) qry <- Q.new tdb addcond qry "bar" QCSTRBW "" setorder qry "foo" QONUMDESC search qry >>= (["jump", "step", "hop"] @=?) qry <- Q.new tdb addcond qry "bar" QCSTRBW "" setorder qry "foo" QONUMASC search qry >>= (["hop", "step", "jump"] @=?) test_setlimit = withoutFile dbname $ \fn -> withOpenedTDB fn $ \tdb -> do all id `fmap` mapM (uncurry $ put tdb) samples @? "put" qry <- Q.new tdb addcond qry "foo" QCNUMGT "0" setlimit qry 1 0 search qry >>= (["hop"] @=?) setlimit qry 1 1 search qry >>= (["step"] @=?) setlimit qry 2 2 search qry >>= (["jump"] @=?) setlimit qry 2 1 search qry >>= (["step", "jump"] @=?) test_searchout = withoutFile dbname $ \fn -> withOpenedTDB fn $ \tdb -> do all id `fmap` mapM (uncurry $ put tdb) samples @? "put" qry <- Q.new tdb addcond qry "foo" QCNUMGT "2" searchout qry @? "searchout" fwmkeys tdb "" (-1) >>= (["hop", "step"] @=?) test_hint = withoutFile dbname $ \fn -> withoutFile (dbname ++ ".idx.foo.dec") $ \_ -> withOpenedTDB fn $ \tdb -> do all id `fmap` mapM (uncurry $ put tdb) samples @? "put" qry <- Q.new tdb addcond qry "foo" QCNUMGT "2" search qry :: IO [String] ("scanning the whole table" `isPrefixOf`) `fmap` hint qry @? "whole" setindex tdb "foo" ITDECIMAL search qry :: IO [String] ("using an index: \"foo\"" `isPrefixOf`) `fmap` hint qry @? "index" test_proc1 = withoutFile dbname $ \fn -> withOpenedTDB fn $ \tdb -> do all id `fmap` mapM (uncurry $ put tdb) samples @? "put" qry <- Q.new tdb addcond qry "foo" QCNUMGE "2" (proc qry $ \pkey (AssocList cols) -> do let val = [(k, v ++ "!") | (k, v) <- cols] :: [(String, String)] return $ QPPUT (AssocList val)) @? "proc" (AssocList res) <- get tdb "step" lookup "foo" res @?= Just "2!" (AssocList res) <- get tdb "jump" lookup "foo" res @?= Just "3!" test_proc2 = withoutFile dbname $ \fn -> withOpenedTDB fn $ \tdb -> do all id `fmap` mapM (uncurry $ put tdb) samples @? "put" acc <- newIORef [] :: IO (IORef [String]) qry <- Q.new tdb addcond qry "foo" QCNUMGE "1" proc qry $ \pkey (AssocList cols) -> do let Just foo = lookup "foo" cols writeIORef acc . (foo:) =<< readIORef acc return $ if foo == "2" then QPSTOP else QPNOP readIORef acc >>= (["2", "1"] @=?) tests = test [ "new delete" ~: test_new_delete , "addcond" ~: test_addcond , "setorder" ~: test_setorder , "setlimit" ~: test_setlimit , "searchout" ~: test_searchout , "hint" ~: test_hint , "proc1" ~: test_proc1 , "proc2" ~: test_proc2 ] main = runTestTT tests