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

Safe Haskell | None
Language | Haskell2010

Database.Persist.Quasi

Contents

- `PersistSettings`
  - Getters and Setters

Description

This module defines the Persistent entity syntax used in the quasiquoter to generate persistent entities.

The basic structure of the syntax looks like this:

    TableName
        fieldName      FieldType
        otherField     String
        nullableField  Int       Maybe

You start an entity definition with the table name, in this case, `TableName`. It's followed by a list of fields on the entity, which have the basic form `fieldName FieldType`. You can indicate that a field is nullable with `Maybe` at the end of the type.

`persistent` automatically generates an ID column for you, if you don't specify one, so the above table definition corresponds to the following SQL:

    CREATE TABLE table_name (
        id                SERIAL PRIMARY KEY,
        field_name        field_type NOT NULL,
        other_field       varchar    NOT NULL,
        nullable_field    int NULL
    );

Note that the exact SQL that is generated can be customized using the `PersistSettings` that are passed to the `parse` function.

It generates a Haskell datatype with the following form:

    data TableName = TableName
        { tableNameFieldName :: FieldType
        , tableNameOtherField :: String
        , tableNameNullableField :: Maybe Int
        }

As with the SQL generated, the specifics of this are customizable. See the Database.Persist.TH module for details.

# Deriving

You can add a deriving clause to a table, and the generated Haskell type will have a deriving clause with that. Unlike normal Haskell syntax, you don't need parentheses or commas to separate the classes, and you can even have multiple deriving clauses.

    User
        name String
        age  Int
        deriving Eq Show
        deriving Ord

# Unique Keys

You can define a uniqueness key on a table with the following format:

    User
       name String
       age  Int

       UniqueUserName name

This will put a unique index on the `user` table and the `name` field.

# Setting defaults

You can use a `default=${sql expression}` clause to set a default for a field. The thing following the `=` is interpreted as SQL that will be put directly into the table definition.

    User
        name    Text
        admin   Bool default=false

This creates a SQL definition like this:

    CREATE TABLE user (
      id      SERIAL PRIMARY KEY,
      name    VARCHAR NOT NULL,
      admin   BOOL DEFAULT=false
    );

A restriction here is that you still need to provide a value when performing an `insert`, because the generated Haskell type has the form:

    data User = User
        { userName :: Text
        , userAdmin :: Bool
        }

You can work around this by using a 'Maybe Bool' and supplying `Nothing` by default.

Note: Persistent determines whether or not to migrate a column's default value by comparing the exact string found in your `models` file with the one returned by the database. If a database canonicalizes the SQL `FALSE` from your `models` file to `false` in the database, Persistent will think the default value needs to be migrated and attempt a migration each time you start your app.

To workaround this, find the exact SQL your DBMS uses for the default value. For example, using postgres:

    psql database_name # Open postgres

    \d+ table_name -- describe the table schema

    ...
    created       | timestamp without time zone | not null default now()

Then use the listed default value SQL inside your `models` file.

# Custom ID column

If you don't want to use the default ID column type of `Int64`, you can set a custom type with an `Id` field. This `User` has a `Text` ID.

    User
        Id   Text
        name Text
        age  Int

If you do this, it's a good idea to set a default for the ID. Otherwise, you will need to use `insertKey` instead of `insert` when performing inserts.

    insertKey (UserKey "Hello world!") (User Bob 32)

If you attempt to do ``insert` (User Bob 32)`, then you will receive a runtime error because the SQL database doesn't know how to make an ID for you anymore. So instead just use a default expression, like this:

    User
        Id      Text default=generate_user_id()
        name    Text
        age     Int

# Custom Primary Keys

Sometimes you don't want to have an ID column, and you want a different sort of primary key. This is a table that stores unique email addresses, and the email is the primary key. We store the first and second part (eg `first@second`) separately.

    Email
        firstPart   Text
        secondPart  Text

        Primary firstPart secondPart

This creates a table with the following form:

    CREATE TABLE email (
        first_part  varchar,
        second_part varchar,

        PRIMARY KEY (first_part, second_part)

Since the primary key for this table is part of the record, it's called a "natural key" in the SQL lingo. As a key with multiple fields, it is also a "composite key."

You can specify a `Primary` key with a single field, too.

# Overriding SQL

You can use a `sql=custom` annotation to provide some customization on the entity and field. For example, you might prefer to name a table differently than what `persistent` will do by default. You may also prefer to name a field differently.

    User sql=big_user_table
        fullName    String sql=name
        age         Int

This will alter the generated SQL to be:

    CREATE TABLE big_user_table (
        id      SERIAL PRIMARY KEY,
        name    VARCHAR,
        age     INT
    );

# Customizing Types/Tables

## JSON instances

You can automatically get ToJSON and FromJSON instances for any entity by adding `json` to the entity line:

    Person json
        name Text

Requires `{-# LANGUAGE FlexibleInstances #-}`

Customizable by using mpsEntityJSON * http://hackage.haskell.org/package/persistent-template/docs/Database-Persist-TH.html#v:EntityJSON * http://hackage.haskell.org/package/persistent/docs/Database-Persist-Class.html#v:keyValueEntityToJSON

## Changing table/collection name

    Person sql=peoples
        name Text

## Change table/collection key definition (field name and/or type, persistent >= 2.1)

`Id` defines the column to use to define the key of the entity. Without type, the default backend key type will be used. You can change its database name using the `sql` attributes :

    Person
       Id         sql=my_id_name
       phone Text

With a Haskell type, the corresponding type is used. Note that you'll need to use `default=` to tell it what to do on insertion.

    Person
       Id    Day default=CURRENT_DATE
       phone Text

`default=` works for SQL databases, and is backend specific. For MongoDB currently one always needs to create the key on the application side and use `insertKey`. `insert` will not work correctly. Sql backends can also do this if default does not work.

`sqltype` can also be used to specify a different database type

    Currency
        Id String sqltype=varchar(3) sql=code

Composite key (using multiple columns) can also be defined using `Primary`.

`sql=` also works for setting the names of unique indexes.

    Person
      name Text
      phone Text
      UniquePersonPhone phone sql=UniqPerPhone

This makes a unique index requiring `phone` to be unique across `Person` rows. Ordinarily Persistent will generate a snake-case index name from the capitalized name provided such that `UniquePersonPhone` becomes `unique_person_phone`. However, we provided a `sql=` so the index name in the database will instead be `UniqPerPhone`. Keep in mind `sql=` and `!` attrs must come after the list of fields in front of the index name in the quasi-quoter.

# Customizing Fields

## Nullable Fields

As illustrated in the example at the beginning of this page, we are able to represent nullable fields by including `Maybe` at the end of the type declaration:

    TableName
        fieldName      FieldType
        otherField     String
        nullableField  Int       Maybe

Alternatively we can specify the keyword nullable:

    TableName
        fieldName      FieldType
        otherField     String
        nullableField  Int       nullable

However the difference here is in the first instance the Haskell type will be 'Maybe Int', but in the second it will be `Int`. Be aware that this will cause runtime errors if the database returns `NULL` and the `PersistField` instance does not handle `PersistNull`.

If you wish to define your Maybe types in a way that is similar to the actual Haskell definition, you can define 'Maybe Int' like so:

    TableName
        fieldName      FieldType
        otherField     String
        nullableField  (Maybe Int)

However, note, the field _must_ be enclosed in parenthesis.

## `sqltype=`

By default, Persistent maps the Haskell types you specify in the Models DSL to an appropriate SQL type in the database (refer to the section "Conversion table (migrations)" for the default mappings). Using the `sqltype=` option, you can customize the SQL type Persistent uses for your column. Use cases include:

- Interacting with an existing database whose column types don't match Persistent's defaults.
- Taking advantage of a specific SQL type's features
- e.g. Using an equivalent type that has better space or performance characteristics

To use this setting, add the `sqltype=` option after declaring your field name and type:

    User
        username Text sqltype=varchar(255)

## Laziness

By default the records created by persistent have strict fields. You can prefix a field name with `~` to make it lazy (or `!` to make it strict).

## Attributes

The QuasiQuoter allows you to provide arbitrary attributes to an entity or field. This can be used to extend the code in ways that the library hasn't anticipated. If you use this feature, we'd definitely appreciate hearing about it and potentially supporting your use case directly!

    User !funny
        field   String  !sad
        good    Dog     !sogood

We can see the attributes using the `entityAttrs` field and the `fieldAttrs` field.

    userAttrs = do
        let userDefinition = entityDef (Proxy :: Proxy User)
        let userAttributes = entityAttrs userDefinition
        let fieldAttributes = map fieldAttrs (entityFields userDefinition)
        print userAttributes
    -- ["funny"]
        print fieldAttributes
    -- [["sad"],["sogood"]]

## `!no-migrate`

To prevent `migrateModels` from generating _any_ migrations for an entity, add the `!no-migrate` attribute to it's definition:

    User !no-migrate
        field   String
        good    Dog

## `MigrationOnly`

Introduced with `persistent-template` 1.2.0. The purpose of this attribute is to mark a field which will be entirely ignored by the normal processing, but retained in the database definition for purposes of migration. This means, in SQL, a column will not be flagged for removal by the migration scripts, even though it is not used in your code. This is useful for phasing out usage of a column before entirely removing it, or having columns which are needed by other tools but not by Persistent.

    Person
        name Text
        age Int
        unusedField ByteString Maybe MigrationOnly

Note that you almost certainly want to either mark the field as `Maybe` or provide a default value, otherwise insertions will fail.

## `SafeToRemove`

This is intended to be used as part of a deprecation of a field, after `MigrationOnly` has been used usually. This works somewhat as a superset of the functionality of `MigrationOnly`. In addition, the field will be removed from the database if it is present. Note that this is a destructive change which you are marking as safe.

## Constraints

Migration will remove any manual constraints from your tables. Exception: constraints whose names begin with the string `__manual_` (which starts with two underscores) will be preserved.

# Foreign Keys

If you define an entity and want to refer to it in another table, you can use the entity's Id type in a column directly.

    Person
        name    Text

    Dog
        name    Text
        owner   PersonId

This automatically creates a foreign key reference from `Dog` to `Person`. The foreign key constraint means that, if you have a `PersonId` on the `Dog`, the database guarantees that the corresponding `Person` exists in the database. If you try to delete a `Person` out of the database that has a `Dog`, you'll receive an exception that a foreign key violation has occurred.

## `constraint=`

You can use the `constraint=` attribute to override the constraint name used in migrations. This is useful particularly when the automatically generated constraint names exceed database limits (e.g. MySQL does not allow constraint names longer than 64 characters).

    VeryLongTableName
      name Text

    AnotherVeryLongTableName
      veryLongTableNameId VeryLongTableNameId constraint=short_foreign_key

## OnUpdate and OnDelete

These options affects how a referring record behaves when the target record is changed. There are several options:

- `Restrict` - This is the default. It prevents the action from occurring.
- `Cascade` - this copies the change to the child record. If a parent record is deleted, then the child record will be deleted too.
- `SetNull` - If the parent record is modified, then this sets the reference to `NULL`. This only works on `Maybe` foreign keys.
- `SetDefault` - This will set the column's value to the `default` for the column, if specified.

To specify the behavior for a reference, write `OnUpdate` or `OnDelete` followed by the action.

    Record
        -- If the referred Foo is deleted or updated, then this record will
        -- also be deleted or updated.
        fooId   FooId   OnDeleteCascade OnUpdateCascade

        -- If the referred Bar is deleted, then we'll set the reference to
        -- Nothing. If the referred Bar is updated, then we'll cascade the
        -- update.
        barId   BarId Maybe     OnDeleteSetNull OnUpdateCascade

        -- If the referred Baz is deleted, then we set to the default ID.
        bazId   BazId   OnDeleteSetDefault  default=1

Let's demonstrate this with a shopping cart example.

    User
        name    Text

    Cart
        user    UserId Maybe

    CartItem
        cartId  CartId
        itemId  ItemId

    Item
        name    Text
        price   Int

Let's consider how we want to handle deletions and updates. If a `User` is deleted or update, then we want to cascade the action to the associated `Cart`.

    Cart
        user    UserId Maybe OnDeleteCascade OnUpdateCascade

If an `Item` is deleted, then we want to set the `CartItem` to refer to a special "deleted item" in the database. If a `Cart` is deleted, though, then we just want to delete the `CartItem`.

    CartItem
        cartId CartId   OnDeleteCascade
        itemId ItemId   OnDeleteSetDefault default=1

## `Foreign` keyword

The above example is a "simple" foreign key. It refers directly to the Id column, and it only works with a non-composite primary key. We can define more complicated foreign keys using the `Foreign` keyword.

A pseudo formal syntax for `Foreign` is:

    Foreign $(TargetEntity) [$(cascade-actions)] $(constraint-name) $(columns) [ $(references) ]

    columns := column0 [column1 column2 .. columnX]
    references := References $(target-columns)
    target-columns := target-column0 [target-column1 target-columns2 .. target-columnX]

Columns are the columns as defined on this entity. `target-columns` are the columns as defined on the target entity.

Let's look at some examples.

### Composite Primary Key References

The most common use for this is to refer to a composite primary key. Since composite primary keys take up more than one column, we can't refer to them with a single `persistent` column.

    Email
        firstPart   Text
        secondPart  Text
        Primary firstPart secondPart

    User
        name            Text
        emailFirstPart  Text
        emailSecondPart Text

        Foreign Email fk_user_email emailFirstPart emailSecondPart

If you omit the `References` keyword, then it assumes that the foreign key reference is for the target table's primary key. If we wanted to be fully redundant, we could specify the `References` keyword.

        Foreign Email fk_user_email emailFirstPart emailSecondPart References firstPart secondPart

We can specify delete/cascade behavior directly after the target table.

        Foreign Email OnDeleteCascade OnUpdateCascade fk_user_email emailFirstPart emailSecondPart

Now, if the email is deleted or updated, the user will be deleted or updated to match.

### Non-Primary Key References

SQL database backends allow you to create a foreign key to any column(s) with a Unique constraint. Persistent does not check this, because you might be defining your uniqueness constraints outside of Persistent. To do this, we must use the `References` keyword.

    User
        name    Text
        email   Text

        UniqueEmail email

    Notification
        content Text
        sentTo  Text

        Foreign User fk_noti_user sentTo References email

If the target uniqueness constraint has multiple columns, then you must specify them independently.

    User
        name            Text
        emailFirst      Text
        emailSecond     Text

        UniqueEmail emailFirst emailSecond

    Notification
        content         Text
        sentToFirst     Text
        sentToSecond    Text

        Foreign User fk_noti_user sentToFirst sentToSecond References emailFirst emailSecond

# Documentation Comments

The quasiquoter supports ordinary comments with `--` and `#`. Since `persistent-2.10.5.1`, it also supports documentation comments. The grammar for documentation comments is similar to Haskell's Haddock syntax, with a few restrictions:

1. Only the `-- |` form is allowed.
2. You must put a space before and after the `|` pipe character.
3. The comment must be indented at the same level as the entity or field it documents.

An example of the field documentation is:

    -- | I am a doc comment for a User. Users are important
    -- | to the application, and should be treasured.
    User
        -- | Users have names. Call them by names.
        name String
        -- | A user can be old, or young, and we care about
        -- | this for some reason.
        age Int

The documentation is present on the `entityComments` field on the `EntityDef` for the entity:

    >>> let userDefinition = entityDef (Proxy :: Proxy User)
    >>> entityComments userDefinition
    "I am a doc comment for a User. Users are importantnto the application, and should be treasured.n"

Likewise, the field documentation is present in the `fieldComments` field on the `FieldDef` present in the `EntityDef`:

    >>> let userFields = entityFields userDefinition
    >>> let comments = map fieldComments userFields
    >>> mapM_ putStrLn comments
    "Users have names. Call them by names."
    "A user can be old, or young, and we care aboutnthis for some reason."

Since `persistent-2.14.6.0`, documentation comments are included in documentation generated using Haddock if `mpsEntityHaddocks` is enabled (defaults to False). `persistent` backends can also use this to generate SQL `COMMENT`s, which are useful for a database perspective, and you can use the @persistent-documentation@ library to render a Markdown document of the entity definitions.

# Sum types

## Field level

You'll frequently want to store an enum of values in your database. For example, you might describe a `Person`'s employment status as being `Employed`, `Unemployed`, or `Retired`. In Haskell this is represented with a sum type, and Persistent provides a Template Haskell function to marshall these values to and from the database:

    -- @Employment.hs
    {-# LANGUAGE TemplateHaskell #-}
    module Employment where

    import Database.Persist.TH
    import Prelude

    data Employment = Employed | Unemployed | Retired
        deriving (Show, Read, Eq)
    derivePersistField Employment

`derivePersistField` stores sum type values as strins in the database. While not as efficient as using integers, this approach simplifies adding and removing values from your enumeration.

Due to the GHC Stage Restriction, the call to the Template Haskell function `derivePersistField` must be in a separate module than where the generated code is used.

Note: If you created a new module, make sure add it to the `exposed-modules` section of your Cabal file.

Use the module by importing it into your `Model.hs` file:

    -- @Model.hs
    import Employment

and use it in the `models` DSL:

    Person
        employment Employment

You can export the Employment module from Import to use it across your app:

    -- @Import.hs
    import Employment as Import

### Entity-level

NOTE: This feature is deprecated as of version 2.14 and will be removed in 2.15 (unless there are many complaints).

The tests for this feature demonstrate their usage. Note the use of the sign `+` in front of the entity name.

The schema in the test is reproduced here:

    share [mkPersist persistSettings, mkMigrate "sumTypeMigrate"] [persistLowerCase|
    Bicycle
        brand T.Text
    Car
        make T.Text
        model T.Text
    +Vehicle
        bicycle BicycleId
        car CarId
    |]

Let's check out the definition of the Haskell type `Vehicle`. Using `ghci`, we can query for `:info Vehicle`:

    >>> :i Vehicle
    type Vehicle = VehicleGeneric SqlBackend
            -- Defined at .../Projects/persistent/persistent-test/src/SumTypeTest.hs:26:1

    >>> :i VehicleGeneric
    type role VehicleGeneric nominal
    data VehicleGeneric backend
      = VehicleBicycleSum (Key (BicycleGeneric backend))
      | VehicleCarSum (Key (CarGeneric backend))
            -- Defined at .../persistent/persistent-test/src/SumTypeTest.hs:26:1
    -- lots of instances follow...

A `VehicleGeneric` has two constructors:

- `VehicleBicycleSum` with a `Key (BicycleGeneric backend)` field
- `VehicleCarSum` with a `Key (CarGeneric backend)` field

The `Bicycle` and `Car` are typical `persistent` entities.

This generates the following SQL migrations (formatted for readability):

    CREATE TABLE "bicycle" (
        "id"        INTEGER PRIMARY KEY,
        "brand"     VARCHAR NOT NULL
    );

    CREATE TABLE "car"(
        "id"        INTEGER PRIMARY KEY,
        "make"      VARCHAR NOT NULL,
        "model"     VARCHAR NOT NULL
    );

    CREATE TABLE "vehicle"(
        "id"        INTEGER PRIMARY KEY,
        "bicycle"   INTEGER NULL REFERENCES "bicycle",
        "car"       INTEGER NULL REFERENCES "car"
    );

The `vehicle` table contains a nullable foreign key reference to both the bicycle and the car tables.

A SQL query that grabs all the vehicles from the database looks like this (note the `??` is for the `persistent` raw SQL query functions):

    SELECT ??, ??, ??
    FROM vehicle
    LEFT JOIN car
        ON vehicle.car = car.id
    LEFT JOIN bicycle
        ON vehicle.bicycle = bicycle.id

If we use the above query with `rawSql`, we'd get the following result:

    getVehicles
        :: SqlPersistM
            [ ( Entity Vehicle
              , Maybe (Entity Bicycle)
              , Maybe (Entity Car)
              )
            ]

This result has some post-conditions that are not guaranteed by the types *or* the schema. The constructor for `Entity Vehicle` is going to determine which of the other members of the tuple is `Nothing`. We can convert this to a friendlier domain model like this:

    data Vehicle'
        = Car' Text Text
        | Bike Text

    check = do
        result <- getVehicles
        pure (map convert result)

    convert
        :: (Entity Vehicle, Maybe (Entity Bicycle), Maybe (Entity Car))
        -> Vehicle'
    convert (Entity _ (VehicleBicycleSum _), Just (Entity _ (Bicycle brand)), _) =
        Bike brand
    convert (Entity _ (VehicleCarSum _), _, Just (Entity _ (Car make model))) =
        Car make model
    convert _ =
        error "The database preconditions have been violated!"

## Times with timezones

Storing times with timezones in one type in databases is not possible, although it seems that it should be possible (`timezone` and `timezonetz` in PostgreSQL). That's why starting with persistent 2.0, all times will be mapped to `UTCTime`. If you need to store timezone information along with times in a database, store the timezone in a second field. Here are some links about the topic with further information:

- https://github.com/yesodweb/persistent/issues/290
- https://groups.google.com/forum/#!msg/yesodweb/MIfcV2bwM80/8QLFpgp1LykJ
- http://stackoverflow.com/questions/14615271/postgres-timestamp/14616640#14616640
- http://justatheory.com/computers/databases/postgresql/use-timestamptz.html
- https://github.com/lpsmith/postgresql-simple/issues/69
- https://github.com/nikita-volkov/hasql-postgres/issues/1

# Conversion table (migrations)

Here are the conversions between Haskell types and database types:

Haskell | PostgreSQL | MySQL | MongoDB | SQLite
--- | --- | --- | --- | ---
Text | VARCHAR | TEXT | String | VARCHAR
ByteString | BYTEA | BLOB | BinData | BLOB
Int | INT8 | BIGINT(20) | NumberLong | INTEGER
Double | DOUBLE PRECISION | DOUBLE | Double | REAL
Rational | NUMERIC(22, 12) | DECIMAL(32,20) | *Unsupported* | NUMERIC(32,20)
Bool | BOOLEAN | TINYINT(1) | Boolean | BOOLEAN
Day | DATE | DATE | NumberLong | DATE
TimeOfDay | TIME | TIME** | *Unsupported* | TIME
UTCTime* | TIMESTAMP | DATETIME** | Date | TIMESTAMP

Notes:

* Support for `ZonedTime` was dropped in persistent 2.0. `UTCTime` can be used with `timestamp without timezone` and `timestamp with timezone` in PostgreSQL. See also the section "Times with timezones".

** The default resolution for `TIME` and `DATETIME` in MySQL is one second. As of MySQL version 5.6.4, and persistent-mysql-2.6.2, fractional seconds are handled correctly if you declare an explicit precision by using `sqltype`. For example, appending `sqltype=TIME(6)` to a `TimeOfDay` field definition will give microsecond resolution.

# Compatibility tables

MySQL:

Haskell type | Compatible MySQL types
--- | ---
Bool | Tiny
Int8 | Tiny
Int16 | Tiny,Short
Int32 | Tiny,Short,Int24,Long
Int | Tiny,Short,Int24,Long,LongLong*
Int64 | Tiny,Short,Int24,Long,LongLong
Integer | Tiny,Short,Int24,Long,LongLong
Word8 | Tiny
Word16 | Tiny,Short
Word32 | Tiny,Short,Int24,Long
Word64 Double | Tiny,Short,Int24,Long,LongLong Float,Double,Decimal,NewDecimal,Tiny,Short,Int24,Long
Ratio Integer | Float,Double,Decimal,NewDecimal,Tiny,Short,Int24,Long,LongLong
ByteString | VarChar,TinyBlob,MediumBlob,LongBlob,Blob,VarString,String,Set,Enum
Lazy.ByteString | VarChar,TinyBlob,MediumBlob,LongBlob,Blob,VarString,String,Set,Enum
Encoding.Text** | VarChar,TinyBlob,MediumBlob,LongBlob,Blob,VarString,String,Set,Enum
Lazy.Text | VarChar,TinyBlob,MediumBlob,LongBlob,Blob,VarString,String,Set,Enum
[Char]/String | VarChar,TinyBlob,MediumBlob,LongBlob,Blob,VarString,String,Set,Enum
UTCTime | DateTime,Timestamp
Day | Year,Date,NewDate
TimeOfDay | Time

* When `Word` size is 64bit

** Utf8 only

Unsupported types:

Not currently supported
Word
Float
Scientific #225

See MySQL.Simple.Result.

Synopsis

- parse :: PersistSettings -> [(Maybe SourceLoc, Text)] -> CumulativeParseResult [UnboundEntityDef]
- data PersistSettings
- upperCaseSettings :: PersistSettings
- lowerCaseSettings :: PersistSettings
- getPsToDBName :: PersistSettings -> Text -> Text
- setPsToDBName :: (Text -> Text) -> PersistSettings -> PersistSettings
- setPsToFKName :: (EntityNameHS -> ConstraintNameHS -> Text) -> PersistSettings -> PersistSettings
- setPsUseSnakeCaseForeignKeys :: PersistSettings -> PersistSettings
- setPsUseSnakeCaseForiegnKeys :: PersistSettings -> PersistSettings
- getPsStrictFields :: PersistSettings -> Bool
- setPsStrictFields :: Bool -> PersistSettings -> PersistSettings
- getPsIdName :: PersistSettings -> Text
- setPsIdName :: Text -> PersistSettings -> PersistSettings
- getPsTabErrorLevel :: PersistSettings -> Maybe ParserErrorLevel
- setPsTabErrorLevel :: Maybe ParserErrorLevel -> PersistSettings -> PersistSettings
- getPsQuotedArgumentErrorLevel :: PersistSettings -> Maybe ParserErrorLevel
- setPsQuotedArgumentErrorLevel :: Maybe ParserErrorLevel -> PersistSettings -> PersistSettings

# Documentation

parse :: PersistSettings -> [(Maybe SourceLoc, Text)] -> CumulativeParseResult [UnboundEntityDef] Source #

Parses a quasi-quoted syntax into a list of entity definitions.

# `PersistSettings`

data PersistSettings Source #

upperCaseSettings :: PersistSettings Source #

lowerCaseSettings :: PersistSettings Source #

## Getters and Setters

getPsToDBName :: PersistSettings -> Text -> Text Source #

Retrieve the function in the `PersistSettings` that modifies the names into database names.

Since: 2.13.0.0

setPsToDBName :: (Text -> Text) -> PersistSettings -> PersistSettings Source #

Set the name modification function that translates the QuasiQuoted names for use in the database.

Since: 2.13.0.0

setPsToFKName :: (EntityNameHS -> ConstraintNameHS -> Text) -> PersistSettings -> PersistSettings Source #

Set a custom function used to create the constraint name for a foreign key.

Since: 2.13.0.0

setPsUseSnakeCaseForeignKeys :: PersistSettings -> PersistSettings Source #

A preset configuration function that puts an underscore between the entity name and the constraint name when creating a foreign key constraint name

Since: 2.14.2.0

setPsUseSnakeCaseForiegnKeys :: PersistSettings -> PersistSettings Source #

Deprecated: use the correctly spelled, equivalent, setPsUseSnakeCaseForeignKeys instead

Equivalent to `setPsUseSnakeCaseForeignKeys`, but misspelled.

Since: 2.13.0.0

getPsStrictFields :: PersistSettings -> Bool Source #

Retrieve whether or not the `PersistSettings` will generate code with strict fields.

Since: 2.13.0.0

setPsStrictFields :: Bool -> PersistSettings -> PersistSettings Source #

Set whether or not the `PersistSettings` will make fields strict.

Since: 2.13.0.0

getPsIdName :: PersistSettings -> Text Source #

Retrieve the default name of the `id` column.

Since: 2.13.0.0

setPsIdName :: Text -> PersistSettings -> PersistSettings Source #

Set the default name of the `id` column.

Since: 2.13.0.0

getPsTabErrorLevel :: PersistSettings -> Maybe ParserErrorLevel Source #

Retrieve the severity of the error generated when the parser encounters a tab. If it is `Nothing`, tabs are permitted in entity definitions.

Since: 2.16.0.0

setPsTabErrorLevel :: Maybe ParserErrorLevel -> PersistSettings -> PersistSettings Source #

Set the severity of the error generated when the parser encounters a tab. If set to `Nothing`, tabs are permitted in entity definitions.

Since: 2.16.0.0

getPsQuotedArgumentErrorLevel :: PersistSettings -> Maybe ParserErrorLevel Source #

Retrieve the severity of the error generated when the parser encounters a quoted entity field attribute or quoted directive argument. If it is `Nothing`, quoted arguments are permitted in both entity field definitions and directives.

Since: 2.17.1.0

setPsQuotedArgumentErrorLevel :: Maybe ParserErrorLevel -> PersistSettings -> PersistSettings Source #

Set the severity of the error generated when the parser encounters a quoted entity field attribute. If set to `Nothing`, quoted arguments are permitted in both entity field definitions and directives.

Since: 2.17.1.0