Safe Haskell | None |
---|---|
Language | Haskell2010 |
This module contains code for documenting a set of persistent
entity
definitions. All the library provides is a means to render a Markdown
document with table and column documentation and comments. A further
expansion could use the information here to generate PostgreSQL COMMENT
s on
the fields and tables too.
Getting Started
You probably already have a persistent
entity definitions somewhere, and
they probably look like this:
share
[mkPersist
sqlSettings
] [persistUpperCase
| User firstName Text.Text active Bool deriving Show Eq Read Ord |]
The persistUpperCase
QuasiQuoter parses the block of text and returns
a value of type [
. We need to get our hands on that
definition so we can document it. We'll use the EntityDef
]mkEntityDefList
function to expose it:
share
[mkPersist
sqlSettings
,mkEntityDefList
"entityDefs" ] [persistUpperCase
| User firstName Text.Text active Bool deriving Show Eq Read Ord |]
You may want to factor out the quasiquoter into a term and import from
another module. This has an important downside: the ID fields from the
QuasiQuoter are given as Int64
regardless of what they actually are.
It's not possible for the persistent quasiquoter to properly know the
types of the IDs.
Documentating The Schema
Now, we're going to use the document
function to link up the
entityDefs
with a documentation expression (type EntityDoc
).
docs :: [EntityDef
] docs =document
entityDefs $ do pure ()
The EntityDoc
type is a monad, and we'll use do
notation to sequence
multiple entity definitions.
docs :: [EntityDef
] docs =document
entityDefs $ do User--^
do pure ()
The --^
operator mimics the Haddock comment syntax. We use the
constructor of the entity (in this case, User
). On the right, we
provide documentation for the entity. The right hand expression will
have the type FieldDoc
, and we can use do
notation to construct it.
We can use string literals to document the entity itself, with the
OverloadedStrings
extension enabled. The string literals are
concatenated, and used to provide entity-level comments. You'll need to
manage whitespace yourself, though.
docs :: [EntityDef
] docs =document
entityDefs $ do User--^
do "This is user documentation. " "You can have multiple lines, but you need to watch out for spaces. " "The lines will be combined."
We can also document the entity fields. We do this using the #
operator.
docs :: [EntityDef
] docs =document
entityDefs $ do User--^
do "This is user documentation. " "You can have multiple lines, but you need to watch out for spaces. " "The lines will be combined." UserFirstName#
"The user's first name." UserActive#
"Whether or not the user is able to log in."
This attaches the comment to the entity field.
Rendering the Documentation
Finally, we'll use render
and provide a Renderer
to generate
documentation. For an example of what this looks like, check out the
file test/example.md
in the repository (linked from the README).
renderedDocs :: Text renderedDocs =render
markdownTableRenderer
docs
Synopsis
- document :: [EntityDef] -> EntityDoc -> [EntityDef]
- (--^) :: forall a r. (KnowResult a ~ r, Typeable r, RC r) => a -> FieldDoc r -> EntityDoc
- (#) :: FC rec typ => EntityField rec typ -> Text -> FieldDoc rec
- type EntityDoc = EntityDoc' ()
- type FieldDoc s = FieldDoc' s ()
- deriveShowFields :: [UnboundEntityDef] -> Q [Dec]
- data Renderer rendered where
- render :: Renderer rendered -> [EntityDef] -> rendered
- markdownTableRenderer :: Renderer Text
The Documentation DSL
document :: [EntityDef] -> EntityDoc -> [EntityDef] Source #
This function accepts a list of EntityDef
and an EntityDoc
block, and
substitutes the entityComments
and fieldComments
from the
EntityDoc
.
Since: 0.1.0.0
:: forall a r. (KnowResult a ~ r, Typeable r, RC r) | |
=> a | A constructor for the |
-> FieldDoc r | A block that contains documentation for the |
-> EntityDoc |
Define documentation for an entity. The left-hand side takes the
Entity
constructor, and the right hand side takes a FieldDoc
expression that documents the entity and it's fields.
Example
x :: EntityDoc x = do User --^ do "This comment is for the entity User." UserName # "This comment is for a field.""
Since: 0.1.0.0
(#) :: FC rec typ => EntityField rec typ -> Text -> FieldDoc rec Source #
Write documentation for the given EntityField
.
Example
x :: EntityDoc x = do User --^ do "This comment is for the entity User." UserName # "This comment is for a field.""
Since: 0.1.0.0
type EntityDoc = EntityDoc' () Source #
An expression of EntityDoc
is used to document the persistent
schema. To construct an EntityDoc
, you'll use the Entity
constructor
and the (--^)
operator. Everything to the right of the (--^)
operator is a 'FieldDoc rec' for the given entity.
This type is a monad, and you can use do
notation to sequence the
documentation.
doc :: EntityDoc
doc = do
User --^ "Documentation for a User"
Dog --^ "Documentation for a Dog"
Since: 0.1.0.0
type FieldDoc s = FieldDoc' s () Source #
A FieldDoc
expression provides documentation for the given Entity
.
This type is a Monad
and you will want to use do
notation to create
this.
There are two ways to create FieldDoc
lines:
- String literals. These are collected and appended as documentation for the entity itself.
- The
(#)
operator, which accepts anEntityField
and the text documentation for that entity.
Since: 0.1.0.0
deriveShowFields :: [UnboundEntityDef] -> Q [Dec] Source #
Given a list of entity definitions, derives Show
for all their fields.
This is necessary for using this library for internal reasons, unfortunately.
Since: 0.1.0.0
Rendering Documentation
data Renderer rendered where Source #
A renderer for documented entities, abstract in the intermediate representations of entities and fields.
Since: 0.1.0.0
Renderer | |
|
render :: Renderer rendered -> [EntityDef] -> rendered Source #
Given a Renderer
for a list of entity defintiions, render it.
Since: 0.1.0.0
markdownTableRenderer :: Renderer Text Source #
A Renderer
that generates Markdown tables for an entity.
Example
Given entityDefs
like:
entityDefs :: [EntityDef
] entityDefs = [persistUpperCase
| User firstName Text.Text active Bool deriving Show Eq Read Ord |]
and a doc block like:
docs :: [EntityDef] docs = document entityDefs $ do User --^ do "you can use string literals to write documentation for the entity itself. " "The strings will be mappended together, so you'll need to handle " "whitespace yourself." UserFirstName # "The user's first name." UserActive # "Whether or not the user is able to log in." UserId # "You can document the user's ID field."
This will rende the given Markdown output:
#User
you can use string literals to write documentation for the entity itself. The strings will be mappended together, so you'll need to handle whitespace yourself. * Primary ID:id
| Column name | Type | Description | |-|-|-| |id
| integer (64) | You can document the user's ID field. | |firstName
| string | The user's first name. | |active
| boolean | Whether or not the user is able to log in. |
Since: 0.1.0.0