graphula-2.0.0.3: A declarative library for describing dependencies between data
Safe HaskellNone
LanguageHaskell2010

Graphula

Description

Graphula is a compact interface for generating data and linking its dependencies. You can use this interface to generate fixtures for automated testing.

The interface is extensible and supports pluggable front-ends.

runGraphIdentity . runGraphulaT $ do
  -- Compose dependencies at the value level
  Identity vet <- node Veterinarian () mempty
  Identity owner <- node Owner (only vet) mempty
  -- TypeApplications is not necessary, but recommended for clarity.
  Identity dog node @Dog (owner, vet) $ edit $ d - d { name = "fido" }
Synopsis

Graph Declaration

node :: forall a m. (GraphulaContext m '[a], GenerateKey a) => Dependencies a -> NodeOptions a -> m (Entity a) Source #

Generate a value with data dependencies. This leverages HasDependencies to insert the specified data in the generated value. All dependency data is inserted after any editing operations.

node @Dog (ownerId, veterinarianId) mempty
node @Dog (ownerId, veterinarianId) $ edit $ \dog ->
  dog {name = "fido"}

A value that has an externally managed key must use nodeKeyed instead.

nodeKeyed :: forall a m. GraphulaContext m '[a] => Key a -> Dependencies a -> NodeOptions a -> m (Entity a) Source #

Generate a value with data dependencies given an externally managed key. This leverages HasDependencies to insert the specified data in the generated value. All dependency data is inserted after any editing operations.

someKey <- generateKey
node @Cat someKey (ownerId, veterinarianId) mempty
anotherKey <- generateKey
node @Cat anotherKey (ownerId, veterinarianId) $ edit $ \cat ->
  cat {name = "milo"}

A value that has an automatically managed key may use node instead.

type family GraphulaContext (m :: Type -> Type) (ts :: [Type]) :: Constraint where ... Source #

A constraint over lists of nodes for MonadGraphula, and GraphulaNode.

Helpful for defining utility functions over many nodes.

mkABC :: (GraphulaContext m '[A, B, C]) => m (Node m C)
mkABC = do
  a <- node A () mempty
  b <- node B (only a) mempty
  node @C (a, b) $ edit $ n ->
    n { cc = "spanish" }

Equations

GraphulaContext m '[] = MonadGraphula m 
GraphulaContext m (t ': ts) = (GraphulaNode m t, GraphulaContext m ts) 

Node options

data NodeOptions a Source #

Options for generating an individual node

NodeOptions can be created and combined with the Monoidal operations (<>) and mempty.

a1 <- node A () mempty
a2 <- node A () $ edit $ a -> a { someField = True }
a3 <- node @A () $ ensure $ (== True) . someField

Instances

Instances details
Generic (NodeOptions a) Source # 
Instance details

Defined in Graphula

Associated Types

type Rep (NodeOptions a) :: Type -> Type #

Methods

from :: NodeOptions a -> Rep (NodeOptions a) x #

to :: Rep (NodeOptions a) x -> NodeOptions a #

Semigroup (NodeOptions a) Source # 
Instance details

Defined in Graphula

Monoid (NodeOptions a) Source # 
Instance details

Defined in Graphula

type Rep (NodeOptions a) Source # 
Instance details

Defined in Graphula

type Rep (NodeOptions a)

edit :: (a -> a) -> NodeOptions a Source #

Modify the node after it's been generated

a node @A () $ edit $ a - a { someField = True }

ensure :: (a -> Bool) -> NodeOptions a Source #

Require a node to satisfy the specified predicate

a <- node @A () $ ensure $ (== True) . someField

Declaring Dependencies and key source

class HasDependencies a where Source #

Minimal complete definition

Nothing

Associated Types

type Dependencies a Source #

A data type that contains values to be injected into a via dependsOn. The default generic implementation of dependsOn supports tuples as Dependencies. Data types with a single dependency should use Only as a 1-tuple.

note: The contents of a tuple must be ordered as they appear in the definition of a.

type Dependencies _a = ()

type KeySource a :: KeySourceType Source #

Specify the method for resolving a node's key

This can be

'SourceDefault   -- automatically generate keys from the database
'SourceArbitrary -- automatically generate keys using Arbitrary
'SourceExternal  -- explicitly pass a key using nodeKeyed

Most types will use SourceDefault or SourceArbitrary. Only use SourceExternal if the key for a value is always defined externally.

Methods

dependsOn :: a -> Dependencies a -> a Source #

Assign values from the Dependencies collection to a value. dependsOn must be an idempotent operation.

Law:

(\x d -> x `dependsOn` d `dependsOn` d) = dependsOn

data KeySourceType Source #

Constructors

SourceDefault

Generate keys using the database's DEFAULT strategy

SourceArbitrary

Generate keys using the Arbitrary instance for the Key

SourceExternal

Always explicitly pass an external key

Abstract over how keys are generated using SourceDefault or

class (GenerateKeyInternal (KeySource a) a, KeyConstraint (KeySource a) a) => GenerateKey a Source #

Abstract over how keys are generated using SourceDefault or SourceArbitrary

Instances

Instances details
(GenerateKeyInternal (KeySource a) a, KeyConstraint (KeySource a) a) => GenerateKey a Source # 
Instance details

Defined in Graphula

Singular Dependencies

newtype Only a Source #

For entities that only have singular Dependencies

Constructors

Only 

Fields

Instances

Instances details
Functor Only Source # 
Instance details

Defined in Graphula

Methods

fmap :: (a -> b) -> Only a -> Only b #

(<$) :: a -> Only b -> Only a #

Foldable Only Source # 
Instance details

Defined in Graphula

Methods

fold :: Monoid m => Only m -> m #

foldMap :: Monoid m => (a -> m) -> Only a -> m #

foldMap' :: Monoid m => (a -> m) -> Only a -> m #

foldr :: (a -> b -> b) -> b -> Only a -> b #

foldr' :: (a -> b -> b) -> b -> Only a -> b #

foldl :: (b -> a -> b) -> b -> Only a -> b #

foldl' :: (b -> a -> b) -> b -> Only a -> b #

foldr1 :: (a -> a -> a) -> Only a -> a #

foldl1 :: (a -> a -> a) -> Only a -> a #

toList :: Only a -> [a] #

null :: Only a -> Bool #

length :: Only a -> Int #

elem :: Eq a => a -> Only a -> Bool #

maximum :: Ord a => Only a -> a #

minimum :: Ord a => Only a -> a #

sum :: Num a => Only a -> a #

product :: Num a => Only a -> a #

Traversable Only Source # 
Instance details

Defined in Graphula

Methods

traverse :: Applicative f => (a -> f b) -> Only a -> f (Only b) #

sequenceA :: Applicative f => Only (f a) -> f (Only a) #

mapM :: Monad m => (a -> m b) -> Only a -> m (Only b) #

sequence :: Monad m => Only (m a) -> m (Only a) #

Eq a => Eq (Only a) Source # 
Instance details

Defined in Graphula

Methods

(==) :: Only a -> Only a -> Bool #

(/=) :: Only a -> Only a -> Bool #

Ord a => Ord (Only a) Source # 
Instance details

Defined in Graphula

Methods

compare :: Only a -> Only a -> Ordering #

(<) :: Only a -> Only a -> Bool #

(<=) :: Only a -> Only a -> Bool #

(>) :: Only a -> Only a -> Bool #

(>=) :: Only a -> Only a -> Bool #

max :: Only a -> Only a -> Only a #

min :: Only a -> Only a -> Only a #

Show a => Show (Only a) Source # 
Instance details

Defined in Graphula

Methods

showsPrec :: Int -> Only a -> ShowS #

show :: Only a -> String #

showList :: [Only a] -> ShowS #

Generic (Only a) Source # 
Instance details

Defined in Graphula

Associated Types

type Rep (Only a) :: Type -> Type #

Methods

from :: Only a -> Rep (Only a) x #

to :: Rep (Only a) x -> Only a #

type Rep (Only a) Source # 
Instance details

Defined in Graphula

type Rep (Only a) = D1 ('MetaData "Only" "Graphula" "graphula-2.0.0.3-D6l6jV46Rn7yPAzqW9uDj" 'True) (C1 ('MetaCons "Only" 'PrefixI 'True) (S1 ('MetaSel ('Just "fromOnly") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 a)))
type Keys (Only (Entity a)) Source # 
Instance details

Defined in Graphula.Key

type Keys (Only (Entity a)) = Only (Key a)

only :: a -> Only a Source #

The Graph Monad

Type Classes

class MonadGraphulaBackend m where Source #

Associated Types

type Logging m :: Type -> Constraint Source #

A constraint provided to log details of the graph to some form of persistence. This is used by runGraphulaLogged to store graph nodes as Shown Text values

Methods

askGen :: m (IORef QCGen) Source #

logNode :: Logging m a => a -> m () Source #

Instances

Instances details
(MonadGraphulaBackend m, MonadIO m) => MonadGraphulaBackend (GraphulaLoggedT m) Source # 
Instance details

Defined in Graphula

Associated Types

type Logging (GraphulaLoggedT m) :: Type -> Constraint Source #

MonadIO m => MonadGraphulaBackend (GraphulaT n m) Source # 
Instance details

Defined in Graphula

Associated Types

type Logging (GraphulaT n m) :: Type -> Constraint Source #

Methods

askGen :: GraphulaT n m (IORef QCGen) Source #

logNode :: Logging (GraphulaT n m) a => a -> GraphulaT n m () Source #

class MonadGraphulaFrontend m where Source #

Backends

runGraphulaT Source #

Arguments

:: MonadUnliftIO m 
=> Maybe Int

Optional seed

-> (forall b. ReaderT SqlBackend n b -> m b)

Database runner

-> GraphulaT n m a 
-> m a 

data GraphulaT n m a Source #

Instances

Instances details
MonadTrans (GraphulaT n) Source # 
Instance details

Defined in Graphula

Methods

lift :: Monad m => m a -> GraphulaT n m a #

Monad m => Monad (GraphulaT n m) Source # 
Instance details

Defined in Graphula

Methods

(>>=) :: GraphulaT n m a -> (a -> GraphulaT n m b) -> GraphulaT n m b #

(>>) :: GraphulaT n m a -> GraphulaT n m b -> GraphulaT n m b #

return :: a -> GraphulaT n m a #

Functor m => Functor (GraphulaT n m) Source # 
Instance details

Defined in Graphula

Methods

fmap :: (a -> b) -> GraphulaT n m a -> GraphulaT n m b #

(<$) :: a -> GraphulaT n m b -> GraphulaT n m a #

Applicative m => Applicative (GraphulaT n m) Source # 
Instance details

Defined in Graphula

Methods

pure :: a -> GraphulaT n m a #

(<*>) :: GraphulaT n m (a -> b) -> GraphulaT n m a -> GraphulaT n m b #

liftA2 :: (a -> b -> c) -> GraphulaT n m a -> GraphulaT n m b -> GraphulaT n m c #

(*>) :: GraphulaT n m a -> GraphulaT n m b -> GraphulaT n m b #

(<*) :: GraphulaT n m a -> GraphulaT n m b -> GraphulaT n m a #

MonadIO m => MonadIO (GraphulaT n m) Source # 
Instance details

Defined in Graphula

Methods

liftIO :: IO a -> GraphulaT n m a #

MonadUnliftIO m => MonadUnliftIO (GraphulaT n m) Source # 
Instance details

Defined in Graphula

Methods

withRunInIO :: ((forall a. GraphulaT n m a -> IO a) -> IO b) -> GraphulaT n m b #

MonadIO m => MonadGraphulaBackend (GraphulaT n m) Source # 
Instance details

Defined in Graphula

Associated Types

type Logging (GraphulaT n m) :: Type -> Constraint Source #

Methods

askGen :: GraphulaT n m (IORef QCGen) Source #

logNode :: Logging (GraphulaT n m) a => a -> GraphulaT n m () Source #

(MonadIO m, Applicative n, MonadIO n) => MonadGraphulaFrontend (GraphulaT n m) Source # 
Instance details

Defined in Graphula

type Logging (GraphulaT n m) Source # 
Instance details

Defined in Graphula

runGraphulaLoggedT :: MonadUnliftIO m => GraphulaLoggedT m a -> m a Source #

An extension of runGraphulaT that logs all nodes to a temporary file on Exception and re-throws the Exception.

runGraphulaLoggedWithFileT :: MonadUnliftIO m => FilePath -> GraphulaLoggedT m a -> m a Source #

A variant of runGraphulaLoggedT that accepts a file path to logged to instead of utilizing a temp file.

data GraphulaLoggedT m a Source #

Instances

Instances details
MonadTrans GraphulaLoggedT Source # 
Instance details

Defined in Graphula

Methods

lift :: Monad m => m a -> GraphulaLoggedT m a #

Monad m => Monad (GraphulaLoggedT m) Source # 
Instance details

Defined in Graphula

Functor m => Functor (GraphulaLoggedT m) Source # 
Instance details

Defined in Graphula

Methods

fmap :: (a -> b) -> GraphulaLoggedT m a -> GraphulaLoggedT m b #

(<$) :: a -> GraphulaLoggedT m b -> GraphulaLoggedT m a #

Applicative m => Applicative (GraphulaLoggedT m) Source # 
Instance details

Defined in Graphula

MonadIO m => MonadIO (GraphulaLoggedT m) Source # 
Instance details

Defined in Graphula

Methods

liftIO :: IO a -> GraphulaLoggedT m a #

(MonadGraphulaBackend m, MonadIO m) => MonadGraphulaBackend (GraphulaLoggedT m) Source # 
Instance details

Defined in Graphula

Associated Types

type Logging (GraphulaLoggedT m) :: Type -> Constraint Source #

(Monad m, MonadGraphulaFrontend m) => MonadGraphulaFrontend (GraphulaLoggedT m) Source # 
Instance details

Defined in Graphula

Monad m => MonadReader (IORef (Seq Text)) (GraphulaLoggedT m) Source # 
Instance details

Defined in Graphula

type Logging (GraphulaLoggedT m) Source # 
Instance details

Defined in Graphula

Frontends

runGraphulaIdempotentT :: MonadUnliftIO m => GraphulaIdempotentT m a -> m a Source #

A wrapper around a graphula frontend that produces finalizers to remove graph nodes on error or completion. An idempotent graph produces no data outside of its own closure.

runGraphIdentity . runGraphulaIdempotentT . runGraphulaT $ do
  node @PancakeBreakfast () mempty

data GraphulaIdempotentT m a Source #

Instances

Instances details
MonadTrans GraphulaIdempotentT Source # 
Instance details

Defined in Graphula

Methods

lift :: Monad m => m a -> GraphulaIdempotentT m a #

Monad m => Monad (GraphulaIdempotentT m) Source # 
Instance details

Defined in Graphula

Functor m => Functor (GraphulaIdempotentT m) Source # 
Instance details

Defined in Graphula

Methods

fmap :: (a -> b) -> GraphulaIdempotentT m a -> GraphulaIdempotentT m b #

(<$) :: a -> GraphulaIdempotentT m b -> GraphulaIdempotentT m a #

Applicative m => Applicative (GraphulaIdempotentT m) Source # 
Instance details

Defined in Graphula

MonadIO m => MonadIO (GraphulaIdempotentT m) Source # 
Instance details

Defined in Graphula

Methods

liftIO :: IO a -> GraphulaIdempotentT m a #

MonadUnliftIO m => MonadUnliftIO (GraphulaIdempotentT m) Source # 
Instance details

Defined in Graphula

Methods

withRunInIO :: ((forall a. GraphulaIdempotentT m a -> IO a) -> IO b) -> GraphulaIdempotentT m b #

(MonadIO m, MonadGraphulaFrontend m) => MonadGraphulaFrontend (GraphulaIdempotentT m) Source # 
Instance details

Defined in Graphula

Monad m => MonadReader (IORef (m ())) (GraphulaIdempotentT m) Source # 
Instance details

Defined in Graphula

Methods

ask :: GraphulaIdempotentT m (IORef (m ())) #

local :: (IORef (m ()) -> IORef (m ())) -> GraphulaIdempotentT m a -> GraphulaIdempotentT m a #

reader :: (IORef (m ()) -> a) -> GraphulaIdempotentT m a #

Extras

class NoConstraint a Source #

Graphula accepts constraints for various uses. Frontends do not always utilize these constraints. NoConstraint is a universal class that all types inhabit. It has no behavior and no additional constraints.

Instances

Instances details
NoConstraint a Source # 
Instance details

Defined in Graphula.Internal

Exceptions