mirror of
https://github.com/qfpl/applied-fp-course.git
synced 2024-11-23 03:44:45 +03:00
Documentation updates. Removed some comments
This commit is contained in:
parent
0dbad01d36
commit
71e9982e08
@ -44,7 +44,9 @@ data Error = Error
|
||||
-- wrong thing with what we meant to be used as text or JSON etc.
|
||||
data ContentType = ContentType
|
||||
|
||||
|
||||
-- The ``ContentType`` constructors don't match what is required for the header
|
||||
-- information, so write a function that will take our ``ContentType`` and
|
||||
-- produce the correct value for the header.
|
||||
renderContentType
|
||||
:: ContentType
|
||||
-> ByteString
|
||||
|
@ -8,3 +8,8 @@ packages. There may also be, depending on your level of interest, some external
|
||||
reading for later as well.
|
||||
|
||||
Start in ``src/FirstApp/Conf.hs``.
|
||||
|
||||
The packages we will use for this are:
|
||||
|
||||
- [Aeson](http://hackage.haskell.org/package/aeson)
|
||||
- [Optparse Applicative](http://hackage.haskell.org/package/optparse-applicative)
|
||||
|
@ -74,9 +74,6 @@ data ContentType
|
||||
= PlainText
|
||||
| JSON
|
||||
|
||||
-- The ContentType description for a header doesn't match our data definition so
|
||||
-- we write a little helper function to pattern match on our ContentType value
|
||||
-- and provide the correct header value.
|
||||
renderContentType
|
||||
:: ContentType
|
||||
-> ByteString
|
||||
|
@ -1,7 +1,8 @@
|
||||
# Level 04
|
||||
|
||||
We're going to add some tests to our application! Types are awesome, tests are
|
||||
pretty good. Types AND tests is pretty much perfect.
|
||||
In this exercise we're going to add some tests to our application. Because types
|
||||
are awesome, and tests are pretty good. But types AND tests is pretty much
|
||||
perfect.
|
||||
|
||||
These tests will not be awe inspiring, this exercise is primarily to introduce
|
||||
you to adding tests to your Haskell application. The setup of the Cabal file is
|
||||
@ -15,9 +16,9 @@ Start in ``tests/Test.hs``.
|
||||
|
||||
#### Aside: Tool Introduction - ghcid
|
||||
|
||||
Additionally we'd like to introduce a command line tool that we find quite
|
||||
useful for Haskell development; [ghcid]. This is a very lightweight tool that
|
||||
works for any project with a functioning cabal setup.
|
||||
Additionally we'd like to introduce a command line tool that you may find useful
|
||||
for Haskell development; [ghcid]. This is a very lightweight tool that works for
|
||||
any project with a functioning cabal setup.
|
||||
|
||||
If you would like to use it, consult its documentation for how to install it,
|
||||
and then in an spare open terminal window, navigate to the root of the Haskell
|
||||
|
@ -94,6 +94,9 @@ executable level04
|
||||
-- Base language which the package is written in.
|
||||
default-language: Haskell2010
|
||||
|
||||
-- This is the declaration of a test-suite for your application. You may have
|
||||
-- multiple test suites in a single application, provided they are named
|
||||
-- differently.
|
||||
test-suite level04-tests
|
||||
default-language: Haskell2010
|
||||
type: exitcode-stdio-1.0
|
||||
|
@ -126,7 +126,7 @@ parseJSONConfigFile fp = do
|
||||
toPartialConf cObj = PartialConf
|
||||
( fromJsonObjWithKey "port" Port cObj )
|
||||
( fromJsonObjWithKey "helloMsg" helloFromStr cObj )
|
||||
-- Use bracket to save ourselves from horrible exceptions.
|
||||
|
||||
readObject
|
||||
:: IO (Maybe Aeson.Object)
|
||||
readObject = bracketOnError
|
||||
|
@ -48,7 +48,7 @@ closeDb =
|
||||
error "closeDb not implemented"
|
||||
|
||||
-- Due to the way our application is designed, we have a slight SQL injection
|
||||
-- risk because we pull the Table name from the Conf. Write a function that
|
||||
-- risk because we pull the `Table` from the `Conf`. Write a function that
|
||||
-- attempts to mitigate that risk a bit, by handling replacement of a place-
|
||||
-- holder value in a given Query. We should be able to write the query and pass
|
||||
-- it through this function and everything is will be taken care of for us.
|
||||
@ -71,16 +71,16 @@ initDb
|
||||
initDb fp tab =
|
||||
error "initDb not implemented"
|
||||
where
|
||||
-- Query has a IsString instance so you can write straight strings like this
|
||||
-- and it will convert them into a Query type, use '?' as place-holders for
|
||||
-- Query has a `IsString` instance so you can write straight strings like this
|
||||
-- and it will convert them into a `Query` type, use '?' as place-holders for
|
||||
-- ORDER DEPENDENT interpolation.
|
||||
createTableQ = withTable tab
|
||||
"CREATE TABLE IF NOT EXISTS $$tablename$$ (id INTEGER PRIMARY KEY, topic TEXT, comment TEXT, time INTEGER)"
|
||||
|
||||
-- Note that we don't store the Comment type in the DB, it is the type we build
|
||||
-- Note that we don't store the `Comment` in the DB, it is the type we build
|
||||
-- to send to the outside world. We will be loading our `DbComment` type from
|
||||
-- the FirstApp.DB.Types module before converting trying to convert it to a
|
||||
-- Comment.
|
||||
-- `Comment`.
|
||||
getComments
|
||||
:: FirstAppDB
|
||||
-> Topic
|
||||
|
@ -17,7 +17,6 @@ module FirstApp.DB.PostgreSQL where
|
||||
|
||||
-- import FirstApp.Types
|
||||
|
||||
-- -- newtype all the things!!
|
||||
-- newtype Table = Table
|
||||
-- { getTableName :: Text }
|
||||
-- deriving Show
|
||||
|
@ -38,12 +38,12 @@ newtype Topic = Topic Text
|
||||
newtype CommentText = CommentText Text
|
||||
deriving (Show, ToJSON)
|
||||
|
||||
-- This is the Comment record that we will be sending to users, it's a simple
|
||||
-- record type, containing an Int, Topic, CommentText, and UTCTime. However
|
||||
-- notice that we've also derived the Generic type class instance as well. This
|
||||
-- saves us some effort when it comes to creating encoding/decoding instances.
|
||||
-- Since our types are all simple types at the end of the day, we're able to let
|
||||
-- GHC do the work.
|
||||
-- This is the `Comment` record that we will be sending to users, it's a simple
|
||||
-- record type, containing an `Int`, `Topic`, `CommentText`, and `UTCTime`.
|
||||
-- However notice that we've also derived the `Generic` type class instance as
|
||||
-- well. This saves us some effort when it comes to creating encoding/decoding
|
||||
-- instances. Since our types are all simple types at the end of the day, we're
|
||||
-- able to let GHC do the work.
|
||||
|
||||
newtype CommentId = CommentId Int
|
||||
deriving (Eq, Show, ToJSON)
|
||||
@ -57,9 +57,9 @@ data Comment = Comment
|
||||
deriving ( Show, Generic )
|
||||
|
||||
instance ToJSON Comment where
|
||||
-- This is one place where we can take advantage of our Generic instance.
|
||||
-- This is one place where we can take advantage of our `Generic` instance.
|
||||
-- Aeson already has the encoding functions written for anything that
|
||||
-- implements the Generic typeclass. So we don't have to write our encoding,
|
||||
-- implements the `Generic` typeclass. So we don't have to write our encoding,
|
||||
-- we ask Aeson to construct it for us.
|
||||
toEncoding = A.genericToEncoding opts
|
||||
where
|
||||
@ -78,9 +78,9 @@ instance ToJSON Comment where
|
||||
-> String
|
||||
modFieldLabel = error "modFieldLabel not implemented"
|
||||
|
||||
-- For safety we take our stored DbComment and try to construct a Comment that
|
||||
-- we would be okay with showing someone. However unlikely it may be, this is a
|
||||
-- nice method for separating out the back and front end of a web app and
|
||||
-- For safety we take our stored `DbComment` and try to construct a `Comment`
|
||||
-- that we would be okay with showing someone. However unlikely it may be, this
|
||||
-- is a nice method for separating out the back and front end of a web app and
|
||||
-- providing greater guarantees about data cleanliness.
|
||||
fromDbComment
|
||||
:: DbComment
|
||||
@ -129,16 +129,13 @@ data Error
|
||||
= UnknownRoute
|
||||
| EmptyCommentText
|
||||
| EmptyTopic
|
||||
-- | DBError SQLiteResponse
|
||||
-- We need another constructor for our DB error types.
|
||||
deriving Show
|
||||
|
||||
data ContentType
|
||||
= PlainText
|
||||
| JSON
|
||||
|
||||
-- The ContentType description for a header doesn't match our data definition so
|
||||
-- we write a little helper function to pattern match on our ContentType value
|
||||
-- and provide the correct header value.
|
||||
renderContentType
|
||||
:: ContentType
|
||||
-> ByteString
|
||||
|
@ -131,6 +131,5 @@ data ContentType
|
||||
renderContentType
|
||||
:: ContentType
|
||||
-> ByteString
|
||||
-- renderContentType = error "renderContentType not implemented"
|
||||
renderContentType PlainText = "text/plain"
|
||||
renderContentType JSON = "application/json"
|
||||
|
Loading…
Reference in New Issue
Block a user