module Main ( main, ) where import Control.Applicative ((<**>)) import Control.Monad.Trans (liftIO) import Data.Aeson qualified as J import Data.ByteString.Lazy.Char8 qualified as LB import Data.ByteString.Lazy.UTF8 qualified as LB import Data.String (IsString (fromString)) import Network.HTTP.Types.Method qualified as W import Network.HTTP.Types.Status qualified as W import Network.Wai qualified as W import Network.Wai.Handler.Warp qualified as W import Options.Applicative qualified as A import Store qualified as Q import System.Console.Repline qualified as R import System.Directory (setCurrentDirectory) import Text.Printf (printf) data Args = Args { cmd :: Cmd } args :: A.Parser Args args = Args <$> cmd_ data Cmd = Repl | Serve cmd_ :: A.Parser Cmd cmd_ = A.hsubparser . mconcat $ [ A.command "repl" . A.info replCmd $ A.progDesc "Interactively execute statements", A.command "serve" . A.info serveCmd $ A.progDesc "Run webserver" ] replCmd, serveCmd :: A.Parser Cmd replCmd = pure Repl serveCmd = pure Serve main :: IO () main = do setCurrentDirectory "./data" let root = "." ref = "HEAD" A.execParser (A.info (args <**> A.helper) A.idm) >>= \case Args {cmd = Repl} -> do -- TODO Catch `ParseError` exception -- -- @topic repl -- TODO Add query auto-completion -- -- @topic repl R.evalRepl (const . pure $ ">>> ") ( liftIO . (mapM_ (LB.putStrLn . J.encode) =<<) . Q.withStore root ref . Q.query . fromString ) ([]) (Just ':') (Just "paste") (R.Word (\_ -> pure ["SELECT"])) (pure ()) (pure R.Exit) Args {cmd = Serve} -> do W.runEnv 8080 $ \req respond -> do if | W.requestMethod req == W.methodPost -> do q <- fromString @Q.Query . LB.toString <$> W.lazyRequestBody req r <- liftIO $ Q.withStore root ref (Q.query q) respond . W.responseLBS W.status200 [] $ J.encode r | otherwise -> respond $ W.responseLBS W.status200 [] "OK"