-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Documentation DSL for persistent entities -- -- A convenient DSL that allows you to attach documentation to persistent -- database entities @package persistent-documentation @version 0.1.0.2 module Data.SemiMap -- | A newtype around Map which uses unionWith -- (<>) for the semigroup and monoid instance. newtype SemiMap k v SemiMap :: Map k v -> SemiMap k v [unSemiMap] :: SemiMap k v -> Map k v instance (GHC.Show.Show k, GHC.Show.Show v) => GHC.Show.Show (Data.SemiMap.SemiMap k v) instance (GHC.Classes.Ord k, GHC.Classes.Ord v) => GHC.Classes.Ord (Data.SemiMap.SemiMap k v) instance (GHC.Classes.Eq k, GHC.Classes.Eq v) => GHC.Classes.Eq (Data.SemiMap.SemiMap k v) instance (GHC.Classes.Ord k, GHC.Base.Semigroup v) => GHC.Base.Semigroup (Data.SemiMap.SemiMap k v) instance (GHC.Classes.Ord k, GHC.Base.Semigroup v) => GHC.Base.Monoid (Data.SemiMap.SemiMap k v) module Data.StrMap -- | A StrMap is sort of like a HashMap, but sorts the keys -- on a Text representation. Additionally, it has more useful -- Semigroup and Monoid instances that (<>) -- the values when present. newtype StrMap k a StrMap :: Map (AsStr k) a -> StrMap k a -- | Insert a value into a StrMap. insert :: Show k => k -> a -> StrMap k a -> StrMap k a -- | Lookup a value in the StrMap. lookup :: Show k => k -> StrMap k a -> Maybe a -- | A datatype for representing the keys of entries in a StrMap. -- Contains the original value as well as the Textual -- representation of that value. -- -- The Eq and Ord instances only use the Text value. data AsStr k AsStr :: Text -> k -> AsStr k [asStrText] :: AsStr k -> Text [asStrValue] :: AsStr k -> k -- | Pack a value into an AsStr of that value. asStr :: Show k => k -> AsStr k instance GHC.Show.Show k => GHC.Show.Show (Data.StrMap.AsStr k) instance (GHC.Show.Show k, GHC.Show.Show a) => GHC.Show.Show (Data.StrMap.StrMap k a) instance GHC.Classes.Ord a => GHC.Classes.Ord (Data.StrMap.StrMap k a) instance GHC.Classes.Eq a => GHC.Classes.Eq (Data.StrMap.StrMap k a) instance GHC.Base.Semigroup a => GHC.Base.Semigroup (Data.StrMap.StrMap k a) instance GHC.Base.Semigroup a => GHC.Base.Monoid (Data.StrMap.StrMap k a) instance GHC.Classes.Eq (Data.StrMap.AsStr k) instance GHC.Classes.Ord (Data.StrMap.AsStr k) -- | This module defines the helpers and internal types that are used in -- the documentation DSL. module Database.Persist.Documentation.Internal -- | Given a list of FieldDefs, this associates each FieldDef -- with the additional documentation comment provided in the -- StrMap (SomeField rec) Text for that -- entity, if any is present. -- -- Precondition: The [FieldDef] comes from the -- PersistEntity rec that this is called for. Doing eg: -- --
--   alignFields
--     (entityFields (entityDef (Proxy :: Proxy User)))
--     (strMap :: StrMap (SomeField Order) Text)
--   
-- -- will be extremely weird. alignFields :: forall rec. RC rec => [FieldDef] -> StrMap (SomeField rec) Text -> [FieldDef] -- | Formats the SomeField rec in the keys of the -- Map to be formatted in the same way as the HaskellName -- present in a FieldDef. asHaskellNames :: forall rec. RC rec => StrMap (SomeField rec) Text -> Map Text Text -- | A type for defining documentation for a schema. newtype EntityDoc' a ED :: Writer SchemaDocs a -> EntityDoc' a -- | The SchemaDocs maps a TypeRep of the Entity -- rec that is documented to the SomeDocs for that entity. type SchemaDocs = SemiMap TypeRep SomeDocs -- | A wrapper around EntityDocs that allows them to be stored in a -- list together. Contains the RC constraint alias, which will -- ensure that all necessary constraints for document rendering are -- packaged in. data SomeDocs [SomeDocs] :: RC rec => EntityDocs rec -> SomeDocs -- | Expand this constraint synonym to pack necessary constraints in with -- the EntityDocs type. Used in a few places to ensure that -- constraints are easy to modify in one place. type RC rec = (Typeable rec) -- | EntityDocs contain the documentation comment for the -- Entity rec that is being documented, as well as a map -- of documentation for the fields of that entity. data EntityDocs rec EntityDocs :: Text -> StrMap (SomeField rec) Text -> EntityDocs rec [entityDocumentation] :: EntityDocs rec -> Text [fieldDocumentation] :: EntityDocs rec -> StrMap (SomeField rec) Text -- | 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"
--   
type EntityDoc = EntityDoc' () -- | 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: -- -- type FieldDoc s = FieldDoc' s () -- | Wrap the result type of a EntityField value so it can be stored -- in homogenous containers. data SomeField rec [SomeField] :: FC rec typ => EntityField rec typ -> SomeField rec -- | Expand this constraint synonym to pack necessary constraints for -- packing EntityField values into SomeFields. type FC rec typ = forall x. Show (EntityField rec x) -- | A monad for writing documentation on an entity's fields. Collects the -- documentation into a Writer. newtype FieldDoc' rec a FD :: Writer (EntityDocs rec) a -> FieldDoc' rec a single :: FC rec typ => EntityField rec typ -> Text -> StrMap (SomeField rec) Text type family KnowResult a lowercaseFirstChar :: Text -> Text -- | 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.""
--   
(--^) :: forall a r. (KnowResult a ~ r, Typeable r, RC r) => a -> FieldDoc r -> EntityDoc -- | 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.""
--   
(#) :: FC rec typ => EntityField rec typ -> Text -> FieldDoc rec instance Control.Monad.Writer.Class.MonadWriter Database.Persist.Documentation.Internal.SchemaDocs Database.Persist.Documentation.Internal.EntityDoc' instance GHC.Base.Monad Database.Persist.Documentation.Internal.EntityDoc' instance GHC.Base.Applicative Database.Persist.Documentation.Internal.EntityDoc' instance GHC.Base.Functor Database.Persist.Documentation.Internal.EntityDoc' instance Control.Monad.Writer.Class.MonadWriter (Database.Persist.Documentation.Internal.EntityDocs rec) (Database.Persist.Documentation.Internal.FieldDoc' rec) instance GHC.Base.Monad (Database.Persist.Documentation.Internal.FieldDoc' rec) instance GHC.Base.Applicative (Database.Persist.Documentation.Internal.FieldDoc' rec) instance GHC.Base.Functor (Database.Persist.Documentation.Internal.FieldDoc' rec) instance (a GHC.Types.~ ()) => Data.String.IsString (Database.Persist.Documentation.Internal.FieldDoc' s a) instance GHC.Base.Semigroup Database.Persist.Documentation.Internal.SomeDocs instance GHC.Base.Semigroup (Database.Persist.Documentation.Internal.EntityDocs rec) instance GHC.Base.Monoid (Database.Persist.Documentation.Internal.EntityDocs rec) instance (forall typ. GHC.Show.Show (Database.Persist.Class.PersistEntity.EntityField rec typ)) => GHC.Show.Show (Database.Persist.Documentation.Internal.SomeField rec) -- | 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 COMMENTs 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 [EntityDef]. We need to get -- our hands on that definition so we can document it. We'll use the -- 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
--   
module Database.Persist.Documentation -- | This function accepts a list of EntityDef and an -- EntityDoc block, and substitutes the entityComments and -- fieldComments from the EntityDoc. document :: [EntityDef] -> EntityDoc -> [EntityDef] -- | 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.""
--   
(--^) :: forall a r. (KnowResult a ~ r, Typeable r, RC r) => a -> FieldDoc r -> EntityDoc -- | 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.""
--   
(#) :: FC rec typ => EntityField rec typ -> Text -> FieldDoc rec -- | 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"
--   
type EntityDoc = EntityDoc' () -- | 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: -- -- type FieldDoc s = FieldDoc' s () -- | Given a list of entity definitions, derives Show for all their -- fields. This is necessary for using this library for internal reasons, -- unfortunately. deriveShowFields :: [EntityDef] -> Q [Dec] -- | A renderer for documented entities, abstract in the intermediate -- representations of entities and fields. data Renderer rendered [Renderer] :: {renderField :: FieldDef -> Maybe Text -> renderedField " Render a field definition as some intermediate structure", renderFields :: [renderedField] -> renderedFields " Fold a collection of rendered fields", renderEntity :: EntityDef -> Maybe Text -> renderedFields -> renderedEntity " Attach some entity-level metadata to a rendered collection of fields", renderEntities :: [renderedEntity] -> rendered " Finally, fold a collection of rendered entities"} -> Renderer rendered -- | Given a Renderer for a list of entity defintiions, render it. render :: Renderer rendered -> [EntityDef] -> rendered -- | 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. |
--   
markdownTableRenderer :: Renderer Text