Database.Persist.Types

persistent-2.2.4.1: Type-safe, multi-backend data serialization.

Safe Haskell | None
Language | Haskell98

Database.Persist.Types

Synopsis

- data Checkmark
  - = Active
  - | Inactive
- data IsNullable
  - = Nullable !WhyNullable
  - | NotNullable
- data WhyNullable
  - = ByMaybeAttr
  - | ByNullableAttr
- data EntityDef = EntityDef {
  - entityHaskell :: !HaskellName
  - entityDB :: !DBName
  - entityId :: !FieldDef
  - entityAttrs :: ![Attr]
  - entityFields :: ![FieldDef]
  - entityUniques :: ![UniqueDef]
  - entityForeigns :: ![ForeignDef]
  - entityDerives :: ![Text]
  - entityExtra :: !(Map Text [ExtraLine])
  - entitySum :: !Bool
  }
- entityPrimary :: EntityDef -> Maybe CompositeDef
- entityKeyFields :: EntityDef -> [FieldDef]
- keyAndEntityFields :: EntityDef -> [FieldDef]
- type ExtraLine = [Text]
- newtype HaskellName = HaskellName {
  - unHaskellName :: Text
  }
- newtype DBName = DBName {
  - unDBName :: Text
  }
- type Attr = Text
- data FieldType
  - = FTTypeCon (Maybe Text) Text
  - | FTApp FieldType FieldType
  - | FTList FieldType
- data FieldDef = FieldDef {
  - fieldHaskell :: !HaskellName
  - fieldDB :: !DBName
  - fieldType :: !FieldType
  - fieldSqlType :: !SqlType
  - fieldAttrs :: ![Attr]
  - fieldStrict :: !Bool
  - fieldReference :: !ReferenceDef
  }
- data ReferenceDef
  - = NoReference
  - | ForeignRef !HaskellName !FieldType
  - | EmbedRef EmbedEntityDef
  - | CompositeRef CompositeDef
  - | SelfReference
- data EmbedEntityDef = EmbedEntityDef {
  - embeddedHaskell :: !HaskellName
  - embeddedFields :: ![EmbedFieldDef]
  }
- data EmbedFieldDef = EmbedFieldDef {
  - emFieldDB :: !DBName
  - emFieldEmbed :: Maybe EmbedEntityDef
  - emFieldCycle :: Maybe HaskellName
  }
- toEmbedEntityDef :: EntityDef -> EmbedEntityDef
- data UniqueDef = UniqueDef {
  - uniqueHaskell :: !HaskellName
  - uniqueDBName :: !DBName
  - uniqueFields :: ![(HaskellName, DBName)]
  - uniqueAttrs :: ![Attr]
  }
- data CompositeDef = CompositeDef {
  - compositeFields :: ![FieldDef]
  - compositeAttrs :: ![Attr]
  }
- type ForeignFieldDef = (HaskellName, DBName)
- data ForeignDef = ForeignDef {
  - foreignRefTableHaskell :: !HaskellName
  - foreignRefTableDBName :: !DBName
  - foreignConstraintNameHaskell :: !HaskellName
  - foreignConstraintNameDBName :: !DBName
  - foreignFields :: ![(ForeignFieldDef, ForeignFieldDef)]
  - foreignAttrs :: ![Attr]
  - foreignNullable :: Bool
  }
- data PersistException
  - = PersistError Text
  - | PersistMarshalError Text
  - | PersistInvalidField Text
  - | PersistForeignConstraintUnmet Text
  - | PersistMongoDBError Text
  - | PersistMongoDBUnsupported Text
- data PersistValue
  - = PersistText Text
  - | PersistByteString ByteString
  - | PersistInt64 Int64
  - | PersistDouble Double
  - | PersistRational Rational
  - | PersistBool Bool
  - | PersistDay Day
  - | PersistTimeOfDay TimeOfDay
  - | PersistUTCTime UTCTime
  - | PersistNull
  - | PersistList [PersistValue]
  - | PersistMap [(Text, PersistValue)]
  - | PersistObjectId ByteString
  - | PersistDbSpecific ByteString
- fromPersistValueText :: PersistValue -> Either Text Text
- data SqlType
  - = SqlString
  - | SqlInt32
  - | SqlInt64
  - | SqlReal
  - | SqlNumeric Word32 Word32
  - | SqlBool
  - | SqlDay
  - | SqlTime
  - | SqlDayTime
  - | SqlBlob
  - | SqlOther Text
- data PersistFilter
  - = Eq
  - | Ne
  - | Gt
  - | Lt
  - | Ge
  - | Le
  - | In
  - | NotIn
  - | BackendSpecificFilter Text
- data UpdateException
  - = KeyNotFound String
  - | UpsertError String
- data OnlyUniqueException = OnlyUniqueException String
- data PersistUpdate
  - = Assign
  - | Add
  - | Subtract
  - | Multiply
  - | Divide
  - | BackendSpecificUpdate Text
- data SomePersistField = forall a . PersistField a => SomePersistField a
- data Update record
  - = forall typ . PersistField typ => Update {
    - updateField :: EntityField record typ
    - updateValue :: typ
    - updateUpdate :: PersistUpdate
    }
  - | BackendUpdate (BackendSpecificUpdate (PersistEntityBackend record) record)
- type family BackendSpecificUpdate backend record
- data SelectOpt record
  - = forall typ . Asc (EntityField record typ)
  - | forall typ . Desc (EntityField record typ)
  - | OffsetBy Int
  - | LimitTo Int
- data Filter record
  - = forall typ . PersistField typ => Filter {
    - filterField :: EntityField record typ
    - filterValue :: Either typ [typ]
    - filterFilter :: PersistFilter
    }
  - | FilterAnd [Filter record]
  - | FilterOr [Filter record]
  - | BackendFilter (BackendSpecificFilter (PersistEntityBackend record) record)
- type family BackendSpecificFilter backend record
- data Entity record = PersistEntity record => Entity {
  - entityKey :: Key record
  - entityVal :: record
  }

# Documentation

data 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` `Location`s 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 `NULL`able 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.

Instances

Bounded Checkmark |
Enum Checkmark |
Eq Checkmark |
Ord Checkmark |
Read Checkmark |
Show Checkmark |
ToHttpApiData Checkmark |
FromHttpApiData Checkmark |
PathPiece Checkmark |
PersistField Checkmark |
PersistFieldSql Checkmark |

data IsNullable

Constructors

Nullable !WhyNullable |
NotNullable |

Instances

Eq IsNullable |
Show IsNullable |

data 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.

Constructors

ByMaybeAttr |
ByNullableAttr |

Instances

Eq WhyNullable |
Show WhyNullable |

data EntityDef

Constructors

EntityDef |
Fields entityHaskell :: !HaskellName entityDB :: !DBName entityId :: !FieldDef entityAttrs :: ![Attr] entityFields :: ![FieldDef] entityUniques :: ![UniqueDef] entityForeigns :: ![ForeignDef] entityDerives :: ![Text] entityExtra :: !(Map Text [ExtraLine]) entitySum :: !Bool

Instances

Eq EntityDef |
Ord EntityDef |
Read EntityDef |
Show EntityDef |

entityPrimary :: EntityDef -> Maybe CompositeDef

entityKeyFields :: EntityDef -> [FieldDef]

keyAndEntityFields :: EntityDef -> [FieldDef]

type ExtraLine = [Text]

newtype HaskellName

Constructors

HaskellName |
Fields unHaskellName :: Text

Instances

Eq HaskellName |
Ord HaskellName |
Read HaskellName |
Show HaskellName |

newtype DBName

Constructors

DBName |
Fields unDBName :: Text

Instances

Eq DBName |
Ord DBName |
Read DBName |
Show DBName |

type Attr = Text

data FieldType

Constructors

FTTypeCon (Maybe Text) Text | Optional module and name.
FTApp FieldType FieldType |
FTList FieldType |

Instances

Eq FieldType |
Ord FieldType |
Read FieldType |
Show FieldType |

data FieldDef

Constructors

FieldDef |
Fields fieldHaskell :: !HaskellName name of the field fieldDB :: !DBName fieldType :: !FieldType fieldSqlType :: !SqlType fieldAttrs :: ![Attr] user annotations for a field fieldStrict :: !Bool a strict field in the data type. Default: true fieldReference :: !ReferenceDef

Instances

Eq FieldDef |
Ord FieldDef |
Read FieldDef |
Show FieldDef |

data ReferenceDef

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

Constructors

NoReference |
ForeignRef !HaskellName !FieldType | A ForeignRef has a late binding to the EntityDef it references via HaskellName and has the Haskell type of the foreign key in the form of FieldType
EmbedRef EmbedEntityDef |
CompositeRef CompositeDef |
SelfReference | A SelfReference stops an immediate cycle which causes non-termination at compile-time (issue #311).

Instances

Eq ReferenceDef |
Ord ReferenceDef |
Read ReferenceDef |
Show ReferenceDef |

data EmbedEntityDef

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

Constructors

EmbedEntityDef |
Fields embeddedHaskell :: !HaskellName embeddedFields :: ![EmbedFieldDef]

Instances

Eq EmbedEntityDef |
Ord EmbedEntityDef |
Read EmbedEntityDef |
Show EmbedEntityDef |

data EmbedFieldDef

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

Constructors

EmbedFieldDef |
Fields emFieldDB :: !DBName emFieldEmbed :: Maybe EmbedEntityDef emFieldCycle :: Maybe HaskellName `emFieldEmbed` can create a cycle (issue #311) when a cycle is detected, `emFieldEmbed` will be Nothing and `emFieldCycle` will be Just

Instances

Eq EmbedFieldDef |
Ord EmbedFieldDef |
Read EmbedFieldDef |
Show EmbedFieldDef |

toEmbedEntityDef :: EntityDef -> EmbedEntityDef

data UniqueDef

Constructors

UniqueDef |
Fields uniqueHaskell :: !HaskellName uniqueDBName :: !DBName uniqueFields :: ![(HaskellName, DBName)] uniqueAttrs :: ![Attr]

Instances

Eq UniqueDef |
Ord UniqueDef |
Read UniqueDef |
Show UniqueDef |

data CompositeDef

Constructors

CompositeDef |
Fields compositeFields :: ![FieldDef] compositeAttrs :: ![Attr]

Instances

Eq CompositeDef |
Ord CompositeDef |
Read CompositeDef |
Show CompositeDef |

type ForeignFieldDef = (HaskellName, DBName)

Used instead of FieldDef to generate a smaller amount of code

data ForeignDef

Constructors

ForeignDef |
Fields foreignRefTableHaskell :: !HaskellName foreignRefTableDBName :: !DBName foreignConstraintNameHaskell :: !HaskellName foreignConstraintNameDBName :: !DBName foreignFields :: ![(ForeignFieldDef, ForeignFieldDef)] foreignAttrs :: ![Attr] foreignNullable :: Bool

Instances

Eq ForeignDef |
Ord ForeignDef |
Read ForeignDef |
Show ForeignDef |

data PersistException

Constructors

PersistError Text | Generic Exception
PersistMarshalError Text |
PersistInvalidField Text |
PersistForeignConstraintUnmet Text |
PersistMongoDBError Text |
PersistMongoDBUnsupported Text |

Instances

Show PersistException |
Exception PersistException |
Error PersistException |

data PersistValue

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

Constructors

PersistText Text |
PersistByteString ByteString |
PersistInt64 Int64 |
PersistDouble Double |
PersistRational Rational |
PersistBool Bool |
PersistDay Day |
PersistTimeOfDay TimeOfDay |
PersistUTCTime UTCTime |
PersistNull |
PersistList [PersistValue] |
PersistMap [(Text, PersistValue)] |
PersistObjectId ByteString | Intended especially for MongoDB backend
PersistDbSpecific ByteString | Using `PersistDbSpecific` allows you to use types specific to a particular backend For example, below is a simple example of the PostGIS geography type:
    data Geo = Geo ByteString

    instance PersistField Geo where
      toPersistValue (Geo t) = PersistDbSpecific t

      fromPersistValue (PersistDbSpecific t) = Right $ Geo $ Data.ByteString.concat ["'", t, "'"]
      fromPersistValue _ = Left "Geo values must be converted from PersistDbSpecific"

    instance PersistFieldSql Geo where
      sqlType _ = SqlOther "GEOGRAPHY(POINT,4326)"

    toPoint :: Double -> Double -> Geo
    toPoint lat lon = Geo $ Data.ByteString.concat ["'POINT(", ps $ lon, " ", ps $ lat, ")'"]
      where ps = Data.Text.pack . show
If Foo has a geography field, we can then perform insertions like the following:
    insert $ Foo (toPoint 44 44)

Instances

Eq PersistValue |
Ord PersistValue |
Read PersistValue |
Show PersistValue |
ToJSON PersistValue |
FromJSON PersistValue |
ToHttpApiData PersistValue |
FromHttpApiData PersistValue |
PathPiece PersistValue |
PersistField PersistValue |
PersistFieldSql PersistValue |

fromPersistValueText :: PersistValue -> Either Text Text

data 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.

Constructors

SqlString |
SqlInt32 |
SqlInt64 |
SqlReal |
SqlNumeric Word32 Word32 |
SqlBool |
SqlDay |
SqlTime |
SqlDayTime | Always uses UTC timezone
SqlBlob |
SqlOther Text | a backend-specific name

Instances

Eq SqlType |
Ord SqlType |
Read SqlType |
Show SqlType |

data PersistFilter

Constructors

Eq |
Ne |
Gt |
Lt |
Ge |
Le |
In |
NotIn |
BackendSpecificFilter Text |

Instances

Read PersistFilter |
Show PersistFilter |

data UpdateException

Constructors

KeyNotFound String |
UpsertError String |

Instances

Show UpdateException |
Exception UpdateException |

data OnlyUniqueException

Constructors

OnlyUniqueException String |

Instances

Show OnlyUniqueException |
Exception OnlyUniqueException |

data PersistUpdate

Constructors

Assign |
Add |
Subtract |
Multiply |
Divide |
BackendSpecificUpdate Text |

Instances

Read PersistUpdate |
Show PersistUpdate |

data SomePersistField

Constructors

forall a . PersistField a => SomePersistField a |

Instances

PersistField SomePersistField |

data Update record

Updating a database entity.

Persistent users use combinators to create these.

Constructors

forall typ . PersistField typ => Update |
Fields updateField :: EntityField record typ updateValue :: typ updateUpdate :: PersistUpdate
BackendUpdate (BackendSpecificUpdate (PersistEntityBackend record) record) |

type family BackendSpecificUpdate backend record

data SelectOpt record

Query options.

Persistent users use these directly.

Constructors

forall typ . Asc (EntityField record typ) |
forall typ . Desc (EntityField record typ) |
OffsetBy Int |
LimitTo Int |

data 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.

Constructors

forall typ . PersistField typ => Filter |
Fields filterField :: EntityField record typ filterValue :: Either typ [typ] filterFilter :: PersistFilter
FilterAnd [Filter record] | convenient for internal use, not needed for the API
FilterOr [Filter record] |
BackendFilter (BackendSpecificFilter (PersistEntityBackend record) record) |

type family BackendSpecificFilter backend record

data 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.GenericSql 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

PersistEntity record => Entity |
Fields entityKey :: Key record entityVal :: record

Instances

(PersistEntity record, Eq (Key record), Eq record) => Eq (Entity record) |
(PersistEntity record, Ord (Key record), Ord record) => Ord (Entity record) |
(PersistEntity record, Read (Key record), Read record) => Read (Entity record) |
(PersistEntity record, Show (Key record), Show record) => Show (Entity record) |
(PersistEntity record, PersistField record, PersistField (Key record)) => PersistField (Entity record) |
(PersistField record, PersistEntity record) => PersistFieldSql (Entity record) |
(PersistEntity record, (~) * (PersistEntityBackend record) SqlBackend) => RawSql (Entity record) |