persistent-2.13.3.3: Type-safe, multi-backend data serialization.
Safe HaskellNone
LanguageHaskell2010

Database.Persist

Description

Welcome to persistent!

This library intends to provide an easy, flexible, and convenient interface to various data storage backends. Backends include SQL databases, like mysql, postgresql, and sqlite, as well as NoSQL databases, like mongodb and redis.

If you intend on using a SQL database, then check out Database.Persist.Sql.

Synopsis

Defining Database Models

persistent lets you define your database models using a special syntax. This syntax allows you to customize the resulting Haskell datatypes and database schema. See Database.Persist.Quasi for details on that definition language.

Reference Schema & Dataset

For a quick example of the syntax, we'll introduce this database schema, and we'll use it to explain the update and filter combinators.

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

This creates a Haskell datatype that looks like this:

data User = User
    { userName :: String
    , userAge :: Int
    }
    deriving Show

In a SQL database, we'd get a migration like this:

CREATE TABLE "user" (
     id    SERIAL PRIMARY KEY,
     name  TEXT NOT NULL,
     age   INT NOT NULL
);

The examples below will refer to this as dataset-1.

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

Database Operations

The module Database.Persist.Class defines how to operate with persistent database models. Check that module out for basic operations, like get, insert, and selectList.

Types

This module re-export contains a lot of the important types for working with persistent datatypes and underlying values.

Query Operators

A convention that persistent tries to follow is that operators on Database types correspond to a Haskell (or database) operator with a . character at the end. So to do a || b , you'd write a ||. b. To

Query update combinators

These operations are used when performing updates against the database. Functions like upsert use them to provide new or modified values.

(=.) :: forall v typ. PersistField typ => EntityField v typ -> typ -> Update v infixr 3 Source #

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      |
+-----+-----+--------+

(+=.) :: forall v typ. PersistField typ => EntityField v typ -> typ -> Update v infixr 3 Source #

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       |
+-----+-----+---------+

(-=.) :: forall v typ. PersistField typ => EntityField v typ -> typ -> Update v infixr 3 Source #

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       |
+-----+-----+---------+

(*=.) :: forall v typ. PersistField typ => EntityField v typ -> typ -> Update v infixr 3 Source #

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      |
+-----+-----+--------+

(/=.) :: forall v typ. PersistField typ => EntityField v typ -> typ -> Update v infixr 3 Source #

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       |
+-----+-----+---------+

Query filter combinators

These functions are useful in the PersistQuery class, like selectList, updateWhere, etc.

(==.) :: forall v typ. PersistField typ => EntityField v typ -> typ -> Filter v infix 4 Source #

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   |
+-----+-----+-----+

(!=.) :: forall v typ. PersistField typ => EntityField v typ -> typ -> Filter v infix 4 Source #

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   |
+-----+-----+-----+

(<.) :: forall v typ. PersistField typ => EntityField v typ -> typ -> Filter v infix 4 Source #

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   |
+-----+-----+-----+

(>.) :: forall v typ. PersistField typ => EntityField v typ -> typ -> Filter v infix 4 Source #

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   |
+-----+-----+-----+

(<=.) :: forall v typ. PersistField typ => EntityField v typ -> typ -> Filter v infix 4 Source #

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   |
+-----+-----+-----+

(>=.) :: forall v typ. PersistField typ => EntityField v typ -> typ -> Filter v infix 4 Source #

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   |
+-----+-----+-----+

(<-.) :: forall v typ. PersistField typ => EntityField v typ -> [typ] -> Filter v infix 4 Source #

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   |
+-----+-----+-----+

(/<-.) :: forall v typ. PersistField typ => EntityField v typ -> [typ] -> Filter v infix 4 Source #

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   |
+-----+-----+-----+

(||.) :: forall v. [Filter v] -> [Filter v] -> [Filter v] infixl 3 Source #

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

JSON Utilities

listToJSON :: [PersistValue] -> Text Source #

Convert list of PersistValues into textual representation of JSON object. This is a type-constrained synonym for toJsonText.

mapToJSON :: [(Text, PersistValue)] -> Text Source #

Convert map (list of tuples) into textual representation of JSON object. This is a type-constrained synonym for toJsonText.

toJsonText :: ToJSON j => j -> Text Source #

A more general way to convert instances of ToJSON type class to strict text Text.

getPersistMap :: PersistValue -> Either Text [(Text, PersistValue)] Source #

FIXME Add documentation to that.

Other utilities

limitOffsetOrder :: PersistEntity val => [SelectOpt val] -> (Int, Int, [SelectOpt val]) Source #

FIXME What's this exactly?