Create a PostgreSQL connection pool and run the given action. The pool is
properly released after the action finishes using it. Note that you should
not use the given ConnectionPool outside the action since it may already
have been released.
The provided action should use runSqlConn and *not* runReaderT because
the former brackets the database action with transaction begin/commit.
Same as withPostgresqlPool, but instead of opening a pool
of connections, only one connection is opened.
The provided action should use runSqlConn and *not* runReaderT because
the former brackets the database action with transaction begin/commit.
Create a PostgreSQL connection pool. Note that it's your
responsibility to properly close the connection pool when
unneeded. Use withPostgresqlPool for an automatic resource
control.
Same as createPostgresqlPool, but additionally takes a callback function
for some connection-specific tweaking to be performed after connection
creation. This could be used, for example, to change the schema. For more
information, see:
Same as other similarly-named functions in this module, but takes callbacks for obtaining
the server version (to work around an Amazon Redshift bug) and connection-specific tweaking
(to change the schema).
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.
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 PoolSqlBackend, 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.
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.
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.
This function allows you to build an Entity a by specifying an
action that returns a value for the field in the callback function.
Let's look at an example.
parseFromEnvironmentVariables :: IO (Entity User)
parseFromEnvironmentVariables =
tabulateEntityA $ \userField ->
case userField of
UserName ->
getEnv USER_NAME
UserAge -> do
ageVar <- getEnv USER_AGE
case readMaybe ageVar of
Just age ->
pure age
Nothing ->
error $ "Failed to parse Age from: " <> ageVar
UserAddressId -> do
addressVar <- getEnv USER_ADDRESS_ID
pure $ AddressKey addressVar
Extract a Key record from a record value. Currently, this is
only defined for entities using the Primary syntax for
natural/composite keys. In a future version of persistent which
incorporates the ID directly into the entity, this will always be Just.
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.
Instances1IsLabel
SymbolToFieldsymrectyp => IsLabelsym (EntityFieldrectyp)Defined in persistent-2.14.6.3 · Database.Persist.Class.PersistEntity
This instance delegates to SymbolToField to provide
OverloadedLabels support to the EntityField type.
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 InPersistFilter requires that you have an array- or list-shaped
EntityField. It is possible to construct values using this that will
create malformed runtime values.
This constructor is used to specify some raw literal value for the
backend. The LiteralType value specifies how the value should be
escaped. This can be used to make special, custom types avaialable
in the back end.
This pattern synonym used to be a data constructor on PersistValue,
but was changed into a catch-all pattern synonym to allow backwards
compatiblity with database types. See the documentation on
PersistDbSpecific for more details.
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.
This pattern synonym used to be a data constructor on PersistValue,
but was changed into a catch-all pattern synonym to allow backwards
compatiblity with database types. See the documentation on
PersistDbSpecific for more details.
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 -> EitherText 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.
TypeError ((((('Text"The instance of PersistField for the Natural type was removed." ':$$: 'Text"Please see the documentation for OverflowNatural if you want to ") ':$$: 'Text"continue using the old behavior or want to see documentation on ") ':$$: 'Text"why the instance was removed.") ':$$: 'Text"") ':$$: 'Text"This error instance will be removed in a future release.") => PersistFieldNaturalDefined in persistent-2.14.6.3 · Database.Persist.Class.PersistField
PersistFieldValueDefined in persistent-postgresql-2.13.6.2 · Database.Persist.Postgresql.JSON · orphan
PersistFieldHtmlDefined in persistent-2.14.6.3 · Database.Persist.Class.PersistField
PersistFieldByteStringDefined in persistent-2.14.6.3 · Database.Persist.Class.PersistField
PersistFieldInt16Defined in persistent-2.14.6.3 · Database.Persist.Class.PersistField
PersistFieldInt32Defined in persistent-2.14.6.3 · Database.Persist.Class.PersistField
PersistFieldInt64Defined in persistent-2.14.6.3 · Database.Persist.Class.PersistField
PersistFieldInt8Defined in persistent-2.14.6.3 · Database.Persist.Class.PersistField
PersistFieldRationalDefined in persistent-2.14.6.3 · Database.Persist.Class.PersistField
PersistFieldWord16Defined in persistent-2.14.6.3 · Database.Persist.Class.PersistField
PersistFieldWord32Defined in persistent-2.14.6.3 · Database.Persist.Class.PersistField
PersistFieldWord64Defined in persistent-2.14.6.3 · Database.Persist.Class.PersistField
PersistFieldWord8Defined in persistent-2.14.6.3 · Database.Persist.Class.PersistField
PersistFieldBoolDefined in persistent-2.14.6.3 · Database.Persist.Class.PersistField
PersistFieldDoubleDefined in persistent-2.14.6.3 · Database.Persist.Class.PersistField
PersistFieldIntDefined in persistent-2.14.6.3 · Database.Persist.Class.PersistField
PersistFieldWordDefined in persistent-2.14.6.3 · Database.Persist.Class.PersistField
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"
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.
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.
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
EqLiteralTypeDefined in persistent-2.14.6.3 · Database.Persist.PersistValue
OrdLiteralTypeDefined in persistent-2.14.6.3 · Database.Persist.PersistValue
ReadLiteralTypeDefined in persistent-2.14.6.3 · Database.Persist.PersistValue
ShowLiteralTypeDefined in persistent-2.14.6.3 · Database.Persist.PersistValue
Get all records matching the given criterion in the specified order.
Returns also the identifiers.
NOTE: This function returns an Acquire and a ConduitM, which implies
that it streams from the database. It does not. Please use selectList
to simplify the code. If you want streaming behavior, consider
persistent-pagination which efficiently chunks a query into ranges, or
investigate a backend-specific streaming solution.
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.
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.
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.
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.
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.
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.
Instances2SafeToInsert
TypeError (EntityErrorMessagea) => SafeToInsert (Entitya)Defined in persistent-2.14.6.3 · Database.Persist.Class.PersistEntity
TypeError (FunctionErrorMessageab) => SafeToInsert (a -> b)Defined in persistent-2.14.6.3 · Database.Persist.Class.PersistEntity
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.
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.
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.
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.
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.
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.
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.
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.
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.
This works for SqlReadBackend because of the instance BackendCompatibleSqlBackendSqlReadBackend, without needing to go through the BaseBackend type family.
Likewise, functions that are currently hardcoded to use SqlBackend can be generalized:
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
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.
ToBackendKey converts a PersistEntityKey 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.
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.
StypetypeMultipleUniqueKeysErrorty = ((('Text"The entity " ':<>: 'ShowTypety) ':<>: '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.
StypetypeNoUniqueKeysErrorty = (('Text"The entity " ':<>: 'ShowTypety) ':<>: 'Text" does not have any unique keys.") ':$$: ('Text"The function you are trying to call requires a unique key " ':<>: 'Text"to be defined on the entity.")
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.
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 singleUnique, 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.
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.
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.
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.
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]
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"]
+----+-----------------+-----+
| 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]
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
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.
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.
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.
Attempt to replace the record of the given key with the given new record.
First query the unique fields to make sure the replacement maintains
uniqueness constraints.
Return Nothing if the replacement was made.
If uniqueness is violated, return a Just with the Unique violation
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.
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.
Retrieve the list of UniqueDef from an EntityDef. As of version 2.14,
this will also include the primary key on the entity, if one is defined. If
you do not want the primary key, see getEntityUniquesNoPrimaryKey.
Retrieve the list of UniqueDef from an EntityDef. This does not include
a Primary key, if one is defined. A future version of persistent will
include a Primary key among the Unique constructors for the Entity.
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
InactiveLocations to be current. However, there may be
at most one currentLocation 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.
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.
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
EqEntityDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
OrdEntityDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
ReadEntityDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
ShowEntityDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
LiftEntityDefDefined in persistent-2.14.6.3 · Database.Persist.Types.Base
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
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.
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.
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
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.
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.
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.
The name of the field. Note that this does not corresponds to the
record labels generated for the particular entity - record labels
are generated with the type name prefixed to the field, so
a FieldDef that contains a FieldNameHS "name" for a type
User will have a record field userName.
Defines how operations on the field cascade on to the referenced
tables. This doesn't have any meaning if the fieldReference is set
to NoReference or SelfReference. The cascade option here should
be the same as the one obtained in the fieldReference.
Parse raw field attributes into structured form. Any unrecognized
attributes will be preserved, identically as they are encountered,
as FieldAttrOther values.
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:
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:
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.
If the override is defined, then this returns a function that accepts an
entity name and field name and provides the ConstraintNameDB for the
foreign key constraint.
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.
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.
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.
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.
Same as runMigration, but does not report the individual migrations on
stderr. Instead it returns a list of the executed SQL commands.
This is a safer/more robust alternative to runMigrationSilent, but may be
less silent for some persistent implementations, most notably
persistent-postgresql
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!
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.
Render a [Filter record] into a Text value suitable for inclusion
into a SQL query, as well as the [PersistValue] to properly fill in the
? place holders.
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.
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)
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.
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.
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.
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.
Creates a pool of connections to a SQL database which can be used by the Pool backend -> m a function.
After the function completes, the connections are destroyed.
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).
Roll back the current transaction and begin a new one.
This rolls back to the state of the last call to transactionSave or the enclosing
runSqlConn call.
A libpq connection string. A simple example of connection
string would be "host=localhost port=5432 user=test
dbname=test password=test". Please read libpq's
documentation at
https://www.postgresql.org/docs/current/static/libpq-connect.html
for more details on how to create such strings.
This type is used to determine how to update rows using Postgres'
INSERT ... ON CONFLICT KEY UPDATE functionality, exposed via
upsertWhere and upsertManyWhere in this library.
Copy the field into the database only if the value in the
corresponding record is non-empty, where "empty" means the Monoid
definition for mempty. Useful for Text, String, ByteString, etc.
Copy the field into the database only if the field is not equal to the
provided value. This is useful to avoid copying weird nullary data into
the database.
Exclude any record field if it doesn't match the filter record. Used only in upsertWhere and
upsertManyWhere
TODO: we could probably make a sum type for the Filter record that's passed into the upsertWhere and
upsertManyWhere methods that has similar behavior to the HandleCollisionUpdate type.
Information required to connect to a PostgreSQL database
using persistent's generic facilities. These values are the
same that are given to withPostgresqlPool.
Postgres specific upsertWhere. This method does the following:
It will insert a record if no matching unique key exists.
If a unique key exists, it will update the relevant field with a user-supplied value, however,
it will only do this update on a user-supplied condition.
For example, here's how this method could be called like such:
upsertWhere record [recordField =. newValue] [recordField /= newValue]
Called thusly, this method will insert a new record (if none exists) OR update a recordField with a new value
assuming the condition in the last block is met.
Postgres specific upsertManyWhere. This method does the following:
It will insert a record if no matching unique key exists.
If a unique key exists, it will update the relevant field with a user-supplied value, however,
it will only do this update on a user-supplied condition.
For example, here's how this method could be called like such:
Called thusly, this method will insert a new record (if none exists) OR update a recordField with a new value
assuming the condition in the last block is met.
Mock a migration even when the database is not present.
This function performs the same functionality of printMigration
with the difference that an actual database is not needed.
The default implementation queries the server with "show server_version".
Some variants of Postgres, such as Redshift, don't support showing the version.
It's recommended you return a hardcoded version in those cases.