    {-# LANGUAGE CPP #-}
    {-# LANGUAGE PatternGuards #-}
    {-# LANGUAGE RankNTypes #-}
    {-# LANGUAGE StandaloneDeriving #-}
    {-# LANGUAGE UndecidableInstances #-}

    -- |
    -- 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
    -- <https://github.com/yesodweb/persistent/issues/241 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 important\nto 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 about\nthis 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 <https://hackage.haskell.org/package/persistent-documentation @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
    -- <https://github.com/yesodweb/persistent/blob/master/persistent-test/src/SumTypeTest.hs#L35 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            | Tiny,Short,Int24,Long,LongLong                                        |
    -- | Double            | 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 <https://github.com/yesodweb/persistent/issues/225 #225>|
    -- +--------------------------------------------------------------------+
    --
    -- See <http://hackage.haskell.org/package/mysql-simple/docs/Database-MySQL-Simple-Result.html MySQL.Simple.Result>.
    module Database.Persist.Quasi
        ( parse

          -- * 'PersistSettings'
        , PersistSettings
        , upperCaseSettings
        , lowerCaseSettings

          -- ** Getters and Setters
        , getPsToDBName
        , setPsToDBName
        , setPsToFKName
        , setPsUseSnakeCaseForeignKeys
        , setPsUseSnakeCaseForiegnKeys
        , getPsStrictFields
        , setPsStrictFields
        , getPsIdName
        , setPsIdName
        , getPsTabErrorLevel
        , setPsTabErrorLevel
        , getPsQuotedArgumentErrorLevel
        , setPsQuotedArgumentErrorLevel
        ) where

    import Database.Persist.Quasi.Internal
    import Database.Persist.Quasi.PersistSettings