-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | A declarative library for describing dependencies between data -- -- Please see README.md @package graphula @version 2.0.0.4 module Graphula.Internal class MonadGraphulaBackend m where { -- | 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 type family Logging m :: Type -> Constraint; } askGen :: MonadGraphulaBackend m => m (IORef QCGen) logNode :: (MonadGraphulaBackend m, Logging m a) => a -> m () class GHasDependencies nodeTyProxy depsTyProxy node deps genericDependsOn :: GHasDependencies nodeTyProxy depsTyProxy node deps => nodeTyProxy -> depsTyProxy -> node -> deps -> node data KeySourceType -- | Generate keys using the database's DEFAULT strategy SourceDefault :: KeySourceType -- | Generate keys using the Arbitrary instance for the -- Key SourceArbitrary :: KeySourceType -- | Always explicitly pass an external key SourceExternal :: KeySourceType -- | Handle key generation for SourceDefault and -- SourceArbitrary -- -- Ths could be a single-parameter class, but carrying the a -- around lets us give a better error message when node -- is called instead of nodeKeyed. class GenerateKeyInternal (s :: KeySourceType) a where { type family KeyConstraint s a :: Constraint; } generateKey :: (GenerateKeyInternal s a, KeyConstraint s a) => Gen (Maybe (Key a)) -- | 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. class NoConstraint a instance Graphula.Internal.GenerateKeyInternal 'Graphula.Internal.SourceDefault a instance (TypeError ...) => Graphula.Internal.GenerateKeyInternal 'Graphula.Internal.SourceExternal a instance Graphula.Internal.NoConstraint a instance Graphula.Internal.GenerateKeyInternal 'Graphula.Internal.SourceArbitrary a instance (Graphula.Internal.FindMatches nodeTy depsTy node deps GHC.Types.~ fields, Graphula.Internal.GHasDependenciesRecursive (Data.Proxy.Proxy fields) node deps) => Graphula.Internal.GHasDependencies (Data.Proxy.Proxy nodeTy) (Data.Proxy.Proxy depsTy) (Data.Either.Either node Data.Void.Void) (Data.Either.Either deps Data.Void.Void) instance (a GHC.Types.~ dep, Graphula.Internal.GHasDependenciesRecursive (Data.Proxy.Proxy fields) as deps) => Graphula.Internal.GHasDependenciesRecursive (Data.Proxy.Proxy ('Graphula.Internal.Match a : fields)) (a, as) (dep, deps) instance Graphula.Internal.GHasDependenciesRecursive (Data.Proxy.Proxy fields) as deps => Graphula.Internal.GHasDependenciesRecursive (Data.Proxy.Proxy ('Graphula.Internal.NoMatch a : fields)) (a, as) deps instance Graphula.Internal.GHasDependenciesRecursive (Data.Proxy.Proxy '[]) () () instance Graphula.Internal.GHasDependencies (Data.Proxy.Proxy nodeTy) (Data.Proxy.Proxy depsTy) Data.Void.Void (Data.Either.Either () Data.Void.Void) instance (TypeError ...) => Graphula.Internal.GHasDependencies (Data.Proxy.Proxy nodeTy) (Data.Proxy.Proxy depsTy) Data.Void.Void (Data.Either.Either deps rest) instance (TypeError ...) => Graphula.Internal.GHasDependencies (Data.Proxy.Proxy nodeTy) (Data.Proxy.Proxy depsTy) (Data.Either.Either left (Data.Either.Either right rest)) (Data.Either.Either deps Data.Void.Void) instance (TypeError ...) => Graphula.Internal.GHasDependencies (Data.Proxy.Proxy nodeTy) (Data.Proxy.Proxy depsTy) (Data.Either.Either node Data.Void.Void) (Data.Either.Either left (Data.Either.Either right rest)) instance (TypeError ...) => Graphula.Internal.GHasDependencies (Data.Proxy.Proxy nodeTy) (Data.Proxy.Proxy depsTy) (Data.Either.Either left1 (Data.Either.Either right1 rest1)) (Data.Either.Either left2 (Data.Either.Either right2 rest2)) instance (TypeError ...) => Graphula.Internal.GHasDependencies (Data.Proxy.Proxy nodeTy) (Data.Proxy.Proxy depsTy) node Data.Void.Void -- | Graphula tracks its own QCGen for deterministic generation -- with Arbitrary and Gen. generate can be used to -- produce arbitrary values utilizing graphula's generation. module Graphula.Arbitrary -- | Run a generator -- -- This is akin to generate, but utilizing graphula's generation. -- The size passed to the generator is always 30; if you want another -- size then you should explicitly use resize. generate :: (MonadIO m, MonadGraphulaBackend m) => Gen a -> m a -- | 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" }
--
module Graphula
-- | 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.
node :: forall a m. (GraphulaContext m '[a], GenerateKey a) => Dependencies a -> NodeOptions a -> m (Entity a)
-- | 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.
nodeKeyed :: forall a m. GraphulaContext m '[a] => Key a -> Dependencies a -> NodeOptions a -> m (Entity a)
type GraphulaNode m a = (HasDependencies a, Logging m a, PersistEntityBackend a ~ SqlBackend, PersistEntity a, Typeable a, Arbitrary a)
-- | 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" }
--
type family GraphulaContext (m :: Type -> Type) (ts :: [Type]) :: Constraint
-- | 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
--
data NodeOptions a
-- | Modify the node after it's been generated
--
--
-- a node @A () $ edit $ a - a { someField = True }
--
edit :: (a -> a) -> NodeOptions a
-- | Require a node to satisfy the specified predicate
--
-- -- a <- node @A () $ ensure $ (== True) . someField --ensure :: (a -> Bool) -> NodeOptions a class HasDependencies a where { -- | 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 family Dependencies a; -- | 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.
type family KeySource a :: KeySourceType;
type Dependencies _a = ();
type KeySource _a = 'SourceDefault;
}
-- | Assign values from the Dependencies collection to a value.
-- dependsOn must be an idempotent operation.
--
-- Law:
--
-- -- (\x d -> x `dependsOn` d `dependsOn` d) = dependsOn --dependsOn :: HasDependencies a => a -> Dependencies a -> a -- | Assign values from the Dependencies collection to a value. -- dependsOn must be an idempotent operation. -- -- Law: -- --
-- (\x d -> x `dependsOn` d `dependsOn` d) = dependsOn --dependsOn :: (HasDependencies a, HasEot a, HasEot (Dependencies a), GHasDependencies (Proxy a) (Proxy (Dependencies a)) (Eot a) (Eot (Dependencies a))) => a -> Dependencies a -> a data KeySourceType -- | Generate keys using the database's DEFAULT strategy SourceDefault :: KeySourceType -- | Generate keys using the Arbitrary instance for the -- Key SourceArbitrary :: KeySourceType -- | Always explicitly pass an external key SourceExternal :: KeySourceType -- | Abstract over how keys are generated using -- SourceDefault or SourceArbitrary class (GenerateKeyInternal (KeySource a) a, KeyConstraint (KeySource a) a) => GenerateKey a -- | For entities that only have singular Dependencies newtype Only a Only :: a -> Only a [fromOnly] :: Only a -> a only :: a -> Only a type MonadGraphula m = (Monad m, MonadGraphulaBackend m, MonadGraphulaFrontend m, MonadIO m) class MonadGraphulaBackend m where { -- | 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 type family Logging m :: Type -> Constraint; } askGen :: MonadGraphulaBackend m => m (IORef QCGen) logNode :: (MonadGraphulaBackend m, Logging m a) => a -> m () class MonadGraphulaFrontend m insert :: (MonadGraphulaFrontend m, PersistEntityBackend a ~ SqlBackend, PersistEntity a, Monad m) => Maybe (Key a) -> a -> m (Maybe (Entity a)) remove :: (MonadGraphulaFrontend m, PersistEntityBackend a ~ SqlBackend, PersistEntity a, Monad m) => Key a -> m () runGraphulaT :: MonadUnliftIO m => Maybe Int -> (forall b. ReaderT SqlBackend n b -> m b) -> GraphulaT n m a -> m a data GraphulaT n m a -- | An extension of runGraphulaT that logs all nodes to a temporary -- file on Exception and re-throws the Exception. runGraphulaLoggedT :: MonadUnliftIO m => GraphulaLoggedT m a -> m a -- | A variant of runGraphulaLoggedT that accepts a file path to -- logged to instead of utilizing a temp file. runGraphulaLoggedWithFileT :: MonadUnliftIO m => FilePath -> GraphulaLoggedT m a -> m a data GraphulaLoggedT m a -- | 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 --runGraphulaIdempotentT :: MonadUnliftIO m => GraphulaIdempotentT m a -> m a data GraphulaIdempotentT m a -- | 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. class NoConstraint a data GenerationFailure -- | Could not satisfy constraints defined using ensure GenerationFailureMaxAttemptsToConstrain :: TypeRep -> GenerationFailure -- | Could not satisfy database constraints on insert GenerationFailureMaxAttemptsToInsert :: TypeRep -> GenerationFailure instance GHC.Base.Monad m => Control.Monad.Reader.Class.MonadReader (Graphula.Args Database.Persist.Sql.Types.Internal.SqlBackend n m) (Graphula.GraphulaT n m) instance Control.Monad.IO.Class.MonadIO m => Control.Monad.IO.Class.MonadIO (Graphula.GraphulaT n m) instance GHC.Base.Monad m => GHC.Base.Monad (Graphula.GraphulaT n m) instance GHC.Base.Applicative m => GHC.Base.Applicative (Graphula.GraphulaT n m) instance GHC.Base.Functor m => GHC.Base.Functor (Graphula.GraphulaT n m) instance GHC.Base.Monad m => Control.Monad.Reader.Class.MonadReader (GHC.IORef.IORef (m ())) (Graphula.GraphulaIdempotentT m) instance Control.Monad.IO.Class.MonadIO m => Control.Monad.IO.Class.MonadIO (Graphula.GraphulaIdempotentT m) instance GHC.Base.Monad m => GHC.Base.Monad (Graphula.GraphulaIdempotentT m) instance GHC.Base.Applicative m => GHC.Base.Applicative (Graphula.GraphulaIdempotentT m) instance GHC.Base.Functor m => GHC.Base.Functor (Graphula.GraphulaIdempotentT m) instance GHC.Base.Monad m => Control.Monad.Reader.Class.MonadReader (GHC.IORef.IORef (Data.Sequence.Internal.Seq Data.Text.Internal.Text)) (Graphula.GraphulaLoggedT m) instance Control.Monad.IO.Class.MonadIO m => Control.Monad.IO.Class.MonadIO (Graphula.GraphulaLoggedT m) instance GHC.Base.Monad m => GHC.Base.Monad (Graphula.GraphulaLoggedT m) instance GHC.Base.Applicative m => GHC.Base.Applicative (Graphula.GraphulaLoggedT m) instance GHC.Base.Functor m => GHC.Base.Functor (Graphula.GraphulaLoggedT m) instance GHC.Classes.Eq Graphula.GenerationFailure instance GHC.Show.Show Graphula.GenerationFailure instance GHC.Generics.Generic (Graphula.Kendo m a) instance GHC.Generics.Generic (Graphula.NodeOptions a) instance Data.Traversable.Traversable Graphula.Only instance Data.Foldable.Foldable Graphula.Only instance GHC.Base.Functor Graphula.Only instance GHC.Generics.Generic (Graphula.Only a) instance GHC.Classes.Ord a => GHC.Classes.Ord (Graphula.Only a) instance GHC.Show.Show a => GHC.Show.Show (Graphula.Only a) instance GHC.Classes.Eq a => GHC.Classes.Eq (Graphula.Only a) instance GHC.Base.Semigroup (Graphula.NodeOptions a) instance GHC.Base.Monoid (Graphula.NodeOptions a) instance GHC.Base.Monad m => GHC.Base.Semigroup (Graphula.Kendo m a) instance GHC.Base.Monad m => GHC.Base.Monoid (Graphula.Kendo m a) instance GHC.Exception.Type.Exception Graphula.GenerationFailure instance (Graphula.Internal.GenerateKeyInternal (Graphula.KeySource a) a, Graphula.Internal.KeyConstraint (Graphula.KeySource a) a) => Graphula.GenerateKey a instance Control.Monad.Trans.Class.MonadTrans Graphula.GraphulaLoggedT instance (Graphula.Internal.MonadGraphulaBackend m, Control.Monad.IO.Class.MonadIO m) => Graphula.Internal.MonadGraphulaBackend (Graphula.GraphulaLoggedT m) instance (GHC.Base.Monad m, Graphula.MonadGraphulaFrontend m) => Graphula.MonadGraphulaFrontend (Graphula.GraphulaLoggedT m) instance Control.Monad.IO.Unlift.MonadUnliftIO m => Control.Monad.IO.Unlift.MonadUnliftIO (Graphula.GraphulaIdempotentT m) instance Control.Monad.Trans.Class.MonadTrans Graphula.GraphulaIdempotentT instance (Control.Monad.IO.Class.MonadIO m, Graphula.MonadGraphulaFrontend m) => Graphula.MonadGraphulaFrontend (Graphula.GraphulaIdempotentT m) instance Control.Monad.Trans.Class.MonadTrans (Graphula.GraphulaT n) instance Control.Monad.IO.Unlift.MonadUnliftIO m => Control.Monad.IO.Unlift.MonadUnliftIO (Graphula.GraphulaT n m) instance Control.Monad.IO.Class.MonadIO m => Graphula.Internal.MonadGraphulaBackend (Graphula.GraphulaT n m) instance (Control.Monad.IO.Class.MonadIO m, GHC.Base.Applicative n, Control.Monad.IO.Class.MonadIO n) => Graphula.MonadGraphulaFrontend (Graphula.GraphulaT n m) module Graphula.Key onlyKey :: Entity a -> Only (Key a) keys :: EntityKeys a => a -> Keys a type family Keys a instance (TypeError ...) => Graphula.Key.EntityKeys (Database.Persist.Class.PersistEntity.Entity a) instance Graphula.Key.EntityKeys (Graphula.Only (Database.Persist.Class.PersistEntity.Entity a)) instance Graphula.Key.EntityKeys (Database.Persist.Class.PersistEntity.Entity a, Database.Persist.Class.PersistEntity.Entity b) instance Graphula.Key.EntityKeys (Database.Persist.Class.PersistEntity.Entity a, Database.Persist.Class.PersistEntity.Entity b, Database.Persist.Class.PersistEntity.Entity c) instance Graphula.Key.EntityKeys (Database.Persist.Class.PersistEntity.Entity a, Database.Persist.Class.PersistEntity.Entity b, Database.Persist.Class.PersistEntity.Entity c, Database.Persist.Class.PersistEntity.Entity d)