diff options
-rw-r--r-- | backend/backend.cabal | 2 | ||||
-rw-r--r-- | backend/lib/ACMS/API/Fetch.hs | 63 | ||||
-rw-r--r-- | backend/lib/ACMS/API/Query.hs | 17 | ||||
-rw-r--r-- | backend/lib/ACMS/API/REST.hs | 50 | ||||
-rw-r--r-- | backend/lib/ACMS/API/REST/Collection.hs | 8 | ||||
-rw-r--r-- | backend/lib/ACMS/API/REST/Collection/Paginated.hs | 3 | ||||
-rw-r--r-- | cli/app/Main.hs | 17 | ||||
-rw-r--r-- | cli/cli.cabal | 3 |
8 files changed, 105 insertions, 58 deletions
diff --git a/backend/backend.cabal b/backend/backend.cabal index 335e8f3..6b13682 100644 --- a/backend/backend.cabal +++ b/backend/backend.cabal @@ -9,11 +9,13 @@ build-type: Simple library exposed-modules: + ACMS.API.Query ACMS.API.REST ACMS.API.REST.Collection ACMS.API.REST.Collection.Paginated hs-source-dirs: lib + other-modules: ACMS.API.Fetch default-language: GHC2021 default-extensions: CPP BlockArguments LambdaCase OverloadedStrings ViewPatterns diff --git a/backend/lib/ACMS/API/Fetch.hs b/backend/lib/ACMS/API/Fetch.hs new file mode 100644 index 0000000..84330b1 --- /dev/null +++ b/backend/lib/ACMS/API/Fetch.hs @@ -0,0 +1,63 @@ +{-# LANGUAGE OverloadedStrings #-} + +module ACMS.API.Fetch + ( APIMonad(fetch), +#ifndef ghcjs_HOST_OS + Network.HTTP.Simple.Request, + Network.HTTP.Simple.setRequestMethod, + Network.HTTP.Simple.setRequestBodyLBS, +#else + JavaScript.Web.XMLHttpRequest.Request, + setRequestMethod, + setRequestBodyLBS, +#endif + ) +where + +#ifndef ghcjs_HOST_OS +import Network.HTTP.Simple +#else +import Data.ByteString.Lazy.UTF8 qualified as LB +import Data.Maybe +import Data.String +import JavaScript.Web.XMLHttpRequest +import Miso.String qualified as J +import Data.ByteString qualified as B +#endif +import Control.Monad.Catch (MonadThrow) +import Data.ByteString.Lazy.Char8 qualified as LB +import Miso (JSM) + +class (MonadThrow m) => APIMonad m where + fetch :: Request -> m LB.ByteString + +instance APIMonad JSM where + fetch req = LB.fromStrict . getResponseBody <$> httpBS req + +#ifdef ghcjs_HOST_OS +httpBS :: Request -> JSM (Response B.ByteString) +httpBS req = xhrByteString req + +instance IsString Request where + fromString uri = + Request + { reqMethod = GET, + reqURI = J.pack uri, + reqLogin = Nothing, + reqHeaders = [], + reqWithCredentials = False, + reqData = NoData + } + +setRequestMethod :: B.ByteString -> Request -> Request +setRequestMethod "POST" req = req {reqMethod = POST} + +setRequestBodyLBS :: LB.ByteString -> Request -> Request +setRequestBodyLBS body req = req {reqData = StringData (J.pack (LB.toString body))} + +getResponseBody :: Response B.ByteString -> B.ByteString +getResponseBody = fromMaybe "" . contents +#else +instance APIMonad IO where + fetch req = LB.fromStrict . getResponseBody <$> httpBS req +#endif diff --git a/backend/lib/ACMS/API/Query.hs b/backend/lib/ACMS/API/Query.hs new file mode 100644 index 0000000..ab2cabc --- /dev/null +++ b/backend/lib/ACMS/API/Query.hs @@ -0,0 +1,17 @@ +{-# LANGUAGE OverloadedStrings #-} + +module ACMS.API.Query where + +import ACMS.API.Fetch +import Data.Aeson qualified as A +import Data.ByteString.Lazy.UTF8 qualified as LB +import Data.Function ((&)) +import Data.String (IsString (fromString)) + +query :: (APIMonad m) => String -> m A.Value +query q = + fromString ("http://localhost:8081/api/query") + & setRequestMethod "POST" + & setRequestBodyLBS (LB.fromString q) + & fetch + >>= A.throwDecode diff --git a/backend/lib/ACMS/API/REST.hs b/backend/lib/ACMS/API/REST.hs index baf9adb..6cd2982 100644 --- a/backend/lib/ACMS/API/REST.hs +++ b/backend/lib/ACMS/API/REST.hs @@ -2,22 +2,10 @@ module ACMS.API.REST where -#ifndef ghcjs_HOST_OS -import Network.HTTP.Simple -import Data.String (IsString(fromString)) -#else -import Data.ByteString.Lazy.UTF8 qualified as LB -import Data.ByteString qualified as B -import Data.Maybe -import Data.String -import JavaScript.Web.XMLHttpRequest -import Miso.String qualified as J -#endif -import Control.Monad.Catch (MonadThrow) +import ACMS.API.Fetch import Data.Aeson qualified as A -import Data.ByteString.Lazy.Char8 qualified as LB import Data.Function ((&)) -import Miso (JSM) +import Data.String (IsString (fromString)) import Miso.String (MisoString) restRequest :: String -> Request @@ -43,37 +31,3 @@ createCollection collection = & setRequestBodyLBS (A.encode (A.toJSON collection)) & fetch >>= A.throwDecode - -class (MonadThrow m) => APIMonad m where - fetch :: Request -> m LB.ByteString - -instance APIMonad JSM where - fetch req = LB.fromStrict . getResponseBody <$> httpBS req - -#ifdef ghcjs_HOST_OS -httpBS :: Request -> JSM (Response B.ByteString) -httpBS req = xhrByteString req - -instance IsString Request where - fromString uri = - Request - { reqMethod = GET, - reqURI = J.pack uri, - reqLogin = Nothing, - reqHeaders = [], - reqWithCredentials = False, - reqData = NoData - } - -setRequestMethod :: B.ByteString -> Request -> Request -setRequestMethod "POST" req = req {reqMethod = POST} - -setRequestBodyLBS :: LB.ByteString -> Request -> Request -setRequestBodyLBS body req = req {reqData = StringData (J.pack (LB.toString body))} - -getResponseBody :: Response B.ByteString -> B.ByteString -getResponseBody = fromMaybe "" . contents -#else -instance APIMonad IO where - fetch req = LB.fromStrict . getResponseBody <$> httpBS req -#endif diff --git a/backend/lib/ACMS/API/REST/Collection.hs b/backend/lib/ACMS/API/REST/Collection.hs index 7eea23b..7de1909 100644 --- a/backend/lib/ACMS/API/REST/Collection.hs +++ b/backend/lib/ACMS/API/REST/Collection.hs @@ -2,12 +2,8 @@ module ACMS.API.REST.Collection where -#ifndef ghcjs_HOST_OS -import Network.HTTP.Simple -#else -import ACMS.API.REST (setRequestMethod, setRequestBodyLBS) -#endif -import ACMS.API.REST (APIMonad, fetch, restRequest) +import ACMS.API.Fetch +import ACMS.API.REST (restRequest) import Collection import Data.Aeson qualified as A import Data.Function ((&)) diff --git a/backend/lib/ACMS/API/REST/Collection/Paginated.hs b/backend/lib/ACMS/API/REST/Collection/Paginated.hs index ad98888..159754a 100644 --- a/backend/lib/ACMS/API/REST/Collection/Paginated.hs +++ b/backend/lib/ACMS/API/REST/Collection/Paginated.hs @@ -3,7 +3,8 @@ module ACMS.API.REST.Collection.Paginated where -import ACMS.API.REST (APIMonad, fetch, restRequest) +import ACMS.API.Fetch +import ACMS.API.REST (restRequest) import Collection import Data.Aeson qualified as A import Data.Function ((&)) diff --git a/cli/app/Main.hs b/cli/app/Main.hs index 4b166e7..12ba7c5 100644 --- a/cli/app/Main.hs +++ b/cli/app/Main.hs @@ -8,12 +8,14 @@ module Main where +import ACMS.API.Query qualified import ACMS.API.REST.Collection qualified import Collection import Control.Applicative ((<**>)) import Data.Aeson qualified as J import Data.Aeson.Encode.Pretty qualified as J import Data.ByteString.Lazy.Char8 qualified as LB +import Data.ByteString.Lazy.UTF8 qualified as LB import Data.Text qualified as T import Options.Applicative qualified as O @@ -24,13 +26,17 @@ newtype Args = Args args :: O.Parser Args args = Args <$> cmd_ -data Cmd = CollectionCmd CollectionCmd +data Cmd + = CollectionCmd CollectionCmd + | QueryCmd cmd_ :: O.Parser Cmd cmd_ = O.hsubparser . mconcat $ [ O.command "collection" . O.info collectionCmd $ - O.progDesc "Manage content collections" + O.progDesc "Manage content collections", + O.command "query" . O.info queryCmd $ + O.progDesc "Manage content through queries" ] data CollectionCmd @@ -68,6 +74,9 @@ collectionArg :: O.Parser Collection collectionArg = Collection . T.pack <$> O.strArgument (O.metavar "COLLECTION_NAME") +queryCmd :: O.Parser Cmd +queryCmd = pure QueryCmd + main :: IO () main = O.execParser (O.info (args <**> O.helper) O.idm) >>= \case @@ -94,3 +103,7 @@ main = CollectionSchema collection -> LB.putStr . J.encodePretty @J.Value =<< ACMS.API.REST.Collection.schema collection + Args {cmd = QueryCmd} -> + LB.putStr . J.encodePretty @J.Value + =<< ACMS.API.Query.query . LB.toString + =<< LB.getContents diff --git a/cli/cli.cabal b/cli/cli.cabal index 5617808..3d0934e 100644 --- a/cli/cli.cabal +++ b/cli/cli.cabal @@ -24,4 +24,5 @@ executable acms filepath, optparse-applicative, sh, - text + text, + utf8-string |