diff --git a/servant-examples/getting-started/GS9.hs b/servant-examples/getting-started/GS9.hs new file mode 100644 index 00000000..3d7a16c6 --- /dev/null +++ b/servant-examples/getting-started/GS9.hs @@ -0,0 +1,101 @@ +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE TypeOperators #-} +module GS9 where + +import Control.Applicative +import Control.Monad.IO.Class +import Data.Aeson +import Data.Char +import Data.List +import GHC.Generics +import qualified Language.Javascript.JQuery as JQ +import Math.Probable +import Network.Wai +import Servant +import Servant.JQuery + +data Point = Point + { x :: Double + , y :: Double + } deriving Generic + +instance ToJSON Point + +randomPoint :: MonadIO m => m Point +randomPoint = liftIO . mwc $ Point <$> d <*> d + + where d = doubleIn (-1, 1) + +data Search a = Search + { query :: String + , results :: [a] + } deriving Generic + +mkSearch :: String -> [a] -> Search a +mkSearch = Search + +instance ToJSON a => ToJSON (Search a) + +data Book = Book + { author :: String + , title :: String + , year :: Int + } deriving Generic + +instance ToJSON Book + +book :: String -> String -> Int -> Book +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 + ] + +searchBook :: Monad m => Maybe String -> m (Search Book) +searchBook Nothing = return (mkSearch "" books) +searchBook (Just q) = return (mkSearch q books') + + where books' = filter (\b -> q' `isInfixOf` map toLower (author b) + || q' `isInfixOf` map toLower (title b) + ) + books + q' = map toLower q + +type API = "point" :> Get '[JSON] Point + :<|> "books" :> QueryParam "q" String :> Get '[JSON] (Search Book) + +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 + :<|> serveDirectory "getting-started/gs9" + +apiJS :: String +apiJS = jsForAPI api + +writeJSFiles :: IO () +writeJSFiles = do + writeFile "getting-started/gs9/api.js" apiJS + jq <- readFile =<< JQ.file + writeFile "getting-started/gs9/jq.js" jq + +app :: Application +app = serve api' server' diff --git a/servant-examples/getting-started/getting-started.hs b/servant-examples/getting-started/getting-started.hs index bf7103d2..d0b90950 100644 --- a/servant-examples/getting-started/getting-started.hs +++ b/servant-examples/getting-started/getting-started.hs @@ -9,24 +9,26 @@ import qualified GS4 import qualified GS5 import qualified GS6 import qualified GS7 +import qualified GS9 -app :: String -> Maybe Application -app n = case n of - "1" -> Just GS1.app - "2" -> Just GS2.app - "3" -> Just GS3.app - "4" -> Just GS4.app - "5" -> Just GS5.app - "6" -> Just GS6.app - "7" -> Just GS7.app - "8" -> Just GS3.app - _ -> Nothing +app :: String -> (Application -> IO ()) -> IO () +app n f = case n of + "1" -> f GS1.app + "2" -> f GS2.app + "3" -> f GS3.app + "4" -> f GS4.app + "5" -> f GS5.app + "6" -> f GS6.app + "7" -> f GS7.app + "8" -> f GS3.app + "9" -> GS9.writeJSFiles >> f GS9.app + _ -> usage main :: IO () main = do args <- getArgs case args of - [n] -> maybe usage (run 8081) (app n) + [n] -> app n (run 8081) _ -> usage usage :: IO () diff --git a/servant-examples/getting-started/gs9/index.html b/servant-examples/getting-started/gs9/index.html new file mode 100644 index 00000000..27d8630c --- /dev/null +++ b/servant-examples/getting-started/gs9/index.html @@ -0,0 +1,26 @@ + + + + + + Getting started - 9 - servant-jquery + + +

Books

+ +
+

Results for ""

+ +
+
+

Approximating π

+

Count: 0

+

Successes: 0

+

+ + + + + + \ No newline at end of file diff --git a/servant-examples/getting-started/gs9/ui.js b/servant-examples/getting-started/gs9/ui.js new file mode 100644 index 00000000..755de45b --- /dev/null +++ b/servant-examples/getting-started/gs9/ui.js @@ -0,0 +1,61 @@ +/* book search */ +function updateResults(data) +{ + console.log(data); + $('#results').html(""); + $('#query').text("\"" + data.query + "\""); + for(var i = 0; i < data.results.length; i++) + { + $('#results').append(renderBook(data.results[i])); + } +} + +function renderBook(book) +{ + var li = '
  • ' + book.title + ', ' + + book.author + ' - ' + book.year + '
  • '; + return li; +} + +function searchBooks() +{ + var q = $('#q').val(); + getbooks(q, updateResults, console.log) +} + +searchBooks(); +$('#q').keyup(function() { + searchBooks(); +}); + +/* approximating pi */ +var count = 0; +var successes = 0; + +function f(data) +{ + var x = data.x, y = data.y; + if(x*x + y*y <= 1) + { + successes++; + } + + count++; + + update('#count', count); + update('#successes', successes); + update('#pi', 4*successes/count); +} + +function update(id, val) +{ + $(id).text(val); +} + +function refresh() +{ + getpoint(f, console.log); +} + +window.setInterval(refresh, 200); + diff --git a/servant-examples/servant-examples.cabal b/servant-examples/servant-examples.cabal index 287e26bd..dab0ab5f 100644 --- a/servant-examples/servant-examples.cabal +++ b/servant-examples/servant-examples.cabal @@ -15,14 +15,17 @@ cabal-version: >=1.10 executable getting-started main-is: getting-started.hs - other-modules: GS1, GS2 + other-modules: GS1, GS2, GS3, GS4, GS5, GS6, GS7, GS8, GS9 build-depends: aeson >= 0.8 , base >= 4.7 , directory , either + , js-jquery , lucid + , probable , servant + , servant-jquery , servant-lucid , servant-server , time