2015-05-09 12:27:45 +02:00
|
|
|
{-# LANGUAGE DataKinds #-}
|
|
|
|
{-# LANGUAGE TypeFamilies #-}
|
|
|
|
{-# LANGUAGE DeriveGeneric #-}
|
|
|
|
{-# LANGUAGE TypeOperators #-}
|
2015-05-09 16:05:09 +02:00
|
|
|
{-# LANGUAGE OverloadedStrings #-}
|
2015-09-23 14:58:47 +02:00
|
|
|
{-# OPTIONS_GHC -fno-warn-unused-imports #-}
|
2015-05-10 13:39:18 +02:00
|
|
|
module T9 where
|
2015-05-09 12:27:45 +02:00
|
|
|
|
|
|
|
import Control.Applicative
|
|
|
|
import Control.Monad.IO.Class
|
|
|
|
import Data.Aeson
|
2015-05-09 16:05:09 +02:00
|
|
|
import Data.Text (Text)
|
2015-05-09 12:27:45 +02:00
|
|
|
import GHC.Generics
|
|
|
|
import Network.Wai
|
|
|
|
import Servant
|
|
|
|
import Servant.JQuery
|
2015-05-10 12:20:02 +02:00
|
|
|
import System.Random
|
2015-05-09 12:27:45 +02:00
|
|
|
|
2015-05-09 16:05:09 +02:00
|
|
|
import qualified Data.Text as T
|
|
|
|
import qualified Language.Javascript.JQuery as JQ
|
|
|
|
|
2015-05-09 12:27:45 +02:00
|
|
|
data Point = Point
|
|
|
|
{ x :: Double
|
|
|
|
, y :: Double
|
|
|
|
} deriving Generic
|
|
|
|
|
|
|
|
instance ToJSON Point
|
|
|
|
|
|
|
|
randomPoint :: MonadIO m => m Point
|
2015-05-10 12:20:02 +02:00
|
|
|
randomPoint = liftIO . getStdRandom $ \g ->
|
|
|
|
let (rx, g') = randomR (-1, 1) g
|
|
|
|
(ry, g'') = randomR (-1, 1) g'
|
|
|
|
in (Point rx ry, g'')
|
2015-05-09 12:27:45 +02:00
|
|
|
|
|
|
|
data Search a = Search
|
2015-05-09 16:05:09 +02:00
|
|
|
{ query :: Text
|
2015-05-09 12:27:45 +02:00
|
|
|
, results :: [a]
|
|
|
|
} deriving Generic
|
|
|
|
|
2015-05-09 16:05:09 +02:00
|
|
|
mkSearch :: Text -> [a] -> Search a
|
2015-05-09 12:27:45 +02:00
|
|
|
mkSearch = Search
|
|
|
|
|
|
|
|
instance ToJSON a => ToJSON (Search a)
|
|
|
|
|
|
|
|
data Book = Book
|
2015-05-09 16:05:09 +02:00
|
|
|
{ author :: Text
|
|
|
|
, title :: Text
|
2015-05-09 12:27:45 +02:00
|
|
|
, year :: Int
|
|
|
|
} deriving Generic
|
|
|
|
|
|
|
|
instance ToJSON Book
|
|
|
|
|
2015-05-09 16:05:09 +02:00
|
|
|
book :: Text -> Text -> Int -> Book
|
2015-05-09 12:27:45 +02:00
|
|
|
book = Book
|
|
|
|
|
|
|
|
books :: [Book]
|
|
|
|
books =
|
|
|
|
[ book "Paul Hudak" "The Haskell School of Expression: Learning Functional Programming through Multimedia" 2000
|
|
|
|
, book "Bryan O'Sullivan, Don Stewart, and John Goerzen" "Real World Haskell" 2008
|
|
|
|
, book "Miran Lipovača" "Learn You a Haskell for Great Good!" 2011
|
|
|
|
, book "Graham Hutton" "Programming in Haskell" 2007
|
|
|
|
, book "Simon Marlow" "Parallel and Concurrent Programming in Haskell" 2013
|
|
|
|
, book "Richard Bird" "Introduction to Functional Programming using Haskell" 1998
|
|
|
|
]
|
|
|
|
|
2015-05-09 16:05:09 +02:00
|
|
|
searchBook :: Monad m => Maybe Text -> m (Search Book)
|
2015-05-09 12:27:45 +02:00
|
|
|
searchBook Nothing = return (mkSearch "" books)
|
|
|
|
searchBook (Just q) = return (mkSearch q books')
|
|
|
|
|
2015-05-09 16:05:09 +02:00
|
|
|
where books' = filter (\b -> q' `T.isInfixOf` T.toLower (author b)
|
|
|
|
|| q' `T.isInfixOf` T.toLower (title b)
|
2015-05-09 12:27:45 +02:00
|
|
|
)
|
|
|
|
books
|
2015-05-09 16:05:09 +02:00
|
|
|
q' = T.toLower q
|
2015-05-09 12:27:45 +02:00
|
|
|
|
|
|
|
type API = "point" :> Get '[JSON] Point
|
2015-05-09 16:05:09 +02:00
|
|
|
:<|> "books" :> QueryParam "q" Text :> Get '[JSON] (Search Book)
|
2015-05-09 12:27:45 +02:00
|
|
|
|
|
|
|
type API' = API :<|> Raw
|
|
|
|
|
|
|
|
api :: Proxy API
|
|
|
|
api = Proxy
|
|
|
|
|
|
|
|
api' :: Proxy API'
|
|
|
|
api' = Proxy
|
|
|
|
|
|
|
|
server :: Server API
|
|
|
|
server = randomPoint
|
|
|
|
:<|> searchBook
|
|
|
|
|
|
|
|
server' :: Server API'
|
|
|
|
server' = server
|
2015-05-10 13:39:18 +02:00
|
|
|
:<|> serveDirectory "tutorial/t9"
|
2015-05-09 12:27:45 +02:00
|
|
|
|
|
|
|
apiJS :: String
|
|
|
|
apiJS = jsForAPI api
|
|
|
|
|
|
|
|
writeJSFiles :: IO ()
|
|
|
|
writeJSFiles = do
|
2015-05-10 13:39:18 +02:00
|
|
|
writeFile "tutorial/t9/api.js" apiJS
|
2015-05-09 12:27:45 +02:00
|
|
|
jq <- readFile =<< JQ.file
|
2015-05-10 13:39:18 +02:00
|
|
|
writeFile "tutorial/t9/jq.js" jq
|
2015-05-09 12:27:45 +02:00
|
|
|
|
|
|
|
app :: Application
|
|
|
|
app = serve api' server'
|