HORIZON HASKELLDocslts/ghc-9.10.xc74966e2026-09-27Search names, modules, packages, or :: a typeCtrl K

GHC 9.10.3 · lts/ghc-9.10.x · c74966e · 2026-09-27

Moduleyesod-1.6.2.1Haskell2010

Yesod

This module simply re-exports from other modules for your convenience.

  • 113 types
  • 50 classes
  • 494 values
  • Packageyesod-1.6.2.1
  • Exports677
  • LanguageHaskell2010
  • LicenceMIT
  • SourceYesod.hs

Re-exports from yesod-core

677 declarations
valuewarp :: YesodDispatch site => Int -> site -> IO ()
#

A convenience method to run an application using the Warp webserver on the specified port. Automatically calls toWaiApp. Provides a default set of middlewares. This set may change at any point without a breaking version number. Currently, it includes:

  • Logging

  • GZIP compression

  • Automatic HEAD method handling

  • Request method override with the _method query string parameter

  • Accept header override with the _accept query string parameter

If you need more fine-grained control of middlewares, please use toWaiApp directly.

Since 1.2.0

classclass RenderRoute site => Yesod site where
#

Define settings for a Yesod applications. All methods have intelligent defaults, and therefore no implementation is required.

Methods

  • approot :: Approot site

    An absolute URL to the root of the application. Do not include trailing slash.

    Default value: guessApproot. If you know your application root statically, it will be more efficient and more reliable to instead use ApprootStatic or ApprootMaster. If you do not need full absolute URLs, you can use ApprootRelative instead.

    Note: Prior to yesod-core 1.5, the default value was ApprootRelative.

  • catchHandlerExceptions :: MonadUnliftIO m => site -> m a -> (SomeException -> m a) -> m a

    allows the user to specify how exceptions are cought. by default all async exceptions are thrown and synchronous exceptions render a 500 page. To catch all exceptions (even async) to render a 500 page, set this to catchSyncOrAsync. Beware this may have negative effects with functions like timeout.

  • errorHandler :: ErrorResponse -> HandlerFor site TypedContent

    Output error response pages.

    Default value: defaultErrorHandler.

  • defaultLayout :: WidgetFor site () -> HandlerFor site Html

    Applies some form of layout to the contents of a page.

  • urlParamRenderOverride :: site -> Route site -> [(Text, Text)] -> Maybe Builder

    Override the rendering function for a particular URL and query string parameters. One use case for this is to offload static hosting to a different domain name to avoid sending cookies.

    For backward compatibility default implementation is in terms of urlRenderOverride, probably ineffective

    Since 1.4.23

  • isAuthorized :: Route site -> Bool -> HandlerFor site AuthResult

    Determine if a request is authorized or not.

    Return Authorized if the request is authorized, Unauthorized a message if unauthorized. If authentication is required, return AuthenticationRequired.

  • isWriteRequest :: Route site -> HandlerFor site Bool

    Determines whether the current request is a write request. By default, this assumes you are following RESTful principles, and determines this from request method. In particular, all except the following request methods are considered write: GET HEAD OPTIONS TRACE.

    This function is used to determine if a request is authorized; see isAuthorized.

  • authRoute :: site -> Maybe (Route site)

    The default route for authentication.

    Used in particular by isAuthorized, but library users can do whatever they want with it.

  • cleanPath :: site -> [Text] -> Either [Text] [Text]

    A function used to clean up path segments. It returns Right with a clean path or Left with a new set of pieces the user should be redirected to. The default implementation enforces:

    • No double slashes

    • There is no trailing slash.

    Note that versions of Yesod prior to 0.7 used a different set of rules involing trailing slashes.

  • joinPath :: site -> Text -> [Text] -> [(Text, Text)] -> Builder

    Builds an absolute URL by concatenating the application root with the pieces of a path and a query string, if any. Note that the pieces of the path have been previously cleaned up by cleanPath.

  • addStaticContent :: Text -> Text -> ByteString -> HandlerFor site (Maybe (Either Text (Route site, [(Text, Text)])))

    This function is used to store some static content to be served as an external file. The most common case of this is stashing CSS and JavaScript content in an external file; the Yesod.Widget module uses this feature.

    The return value is Nothing if no storing was performed; this is the default implementation. A Just Left gives the absolute URL of the file, whereas a Just Right gives the type-safe URL. The former is necessary when you are serving the content outside the context of a Yesod application, such as via memcached.

  • maximumContentLength :: site -> Maybe (Route site) -> Maybe Word64

    Maximum allowed length of the request body, in bytes. This method may be ignored if maximumContentLengthIO is overridden.

    If Nothing, no maximum is applied.

    Default: 2 megabytes.

  • maximumContentLengthIO :: site -> Maybe (Route site) -> IO (Maybe Word64)

    Maximum allowed length of the request body, in bytes. This is similar to maximumContentLength, but the result lives in IO. This allows you to dynamically change the maximum file size based on some external source like a database or an IORef.

    The default implementation uses maximumContentLength. Future version of yesod will remove maximumContentLength and use this method exclusively.

  • makeLogger :: site -> IO Logger

    Creates a Logger to use for log messages.

    Note that a common technique (endorsed by the scaffolding) is to create a Logger value and place it in your foundation datatype, and have this method return that already created value. That way, you can use that same Logger for printing messages during app initialization.

    Default: the defaultMakeLogger function.

  • messageLoggerSource :: site -> Logger -> Loc -> LogSource -> LogLevel -> LogStr -> IO ()

    Send a message to the Logger provided by getLogger.

    Default: the defaultMessageLoggerSource function, using shouldLogIO to check whether we should log.

  • jsLoader :: site -> ScriptLoadPosition site

    Where to Load sripts from. We recommend the default value, BottomOfBody.

  • jsAttributes :: site -> [(Text, Text)]

    Default attributes to put on the JavaScript script tag generated for julius files

  • jsAttributesHandler :: HandlerFor site [(Text, Text)]

    Same as jsAttributes but allows you to run arbitrary Handler code

    This is useful if you need to add a randomised nonce value to the script tag generated by widgetFile. If this function is overridden then jsAttributes is ignored.

  • makeSessionBackend :: site -> IO (Maybe SessionBackend)

    Create a session backend. Returning Nothing disables sessions. If you'd like to change the way that the session cookies are created, take a look at customizeSessionCookies.

    Default: Uses clientsession with a 2 hour timeout.

  • fileUpload :: site -> RequestBodyLength -> FileUpload

    How to store uploaded files.

    Default: When the request body is greater than 50kb, store in a temp file. For chunked request bodies, store in a temp file. Otherwise, store in memory.

  • shouldLogIO :: site -> LogSource -> LogLevel -> IO Bool

    Should we log the given log source/level combination.

    Default: the defaultShouldLogIO function.

    Since 1.2.4

  • yesodMiddleware :: ToTypedContent res => HandlerFor site res -> HandlerFor site res

    A Yesod middleware, which will wrap every handler function. This allows you to run code before and after a normal handler.

    Default: the defaultYesodMiddleware function.

    Since: 1.1.6

  • yesodWithInternalState :: site -> Maybe (Route site) -> (InternalState -> IO a) -> IO a

    How to allocate an InternalState for each request.

    The default implementation is almost always what you want. However, if you know that you are never taking advantage of the MonadResource instance in your handler functions, setting this to a dummy implementation can provide a small optimization. Only do this if you really know what you're doing, otherwise you can turn safe code into a runtime error!

    Since 1.4.2

  • defaultMessageWidget :: Html -> HtmlUrl (Route site) -> WidgetFor site ()

    Convert a title and HTML snippet into a Widget. Used primarily for wrapping up error messages for better display.

Instances1Yesod
  • Yesod LiteAppDefined in yesod-core-1.6.26.0 · Yesod.Core.Internal.LiteApp
datadata Value
#

A JSON value represented as a Haskell value.

Instances41Eq, Data, Ord, Read, Show, IsString, …

The WAI application.

Note that, since WAI 3.0, this type is structured in continuation passing style to allow for proper safe resource handling. This was handled in the past via other means (e.g., ResourceT). As a demonstration:

app :: Application
app req respond = bracket_
    (putStrLn "Allocating scarce resource")
    (putStrLn "Cleaning up")
    (respond $ responseLBS status200 [] "Hello World")
Instances2ToApplication
  • ToApplication ApplicationDefined in wai-extra-3.1.16 · Network.Wai.UrlMap
  • ToApplication UrlMapDefined in wai-extra-3.1.16 · Network.Wai.UrlMap
classclass (MonadResource m, MonadLogger m) => MonadHandler (m :: Type -> Type) where
#

Associated types

Instances15MonadHandler, …
valuesendFile :: MonadHandler m => ContentType -> FilePath -> m a
#

Bypass remaining handler code and output the given file.

For some backends, this is more efficient than reading in the file to memory, since they can optimize file sending via a system call to sendfile.

familydata family Route a
#

The type-safe URLs associated with a site argument.

Instances18RedirectUrl, Eq, Ord, Read, Show, Route, …
newtypenewtype HandlerFor site a
#

A generic handler monad, which can have a different subsite and master site. We define a newtype for better error message.

Instances15Monad, Functor, Applicative, MonadIO, MonadThrow, PrimMonad, …
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
    
Instances32MonadIO, …
classclass FromJSON a where
#

A type that can be converted from JSON, with the possibility of failure.

In many cases, you can get the compiler to generate parsing code for you (see below). To begin, let's cover writing an instance by hand.

There are various reasons a conversion could fail. For example, an Object could be missing a required key, an Array could be of the wrong size, or a value could be of an incompatible type.

The basic ways to signal a failed conversion are as follows:

  • fail yields a custom error message: it is the recommended way of reporting a failure;

  • empty (or mzero) is uninformative: use it when the error is meant to be caught by some (<|>);

  • typeMismatch can be used to report a failure when the encountered value is not of the expected JSON type; unexpected is an appropriate alternative when more than one type may be expected, or to keep the expected type implicit.

prependFailure (or modifyFailure) add more information to a parser's error messages.

An example type and instance using typeMismatch and prependFailure:

-- Allow ourselves to write Text literals.
{-# LANGUAGE OverloadedStrings #-}

data Coord = Coord { x :: Double, y :: Double }

instance FromJSON Coord where
    parseJSON (Object v) = Coord
        <$> v .: "x"
        <*> v .: "y"

    -- We do not expect a non-Object value here.
    -- We could use empty to fail, but typeMismatch
    -- gives a much more informative error message.
    parseJSON invalid    =
        prependFailure "parsing Coord failed, "
            (typeMismatch "Object" invalid)

For this common case of only being concerned with a single type of JSON value, the functions withObject, withScientific, etc. are provided. Their use is to be preferred when possible, since they are more terse. Using withObject, we can rewrite the above instance (assuming the same language extension and data type) as:

instance FromJSON Coord where
    parseJSON = withObject "Coord" $ \v -> Coord
        <$> v .: "x"
        <*> v .: "y"

Instead of manually writing your FromJSON instance, there are two options to do it automatically:

  • Data.Aeson.TH provides Template Haskell functions which will derive an instance at compile time. The generated instance is optimized for your type so it will probably be more efficient than the following option.

  • The compiler can provide a default generic implementation for parseJSON.

To use the second, simply add a deriving Generic clause to your datatype and declare a FromJSON instance for your datatype without giving a definition for parseJSON.

For example, the previous example can be simplified to just:

{-# LANGUAGE DeriveGeneric #-}

import GHC.Generics

data Coord = Coord { x :: Double, y :: Double } deriving Generic

instance FromJSON Coord

or using the DerivingVia extension

deriving via Generically Coord instance FromJSON Coord

The default implementation will be equivalent to parseJSON = genericParseJSON defaultOptions; if you need different options, you can customize the generic decoding by defining:

customOptions = defaultOptions
                { fieldLabelModifier = map toUpper
                }

instance FromJSON Coord where
    parseJSON = genericParseJSON customOptions

Methods

Instances119FromJSON, …
value(.:) :: FromJSON a => Object -> Key -> Parser a
#

Retrieve the value associated with the given key of an Object. The result is empty if the key is not present or the value cannot be converted to the desired type.

This accessor is appropriate if the key and value must be present in an object for it to be valid. If the key and value are optional, use .:? instead.

classclass ToWidget site a where
#

Methods

Instances12ToWidget, …
  • ToWidget site HtmlDefined in yesod-core-1.6.26.0 · Yesod.Core.Widget
  • ToWidget site CssDefined in yesod-core-1.6.26.0 · Yesod.Core.Widget
  • ToWidget site JavascriptDefined in yesod-core-1.6.26.0 · Yesod.Core.Widget
  • ToWidget site TextDefined in yesod-core-1.6.26.0 · Yesod.Core.Widget
  • ToWidget site BuilderDefined in yesod-core-1.6.26.0 · Yesod.Core.Widget
  • ToWidget site TextDefined in yesod-core-1.6.26.0 · Yesod.Core.Widget
  • ToWidget site CssBuilderDefined in yesod-core-1.6.26.0 · Yesod.Core.Widget
  • (site' ~ site, a ~ ()) => ToWidget site' (WidgetFor site a)Defined in yesod-core-1.6.26.0 · Yesod.Core.Widget
  • render ~ RY site => ToWidget site (render -> Html)Defined in yesod-core-1.6.26.0 · Yesod.Core.Widget
  • render ~ RY site => ToWidget site (render -> Css)Defined in yesod-core-1.6.26.0 · Yesod.Core.Widget
  • render ~ RY site => ToWidget site (render -> Javascript)Defined in yesod-core-1.6.26.0 · Yesod.Core.Widget
  • render ~ RY site => ToWidget site (render -> CssBuilder)Defined in yesod-core-1.6.26.0 · Yesod.Core.Widget
classclass YesodBreadcrumbs site where
#

A type-safe, concise method of creating breadcrumbs for pages. For each resource, you declare the title of the page and the parent resource (if present).

Methods

familytype family HandlerSite (m :: Type -> Type)
#
Instances15HandlerSite, …
classclass MonadHandler m => MonadWidget (m :: Type -> Type) where
#

Methods

Instances13MonadWidget, …
familytype family SubHandlerSite (m :: Type -> Type)
#
Instances15SubHandlerSite, …
valuecsrfCheckMiddleware
  1. :: HandlerFor site res
  2. -> HandlerFor site Bool

    Whether or not to perform the CSRF check.

  3. -> CI ByteString

    The header name to lookup the CSRF token from.

  4. -> Text

    The POST parameter name to lookup the CSRF token from.

  5. -> HandlerFor site res
#

Looks up the CSRF token from the request headers or POST parameters. If the value doesn't match the token stored in the session, this function throws a PermissionDenied error.

For details, see the "AJAX CSRF protection" section of Yesod.Core.Handler.

Since 1.4.14

valuecsrfSetCookieMiddleware
  1. :: HandlerFor site res
  2. -> SetCookie
  3. -> HandlerFor site res
#

Takes a SetCookie and overrides its value with a CSRF token, then sets the cookie. See setCsrfCookieWithCookie.

For details, see the "AJAX CSRF protection" section of Yesod.Core.Handler.

Make sure to set the setCookiePath to the root path of your application, otherwise you'll generate a new CSRF token for every path of your app. If your app is run from from e.g. www.example.com/app1, use app1. The vast majority of sites will just use /.

Since 1.4.14

valueenvClientSessionBackend
  1. :: Int

    minutes

  2. -> String

    environment variable name

  3. -> IO SessionBackend
#

Create a SessionBackend which reads the session key from the named environment variable.

This can be useful if:

  1. You can't rely on a persistent file system (e.g. Heroku)

  2. Your application is open source (e.g. you can't commit the key)

By keeping a consistent value in the environment variable, your users will have consistent sessions without relying on the file system.

Note: A suitable value should only be obtained in one of two ways:

  1. Run this code without the variable set, a value will be generated and printed on devstdout/

  2. Use clientsession-generate

Since 1.4.5

Default formatting for log messages. When you use the template haskell logging functions for to log with information about the source location, that information will be appended to the end of the log. When you use the non-TH logging functions, like logDebugN, this function does not include source information. This currently works by checking to see if the package name is the string "<unknown>". This is a hack, but it removes some of the visual clutter from non-TH logs.

Since 1.4.10

valueguessApprootOr :: Approot site -> Approot site
#

Guess the approot based on request headers, with fall back to the specified AppRoot.

Since 1.4.16

Helps defend against CSRF attacks by setting the SameSite attribute on session cookies to Lax. With the Lax setting, the cookie will be sent with same-site requests, and with cross-site top-level navigations.

This option is liable to change in future versions of Yesod as the spec evolves. View more information here.

valuesslOnlyMiddleware
  1. :: Int

    minutes

  2. -> HandlerFor site res
  3. -> HandlerFor site res
#

Apply a Strict-Transport-Security header with the specified timeout to all responses so that browsers will rewrite all http links to https until the timeout expires. For security, the max-age of the STS header should always equal or exceed the client sessions timeout. This defends against SSL-stripping man-in-the-middle attacks. It is only effective if a secure connection has already been made; Strict-Transport-Security headers are ignored over HTTP.

Since 1.4.7

Defends against session hijacking by setting the secure bit on session cookies so that browsers will not transmit them over http. With this setting on, it follows that the server will regard requests made over http as sessionless, because the session cookie will not be included in the request. Use this as part of a total security measure which also includes disabling HTTP traffic to the site or issuing redirects from HTTP urls, and composing sslOnlyMiddleware with the site's yesodMiddleware.

Since 1.4.7

Helps defend against CSRF attacks by setting the SameSite attribute on session cookies to Strict. With the Strict setting, the cookie will only be sent with same-site requests.

This option is liable to change in future versions of Yesod as the spec evolves. View more information here.

classclass ToTypedContent a => HasContentType a where
#

Methods

Instances12HasContentType, …
classclass ToContent a where
#

Anything which can be converted into Content. Most of the time, you will want to use the ContentBuilder constructor. An easier approach will be to use a pre-defined toContent function, such as converting your data into a lazy bytestring and then calling toContent on that.

Please note that the built-in instances for lazy data structures (String, lazy ByteString, lazy Text and Html) will not automatically include the content length for the ContentBuilder constructor.

Methods

Instances24ToContent, …
classclass ToFlushBuilder a where
#

A class for all data which can be sent in a streaming response. Note that for textual data, instances must use UTF-8 encoding.

Since 1.2.0

Instances14ToFlushBuilder, …
classclass ToContent a => ToTypedContent a where
#

Any type which can be converted to TypedContent.

Since 1.2.0

Instances17ToTypedContent, …

Removes "extra" information at the end of a content type string. In particular, removes everything after the semicolon, if present.

For example, "text/html; charset=utf-8" is commonly used to specify the character encoding for HTML data. This function would return "text/html".

valuedefaultGen :: IO Int
#

Generate a random number uniformly distributed in the full range of Int.

Note: Before 1.6.20, this generates pseudo-random number in an unspecified range. The range size may not be a power of 2. Since 1.6.20, this uses a secure entropy source and generates in the full range of Int.

valuetoWaiApp :: YesodDispatch site => site -> IO Application
#

Same as toWaiAppPlain, but provides a default set of middlewares. This set may change with future releases, but currently covers:

  • Logging

  • GZIP compression

  • Automatic HEAD method handling

  • Request method override with the _method query string parameter

  • Accept header override with the _accept query string parameter

valuetoWaiAppPlain :: YesodDispatch site => site -> IO Application
#

Convert the given argument into a WAI application, executable with any WAI handler. This function will provide no middlewares; if you want commonly used middlewares, please use toWaiApp.

valuewarpEnv :: YesodDispatch site => site -> IO ()
#

Runs your application using default middlewares (i.e., via toWaiApp). It reads port information from the PORT environment variable, as used by tools such as Keter and the FP Complete School of Haskell.

Note that the exact behavior of this function may be modified slightly over time to work correctly with external tools, without a change to the type signature.

datadata Fragment a b
#

Add a fragment identifier to a route to be used when redirecting. For example:

redirect (NewsfeedR :#: storyId)

@since 1.2.9.

Constructors

Instances2RedirectUrl, Show
datadata ProvidedRep (m :: Type -> Type)
#

Internal representation of a single provided representation.

classclass RedirectUrl master a where
#

Some value which can be turned into a URL for redirects.

Methods

Instances6RedirectUrl
valueaddHeader :: MonadHandler m => Text -> Text -> m ()
#

Set an arbitrary response header.

Note that, while the data type used here is Text, you must provide only ASCII value to be HTTP compliant.

valuecacheSeconds :: MonadHandler m => Int -> m ()
#

Set the Cache-Control header to indicate this response should be cached for the given number of seconds.

valuecached :: (MonadHandler m, Typeable a) => m a -> m a
#

Use a per-request cache to avoid performing the same action multiple times. Values are stored by their type, the result of typeOf from Typeable. Therefore, you should use different newtype wrappers at each cache site.

For example, yesod-auth uses an un-exported newtype, CachedMaybeAuth and exports functions that utilize it such as maybeAuth. This means that another module can create its own newtype wrapper to cache the same type from a different action without any cache conflicts.

See the original announcement: http://www.yesodweb.com/blog/2013/03/yesod-1-2-cleaner-internals

valuecachedBy :: (MonadHandler m, Typeable a) => ByteString -> m a -> m a
#

a per-request cache. just like cached. cached can only cache a single value per type. cachedBy stores multiple values per type by usage of a ByteString key

cached is ideal to cache an action that has only one value of a type, such as the session's current user cachedBy is required if the action has parameters and can return multiple values per type. You can turn those parameters into a ByteString cache key. For example, caching a lookup of a Link by a token where multiple token lookups might be performed.

valuedeleteCookie
  1. :: MonadHandler m
  2. => Text

    key

  3. -> Text

    path

  4. -> m ()
#

Unset the cookie on the client.

Note: although the value used for key and path is Text, you should only use ASCII values to be HTTP compliant.

valuegetsYesod :: MonadHandler m => (HandlerSite m -> a) -> m a
#

Get a specific component of the master site application argument. Analogous to the gets function for operating on StateT.

valuehandlerToIO :: MonadIO m => HandlerFor site (HandlerFor site a -> m a)
#

Returns a function that runs HandlerFor actions inside IO.

Sometimes you want to run an inner HandlerFor action outside the control flow of an HTTP request (on the outer HandlerFor action). For example, you may want to spawn a new thread:

getFooR :: Handler RepHtml
getFooR = do
  runInnerHandler <- handlerToIO
  liftIO $ forkIO $ runInnerHandler $ do
    Code here runs inside HandlerFor but on a new thread.
    This is the inner HandlerFor.
    ...
  Code here runs inside the request's control flow.
  This is the outer HandlerFor.
  ...

Another use case for this function is creating a stream of server-sent events using HandlerFor actions (see yesod-eventsource).

Most of the environment from the outer HandlerFor is preserved on the inner HandlerFor, however:

  • The request body is cleared (otherwise it would be very difficult to prevent huge memory leaks).

  • The cache is cleared (see cached).

Changes to the response made inside the inner HandlerFor are ignored (e.g., session variables, cookies, response headers). This allows the inner HandlerFor to outlive the outer HandlerFor (e.g., on the forkIO example above, a response may be sent to the client without killing the new thread).

valuelanguages :: MonadHandler m => m [Text]
#

Get the list of supported languages supplied by the user.

Languages are determined based on the following (in descending order of preference):

  • The _LANG get parameter.

  • The _LANG user session variable.

  • The _LANG cookie.

  • Accept-Language HTTP header.

Yesod will seek the first language from the returned list matched with languages supporting by your application. This language will be used to render i18n templates. If a matching language is not found the default language will be used.

This is handled by parseWaiRequest (not exposed).

NOTE: Before version 1.6.19.0, this function prioritized the session variable above all other sources.

valueneverExpires :: MonadHandler m => m ()
#

Set the Expires header to some date in 2037. In other words, this content is never (realistically) expired.

valuenotFound :: MonadHandler m => m a
#

Return a 404 not found page. Also denotes no handler available.

valuenotModified :: MonadHandler m => m a
#

Send a 304 not modified response immediately. This is a short-circuiting action.

valueprovideRepType
  1. :: (Monad m, ToContent a)
  2. => ContentType
  3. -> m a
  4. -> Writer (Endo [ProvidedRep m]) ()
#

Same as provideRep, but instead of determining the content type from the type of the value itself, you provide the content type separately. This can be a convenience instead of creating newtype wrappers for uncommonly used content types.

provideRepType "application/x-special-format" "This is the content"
valueredirect :: (MonadHandler m, RedirectUrl (HandlerSite m) url) => url -> m a
#

Redirect to the given route. HTTP status code 303 for HTTP 1.1 clients and 302 for HTTP 1.0 This is the appropriate choice for a get-following-post technique, which should be the usual use case.

If you want direct control of the final status code, or need a different status code, please use redirectWith.

valueredirectToPost
  1. :: (MonadHandler m, RedirectUrl (HandlerSite m) url)
  2. => url
  3. -> m a
#

Redirect to a POST resource.

This is not technically a redirect; instead, it returns an HTML page with a POST form, and some Javascript to automatically submit the form. This can be useful when you need to post a plain link somewhere that needs to cause changes on the server.

valueredirectUltDest
  1. :: (RedirectUrl (HandlerSite m) url, MonadHandler m)
  2. => url

    default destination if nothing in session

  3. -> m a
#

Redirect to the ultimate destination in the user's session. Clear the value from the session.

The ultimate destination is set with setUltDest.

This function uses redirect, and thus will perform a temporary redirect to a GET request.

valuereplaceOrAddHeader :: MonadHandler m => Text -> Text -> m ()
#

Replace an existing header with a new value or add a new header if not present.

Note that, while the data type used here is Text, you must provide only ASCII value to be HTTP compliant.

Use a Source for the response body.

Note that, for ease of use, the underlying monad is a HandlerFor. This implies that you can run any HandlerFor action. However, since a streaming response occurs after the response headers have already been sent, some actions make no sense here. For example: short-circuit responses, setting headers, changing status codes, etc.

valuesendFlush :: Monad m => ConduitT i (Flush Builder) m ()
#

In a streaming response, send a flush command, causing all buffered data to be immediately sent to the client.

valuesendWaiResponse :: MonadHandler m => Response -> m b
#

Send a Response. Please note: this function is rarely necessary, and will disregard any changes to response headers and session that you have already specified. This function short-circuits. It should be considered only for very specific needs. If you are not sure if you need it, you don't.

Takes a SetCookie and overrides its value with a CSRF token, then sets the cookie.

Make sure to set the setCookiePath to the root path of your application, otherwise you'll generate a new CSRF token for every path of your app. If your app is run from from e.g. www.example.com/app1, use app1. The vast majority of sites will just use /.

valuesetEtag :: MonadHandler m => Text -> m ()
#

Check the if-none-match header and, if it matches the given value, return a 304 not modified response. Otherwise, set the etag header to the given value.

Note that it is the responsibility of the caller to ensure that the provided value is a valid etag value, no sanity checking is performed by this function.

valuesetSession
  1. :: MonadHandler m
  2. => Text

    key

  3. -> Text

    value

  4. -> m ()
#

Set a variable in the user's session.

The session is handled by the clientsession package: it sets an encrypted and hashed cookie on the client. This ensures that all data is secure and not tampered with.

valuesetUltDestReferer :: MonadHandler m => m ()
#

Sets the ultimate destination to the referer request header, if present.

This function will not overwrite an existing ultdest.

valuesetWeakEtag :: MonadHandler m => Text -> m ()
#

Check the if-none-match header and, if it matches the given value, return a 304 not modified response. Otherwise, set the etag header to the given value.

A weak etag is only expected to be semantically identical to the prior content, but doesn't have to be byte-for-byte identical. Therefore it can be useful for dynamically generated content that may be difficult to perform bytewise hashing upon.

Note that it is the responsibility of the caller to ensure that the provided value is a valid etag value, no sanity checking is performed by this function.

newtypenewtype LiteApp
#
Instances11Semigroup, Monoid, YesodDispatch, Yesod, ParseRoute, RenderRoute, …
valuemkYesod
  1. :: String

    name of the argument datatype

  2. -> [ResourceTree String]
  3. -> Q [Dec]
#

Generates URL datatype and site function for the given Resources. This is used for creating sites, not subsites. See mkYesodSubData and mkYesodSubDispatch for the latter. Use parseRoutes to create the Resources.

Contexts and type variables in the name of the datatype are parsed. For example, a datatype App a with typeclass constraint MyClass a can be written as "(MyClass a) => App a".

valuemkYesodData :: String -> [ResourceTree String] -> Q [Dec]
#

Sometimes, you will want to declare your routes in one file and define your handlers elsewhere. For example, this is the only way to break up a monolithic file into smaller parts. Use this function, paired with mkYesodDispatch, to do just that.

valueacceptsJson :: MonadHandler m => m Bool
#

Returns True if the client prefers application/json as indicated by the Accept HTTP header.

Given the Content-Type header, returns if it is JSON.

This function is currently a simple check for application/json, but in the future may check for alternative representations such as xxx/yyy+json.

valuejsonEncodingOrRedirect
  1. :: (MonadHandler m, ToJSON a)
  2. => Route (HandlerSite m)

    Redirect target

  3. -> a

    Data to send via JSON

  4. -> m Encoding
#

jsonEncodingOrRedirect simplifies the scenario where a POST handler sends a different response based on Accept headers:

  1. 200 with JSON data if the client prefers application/json (e.g. AJAX, see acceptsJSON).

  2. 3xx otherwise, following the PRG pattern. @since 1.4.21

valuejsonOrRedirect
  1. :: (MonadHandler m, ToJSON a)
  2. => Route (HandlerSite m)

    Redirect target

  3. -> a

    Data to send via JSON

  4. -> m Value
#

jsonOrRedirect simplifies the scenario where a POST handler sends a different response based on Accept headers:

  1. 200 with JSON data if the client prefers application/json (e.g. AJAX, see acceptsJSON).

  2. 3xx otherwise, following the PRG pattern.

valuejsonToRepJson :: (Monad m, ToJSON a) => a -> m Value
#

Deprecated. Use returnJson instead

Wraps a data type in a RepJson. The data type must support conversion to JSON via ToJSON.

valueparseCheckJsonBody :: (MonadHandler m, FromJSON a) => m (Result a)
#

Parse the request body to a data type as a JSON value. The data type must support conversion from JSON via FromJSON. If you want the raw JSON value, just ask for a Result Value.

The MIME type must indicate JSON content. Requiring a JSON content-type helps secure your site against CSRF attacks (browsers will perform POST requests for form and text/plain content-types without doing a CORS check, and those content-types can easily contain valid JSON).

Note that this function will consume the request body. As such, calling it twice will result in a parse error on the second call, since the request body will no longer be available.

datadata ErrorResponse
#

Responses to indicate some form of an error occurred.

Constructors

  • NotFound

    The requested resource was not found. Examples of when this occurs include when an incorrect URL is used, or yesod-persistent's get404 doesn't find a value. HTTP status: 404.

  • InternalError !Text

    Some sort of unexpected exception. If your application uses throwIO or error to throw an exception, this is the form it would take. HTTP status: 500.

  • InvalidArgs ![Text]

    Indicates some sort of invalid or missing argument, like a missing query parameter or malformed JSON body. Examples Yesod functions that send this include requireCheckJsonBody and Yesod.Auth.GoogleEmail2. HTTP status: 400.

  • NotAuthenticated

    Indicates the user is not logged in. This is thrown when isAuthorized returns AuthenticationRequired. HTTP code: 401.

  • PermissionDenied !Text

    Indicates the user doesn't have permission to access the requested resource. This is thrown when isAuthorized returns Unauthorized. HTTP code: 403.

  • BadMethod !Method

    Indicates the URL would have been valid if used with a different HTTP method (e.g. a GET was used, but only POST is handled.) HTTP code: 405.

Instances5Eq, Show, Generic, NFData, Rep
datadata Content
#
Instances4IsString, ToContent, ToTypedContent
newtypenewtype CssBuilder
#

Newtype wrapper allowing injection of arbitrary content into CSS.

Usage:

toWidget $ CssBuilder "p { color: red }"

Since: 1.1.3

Instances6ToWidget, ToWidgetHead, ToWidgetMedia
newtypenewtype DontFullyEvaluate a
#

Prevents a response body from being fully evaluated before sending the request.

Since 1.1.0

Instances3HasContentType, ToContent, ToTypedContent
typetype RepHtml = Html
#

Deprecated. Please use Html instead

newtypenewtype SubHandlerFor sub master a
#

A handler monad for subsite

Instances13Monad, Functor, Applicative, MonadIO, MonadThrow, MonadUnliftIO, …
newtypenewtype WaiSubsite
#

Wrap up a normal WAI application as a Yesod subsite. Ignore parent site's middleware and isAuthorized.

Instances8ParseRoute, RenderRoute, YesodSubDispatch, Eq, Ord, Read, …
newtypenewtype WaiSubsiteWithAuth
#

Like WaiSubsite, but applies parent site's middleware and isAuthorized.

Instances8ParseRoute, RenderRoute, YesodSubDispatch, Eq, Ord, Read, …
newtypenewtype WidgetFor site a
#

A generic widget, allowing specification of both the subsite and master site datatypes. While this is simply a WriterT, we define a newtype for better error messages.

Instances20ToWidget, Monad, Functor, Applicative, MonadIO, MonadThrow, …
datadata YesodRequest
#

The parsed request information. This type augments the standard WAI Request with additional information.

Constructors

classclass ToWidgetBody site a where
#

Methods

Instances4ToWidgetBody
classclass ToWidgetHead site a where
#

Methods

Instances8ToWidgetHead, …
classclass ToWidgetMedia site a where
#

Allows adding some CSS to the page with a specific media type.

Since 1.2

Methods

Instances4ToWidgetMedia
valuesetDescription :: MonadWidget m => Text -> m ()
#

setDescription is not idempotent; we recommend setDescriptionIdemp instead Multiple calls to setDescription will insert multiple meta tags in the page head. If you want an idempotent function, use setDescriptionIdemp - but if you do, you may need to change your layout to include pageDescription.

Add description meta tag to the head of the page

Google does not use the description tag as a ranking signal, but the contents of this tag will likely affect your click-through rate since it shows up in search results.

The average length of the description shown in Google's search results is about 160 characters on desktop, and about 130 characters on mobile, at time of writing.

Source: https://www.advancedwebranking.com/blog/meta-tags-important-in-seo/

valuesetDescriptionI
  1. :: (MonadWidget m, RenderMessage (HandlerSite m) msg)
  2. => msg
  3. -> m ()
#

setDescriptionI is not idempotent; we recommend setDescriptionIdempI instead Multiple calls to setDescriptionI will insert multiple meta tags in the page head. If you want an idempotent function, use setDescriptionIdempI - but if you do, you may need to change your layout to include pageDescription.

Add translated description meta tag to the head of the page

n.b. See comments for setDescription.

valuesetDescriptionIdemp :: MonadWidget m => Text -> m ()
#

Add description meta tag to the head of the page

Google does not use the description tag as a ranking signal, but the contents of this tag will likely affect your click-through rate since it shows up in search results.

The average length of the description shown in Google's search results is about 160 characters on desktop, and about 130 characters on mobile, at time of writing.

Unlike setDescription, this version is *idempotent* - calling it multiple times will result in only a single description meta tag in the head.

Source: https://www.advancedwebranking.com/blog/meta-tags-important-in-seo/

valuesetOGImage :: MonadWidget m => Text -> m ()
#

Add OpenGraph image meta tag to the head of the page

Best practices:

  • Use custom images for shareable pages, e.g., homepage, articles, etc.

  • Use your logo or any other branded image for the rest of your pages.

  • Use images with a 1.91:1 ratio and minimum recommended dimensions of 1200x630 for optimal clarity across all devices.

Source: https://ahrefs.com/blog/open-graph-meta-tags/

valuesetTitle :: MonadWidget m => Html -> m ()
#

Set the page title.

Calling setTitle or setTitleI multiple times overrides previously set values.

SEO Notes:

  • Title tags are the second most important on-page factor for SEO, after content

  • Every page should have a unique title tag

  • Start your title tag with your main targeted keyword

  • Don't stuff your keywords

  • Google typically shows 55-64 characters, so aim to keep your title length under 60 characters

datadata RouteOpts
#

General opts data type for generating yesod.

Contains options for what instances are derived for the route. Use the setting functions on defaultOpts to set specific fields.

valuedefaultOpts :: RouteOpts
#

Default options for generating routes.

Defaults to all instances derived.

valueobject :: [Pair] -> Value
#

Create a Value from a list of name/value Pairs. If duplicate keys arise, later keys and their associated values win.

valuelogDebug :: Q Exp
#

Generates a function that takes a Text and logs a LevelDebug message. Usage:

$(logDebug) "This is a debug log message"
valuelogOther :: Text -> Q Exp
#

Generates a function that takes a Text and logs a LevelOther message. Usage:

$(logOther "My new level") "This is a log message"
valuelogOtherS :: Q Exp
#

Generates a function that takes a LogSource, a level name and a Text and logs a LevelOther message. Usage:

$logOtherS "SomeSource" "My new level" "This is a log message"
valuehamlet :: QuasiQuoter
#

Hamlet quasi-quoter. May only be used to generate expressions.

Generated expression have type HtmlUrl url, for some url.

data MyRoute = Home

render :: Render MyRoute
render Home _ = "/home"

>>> putStrLn (renderHtml ([hamlet|<a href=@{Home}>Home|] render))
<a href="/home">Home</a>
valueshamlet :: QuasiQuoter
#

"Simple Hamlet" quasi-quoter. May only be used to generate expressions.

Generated expressions have type Html.

>>> putStrLn (Text.Blaze.Html.Renderer.renderHtml [shamlet|<div>Hello, world!|])
<div>Hello, world!</div>
valuerenderJavascriptUrl
  1. :: url -> [(Text, Text)] -> Text
  2. -> JavascriptUrl url
  3. -> Text
#

render with route interpolation. If using this module standalone, apart from type-safe routes, a dummy renderer can be used:

renderJavascriptUrl (\_ _ -> undefined) javascriptUrl

When using Yesod, a renderer is generated for you, which can be accessed within the GHandler monad: getUrlRenderParams.

valuelucius :: QuasiQuoter
#
Example1 expression
renderCss ([lucius|foo{bar:baz}|] undefined)"foo{bar:baz}"
valuemkMessage
  1. :: String

    base name to use for translation type

  2. -> FilePath

    subdirectory which contains the translation files

  3. -> Lang

    default translation language

  4. -> Q [Dec]
#

generate translations from translation files

This function will:

  1. look in the supplied subdirectory for files ending in .msg

  2. generate a type based on the constructors found

  3. create a RenderMessage instance

classclass ToJSON a where
#

A type that can be converted to JSON.

Instances in general must specify toJSON and should (but don't need to) specify toEncoding.

An example type and instance:

-- Allow ourselves to write Text literals.
{-# LANGUAGE OverloadedStrings #-}

data Coord = Coord { x :: Double, y :: Double }

instance ToJSON Coord where
  toJSON (Coord x y) = object ["x" .= x, "y" .= y]

  toEncoding (Coord x y) = pairs ("x" .= x <> "y" .= y)

Instead of manually writing your ToJSON instance, there are two options to do it automatically:

  • Data.Aeson.TH provides Template Haskell functions which will derive an instance at compile time. The generated instance is optimized for your type so it will probably be more efficient than the following option.

  • The compiler can provide a default generic implementation for toJSON.

To use the second, simply add a deriving Generic clause to your datatype and declare a ToJSON instance. If you require nothing other than defaultOptions, it is sufficient to write (and this is the only alternative where the default toJSON implementation is sufficient):

{-# LANGUAGE DeriveGeneric #-}

import GHC.Generics

data Coord = Coord { x :: Double, y :: Double } deriving Generic

instance ToJSON Coord where
    toEncoding = genericToEncoding defaultOptions

or more conveniently using the DerivingVia extension

deriving via Generically Coord instance ToJSON Coord

If on the other hand you wish to customize the generic decoding, you have to implement both methods:

customOptions = defaultOptions
                { fieldLabelModifier = map toUpper
                }

instance ToJSON Coord where
    toJSON     = genericToJSON customOptions
    toEncoding = genericToEncoding customOptions

Previous versions of this library only had the toJSON method. Adding toEncoding had two reasons:

  1. toEncoding is more efficient for the common case that the output of toJSON is directly serialized to a ByteString. Further, expressing either method in terms of the other would be non-optimal.

  2. The choice of defaults allows a smooth transition for existing users: Existing instances that do not define toEncoding still compile and have the correct semantics. This is ensured by making the default implementation of toEncoding use toJSON. This produces correct results, but since it performs an intermediate conversion to a Value, it will be less efficient than directly emitting an Encoding. (this also means that specifying nothing more than instance ToJSON Coord would be sufficient as a generically decoding instance, but there probably exists no good reason to not specify toEncoding in new instances.)

Methods

  • toJSON :: a -> Value

    Convert a Haskell value to a JSON-friendly intermediate type.

  • toEncoding :: a -> Encoding

    Encode a Haskell value as JSON.

    The default implementation of this method creates an intermediate Value using toJSON. This provides source-level compatibility for people upgrading from older versions of this library, but obviously offers no performance advantage.

    To benefit from direct encoding, you must provide an implementation for this method. The easiest way to do so is by having your types implement Generic using the DeriveGeneric extension, and then have GHC generate a method body as follows.

    instance ToJSON Coord where
        toEncoding = genericToEncoding defaultOptions
    
  • toJSONList :: [a] -> Value
  • toEncodingList :: [a] -> Encoding
  • omitField :: a -> Bool

    Defines when it is acceptable to omit a field of this type from a record. Used by (.?=) operator, and Generics and TH deriving with omitNothingFields = True.

Instances119ToJSON, …
typetype Html = Markup
#
Instances14PersistField, PersistFieldSql, ToHamletData, HasContentType, ToContent, ToTypedContent, …
classclass Monad m => MonadLogger (m :: Type -> Type) where
#

A Monad which has the ability to log messages in some manner.

Instances20MonadLogger, …
classclass PathPiece s where
#

Methods

Instances23PathPiece, …
classclass MonadIO m => MonadResource (m :: Type -> Type) where
#

A Monad which allows for safe resource allocation. In theory, any monad transformer stack which includes a ResourceT can be an instance of MonadResource.

Note: runResourceT has a requirement for a MonadUnliftIO m monad, which allows control operations to be lifted. A MonadResource does not have this requirement. This means that transformers such as ContT can be an instance of MonadResource. However, the ContT wrapper will need to be unwrapped before calling runResourceT.

Since 0.3.0

Methods

Instances19MonadResource, …
typetype Lang = Text
#

an RFC1766 / ISO 639-1 language code (eg, fr, en-GB, etc).

classclass RenderMessage master message where
#

the RenderMessage is used to provide translations for a message types

The master argument exists so that it is possible to provide more than one set of translations for a message type. This is useful if a library provides a default set of translations, but the user of the library wants to provide a different set of translations.

Methods

Instances2RenderMessage
classclass ToMessage a where
#

ToMessage is used to convert the value inside #{ } to Text

The primary purpose of this class is to allow the value in #{ } to be a String or Text rather than forcing it to always be Text.

Methods

Instances2ToMessage
  • ToMessage StringDefined in shakespeare-2.1.0.1 · Text.Shakespeare.I18N
  • ToMessage TextDefined in shakespeare-2.1.0.1 · Text.Shakespeare.I18N
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.

Instances25MonadTrans, …
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.

Instances9MonadUnliftIO, …
datadata OptionList a
#

A structure holding a list of options. Typically you can use a convenience function like mkOptionList or optionsPairs instead of creating this directly.

Extended by OptionListGrouped in 1.7.0.

Constructors

Instances1Functor
newtypenewtype Textarea
#

A newtype wrapper around a Text whose ToMarkup instance converts newlines to HTML <br> tags.

(When text is entered into a <textarea>, newline characters are used to separate lines. If this text is then placed verbatim into HTML, the lines won't be separated, thus the need for replacing with <br> tags). If you don't need this functionality, simply use unTextarea to access the raw text.

Constructors

Instances10Eq, Ord, Read, Show, IsString, FromJSON, …

Creates a group of radio buttons to answer the question given in the message. Radio buttons are used to allow differentiating between an empty response (Nothing) and a no response (Just False). Consider using the simpler checkBoxField if you don't need to make this distinction.

If this field is optional, the first radio button is labeled "<None>", the second "Yes" and the third "No".

If this field is required, the first radio button is labeled "Yes" and the second "No".

(Exact label titles will depend on localization).

valuecheckBoxField :: Monad m => Field m Bool
#

Creates an input with type="checkbox". While the default boolField implements a radio button so you can differentiate between an empty response (Nothing) and a no response (Just False), this simpler checkbox field returns an empty response as Just False.

Note that this makes the field always optional.

valueoptionsPersist
  1. :: (YesodPersist site, PersistQueryRead backend, PathPiece (Key a), RenderMessage site msg, YesodPersistBackend site ~ backend, PersistRecordBackend a backend)
  2. => [Filter a]
  3. -> [SelectOpt a]
  4. -> a -> msg
  5. -> HandlerFor site (OptionList (Entity a))
#

Selects a list of Entitys with the given Filter and SelectOpts. The (a -> msg) function is then used to derive the display value for an OptionList. Example usage:

Country
   name Text
   deriving Eq -- Must derive Eq
data CountryForm = CountryForm
  { country :: Entity Country
  }

countryNameForm :: AForm Handler CountryForm
countryNameForm = CountryForm
        <$> areq (selectField countries) "Which country do you live in?" Nothing
        where
          countries = optionsPersist [] [Asc CountryName] countryName
valueselectFieldHelper
  1. :: (Eq a, RenderMessage site FormMessage)
  2. => (Text -> Text -> [(Text, Text)] -> WidgetFor site () -> WidgetFor site ())

    Outermost part of the field

  3. -> (Text -> Text -> Bool -> WidgetFor site ())

    An option for None if the field is optional

  4. -> (Text -> Text -> [(Text, Text)] -> Text -> Bool -> Text -> WidgetFor site ())

    Other options

  5. -> Maybe (Text -> WidgetFor site ())

    Group headers placed inbetween options

  6. -> HandlerFor site (OptionList a)
  7. -> Field (HandlerFor site) a
#

A helper function for constucting selectFields with optional option groups. You may want to use this when you define your custom selectFields or radioFields.

Creates an input with type="text", parsing the time from an [H]H:MM[:SS] format, with an optional AM or PM (if not given, AM is assumed for compatibility with the 24 hour clock system).

This function exists for backwards compatibility with the old implementation of timeField, which used to use type="text". Consider using timeField or timeFieldTypeTime for improved UX and validation from the browser.

Add the time package and import the Data.Time.LocalTime module to use this function.

valueaddClass
  1. :: Text

    The class to add

  2. -> [(Text, Text)]

    List of existing fsAttrs

  3. -> [(Text, Text)]
#

Adds a CSS class to the fsAttrs in a FieldSettings.

Examples
Example1 expression
addClass "login-form" [("class", "form-control"), ("id", "home-login")][("class","form-control login-form"),("id","home-login")]
valueareqMsg
  1. :: (RenderMessage site msg, HandlerSite m ~ site, MonadHandler m)
  2. => Field m a

    form field

  3. -> FieldSettings site

    settings for this field

  4. -> msg

    message to use in case value is Nothing

  5. -> Maybe a

    optional default value

  6. -> AForm m a
#

Same as areq but with your own message to be rendered in case the value is not provided.

This is useful when you have several required fields on the page and you want to differentiate between which fields were left blank. Otherwise the user sees "Value is required" multiple times, which is ambiguous.

valuecheckMMap
  1. :: (Monad m, RenderMessage (HandlerSite m) msg)
  2. => a -> m (Either msg b)
  3. -> b -> a
  4. -> Field m a
  5. -> Field m b
#

Same as checkM, but modifies the datatype.

In order to make this work, you must provide a function to convert back from the new datatype to the old one (the second argument to this function).

Since 1.1.2

valueconvertField :: Functor m => (a -> b) -> (b -> a) -> Field m a -> Field m b
#

Since a Field cannot be a Functor, it is not obvious how to "reuse" a Field on a newtype or otherwise equivalent type. This function allows you to convert a Field m a to a Field m b assuming you provide a bidirectional conversion between the two, through the first two functions.

A simple example:

import Data.Monoid
sumField :: (Functor m, Monad m, RenderMessage (HandlerSite m) FormMessage) => Field m (Sum Int)
sumField = convertField Sum getSum intField

Another example, not using a newtype, but instead creating a Lazy Text field:

import qualified Data.Text.Lazy as TL
TextField :: (Functor m, Monad m, RenderMessage (HandlerSite m) FormMessage) => Field m TL.Text
lazyTextField = convertField TL.fromStrict TL.toStrict textField

Since 1.3.16

valueidentifyForm
  1. :: Monad m
  2. => Text

    Form identification string.

  3. -> (Markup -> MForm m (FormResult a, WidgetFor (HandlerSite m) ()))
  4. -> Markup
  5. -> MForm m (FormResult a, WidgetFor (HandlerSite m) ())
#

Creates a hidden field on the form that identifies it. This identification is then used to distinguish between missing and wrong form data when a single handler contains more than one form.

For instance, if you have the following code on your handler:

((fooRes, fooWidget), fooEnctype) <- runFormPost fooForm
((barRes, barWidget), barEnctype) <- runFormPost barForm

Then replace it with

((fooRes, fooWidget), fooEnctype) <- runFormPost $ identifyForm "foo" fooForm
((barRes, barWidget), barEnctype) <- runFormPost $ identifyForm "bar" barForm

Note that it's your responsibility to ensure that the identification strings are unique (using the same one twice on a single handler will not generate any errors). This allows you to create a variable number of forms and still have them work even if their number or order change between the HTML generation and the form submission.

valuemreqMsg
  1. :: (RenderMessage site msg, HandlerSite m ~ site, MonadHandler m)
  2. => Field m a

    form field

  3. -> FieldSettings site

    settings for this field

  4. -> msg

    Message to use in case value is Nothing

  5. -> Maybe a

    optional default value

  6. -> MForm m (FormResult a, FieldView site)
#

Same as mreq but with your own message to be rendered in case the value is not provided.

This is useful when you have several required fields on the page and you want to differentiate between which fields were left blank. Otherwise the user sees "Value is required" multiple times, which is ambiguous.

valueremoveClass
  1. :: Text

    The class to remove

  2. -> [(Text, Text)]

    List of existing fsAttrs

  3. -> [(Text, Text)]
#

Removes a CSS class from the fsAttrs in a FieldSettings.

Examples
Example1 expression
removeClass "form-control" [("class","form-control login-form"),("id","home-login")][("class","  login-form"),("id","home-login")]
valuerenderBootstrap2 :: Monad m => FormRender m a
#

Render a form using Bootstrap v2-friendly shamlet syntax. If you're using Bootstrap v3, then you should use the functions from module Yesod.Form.Bootstrap3.

Sample Hamlet:

 <form .form-horizontal method=post action=@{ActionR} enctype=#{formEnctype}>
   <fieldset>
     <legend>_{MsgLegend}
     $case result
       $of FormFailure reasons
         $forall reason <- reasons
           <div .alert .alert-error>#{reason}
       $of _
     ^{formWidget}
     <div .form-actions>
       <input .btn .primary type=submit value=_{MsgSubmit}>

Since 1.3.14

valuerenderTable :: Monad m => FormRender m a
#

Render a form into a series of tr tags. Note that, in order to allow you to add extra rows to the table, this function does not wrap up the resulting HTML in a table tag; you must do that yourself.

This function is used to both initially render a form and to later extract results from it. Note that, due to CSRF protection and a few other issues, forms submitted via GET and POST are slightly different. As such, be sure to call the relevant function based on how the form will be submitted, not the current request method.

For example, a common case is displaying a form on a GET request and having the form submit to a POST page. In such a case, both the GET and POST handlers should use runFormPost.

valuewreqMsg
  1. :: (RenderMessage site msg, HandlerSite m ~ site, MonadHandler m)
  2. => Field m a

    form field

  3. -> FieldSettings site

    settings for this field

  4. -> msg

    message to use in case value is Nothing

  5. -> Maybe a

    optional default value

  6. -> WForm m (FormResult a)
#

Same as wreq but with your own message to be rendered in case the value is not provided.

This is useful when you have several required fields on the page and you want to differentiate between which fields were left blank. Otherwise the user sees "Value is required" multiple times, which is ambiguous.

valueiopt :: Monad m => Field m a -> Text -> FormInput m (Maybe a)
#

Promote a Field into a FormInput, with its presence being optional. If the value is present but does not parse correctly, the form will still fail.

newtypenewtype AForm (m :: Type -> Type) a
#
Instances6MonadTrans, Monad, Functor, Applicative, Semigroup, Monoid
datadata Enctype
#

The encoding type required by a form. The ToHtml instance produces values that can be inserted directly into HTML.

Instances7Bounded, Enum, Eq, Semigroup, Monoid, ToMarkup, …
datadata FormResult a
#

A form can produce three different results: there was no data available, the data was invalid, or there was a successful parse.

The Applicative instance will concatenate the failure messages in two FormResults. The Alternative instance will choose FormFailure before FormSuccess, and FormMissing last of all.

Instances9Functor, Applicative, Foldable, Traversable, Alternative, Eq, …
datadata FormMessage
#
Instances3Eq, Read, Show
typetype WForm (m :: Type -> Type) a = MForm (WriterT [FieldView (HandlerSite m)] m) a
#

MForm variant stacking a WriterT. The following code example using a monadic form MForm:

formToAForm $ do
  (field1F, field1V) <- mreq textField MsgField1 Nothing
  (field2F, field2V) <- mreq (checkWith field1F textField) MsgField2 Nothing
  (field3F, field3V) <- mreq (checkWith field1F textField) MsgField3 Nothing
  return
    ( MyForm <$> field1F <*> field2F <*> field3F
    , [field1V, field2V, field3V]
    )

Could be rewritten as follows using WForm:

wFormToAForm $ do
  field1F <- wreq textField MsgField1 Nothing
  field2F <- wreq (checkWith field1F textField) MsgField2 Nothing
  field3F <- wreq (checkWith field1F textField) MsgField3 Nothing
  return $ MyForm <$> field1F <*> field2F <*> field3F
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
classclass (PersistCore backend, PersistStoreRead backend) => PersistQueryRead backend where
#

Backends supporting conditional read operations.

Methods

Instances4PersistQueryRead
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

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.

Instances1RawSql
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 Monad (YesodDB site) => YesodPersist site where
#

Associated types

Methods

  • runDB :: YesodDB site a -> HandlerFor site a

    Allows you to execute database actions within Yesod Handlers. For databases that support it, code inside the action will run as an atomic transaction.

    Example Usage
    userId <- runDB $ do
      userId <- insert $ User "username" "email@example.com"
      insert_ $ UserPreferences userId True
      pure userId
classclass YesodPersist site => YesodPersistRunner site where
#

Since 1.2.0

Methods

  • getDBRunner :: HandlerFor site (DBRunner site, HandlerFor site ())

    This function differs from runDB in that it returns a database runner function, as opposed to simply running a single action. This will usually mean that a connection is taken from a pool and then reused for each invocation. This can be useful for creating streaming responses; see runDBSource.

    It additionally returns a cleanup function to free the connection. If your code finishes successfully, you must call this cleanup to indicate changes should be committed. Otherwise, for SQL backends at least, a rollback will be used instead.

    Since 1.2.0

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

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

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.

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.

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

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.

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.

Automatically creates a valid PersistField instance for any datatype that has valid ToJSON and FromJSON instances. For a datatype T it generates instances similar to these:

   instance PersistField T where
       toPersistValue = PersistByteString . L.toStrict . encode
       fromPersistValue = (left T.pack) . eitherDecodeStrict' <=< fromPersistValue
   instance PersistFieldSql T where
       sqlType _ = SqlString
valuediscoverEntities :: Q Exp
#

Splice in a list of all EntityDef in scope. This is useful when running mkPersist to ensure that all entity definitions are available for setting foreign keys, and for performing migrations with all entities available.

mkPersist has the type MkPersistSettings -> [EntityDef] -> DecsQ. So, to account for entities defined elsewhere, you'll mappend $(discoverEntities).

For example,

share
  [ mkPersistWith sqlSettings $(discoverEntities)
  ]
  [persistLowerCase| ... |]

Likewise, to run migrations with all entity instances in scope, you'd write:

migrateAll = migrateModels $(discoverEntities)

Note that there is some odd behavior with Template Haskell and splicing groups. If you call discoverEntities in the same module that defines PersistEntity instances, you need to ensure they are in different top-level binding groups. You can write $(pure []) at the top level to do this.

-- Foo and Bar both export an instance of PersistEntity
import Foo
import Bar

-- Since Foo and Bar are both imported, discoverEntities can find them here.
mkPersistWith sqlSettings $(discoverEntities) [persistLowerCase|
  User
    name Text
    age  Int
  |]

-- onlyFooBar is defined in the same 'top level group' as the above generated
-- instance for User, so it isn't present in this list.
onlyFooBar :: [EntityDef]
onlyFooBar = $(discoverEntities)

-- We can manually create a new binding group with this, which splices an
-- empty list of declarations in.
$(pure [])

-- fooBarUser is able to see the User instance.
fooBarUser :: [EntityDef]
fooBarUser = $(discoverEntities)
valueembedEntityDefs
  1. :: [EntityDef]

    A list of EntityDef that have been defined in a previous mkPersist call.

  2. -> [UnboundEntityDef]
  3. -> [UnboundEntityDef]
#

Takes a list of (potentially) independently defined entities and properly links all foreign keys to reference the right EntityDef, tying the knot between entities.

Allows users to define entities indepedently or in separate modules and then fix the cross-references between them at runtime to create a Migration.

valuefieldError :: Text -> Text -> Text -> Text
#

Render an error message based on the tableName and fieldName with the provided message.

valuelensPTH :: (s -> a) -> (s -> b -> t) -> Lens s t a b
#

The basic function for migrating models, no Template Haskell required.

It's probably best to use this in concert with mkEntityDefList, and then call migrateModels with the result from that function.

share [mkPersist sqlSettings, mkEntityDefList "entities"] [persistLowerCase| ... |]

migrateAll = migrateModels entities

The function mkMigrate currently implements exactly this behavior now. If you're splitting up the entity definitions into separate files, then it is better to use the entity definition list and the concatenate all the models together into a big list to call with migrateModels.

module Foo where

    share [mkPersist s, mkEntityDefList "fooModels"] ...


module Bar where

    share [mkPersist s, mkEntityDefList "barModels"] ...

module Migration where

    import Foo
    import Bar

    migrateAll = migrateModels (fooModels <> barModels)
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.

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.

Like mkPersist, but allows you to provide a [EntityDef] representing the predefined entities. This function will include those EntityDef when looking for foreign key references.

You should use this if you intend on defining Persistent models in multiple files.

Suppose we define a table Foo which has no dependencies.

module DB.Foo where

    mkPersistWith sqlSettings [] [persistLowerCase|
        Foo
           name    Text
       |]

Then, we define a table Bar which depends on Foo:

module DB.Bar where

    import DB.Foo

    mkPersistWith sqlSettings [entityDef (Proxy :: Proxy Foo)] [persistLowerCase|
        Bar
            fooId  FooId
     |]

Writing out the list of EntityDef can be annoying. The $(discoverEntities) shortcut will work to reduce this boilerplate.

module DB.Quux where

    import DB.Foo
    import DB.Bar

    mkPersistWith sqlSettings $(discoverEntities) [persistLowerCase|
        Quux
            name     Text
            fooId    FooId
            barId    BarId
     |]

Produce code similar to the following:

  instance PersistEntity e => PersistField e where
     toPersistValue = entityToPersistValueHelper
     fromPersistValue = entityFromPersistValueHelper ["col1", "col2"]
     sqlType _ = SqlString

Same as persistFileWith, but uses several external files instead of one. Splitting your Persistent definitions into multiple modules can potentially dramatically speed up compile times.

The recommended file extension is .persistentmodels.

Examples

Split your Persistent definitions into multiple files (models1, models2), then create a new module for each new file and run mkPersist there:

-- Model1.hs
share
    [mkPersist sqlSettings]
    $(persistFileWith lowerCaseSettings "models1")
-- Model2.hs
share
    [mkPersist sqlSettings]
    $(persistFileWith lowerCaseSettings "models2")

Use persistManyFileWith to create your migrations:

-- Migrate.hs
mkMigrate "migrateAll"
    $(persistManyFileWith lowerCaseSettings ["models1.persistentmodels","models2.persistentmodels"])

Tip: To get the same import behavior as if you were declaring all your models in one file, import your new files as Name into another file, then export module Name.

This approach may be used in the future to reduce memory usage during compilation, but so far we've only seen mild reductions.

See persistent#778 and persistent#791 for more details.

Converts a quasi-quoted syntax into a list of entity definitions, to be used as input to the template haskell generation code (mkPersist).

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.

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.

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.

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.

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

Instances10Eq, Ord, Read, Show, Generic, SafeToInsert, …
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.

Instances1IsLabel
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

familytype family PersistEntityBackend record
#

Persistent allows multiple different backends (databases).

familydata family Unique record
#

Unique keys besides the Key.

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.

Instances2SafeToInsert
  • TypeError (EntityErrorMessage a) => SafeToInsert (Entity a)Defined in persistent-2.14.6.3 · Database.Persist.Class.PersistEntity
  • TypeError (FunctionErrorMessage a b) => SafeToInsert (a -> b)Defined in persistent-2.14.6.3 · Database.Persist.Class.PersistEntity
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

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.

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.

Instances39PersistField, …
classclass (PersistQueryRead backend, PersistStoreWrite backend) => PersistQueryWrite backend where
#

Backends supporting conditional write operations

Methods

Instances3PersistQueryWrite
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
classclass PersistCore backend where
#

Associated types

Instances4PersistCore
familydata family BackendKey backend
#
Instances71Bounded, Enum, Eq, Integral, Num, Ord, …
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 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
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
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

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

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

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
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 ImplicitIdDef
#

A specification for how the implied ID columns are created.

By default, persistent will give each table a default column named id (customizable by PersistSettings), and the column type will be whatever you'd expect from BackendKey yourBackendType. For The SqlBackend type, this is an auto incrementing integer primary key.

You might want to give a different example. A common use case in postgresql is to use the UUID type, and automatically generate them using a SQL function.

Previously, you'd need to add a custom Id annotation for each model.

User
    Id   UUID default="uuid_generate_v1mc()"
    name Text

Dog
    Id   UUID default="uuid_generate_v1mc()"
    name Text
    user UserId

Now, you can simply create an ImplicitIdDef that corresponds to this declaration.

newtype UUID = UUID ByteString

instance PersistField UUID where
    toPersistValue (UUID bs) =
        PersistLiteral_ Escaped bs
    fromPersistValue pv =
        case pv of
            PersistLiteral_ Escaped bs ->
                Right (UUID bs)
            _ ->
                Left "nope"

instance PersistFieldSql UUID where
    sqlType _ = SqlOther UUID

With this instance at the ready, we can now create our implicit definition:

uuidDef :: ImplicitIdDef
uuidDef = mkImplicitIdDef @UUID "uuid_generate_v1mc()"

And we can use setImplicitIdDef to use this with the MkPersistSettings for our block.

mkPersist (setImplicitIdDef uuidDef sqlSettings) [persistLowerCase| ... |]

TODO: either explain interaction with mkMigrate or fix it. see issue #1249 for more details.

newtypenewtype ConstraintNameDB
#

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

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

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

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
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
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
datadata PersistValue
#

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

Constructors

Instances12Eq, Ord, Read, Show, NFData, FromJSON, …
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.

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.

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.

datadata CascadeAction
#

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

Instances5Eq, Ord, Read, Show, 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.

Instances11Bounded, Enum, Eq, Ord, Read, Show, …
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 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 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 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
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
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 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
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
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 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
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 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 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