HORIZON HASKELLDocslts/ghc-9.10.x248f8f02026-10-05Search names, modules, packages, or :: a typeCtrl K

GHC 9.10.3 · lts/ghc-9.10.x · 248f8f0 · 2026-10-05

Modulepersistent-test-2.13.1.3Haskell2010

Init

This will hopefully be the only module with CPP in it.

  • 136 types
  • 48 classes
  • 348 values
classclass (PersistField (Key record), ToJSON (Key record), FromJSON (Key record), Show (Key record), Read (Key record), Eq (Key record), Ord (Key record)) => PersistEntity record where
#

Persistent serialized Haskell records to the database. A Database Entity (A row in SQL, a document in MongoDB, etc) corresponds to a Key plus a Haskell record.

For every Haskell record type stored in the database there is a corresponding PersistEntity instance. An instance of PersistEntity contains meta-data for the record. PersistEntity also helps abstract over different record types. That way the same query interface can return a PersistEntity, with each query returning different types of Haskell records.

Some advanced type system capabilities are used to make this process type-safe. Persistent users usually don't need to understand the class associated data and functions.

Associated types

  • type family PersistEntityBackend record

    Persistent allows multiple different backends (databases).

  • data family Key record

    By default, a backend will automatically generate the key Instead you can specify a Primary key made up of unique values.

  • data family EntityField record :: Type -> Type

    An EntityField is parameterised by the Haskell record it belongs to and the additional type of that field.

    As of persistent-2.11.0.0, it's possible to use the OverloadedLabels language extension to refer to EntityField values polymorphically. See the documentation on SymbolToField for more information.

  • data family Unique record

    Unique keys besides the Key.

Methods

Instances122PersistEntity, …
classclass (Show (BackendKey backend), Read (BackendKey backend), Eq (BackendKey backend), Ord (BackendKey backend), PersistStoreRead backend, PersistField (BackendKey backend), ToJSON (BackendKey backend), FromJSON (BackendKey backend)) => PersistStoreWrite backend where
#

Methods

  • insert :: (MonadIO m, PersistRecordBackend record backend, SafeToInsert record) => record -> ReaderT backend m (Key record)

    Create a new record in the database, returning an automatically created key (in SQL an auto-increment id).

    Example usage

    Using schema-1 and dataset-1, let's insert a new user John.

    insertJohn :: MonadIO m => ReaderT SqlBackend m (Key User)
    insertJohn = insert $ User "John" 30
    johnId <- insertJohn

    The above query when applied on dataset-1, will produce this:

    +-----+------+-----+
    |id   |name  |age  |
    +-----+------+-----+
    |1    |SPJ   |40   |
    +-----+------+-----+
    |2    |Simon |41   |
    +-----+------+-----+
    |3    |John  |30   |
    +-----+------+-----+
  • insert_ :: (MonadIO m, PersistRecordBackend record backend, SafeToInsert record) => record -> ReaderT backend m ()

    Same as insert, but doesn't return a Key.

    Example usage

    with schema-1 and dataset-1,

    insertJohn :: MonadIO m => ReaderT SqlBackend m (Key User)
    insertJohn = insert_ $ User "John" 30

    The above query when applied on dataset-1, will produce this:

    +-----+------+-----+
    |id   |name  |age  |
    +-----+------+-----+
    |1    |SPJ   |40   |
    +-----+------+-----+
    |2    |Simon |41   |
    +-----+------+-----+
    |3    |John  |30   |
    +-----+------+-----+
  • insertMany :: (MonadIO m, PersistRecordBackend record backend, SafeToInsert record) => [record] -> ReaderT backend m [Key record]

    Create multiple records in the database and return their Keys.

    If you don't need the inserted Keys, use insertMany_.

    The MongoDB and PostgreSQL backends insert all records and retrieve their keys in one database query.

    The SQLite and MySQL backends use the slow, default implementation of mapM insert.

    Example usage

    with schema-1 and dataset-1,

    insertUsers :: MonadIO m => ReaderT SqlBackend m [Key User]
    insertUsers = insertMany [User "John" 30, User "Nick" 32, User "Jane" 20]
    userIds <- insertUsers

    The above query when applied on dataset-1, will produce this:

    +-----+------+-----+
    |id   |name  |age  |
    +-----+------+-----+
    |1    |SPJ   |40   |
    +-----+------+-----+
    |2    |Simon |41   |
    +-----+------+-----+
    |3    |John  |30   |
    +-----+------+-----+
    |4    |Nick  |32   |
    +-----+------+-----+
    |5    |Jane  |20   |
    +-----+------+-----+
  • insertMany_ :: (MonadIO m, PersistRecordBackend record backend, SafeToInsert record) => [record] -> ReaderT backend m ()

    Same as insertMany, but doesn't return any Keys.

    The MongoDB, PostgreSQL, SQLite and MySQL backends insert all records in one database query.

    Example usage

    With schema-1 and dataset-1,

    insertUsers_ :: MonadIO m => ReaderT SqlBackend m ()
    insertUsers_ = insertMany_ [User "John" 30, User "Nick" 32, User "Jane" 20]

    The above query when applied on dataset-1, will produce this:

    +-----+------+-----+
    |id   |name  |age  |
    +-----+------+-----+
    |1    |SPJ   |40   |
    +-----+------+-----+
    |2    |Simon |41   |
    +-----+------+-----+
    |3    |John  |30   |
    +-----+------+-----+
    |4    |Nick  |32   |
    +-----+------+-----+
    |5    |Jane  |20   |
    +-----+------+-----+
  • insertEntityMany :: (MonadIO m, PersistRecordBackend record backend) => [Entity record] -> ReaderT backend m ()

    Same as insertMany_, but takes an Entity instead of just a record.

    Useful when migrating data from one entity to another and want to preserve ids.

    The MongoDB, PostgreSQL, SQLite and MySQL backends insert all records in one database query.

    Example usage

    With schema-1 and dataset-1,

    insertUserEntityMany :: MonadIO m => ReaderT SqlBackend m ()
    insertUserEntityMany = insertEntityMany [SnakeEntity, EvaEntity]

    The above query when applied on dataset-1, will produce this:

    +-----+------+-----+
    |id   |name  |age  |
    +-----+------+-----+
    |1    |SPJ   |40   |
    +-----+------+-----+
    |2    |Simon |41   |
    +-----+------+-----+
    |3    |Snake |38   |
    +-----+------+-----+
    |4    |Eva   |38   |
    +-----+------+-----+
  • insertKey :: (MonadIO m, PersistRecordBackend record backend) => Key record -> record -> ReaderT backend m ()

    Create a new record in the database using the given key.

    Example usage

    With schema-1 and dataset-1,

    insertAliceKey :: MonadIO m => Key User -> ReaderT SqlBackend m ()
    insertAliceKey key = insertKey key $ User "Alice" 20
    insertAliceKey $ UserKey {unUserKey = SqlBackendKey {unSqlBackendKey = 3}}

    The above query when applied on dataset-1, will produce this:

    +-----+------+-----+
    |id   |name  |age  |
    +-----+------+-----+
    |1    |SPJ   |40   |
    +-----+------+-----+
    |2    |Simon |41   |
    +-----+------+-----+
    |3    |Alice |20   |
    +-----+------+-----+
  • repsert :: (MonadIO m, PersistRecordBackend record backend) => Key record -> record -> ReaderT backend m ()

    Put the record in the database with the given key. Unlike replace, if a record with the given key does not exist then a new record will be inserted.

    Example usage

    We try to explain upsertBy using schema-1 and dataset-1.

    First, we insert Philip to dataset-1.

    insertPhilip :: MonadIO m => ReaderT SqlBackend m (Key User)
    insertPhilip = insert $ User "Philip" 42
    philipId <- insertPhilip

    This query will produce:

    +-----+------+-----+
    |id   |name  |age  |
    +-----+------+-----+
    |1    |SPJ   |40   |
    +-----+------+-----+
    |2    |Simon |41   |
    +-----+------+-----+
    |3    |Philip|42   |
    +-----+------+-----+
    repsertHaskell :: MonadIO m => Key record -> ReaderT SqlBackend m ()
    repsertHaskell id = repsert id $ User "Haskell" 81
    repsertHaskell philipId

    This query will replace Philip's record with Haskell's one:

    +-----+-----------------+--------+
    |id   |name             |age     |
    +-----+-----------------+--------+
    |1    |SPJ              |40      |
    +-----+-----------------+--------+
    |2    |Simon            |41      |
    +-----+-----------------+--------+
    |3    |Philip -> Haskell|42 -> 81|
    +-----+-----------------+--------+

    repsert inserts the given record if the key doesn't exist.

    repsertXToUnknown :: MonadIO m => ReaderT SqlBackend m ()
    repsertXToUnknown = repsert unknownId $ User "X" 999

    For example, applying the above query to dataset-1 will produce this:

    +-----+------+-----+
    |id   |name  |age  |
    +-----+------+-----+
    |1    |SPJ   |40   |
    +-----+------+-----+
    |2    |Simon |41   |
    +-----+------+-----+
    |3    |X     |999  |
    +-----+------+-----+
  • repsertMany :: (MonadIO m, PersistRecordBackend record backend) => [(Key record, record)] -> ReaderT backend m ()

    Put many entities into the database.

    Batch version of repsert for SQL backends.

    Useful when migrating data from one entity to another and want to preserve ids.

    Example usage

    With schema-1 and dataset-1,

    repsertManyUsers :: MonadIO m =>ReaderT SqlBackend m ()
    repsertManyusers = repsertMany [(simonId, User "Philip" 20), (unknownId999, User "Mr. X" 999)]

    The above query when applied on dataset-1, will produce this:

    +-----+----------------+---------+
    |id   |name            |age      |
    +-----+----------------+---------+
    |1    |SPJ             |40       |
    +-----+----------------+---------+
    |2    |Simon -> Philip |41 -> 20 |
    +-----+----------------+---------+
    |999  |Mr. X           |999      |
    +-----+----------------+---------+
  • replace :: (MonadIO m, PersistRecordBackend record backend) => Key record -> record -> ReaderT backend m ()

    Replace the record in the database with the given key. Note that the result is undefined if such record does not exist, so you must use insertKey or repsert in these cases.

    Example usage

    With schema-1 schama-1 and dataset-1,

    replaceSpj :: MonadIO m => User -> ReaderT SqlBackend m ()
    replaceSpj record = replace spjId record

    The above query when applied on dataset-1, will produce this:

    +-----+------+-----+
    |id   |name  |age  |
    +-----+------+-----+
    |1    |Mike  |45   |
    +-----+------+-----+
    |2    |Simon |41   |
    +-----+------+-----+
  • delete :: (MonadIO m, PersistRecordBackend record backend) => Key record -> ReaderT backend m ()

    Delete a specific record by identifier. Does nothing if record does not exist.

    Example usage

    With schema-1 and dataset-1,

    deleteSpj :: MonadIO m => ReaderT SqlBackend m ()
    deleteSpj = delete spjId

    The above query when applied on dataset-1, will produce this:

    +-----+------+-----+
    |id   |name  |age  |
    +-----+------+-----+
    |2    |Simon |41   |
    +-----+------+-----+
  • update :: (MonadIO m, PersistRecordBackend record backend) => Key record -> [Update record] -> ReaderT backend m ()

    Update individual fields on a specific record.

    Example usage

    With schema-1 and dataset-1,

    updateSpj :: MonadIO m => [Update User] -> ReaderT SqlBackend m ()
    updateSpj updates = update spjId updates
    updateSpj [UserAge +=. 100]

    The above query when applied on dataset-1, will produce this:

    +-----+------+-----+
    |id   |name  |age  |
    +-----+------+-----+
    |1    |SPJ   |140  |
    +-----+------+-----+
    |2    |Simon |41   |
    +-----+------+-----+
  • updateGet :: (MonadIO m, PersistRecordBackend record backend) => Key record -> [Update record] -> ReaderT backend m record

    Update individual fields on a specific record, and retrieve the updated value from the database.

    Note that this function will throw an exception if the given key is not found in the database.

    Example usage

    With schema-1 and dataset-1,

    updateGetSpj :: MonadIO m => [Update User] -> ReaderT SqlBackend m User
    updateGetSpj updates = updateGet spjId updates
    spj <- updateGetSpj [UserAge +=. 100]

    The above query when applied on dataset-1, will produce this:

    +-----+------+-----+
    |id   |name  |age  |
    +-----+------+-----+
    |1    |SPJ   |140  |
    +-----+------+-----+
    |2    |Simon |41   |
    +-----+------+-----+
Instances3PersistStoreWrite
classclass PersistCore backend where
#

Associated types

Instances4PersistCore
familydata family BackendKey backend
#
Instances72Bounded, Enum, Eq, Integral, Num, Ord, …
datadata EntityDef
#

An EntityDef represents the information that persistent knows about an Entity. It uses this information to generate the Haskell datatype, the SQL migrations, and other relevant conversions.

Instances5Eq, Ord, Read, Show, Lift
  • Eq EntityDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Ord EntityDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Read EntityDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Show EntityDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Lift EntityDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
familydata family Key record
#

By default, a backend will automatically generate the key Instead you can specify a Primary key made up of unique values.

Instances1608SymbolToField, Eq, Ord, Read, Show, Generic, …
datadata SqlBackend
#

A SqlBackend represents a handle or connection to a database. It contains functions and values that allow databases to have more optimized implementations, as well as references that benefit performance and sharing.

Instead of using the SqlBackend constructor directly, use the mkSqlBackend function.

A SqlBackend is *not* thread-safe. You should not assume that a SqlBackend can be shared among threads and run concurrent queries. This *will* result in problems. Instead, you should create a Pool SqlBackend, known as a ConnectionPool, and pass that around in multi-threaded applications.

To run actions in the persistent library, you should use the runSqlConn function. If you're using a multithreaded application, use the runSqlPool function.

Instances92Arbitrary, PersistQueryRead, PersistQueryWrite, HasPersistBackend, IsPersistBackend, PersistCore, …
datadata PersistValue
#

A raw value which can be stored in any backend and can be marshalled to and from a PersistField.

Constructors

Instances13Eq, Ord, Read, Show, NFData, Arbitrary, …
patternpattern PersistDbSpecific :: ByteString -> PersistValue
#

Deprecated. Deprecated since 2.11 because of inconsistent escaping behavior across backends. The Postgres backend escapes these values, while the MySQL backend does not. If you are using this, please switch to PersistLiteral_ and provide a relevant LiteralType for your conversion.

This pattern synonym used to be a data constructor for the PersistValue type. It was changed to be a pattern so that JSON-encoded database values could be parsed into their corresponding values. You should not use this, and instead prefer to pattern match on PersistLiteral_ directly.

If you use this, it will overlap a patern match on the 'PersistLiteral_, PersistLiteral, and PersistLiteralEscaped patterns. If you need to disambiguate between these constructors, pattern match on PersistLiteral_ directly.

typetype PersistStore a = PersistStoreWrite a
#

A backwards-compatible alias for those that don't care about distinguishing between read and write queries. It signifies the assumption that, by default, a backend can write as well as read.

classclass PersistField a where
#

This class teaches Persistent how to take a custom type and marshal it to and from a PersistValue, allowing it to be stored in a database.

Examples
Simple Newtype

You can use newtype to add more type safety/readability to a basis type like ByteString. In these cases, just derive PersistField and PersistFieldSql:

{-# LANGUAGE GeneralizedNewtypeDeriving #-}

newtype HashedPassword = HashedPassword ByteString
  deriving (Eq, Show, PersistField, PersistFieldSql)
Smart Constructor Newtype

In this example, we create a PersistField instance for a newtype following the "Smart Constructor" pattern.

{-# LANGUAGE GeneralizedNewtypeDeriving #-}
import qualified Data.Text as T
import qualified Data.Char as C

-- | An American Social Security Number
newtype SSN = SSN Text
 deriving (Eq, Show, PersistFieldSql)

mkSSN :: Text -> Either Text SSN
mkSSN t = if (T.length t == 9) && (T.all C.isDigit t)
 then Right $ SSN t
 else Left $ "Invalid SSN: " <> t

instance PersistField SSN where
  toPersistValue (SSN t) = PersistText t
  fromPersistValue (PersistText t) = mkSSN t
  -- Handle cases where the database does not give us PersistText
  fromPersistValue x = Left $ "File.hs: When trying to deserialize an SSN: expected PersistText, received: " <> T.pack (show x)

Tips:

  • This file contain dozens of PersistField instances you can look at for examples.

  • Typically custom PersistField instances will only accept a single PersistValue constructor in fromPersistValue.

  • Internal PersistField instances accept a wide variety of PersistValues to accomodate e.g. storing booleans as integers, booleans or strings.

  • If you're making a custom instance and using a SQL database, you'll also need PersistFieldSql to specify the type of the database column.

Instances288PersistField, …
datadata Entity record
#

Datatype that represents an entity, with both its Key and its Haskell record representation.

When using a SQL-based backend (such as SQLite or PostgreSQL), an Entity may take any number of columns depending on how many fields it has. In order to reconstruct your entity on the Haskell side, persistent needs all of your entity columns and in the right order. Note that you don't need to worry about this when using persistent's API since everything is handled correctly behind the scenes.

However, if you want to issue a raw SQL command that returns an Entity, then you have to be careful with the column order. While you could use SELECT Entity.* WHERE ... and that would work most of the time, there are times when the order of the columns on your database is different from the order that persistent expects (for example, if you add a new field in the middle of you entity definition and then use the migration code -- persistent will expect the column to be in the middle, but your DBMS will put it as the last column). So, instead of using a query like the one above, you may use rawSql (from the Database.Persist.Sql module) with its /entity selection placeholder/ (a double question mark ??). Using rawSql the query above must be written as SELECT ?? WHERE ... Then rawSql will replace ?? with the list of all columns that we need from your entity in the right order. If your query returns two entities (i.e. (Entity backend a, Entity backend b)), then you must you use SELECT ??, ?? WHERE ..., and so on.

Constructors

Instances16SymbolToField, Eq, Ord, Read, Show, Generic, …
familydata family EntityField record :: Type -> Type
#

An EntityField is parameterised by the Haskell record it belongs to and the additional type of that field.

As of persistent-2.11.0.0, it's possible to use the OverloadedLabels language extension to refer to EntityField values polymorphically. See the documentation on SymbolToField for more information.

Instances123IsLabel, EntityField, …
familytype family PersistEntityBackend record
#

Persistent allows multiple different backends (databases).

Instances122PersistEntityBackend, …
classclass SafeToInsert a
#

A type class which is used to witness that a type is safe to insert into the database without providing a primary key.

The TemplateHaskell function mkPersist will generate instances of this class for any entity that it works on. If the entity has a default primary key, then it provides a regular instance. If the entity has a Primary natural key, then this works fine. But if the entity has an Id column with no default=, then this does a TypeError and forces the user to use insertKey.

Instances123SafeToInsert, …
classclass SymbolToField (sym :: Symbol) rec typ | sym rec -> typ where
#

This type class is used with the OverloadedLabels extension to provide a more convenient means of using the EntityField type. EntityField definitions are prefixed with the type name to avoid ambiguity, but this ambiguity can result in verbose code.

If you have a table User with a name Text field, then the corresponding EntityField is UserName. With this, we can write #name :: EntityField User Text.

What's more fun is that the type is more general: it's actually #name :: (SymbolToField "name" rec typ) => EntityField rec typ

Which means it is *polymorphic* over the actual record. This allows you to write code that can be generic over the tables, provided they have the right fields.

Methods

Instances372SymbolToField, …
familydata family Unique record
#

Unique keys besides the Key.

Instances126Eq, Show, Unique, …
  • Eq (Unique Ba)Defined in persistent-test-2.13.1.3 · PersistUniqueTest
  • Eq (Unique Fo)Defined in persistent-test-2.13.1.3 · PersistUniqueTest
  • Show (Unique Ba)Defined in persistent-test-2.13.1.3 · PersistUniqueTest
  • Show (Unique Fo)Defined in persistent-test-2.13.1.3 · PersistUniqueTest
  • data Unique AddressDefined in persistent-test-2.13.1.3 · CompositeTest
  • data Unique CitizenDefined in persistent-test-2.13.1.3 · CompositeTest
  • data Unique CitizenAddressDefined in persistent-test-2.13.1.3 · CompositeTest
  • data Unique PrimaryCompositeWithOtherNullableFields
    • PrimaryCompositeWithOtherNullableFieldsPrimaryKey String String
    Defined in persistent-test-2.13.1.3 · CompositeTest
  • data Unique TestChildDefined in persistent-test-2.13.1.3 · CompositeTest
  • data Unique TestParentDefined in persistent-test-2.13.1.3 · CompositeTest
  • data Unique Tweet
    • TweetPrimaryKey Int
    • UniqueTweetId Int
    Defined in persistent-test-2.13.1.3 · CustomPrimaryKeyReferenceTest
  • data Unique TweetUrlDefined in persistent-test-2.13.1.3 · CustomPrimaryKeyReferenceTest
  • data Unique EquivalentTypeDefined in persistent-test-2.13.1.3 · EquivalentTypeTest
  • data Unique EquivalentType2Defined in persistent-test-2.13.1.3 · EquivalentTypeTest
  • data Unique ADefined in persistent-test-2.13.1.3 · ForeignKey
  • data Unique ACompositeDefined in persistent-test-2.13.1.3 · ForeignKey
  • data Unique BDefined in persistent-test-2.13.1.3 · ForeignKey
  • data Unique BCompositeDefined in persistent-test-2.13.1.3 · ForeignKey
  • data Unique BExplicitDefined in persistent-test-2.13.1.3 · ForeignKey
  • data Unique ChainDefined in persistent-test-2.13.1.3 · ForeignKey
  • data Unique Chain2Defined in persistent-test-2.13.1.3 · ForeignKey
  • data Unique Chain3Defined in persistent-test-2.13.1.3 · ForeignKey
  • data Unique ChildDefined in persistent-test-2.13.1.3 · ForeignKey
  • data Unique ChildCompositeDefined in persistent-test-2.13.1.3 · ForeignKey
  • data Unique ChildImplicitDefined in persistent-test-2.13.1.3 · ForeignKey
  • data Unique Parent
    • ParentPrimaryKey Int
    Defined in persistent-test-2.13.1.3 · ForeignKey
  • data Unique ParentComposite
    • ParentCompositePrimaryKey Int Int
    Defined in persistent-test-2.13.1.3 · ForeignKey
  • data Unique ParentImplicitDefined in persistent-test-2.13.1.3 · ForeignKey
  • data Unique SelfReferenced
    • SelfReferencedPrimaryKey Int
    Defined in persistent-test-2.13.1.3 · ForeignKey
  • data Unique SimpleCascadeDefined in persistent-test-2.13.1.3 · ForeignKey
  • data Unique SimpleCascadeChildDefined in persistent-test-2.13.1.3 · ForeignKey
  • data Unique GenTestDefined in persistent-test-2.13.1.3 · GeneratedColumnTestSQL
  • data Unique MigrateTestV1Defined in persistent-test-2.13.1.3 · GeneratedColumnTestSQL
  • data Unique MigrateTestV2Defined in persistent-test-2.13.1.3 · GeneratedColumnTestSQL
  • data Unique TableAnExtremelyFantasticallySuperLongNameChildDefined in persistent-test-2.13.1.3 · LongIdentifierTest
  • data Unique TableAnExtremelyFantasticallySuperLongNameParentDefined in persistent-test-2.13.1.3 · LongIdentifierTest
  • data Unique VaryingLengthsDefined in persistent-test-2.13.1.3 · MigrationColumnLengthTest
  • data Unique IdempotencyDefined in persistent-test-2.13.1.3 · MigrationIdempotencyTest
  • data Unique CustomSqlId
    • CustomSqlIdPrimaryKey Int
    Defined in persistent-test-2.13.1.3 · MigrationTest
  • data Unique SourceDefined in persistent-test-2.13.1.3 · MigrationTest
  • data Unique Source1Defined in persistent-test-2.13.1.3 · MigrationTest
  • data Unique TargetDefined in persistent-test-2.13.1.3 · MigrationTest
  • data Unique Target1Defined in persistent-test-2.13.1.3 · MigrationTest
  • data Unique BaDefined in persistent-test-2.13.1.3 · PersistUniqueTest
  • data Unique FoDefined in persistent-test-2.13.1.3 · PersistUniqueTest
  • data Unique OnlyPrimaryKey
    • OnlyPrimaryKeyPrimaryKey Int
    Defined in persistent-test-2.13.1.3 · PersistUniqueTest
  • data Unique TreeDefined in persistent-test-2.13.1.3 · PersistentTestModels
  • data Unique UserDefined in persistent-test-2.13.1.3 · PersistentTestModelsImports
  • data Unique BarDefined in persistent-test-2.13.1.3 · PrimaryTest
  • data Unique CompositePrimaryDefined in persistent-test-2.13.1.3 · PrimaryTest
  • data Unique FooDefined in persistent-test-2.13.1.3 · PrimaryTest
  • data Unique TreesDefined in persistent-test-2.13.1.3 · PrimaryTest
  • data Unique Wombat
    • WombatPrimaryKey Text
    Defined in persistent-test-2.13.1.3 · TransactionLevelTest
  • data Unique TreeDefined in persistent-test-2.13.1.3 · TreeTest
  • data Unique TestCheckmarkDefined in persistent-test-2.13.1.3 · UniqueTest
  • data Unique TestNonNull
    • UniqueTestNonNull Int
    Defined in persistent-test-2.13.1.3 · UniqueTest
  • data Unique TestNullDefined in persistent-test-2.13.1.3 · UniqueTest
  • data Unique (BlogPostGeneric backend)Defined in persistent-test-2.13.1.3 · CustomPersistFieldTest
  • data Unique (DataTypeTableGeneric backend)Defined in persistent-test-2.13.1.3 · DataTypeTest
  • data Unique (BarGeneric backend)Defined in persistent-test-2.13.1.3 · EmbedOrderTest
  • data Unique (FooGeneric backend)Defined in persistent-test-2.13.1.3 · EmbedOrderTest
  • data Unique (AccountGeneric backend)Defined in persistent-test-2.13.1.3 · EmbedTest
  • data Unique (ContactGeneric backend)Defined in persistent-test-2.13.1.3 · EmbedTest
  • data Unique (EmbedsHasMapGeneric backend)Defined in persistent-test-2.13.1.3 · EmbedTest
  • data Unique (HasArrayWithEntitiesGeneric backend)Defined in persistent-test-2.13.1.3 · EmbedTest
  • data Unique (HasEmbedGeneric backend)Defined in persistent-test-2.13.1.3 · EmbedTest
  • data Unique (HasEmbedsGeneric backend)Defined in persistent-test-2.13.1.3 · EmbedTest
  • data Unique (HasListEmbedGeneric backend)Defined in persistent-test-2.13.1.3 · EmbedTest
  • data Unique (HasListGeneric backend)Defined in persistent-test-2.13.1.3 · EmbedTest
  • data Unique (HasMapGeneric backend)Defined in persistent-test-2.13.1.3 · EmbedTest
  • data Unique (HasNestedListGeneric backend)Defined in persistent-test-2.13.1.3 · EmbedTest
  • data Unique (HasSetEmbedGeneric backend)Defined in persistent-test-2.13.1.3 · EmbedTest
  • data Unique (InListGeneric backend)Defined in persistent-test-2.13.1.3 · EmbedTest
  • data Unique (IntListGeneric backend)Defined in persistent-test-2.13.1.3 · EmbedTest
  • data Unique (ListEmbedGeneric backend)Defined in persistent-test-2.13.1.3 · EmbedTest
  • data Unique (MapIdValueGeneric backend)Defined in persistent-test-2.13.1.3 · EmbedTest
  • data Unique (OnlyNameGeneric backend)Defined in persistent-test-2.13.1.3 · EmbedTest
  • data Unique (ProfileGeneric backend)Defined in persistent-test-2.13.1.3 · EmbedTest
  • data Unique (SelfListGeneric backend)Defined in persistent-test-2.13.1.3 · EmbedTest
  • data Unique (SelfMaybeGeneric backend)Defined in persistent-test-2.13.1.3 · EmbedTest
  • data Unique (UserGeneric backend)Defined in persistent-test-2.13.1.3 · EmbedTest
  • data Unique (EmptyEntityGeneric backend)Defined in persistent-test-2.13.1.3 · EmptyEntityTest
  • data Unique (ARecordGeneric backend)Defined in persistent-test-2.13.1.3 · EntityEmbedTest
  • data Unique (HtmlTableGeneric backend)Defined in persistent-test-2.13.1.3 · HtmlTest
  • data Unique (NumberGeneric backend)Defined in persistent-test-2.13.1.3 · LargeNumberTest
  • data Unique (MaxLenGeneric backend)Defined in persistent-test-2.13.1.3 · MaxLenTest
  • data Unique (MaybeFieldDefEntityGeneric backend)Defined in persistent-test-2.13.1.3 · MaybeFieldDefsTest
  • data Unique (ReferencingGeneric backend)Defined in persistent-test-2.13.1.3 · MigrationOnlyTest
  • data Unique (TwoField1Generic backend)Defined in persistent-test-2.13.1.3 · MigrationOnlyTest
  • data Unique (TwoFieldGeneric backend)Defined in persistent-test-2.13.1.3 · MigrationOnlyTest
  • data Unique (CustomPrefix1Generic backend)Defined in persistent-test-2.13.1.3 · PersistentTestModels
  • data Unique (CustomPrefix2Generic backend)Defined in persistent-test-2.13.1.3 · PersistentTestModels
  • data Unique (CustomPrefixSumGeneric backend)Defined in persistent-test-2.13.1.3 · PersistentTestModels
  • data Unique (DudeWeirdColumnsGeneric backend)Defined in persistent-test-2.13.1.3 · PersistentTestModels
  • data Unique (EmailPTGeneric backend)Defined in persistent-test-2.13.1.3 · PersistentTestModels
  • data Unique (MaybeOwnedPetGeneric backend)Defined in persistent-test-2.13.1.3 · PersistentTestModels
  • data Unique (MutAGeneric backend)Defined in persistent-test-2.13.1.3 · PersistentTestModels
  • data Unique (MutBGeneric backend)Defined in persistent-test-2.13.1.3 · PersistentTestModels
  • data Unique (NeedsPetGeneric backend)Defined in persistent-test-2.13.1.3 · PersistentTestModels
  • data Unique (NoPrefix1Generic backend)Defined in persistent-test-2.13.1.3 · PersistentTestModels
  • data Unique (NoPrefix2Generic backend)Defined in persistent-test-2.13.1.3 · PersistentTestModels
  • data Unique (NoPrefixSumGeneric backend)Defined in persistent-test-2.13.1.3 · PersistentTestModels
  • data Unique (OutdoorPetGeneric backend)Defined in persistent-test-2.13.1.3 · PersistentTestModels
  • data Unique (Person1Generic backend)Defined in persistent-test-2.13.1.3 · PersistentTestModels
  • data Unique (PersonGeneric backend)Defined in persistent-test-2.13.1.3 · PersistentTestModels
  • data Unique (PersonMayGeneric backend)Defined in persistent-test-2.13.1.3 · PersistentTestModels
  • data Unique (PersonMaybeAgeGeneric backend)Defined in persistent-test-2.13.1.3 · PersistentTestModels
  • data Unique (PetGeneric backend)Defined in persistent-test-2.13.1.3 · PersistentTestModels
  • data Unique (RelationshipGeneric backend)Defined in persistent-test-2.13.1.3 · PersistentTestModels
  • data Unique (ReverseFieldOrder a)Defined in persistent-test-2.13.1.3 · PersistentTestModels
  • data Unique (StrictGeneric backend)Defined in persistent-test-2.13.1.3 · PersistentTestModels
  • data Unique (UpsertByGeneric backend)
    • UniqueUpsertBy Text
    • UniqueUpsertByCity Text
    Defined in persistent-test-2.13.1.3 · PersistentTestModels
  • data Unique (UpsertGeneric backend)Defined in persistent-test-2.13.1.3 · PersistentTestModels
  • data Unique (UserPTGeneric backend)Defined in persistent-test-2.13.1.3 · PersistentTestModels
  • data Unique (MenuObjectGeneric backend)Defined in persistent-test-2.13.1.3 · Recursive
  • data Unique (SubTypeGeneric backend)Defined in persistent-test-2.13.1.3 · Recursive
  • data Unique (ForeignIdTableGeneric backend)Defined in persistent-test-2.13.1.3 · RenameTest
  • data Unique (IdTableGeneric backend)Defined in persistent-test-2.13.1.3 · RenameTest
  • data Unique (KeyTableGeneric backend)Defined in persistent-test-2.13.1.3 · RenameTest
  • data Unique (LowerCaseTableGeneric backend)Defined in persistent-test-2.13.1.3 · RenameTest
  • data Unique (RefTableGeneric backend)
    • UniqueRefTable Int
    Defined in persistent-test-2.13.1.3 · RenameTest
  • data Unique (BicycleGeneric backend)Defined in persistent-test-2.13.1.3 · SumTypeTest
  • data Unique (CarGeneric backend)Defined in persistent-test-2.13.1.3 · SumTypeTest
  • data Unique (VehicleGeneric backend)Defined in persistent-test-2.13.1.3 · SumTypeTest
  • data Unique (TypeLitFieldDefsLabelledGeneric backend)Defined in persistent-test-2.13.1.3 · TypeLitFieldDefsTest
  • data Unique (TypeLitFieldDefsNumericGeneric backend)Defined in persistent-test-2.13.1.3 · TypeLitFieldDefsTest
valueentityIdToJSON
  1. :: (PersistEntity record, ToJSON record)
  2. => Entity record
  3. -> Value
#

Predefined toJSON. The resulting JSON looks like {"id": 1, "name": ...}.

The typical usage is:

instance ToJSON (Entity User) where
    toJSON = entityIdToJSON
classclass (PersistEntity record, PersistEntityBackend record ~ backend, PersistCore backend) => ToBackendKey backend record where
#

ToBackendKey converts a PersistEntity Key into a BackendKey This can be used by each backend to convert between a Key and a plain Haskell type. For Sql, that is done with toSqlKey and fromSqlKey.

By default, a PersistEntity uses the default BackendKey for its Key and is an instance of ToBackendKey

A Key that instead uses a custom type will not be an instance of ToBackendKey.

Methods

Instances103ToBackendKey, …
classclass PersistEntity record => AtLeastOneUniqueKey record where
#

This class is used to ensure that functions requring at least one unique key are not called with records that have 0 unique keys. The quasiquoter automatically writes working instances for appropriate entities, and generates TypeError instances for records that have 0 unique keys.

Methods

Instances121AtLeastOneUniqueKey, …
typetype MultipleUniqueKeysError ty = ((('Text "The entity " ':<>: 'ShowType ty) ':<>: 'Text " has multiple unique keys.") ':$$: ('Text "The function you are trying to call requires only a single " ':<>: 'Text "unique key.")) ':$$: (('Text "There is probably a variant of the function with 'By' " ':<>: 'Text "appended that will allow you to select a unique key ") ':<>: 'Text "for the operation.")
#

This is an error message. It is used when an entity has multiple unique keys, and the function expects a single unique key.

classclass PersistEntity record => OnlyOneUniqueKey record where
#

This class is used to ensure that upsert is only called on records that have a single Unique key. The quasiquoter automatically generates working instances for appropriate records, and generates TypeError instances for records that have 0 or multiple unique keys.

Methods

Instances121OnlyOneUniqueKey, …

Retrieve the list of FieldDef that makes up the fields of the entity.

This does not return the fields for an Id column or an implicit id. It will return the key columns if you used the Primary syntax for defining the primary key.

This does not return fields that are marked SafeToRemove or MigrationOnly - so it only returns fields that are represented in the Haskell type. If you need those fields, use getEntityFieldsDatabase.

newtypenewtype ConstraintNameHS
#

An ConstraintNameHS represents the Haskell-side name that persistent will use for a constraint.

Instances5Eq, Ord, Read, Show, Lift
newtypenewtype EntityNameHS
#

An EntityNameHS represents the Haskell-side name that persistent will use for an entity.

Instances5Eq, Ord, Read, Show, Lift
newtypenewtype FieldNameDB
#

A FieldNameDB represents the datastore-side name that persistent will use for a field.

Instances6Eq, Ord, Read, Show, DatabaseName, Lift
newtypenewtype FieldNameHS
#

A FieldNameHS represents the Haskell-side name that persistent will use for a field.

Instances5Eq, Ord, Read, Show, Lift
newtypenewtype EntityNameDB
#

An EntityNameDB represents the datastore-side name that persistent will use for an entity.

Instances6Eq, Ord, Read, Show, DatabaseName, Lift
classclass HasPersistBackend backend where
#

Class which allows the plucking of a BaseBackend backend from some larger type. For example, instance HasPersistBackend (SqlReadBackend, Int) where type BaseBackend (SqlReadBackend, Int) = SqlBackend persistBackend = unSqlReadBackend . fst

Associated types

Methods

Instances4HasPersistBackend
familytype family BaseBackend backend
#
Instances4BaseBackend
classclass PersistField a => PersistFieldSql a where
#

Tells Persistent what database column type should be used to store a Haskell type.

Examples
Simple Boolean Alternative
data Switch = On | Off
  deriving (Show, Eq)

instance PersistField Switch where
  toPersistValue s = case s of
    On -> PersistBool True
    Off -> PersistBool False
  fromPersistValue (PersistBool b) = if b then Right On else Right Off
  fromPersistValue x = Left $ "File.hs: When trying to deserialize a Switch: expected PersistBool, received: " <> T.pack (show x)

instance PersistFieldSql Switch where
  sqlType _ = SqlBool
Non-Standard Database Types

If your database supports non-standard types, such as Postgres' uuid, you can use SqlOther to use them:

import qualified Data.UUID as UUID
instance PersistField UUID where
  toPersistValue = PersistLiteralEncoded . toASCIIBytes
  fromPersistValue (PersistLiteralEncoded uuid) =
    case fromASCIIBytes uuid of
      Nothing -> Left $ "Model/CustomTypes.hs: Failed to deserialize a UUID; received: " <> T.pack (show uuid)
      Just uuid' -> Right uuid'
  fromPersistValue x = Left $ "File.hs: When trying to deserialize a UUID: expected PersistLiteralEncoded, received: "-- >  <> T.pack (show x)

instance PersistFieldSql UUID where
  sqlType _ = SqlOther "uuid"
User Created Database Types

Similarly, some databases support creating custom types, e.g. Postgres' DOMAIN and ENUM features. You can use SqlOther to specify a custom type:

CREATE DOMAIN ssn AS text
      CHECK ( value ~ '^[0-9]{9}$');
instance PersistFieldSQL SSN where
  sqlType _ = SqlOther "ssn"
CREATE TYPE rainbow_color AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet');
instance PersistFieldSQL RainbowColor where
  sqlType _ = SqlOther "rainbow_color"

Methods

Instances287PersistFieldSql, …
datadata WhyNullable
#

The reason why a field is nullable is very important. A field that is nullable because of a Maybe tag will have its type changed from A to Maybe A. OTOH, a field that is nullable because of a nullable tag will remain with the same type.

Instances2Eq, Show
  • Eq WhyNullableDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Show WhyNullableDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
datadata CompositeDef
#
Instances5Eq, Ord, Read, Show, Lift
  • Eq CompositeDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Ord CompositeDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Read CompositeDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Show CompositeDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Lift CompositeDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
datadata ReferenceDef
#

There are 3 kinds of references 1) composite (to fields that exist in the record) 2) single field 3) embedded

Constructors

Instances5Eq, Ord, Read, Show, Lift
  • Eq ReferenceDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Ord ReferenceDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Read ReferenceDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Show ReferenceDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Lift ReferenceDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
datadata EntityIdDef
#

The definition for the entity's primary key ID.

Constructors

  • EntityIdField !FieldDef

    The entity has a single key column, and it is a surrogate key - that is, you can't go from rec -> Key rec.

  • EntityIdNaturalKey !CompositeDef

    The entity has a natural key. This means you can write rec -> Key rec because all the key fields are present on the datatype.

    A natural key can have one or more columns.

Instances5Eq, Ord, Read, Show, Lift
  • Eq EntityIdDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Ord EntityIdDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Read EntityIdDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Show EntityIdDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Lift EntityIdDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
classclass (PersistUniqueRead backend, PersistStoreWrite backend) => PersistUniqueWrite backend where
#

Some functions in this module (insertUnique, insertBy, and replaceUnique) first query the unique indexes to check for conflicts. You could instead optimistically attempt to perform the operation (e.g. replace instead of replaceUnique). However,

  • there is some fragility to trying to catch the correct exception and determing the column of failure;

  • an exception will automatically abort the current SQL transaction.

Methods

  • deleteBy :: (MonadIO m, PersistRecordBackend record backend) => Unique record -> ReaderT backend m ()

    Delete a specific record by unique key. Does nothing if no record matches.

    Example usage

    With schema-1 and dataset-1,

    deleteBySpjName :: MonadIO m => ReaderT SqlBackend m ()
    deleteBySpjName = deleteBy UniqueUserName "SPJ"

    The above query when applied on dataset-1, will produce this:

    +-----+------+-----+
    |id   |name  |age  |
    +-----+------+-----+
    |2    |Simon |41   |
    +-----+------+-----+
  • insertUnique :: (MonadIO m, PersistRecordBackend record backend, SafeToInsert record) => record -> ReaderT backend m (Maybe (Key record))

    Like insert, but returns Nothing when the record couldn't be inserted because of a uniqueness constraint.

    Example usage

    With schema-1 and dataset-1, we try to insert the following two records:

    linusId <- insertUnique $ User "Linus" 48
    spjId   <- insertUnique $ User "SPJ" 90
    +-----+------+-----+
    |id   |name  |age  |
    +-----+------+-----+
    |1    |SPJ   |40   |
    +-----+------+-----+
    |2    |Simon |41   |
    +-----+------+-----+
    |3    |Linus |48   |
    +-----+------+-----+

    Linus's record was inserted to dataset-1, while SPJ wasn't because SPJ already exists in dataset-1.

  • insertUnique_ :: (MonadIO m, PersistRecordBackend record backend, SafeToInsert record) => record -> ReaderT backend m (Maybe ())

    Same as insertUnique but doesn't return a Key.

    Example usage

    With schema-1 and dataset-1, we try to insert the following two records:

    linusId <- insertUnique_ $ User "Linus" 48
    spjId   <- insertUnique_ $ User "SPJ" 90
    +-----+------+-----+
    |id   |name  |age  |
    +-----+------+-----+
    |1    |SPJ   |40   |
    +-----+------+-----+
    |2    |Simon |41   |
    +-----+------+-----+
    |3    |Linus |48   |
    +-----+------+-----+

    Linus's record was inserted to dataset-1, while SPJ wasn't because SPJ already exists in dataset-1.

  • upsert :: (MonadIO m, PersistRecordBackend record backend, OnlyOneUniqueKey record, SafeToInsert record) => record -> [Update record] -> ReaderT backend m (Entity record)

    Update based on a uniqueness constraint or insert:

    • insert the new record if it does not exist;

    • If the record exists (matched via it's uniqueness constraint), then update the existing record with the parameters which is passed on as list to the function.

    Example usage

    First, we try to explain upsert using schema-1 and dataset-1.

    upsertSpj :: MonadIO m => [Update User] -> ReaderT SqlBackend m (Maybe (Entity User))
    upsertSpj updates = upsert (User "SPJ" 999) updates
    mSpjEnt <- upsertSpj [UserAge +=. 15]

    The above query when applied on dataset-1, will produce this:

    +-----+-----+--------+
    |id   |name |age     |
    +-----+-----+--------+
    |1    |SPJ  |40 -> 55|
    +-----+-----+--------+
    |2    |Simon|41      |
    +-----+-----+--------+
    upsertX :: MonadIO m => [Update User] -> ReaderT SqlBackend m (Maybe (Entity User))
    upsertX updates = upsert (User "X" 999) updates
    mXEnt <- upsertX [UserAge +=. 15]

    The above query when applied on dataset-1, will produce this:

    +-----+-----+--------+
    |id   |name |age     |
    +-----+-----+--------+
    |1    |SPJ  |40      |
    +-----+-----+--------+
    |2    |Simon|41      |
    +-----+-----+--------+
    |3    |X    |999     |
    +-----+-----+--------+

    Next, what if the schema has two uniqueness constraints? Let's check it out using schema-2:

    mSpjEnt <- upsertSpj [UserAge +=. 15]

    This fails with a compile-time type error alerting us to the fact that this record has multiple unique keys, and suggests that we look for upsertBy to select the unique key we want.

  • upsertBy :: (MonadIO m, PersistRecordBackend record backend, SafeToInsert record) => Unique record -> record -> [Update record] -> ReaderT backend m (Entity record)

    Update based on a given uniqueness constraint or insert:

    • insert the new record if it does not exist;

    • update the existing record that matches the given uniqueness constraint.

    Example usage

    We try to explain upsertBy using schema-2 and dataset-1.

    upsertBySpjName :: MonadIO m => User -> [Update User] -> ReaderT SqlBackend m (Entity User)
    upsertBySpjName record updates = upsertBy (UniqueUserName "SPJ") record updates
    mSpjEnt <- upsertBySpjName (Person "X" 999) [PersonAge += .15]

    The above query will alter dataset-1 to:

    +-----+-----+--------+
    |id   |name |age     |
    +-----+-----+--------+
    |1    |SPJ  |40 -> 55|
    +-----+-----+--------+
    |2    |Simon|41      |
    +-----+-----+--------+
    upsertBySimonAge :: MonadIO m => User -> [Update User] -> ReaderT SqlBackend m (Entity User)
    upsertBySimonAge record updates = upsertBy (UniqueUserName "SPJ") record updates
    mPhilipEnt <- upsertBySimonAge (User "X" 999) [UserName =. "Philip"]

    The above query will alter dataset-1 to:

    +----+-----------------+-----+
    | id |      name       | age |
    +----+-----------------+-----+
    |  1 | SPJ             |  40 |
    +----+-----------------+-----+
    |  2 | Simon -> Philip |  41 |
    +----+-----------------+-----+
    upsertByUnknownName :: MonadIO m => User -> [Update User] -> ReaderT SqlBackend m (Entity User)
    upsertByUnknownName record updates = upsertBy (UniqueUserName "Unknown") record updates
    mXEnt <- upsertByUnknownName (User "X" 999) [UserAge +=. 15]

    This query will alter dataset-1 to:

    +-----+-----+-----+
    |id   |name |age  |
    +-----+-----+-----+
    |1    |SPJ  |40   |
    +-----+-----+-----+
    |2    |Simon|41   |
    +-----+-----+-----+
    |3    |X    |999  |
    +-----+-----+-----+
  • putMany :: (MonadIO m, PersistRecordBackend record backend, SafeToInsert record) => [record] -> ReaderT backend m ()

    Put many records into db

    • insert new records that do not exist (or violate any unique constraints)

    • replace existing records (matching any unique constraint)

Instances3PersistUniqueWrite
datadata FieldType
#

A FieldType describes a field parsed from the QuasiQuoter and is used to determine the Haskell type in the generated code.

name Text parses into FTTypeCon Nothing Text

name T.Text parses into FTTypeCon (Just T Text)

name (Jsonb User) parses into:

FTApp (FTTypeCon Nothing Jsonb) (FTTypeCon Nothing User)
Instances5Eq, Ord, Read, Show, Lift
  • Eq FieldTypeDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Ord FieldTypeDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Read FieldTypeDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Show FieldTypeDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Lift FieldTypeDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
datadata FieldAttr
#

Attributes that may be attached to fields that can affect migrations and serialization in backend-specific ways.

While we endeavor to, we can't forsee all use cases for all backends, and so FieldAttr is extensible through its constructor FieldAttrOther.

Constructors

  • FieldAttrMaybe

    The Maybe keyword goes after the type. This indicates that the column is nullable, and the generated Haskell code will have a Maybe type for it.

    Example:

    User
        name Text Maybe
    
  • FieldAttrNullable

    This indicates that the column is nullable, but should not have a Maybe type. For this to work out, you need to ensure that the PersistField instance for the type in question can support a PersistNull value.

    data What = NoWhat | Hello Text
    
    instance PersistField What where
        fromPersistValue PersistNull =
            pure NoWhat
        fromPersistValue pv =
            Hello $ fromPersistValue pv
    
    instance PersistFieldSql What where
        sqlType _ = SqlString
    
    User
        what What nullable
    
  • FieldAttrMigrationOnly

    This tag means that the column will not be present on the Haskell code, but will not be removed from the database. Useful to deprecate fields in phases.

    You should set the column to be nullable in the database. Otherwise, inserts won't have values.

    User
        oldName Text MigrationOnly
        newName Text
    
  • FieldAttrSafeToRemove

    A SafeToRemove attribute is not present on the Haskell datatype, and the backend migrations should attempt to drop the column without triggering any unsafe migration warnings.

    Useful after you've used MigrationOnly to remove a column from the database in phases.

    User
        oldName Text SafeToRemove
        newName Text
    
  • FieldAttrNoreference

    This attribute indicates that we should not create a foreign key reference from a column. By default, persistent will try and create a foreign key reference for a column if it can determine that the type of the column is a Key entity or an EntityId and the Entity's name was present in mkPersist.

    This is useful if you want to use the explicit foreign key syntax.

    Post
        title    Text
    
    Comment
        postId   PostId      noreference
        Foreign Post fk_comment_post postId
    
  • FieldAttrReference Text

    This is set to specify precisely the database table the column refers to.

    Post
        title    Text
    
    Comment
        postId   PostId references="post"
    

    You should not need this - persistent should be capable of correctly determining the target table's name. If you do need this, please file an issue describing why.

  • FieldAttrConstraint Text

    Specify a name for the constraint on the foreign key reference for this table.

    Post
        title    Text
    
    Comment
        postId   PostId constraint="my_cool_constraint_name"
    
  • FieldAttrDefault Text

    Specify the default value for a column.

    User
        createdAt    UTCTime     default="NOW()"
    

    Note that a default= attribute does not mean you can omit the value while inserting.

  • FieldAttrSqltype Text

    Specify a custom SQL type for the column. Generally, you should define a custom datatype with a custom PersistFieldSql instance instead of using this.

    User
        uuid     Text    sqltype=UUID
    
  • FieldAttrMaxlen Integer

    Set a maximum length for a column. Useful for VARCHAR and indexes.

    User
        name     Text    maxlen=200
    
        UniqueName name
    
  • FieldAttrSql Text

    Specify the database name of the column.

    User
        blarghle     Int     sql="b_l_a_r_g_h_l_e"
    

    Useful for performing phased migrations, where one column is renamed to another column over time.

  • FieldAttrOther Text

    A grab bag of random attributes that were unrecognized by the parser.

Instances5Eq, Ord, Read, Show, Lift
  • Eq FieldAttrDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Ord FieldAttrDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Read FieldAttrDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Show FieldAttrDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Lift FieldAttrDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
datadata FieldDef
#

A FieldDef represents the inormation that persistent knows about a field of a datatype. This includes information used to parse the field out of the database and what the field corresponds to.

Constructors

Instances5Eq, Ord, Read, Show, Lift
  • Eq FieldDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Ord FieldDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Read FieldDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Show FieldDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Lift FieldDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
classclass (PersistQueryRead backend, PersistStoreWrite backend) => PersistQueryWrite backend where
#

Backends supporting conditional write operations

Methods

Instances3PersistQueryWrite
datadata SqlType
#

A SQL data type. Naming attempts to reflect the underlying Haskell datatypes, eg SqlString instead of SqlVarchar. Different SQL databases may have different translations for these types.

Instances5Eq, Ord, Read, Show, Lift
  • Eq SqlTypeDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Ord SqlTypeDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Read SqlTypeDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Show SqlTypeDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Lift SqlTypeDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
datadata UniqueDef
#

Type for storing the Uniqueness constraint in the Schema. Assume you have the following schema with a uniqueness constraint:

Person
  name String
  age Int
  UniqueAge age

This will be represented as:

UniqueDef
    { uniqueHaskell = ConstraintNameHS (packPTH UniqueAge)
    , uniqueDBName = ConstraintNameDB (packPTH "unique_age")
    , uniqueFields = [(FieldNameHS (packPTH "age"), FieldNameDB (packPTH "age"))]
    , uniqueAttrs = []
    }
Instances5Eq, Ord, Read, Show, Lift
  • Eq UniqueDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Ord UniqueDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Read UniqueDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Show UniqueDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Lift UniqueDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
datadata ForeignDef
#
Instances5Eq, Ord, Read, Show, Lift
  • Eq ForeignDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Ord ForeignDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Read ForeignDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Show ForeignDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Lift ForeignDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
classclass (PersistCore backend, PersistStoreRead backend) => PersistQueryRead backend where
#

Backends supporting conditional read operations.

Methods

Instances4PersistQueryRead
typetype CautiousMigration = [(Bool, Sql)]
#

A list of SQL operations, marked with a safety flag. If the Bool is True, then the operation is *unsafe* - it might be destructive, or otherwise not idempotent. If the Bool is False, then the operation is *safe*, and can be run repeatedly without issues.

datadata EmbedEntityDef
#

An EmbedEntityDef is the same as an EntityDef But it is only used for fieldReference so it only has data needed for embedding

Instances5Eq, Ord, Read, Show, Lift
datadata LiteralType
#

A type that determines how a backend should handle the literal.

Constructors

  • Escaped

    The accompanying value will be escaped before inserting into the database. This is the correct default choice to use.

  • Unescaped

    The accompanying value will not be escaped when inserting into the database. This is potentially dangerous - use this with care.

  • DbSpecific

    The DbSpecific constructor corresponds to the legacy PersistDbSpecific constructor. We need to keep this around because old databases may have serialized JSON representations that reference this. We don't want to break the ability of a database to load rows.

Instances4Eq, Ord, Read, Show
  • Eq LiteralTypeDefined in persistent-2.14.6.3 · Database.Persist.PersistValue
  • Ord LiteralTypeDefined in persistent-2.14.6.3 · Database.Persist.PersistValue
  • Read LiteralTypeDefined in persistent-2.14.6.3 · Database.Persist.PersistValue
  • Show LiteralTypeDefined in persistent-2.14.6.3 · Database.Persist.PersistValue
classclass (Show (BackendKey backend), Read (BackendKey backend), Eq (BackendKey backend), Ord (BackendKey backend), PersistCore backend, PersistField (BackendKey backend), ToJSON (BackendKey backend), FromJSON (BackendKey backend)) => PersistStoreRead backend where
#

Methods

  • get :: (MonadIO m, PersistRecordBackend record backend) => Key record -> ReaderT backend m (Maybe record)

    Get a record by identifier, if available.

    Example usage

    With schema-1 and dataset-1,

    getSpj :: MonadIO m => ReaderT SqlBackend m (Maybe User)
    getSpj = get spjId
    mspj <- getSpj

    The above query when applied on dataset-1, will get this:

    +------+-----+
    | name | age |
    +------+-----+
    | SPJ  |  40 |
    +------+-----+
  • getMany :: (MonadIO m, PersistRecordBackend record backend) => [Key record] -> ReaderT backend m (Map (Key record) record)

    Get many records by their respective identifiers, if available.

    Example usage

    With schema-1 and dataset-1:

    getUsers :: MonadIO m => ReaderT SqlBackend m (Map (Key User) User)
    getUsers = getMany allkeys
    musers <- getUsers

    The above query when applied on dataset-1, will get these records:

    +----+-------+-----+
    | id | name  | age |
    +----+-------+-----+
    |  1 | SPJ   |  40 |
    +----+-------+-----+
    |  2 | Simon |  41 |
    +----+-------+-----+
Instances4PersistStoreRead
datadata Filter record
#

Filters which are available for select, updateWhere and deleteWhere. Each filter constructor specifies the field being filtered on, the type of comparison applied (equals, not equals, etc) and the argument for the comparison.

Persistent users use combinators to create these.

Note that it's important to be careful about the PersistFilter that you are using, if you use this directly. For example, using the In PersistFilter requires that you have an array- or list-shaped EntityField. It is possible to construct values using this that will create malformed runtime values.

Constructors

classclass BackendCompatible sup sub where
#

This class witnesses that two backend are compatible, and that you can convert from the sub backend into the sup backend. This is similar to the HasPersistBackend and IsPersistBackend classes, but where you don't want to fix the type associated with the PersistEntityBackend of a record.

Generally speaking, where you might have:

foo ::
  ( PersistEntity record
  , PersistEntityBackend record ~ BaseBackend backend
  , IsSqlBackend backend
  )

this can be replaced with:

foo ::
  ( PersistEntity record,
  , PersistEntityBackend record ~ backend
  , BackendCompatible SqlBackend backend
  )

This works for SqlReadBackend because of the instance BackendCompatible SqlBackend SqlReadBackend, without needing to go through the BaseBackend type family.

Likewise, functions that are currently hardcoded to use SqlBackend can be generalized:

-- before:
asdf :: ReaderT SqlBackend m ()
asdf = pure ()

-- after:
asdf' :: BackendCompatible SqlBackend backend => ReaderT backend m ()
asdf' = withCompatibleBackend asdf

Methods

Instances3BackendCompatible
valuewithCompatibleBackend
  1. :: BackendCompatible sup sub
  2. => ReaderT sup m a
  3. -> ReaderT sub m a
#

Run a query against a compatible backend, by projecting the backend

This is a helper for using queries which run against a specific backend type that your backend is compatible with.

newtypenewtype SqlReadBackend
#

An SQL backend which can only handle read queries

The constructor was exposed in 2.10.0.

Instances27PersistQueryRead, HasPersistBackend, IsPersistBackend, PersistCore, PersistStoreRead, PersistUniqueRead, …
newtypenewtype SqlWriteBackend
#

An SQL backend which can handle read or write queries

The constructor was exposed in 2.10.0

Instances30PersistQueryRead, PersistQueryWrite, HasPersistBackend, IsPersistBackend, PersistCore, PersistStoreRead, …
datadata FilterTablePrefix
#

Used when determining how to prefix a column name in a WHERE clause.

Constructors

  • PrefixTableName

    Prefix the column with the table name. This is useful if the column name might be ambiguous.

  • PrefixExcluded

    Prefix the column name with the EXCLUDED keyword. This is used with the Postgresql backend when doing ON CONFLICT DO UPDATE clauses - see the documentation on upsertWhere and upsertManyWhere.

valuerawSql
  1. :: (RawSql a, MonadIO m, BackendCompatible SqlBackend backend)
  2. => Text

    SQL statement, possibly with placeholders.

  3. -> [PersistValue]

    Values to fill the placeholders.

  4. -> ReaderT backend m [a]
#

Execute a raw SQL statement and return its results as a list. If you do not expect a return value, use of rawExecute is recommended.

If you're using Entitys (which is quite likely), then you must use entity selection placeholders (double question mark, ??). These ?? placeholders are then replaced for the names of the columns that we need for your entities. You'll receive an error if you don't use the placeholders. Please see the Entitys documentation for more details.

You may put value placeholders (question marks, ?) in your SQL query. These placeholders are then replaced by the values you pass on the second parameter, already correctly escaped. You may want to use toPersistValue to help you constructing the placeholder values.

Since you're giving a raw SQL statement, you don't get any guarantees regarding safety. If rawSql is not able to parse the results of your query back, then an exception is raised. However, most common problems are mitigated by using the entity selection placeholder ??, and you shouldn't see any error at all if you're not using Single.

Some example of rawSql based on this schema:

share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase|
Person
    name String
    age Int Maybe
    deriving Show
BlogPost
    title String
    authorId PersonId
    deriving Show
|]

Examples based on the above schema:

getPerson :: MonadIO m => ReaderT SqlBackend m [Entity Person]
getPerson = rawSql "select ?? from person where name=?" [PersistText "john"]

getAge :: MonadIO m => ReaderT SqlBackend m [Single Int]
getAge = rawSql "select person.age from person where name=?" [PersistText "john"]

getAgeName :: MonadIO m => ReaderT SqlBackend m [(Single Int, Single Text)]
getAgeName = rawSql "select person.age, person.name from person where name=?" [PersistText "john"]

getPersonBlog :: MonadIO m => ReaderT SqlBackend m [(Entity Person, Entity BlogPost)]
getPersonBlog = rawSql "select ??,?? from person,blog_post where person.id = blog_post.author_id" []

Minimal working program for PostgreSQL backend based on the above concepts:

{-# LANGUAGE EmptyDataDecls             #-}
{-# LANGUAGE FlexibleContexts           #-}
{-# LANGUAGE GADTs                      #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses      #-}
{-# LANGUAGE OverloadedStrings          #-}
{-# LANGUAGE QuasiQuotes                #-}
{-# LANGUAGE TemplateHaskell            #-}
{-# LANGUAGE TypeFamilies               #-}

import           Control.Monad.IO.Class  (liftIO)
import           Control.Monad.Logger    (runStderrLoggingT)
import           Database.Persist
import           Control.Monad.Reader
import           Data.Text
import           Database.Persist.Sql
import           Database.Persist.Postgresql
import           Database.Persist.TH

share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase|
Person
    name String
    age Int Maybe
    deriving Show
|]

conn = "host=localhost dbname=new_db user=postgres password=postgres port=5432"

getPerson :: MonadIO m => ReaderT SqlBackend m [Entity Person]
getPerson = rawSql "select ?? from person where name=?" [PersistText "sibi"]

liftSqlPersistMPool y x = liftIO (runSqlPersistMPool y x)

main :: IO ()
main = runStderrLoggingT $ withPostgresqlPool conn 10 $ liftSqlPersistMPool $ do
         runMigration migrateAll
         xs <- getPerson
         liftIO (print xs)
classclass PersistStoreRead backend => PersistUniqueRead backend where
#

Queries against Unique keys (other than the id Key).

Please read the general Persistent documentation to learn how to create Unique keys.

Using this with an Entity without a Unique key leads to undefined behavior. A few of these functions require a single Unique, so using an Entity with multiple Uniques is also undefined. In these cases persistent's goal is to throw an exception as soon as possible, but persistent is still transitioning to that.

SQL backends automatically create uniqueness constraints, but for MongoDB you must manually place a unique index on a field to have a uniqueness constraint.

Methods

  • getBy :: (MonadIO m, PersistRecordBackend record backend) => Unique record -> ReaderT backend m (Maybe (Entity record))

    Get a record by unique key, if available. Returns also the identifier.

    Example usage

    With schema-1 and dataset-1:

    getBySpjName :: MonadIO m  => ReaderT SqlBackend m (Maybe (Entity User))
    getBySpjName = getBy $ UniqueUserName "SPJ"
    mSpjEnt <- getBySpjName

    The above query when applied on dataset-1, will get this entity:

    +----+------+-----+
    | id | name | age |
    +----+------+-----+
    |  1 | SPJ  |  40 |
    +----+------+-----+
  • existsBy :: (MonadIO m, PersistRecordBackend record backend) => Unique record -> ReaderT backend m Bool

    Returns True if a record with this unique key exists, otherwise False.

    Example usage

    With schema-1 and dataset-1:

    existsBySpjName :: MonadIO m  => ReaderT SqlBackend m Bool
    existsBySpjName = existsBy $ UniqueUserName "SPJ"
    spjEntExists <- existsBySpjName

    The above query when applied on dataset-1, will return the value True.

Instances4PersistUniqueRead
typetype PersistQuery a = PersistQueryWrite a
#

A backwards-compatible alias for those that don't care about distinguishing between read and write queries. It signifies the assumption that, by default, a backend can write as well as read.

A backwards-compatible alias for those that don't care about distinguishing between read and write queries. It signifies the assumption that, by default, a backend can write as well as read.

classclass PersistConfig c where
#

Represents a value containing all the configuration options for a specific backend. This abstraction makes it easier to write code that can easily swap backends.

Associated types

Methods

Instances1PersistConfig

Convenience function for getting a free PersistField instance from a type with JSON instances. The JSON parser used will accept JSON values other that object and arrays. So, if your instance serializes the data to a JSON string, this will still work.

Example usage in combination with toPersistValueJSON:

instance PersistField MyData where
  fromPersistValue = fromPersistValueJSON
  toPersistValue = toPersistValueJSON
valuekeyValueEntityToJSON
  1. :: (PersistEntity record, ToJSON record)
  2. => Entity record
  3. -> Value
#

Predefined toJSON. The resulting JSON looks like {"key": 1, "value": {"name": ...}}.

The typical usage is:

instance ToJSON (Entity User) where
    toJSON = keyValueEntityToJSON
valuetabulateEntity
  1. :: PersistEntity record
  2. => forall a. EntityField record a -> a
  3. -> Entity record
#

Construct an Entity record by providing a value for each of the record's fields.

These constructions are equivalent:

entityMattConstructor, entityMattTabulate :: Entity User
entityMattConstructor =
    Entity
        { entityKey = toSqlKey 123
        , entityVal =
            User
                { userName = Matt
                , userAge = 33
                }
        }

entityMattTabulate =
    tabulateEntity $ \case
        UserId ->
            toSqlKey 123
        UserName ->
            Matt
        UserAge ->
            33

This is a specialization of tabulateEntityA, which allows you to construct an Entity by providing an Applicative action for each field instead of a regular function.

newtypenewtype OverflowNatural
#

Prior to persistent-2.11.0, we provided an instance of PersistField for the Natural type. This was in error, because Natural represents an infinite value, and databases don't have reasonable types for this.

The instance for Natural used the Int64 underlying type, which will cause underflow and overflow errors. This type has the exact same code in the instances, and will work seamlessly.

A more appropriate type for this is the Word series of types from Data.Word. These have a bounded size, are guaranteed to be non-negative, and are quite efficient for the database to store.

Instances6Eq, Num, Ord, Show, PersistField, PersistFieldSql
  • Eq OverflowNaturalDefined in persistent-2.14.6.3 · Database.Persist.Class.PersistField
  • Num OverflowNaturalDefined in persistent-2.14.6.3 · Database.Persist.Class.PersistField
  • Ord OverflowNaturalDefined in persistent-2.14.6.3 · Database.Persist.Class.PersistField
  • Show OverflowNaturalDefined in persistent-2.14.6.3 · Database.Persist.Class.PersistField
  • PersistField OverflowNaturalDefined in persistent-2.14.6.3 · Database.Persist.Class.PersistField
  • PersistFieldSql OverflowNaturalDefined in persistent-2.14.6.3 · Database.Persist.Sql.Class

    This type uses the SqlInt64 version, which will exhibit overflow and underflow behavior. Additionally, it permits negative values in the database, which isn't ideal.

valueselectList
  1. :: (MonadIO m, PersistQueryRead backend, PersistRecordBackend record backend)
  2. => [Filter record]
  3. -> [SelectOpt record]
  4. -> ReaderT backend m [Entity record]
#

Returns a [Entity record] corresponding to the filters and options provided.

Filters are constructed using the operators defined in Database.Persist (and re-exported from Database.Persist.Sql). Let's look at some examples:

usersWithAgeOver40 :: SqlPersistT IO [Entity User]
usersWithAgeOver40 =
    selectList [UserAge >=. 40] []

If you provide multiple values in the list, the conditions are ANDed together.

usersWithAgeBetween30And50 :: SqlPersistT IO [Entity User]
usersWithAgeBetween30And50 =
     selectList
         [ UserAge >=. 30
         , UserAge <=. 50
         ]
         []

The second list contains the SelectOpt for a record. We can select the first ten records with LimitTo

firstTenUsers =
    selectList [] [LimitTo 10]

And we can select the second ten users with OffsetBy.

secondTenUsers =
    selectList [] [LimitTo 10, OffsetBy 10]

Warning that LIMIT/OFFSET is bad for pagination!

The type of record can usually be infered from the types of the provided filters and select options. In the previous two examples, though, you'll notice that the select options are polymorphic, applying to any record type. In order to help type inference in such situations, or simply as an enhancement to readability, you might find type application useful, illustrated below.

{-# LANGUAGE TypeApplications #-}
...

firstTenUsers =
    selectList User [] [LimitTo 10]

secondTenUsers =
    selectList User [] [LimitTo 10, OffsetBy 10]

With Asc and Desc, we can provide the field we want to sort on. We can provide multiple sort orders - later ones are used to sort records that are equal on the first field.

newestUsers =
    selectList [] [Desc UserCreatedAt, LimitTo 10]

oldestUsers =
    selectList [] [Asc UserCreatedAt, LimitTo 10]
valueselectSource
  1. :: (PersistQueryRead backend, MonadResource m, PersistRecordBackend record backend, MonadReader backend m)
  2. => [Filter record]
  3. -> [SelectOpt record]
  4. -> ConduitM () (Entity record) m ()
#

Get all records matching the given criterion in the specified order. Returns also the identifiers.

WARNING: This function returns a ConduitM, which suggests that it streams the results. It does not stream results on most backends. If you need streaming, see persistent-pagination for a means of chunking results based on indexed ranges.

classclass HasPersistBackend backend => IsPersistBackend backend where
#

Class which witnesses that backend is essentially the same as BaseBackend backend. That is, they're isomorphic and backend is just some wrapper over BaseBackend backend.

Instances3IsPersistBackend
valuegetEntity
  1. :: (PersistStoreRead backend, PersistRecordBackend e backend, MonadIO m)
  2. => Key e
  3. -> ReaderT backend m (Maybe (Entity e))
#

Like get, but returns the complete Entity.

Example usage

With schema-1 and dataset-1,

getSpjEntity :: MonadIO m => ReaderT SqlBackend m (Maybe (Entity User))
getSpjEntity = getEntity spjId
mSpjEnt <- getSpjEntity

The above query when applied on dataset-1, will get this entity:

+----+------+-----+
| id | name | age |
+----+------+-----+
|  1 | SPJ  |  40 |
+----+------+-----+
valuegetJust
  1. :: (PersistStoreRead backend, PersistRecordBackend record backend, MonadIO m)
  2. => Key record
  3. -> ReaderT backend m record
#

Same as get, but for a non-null (not Maybe) foreign key. Unsafe unless your database is enforcing that the foreign key is valid.

Example usage

With schema-1 and dataset-1,

getJustSpj :: MonadIO m => ReaderT SqlBackend m User
getJustSpj = getJust spjId
spj <- getJust spjId

The above query when applied on dataset-1, will get this record:

+----+------+-----+
| id | name | age |
+----+------+-----+
|  1 | SPJ  |  40 |
+----+------+-----+
getJustUnknown :: MonadIO m => ReaderT SqlBackend m User
getJustUnknown = getJust unknownId

mrx <- getJustUnknown

This just throws an error.

valuegetJustEntity
  1. :: (PersistEntityBackend record ~ BaseBackend backend, MonadIO m, PersistEntity record, PersistStoreRead backend)
  2. => Key record
  3. -> ReaderT backend m (Entity record)
#

Same as getJust, but returns an Entity instead of just the record.

Example usage

With schema-1 and dataset-1,

getJustEntitySpj :: MonadIO m => ReaderT SqlBackend m (Entity User)
getJustEntitySpj = getJustEntity spjId
spjEnt <- getJustEntitySpj

The above query when applied on dataset-1, will get this entity:

+----+------+-----+
| id | name | age |
+----+------+-----+
|  1 | SPJ  |  40 |
+----+------+-----+
valueinsertEntity
  1. :: (PersistStoreWrite backend, PersistRecordBackend e backend, SafeToInsert e, MonadIO m, HasCallStack)
  2. => e
  3. -> ReaderT backend m (Entity e)
#

Like insert, but returns the complete Entity.

Example usage

With schema-1 and dataset-1,

insertHaskellEntity :: MonadIO m => ReaderT SqlBackend m (Entity User)
insertHaskellEntity = insertEntity $ User "Haskell" 81
haskellEnt <- insertHaskellEntity

The above query when applied on dataset-1, will produce this:

+----+---------+-----+
| id |  name   | age |
+----+---------+-----+
|  1 | SPJ     |  40 |
+----+---------+-----+
|  2 | Simon   |  41 |
+----+---------+-----+
|  3 | Haskell |  81 |
+----+---------+-----+
valueinsertRecord
  1. :: (PersistEntityBackend record ~ BaseBackend backend, PersistEntity record, MonadIO m, PersistStoreWrite backend, SafeToInsert record, HasCallStack)
  2. => record
  3. -> ReaderT backend m record
#

Like insertEntity but just returns the record instead of Entity.

Example usage

With schema-1 and dataset-1,

insertDaveRecord :: MonadIO m => ReaderT SqlBackend m User
insertDaveRecord = insertRecord $ User "Dave" 50
dave <- insertDaveRecord

The above query when applied on dataset-1, will produce this:

+-----+------+-----+
|id   |name  |age  |
+-----+------+-----+
|1    |SPJ   |40   |
+-----+------+-----+
|2    |Simon |41   |
+-----+------+-----+
|3    |Dave  |50   |
+-----+------+-----+
valuecheckUnique
  1. :: (MonadIO m, PersistRecordBackend record backend, PersistUniqueRead backend)
  2. => record
  3. -> ReaderT backend m (Maybe (Unique record))
#

Check whether there are any conflicts for unique keys with this entity and existing entities in the database.

Returns Nothing if the entity would be unique, and could thus safely be inserted. on a conflict returns the conflicting key

Example usage

We use schema-1 and dataset-1 here.

This would be Nothing:

mAlanConst <- checkUnique $ User "Alan" 70

While this would be Just because SPJ already exists:

mSpjConst <- checkUnique $ User "SPJ" 60
valuecheckUniqueUpdateable
  1. :: (MonadIO m, PersistRecordBackend record backend, PersistUniqueRead backend)
  2. => Entity record
  3. -> ReaderT backend m (Maybe (Unique record))
#

Check whether there are any conflicts for unique keys with this entity and existing entities in the database.

Returns Nothing if the entity would stay unique, and could thus safely be updated. on a conflict returns the conflicting key

This is similar to checkUnique, except it's useful for updating - when the particular entity already exists, it would normally conflict with itself. This variant ignores those conflicts

Example usage

We use schema-1 and dataset-1 here.

This would be Nothing:

mAlanConst <- checkUnique $ User "Alan" 70

While this would be Just because SPJ already exists:

mSpjConst <- checkUnique $ User "SPJ" 60
valuegetByValue
  1. :: (MonadIO m, PersistUniqueRead backend, PersistRecordBackend record backend, AtLeastOneUniqueKey record)
  2. => record
  3. -> ReaderT backend m (Maybe (Entity record))
#

A modification of getBy, which takes the PersistEntity itself instead of a Unique record. Returns a record matching one of the unique keys. This function makes the most sense on entities with a single Unique constructor.

Example usage

With schema-1 and dataset-1,

getBySpjValue :: MonadIO m => ReaderT SqlBackend m (Maybe (Entity User)) getBySpjValue = getByValue $ User SPJ 999

mSpjEnt <- getBySpjValue

The above query when applied on dataset-1, will get this record:

+----+------+-----+
| id | name | age |
+----+------+-----+
|  1 | SPJ  |  40 |
+----+------+-----+
valueinsertBy
  1. :: (MonadIO m, PersistUniqueWrite backend, PersistRecordBackend record backend, AtLeastOneUniqueKey record, SafeToInsert record)
  2. => record
  3. -> ReaderT backend m (Either (Entity record) (Key record))
#

Insert a value, checking for conflicts with any unique constraints. If a duplicate exists in the database, it is returned as Left. Otherwise, the new 'Key is returned as Right.

Example usage

With schema-2 and dataset-1, we have following lines of code:

l1 <- insertBy $ User "SPJ" 20
l2 <- insertBy $ User "XXX" 41
l3 <- insertBy $ User "SPJ" 40
r1 <- insertBy $ User "XXX" 100

First three lines return Left because there're duplicates in given record's uniqueness constraints. While the last line returns a new key as Right.

valueinsertUniqueEntity
  1. :: (MonadIO m, PersistRecordBackend record backend, PersistUniqueWrite backend, SafeToInsert record)
  2. => record
  3. -> ReaderT backend m (Maybe (Entity record))
#

Like insertEntity, but returns Nothing when the record couldn't be inserted because of a uniqueness constraint.

Example usage

We use schema-2 and dataset-1 here.

insertUniqueSpjEntity :: MonadIO m => ReaderT SqlBackend m (Maybe (Entity User))
insertUniqueSpjEntity = insertUniqueEntity $ User "SPJ" 50
mSpjEnt <- insertUniqueSpjEntity

The above query results Nothing as SPJ already exists.

insertUniqueAlexaEntity :: MonadIO m => ReaderT SqlBackend m (Maybe (Entity User))
insertUniqueAlexaEntity = insertUniqueEntity $ User "Alexa" 3
mAlexaEnt <- insertUniqueSpjEntity

Because there's no such unique keywords of the given record, the above query when applied on dataset-1, will produce this:

+----+-------+-----+
| id | name  | age |
+----+-------+-----+
|  1 | SPJ   |  40 |
+----+-------+-----+
|  2 | Simon |  41 |
+----+-------+-----+
|  3 | Alexa |   3 |
+----+-------+-----+
valueonlyUnique
  1. :: (MonadIO m, PersistUniqueWrite backend, PersistRecordBackend record backend, OnlyOneUniqueKey record)
  2. => record
  3. -> ReaderT backend m (Unique record)
#

Return the single unique key for a record.

Example usage

We use shcema-1 and dataset-1 here.

onlySimonConst :: MonadIO m => ReaderT SqlBackend m (Unique User)
onlySimonConst = onlyUnique $ User "Simon" 999
mSimonConst <- onlySimonConst

mSimonConst would be Simon's uniqueness constraint. Note that onlyUnique doesn't work if there're more than two constraints. It will fail with a type error instead.

This returns all of the FieldDef defined for the EntityDef, including those fields that are marked as MigrationOnly (and therefore only present in the database) or SafeToRemove (and a migration will drop the column if it exists in the database).

For all the fields that are present on the Haskell-type, see getEntityFields.

newtypenewtype ConstraintNameDB
#

A ConstraintNameDB represents the datastore-side name that persistent will use for a constraint.

Instances6Eq, Ord, Read, Show, DatabaseName, Lift
datadata Checkmark
#

A Checkmark should be used as a field type whenever a uniqueness constraint should guarantee that a certain kind of record may appear at most once, but other kinds of records may appear any number of times.

NOTE: You need to mark any Checkmark fields as nullable (see the following example).

For example, suppose there's a Location entity that represents where a user has lived:

Location
    user    UserId
    name    Text
    current Checkmark nullable

    UniqueLocation user current

The UniqueLocation constraint allows any number of Inactive Locations to be current. However, there may be at most one current Location per user (i.e., either zero or one per user).

This data type works because of the way that SQL treats NULLable fields within uniqueness constraints. The SQL standard says that NULL values should be considered different, so we represent Inactive as SQL NULL, thus allowing any number of Inactive records. On the other hand, we represent Active as TRUE, so the uniqueness constraint will disallow more than one Active record.

Note: There may be DBMSs that do not respect the SQL standard's treatment of NULL values on uniqueness constraints, please check if this data type works before relying on it.

The SQL BOOLEAN type is used because it's the smallest data type available. Note that we never use FALSE, just TRUE and NULL. Provides the same behavior Maybe () would if () was a valid PersistField.

Constructors

  • Active

    When used on a uniqueness constraint, there may be at most one Active record.

  • Inactive

    When used on a uniqueness constraint, there may be any number of Inactive records.

Instances12Bounded, Enum, Eq, Ord, Read, Show, …
datadata CascadeAction
#

An action that might happen on a deletion or update on a foreign key change.

Instances5Eq, Ord, Read, Show, Lift
datadata EmbedFieldDef
#

An EmbedFieldDef is the same as a FieldDef But it is only used for embeddedFields so it only has data needed for embedding

Instances5Eq, Ord, Read, Show, Lift
datadata FieldCascade
#

This datatype describes how a foreign reference field cascades deletes or updates.

This type is used in both parsing the model definitions and performing migrations. A Nothing in either of the field values means that the user has not specified a CascadeAction. An unspecified CascadeAction is defaulted to Restrict when doing migrations.

Instances5Eq, Ord, Read, Show, Lift
  • Eq FieldCascadeDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Ord FieldCascadeDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Read FieldCascadeDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Show FieldCascadeDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Lift FieldCascadeDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
value(!=.) :: PersistField typ => EntityField v typ -> typ -> Filter v
#

Non-equality check.

Examples
selectSimon :: MonadIO m => ReaderT SqlBackend m [Entity User]
selectSimon = selectList [UserName !=. "SPJ" ] []

The above query when applied on dataset-1, will produce this:

+-----+-----+-----+
|id   |name |age  |
+-----+-----+-----+
|2    |Simon|41   |
+-----+-----+-----+
value(*=.) :: PersistField typ => EntityField v typ -> typ -> Update v
#

Assign a field by multiplication (*=).

Examples
multiplyAge :: MonadIO m => ReaderT SqlBackend m ()
multiplyAge = updateWhere [UserName ==. "SPJ" ] [UserAge *=. 2]

The above query when applied on dataset-1, will produce this:

+-----+-----+--------+
|id   |name |age     |
+-----+-----+--------+
|1    |SPJ  |40 -> 80|
+-----+-----+--------+
|2    |Simon|41      |
+-----+-----+--------+
value(+=.) :: PersistField typ => EntityField v typ -> typ -> Update v
#

Assign a field by addition (+=).

Examples
addAge :: MonadIO m => ReaderT SqlBackend m ()
addAge = updateWhere [UserName ==. "SPJ" ] [UserAge +=. 1]

The above query when applied on dataset-1, will produce this:

+-----+-----+---------+
|id   |name |age      |
+-----+-----+---------+
|1    |SPJ  |40 -> 41 |
+-----+-----+---------+
|2    |Simon|41       |
+-----+-----+---------+
value(-=.) :: PersistField typ => EntityField v typ -> typ -> Update v
#

Assign a field by subtraction (-=).

Examples
subtractAge :: MonadIO m => ReaderT SqlBackend m ()
subtractAge = updateWhere [UserName ==. "SPJ" ] [UserAge -=. 1]

The above query when applied on dataset-1, will produce this:

+-----+-----+---------+
|id   |name |age      |
+-----+-----+---------+
|1    |SPJ  |40 -> 39 |
+-----+-----+---------+
|2    |Simon|41       |
+-----+-----+---------+
value(/<-.) :: PersistField typ => EntityField v typ -> [typ] -> Filter v
#

Check if value is not in given list.

Examples
selectSimon :: MonadIO m => ReaderT SqlBackend m [Entity User]
selectSimon = selectList [UserAge /<-. [40]] []

The above query when applied on dataset-1, will produce this:

+-----+-----+-----+
|id   |name |age  |
+-----+-----+-----+
|2    |Simon|41   |
+-----+-----+-----+
value(/=.) :: PersistField typ => EntityField v typ -> typ -> Update v
#

Assign a field by division (/=).

Examples
divideAge :: MonadIO m => ReaderT SqlBackend m ()
divideAge = updateWhere [UserName ==. "SPJ" ] [UserAge /=. 2]

The above query when applied on dataset-1, will produce this:

+-----+-----+---------+
|id   |name |age      |
+-----+-----+---------+
|1    |SPJ  |40 -> 20 |
+-----+-----+---------+
|2    |Simon|41       |
+-----+-----+---------+
value(<-.) :: PersistField typ => EntityField v typ -> [typ] -> Filter v
#

Check if value is in given list.

Examples
selectUsers :: MonadIO m => ReaderT SqlBackend m [Entity User]
selectUsers = selectList [UserAge <-. [40, 41]] []

The above query when applied on dataset-1, will produce this:

+-----+-----+-----+
|id   |name |age  |
+-----+-----+-----+
|1    |SPJ  |40   |
+-----+-----+-----+
|2    |Simon|41   |
+-----+-----+-----+
selectSPJ :: MonadIO m => ReaderT SqlBackend m [Entity User]
selectSPJ = selectList [UserAge <-. [40]] []

The above query when applied on dataset-1, will produce this:

+-----+-----+-----+
|id   |name |age  |
+-----+-----+-----+
|1    |SPJ  |40   |
+-----+-----+-----+
value(<.) :: PersistField typ => EntityField v typ -> typ -> Filter v
#

Less-than check.

Examples
selectLessAge :: MonadIO m => ReaderT SqlBackend m [Entity User]
selectLessAge = selectList [UserAge <. 41 ] []

The above query when applied on dataset-1, will produce this:

+-----+-----+-----+
|id   |name |age  |
+-----+-----+-----+
|1    |SPJ  |40   |
+-----+-----+-----+
value(<=.) :: PersistField typ => EntityField v typ -> typ -> Filter v
#

Less-than or equal check.

Examples
selectLessEqualAge :: MonadIO m => ReaderT SqlBackend m [Entity User]
selectLessEqualAge = selectList [UserAge <=. 40 ] []

The above query when applied on dataset-1, will produce this:

+-----+-----+-----+
|id   |name |age  |
+-----+-----+-----+
|1    |SPJ  |40   |
+-----+-----+-----+
value(=.) :: PersistField typ => EntityField v typ -> typ -> Update v
#

Assign a field a value.

Examples
updateAge :: MonadIO m => ReaderT SqlBackend m ()
updateAge = updateWhere [UserName ==. "SPJ" ] [UserAge =. 45]

Similar to updateWhere which is shown in the above example you can use other functions present in the module Database.Persist.Class. Note that the first parameter of updateWhere is [Filter val] and second parameter is [Update val]. By comparing this with the type of ==. and =., you can see that they match up in the above usage.

The above query when applied on dataset-1, will produce this:

+-----+-----+--------+
|id   |name |age     |
+-----+-----+--------+
|1    |SPJ  |40 -> 45|
+-----+-----+--------+
|2    |Simon|41      |
+-----+-----+--------+
value(==.) :: PersistField typ => EntityField v typ -> typ -> Filter v
#

Check for equality.

Examples
selectSPJ :: MonadIO m => ReaderT SqlBackend m [Entity User]
selectSPJ = selectList [UserName ==. "SPJ" ] []

The above query when applied on dataset-1, will produce this:

+-----+-----+-----+
|id   |name |age  |
+-----+-----+-----+
|1    |SPJ  |40   |
+-----+-----+-----+
value(>.) :: PersistField typ => EntityField v typ -> typ -> Filter v
#

Greater-than check.

Examples
selectGreaterAge :: MonadIO m => ReaderT SqlBackend m [Entity User]
selectGreaterAge = selectList [UserAge >. 40 ] []

The above query when applied on dataset-1, will produce this:

+-----+-----+-----+
|id   |name |age  |
+-----+-----+-----+
|2    |Simon|41   |
+-----+-----+-----+
value(>=.) :: PersistField typ => EntityField v typ -> typ -> Filter v
#

Greater-than or equal check.

Examples
selectGreaterEqualAge :: MonadIO m => ReaderT SqlBackend m [Entity User]
selectGreaterEqualAge = selectList [UserAge >=. 41 ] []

The above query when applied on dataset-1, will produce this:

+-----+-----+-----+
|id   |name |age  |
+-----+-----+-----+
|2    |Simon|41   |
+-----+-----+-----+
value(||.) :: [Filter v] -> [Filter v] -> [Filter v]
#

The OR of two lists of filters. For example:

selectList
    ([ PersonAge >. 25
     , PersonAge <. 30 ] ||.
     [ PersonIncome >. 15000
     , PersonIncome <. 25000 ])
    []

will filter records where a person's age is between 25 and 30 or a person's income is between (15000 and 25000).

If you are looking for an (&&.) operator to do (A AND B AND (C OR D)) you can use the (++) operator instead as there is no (&&.). For example:

selectList
    ([ PersonAge >. 25
     , PersonAge <. 30 ] ++
    ([PersonCategory ==. 1] ||.
     [PersonCategory ==. 5]))
    []

will filter records where a person's age is between 25 and 30 and (person's category is either 1 or 5).

newtypenewtype EntityWithPrefix (prefix :: Symbol) record
#

This newtype wrapper is useful when selecting an entity out of the database and you want to provide a prefix to the table being selected.

Consider this raw SQL query:

SELECT ??
FROM my_long_table_name AS mltn
INNER JOIN other_table AS ot
   ON mltn.some_col = ot.other_col
WHERE ...

We don't want to refer to my_long_table_name every time, so we create an alias. If we want to select it, we have to tell the raw SQL quasi-quoter that we expect the entity to be prefixed with some other name.

We can give the above query a type with this, like:

getStuff :: SqlPersistM [EntityWithPrefix "mltn" MyLongTableName]
getStuff = rawSql queryText []

The EntityWithPrefix bit is a boilerplate newtype wrapper, so you can remove it with unPrefix, like this:

getStuff :: SqlPersistM [Entity MyLongTableName]
getStuff = unPrefix @"mltn" <$> rawSql queryText []

The symbol is a "type application" and requires the TypeApplications@ language extension.

Instances1RawSql
classclass RawSql a where
#

Class for data types that may be retrived from a rawSql query.

Methods

Instances66RawSql, …
valueunPrefix :: EntityWithPrefix prefix record -> Entity record
#

A helper function to tell GHC what the EntityWithPrefix prefix should be. This allows you to use a type application to specify the prefix, instead of specifying the etype on the result.

As an example, here's code that uses this:

myQuery :: SqlPersistM [Entity Person]
myQuery = fmap (unPrefix @"p") $ rawSql query []
  where
    query = "SELECT ?? FROM person AS p"

Record of functions to override the default behavior in mkColumns. It is recommended you initialize this with emptyBackendSpecificOverrides and override the default values, so that as new fields are added, your code still compiles.

For added safety, use the getBackendSpecific* and setBackendSpecific* functions, as a breaking change to the record field labels won't be reflected in a major version bump of the library.

An exception indicating that Persistent refused to run some unsafe migrations. Contains a list of pairs where the Bool tracks whether the migration was unsafe (True means unsafe), and the Sql is the sql statement for the migration.

Instances2Show, Exception
  • Show PersistUnsafeMigrationExceptionDefined in persistent-2.14.6.3 · Database.Persist.Sql.Migration

    This Show instance renders an error message suitable for printing to the console. This is a little dodgy, but since GHC uses Show instances when displaying uncaught exceptions, we have little choice.

  • Exception PersistUnsafeMigrationExceptionDefined in persistent-2.14.6.3 · Database.Persist.Sql.Migration
valueaddMigration
  1. :: Bool

    Is the migration unsafe to run? (eg a destructive or non-idempotent update on the schema). If True, the migration is *unsafe*, and will need to be run manually later. If False, the migration is *safe*, and can be run any number of times.

  2. -> Sql

    A Text value representing the command to run on the database.

  3. -> Migration
#

Add a migration to the migration plan.

Same as runMigration, but returns a list of the SQL commands executed instead of printing them to stderr.

This function silences the migration by remapping stderr. As a result, it is not thread-safe and can clobber output from other parts of the program. This implementation method was chosen to also silence postgresql migration output on stderr, but is not recommended!

Run an action against the database during a migration. Can be useful for eg creating Postgres extensions:

runSqlCommand $ rawExecute "CREATE EXTENSION IF NOT EXISTS "uuid-ossp";" []
valueacquireSqlConn :: (MonadReader backend m, BackendCompatible SqlBackend backend) => m (Acquire backend)
#

Starts a new transaction on the connection. When the acquired connection is released the transaction is committed and the connection returned to the pool.

Upon an exception the transaction is rolled back and the connection destroyed.

This is equivalent to runSqlConn but does not incur the MonadUnliftIO constraint, meaning it can be used within, for example, a Conduit pipeline.

valuerunSqlPool
  1. :: (MonadUnliftIO m, BackendCompatible SqlBackend backend)
  2. => ReaderT backend m a
  3. -> Pool backend
  4. -> m a
#

Get a connection from the pool, run the given action, and then return the connection to the pool.

This function performs the given action in a transaction. If an exception occurs during the action, then the transaction is rolled back.

Note: This function previously timed out after 2 seconds, but this behavior was buggy and caused more problems than it solved. Since version 2.1.2, it performs no timeout checks.

valuerunSqlPoolWithHooks
  1. :: (MonadUnliftIO m, BackendCompatible SqlBackend backend)
  2. => ReaderT backend m a
  3. -> Pool backend
  4. -> Maybe IsolationLevel
  5. -> (backend -> m before)

    Run this action immediately before the action is performed.

  6. -> (backend -> m after)

    Run this action immediately after the action is completed.

  7. -> (backend -> SomeException -> m onException)

    This action is performed when an exception is received. The exception is provided as a convenience - it is rethrown once this cleanup function is complete.

  8. -> m a
#

This function is how runSqlPool and runSqlPoolNoTransaction are defined. In addition to the action to be performed and the Pool of conections to use, we give you the opportunity to provide three actions - initialize, afterwards, and onException.

valuewithSqlConn
  1. :: (MonadUnliftIO m, MonadLoggerIO m, BackendCompatible SqlBackend backend)
  2. => LogFunc -> IO backend
  3. -> backend -> m a
  4. -> m a
#

Create a connection and run sql queries within it. This function automatically closes the connection on it's completion.

Example usage
{-# LANGUAGE GADTs #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeFamilies#-}
{-# LANGUAGE TemplateHaskell#-}
{-# LANGUAGE QuasiQuotes#-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}

import Control.Monad.IO.Class  (liftIO)
import Control.Monad.Logger
import Conduit
import Database.Persist
import Database.Sqlite
import Database.Persist.Sqlite
import Database.Persist.TH

share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase|
Person
  name String
  age Int Maybe
  deriving Show
|]

openConnection :: LogFunc -> IO SqlBackend
openConnection logfn = do
 conn <- open "/home/sibi/test.db"
 wrapConnection conn logfn

main :: IO ()
main = do
  runNoLoggingT $ runResourceT $ withSqlConn openConnection (\backend ->
                                      flip runSqlConn backend $ do
                                        runMigration migrateAll
                                        insert_ $ Person "John doe" $ Just 35
                                        insert_ $ Person "Divya" $ Just 36
                                        (pers :: [Entity Person]) <- selectList [] []
                                        liftIO $ print pers
                                        return ()
                                     )

On executing it, you get this output:

Migrating: CREATE TABLE "person"("id" INTEGER PRIMARY KEY,"name" VARCHAR NOT NULL,"age" INTEGER NULL)
[Entity {entityKey = PersonKey {unPersonKey = SqlBackendKey {unSqlBackendKey = 1}}, entityVal = Person {personName = "John doe", personAge = Just 35}},Entity {entityKey = PersonKey {unPersonKey = SqlBackendKey {unSqlBackendKey = 2}}, entityVal = Person {personName = "Hema", personAge = Just 36}}]
datadata ColumnReference
#

This value specifies how a field references another table.

Constructors

Instances3Eq, Ord, Show
datadata ConnectionPoolConfig
#

Values to configure a pool of database connections. See Data.Pool for details.

Constructors

Instances1Show
newtypenewtype Single a
#

A single column (see rawSql). Any PersistField may be used here, including PersistValue (which does not do any processing).

Constructors

Instances5Eq, Ord, Read, Show, RawSql
  • Eq a => Eq (Single a)Defined in persistent-2.14.6.3 · Database.Persist.Sql.Types
  • Ord a => Ord (Single a)Defined in persistent-2.14.6.3 · Database.Persist.Sql.Types
  • Read a => Read (Single a)Defined in persistent-2.14.6.3 · Database.Persist.Sql.Types
  • Show a => Show (Single a)Defined in persistent-2.14.6.3 · Database.Persist.Sql.Types
  • PersistField a => RawSql (Single a)Defined in persistent-2.14.6.3 · Database.Persist.Sql.Class
datadata IsolationLevel
#

Please refer to the documentation for the database in question for a full overview of the semantics of the varying isloation levels

Instances5Bounded, Enum, Eq, Ord, Show
  • Bounded IsolationLevelDefined in persistent-2.14.6.3 · Database.Persist.SqlBackend.Internal.IsolationLevel
  • Enum IsolationLevelDefined in persistent-2.14.6.3 · Database.Persist.SqlBackend.Internal.IsolationLevel
  • Eq IsolationLevelDefined in persistent-2.14.6.3 · Database.Persist.SqlBackend.Internal.IsolationLevel
  • Ord IsolationLevelDefined in persistent-2.14.6.3 · Database.Persist.SqlBackend.Internal.IsolationLevel
  • Show IsolationLevelDefined in persistent-2.14.6.3 · Database.Persist.SqlBackend.Internal.IsolationLevel

Commit the current transaction and begin a new one. This is used when a transaction commit is required within the context of runSqlConn (which brackets its provided action with a transaction begin/commit pair).

Deprecated. The mpsGeneric function adds a considerable amount of overhead and complexity to the library without bringing significant benefit. We would like to remove it. If you require this feature, please comment on the linked GitHub issue, and we'll either keep it around, or we can figure out a nicer way to solve your problem.Github: https://github.com/yesodweb/persistent/issues/1204

Create generic types that can be used with multiple backends. Good for reusable code, but makes error messages harder to understand. Default: False.

Which database backend we're using. This type is used for the PersistEntityBackend associated type in the entities that are generated.

If the mpsGeneric value is set to True, then this type is used for the non-Generic type alias. The data and type will be named:

data ModelGeneric backend = Model { ... }

And, for convenience's sake, we provide a type alias:

type Model = ModelGeneric $(the type you give here)

Should we generate composite key accessors in the correct CamelCase style.

If the mpsCamelCaseCompositeKeySelector value is set to False, then the field part of the accessor starts with the lowercase. This is a legacy style.

data Key CompanyUser = CompanyUserKey
  { companyUserKeycompanyId :: CompanyId
  , companyUserKeyuserId :: UserId
  }

If the mpsCamelCaseCompositeKeySelector value is set to True, then field accessors are generated in CamelCase style.

data Key CompanyUser = CompanyUserKey
  { companyUserKeyCompanyId :: CompanyId
  , companyUserKeyUserId :: UserId
  }

Customise the Constraint names using the entity and field name. The result should be a valid haskell type (start with an upper cased letter).

Default: appends entity and field

Note: this setting is ignored if mpsPrefixFields is set to False.

Customise the field accessors and lens names using the entity and field name. Both arguments are upper cased.

Default: appends entity and field.

Note: this setting is ignored if mpsPrefixFields is set to False.

familydata family BackendKey backend
#
Instances72Bounded, Enum, Eq, Integral, Num, Ord, …
classclass (PersistField (Key record), ToJSON (Key record), FromJSON (Key record), Show (Key record), Read (Key record), Eq (Key record), Ord (Key record)) => PersistEntity record where
#

Persistent serialized Haskell records to the database. A Database Entity (A row in SQL, a document in MongoDB, etc) corresponds to a Key plus a Haskell record.

For every Haskell record type stored in the database there is a corresponding PersistEntity instance. An instance of PersistEntity contains meta-data for the record. PersistEntity also helps abstract over different record types. That way the same query interface can return a PersistEntity, with each query returning different types of Haskell records.

Some advanced type system capabilities are used to make this process type-safe. Persistent users usually don't need to understand the class associated data and functions.

Associated types

  • type family PersistEntityBackend record

    Persistent allows multiple different backends (databases).

  • data family Key record

    By default, a backend will automatically generate the key Instead you can specify a Primary key made up of unique values.

  • data family EntityField record :: Type -> Type

    An EntityField is parameterised by the Haskell record it belongs to and the additional type of that field.

    As of persistent-2.11.0.0, it's possible to use the OverloadedLabels language extension to refer to EntityField values polymorphically. See the documentation on SymbolToField for more information.

  • data family Unique record

    Unique keys besides the Key.

Methods

Instances122PersistEntity, …
classclass (Show (BackendKey backend), Read (BackendKey backend), Eq (BackendKey backend), Ord (BackendKey backend), PersistStoreRead backend, PersistField (BackendKey backend), ToJSON (BackendKey backend), FromJSON (BackendKey backend)) => PersistStoreWrite backend where
#

Methods

  • insert :: (MonadIO m, PersistRecordBackend record backend, SafeToInsert record) => record -> ReaderT backend m (Key record)

    Create a new record in the database, returning an automatically created key (in SQL an auto-increment id).

    Example usage

    Using schema-1 and dataset-1, let's insert a new user John.

    insertJohn :: MonadIO m => ReaderT SqlBackend m (Key User)
    insertJohn = insert $ User "John" 30
    johnId <- insertJohn

    The above query when applied on dataset-1, will produce this:

    +-----+------+-----+
    |id   |name  |age  |
    +-----+------+-----+
    |1    |SPJ   |40   |
    +-----+------+-----+
    |2    |Simon |41   |
    +-----+------+-----+
    |3    |John  |30   |
    +-----+------+-----+
  • insert_ :: (MonadIO m, PersistRecordBackend record backend, SafeToInsert record) => record -> ReaderT backend m ()

    Same as insert, but doesn't return a Key.

    Example usage

    with schema-1 and dataset-1,

    insertJohn :: MonadIO m => ReaderT SqlBackend m (Key User)
    insertJohn = insert_ $ User "John" 30

    The above query when applied on dataset-1, will produce this:

    +-----+------+-----+
    |id   |name  |age  |
    +-----+------+-----+
    |1    |SPJ   |40   |
    +-----+------+-----+
    |2    |Simon |41   |
    +-----+------+-----+
    |3    |John  |30   |
    +-----+------+-----+
  • insertMany :: (MonadIO m, PersistRecordBackend record backend, SafeToInsert record) => [record] -> ReaderT backend m [Key record]

    Create multiple records in the database and return their Keys.

    If you don't need the inserted Keys, use insertMany_.

    The MongoDB and PostgreSQL backends insert all records and retrieve their keys in one database query.

    The SQLite and MySQL backends use the slow, default implementation of mapM insert.

    Example usage

    with schema-1 and dataset-1,

    insertUsers :: MonadIO m => ReaderT SqlBackend m [Key User]
    insertUsers = insertMany [User "John" 30, User "Nick" 32, User "Jane" 20]
    userIds <- insertUsers

    The above query when applied on dataset-1, will produce this:

    +-----+------+-----+
    |id   |name  |age  |
    +-----+------+-----+
    |1    |SPJ   |40   |
    +-----+------+-----+
    |2    |Simon |41   |
    +-----+------+-----+
    |3    |John  |30   |
    +-----+------+-----+
    |4    |Nick  |32   |
    +-----+------+-----+
    |5    |Jane  |20   |
    +-----+------+-----+
  • insertMany_ :: (MonadIO m, PersistRecordBackend record backend, SafeToInsert record) => [record] -> ReaderT backend m ()

    Same as insertMany, but doesn't return any Keys.

    The MongoDB, PostgreSQL, SQLite and MySQL backends insert all records in one database query.

    Example usage

    With schema-1 and dataset-1,

    insertUsers_ :: MonadIO m => ReaderT SqlBackend m ()
    insertUsers_ = insertMany_ [User "John" 30, User "Nick" 32, User "Jane" 20]

    The above query when applied on dataset-1, will produce this:

    +-----+------+-----+
    |id   |name  |age  |
    +-----+------+-----+
    |1    |SPJ   |40   |
    +-----+------+-----+
    |2    |Simon |41   |
    +-----+------+-----+
    |3    |John  |30   |
    +-----+------+-----+
    |4    |Nick  |32   |
    +-----+------+-----+
    |5    |Jane  |20   |
    +-----+------+-----+
  • insertEntityMany :: (MonadIO m, PersistRecordBackend record backend) => [Entity record] -> ReaderT backend m ()

    Same as insertMany_, but takes an Entity instead of just a record.

    Useful when migrating data from one entity to another and want to preserve ids.

    The MongoDB, PostgreSQL, SQLite and MySQL backends insert all records in one database query.

    Example usage

    With schema-1 and dataset-1,

    insertUserEntityMany :: MonadIO m => ReaderT SqlBackend m ()
    insertUserEntityMany = insertEntityMany [SnakeEntity, EvaEntity]

    The above query when applied on dataset-1, will produce this:

    +-----+------+-----+
    |id   |name  |age  |
    +-----+------+-----+
    |1    |SPJ   |40   |
    +-----+------+-----+
    |2    |Simon |41   |
    +-----+------+-----+
    |3    |Snake |38   |
    +-----+------+-----+
    |4    |Eva   |38   |
    +-----+------+-----+
  • insertKey :: (MonadIO m, PersistRecordBackend record backend) => Key record -> record -> ReaderT backend m ()

    Create a new record in the database using the given key.

    Example usage

    With schema-1 and dataset-1,

    insertAliceKey :: MonadIO m => Key User -> ReaderT SqlBackend m ()
    insertAliceKey key = insertKey key $ User "Alice" 20
    insertAliceKey $ UserKey {unUserKey = SqlBackendKey {unSqlBackendKey = 3}}

    The above query when applied on dataset-1, will produce this:

    +-----+------+-----+
    |id   |name  |age  |
    +-----+------+-----+
    |1    |SPJ   |40   |
    +-----+------+-----+
    |2    |Simon |41   |
    +-----+------+-----+
    |3    |Alice |20   |
    +-----+------+-----+
  • repsert :: (MonadIO m, PersistRecordBackend record backend) => Key record -> record -> ReaderT backend m ()

    Put the record in the database with the given key. Unlike replace, if a record with the given key does not exist then a new record will be inserted.

    Example usage

    We try to explain upsertBy using schema-1 and dataset-1.

    First, we insert Philip to dataset-1.

    insertPhilip :: MonadIO m => ReaderT SqlBackend m (Key User)
    insertPhilip = insert $ User "Philip" 42
    philipId <- insertPhilip

    This query will produce:

    +-----+------+-----+
    |id   |name  |age  |
    +-----+------+-----+
    |1    |SPJ   |40   |
    +-----+------+-----+
    |2    |Simon |41   |
    +-----+------+-----+
    |3    |Philip|42   |
    +-----+------+-----+
    repsertHaskell :: MonadIO m => Key record -> ReaderT SqlBackend m ()
    repsertHaskell id = repsert id $ User "Haskell" 81
    repsertHaskell philipId

    This query will replace Philip's record with Haskell's one:

    +-----+-----------------+--------+
    |id   |name             |age     |
    +-----+-----------------+--------+
    |1    |SPJ              |40      |
    +-----+-----------------+--------+
    |2    |Simon            |41      |
    +-----+-----------------+--------+
    |3    |Philip -> Haskell|42 -> 81|
    +-----+-----------------+--------+

    repsert inserts the given record if the key doesn't exist.

    repsertXToUnknown :: MonadIO m => ReaderT SqlBackend m ()
    repsertXToUnknown = repsert unknownId $ User "X" 999

    For example, applying the above query to dataset-1 will produce this:

    +-----+------+-----+
    |id   |name  |age  |
    +-----+------+-----+
    |1    |SPJ   |40   |
    +-----+------+-----+
    |2    |Simon |41   |
    +-----+------+-----+
    |3    |X     |999  |
    +-----+------+-----+
  • repsertMany :: (MonadIO m, PersistRecordBackend record backend) => [(Key record, record)] -> ReaderT backend m ()

    Put many entities into the database.

    Batch version of repsert for SQL backends.

    Useful when migrating data from one entity to another and want to preserve ids.

    Example usage

    With schema-1 and dataset-1,

    repsertManyUsers :: MonadIO m =>ReaderT SqlBackend m ()
    repsertManyusers = repsertMany [(simonId, User "Philip" 20), (unknownId999, User "Mr. X" 999)]

    The above query when applied on dataset-1, will produce this:

    +-----+----------------+---------+
    |id   |name            |age      |
    +-----+----------------+---------+
    |1    |SPJ             |40       |
    +-----+----------------+---------+
    |2    |Simon -> Philip |41 -> 20 |
    +-----+----------------+---------+
    |999  |Mr. X           |999      |
    +-----+----------------+---------+
  • replace :: (MonadIO m, PersistRecordBackend record backend) => Key record -> record -> ReaderT backend m ()

    Replace the record in the database with the given key. Note that the result is undefined if such record does not exist, so you must use insertKey or repsert in these cases.

    Example usage

    With schema-1 schama-1 and dataset-1,

    replaceSpj :: MonadIO m => User -> ReaderT SqlBackend m ()
    replaceSpj record = replace spjId record

    The above query when applied on dataset-1, will produce this:

    +-----+------+-----+
    |id   |name  |age  |
    +-----+------+-----+
    |1    |Mike  |45   |
    +-----+------+-----+
    |2    |Simon |41   |
    +-----+------+-----+
  • delete :: (MonadIO m, PersistRecordBackend record backend) => Key record -> ReaderT backend m ()

    Delete a specific record by identifier. Does nothing if record does not exist.

    Example usage

    With schema-1 and dataset-1,

    deleteSpj :: MonadIO m => ReaderT SqlBackend m ()
    deleteSpj = delete spjId

    The above query when applied on dataset-1, will produce this:

    +-----+------+-----+
    |id   |name  |age  |
    +-----+------+-----+
    |2    |Simon |41   |
    +-----+------+-----+
  • update :: (MonadIO m, PersistRecordBackend record backend) => Key record -> [Update record] -> ReaderT backend m ()

    Update individual fields on a specific record.

    Example usage

    With schema-1 and dataset-1,

    updateSpj :: MonadIO m => [Update User] -> ReaderT SqlBackend m ()
    updateSpj updates = update spjId updates
    updateSpj [UserAge +=. 100]

    The above query when applied on dataset-1, will produce this:

    +-----+------+-----+
    |id   |name  |age  |
    +-----+------+-----+
    |1    |SPJ   |140  |
    +-----+------+-----+
    |2    |Simon |41   |
    +-----+------+-----+
  • updateGet :: (MonadIO m, PersistRecordBackend record backend) => Key record -> [Update record] -> ReaderT backend m record

    Update individual fields on a specific record, and retrieve the updated value from the database.

    Note that this function will throw an exception if the given key is not found in the database.

    Example usage

    With schema-1 and dataset-1,

    updateGetSpj :: MonadIO m => [Update User] -> ReaderT SqlBackend m User
    updateGetSpj updates = updateGet spjId updates
    spj <- updateGetSpj [UserAge +=. 100]

    The above query when applied on dataset-1, will produce this:

    +-----+------+-----+
    |id   |name  |age  |
    +-----+------+-----+
    |1    |SPJ   |140  |
    +-----+------+-----+
    |2    |Simon |41   |
    +-----+------+-----+
Instances3PersistStoreWrite
classclass PersistCore backend where
#

Associated types

Instances4PersistCore
familydata family BackendKey backend
#
Instances72Bounded, Enum, Eq, Integral, Num, Ord, …
datadata EntityDef
#

An EntityDef represents the information that persistent knows about an Entity. It uses this information to generate the Haskell datatype, the SQL migrations, and other relevant conversions.

Instances5Eq, Ord, Read, Show, Lift
  • Eq EntityDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Ord EntityDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Read EntityDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Show EntityDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Lift EntityDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
familydata family Key record
#

By default, a backend will automatically generate the key Instead you can specify a Primary key made up of unique values.

Instances1608SymbolToField, Eq, Ord, Read, Show, Generic, …
datadata PersistValue
#

A raw value which can be stored in any backend and can be marshalled to and from a PersistField.

Constructors

Instances13Eq, Ord, Read, Show, NFData, Arbitrary, …
patternpattern PersistDbSpecific :: ByteString -> PersistValue
#

Deprecated. Deprecated since 2.11 because of inconsistent escaping behavior across backends. The Postgres backend escapes these values, while the MySQL backend does not. If you are using this, please switch to PersistLiteral_ and provide a relevant LiteralType for your conversion.

This pattern synonym used to be a data constructor for the PersistValue type. It was changed to be a pattern so that JSON-encoded database values could be parsed into their corresponding values. You should not use this, and instead prefer to pattern match on PersistLiteral_ directly.

If you use this, it will overlap a patern match on the 'PersistLiteral_, PersistLiteral, and PersistLiteralEscaped patterns. If you need to disambiguate between these constructors, pattern match on PersistLiteral_ directly.

typetype PersistStore a = PersistStoreWrite a
#

A backwards-compatible alias for those that don't care about distinguishing between read and write queries. It signifies the assumption that, by default, a backend can write as well as read.

classclass PersistField a where
#

This class teaches Persistent how to take a custom type and marshal it to and from a PersistValue, allowing it to be stored in a database.

Examples
Simple Newtype

You can use newtype to add more type safety/readability to a basis type like ByteString. In these cases, just derive PersistField and PersistFieldSql:

{-# LANGUAGE GeneralizedNewtypeDeriving #-}

newtype HashedPassword = HashedPassword ByteString
  deriving (Eq, Show, PersistField, PersistFieldSql)
Smart Constructor Newtype

In this example, we create a PersistField instance for a newtype following the "Smart Constructor" pattern.

{-# LANGUAGE GeneralizedNewtypeDeriving #-}
import qualified Data.Text as T
import qualified Data.Char as C

-- | An American Social Security Number
newtype SSN = SSN Text
 deriving (Eq, Show, PersistFieldSql)

mkSSN :: Text -> Either Text SSN
mkSSN t = if (T.length t == 9) && (T.all C.isDigit t)
 then Right $ SSN t
 else Left $ "Invalid SSN: " <> t

instance PersistField SSN where
  toPersistValue (SSN t) = PersistText t
  fromPersistValue (PersistText t) = mkSSN t
  -- Handle cases where the database does not give us PersistText
  fromPersistValue x = Left $ "File.hs: When trying to deserialize an SSN: expected PersistText, received: " <> T.pack (show x)

Tips:

  • This file contain dozens of PersistField instances you can look at for examples.

  • Typically custom PersistField instances will only accept a single PersistValue constructor in fromPersistValue.

  • Internal PersistField instances accept a wide variety of PersistValues to accomodate e.g. storing booleans as integers, booleans or strings.

  • If you're making a custom instance and using a SQL database, you'll also need PersistFieldSql to specify the type of the database column.

Instances288PersistField, …
datadata Entity record
#

Datatype that represents an entity, with both its Key and its Haskell record representation.

When using a SQL-based backend (such as SQLite or PostgreSQL), an Entity may take any number of columns depending on how many fields it has. In order to reconstruct your entity on the Haskell side, persistent needs all of your entity columns and in the right order. Note that you don't need to worry about this when using persistent's API since everything is handled correctly behind the scenes.

However, if you want to issue a raw SQL command that returns an Entity, then you have to be careful with the column order. While you could use SELECT Entity.* WHERE ... and that would work most of the time, there are times when the order of the columns on your database is different from the order that persistent expects (for example, if you add a new field in the middle of you entity definition and then use the migration code -- persistent will expect the column to be in the middle, but your DBMS will put it as the last column). So, instead of using a query like the one above, you may use rawSql (from the Database.Persist.Sql module) with its /entity selection placeholder/ (a double question mark ??). Using rawSql the query above must be written as SELECT ?? WHERE ... Then rawSql will replace ?? with the list of all columns that we need from your entity in the right order. If your query returns two entities (i.e. (Entity backend a, Entity backend b)), then you must you use SELECT ??, ?? WHERE ..., and so on.

Constructors

Instances16SymbolToField, Eq, Ord, Read, Show, Generic, …
familydata family EntityField record :: Type -> Type
#

An EntityField is parameterised by the Haskell record it belongs to and the additional type of that field.

As of persistent-2.11.0.0, it's possible to use the OverloadedLabels language extension to refer to EntityField values polymorphically. See the documentation on SymbolToField for more information.

Instances123IsLabel, EntityField, …
familytype family PersistEntityBackend record
#

Persistent allows multiple different backends (databases).

Instances122PersistEntityBackend, …
classclass SafeToInsert a
#

A type class which is used to witness that a type is safe to insert into the database without providing a primary key.

The TemplateHaskell function mkPersist will generate instances of this class for any entity that it works on. If the entity has a default primary key, then it provides a regular instance. If the entity has a Primary natural key, then this works fine. But if the entity has an Id column with no default=, then this does a TypeError and forces the user to use insertKey.

Instances123SafeToInsert, …
classclass SymbolToField (sym :: Symbol) rec typ | sym rec -> typ where
#

This type class is used with the OverloadedLabels extension to provide a more convenient means of using the EntityField type. EntityField definitions are prefixed with the type name to avoid ambiguity, but this ambiguity can result in verbose code.

If you have a table User with a name Text field, then the corresponding EntityField is UserName. With this, we can write #name :: EntityField User Text.

What's more fun is that the type is more general: it's actually #name :: (SymbolToField "name" rec typ) => EntityField rec typ

Which means it is *polymorphic* over the actual record. This allows you to write code that can be generic over the tables, provided they have the right fields.

Methods

Instances372SymbolToField, …
familydata family Unique record
#

Unique keys besides the Key.

Instances126Eq, Show, Unique, …
  • Eq (Unique Ba)Defined in persistent-test-2.13.1.3 · PersistUniqueTest
  • Eq (Unique Fo)Defined in persistent-test-2.13.1.3 · PersistUniqueTest
  • Show (Unique Ba)Defined in persistent-test-2.13.1.3 · PersistUniqueTest
  • Show (Unique Fo)Defined in persistent-test-2.13.1.3 · PersistUniqueTest
  • data Unique AddressDefined in persistent-test-2.13.1.3 · CompositeTest
  • data Unique CitizenDefined in persistent-test-2.13.1.3 · CompositeTest
  • data Unique CitizenAddressDefined in persistent-test-2.13.1.3 · CompositeTest
  • data Unique PrimaryCompositeWithOtherNullableFields
    • PrimaryCompositeWithOtherNullableFieldsPrimaryKey String String
    Defined in persistent-test-2.13.1.3 · CompositeTest
  • data Unique TestChildDefined in persistent-test-2.13.1.3 · CompositeTest
  • data Unique TestParentDefined in persistent-test-2.13.1.3 · CompositeTest
  • data Unique Tweet
    • TweetPrimaryKey Int
    • UniqueTweetId Int
    Defined in persistent-test-2.13.1.3 · CustomPrimaryKeyReferenceTest
  • data Unique TweetUrlDefined in persistent-test-2.13.1.3 · CustomPrimaryKeyReferenceTest
  • data Unique EquivalentTypeDefined in persistent-test-2.13.1.3 · EquivalentTypeTest
  • data Unique EquivalentType2Defined in persistent-test-2.13.1.3 · EquivalentTypeTest
  • data Unique ADefined in persistent-test-2.13.1.3 · ForeignKey
  • data Unique ACompositeDefined in persistent-test-2.13.1.3 · ForeignKey
  • data Unique BDefined in persistent-test-2.13.1.3 · ForeignKey
  • data Unique BCompositeDefined in persistent-test-2.13.1.3 · ForeignKey
  • data Unique BExplicitDefined in persistent-test-2.13.1.3 · ForeignKey
  • data Unique ChainDefined in persistent-test-2.13.1.3 · ForeignKey
  • data Unique Chain2Defined in persistent-test-2.13.1.3 · ForeignKey
  • data Unique Chain3Defined in persistent-test-2.13.1.3 · ForeignKey
  • data Unique ChildDefined in persistent-test-2.13.1.3 · ForeignKey
  • data Unique ChildCompositeDefined in persistent-test-2.13.1.3 · ForeignKey
  • data Unique ChildImplicitDefined in persistent-test-2.13.1.3 · ForeignKey
  • data Unique Parent
    • ParentPrimaryKey Int
    Defined in persistent-test-2.13.1.3 · ForeignKey
  • data Unique ParentComposite
    • ParentCompositePrimaryKey Int Int
    Defined in persistent-test-2.13.1.3 · ForeignKey
  • data Unique ParentImplicitDefined in persistent-test-2.13.1.3 · ForeignKey
  • data Unique SelfReferenced
    • SelfReferencedPrimaryKey Int
    Defined in persistent-test-2.13.1.3 · ForeignKey
  • data Unique SimpleCascadeDefined in persistent-test-2.13.1.3 · ForeignKey
  • data Unique SimpleCascadeChildDefined in persistent-test-2.13.1.3 · ForeignKey
  • data Unique GenTestDefined in persistent-test-2.13.1.3 · GeneratedColumnTestSQL
  • data Unique MigrateTestV1Defined in persistent-test-2.13.1.3 · GeneratedColumnTestSQL
  • data Unique MigrateTestV2Defined in persistent-test-2.13.1.3 · GeneratedColumnTestSQL
  • data Unique TableAnExtremelyFantasticallySuperLongNameChildDefined in persistent-test-2.13.1.3 · LongIdentifierTest
  • data Unique TableAnExtremelyFantasticallySuperLongNameParentDefined in persistent-test-2.13.1.3 · LongIdentifierTest
  • data Unique VaryingLengthsDefined in persistent-test-2.13.1.3 · MigrationColumnLengthTest
  • data Unique IdempotencyDefined in persistent-test-2.13.1.3 · MigrationIdempotencyTest
  • data Unique CustomSqlId
    • CustomSqlIdPrimaryKey Int
    Defined in persistent-test-2.13.1.3 · MigrationTest
  • data Unique SourceDefined in persistent-test-2.13.1.3 · MigrationTest
  • data Unique Source1Defined in persistent-test-2.13.1.3 · MigrationTest
  • data Unique TargetDefined in persistent-test-2.13.1.3 · MigrationTest
  • data Unique Target1Defined in persistent-test-2.13.1.3 · MigrationTest
  • data Unique BaDefined in persistent-test-2.13.1.3 · PersistUniqueTest
  • data Unique FoDefined in persistent-test-2.13.1.3 · PersistUniqueTest
  • data Unique OnlyPrimaryKey
    • OnlyPrimaryKeyPrimaryKey Int
    Defined in persistent-test-2.13.1.3 · PersistUniqueTest
  • data Unique TreeDefined in persistent-test-2.13.1.3 · PersistentTestModels
  • data Unique UserDefined in persistent-test-2.13.1.3 · PersistentTestModelsImports
  • data Unique BarDefined in persistent-test-2.13.1.3 · PrimaryTest
  • data Unique CompositePrimaryDefined in persistent-test-2.13.1.3 · PrimaryTest
  • data Unique FooDefined in persistent-test-2.13.1.3 · PrimaryTest
  • data Unique TreesDefined in persistent-test-2.13.1.3 · PrimaryTest
  • data Unique Wombat
    • WombatPrimaryKey Text
    Defined in persistent-test-2.13.1.3 · TransactionLevelTest
  • data Unique TreeDefined in persistent-test-2.13.1.3 · TreeTest
  • data Unique TestCheckmarkDefined in persistent-test-2.13.1.3 · UniqueTest
  • data Unique TestNonNull
    • UniqueTestNonNull Int
    Defined in persistent-test-2.13.1.3 · UniqueTest
  • data Unique TestNullDefined in persistent-test-2.13.1.3 · UniqueTest
  • data Unique (BlogPostGeneric backend)Defined in persistent-test-2.13.1.3 · CustomPersistFieldTest
  • data Unique (DataTypeTableGeneric backend)Defined in persistent-test-2.13.1.3 · DataTypeTest
  • data Unique (BarGeneric backend)Defined in persistent-test-2.13.1.3 · EmbedOrderTest
  • data Unique (FooGeneric backend)Defined in persistent-test-2.13.1.3 · EmbedOrderTest
  • data Unique (AccountGeneric backend)Defined in persistent-test-2.13.1.3 · EmbedTest
  • data Unique (ContactGeneric backend)Defined in persistent-test-2.13.1.3 · EmbedTest
  • data Unique (EmbedsHasMapGeneric backend)Defined in persistent-test-2.13.1.3 · EmbedTest
  • data Unique (HasArrayWithEntitiesGeneric backend)Defined in persistent-test-2.13.1.3 · EmbedTest
  • data Unique (HasEmbedGeneric backend)Defined in persistent-test-2.13.1.3 · EmbedTest
  • data Unique (HasEmbedsGeneric backend)Defined in persistent-test-2.13.1.3 · EmbedTest
  • data Unique (HasListEmbedGeneric backend)Defined in persistent-test-2.13.1.3 · EmbedTest
  • data Unique (HasListGeneric backend)Defined in persistent-test-2.13.1.3 · EmbedTest
  • data Unique (HasMapGeneric backend)Defined in persistent-test-2.13.1.3 · EmbedTest
  • data Unique (HasNestedListGeneric backend)Defined in persistent-test-2.13.1.3 · EmbedTest
  • data Unique (HasSetEmbedGeneric backend)Defined in persistent-test-2.13.1.3 · EmbedTest
  • data Unique (InListGeneric backend)Defined in persistent-test-2.13.1.3 · EmbedTest
  • data Unique (IntListGeneric backend)Defined in persistent-test-2.13.1.3 · EmbedTest
  • data Unique (ListEmbedGeneric backend)Defined in persistent-test-2.13.1.3 · EmbedTest
  • data Unique (MapIdValueGeneric backend)Defined in persistent-test-2.13.1.3 · EmbedTest
  • data Unique (OnlyNameGeneric backend)Defined in persistent-test-2.13.1.3 · EmbedTest
  • data Unique (ProfileGeneric backend)Defined in persistent-test-2.13.1.3 · EmbedTest
  • data Unique (SelfListGeneric backend)Defined in persistent-test-2.13.1.3 · EmbedTest
  • data Unique (SelfMaybeGeneric backend)Defined in persistent-test-2.13.1.3 · EmbedTest
  • data Unique (UserGeneric backend)Defined in persistent-test-2.13.1.3 · EmbedTest
  • data Unique (EmptyEntityGeneric backend)Defined in persistent-test-2.13.1.3 · EmptyEntityTest
  • data Unique (ARecordGeneric backend)Defined in persistent-test-2.13.1.3 · EntityEmbedTest
  • data Unique (HtmlTableGeneric backend)Defined in persistent-test-2.13.1.3 · HtmlTest
  • data Unique (NumberGeneric backend)Defined in persistent-test-2.13.1.3 · LargeNumberTest
  • data Unique (MaxLenGeneric backend)Defined in persistent-test-2.13.1.3 · MaxLenTest
  • data Unique (MaybeFieldDefEntityGeneric backend)Defined in persistent-test-2.13.1.3 · MaybeFieldDefsTest
  • data Unique (ReferencingGeneric backend)Defined in persistent-test-2.13.1.3 · MigrationOnlyTest
  • data Unique (TwoField1Generic backend)Defined in persistent-test-2.13.1.3 · MigrationOnlyTest
  • data Unique (TwoFieldGeneric backend)Defined in persistent-test-2.13.1.3 · MigrationOnlyTest
  • data Unique (CustomPrefix1Generic backend)Defined in persistent-test-2.13.1.3 · PersistentTestModels
  • data Unique (CustomPrefix2Generic backend)Defined in persistent-test-2.13.1.3 · PersistentTestModels
  • data Unique (CustomPrefixSumGeneric backend)Defined in persistent-test-2.13.1.3 · PersistentTestModels
  • data Unique (DudeWeirdColumnsGeneric backend)Defined in persistent-test-2.13.1.3 · PersistentTestModels
  • data Unique (EmailPTGeneric backend)Defined in persistent-test-2.13.1.3 · PersistentTestModels
  • data Unique (MaybeOwnedPetGeneric backend)Defined in persistent-test-2.13.1.3 · PersistentTestModels
  • data Unique (MutAGeneric backend)Defined in persistent-test-2.13.1.3 · PersistentTestModels
  • data Unique (MutBGeneric backend)Defined in persistent-test-2.13.1.3 · PersistentTestModels
  • data Unique (NeedsPetGeneric backend)Defined in persistent-test-2.13.1.3 · PersistentTestModels
  • data Unique (NoPrefix1Generic backend)Defined in persistent-test-2.13.1.3 · PersistentTestModels
  • data Unique (NoPrefix2Generic backend)Defined in persistent-test-2.13.1.3 · PersistentTestModels
  • data Unique (NoPrefixSumGeneric backend)Defined in persistent-test-2.13.1.3 · PersistentTestModels
  • data Unique (OutdoorPetGeneric backend)Defined in persistent-test-2.13.1.3 · PersistentTestModels
  • data Unique (Person1Generic backend)Defined in persistent-test-2.13.1.3 · PersistentTestModels
  • data Unique (PersonGeneric backend)Defined in persistent-test-2.13.1.3 · PersistentTestModels
  • data Unique (PersonMayGeneric backend)Defined in persistent-test-2.13.1.3 · PersistentTestModels
  • data Unique (PersonMaybeAgeGeneric backend)Defined in persistent-test-2.13.1.3 · PersistentTestModels
  • data Unique (PetGeneric backend)Defined in persistent-test-2.13.1.3 · PersistentTestModels
  • data Unique (RelationshipGeneric backend)Defined in persistent-test-2.13.1.3 · PersistentTestModels
  • data Unique (ReverseFieldOrder a)Defined in persistent-test-2.13.1.3 · PersistentTestModels
  • data Unique (StrictGeneric backend)Defined in persistent-test-2.13.1.3 · PersistentTestModels
  • data Unique (UpsertByGeneric backend)
    • UniqueUpsertBy Text
    • UniqueUpsertByCity Text
    Defined in persistent-test-2.13.1.3 · PersistentTestModels
  • data Unique (UpsertGeneric backend)Defined in persistent-test-2.13.1.3 · PersistentTestModels
  • data Unique (UserPTGeneric backend)Defined in persistent-test-2.13.1.3 · PersistentTestModels
  • data Unique (MenuObjectGeneric backend)Defined in persistent-test-2.13.1.3 · Recursive
  • data Unique (SubTypeGeneric backend)Defined in persistent-test-2.13.1.3 · Recursive
  • data Unique (ForeignIdTableGeneric backend)Defined in persistent-test-2.13.1.3 · RenameTest
  • data Unique (IdTableGeneric backend)Defined in persistent-test-2.13.1.3 · RenameTest
  • data Unique (KeyTableGeneric backend)Defined in persistent-test-2.13.1.3 · RenameTest
  • data Unique (LowerCaseTableGeneric backend)Defined in persistent-test-2.13.1.3 · RenameTest
  • data Unique (RefTableGeneric backend)
    • UniqueRefTable Int
    Defined in persistent-test-2.13.1.3 · RenameTest
  • data Unique (BicycleGeneric backend)Defined in persistent-test-2.13.1.3 · SumTypeTest
  • data Unique (CarGeneric backend)Defined in persistent-test-2.13.1.3 · SumTypeTest
  • data Unique (VehicleGeneric backend)Defined in persistent-test-2.13.1.3 · SumTypeTest
  • data Unique (TypeLitFieldDefsLabelledGeneric backend)Defined in persistent-test-2.13.1.3 · TypeLitFieldDefsTest
  • data Unique (TypeLitFieldDefsNumericGeneric backend)Defined in persistent-test-2.13.1.3 · TypeLitFieldDefsTest
valueentityIdToJSON
  1. :: (PersistEntity record, ToJSON record)
  2. => Entity record
  3. -> Value
#

Predefined toJSON. The resulting JSON looks like {"id": 1, "name": ...}.

The typical usage is:

instance ToJSON (Entity User) where
    toJSON = entityIdToJSON
classclass (PersistEntity record, PersistEntityBackend record ~ backend, PersistCore backend) => ToBackendKey backend record where
#

ToBackendKey converts a PersistEntity Key into a BackendKey This can be used by each backend to convert between a Key and a plain Haskell type. For Sql, that is done with toSqlKey and fromSqlKey.

By default, a PersistEntity uses the default BackendKey for its Key and is an instance of ToBackendKey

A Key that instead uses a custom type will not be an instance of ToBackendKey.

Methods

Instances103ToBackendKey, …
classclass PersistEntity record => AtLeastOneUniqueKey record where
#

This class is used to ensure that functions requring at least one unique key are not called with records that have 0 unique keys. The quasiquoter automatically writes working instances for appropriate entities, and generates TypeError instances for records that have 0 unique keys.

Methods

Instances121AtLeastOneUniqueKey, …
typetype MultipleUniqueKeysError ty = ((('Text "The entity " ':<>: 'ShowType ty) ':<>: 'Text " has multiple unique keys.") ':$$: ('Text "The function you are trying to call requires only a single " ':<>: 'Text "unique key.")) ':$$: (('Text "There is probably a variant of the function with 'By' " ':<>: 'Text "appended that will allow you to select a unique key ") ':<>: 'Text "for the operation.")
#

This is an error message. It is used when an entity has multiple unique keys, and the function expects a single unique key.

classclass PersistEntity record => OnlyOneUniqueKey record where
#

This class is used to ensure that upsert is only called on records that have a single Unique key. The quasiquoter automatically generates working instances for appropriate records, and generates TypeError instances for records that have 0 or multiple unique keys.

Methods

Instances121OnlyOneUniqueKey, …

Retrieve the list of FieldDef that makes up the fields of the entity.

This does not return the fields for an Id column or an implicit id. It will return the key columns if you used the Primary syntax for defining the primary key.

This does not return fields that are marked SafeToRemove or MigrationOnly - so it only returns fields that are represented in the Haskell type. If you need those fields, use getEntityFieldsDatabase.

newtypenewtype ConstraintNameHS
#

An ConstraintNameHS represents the Haskell-side name that persistent will use for a constraint.

Instances5Eq, Ord, Read, Show, Lift
newtypenewtype EntityNameHS
#

An EntityNameHS represents the Haskell-side name that persistent will use for an entity.

Instances5Eq, Ord, Read, Show, Lift
newtypenewtype FieldNameDB
#

A FieldNameDB represents the datastore-side name that persistent will use for a field.

Instances6Eq, Ord, Read, Show, DatabaseName, Lift
newtypenewtype FieldNameHS
#

A FieldNameHS represents the Haskell-side name that persistent will use for a field.

Instances5Eq, Ord, Read, Show, Lift
newtypenewtype EntityNameDB
#

An EntityNameDB represents the datastore-side name that persistent will use for an entity.

Instances6Eq, Ord, Read, Show, DatabaseName, Lift
classclass HasPersistBackend backend where
#

Class which allows the plucking of a BaseBackend backend from some larger type. For example, instance HasPersistBackend (SqlReadBackend, Int) where type BaseBackend (SqlReadBackend, Int) = SqlBackend persistBackend = unSqlReadBackend . fst

Associated types

Methods

Instances4HasPersistBackend
familytype family BaseBackend backend
#
Instances4BaseBackend
datadata WhyNullable
#

The reason why a field is nullable is very important. A field that is nullable because of a Maybe tag will have its type changed from A to Maybe A. OTOH, a field that is nullable because of a nullable tag will remain with the same type.

Instances2Eq, Show
  • Eq WhyNullableDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Show WhyNullableDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
datadata CompositeDef
#
Instances5Eq, Ord, Read, Show, Lift
  • Eq CompositeDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Ord CompositeDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Read CompositeDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Show CompositeDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Lift CompositeDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
datadata ReferenceDef
#

There are 3 kinds of references 1) composite (to fields that exist in the record) 2) single field 3) embedded

Constructors

Instances5Eq, Ord, Read, Show, Lift
  • Eq ReferenceDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Ord ReferenceDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Read ReferenceDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Show ReferenceDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Lift ReferenceDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
datadata EntityIdDef
#

The definition for the entity's primary key ID.

Constructors

  • EntityIdField !FieldDef

    The entity has a single key column, and it is a surrogate key - that is, you can't go from rec -> Key rec.

  • EntityIdNaturalKey !CompositeDef

    The entity has a natural key. This means you can write rec -> Key rec because all the key fields are present on the datatype.

    A natural key can have one or more columns.

Instances5Eq, Ord, Read, Show, Lift
  • Eq EntityIdDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Ord EntityIdDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Read EntityIdDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Show EntityIdDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Lift EntityIdDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
classclass (PersistUniqueRead backend, PersistStoreWrite backend) => PersistUniqueWrite backend where
#

Some functions in this module (insertUnique, insertBy, and replaceUnique) first query the unique indexes to check for conflicts. You could instead optimistically attempt to perform the operation (e.g. replace instead of replaceUnique). However,

  • there is some fragility to trying to catch the correct exception and determing the column of failure;

  • an exception will automatically abort the current SQL transaction.

Methods

  • deleteBy :: (MonadIO m, PersistRecordBackend record backend) => Unique record -> ReaderT backend m ()

    Delete a specific record by unique key. Does nothing if no record matches.

    Example usage

    With schema-1 and dataset-1,

    deleteBySpjName :: MonadIO m => ReaderT SqlBackend m ()
    deleteBySpjName = deleteBy UniqueUserName "SPJ"

    The above query when applied on dataset-1, will produce this:

    +-----+------+-----+
    |id   |name  |age  |
    +-----+------+-----+
    |2    |Simon |41   |
    +-----+------+-----+
  • insertUnique :: (MonadIO m, PersistRecordBackend record backend, SafeToInsert record) => record -> ReaderT backend m (Maybe (Key record))

    Like insert, but returns Nothing when the record couldn't be inserted because of a uniqueness constraint.

    Example usage

    With schema-1 and dataset-1, we try to insert the following two records:

    linusId <- insertUnique $ User "Linus" 48
    spjId   <- insertUnique $ User "SPJ" 90
    +-----+------+-----+
    |id   |name  |age  |
    +-----+------+-----+
    |1    |SPJ   |40   |
    +-----+------+-----+
    |2    |Simon |41   |
    +-----+------+-----+
    |3    |Linus |48   |
    +-----+------+-----+

    Linus's record was inserted to dataset-1, while SPJ wasn't because SPJ already exists in dataset-1.

  • insertUnique_ :: (MonadIO m, PersistRecordBackend record backend, SafeToInsert record) => record -> ReaderT backend m (Maybe ())

    Same as insertUnique but doesn't return a Key.

    Example usage

    With schema-1 and dataset-1, we try to insert the following two records:

    linusId <- insertUnique_ $ User "Linus" 48
    spjId   <- insertUnique_ $ User "SPJ" 90
    +-----+------+-----+
    |id   |name  |age  |
    +-----+------+-----+
    |1    |SPJ   |40   |
    +-----+------+-----+
    |2    |Simon |41   |
    +-----+------+-----+
    |3    |Linus |48   |
    +-----+------+-----+

    Linus's record was inserted to dataset-1, while SPJ wasn't because SPJ already exists in dataset-1.

  • upsert :: (MonadIO m, PersistRecordBackend record backend, OnlyOneUniqueKey record, SafeToInsert record) => record -> [Update record] -> ReaderT backend m (Entity record)

    Update based on a uniqueness constraint or insert:

    • insert the new record if it does not exist;

    • If the record exists (matched via it's uniqueness constraint), then update the existing record with the parameters which is passed on as list to the function.

    Example usage

    First, we try to explain upsert using schema-1 and dataset-1.

    upsertSpj :: MonadIO m => [Update User] -> ReaderT SqlBackend m (Maybe (Entity User))
    upsertSpj updates = upsert (User "SPJ" 999) updates
    mSpjEnt <- upsertSpj [UserAge +=. 15]

    The above query when applied on dataset-1, will produce this:

    +-----+-----+--------+
    |id   |name |age     |
    +-----+-----+--------+
    |1    |SPJ  |40 -> 55|
    +-----+-----+--------+
    |2    |Simon|41      |
    +-----+-----+--------+
    upsertX :: MonadIO m => [Update User] -> ReaderT SqlBackend m (Maybe (Entity User))
    upsertX updates = upsert (User "X" 999) updates
    mXEnt <- upsertX [UserAge +=. 15]

    The above query when applied on dataset-1, will produce this:

    +-----+-----+--------+
    |id   |name |age     |
    +-----+-----+--------+
    |1    |SPJ  |40      |
    +-----+-----+--------+
    |2    |Simon|41      |
    +-----+-----+--------+
    |3    |X    |999     |
    +-----+-----+--------+

    Next, what if the schema has two uniqueness constraints? Let's check it out using schema-2:

    mSpjEnt <- upsertSpj [UserAge +=. 15]

    This fails with a compile-time type error alerting us to the fact that this record has multiple unique keys, and suggests that we look for upsertBy to select the unique key we want.

  • upsertBy :: (MonadIO m, PersistRecordBackend record backend, SafeToInsert record) => Unique record -> record -> [Update record] -> ReaderT backend m (Entity record)

    Update based on a given uniqueness constraint or insert:

    • insert the new record if it does not exist;

    • update the existing record that matches the given uniqueness constraint.

    Example usage

    We try to explain upsertBy using schema-2 and dataset-1.

    upsertBySpjName :: MonadIO m => User -> [Update User] -> ReaderT SqlBackend m (Entity User)
    upsertBySpjName record updates = upsertBy (UniqueUserName "SPJ") record updates
    mSpjEnt <- upsertBySpjName (Person "X" 999) [PersonAge += .15]

    The above query will alter dataset-1 to:

    +-----+-----+--------+
    |id   |name |age     |
    +-----+-----+--------+
    |1    |SPJ  |40 -> 55|
    +-----+-----+--------+
    |2    |Simon|41      |
    +-----+-----+--------+
    upsertBySimonAge :: MonadIO m => User -> [Update User] -> ReaderT SqlBackend m (Entity User)
    upsertBySimonAge record updates = upsertBy (UniqueUserName "SPJ") record updates
    mPhilipEnt <- upsertBySimonAge (User "X" 999) [UserName =. "Philip"]

    The above query will alter dataset-1 to:

    +----+-----------------+-----+
    | id |      name       | age |
    +----+-----------------+-----+
    |  1 | SPJ             |  40 |
    +----+-----------------+-----+
    |  2 | Simon -> Philip |  41 |
    +----+-----------------+-----+
    upsertByUnknownName :: MonadIO m => User -> [Update User] -> ReaderT SqlBackend m (Entity User)
    upsertByUnknownName record updates = upsertBy (UniqueUserName "Unknown") record updates
    mXEnt <- upsertByUnknownName (User "X" 999) [UserAge +=. 15]

    This query will alter dataset-1 to:

    +-----+-----+-----+
    |id   |name |age  |
    +-----+-----+-----+
    |1    |SPJ  |40   |
    +-----+-----+-----+
    |2    |Simon|41   |
    +-----+-----+-----+
    |3    |X    |999  |
    +-----+-----+-----+
  • putMany :: (MonadIO m, PersistRecordBackend record backend, SafeToInsert record) => [record] -> ReaderT backend m ()

    Put many records into db

    • insert new records that do not exist (or violate any unique constraints)

    • replace existing records (matching any unique constraint)

Instances3PersistUniqueWrite
datadata FieldType
#

A FieldType describes a field parsed from the QuasiQuoter and is used to determine the Haskell type in the generated code.

name Text parses into FTTypeCon Nothing Text

name T.Text parses into FTTypeCon (Just T Text)

name (Jsonb User) parses into:

FTApp (FTTypeCon Nothing Jsonb) (FTTypeCon Nothing User)
Instances5Eq, Ord, Read, Show, Lift
  • Eq FieldTypeDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Ord FieldTypeDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Read FieldTypeDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Show FieldTypeDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Lift FieldTypeDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
datadata FieldAttr
#

Attributes that may be attached to fields that can affect migrations and serialization in backend-specific ways.

While we endeavor to, we can't forsee all use cases for all backends, and so FieldAttr is extensible through its constructor FieldAttrOther.

Constructors

  • FieldAttrMaybe

    The Maybe keyword goes after the type. This indicates that the column is nullable, and the generated Haskell code will have a Maybe type for it.

    Example:

    User
        name Text Maybe
    
  • FieldAttrNullable

    This indicates that the column is nullable, but should not have a Maybe type. For this to work out, you need to ensure that the PersistField instance for the type in question can support a PersistNull value.

    data What = NoWhat | Hello Text
    
    instance PersistField What where
        fromPersistValue PersistNull =
            pure NoWhat
        fromPersistValue pv =
            Hello $ fromPersistValue pv
    
    instance PersistFieldSql What where
        sqlType _ = SqlString
    
    User
        what What nullable
    
  • FieldAttrMigrationOnly

    This tag means that the column will not be present on the Haskell code, but will not be removed from the database. Useful to deprecate fields in phases.

    You should set the column to be nullable in the database. Otherwise, inserts won't have values.

    User
        oldName Text MigrationOnly
        newName Text
    
  • FieldAttrSafeToRemove

    A SafeToRemove attribute is not present on the Haskell datatype, and the backend migrations should attempt to drop the column without triggering any unsafe migration warnings.

    Useful after you've used MigrationOnly to remove a column from the database in phases.

    User
        oldName Text SafeToRemove
        newName Text
    
  • FieldAttrNoreference

    This attribute indicates that we should not create a foreign key reference from a column. By default, persistent will try and create a foreign key reference for a column if it can determine that the type of the column is a Key entity or an EntityId and the Entity's name was present in mkPersist.

    This is useful if you want to use the explicit foreign key syntax.

    Post
        title    Text
    
    Comment
        postId   PostId      noreference
        Foreign Post fk_comment_post postId
    
  • FieldAttrReference Text

    This is set to specify precisely the database table the column refers to.

    Post
        title    Text
    
    Comment
        postId   PostId references="post"
    

    You should not need this - persistent should be capable of correctly determining the target table's name. If you do need this, please file an issue describing why.

  • FieldAttrConstraint Text

    Specify a name for the constraint on the foreign key reference for this table.

    Post
        title    Text
    
    Comment
        postId   PostId constraint="my_cool_constraint_name"
    
  • FieldAttrDefault Text

    Specify the default value for a column.

    User
        createdAt    UTCTime     default="NOW()"
    

    Note that a default= attribute does not mean you can omit the value while inserting.

  • FieldAttrSqltype Text

    Specify a custom SQL type for the column. Generally, you should define a custom datatype with a custom PersistFieldSql instance instead of using this.

    User
        uuid     Text    sqltype=UUID
    
  • FieldAttrMaxlen Integer

    Set a maximum length for a column. Useful for VARCHAR and indexes.

    User
        name     Text    maxlen=200
    
        UniqueName name
    
  • FieldAttrSql Text

    Specify the database name of the column.

    User
        blarghle     Int     sql="b_l_a_r_g_h_l_e"
    

    Useful for performing phased migrations, where one column is renamed to another column over time.

  • FieldAttrOther Text

    A grab bag of random attributes that were unrecognized by the parser.

Instances5Eq, Ord, Read, Show, Lift
  • Eq FieldAttrDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Ord FieldAttrDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Read FieldAttrDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Show FieldAttrDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Lift FieldAttrDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
datadata FieldDef
#

A FieldDef represents the inormation that persistent knows about a field of a datatype. This includes information used to parse the field out of the database and what the field corresponds to.

Constructors

Instances5Eq, Ord, Read, Show, Lift
  • Eq FieldDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Ord FieldDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Read FieldDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Show FieldDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Lift FieldDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
classclass (PersistQueryRead backend, PersistStoreWrite backend) => PersistQueryWrite backend where
#

Backends supporting conditional write operations

Methods

Instances3PersistQueryWrite
datadata SqlType
#

A SQL data type. Naming attempts to reflect the underlying Haskell datatypes, eg SqlString instead of SqlVarchar. Different SQL databases may have different translations for these types.

Instances5Eq, Ord, Read, Show, Lift
  • Eq SqlTypeDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Ord SqlTypeDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Read SqlTypeDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Show SqlTypeDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Lift SqlTypeDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
datadata UniqueDef
#

Type for storing the Uniqueness constraint in the Schema. Assume you have the following schema with a uniqueness constraint:

Person
  name String
  age Int
  UniqueAge age

This will be represented as:

UniqueDef
    { uniqueHaskell = ConstraintNameHS (packPTH UniqueAge)
    , uniqueDBName = ConstraintNameDB (packPTH "unique_age")
    , uniqueFields = [(FieldNameHS (packPTH "age"), FieldNameDB (packPTH "age"))]
    , uniqueAttrs = []
    }
Instances5Eq, Ord, Read, Show, Lift
  • Eq UniqueDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Ord UniqueDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Read UniqueDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Show UniqueDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Lift UniqueDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
datadata ForeignDef
#
Instances5Eq, Ord, Read, Show, Lift
  • Eq ForeignDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Ord ForeignDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Read ForeignDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Show ForeignDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Lift ForeignDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
classclass (PersistCore backend, PersistStoreRead backend) => PersistQueryRead backend where
#

Backends supporting conditional read operations.

Methods

Instances4PersistQueryRead
datadata EmbedEntityDef
#

An EmbedEntityDef is the same as an EntityDef But it is only used for fieldReference so it only has data needed for embedding

Instances5Eq, Ord, Read, Show, Lift
datadata LiteralType
#

A type that determines how a backend should handle the literal.

Constructors

  • Escaped

    The accompanying value will be escaped before inserting into the database. This is the correct default choice to use.

  • Unescaped

    The accompanying value will not be escaped when inserting into the database. This is potentially dangerous - use this with care.

  • DbSpecific

    The DbSpecific constructor corresponds to the legacy PersistDbSpecific constructor. We need to keep this around because old databases may have serialized JSON representations that reference this. We don't want to break the ability of a database to load rows.

Instances4Eq, Ord, Read, Show
  • Eq LiteralTypeDefined in persistent-2.14.6.3 · Database.Persist.PersistValue
  • Ord LiteralTypeDefined in persistent-2.14.6.3 · Database.Persist.PersistValue
  • Read LiteralTypeDefined in persistent-2.14.6.3 · Database.Persist.PersistValue
  • Show LiteralTypeDefined in persistent-2.14.6.3 · Database.Persist.PersistValue
classclass (Show (BackendKey backend), Read (BackendKey backend), Eq (BackendKey backend), Ord (BackendKey backend), PersistCore backend, PersistField (BackendKey backend), ToJSON (BackendKey backend), FromJSON (BackendKey backend)) => PersistStoreRead backend where
#

Methods

  • get :: (MonadIO m, PersistRecordBackend record backend) => Key record -> ReaderT backend m (Maybe record)

    Get a record by identifier, if available.

    Example usage

    With schema-1 and dataset-1,

    getSpj :: MonadIO m => ReaderT SqlBackend m (Maybe User)
    getSpj = get spjId
    mspj <- getSpj

    The above query when applied on dataset-1, will get this:

    +------+-----+
    | name | age |
    +------+-----+
    | SPJ  |  40 |
    +------+-----+
  • getMany :: (MonadIO m, PersistRecordBackend record backend) => [Key record] -> ReaderT backend m (Map (Key record) record)

    Get many records by their respective identifiers, if available.

    Example usage

    With schema-1 and dataset-1:

    getUsers :: MonadIO m => ReaderT SqlBackend m (Map (Key User) User)
    getUsers = getMany allkeys
    musers <- getUsers

    The above query when applied on dataset-1, will get these records:

    +----+-------+-----+
    | id | name  | age |
    +----+-------+-----+
    |  1 | SPJ   |  40 |
    +----+-------+-----+
    |  2 | Simon |  41 |
    +----+-------+-----+
Instances4PersistStoreRead
datadata Filter record
#

Filters which are available for select, updateWhere and deleteWhere. Each filter constructor specifies the field being filtered on, the type of comparison applied (equals, not equals, etc) and the argument for the comparison.

Persistent users use combinators to create these.

Note that it's important to be careful about the PersistFilter that you are using, if you use this directly. For example, using the In PersistFilter requires that you have an array- or list-shaped EntityField. It is possible to construct values using this that will create malformed runtime values.

Constructors

classclass BackendCompatible sup sub where
#

This class witnesses that two backend are compatible, and that you can convert from the sub backend into the sup backend. This is similar to the HasPersistBackend and IsPersistBackend classes, but where you don't want to fix the type associated with the PersistEntityBackend of a record.

Generally speaking, where you might have:

foo ::
  ( PersistEntity record
  , PersistEntityBackend record ~ BaseBackend backend
  , IsSqlBackend backend
  )

this can be replaced with:

foo ::
  ( PersistEntity record,
  , PersistEntityBackend record ~ backend
  , BackendCompatible SqlBackend backend
  )

This works for SqlReadBackend because of the instance BackendCompatible SqlBackend SqlReadBackend, without needing to go through the BaseBackend type family.

Likewise, functions that are currently hardcoded to use SqlBackend can be generalized:

-- before:
asdf :: ReaderT SqlBackend m ()
asdf = pure ()

-- after:
asdf' :: BackendCompatible SqlBackend backend => ReaderT backend m ()
asdf' = withCompatibleBackend asdf

Methods

Instances3BackendCompatible
valuewithCompatibleBackend
  1. :: BackendCompatible sup sub
  2. => ReaderT sup m a
  3. -> ReaderT sub m a
#

Run a query against a compatible backend, by projecting the backend

This is a helper for using queries which run against a specific backend type that your backend is compatible with.

classclass PersistStoreRead backend => PersistUniqueRead backend where
#

Queries against Unique keys (other than the id Key).

Please read the general Persistent documentation to learn how to create Unique keys.

Using this with an Entity without a Unique key leads to undefined behavior. A few of these functions require a single Unique, so using an Entity with multiple Uniques is also undefined. In these cases persistent's goal is to throw an exception as soon as possible, but persistent is still transitioning to that.

SQL backends automatically create uniqueness constraints, but for MongoDB you must manually place a unique index on a field to have a uniqueness constraint.

Methods

  • getBy :: (MonadIO m, PersistRecordBackend record backend) => Unique record -> ReaderT backend m (Maybe (Entity record))

    Get a record by unique key, if available. Returns also the identifier.

    Example usage

    With schema-1 and dataset-1:

    getBySpjName :: MonadIO m  => ReaderT SqlBackend m (Maybe (Entity User))
    getBySpjName = getBy $ UniqueUserName "SPJ"
    mSpjEnt <- getBySpjName

    The above query when applied on dataset-1, will get this entity:

    +----+------+-----+
    | id | name | age |
    +----+------+-----+
    |  1 | SPJ  |  40 |
    +----+------+-----+
  • existsBy :: (MonadIO m, PersistRecordBackend record backend) => Unique record -> ReaderT backend m Bool

    Returns True if a record with this unique key exists, otherwise False.

    Example usage

    With schema-1 and dataset-1:

    existsBySpjName :: MonadIO m  => ReaderT SqlBackend m Bool
    existsBySpjName = existsBy $ UniqueUserName "SPJ"
    spjEntExists <- existsBySpjName

    The above query when applied on dataset-1, will return the value True.

Instances4PersistUniqueRead
typetype PersistQuery a = PersistQueryWrite a
#

A backwards-compatible alias for those that don't care about distinguishing between read and write queries. It signifies the assumption that, by default, a backend can write as well as read.

A backwards-compatible alias for those that don't care about distinguishing between read and write queries. It signifies the assumption that, by default, a backend can write as well as read.

classclass PersistConfig c where
#

Represents a value containing all the configuration options for a specific backend. This abstraction makes it easier to write code that can easily swap backends.

Associated types

Methods

Instances1PersistConfig

Convenience function for getting a free PersistField instance from a type with JSON instances. The JSON parser used will accept JSON values other that object and arrays. So, if your instance serializes the data to a JSON string, this will still work.

Example usage in combination with toPersistValueJSON:

instance PersistField MyData where
  fromPersistValue = fromPersistValueJSON
  toPersistValue = toPersistValueJSON
valuekeyValueEntityToJSON
  1. :: (PersistEntity record, ToJSON record)
  2. => Entity record
  3. -> Value
#

Predefined toJSON. The resulting JSON looks like {"key": 1, "value": {"name": ...}}.

The typical usage is:

instance ToJSON (Entity User) where
    toJSON = keyValueEntityToJSON
valuetabulateEntity
  1. :: PersistEntity record
  2. => forall a. EntityField record a -> a
  3. -> Entity record
#

Construct an Entity record by providing a value for each of the record's fields.

These constructions are equivalent:

entityMattConstructor, entityMattTabulate :: Entity User
entityMattConstructor =
    Entity
        { entityKey = toSqlKey 123
        , entityVal =
            User
                { userName = Matt
                , userAge = 33
                }
        }

entityMattTabulate =
    tabulateEntity $ \case
        UserId ->
            toSqlKey 123
        UserName ->
            Matt
        UserAge ->
            33

This is a specialization of tabulateEntityA, which allows you to construct an Entity by providing an Applicative action for each field instead of a regular function.

newtypenewtype OverflowNatural
#

Prior to persistent-2.11.0, we provided an instance of PersistField for the Natural type. This was in error, because Natural represents an infinite value, and databases don't have reasonable types for this.

The instance for Natural used the Int64 underlying type, which will cause underflow and overflow errors. This type has the exact same code in the instances, and will work seamlessly.

A more appropriate type for this is the Word series of types from Data.Word. These have a bounded size, are guaranteed to be non-negative, and are quite efficient for the database to store.

Instances6Eq, Num, Ord, Show, PersistField, PersistFieldSql
  • Eq OverflowNaturalDefined in persistent-2.14.6.3 · Database.Persist.Class.PersistField
  • Num OverflowNaturalDefined in persistent-2.14.6.3 · Database.Persist.Class.PersistField
  • Ord OverflowNaturalDefined in persistent-2.14.6.3 · Database.Persist.Class.PersistField
  • Show OverflowNaturalDefined in persistent-2.14.6.3 · Database.Persist.Class.PersistField
  • PersistField OverflowNaturalDefined in persistent-2.14.6.3 · Database.Persist.Class.PersistField
  • PersistFieldSql OverflowNaturalDefined in persistent-2.14.6.3 · Database.Persist.Sql.Class

    This type uses the SqlInt64 version, which will exhibit overflow and underflow behavior. Additionally, it permits negative values in the database, which isn't ideal.

valueselectList
  1. :: (MonadIO m, PersistQueryRead backend, PersistRecordBackend record backend)
  2. => [Filter record]
  3. -> [SelectOpt record]
  4. -> ReaderT backend m [Entity record]
#

Returns a [Entity record] corresponding to the filters and options provided.

Filters are constructed using the operators defined in Database.Persist (and re-exported from Database.Persist.Sql). Let's look at some examples:

usersWithAgeOver40 :: SqlPersistT IO [Entity User]
usersWithAgeOver40 =
    selectList [UserAge >=. 40] []

If you provide multiple values in the list, the conditions are ANDed together.

usersWithAgeBetween30And50 :: SqlPersistT IO [Entity User]
usersWithAgeBetween30And50 =
     selectList
         [ UserAge >=. 30
         , UserAge <=. 50
         ]
         []

The second list contains the SelectOpt for a record. We can select the first ten records with LimitTo

firstTenUsers =
    selectList [] [LimitTo 10]

And we can select the second ten users with OffsetBy.

secondTenUsers =
    selectList [] [LimitTo 10, OffsetBy 10]

Warning that LIMIT/OFFSET is bad for pagination!

The type of record can usually be infered from the types of the provided filters and select options. In the previous two examples, though, you'll notice that the select options are polymorphic, applying to any record type. In order to help type inference in such situations, or simply as an enhancement to readability, you might find type application useful, illustrated below.

{-# LANGUAGE TypeApplications #-}
...

firstTenUsers =
    selectList User [] [LimitTo 10]

secondTenUsers =
    selectList User [] [LimitTo 10, OffsetBy 10]

With Asc and Desc, we can provide the field we want to sort on. We can provide multiple sort orders - later ones are used to sort records that are equal on the first field.

newestUsers =
    selectList [] [Desc UserCreatedAt, LimitTo 10]

oldestUsers =
    selectList [] [Asc UserCreatedAt, LimitTo 10]
valueselectSource
  1. :: (PersistQueryRead backend, MonadResource m, PersistRecordBackend record backend, MonadReader backend m)
  2. => [Filter record]
  3. -> [SelectOpt record]
  4. -> ConduitM () (Entity record) m ()
#

Get all records matching the given criterion in the specified order. Returns also the identifiers.

WARNING: This function returns a ConduitM, which suggests that it streams the results. It does not stream results on most backends. If you need streaming, see persistent-pagination for a means of chunking results based on indexed ranges.

classclass HasPersistBackend backend => IsPersistBackend backend where
#

Class which witnesses that backend is essentially the same as BaseBackend backend. That is, they're isomorphic and backend is just some wrapper over BaseBackend backend.

Instances3IsPersistBackend
valuegetEntity
  1. :: (PersistStoreRead backend, PersistRecordBackend e backend, MonadIO m)
  2. => Key e
  3. -> ReaderT backend m (Maybe (Entity e))
#

Like get, but returns the complete Entity.

Example usage

With schema-1 and dataset-1,

getSpjEntity :: MonadIO m => ReaderT SqlBackend m (Maybe (Entity User))
getSpjEntity = getEntity spjId
mSpjEnt <- getSpjEntity

The above query when applied on dataset-1, will get this entity:

+----+------+-----+
| id | name | age |
+----+------+-----+
|  1 | SPJ  |  40 |
+----+------+-----+
valuegetJust
  1. :: (PersistStoreRead backend, PersistRecordBackend record backend, MonadIO m)
  2. => Key record
  3. -> ReaderT backend m record
#

Same as get, but for a non-null (not Maybe) foreign key. Unsafe unless your database is enforcing that the foreign key is valid.

Example usage

With schema-1 and dataset-1,

getJustSpj :: MonadIO m => ReaderT SqlBackend m User
getJustSpj = getJust spjId
spj <- getJust spjId

The above query when applied on dataset-1, will get this record:

+----+------+-----+
| id | name | age |
+----+------+-----+
|  1 | SPJ  |  40 |
+----+------+-----+
getJustUnknown :: MonadIO m => ReaderT SqlBackend m User
getJustUnknown = getJust unknownId

mrx <- getJustUnknown

This just throws an error.

valuegetJustEntity
  1. :: (PersistEntityBackend record ~ BaseBackend backend, MonadIO m, PersistEntity record, PersistStoreRead backend)
  2. => Key record
  3. -> ReaderT backend m (Entity record)
#

Same as getJust, but returns an Entity instead of just the record.

Example usage

With schema-1 and dataset-1,

getJustEntitySpj :: MonadIO m => ReaderT SqlBackend m (Entity User)
getJustEntitySpj = getJustEntity spjId
spjEnt <- getJustEntitySpj

The above query when applied on dataset-1, will get this entity:

+----+------+-----+
| id | name | age |
+----+------+-----+
|  1 | SPJ  |  40 |
+----+------+-----+
valueinsertEntity
  1. :: (PersistStoreWrite backend, PersistRecordBackend e backend, SafeToInsert e, MonadIO m, HasCallStack)
  2. => e
  3. -> ReaderT backend m (Entity e)
#

Like insert, but returns the complete Entity.

Example usage

With schema-1 and dataset-1,

insertHaskellEntity :: MonadIO m => ReaderT SqlBackend m (Entity User)
insertHaskellEntity = insertEntity $ User "Haskell" 81
haskellEnt <- insertHaskellEntity

The above query when applied on dataset-1, will produce this:

+----+---------+-----+
| id |  name   | age |
+----+---------+-----+
|  1 | SPJ     |  40 |
+----+---------+-----+
|  2 | Simon   |  41 |
+----+---------+-----+
|  3 | Haskell |  81 |
+----+---------+-----+
valueinsertRecord
  1. :: (PersistEntityBackend record ~ BaseBackend backend, PersistEntity record, MonadIO m, PersistStoreWrite backend, SafeToInsert record, HasCallStack)
  2. => record
  3. -> ReaderT backend m record
#

Like insertEntity but just returns the record instead of Entity.

Example usage

With schema-1 and dataset-1,

insertDaveRecord :: MonadIO m => ReaderT SqlBackend m User
insertDaveRecord = insertRecord $ User "Dave" 50
dave <- insertDaveRecord

The above query when applied on dataset-1, will produce this:

+-----+------+-----+
|id   |name  |age  |
+-----+------+-----+
|1    |SPJ   |40   |
+-----+------+-----+
|2    |Simon |41   |
+-----+------+-----+
|3    |Dave  |50   |
+-----+------+-----+
valuecheckUnique
  1. :: (MonadIO m, PersistRecordBackend record backend, PersistUniqueRead backend)
  2. => record
  3. -> ReaderT backend m (Maybe (Unique record))
#

Check whether there are any conflicts for unique keys with this entity and existing entities in the database.

Returns Nothing if the entity would be unique, and could thus safely be inserted. on a conflict returns the conflicting key

Example usage

We use schema-1 and dataset-1 here.

This would be Nothing:

mAlanConst <- checkUnique $ User "Alan" 70

While this would be Just because SPJ already exists:

mSpjConst <- checkUnique $ User "SPJ" 60
valuecheckUniqueUpdateable
  1. :: (MonadIO m, PersistRecordBackend record backend, PersistUniqueRead backend)
  2. => Entity record
  3. -> ReaderT backend m (Maybe (Unique record))
#

Check whether there are any conflicts for unique keys with this entity and existing entities in the database.

Returns Nothing if the entity would stay unique, and could thus safely be updated. on a conflict returns the conflicting key

This is similar to checkUnique, except it's useful for updating - when the particular entity already exists, it would normally conflict with itself. This variant ignores those conflicts

Example usage

We use schema-1 and dataset-1 here.

This would be Nothing:

mAlanConst <- checkUnique $ User "Alan" 70

While this would be Just because SPJ already exists:

mSpjConst <- checkUnique $ User "SPJ" 60
valuegetByValue
  1. :: (MonadIO m, PersistUniqueRead backend, PersistRecordBackend record backend, AtLeastOneUniqueKey record)
  2. => record
  3. -> ReaderT backend m (Maybe (Entity record))
#

A modification of getBy, which takes the PersistEntity itself instead of a Unique record. Returns a record matching one of the unique keys. This function makes the most sense on entities with a single Unique constructor.

Example usage

With schema-1 and dataset-1,

getBySpjValue :: MonadIO m => ReaderT SqlBackend m (Maybe (Entity User)) getBySpjValue = getByValue $ User SPJ 999

mSpjEnt <- getBySpjValue

The above query when applied on dataset-1, will get this record:

+----+------+-----+
| id | name | age |
+----+------+-----+
|  1 | SPJ  |  40 |
+----+------+-----+
valueinsertBy
  1. :: (MonadIO m, PersistUniqueWrite backend, PersistRecordBackend record backend, AtLeastOneUniqueKey record, SafeToInsert record)
  2. => record
  3. -> ReaderT backend m (Either (Entity record) (Key record))
#

Insert a value, checking for conflicts with any unique constraints. If a duplicate exists in the database, it is returned as Left. Otherwise, the new 'Key is returned as Right.

Example usage

With schema-2 and dataset-1, we have following lines of code:

l1 <- insertBy $ User "SPJ" 20
l2 <- insertBy $ User "XXX" 41
l3 <- insertBy $ User "SPJ" 40
r1 <- insertBy $ User "XXX" 100

First three lines return Left because there're duplicates in given record's uniqueness constraints. While the last line returns a new key as Right.

valueinsertUniqueEntity
  1. :: (MonadIO m, PersistRecordBackend record backend, PersistUniqueWrite backend, SafeToInsert record)
  2. => record
  3. -> ReaderT backend m (Maybe (Entity record))
#

Like insertEntity, but returns Nothing when the record couldn't be inserted because of a uniqueness constraint.

Example usage

We use schema-2 and dataset-1 here.

insertUniqueSpjEntity :: MonadIO m => ReaderT SqlBackend m (Maybe (Entity User))
insertUniqueSpjEntity = insertUniqueEntity $ User "SPJ" 50
mSpjEnt <- insertUniqueSpjEntity

The above query results Nothing as SPJ already exists.

insertUniqueAlexaEntity :: MonadIO m => ReaderT SqlBackend m (Maybe (Entity User))
insertUniqueAlexaEntity = insertUniqueEntity $ User "Alexa" 3
mAlexaEnt <- insertUniqueSpjEntity

Because there's no such unique keywords of the given record, the above query when applied on dataset-1, will produce this:

+----+-------+-----+
| id | name  | age |
+----+-------+-----+
|  1 | SPJ   |  40 |
+----+-------+-----+
|  2 | Simon |  41 |
+----+-------+-----+
|  3 | Alexa |   3 |
+----+-------+-----+
valueonlyUnique
  1. :: (MonadIO m, PersistUniqueWrite backend, PersistRecordBackend record backend, OnlyOneUniqueKey record)
  2. => record
  3. -> ReaderT backend m (Unique record)
#

Return the single unique key for a record.

Example usage

We use shcema-1 and dataset-1 here.

onlySimonConst :: MonadIO m => ReaderT SqlBackend m (Unique User)
onlySimonConst = onlyUnique $ User "Simon" 999
mSimonConst <- onlySimonConst

mSimonConst would be Simon's uniqueness constraint. Note that onlyUnique doesn't work if there're more than two constraints. It will fail with a type error instead.

This returns all of the FieldDef defined for the EntityDef, including those fields that are marked as MigrationOnly (and therefore only present in the database) or SafeToRemove (and a migration will drop the column if it exists in the database).

For all the fields that are present on the Haskell-type, see getEntityFields.

newtypenewtype ConstraintNameDB
#

A ConstraintNameDB represents the datastore-side name that persistent will use for a constraint.

Instances6Eq, Ord, Read, Show, DatabaseName, Lift
datadata Checkmark
#

A Checkmark should be used as a field type whenever a uniqueness constraint should guarantee that a certain kind of record may appear at most once, but other kinds of records may appear any number of times.

NOTE: You need to mark any Checkmark fields as nullable (see the following example).

For example, suppose there's a Location entity that represents where a user has lived:

Location
    user    UserId
    name    Text
    current Checkmark nullable

    UniqueLocation user current

The UniqueLocation constraint allows any number of Inactive Locations to be current. However, there may be at most one current Location per user (i.e., either zero or one per user).

This data type works because of the way that SQL treats NULLable fields within uniqueness constraints. The SQL standard says that NULL values should be considered different, so we represent Inactive as SQL NULL, thus allowing any number of Inactive records. On the other hand, we represent Active as TRUE, so the uniqueness constraint will disallow more than one Active record.

Note: There may be DBMSs that do not respect the SQL standard's treatment of NULL values on uniqueness constraints, please check if this data type works before relying on it.

The SQL BOOLEAN type is used because it's the smallest data type available. Note that we never use FALSE, just TRUE and NULL. Provides the same behavior Maybe () would if () was a valid PersistField.

Constructors

  • Active

    When used on a uniqueness constraint, there may be at most one Active record.

  • Inactive

    When used on a uniqueness constraint, there may be any number of Inactive records.

Instances12Bounded, Enum, Eq, Ord, Read, Show, …
datadata CascadeAction
#

An action that might happen on a deletion or update on a foreign key change.

Instances5Eq, Ord, Read, Show, Lift
datadata EmbedFieldDef
#

An EmbedFieldDef is the same as a FieldDef But it is only used for embeddedFields so it only has data needed for embedding

Instances5Eq, Ord, Read, Show, Lift
datadata FieldCascade
#

This datatype describes how a foreign reference field cascades deletes or updates.

This type is used in both parsing the model definitions and performing migrations. A Nothing in either of the field values means that the user has not specified a CascadeAction. An unspecified CascadeAction is defaulted to Restrict when doing migrations.

Instances5Eq, Ord, Read, Show, Lift
  • Eq FieldCascadeDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Ord FieldCascadeDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Read FieldCascadeDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Show FieldCascadeDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
  • Lift FieldCascadeDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
value(!=.) :: PersistField typ => EntityField v typ -> typ -> Filter v
#

Non-equality check.

Examples
selectSimon :: MonadIO m => ReaderT SqlBackend m [Entity User]
selectSimon = selectList [UserName !=. "SPJ" ] []

The above query when applied on dataset-1, will produce this:

+-----+-----+-----+
|id   |name |age  |
+-----+-----+-----+
|2    |Simon|41   |
+-----+-----+-----+
value(*=.) :: PersistField typ => EntityField v typ -> typ -> Update v
#

Assign a field by multiplication (*=).

Examples
multiplyAge :: MonadIO m => ReaderT SqlBackend m ()
multiplyAge = updateWhere [UserName ==. "SPJ" ] [UserAge *=. 2]

The above query when applied on dataset-1, will produce this:

+-----+-----+--------+
|id   |name |age     |
+-----+-----+--------+
|1    |SPJ  |40 -> 80|
+-----+-----+--------+
|2    |Simon|41      |
+-----+-----+--------+
value(+=.) :: PersistField typ => EntityField v typ -> typ -> Update v
#

Assign a field by addition (+=).

Examples
addAge :: MonadIO m => ReaderT SqlBackend m ()
addAge = updateWhere [UserName ==. "SPJ" ] [UserAge +=. 1]

The above query when applied on dataset-1, will produce this:

+-----+-----+---------+
|id   |name |age      |
+-----+-----+---------+
|1    |SPJ  |40 -> 41 |
+-----+-----+---------+
|2    |Simon|41       |
+-----+-----+---------+
value(-=.) :: PersistField typ => EntityField v typ -> typ -> Update v
#

Assign a field by subtraction (-=).

Examples
subtractAge :: MonadIO m => ReaderT SqlBackend m ()
subtractAge = updateWhere [UserName ==. "SPJ" ] [UserAge -=. 1]

The above query when applied on dataset-1, will produce this:

+-----+-----+---------+
|id   |name |age      |
+-----+-----+---------+
|1    |SPJ  |40 -> 39 |
+-----+-----+---------+
|2    |Simon|41       |
+-----+-----+---------+
value(/<-.) :: PersistField typ => EntityField v typ -> [typ] -> Filter v
#

Check if value is not in given list.

Examples
selectSimon :: MonadIO m => ReaderT SqlBackend m [Entity User]
selectSimon = selectList [UserAge /<-. [40]] []

The above query when applied on dataset-1, will produce this:

+-----+-----+-----+
|id   |name |age  |
+-----+-----+-----+
|2    |Simon|41   |
+-----+-----+-----+
value(/=.) :: PersistField typ => EntityField v typ -> typ -> Update v
#

Assign a field by division (/=).

Examples
divideAge :: MonadIO m => ReaderT SqlBackend m ()
divideAge = updateWhere [UserName ==. "SPJ" ] [UserAge /=. 2]

The above query when applied on dataset-1, will produce this:

+-----+-----+---------+
|id   |name |age      |
+-----+-----+---------+
|1    |SPJ  |40 -> 20 |
+-----+-----+---------+
|2    |Simon|41       |
+-----+-----+---------+
value(<-.) :: PersistField typ => EntityField v typ -> [typ] -> Filter v
#

Check if value is in given list.

Examples
selectUsers :: MonadIO m => ReaderT SqlBackend m [Entity User]
selectUsers = selectList [UserAge <-. [40, 41]] []

The above query when applied on dataset-1, will produce this:

+-----+-----+-----+
|id   |name |age  |
+-----+-----+-----+
|1    |SPJ  |40   |
+-----+-----+-----+
|2    |Simon|41   |
+-----+-----+-----+
selectSPJ :: MonadIO m => ReaderT SqlBackend m [Entity User]
selectSPJ = selectList [UserAge <-. [40]] []

The above query when applied on dataset-1, will produce this:

+-----+-----+-----+
|id   |name |age  |
+-----+-----+-----+
|1    |SPJ  |40   |
+-----+-----+-----+
value(<.) :: PersistField typ => EntityField v typ -> typ -> Filter v
#

Less-than check.

Examples
selectLessAge :: MonadIO m => ReaderT SqlBackend m [Entity User]
selectLessAge = selectList [UserAge <. 41 ] []

The above query when applied on dataset-1, will produce this:

+-----+-----+-----+
|id   |name |age  |
+-----+-----+-----+
|1    |SPJ  |40   |
+-----+-----+-----+
value(<=.) :: PersistField typ => EntityField v typ -> typ -> Filter v
#

Less-than or equal check.

Examples
selectLessEqualAge :: MonadIO m => ReaderT SqlBackend m [Entity User]
selectLessEqualAge = selectList [UserAge <=. 40 ] []

The above query when applied on dataset-1, will produce this:

+-----+-----+-----+
|id   |name |age  |
+-----+-----+-----+
|1    |SPJ  |40   |
+-----+-----+-----+
value(=.) :: PersistField typ => EntityField v typ -> typ -> Update v
#

Assign a field a value.

Examples
updateAge :: MonadIO m => ReaderT SqlBackend m ()
updateAge = updateWhere [UserName ==. "SPJ" ] [UserAge =. 45]

Similar to updateWhere which is shown in the above example you can use other functions present in the module Database.Persist.Class. Note that the first parameter of updateWhere is [Filter val] and second parameter is [Update val]. By comparing this with the type of ==. and =., you can see that they match up in the above usage.

The above query when applied on dataset-1, will produce this:

+-----+-----+--------+
|id   |name |age     |
+-----+-----+--------+
|1    |SPJ  |40 -> 45|
+-----+-----+--------+
|2    |Simon|41      |
+-----+-----+--------+
value(==.) :: PersistField typ => EntityField v typ -> typ -> Filter v
#

Check for equality.

Examples
selectSPJ :: MonadIO m => ReaderT SqlBackend m [Entity User]
selectSPJ = selectList [UserName ==. "SPJ" ] []

The above query when applied on dataset-1, will produce this:

+-----+-----+-----+
|id   |name |age  |
+-----+-----+-----+
|1    |SPJ  |40   |
+-----+-----+-----+
value(>.) :: PersistField typ => EntityField v typ -> typ -> Filter v
#

Greater-than check.

Examples
selectGreaterAge :: MonadIO m => ReaderT SqlBackend m [Entity User]
selectGreaterAge = selectList [UserAge >. 40 ] []

The above query when applied on dataset-1, will produce this:

+-----+-----+-----+
|id   |name |age  |
+-----+-----+-----+
|2    |Simon|41   |
+-----+-----+-----+
value(>=.) :: PersistField typ => EntityField v typ -> typ -> Filter v
#

Greater-than or equal check.

Examples
selectGreaterEqualAge :: MonadIO m => ReaderT SqlBackend m [Entity User]
selectGreaterEqualAge = selectList [UserAge >=. 41 ] []

The above query when applied on dataset-1, will produce this:

+-----+-----+-----+
|id   |name |age  |
+-----+-----+-----+
|2    |Simon|41   |
+-----+-----+-----+
value(||.) :: [Filter v] -> [Filter v] -> [Filter v]
#

The OR of two lists of filters. For example:

selectList
    ([ PersonAge >. 25
     , PersonAge <. 30 ] ||.
     [ PersonIncome >. 15000
     , PersonIncome <. 25000 ])
    []

will filter records where a person's age is between 25 and 30 or a person's income is between (15000 and 25000).

If you are looking for an (&&.) operator to do (A AND B AND (C OR D)) you can use the (++) operator instead as there is no (&&.). For example:

selectList
    ([ PersonAge >. 25
     , PersonAge <. 30 ] ++
    ([PersonCategory ==. 1] ||.
     [PersonCategory ==. 5]))
    []

will filter records where a person's age is between 25 and 30 and (person's category is either 1 or 5).

valuehspec :: Spec -> IO ()
#

Run a given spec and write a report to stdout. Exit with exitFailure if at least one spec item fails.

Note: hspec handles command-line options and reads config files. This is not always desirable. Use evalSpec and runSpecForest if you need more control over these aspects.

typetype HasCallStack = IP "callStack" CallStack
#

Request a CallStack.

NOTE: The implicit parameter ?callStack :: CallStack is an implementation detail and should not be considered part of the CallStack API, we may decide to change the implementation in the future.

typetype Selector a = a -> Bool
#

A Selector is a predicate; it can simultaneously constrain the type and value of an exception.

example is a type restricted version of id. It can be used to get better error messages on type mismatches.

Compare e.g.

it "exposes some behavior" $ example $ do
  putStrLn

with

it "exposes some behavior" $ do
  putStrLn
valuearound
  1. :: (ActionWith a -> IO ())

    Function provided with an action to run the spec item as argument. It should return the action to actually execute the item.

  2. -> SpecWith a

    Spec to modify

  3. -> Spec
#

Run a custom action before and/or after every spec item, supplying it with an argument obtained via IO.

This is useful for tasks like creating a file handle or similar resource before a test and destroying it after the test.

valuemapSubject :: (b -> a) -> SpecWith a -> SpecWith b
#

Modify the subject under test.

Note that this resembles a contravariant functor on the first type parameter of SpecM. This is because the subject is passed inwards, as an argument to the spec item.

valueit :: (HasCallStack, Example a) => String -> a -> SpecWith (Arg a)
#

The it function creates a spec item.

A spec item consists of:

  • a textual description of a desired behavior

  • an example for that behavior

describe "absolute" $ do
  it "returns a positive number when given a negative number" $
    absolute (-1) == 1

Example a optionally accepts an argument Arg a, which is then given to the test body. This is useful for provisioning resources for a test which are created and cleaned up outside the test itself. See Arg for details.

Note that this function is often on the scene of nasty type errors due to GHC failing to infer the type of do notation in the test body. It can be helpful to use TypeApplications to explicitly specify the intended Example type.

pending can be used to mark a spec item as pending.

If you want to textually specify a behavior but do not have an example yet, use this:

describe "fancyFormatter" $ do
  it "can format text in a way that everyone likes" $
    pending
valuerunIO :: IO r -> SpecM a r
#

Run an IO action while constructing the spec tree.

SpecM is a monad to construct a spec tree, without executing any spec items itself. runIO allows you to run IO actions during this construction phase. The IO action is always run when the spec tree is constructed (e.g. even when --dry-run is specified). If you do not need the result of the IO action to construct the spec tree, beforeAll may be more suitable for your use case.

typetype ActionWith a = a -> IO ()
#

An IO action that expects an argument of type a.

This type is what Examples are ultimately unlifted into for execution.

classclass Example e where
#

A type class for examples, that is to say, test bodies as used in it and similar functions.

Associated types

  • type family Arg e

    The argument type that is needed to run this Example. If Arg is (), no argument is required and the Example can be run as-is.

    The value of Arg is the difference between Test.Hspec.Core.Spec.Spec (aka Test.Hspec.Core.Hspec.SpecWith ()), which can be executed, and Test.Hspec.Core.Spec.SpecWith a, which cannot be executed without turning it into Test.Hspec.Core.Spec.Spec first.

    To supply an argument to examples, use the functions in Test.Hspec.Core.Hooks such as around, before, mapSubject and similar.

Instances8Example, …
  • Example PropertyDefined in hspec-core-2.11.14 · Test.Hspec.Core.QuickCheck · orphan
  • Example BoolDefined in hspec-core-2.11.14 · Test.Hspec.Core.Example
  • Example ResultDefined in hspec-core-2.11.14 · Test.Hspec.Core.Example
  • Example ExpectationDefined in hspec-core-2.11.14 · Test.Hspec.Core.Example
  • Example (a -> Property)Defined in hspec-core-2.11.14 · Test.Hspec.Core.QuickCheck · orphan
  • Example (a -> Bool)Defined in hspec-core-2.11.14 · Test.Hspec.Core.Example
  • Example (a -> Result)Defined in hspec-core-2.11.14 · Test.Hspec.Core.Example
  • Example (a -> Expectation)Defined in hspec-core-2.11.14 · Test.Hspec.Core.Example
familytype family Arg e
#

The argument type that is needed to run this Example. If Arg is (), no argument is required and the Example can be run as-is.

The value of Arg is the difference between Test.Hspec.Core.Spec.Spec (aka Test.Hspec.Core.Hspec.SpecWith ()), which can be executed, and Test.Hspec.Core.Spec.SpecWith a, which cannot be executed without turning it into Test.Hspec.Core.Spec.Spec first.

To supply an argument to examples, use the functions in Test.Hspec.Core.Hooks such as around, before, mapSubject and similar.

Instances8Arg, …
  • type Arg Property = ()Defined in hspec-core-2.11.14 · Test.Hspec.Core.QuickCheck · orphan
  • type Arg Bool = ()Defined in hspec-core-2.11.14 · Test.Hspec.Core.Example
  • type Arg Result = ()Defined in hspec-core-2.11.14 · Test.Hspec.Core.Example
  • type Arg Expectation = ()Defined in hspec-core-2.11.14 · Test.Hspec.Core.Example
  • type Arg (a -> Property) = aDefined in hspec-core-2.11.14 · Test.Hspec.Core.QuickCheck · orphan
  • type Arg (a -> Bool) = aDefined in hspec-core-2.11.14 · Test.Hspec.Core.Example
  • type Arg (a -> Result) = aDefined in hspec-core-2.11.14 · Test.Hspec.Core.Example
  • type Arg (a -> Expectation) = aDefined in hspec-core-2.11.14 · Test.Hspec.Core.Example
typetype Spec = SpecWith ()
#

A SpecWith that can be evaluated directly by the hspec function as it does not require any parameters.

typetype Assertion = IO ()
#

When an assertion is evaluated, it will output a message if and only if the assertion fails.

Test cases are composed of a sequence of one or more assertions.

Instances1Testable
value(@=?)
  1. :: (HasCallStack, Eq a, Show a)
  2. => a

    The expected value

  3. -> a

    The actual value

  4. -> Assertion
#

Asserts that the specified actual value is equal to the expected value (with the expected value on the left-hand side).

value(@?=)
  1. :: (HasCallStack, Eq a, Show a)
  2. => a

    The actual value

  3. -> a

    The expected value

  4. -> Assertion
#

Asserts that the specified actual value is equal to the expected value (with the actual value on the left-hand side).

Create data types and appropriate PersistEntity instances for the given UnboundEntityDefs.

This function should be used if you are only defining a single block of Persistent models for the entire application. If you intend on defining multiple blocks in different fiels, see mkPersistWith which allows you to provide existing entity definitions so foreign key references work.

Example:

mkPersist sqlSettings [persistLowerCase|
     User
         name    Text
         age     Int

     Dog
         name    Text
         owner   UserId

|]

Example from a file:

mkPersist sqlSettings $(persistFileWith lowerCaseSettings "models.persistentmodels")

For full information on the QuasiQuoter syntax, see Database.Persist.Quasi documentation.

valuemkMigrate :: String -> [UnboundEntityDef] -> Q [Dec]
#

Creates a single function to perform all migrations for the entities defined here. One thing to be aware of is dependencies: if you have entities with foreign references, make sure to place those definitions after the entities they reference.

In persistent-2.13.0.0, this was changed to *ignore* the input entity def list, and instead defer to mkEntityDefList to get the correct entities. This avoids problems where the QuasiQuoter is unable to know what the right reference types are. This sets mkPersist to be the "single source of truth" for entity definitions.

valueshare :: [[a] -> Q [Dec]] -> [a] -> Q [Dec]
#

Apply the given list of functions to the same EntityDefs.

This function is useful for cases such as:

share [mkEntityDefList "myDefs", mkPersist sqlSettings] [persistLowerCase|
    -- ...
|]

If you only have a single function, though, you don't need this. The following is redundant:

share [mkPersist sqlSettings] [persistLowerCase|
     -- ...
|]

Most functions require a full [EntityDef], which can be provided using $(discoverEntities) for all entites in scope, or defining mkEntityDefList to define a list of entities from the given block.

datadata Int32
#

32-bit signed integer type

Instances55Bounded, Enum, Eq, Integral, Data, Num, …
datadata Int64
#

64-bit signed integer type

Instances55Bounded, Enum, Eq, Integral, Data, Num, …
datadata Text
#

A space efficient, packed, unboxed Unicode text type.

Instances126IsList, Eq, Data, Ord, Read, Show, …
classclass Monad m => MonadIO (m :: Type -> Type) where
#

Monads in which IO computations may be embedded. Any monad built by applying a sequence of monad transformers to the IO monad will be an instance of this class.

Instances should satisfy the following laws, which state that liftIO is a transformer of monads:

Methods

  • liftIO :: IO a -> m a

    Lift a computation from the IO monad. This allows us to run IO computations in any monadic stack, so long as it supports these kinds of operations (i.e. IO is the base monad for the stack).

    Example
    import Control.Monad.Trans.State -- from the "transformers" library
    
    printState :: Show s => StateT s IO ()
    printState = do
      state <- get
      liftIO $ print state

    Had we omitted liftIO, we would have ended up with this error:

    • Couldn't match type ‘IO’ with ‘StateT s IO’
     Expected type: StateT s IO ()
       Actual type: IO ()

    The important part here is the mismatch between StateT s IO () and IO ().

    Luckily, we know of a function that takes an IO a and returns an (m a): liftIO, enabling us to run the program and see the expected results:

    > evalStateT printState "hello"
    "hello"
    
    > evalStateT printState 3
    3
    
Instances31MonadIO, …
newtypenewtype ReaderT r (m :: Type -> Type) a
#

The reader monad transformer, which adds a read-only environment to the given monad.

The return function ignores the environment, while m >>= k passes the inherited environment to both subcomputations:

image: images/bind-ReaderT.svg

Constructors

Instances52Generic1, MonadAccum, MonadError, MonadReader, MonadState, MonadWriter, …
classclass (forall (m :: Type -> Type). Monad m => Monad (t m)) => MonadTrans (t :: (Type -> Type) -> Type -> Type) where
#

The class of monad transformers. For any monad m, the result t m should also be a monad, and lift should be a monad transformation from m to t m, i.e. it should satisfy the following laws:

Since 0.6.0.0 and for GHC 8.6 and later, the requirement that t m be a Monad is enforced by the implication constraint forall m. Monad m => Monad (t m) enabled by the QuantifiedConstraints extension.

Ambiguity error with GHC 9.0 to 9.2.2

These versions of GHC have a bug (https://gitlab.haskell.org/ghc/ghc/-/issues/20582) which causes constraints like

(MonadTrans t, forall m. Monad m => Monad (t m)) => ...

to be reported as ambiguous. For transformers 0.6 and later, this can be fixed by removing the second constraint, which is implied by the first.

Methods

  • lift :: Monad m => m a -> t m a

    Lift a computation from the argument monad to the constructed monad.

Instances24MonadTrans, …
classclass Monad m => MonadReader r (m :: Type -> Type) | m -> r where
#

See examples in Control.Monad.Reader. Note, the partially applied function type (->) r is a simple reader monad. See the instance declaration below.

Methods

  • ask :: m r

    Retrieves the monad environment.

  • local :: (r -> r) -> m a -> m a

    Executes a computation in a modified environment.

  • reader :: (r -> a) -> m a

    Retrieves a function of the current environment.

Instances23MonadReader, …
valueasks
  1. :: MonadReader r m
  2. => (r -> a)

    The selector function to apply to the environment.

  3. -> m a
#

Retrieves a function of the current environment.

valuerunReader
  1. :: Reader r a

    A Reader to run.

  2. -> r

    An initial environment.

  3. -> a
#

Runs a Reader and extracts the final value from it. (The inverse of reader.)

valueforM_ :: (Foldable t, Monad m) => t a -> (a -> m b) -> m ()
#

forM_ is mapM_ with its arguments flipped. For a version that doesn't ignore the results see Data.Traversable.forM.

forM_ is just like for_, but specialised to monadic actions.

valueliftM :: Monad m => (a1 -> r) -> m a1 -> m r
#

Promote a function to a monad. This is equivalent to fmap but specialised to Monads.

valuereplicateM :: Applicative m => Int -> m a -> m [a]
#

replicateM n act performs the action act n times, and then returns the list of results.

replicateM n (pure x) == replicate n x
Examples
Example1 expression
replicateM 3 getLinehiheyahiya["hi","heya","hiya"]
Example2 expressions
import Control.Monad.StaterunState (replicateM 3 $ state $ \s -> (s, s + 1)) 1([1,2,3],4)
valuevoid :: Functor f => f a -> f ()
#

void value discards or ignores the result of evaluation, such as the return value of an System.IO.IO action.

Examples

Replace the contents of a Maybe Int with unit:

Example1 expression
void NothingNothing
Example1 expression
void (Just 3)Just ()

Replace the contents of an Either Int Int with unit, resulting in an Either Int ():

Example1 expression
void (Left 8675309)Left 8675309
Example1 expression
void (Right 8675309)Right ()

Replace every element of a list with unit:

Example1 expression
void [1,2,3][(),(),()]

Replace the second element of a pair with unit:

Example1 expression
void (1,2)(1,())

Discard the result of an System.IO.IO action:

Example1 expression
mapM print [1,2]12[(),()]
Example1 expression
void $ mapM print [1,2]12
valuewhen :: Applicative f => Bool -> f () -> f ()
#

Conditional execution of Applicative expressions. For example,

Examples
when debug (putStrLn "Debugging")

will output the string Debugging if the Boolean value debug is True, and otherwise do nothing.

Example1 expression
putStr "pi:" >> when False (print 3.14159)pi:
valueunless :: Applicative f => Bool -> f () -> f ()
#

The reverse of when.

Examples
Example1 expression
do x <- getLine       unless (x == "hi") (putStrLn "hi!")comingupwithexamplesisdifficulthi!
Example1 expression
unless (pi > exp 1) NothingJust ()
value(>=>) :: Monad m => (a -> m b) -> (b -> m c) -> a -> m c
#

Left-to-right composition of Kleisli arrows.

'(bs >=> cs) a' can be understood as the do expression

do b <- bs a
   cs b

or in terms of (>>=) as

bs a >>= cs
newtypenewtype UnliftIO (m :: Type -> Type)
#

The ability to run any monadic action m a as IO a.

This is more precisely a natural transformation. We need to new datatype (instead of simply using a forall) due to lack of support in GHC for impredicative types.

Constructors

classclass MonadIO m => MonadUnliftIO (m :: Type -> Type) where
#

Monads which allow their actions to be run in IO.

While MonadIO allows an IO action to be lifted into another monad, this class captures the opposite concept: allowing you to capture the monadic context. Note that, in order to meet the laws given below, the intuition is that a monad must have no monadic state, but may have monadic context. This essentially limits MonadUnliftIO to ReaderT and IdentityT transformers on top of IO.

Laws. For any function run provided by withRunInIO, it must meet the monad transformer laws as reformulated for MonadUnliftIO:

  • run . return = return
  • run (m >>= f) = run m >>= run . f

Instances of MonadUnliftIO must also satisfy the following laws:

Identity law

withRunInIO (\run -> run m) = m

Inverse law

withRunInIO (\_ -> m) = liftIO m

As an example of an invalid instance, a naive implementation of MonadUnliftIO (StateT s m) might be

withRunInIO inner =
  StateT $ \s ->
    withRunInIO $ \run ->
      inner (run . flip evalStateT s)

This breaks the identity law because the inner run m would throw away any state changes in m.

Methods

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

    Convenience function for capturing the monadic context and running an IO action with a runner function. The runner function is used to run a monadic action m in IO.

Instances6MonadUnliftIO
classclass Monad m => MonadIO (m :: Type -> Type) where
#

Monads in which IO computations may be embedded. Any monad built by applying a sequence of monad transformers to the IO monad will be an instance of this class.

Instances should satisfy the following laws, which state that liftIO is a transformer of monads:

Methods

  • liftIO :: IO a -> m a

    Lift a computation from the IO monad. This allows us to run IO computations in any monadic stack, so long as it supports these kinds of operations (i.e. IO is the base monad for the stack).

    Example
    import Control.Monad.Trans.State -- from the "transformers" library
    
    printState :: Show s => StateT s IO ()
    printState = do
      state <- get
      liftIO $ print state

    Had we omitted liftIO, we would have ended up with this error:

    • Couldn't match type ‘IO’ with ‘StateT s IO’
     Expected type: StateT s IO ()
       Actual type: IO ()

    The important part here is the mismatch between StateT s IO () and IO ().

    Luckily, we know of a function that takes an IO a and returns an (m a): liftIO, enabling us to run the program and see the expected results:

    > evalStateT printState "hello"
    "hello"
    
    > evalStateT printState 3
    3
    
Instances31MonadIO, …
valueaskRunInIO :: MonadUnliftIO m => m (m a -> IO a)
#

Same as askUnliftIO, but returns a monomorphic function instead of a polymorphic newtype wrapper. If you only need to apply the transformation on one concrete type, this function can be more convenient.

valueliftIOOp :: MonadUnliftIO m => (IO a -> IO b) -> m a -> m b
#

A helper function for lifting IO a -> IO b functions into any MonadUnliftIO.

Example
liftedTry :: (Exception e, MonadUnliftIO m) => m a -> m (Either e a)
liftedTry m = liftIOOp Control.Exception.try m
valuewrappedWithRunInIO
  1. :: MonadUnliftIO n
  2. => (n b -> m b)

    The wrapper, for instance IdentityT.

  3. -> (forall a. m a -> n a)

    The inverse, for instance runIdentityT.

  4. -> ((forall a. m a -> IO a) -> IO b)

    The actual function to invoke withRunInIO with.

  5. -> m b
#

A helper function for implementing MonadUnliftIO instances. Useful for the common case where you want to simply delegate to the underlying transformer.

Note: You can derive MonadUnliftIO for newtypes without this helper function in unliftio-core 0.2.0.0 and later.

Example
newtype AppT m a = AppT { unAppT :: ReaderT Int (ResourceT m) a }
  deriving (Functor, Applicative, Monad, MonadIO)

-- Same as `deriving newtype (MonadUnliftIO)`
instance MonadUnliftIO m => MonadUnliftIO (AppT m) where
  withRunInIO = wrappedWithRunInIO AppT unAppT
datadata ByteString
#

A space-efficient representation of a Word8 vector, supporting many efficient operations.

A ByteString contains 8-bit bytes, or by using the operations from Data.ByteString.Char8 it can be interpreted as containing 8-bit characters.

Instances48IsList, Eq, Data, Ord, Read, Show, …
datadata SomeException
#

The SomeException type is the root of the exception type hierarchy. When an exception of type e is thrown, behind the scenes it is encapsulated in a SomeException.

Instances2Show, Exception
classclass Monad m => MonadFail (m :: Type -> Type) where
#

When a value is bound in do-notation, the pattern on the left hand side of <- might not match. In this case, this class provides a function to recover.

A Monad without a MonadFail instance may only be used in conjunction with pattern that always match, such as newtypes, tuples, data types with only a single data constructor, and irrefutable patterns (~pat).

Instances of MonadFail should satisfy the following law: fail s should be a left zero for >>=,

fail s >>= f  =  fail s

If your Monad is also MonadPlus, a popular definition is

fail _ = mzero

fail s should be an action that runs in the monad itself, not an exception (except in instances of MonadIO). In particular, fail should not be implemented in terms of error.

Instances45MonadFail, …
datadata TestFn entity where
#

A datatype that wraps a function on entity that can has testable results.

Allows us to write:

foo :: entity -> entity -> [TestFn entity] -> Bool
foo e0 e1 = all ((TestFn msg f) -> f e0 == f e1)

Constructors

methodliftA2 :: (a -> b -> c) -> f a -> f b -> f c
#

Lift a binary function to actions.

Some functors support an implementation of liftA2 that is more efficient than the default one. In particular, if fmap is an expensive operation, it is likely better to use liftA2 than to fmap over the structure and then use <*>.

This became a typeclass method in 4.10.0.0. Prior to that, it was a function defined in terms of <*> and fmap.

Example
Example1 expression
liftA2 (,) (Just 3) (Just 5)Just (3,5)
Example1 expression
liftA2 (+) [1, 2, 3] [4, 5, 6][5,6,7,6,7,8,7,8,9]
datadata Proxy (t :: k)
#

Proxy is a type that holds no data, but has a phantom parameter of arbitrary type (or even kind). Its use is to provide type information, even though there is no value available of that type (or it may be too costly to create one).

Historically, Proxy :: Proxy a is a safer alternative to the undefined :: a idiom.

Example1 expression
Proxy :: Proxy (Void, Int -> Int)Proxy

Proxy can even hold types of higher kinds,

Example1 expression
Proxy :: Proxy EitherProxy
Example1 expression
Proxy :: Proxy FunctorProxy
Example1 expression
Proxy :: Proxy complicatedStructureProxy
Instances72Generic1, FoldableWithIndex, FunctorWithIndex, TraversableWithIndex, RepeatWithIndex, SemialignWithIndex, …
  • Generic1 ProxyDefined in ghc-internal-9.1003.0 · GHC.Internal.Generics
  • FoldableWithIndex Void ProxyDefined in indexed-traversable-0.1.4 · WithIndex
  • FunctorWithIndex Void ProxyDefined in indexed-traversable-0.1.4 · WithIndex
  • TraversableWithIndex Void ProxyDefined in indexed-traversable-0.1.4 · WithIndex
  • RepeatWithIndex Void ProxyDefined in semialign-1.3.1 · Data.Semialign.Internal
  • SemialignWithIndex Void ProxyDefined in semialign-1.3.1 · Data.Semialign.Internal
  • ZipWithIndex Void ProxyDefined in semialign-1.3.1 · Data.Semialign.Internal
  • FilterableWithIndex Void ProxyDefined in witherable-0.5 · Witherable
  • WitherableWithIndex Void ProxyDefined in witherable-0.5 · Witherable
  • Monad ProxyDefined in ghc-internal-9.1003.0 · GHC.Internal.Data.Proxy
  • Functor ProxyDefined in ghc-internal-9.1003.0 · GHC.Internal.Data.Proxy
  • Applicative ProxyDefined in ghc-internal-9.1003.0 · GHC.Internal.Data.Proxy
  • Foldable ProxyDefined in ghc-internal-9.1003.0 · GHC.Internal.Data.Foldable
  • Traversable ProxyDefined in ghc-internal-9.1003.0 · GHC.Internal.Data.Traversable
  • Alternative ProxyDefined in ghc-internal-9.1003.0 · GHC.Internal.Data.Proxy
  • MonadPlus ProxyDefined in ghc-internal-9.1003.0 · GHC.Internal.Data.Proxy
  • MonadZip ProxyDefined in base-4.20.2.0 · Control.Monad.Zip
  • Eq1 ProxyDefined in base-4.20.2.0 · Data.Functor.Classes
  • Ord1 ProxyDefined in base-4.20.2.0 · Data.Functor.Classes
  • Read1 ProxyDefined in base-4.20.2.0 · Data.Functor.Classes
  • Show1 ProxyDefined in base-4.20.2.0 · Data.Functor.Classes
  • Contravariant ProxyDefined in base-4.20.2.0 · Data.Functor.Contravariant
  • NFData1 ProxyDefined in deepseq-1.5.0.0 · Control.DeepSeq
  • Arbitrary1 ProxyDefined in quickcheck-instances-0.3.33 · Test.QuickCheck.Instances.Tagged · orphan
  • Hashable1 ProxyDefined in hashable-1.4.7.0 · Data.Hashable.Class
  • Distributive ProxyDefined in distributive-0.6.2.1 · Data.Distributive
  • Decidable ProxyDefined in contravariant-1.5.5 · Data.Functor.Contravariant.Divisible
  • Divisible ProxyDefined in contravariant-1.5.5 · Data.Functor.Contravariant.Divisible
  • Alt ProxyDefined in semigroupoids-6.0.1 · Data.Functor.Alt
  • Apply ProxyDefined in semigroupoids-6.0.1 · Data.Functor.Bind.Class
  • Bind ProxyDefined in semigroupoids-6.0.1 · Data.Functor.Bind.Class
  • Extend ProxyDefined in semigroupoids-6.0.1 · Data.Functor.Extend
  • Conclude ProxyDefined in semigroupoids-6.0.1 · Data.Functor.Contravariant.Conclude
  • Decide ProxyDefined in semigroupoids-6.0.1 · Data.Functor.Contravariant.Decide
  • Divise ProxyDefined in semigroupoids-6.0.1 · Data.Functor.Contravariant.Divise
  • Plus ProxyDefined in semigroupoids-6.0.1 · Data.Functor.Plus
  • Align ProxyDefined in semialign-1.3.1 · Data.Semialign.Internal
  • Semialign ProxyDefined in semialign-1.3.1 · Data.Semialign.Internal
  • Unalign ProxyDefined in semialign-1.3.1 · Data.Semialign.Internal
  • Repeat ProxyDefined in semialign-1.3.1 · Data.Semialign.Internal
  • Unzip ProxyDefined in semialign-1.3.1 · Data.Semialign.Internal
  • Zip ProxyDefined in semialign-1.3.1 · Data.Semialign.Internal
  • Filterable ProxyDefined in witherable-0.5 · Witherable
  • Witherable ProxyDefined in witherable-0.5 · Witherable
  • FromJSON1 ProxyDefined in aeson-2.2.3.0 · Data.Aeson.Types.FromJSON
  • ToJSON1 ProxyDefined in aeson-2.2.3.0 · Data.Aeson.Types.ToJSON
  • Bounded (Proxy t)Defined in ghc-internal-9.1003.0 · GHC.Internal.Data.Proxy
  • Enum (Proxy s)Defined in ghc-internal-9.1003.0 · GHC.Internal.Data.Proxy
  • Eq (Proxy s)Defined in ghc-internal-9.1003.0 · GHC.Internal.Data.Proxy
  • Data t => Data (Proxy t)Defined in ghc-internal-9.1003.0 · GHC.Internal.Data.Data
  • Ord (Proxy s)Defined in ghc-internal-9.1003.0 · GHC.Internal.Data.Proxy
  • Read (Proxy t)Defined in ghc-internal-9.1003.0 · GHC.Internal.Data.Proxy
  • Show (Proxy s)Defined in ghc-internal-9.1003.0 · GHC.Internal.Data.Proxy
  • Ix (Proxy s)Defined in ghc-internal-9.1003.0 · GHC.Internal.Data.Proxy
  • Generic (Proxy t)Defined in ghc-internal-9.1003.0 · GHC.Internal.Generics
  • Semigroup (Proxy s)Defined in ghc-internal-9.1003.0 · GHC.Internal.Data.Proxy
  • Monoid (Proxy s)Defined in ghc-internal-9.1003.0 · GHC.Internal.Data.Proxy
  • NFData (Proxy a)Defined in deepseq-1.5.0.0 · Control.DeepSeq
  • Arbitrary (Proxy a)Defined in quickcheck-instances-0.3.33 · Test.QuickCheck.Instances.Tagged · orphan
  • CoArbitrary (Proxy a)Defined in quickcheck-instances-0.3.33 · Test.QuickCheck.Instances.Tagged · orphan
  • Function (Proxy a)Defined in quickcheck-instances-0.3.33 · Test.QuickCheck.Instances.Tagged · orphan
  • Hashable (Proxy a)Defined in hashable-1.4.7.0 · Data.Hashable.Class
  • FromJSON (Proxy a)Defined in aeson-2.2.3.0 · Data.Aeson.Types.FromJSON
  • ToJSON (Proxy a)Defined in aeson-2.2.3.0 · Data.Aeson.Types.ToJSON
  • Default (Proxy a)Defined in data-default-0.8.0.1 · Data.Default.Internal
  • MonoFoldable (Proxy a)Defined in mono-traversable-1.0.21.0 · Data.MonoTraversable
  • MonoTraversable (Proxy a)Defined in mono-traversable-1.0.21.0 · Data.MonoTraversable
  • MonoFunctor (Proxy a)Defined in mono-traversable-1.0.21.0 · Data.MonoTraversable
  • MonoPointed (Proxy a)Defined in mono-traversable-1.0.21.0 · Data.MonoTraversable
  • type Rep (Proxy t) = D1 ('MetaData "Proxy" "GHC.Internal.Data.Proxy" "ghc-internal" 'False) (C1 ('MetaCons "Proxy" 'PrefixI 'False) U1)Defined in ghc-internal-9.1003.0 · GHC.Internal.Generics
  • type Rep1 Proxy = D1 ('MetaData "Proxy" "GHC.Internal.Data.Proxy" "ghc-internal" 'False) (C1 ('MetaCons "Proxy" 'PrefixI 'False) U1)Defined in ghc-internal-9.1003.0 · GHC.Internal.Generics
  • type Element (Proxy a) = aDefined in mono-traversable-1.0.21.0 · Data.MonoTraversable
newtypenewtype UUID
#

Constructors

Instances11Eq, Ord, Read, Show, FromJSON, ToJSON, …

Orphan instances

4 instances