add querying
This commit is contained in:
@@ -23,6 +23,7 @@ import Network.HTTP.Types.Status qualified as W
|
|||||||
import Network.Wai qualified as W
|
import Network.Wai qualified as W
|
||||||
import Network.Wai.Handler.Warp qualified as W
|
import Network.Wai.Handler.Warp qualified as W
|
||||||
import Options.Applicative qualified as A
|
import Options.Applicative qualified as A
|
||||||
|
import Store qualified as Q
|
||||||
import System.Directory (setCurrentDirectory)
|
import System.Directory (setCurrentDirectory)
|
||||||
import System.FilePath
|
import System.FilePath
|
||||||
import Text.Printf (printf)
|
import Text.Printf (printf)
|
||||||
@@ -117,16 +118,25 @@ main = do
|
|||||||
Right (SchemaJson path) -> do
|
Right (SchemaJson path) -> do
|
||||||
let [c] = filter ((== path) . (.path)) (head repo.commits).collections
|
let [c] = filter ((== path) . (.path)) (head repo.commits).collections
|
||||||
respond $ W.responseLBS W.status200 [] (J.encode c.schema)
|
respond $ W.responseLBS W.status200 [] (J.encode c.schema)
|
||||||
|
Right Query -> 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
|
||||||
(Debug.Trace.traceShowId -> !_) ->
|
(Debug.Trace.traceShowId -> !_) ->
|
||||||
respond $ W.responseLBS W.status200 [] "OK"
|
respond $ W.responseLBS W.status200 [] "not implemented"
|
||||||
|
|
||||||
data Route
|
data Route
|
||||||
= SchemaJson String
|
= SchemaJson String
|
||||||
|
| Query
|
||||||
deriving (Show)
|
deriving (Show)
|
||||||
|
|
||||||
routeP :: P.Parser Route
|
routeP :: P.Parser Route
|
||||||
routeP =
|
routeP =
|
||||||
( SchemaJson
|
( P.choice
|
||||||
<$> (P.string "/" *> P.manyTill P.anyChar (P.string ".schema.json"))
|
[ SchemaJson <$> (P.string "/" *> P.manyTill P.anyChar (P.string ".schema.json")),
|
||||||
|
pure Query <* (P.string "/")
|
||||||
|
]
|
||||||
)
|
)
|
||||||
<* P.endOfInput
|
<* P.endOfInput
|
||||||
|
|||||||
@@ -1,28 +1,71 @@
|
|||||||
module Main where
|
module Main where
|
||||||
|
|
||||||
#ifndef ghcjs_HOST_OS
|
#ifndef ghcjs_HOST_OS
|
||||||
import Language.Javascript.JSaddle.Warp as JSaddle
|
|
||||||
#endif
|
|
||||||
|
|
||||||
import Data.ByteString.UTF8 qualified as B
|
|
||||||
import Data.Maybe
|
|
||||||
import Miso
|
|
||||||
import Miso.String
|
|
||||||
|
|
||||||
#ifndef ghcjs_HOST_OS
|
|
||||||
import Network.HTTP.Simple
|
|
||||||
import Data.String
|
import Data.String
|
||||||
|
import Language.Javascript.JSaddle.Warp as JSaddle
|
||||||
|
import Network.HTTP.Simple
|
||||||
#else
|
#else
|
||||||
|
import Data.ByteString.Char8 qualified as B
|
||||||
|
import Data.Maybe
|
||||||
|
import Data.String
|
||||||
import JavaScript.Web.XMLHttpRequest
|
import JavaScript.Web.XMLHttpRequest
|
||||||
|
import Miso.String qualified as J
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
type Model = Maybe Schema
|
import Data.Aeson qualified as A
|
||||||
|
import Data.ByteString.Lazy.Char8 qualified as LB
|
||||||
|
import Data.Default
|
||||||
|
import Data.Function
|
||||||
|
import Data.Map qualified as M
|
||||||
|
import GHC.Generics (Generic)
|
||||||
|
import Miso
|
||||||
|
import Miso.String (toMisoString)
|
||||||
|
|
||||||
type Schema = String
|
data Model = Model
|
||||||
|
{ schema :: Maybe (Either String Schema),
|
||||||
|
posts :: Maybe (Either String [A.Value])
|
||||||
|
}
|
||||||
|
deriving (Show, Eq, Generic, Default)
|
||||||
|
|
||||||
|
data Schema = Schema
|
||||||
|
{ id :: String,
|
||||||
|
schema :: String,
|
||||||
|
title :: String,
|
||||||
|
type_ :: SchemaType
|
||||||
|
}
|
||||||
|
deriving (Show, Eq)
|
||||||
|
|
||||||
|
instance A.FromJSON Schema where
|
||||||
|
parseJSON =
|
||||||
|
A.withObject
|
||||||
|
"Schema"
|
||||||
|
( \v ->
|
||||||
|
Schema
|
||||||
|
<$> v A..: "$id"
|
||||||
|
<*> v A..: "$schema"
|
||||||
|
<*> v A..: "title"
|
||||||
|
<*> A.parseJSON (A.Object v)
|
||||||
|
)
|
||||||
|
|
||||||
|
data SchemaType = Object (M.Map String String)
|
||||||
|
deriving (Show, Eq)
|
||||||
|
|
||||||
|
instance A.FromJSON SchemaType where
|
||||||
|
parseJSON =
|
||||||
|
A.withObject
|
||||||
|
"SchemaType"
|
||||||
|
( \v ->
|
||||||
|
v A..: "type" >>= \case
|
||||||
|
("object" :: String) -> Object <$> v A..: "properties"
|
||||||
|
)
|
||||||
|
|
||||||
data Action
|
data Action
|
||||||
= FetchSchema
|
= NoOp
|
||||||
| SetSchema Schema
|
| Init
|
||||||
|
| FetchSchema
|
||||||
|
| SetSchema (Either String Schema)
|
||||||
|
| FetchPosts
|
||||||
|
| SetPosts (Either String [A.Value])
|
||||||
deriving (Show, Eq)
|
deriving (Show, Eq)
|
||||||
|
|
||||||
#ifndef ghcjs_HOST_OS
|
#ifndef ghcjs_HOST_OS
|
||||||
@@ -36,8 +79,8 @@ runApp app = app
|
|||||||
main :: IO ()
|
main :: IO ()
|
||||||
main = runApp $ startApp App {..}
|
main = runApp $ startApp App {..}
|
||||||
where
|
where
|
||||||
initialAction = FetchSchema
|
initialAction = Init
|
||||||
model = Nothing
|
model = def
|
||||||
update = updateModel
|
update = updateModel
|
||||||
view = viewModel
|
view = viewModel
|
||||||
events = defaultEvents
|
events = defaultEvents
|
||||||
@@ -48,30 +91,85 @@ main = runApp $ startApp App {..}
|
|||||||
updateModel :: Action -> Model -> Effect Action Model
|
updateModel :: Action -> Model -> Effect Action Model
|
||||||
updateModel action m =
|
updateModel action m =
|
||||||
case action of
|
case action of
|
||||||
|
NoOp -> noEff m
|
||||||
|
Init -> batchEff m [pure FetchSchema, pure FetchPosts]
|
||||||
FetchSchema -> m <# do SetSchema <$> fetchSchema
|
FetchSchema -> m <# do SetSchema <$> fetchSchema
|
||||||
SetSchema schema -> noEff (Just schema)
|
SetSchema schema ->
|
||||||
|
let setSchema :: Either String Schema -> Model -> Model
|
||||||
|
setSchema schema m = m {schema = Just schema}
|
||||||
|
in noEff (setSchema schema m)
|
||||||
|
FetchPosts -> m <# do SetPosts <$> fetchPosts
|
||||||
|
SetPosts posts ->
|
||||||
|
let setPosts :: Either String [A.Value] -> Model -> Model
|
||||||
|
setPosts posts m = m {posts = Just posts}
|
||||||
|
in noEff (setPosts posts m)
|
||||||
|
|
||||||
fetchSchema :: JSM String
|
fetchSchema :: JSM (Either String Schema)
|
||||||
fetchSchema = fetch "http://localhost:8081/posts.schema.json"
|
fetchSchema =
|
||||||
|
A.eitherDecode <$> fetch (fromString "http://localhost:8081/posts.schema.json")
|
||||||
|
|
||||||
#ifndef ghcjs_HOST_OS
|
fetchPosts :: JSM (Either String [A.Value])
|
||||||
fetch :: String -> JSM String
|
fetchPosts =
|
||||||
fetch url = B.toString . getResponseBody <$> httpBS (fromString url)
|
A.eitherDecode
|
||||||
#else
|
<$> fetch
|
||||||
fetch :: String -> JSM String
|
( fromString "http://localhost:8081"
|
||||||
fetch url = maybe "" B.toString . contents <$> xhrByteString req
|
& setRequestMethod "POST"
|
||||||
where
|
& setRequestBodyLBS "SELECT posts FROM posts"
|
||||||
req =
|
)
|
||||||
|
|
||||||
|
fetch :: Request -> JSM LB.ByteString
|
||||||
|
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
|
Request
|
||||||
{ reqMethod = GET,
|
{ reqMethod = GET,
|
||||||
reqURI = pack url,
|
reqURI = J.pack uri,
|
||||||
reqLogin = Nothing,
|
reqLogin = Nothing,
|
||||||
reqHeaders = [],
|
reqHeaders = [],
|
||||||
reqWithCredentials = False,
|
reqWithCredentials = False,
|
||||||
reqData = NoData
|
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.unpack body))}
|
||||||
|
|
||||||
|
getResponseBody :: Response B.ByteString -> B.ByteString
|
||||||
|
getResponseBody = fromMaybe "" . contents
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
viewModel :: Model -> View Action
|
viewModel :: Model -> View Action
|
||||||
viewModel schema =
|
viewModel model =
|
||||||
div_ [] [text (toMisoString (fromMaybe ".." schema))]
|
div_ [] $
|
||||||
|
[ maybe (text "..") (either err viewSchema) model.schema,
|
||||||
|
maybe (text "..") (either err viewPosts) model.posts
|
||||||
|
]
|
||||||
|
|
||||||
|
err :: String -> View Action
|
||||||
|
err = text . toMisoString . ("err! " <>)
|
||||||
|
|
||||||
|
viewSchema :: Schema -> View Action
|
||||||
|
viewSchema schema =
|
||||||
|
case schema.type_ of
|
||||||
|
Object properties ->
|
||||||
|
ol_ [] $
|
||||||
|
( \(k, v) ->
|
||||||
|
li_ [] $
|
||||||
|
[ text (toMisoString k),
|
||||||
|
text ":",
|
||||||
|
text (toMisoString v)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
<$> (M.toList properties)
|
||||||
|
|
||||||
|
viewPosts :: [A.Value] -> View Action
|
||||||
|
viewPosts posts = ol_ [] (viewPost <$> posts)
|
||||||
|
where
|
||||||
|
viewPost post = pre_ [] [text (toMisoString (A.encode post))]
|
||||||
|
|||||||
@@ -12,12 +12,21 @@ executable frontend
|
|||||||
main-is: Main.hs
|
main-is: Main.hs
|
||||||
hs-source-dirs: app
|
hs-source-dirs: app
|
||||||
default-language: GHC2021
|
default-language: GHC2021
|
||||||
default-extensions: CPP OverloadedStrings RecordWildCards
|
default-extensions:
|
||||||
ghc-options: -Wall
|
CPP OverloadedStrings RecordWildCards DeriveAnyClass
|
||||||
|
DuplicateRecordFields LambdaCase OverloadedRecordDot
|
||||||
|
NoFieldSelectors
|
||||||
|
|
||||||
|
ghc-options:
|
||||||
|
-Wall -fno-warn-name-shadowing -fno-warn-ambiguous-fields
|
||||||
|
-fno-warn-incomplete-patterns -fno-warn-orphans
|
||||||
|
|
||||||
build-depends:
|
build-depends:
|
||||||
|
aeson,
|
||||||
base,
|
base,
|
||||||
bytestring,
|
bytestring,
|
||||||
containers,
|
containers,
|
||||||
|
data-default,
|
||||||
miso,
|
miso,
|
||||||
text,
|
text,
|
||||||
utf8-string
|
utf8-string
|
||||||
@@ -27,5 +36,6 @@ executable frontend
|
|||||||
|
|
||||||
if arch(javascript)
|
if arch(javascript)
|
||||||
build-depends: ghcjs-base
|
build-depends: ghcjs-base
|
||||||
|
|
||||||
else
|
else
|
||||||
build-depends: http-conduit
|
build-depends: http-conduit
|
||||||
|
|||||||
Reference in New Issue
Block a user