persistent 2.13.1.1 → 2.13.1.2
raw patch · 11 files changed
+845/−148 lines, 11 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
- Database.Persist.Sql: PersistUnsafeMigrationException :: [(Bool, Sql)] -> PersistUnsafeMigrationException
- Database.Persist.Sql: addMigration :: Bool -> Sql -> Migration
- Database.Persist.Sql: addMigrations :: CautiousMigration -> Migration
- Database.Persist.Sql: getMigration :: (MonadIO m, HasCallStack) => Migration -> ReaderT SqlBackend m [Sql]
- Database.Persist.Sql: migrate :: [EntityDef] -> EntityDef -> Migration
- Database.Persist.Sql: newtype PersistUnsafeMigrationException
- Database.Persist.Sql: parseMigration :: (HasCallStack, MonadIO m) => Migration -> ReaderT SqlBackend m (Either [Text] CautiousMigration)
- Database.Persist.Sql: parseMigration' :: (HasCallStack, MonadIO m) => Migration -> ReaderT SqlBackend m CautiousMigration
- Database.Persist.Sql: printMigration :: (HasCallStack, MonadIO m) => Migration -> ReaderT SqlBackend m ()
- Database.Persist.Sql: reportError :: Text -> Migration
- Database.Persist.Sql: reportErrors :: [Text] -> Migration
- Database.Persist.Sql: runMigration :: MonadIO m => Migration -> ReaderT SqlBackend m ()
- Database.Persist.Sql: runMigrationQuiet :: MonadIO m => Migration -> ReaderT SqlBackend m [Text]
- Database.Persist.Sql: runMigrationSilent :: MonadUnliftIO m => Migration -> ReaderT SqlBackend m [Text]
- Database.Persist.Sql: runMigrationUnsafe :: MonadIO m => Migration -> ReaderT SqlBackend m ()
- Database.Persist.Sql: runMigrationUnsafeQuiet :: (HasCallStack, MonadIO m) => Migration -> ReaderT SqlBackend m [Text]
- Database.Persist.Sql: runSqlCommand :: SqlPersistT IO () -> Migration
- Database.Persist.Sql: showMigration :: (HasCallStack, MonadIO m) => Migration -> ReaderT SqlBackend m [Text]
- Database.Persist.Sql: type CautiousMigration = [(Bool, Sql)]
- Database.Persist.Sql: type Migration = WriterT [Text] (WriterT CautiousMigration (ReaderT SqlBackend IO)) ()
- Database.Persist.Sql: type Sql = Text
+ Database.Persist.Sql.Migration: PersistUnsafeMigrationException :: [(Bool, Sql)] -> PersistUnsafeMigrationException
+ Database.Persist.Sql.Migration: addMigration :: Bool -> Sql -> Migration
+ Database.Persist.Sql.Migration: addMigrations :: CautiousMigration -> Migration
+ Database.Persist.Sql.Migration: getMigration :: (MonadIO m, HasCallStack) => Migration -> ReaderT SqlBackend m [Sql]
+ Database.Persist.Sql.Migration: instance GHC.Exception.Type.Exception Database.Persist.Sql.Migration.PersistUnsafeMigrationException
+ Database.Persist.Sql.Migration: instance GHC.Show.Show Database.Persist.Sql.Migration.PersistUnsafeMigrationException
+ Database.Persist.Sql.Migration: migrate :: [EntityDef] -> EntityDef -> Migration
+ Database.Persist.Sql.Migration: newtype PersistUnsafeMigrationException
+ Database.Persist.Sql.Migration: parseMigration :: (HasCallStack, MonadIO m) => Migration -> ReaderT SqlBackend m (Either [Text] CautiousMigration)
+ Database.Persist.Sql.Migration: parseMigration' :: (HasCallStack, MonadIO m) => Migration -> ReaderT SqlBackend m CautiousMigration
+ Database.Persist.Sql.Migration: printMigration :: (HasCallStack, MonadIO m) => Migration -> ReaderT SqlBackend m ()
+ Database.Persist.Sql.Migration: reportError :: Text -> Migration
+ Database.Persist.Sql.Migration: reportErrors :: [Text] -> Migration
+ Database.Persist.Sql.Migration: runMigration :: MonadIO m => Migration -> ReaderT SqlBackend m ()
+ Database.Persist.Sql.Migration: runMigrationQuiet :: MonadIO m => Migration -> ReaderT SqlBackend m [Text]
+ Database.Persist.Sql.Migration: runMigrationSilent :: MonadUnliftIO m => Migration -> ReaderT SqlBackend m [Text]
+ Database.Persist.Sql.Migration: runMigrationUnsafe :: MonadIO m => Migration -> ReaderT SqlBackend m ()
+ Database.Persist.Sql.Migration: runMigrationUnsafeQuiet :: (HasCallStack, MonadIO m) => Migration -> ReaderT SqlBackend m [Text]
+ Database.Persist.Sql.Migration: runSqlCommand :: SqlPersistT IO () -> Migration
+ Database.Persist.Sql.Migration: showMigration :: (HasCallStack, MonadIO m) => Migration -> ReaderT SqlBackend m [Text]
+ Database.Persist.Sql.Migration: type CautiousMigration = [(Bool, Sql)]
+ Database.Persist.Sql.Migration: type Migration = WriterT [Text] (WriterT CautiousMigration (ReaderT SqlBackend IO)) ()
+ Database.Persist.Sql.Migration: type Sql = Text
- Database.Persist.Class: data family Unique record;
+ Database.Persist.Class: data family BackendKey backend;
- Database.Persist.Sql.Util: keyAndEntityColumnNames :: EntityDef -> SqlBackend -> NonEmpty Sql
+ Database.Persist.Sql.Util: keyAndEntityColumnNames :: EntityDef -> SqlBackend -> NonEmpty Text
Files
- ChangeLog.md +9/−0
- Database/Persist.hs +93/−39
- Database/Persist/Class.hs +32/−8
- Database/Persist/Class/PersistQuery.hs +73/−7
- Database/Persist/Quasi.hs +496/−38
- Database/Persist/Sql.hs +29/−2
- Database/Persist/Sql/Migration.hs +85/−4
- Database/Persist/Sql/Types.hs +0/−43
- Database/Persist/Sql/Util.hs +1/−2
- Database/Persist/Types.hs +24/−2
- persistent.cabal +3/−3
ChangeLog.md view
@@ -1,5 +1,14 @@ # Changelog for persistent +## 2.13.1.2++* [#1308](https://github.com/yesodweb/persistent/pull/1308)+ * Consolidate the documentation for the Persistent quasiquoter in+ Database.Persist.Quasi.+* [#1312](https://github.com/yesodweb/persistent/pull/1312)+ * Reorganize documentation and link to more modules.+ * Expose `Database.Persist.Sql.Migration`+ ## 2.13.1.1 * [#1294](https://github.com/yesodweb/persistent/pull/1294)
Database/Persist.hs view
@@ -1,37 +1,91 @@ {-# LANGUAGE ExistentialQuantification #-} +-- | Welcome to @persistent@!+--+-- This library intends to provide an easy, flexible, and convenient interface+-- to various data storage backends. Backends include SQL databases, like+-- @mysql@, @postgresql@, and @sqlite@, as well as NoSQL databases, like+-- @mongodb@ and @redis@.+--+-- If you intend on using a SQL database, then check out "Database.Persist.Sql". module Database.Persist- ( module Database.Persist.Class+ (+-- * Defining Database Models+--+-- | @persistent@ lets you define your database models using a special syntax.+-- This syntax allows you to customize the resulting Haskell datatypes and+-- database schema. See "Database.Persist.Quasi" for details on that definition+-- language.+--+-- ** Reference Schema & Dataset+--+-- | For a quick example of the syntax, we'll introduce this database schema, and+-- we'll use it to explain the update and filter combinators.+--+-- @+-- 'share' ['mkPersist' 'sqlSettings', 'mkMigrate' "migrateAll"] ['persistLowerCase'|+-- User+-- name String+-- age Int+-- deriving Show+-- |]+-- @+--+-- This creates a Haskell datatpe that looks like this:+--+-- @+-- data User = User+-- { userName :: String+-- , userAge :: Int+-- }+-- deriving Show+-- @+--+-- In a SQL database, we'd get a migration like this:+--+-- @+-- CREATE TABLE "user" (+-- id SERIAL PRIMARY KEY,+-- name TEXT NOT NULL,+-- age INT NOT NULL+-- );+-- @+--+-- The examples below will refer to this as dataset-1.+--+-- #dataset#+--+-- > +-----+-----+-----++-- > |id |name |age |+-- > +-----+-----+-----++-- > |1 |SPJ |40 |+-- > +-----+-----+-----++-- > |2 |Simon|41 |+-- > +-----+-----+-----+++ -- * Database Operations+ -- | The module "Database.Persist.Class" defines how to operate with+ -- @persistent@ database models. Check that module out for basic+ -- operations, like 'get', 'insert', and 'selectList'.+ module Database.Persist.Class+ -- * Types+ -- | This module re-export contains a lot of the important types for+ -- working with @persistent@ datatypes and underlying values. , module Database.Persist.Types - -- * Reference Schema & Dataset- -- |- --- -- All the combinators present here will be explained based on this schema:- --- -- > share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase|- -- > User- -- > name String- -- > age Int- -- > deriving Show- -- > |]- --- -- and this dataset. The examples below will refer to this as dataset-1.- --- -- #dataset#- --- -- > +-----+-----+-----+- -- > |id |name |age |- -- > +-----+-----+-----+- -- > |1 |SPJ |40 |- -- > +-----+-----+-----+- -- > |2 |Simon|41 |- -- > +-----+-----+-----++ -- * Query Operators+ -- | A convention that @persistent@ tries to follow is that operators on+ -- Database types correspond to a Haskell (or database) operator with a @.@+ -- character at the end. So to do @a || b@ , you'd write @a '||.' b@. To - -- * Query update combinators+ -- ** Query update combinators+ -- | These operations are used when performing updates against the database.+ -- Functions like 'upsert' use them to provide new or modified values. , (=.), (+=.), (-=.), (*=.), (/=.) - -- * Query filter combinators+ -- ** Query filter combinators+ -- | These functions are useful in the 'PersistQuery' class, like+ -- 'selectList', 'updateWhere', etc. , (==.), (!=.), (<.), (>.), (<=.), (>=.), (<-.), (/<-.), (||.) -- * JSON Utilities@@ -60,7 +114,7 @@ -- | Assign a field a value. ----- === __Example usage__+-- === Examples -- -- @ -- updateAge :: MonadIO m => ReaderT SqlBackend m ()@@ -83,7 +137,7 @@ -- | Assign a field by addition (@+=@). ----- === __Example usage__+-- === Examples -- -- @ -- addAge :: MonadIO m => ReaderT SqlBackend m ()@@ -105,7 +159,7 @@ -- | Assign a field by subtraction (@-=@). ----- === __Example usage__+-- === Examples -- -- @ -- subtractAge :: MonadIO m => ReaderT SqlBackend m ()@@ -126,7 +180,7 @@ -- | Assign a field by multiplication (@*=@). ----- === __Example usage__+-- === Examples -- -- @ -- multiplyAge :: MonadIO m => ReaderT SqlBackend m ()@@ -148,7 +202,7 @@ -- | Assign a field by division (@/=@). ----- === __Example usage__+-- === Examples -- -- @ -- divideAge :: MonadIO m => ReaderT SqlBackend m ()@@ -173,7 +227,7 @@ -- | Check for equality. ----- === __Example usage__+-- === Examples -- -- @ -- selectSPJ :: MonadIO m => ReaderT SqlBackend m [Entity User]@@ -192,7 +246,7 @@ -- | Non-equality check. ----- === __Example usage__+-- === Examples -- -- @ -- selectSimon :: MonadIO m => ReaderT SqlBackend m [Entity User]@@ -211,7 +265,7 @@ -- | Less-than check. ----- === __Example usage__+-- === Examples -- -- @ -- selectLessAge :: MonadIO m => ReaderT SqlBackend m [Entity User]@@ -230,7 +284,7 @@ -- | Less-than or equal check. ----- === __Example usage__+-- === Examples -- -- @ -- selectLessEqualAge :: MonadIO m => ReaderT SqlBackend m [Entity User]@@ -249,7 +303,7 @@ -- | Greater-than check. ----- === __Example usage__+-- === Examples -- -- @ -- selectGreaterAge :: MonadIO m => ReaderT SqlBackend m [Entity User]@@ -268,7 +322,7 @@ -- | Greater-than or equal check. ----- === __Example usage__+-- === Examples -- -- @ -- selectGreaterEqualAge :: MonadIO m => ReaderT SqlBackend m [Entity User]@@ -290,7 +344,7 @@ -- | Check if value is in given list. ----- === __Example usage__+-- === Examples -- -- @ -- selectUsers :: MonadIO m => ReaderT SqlBackend m [Entity User]@@ -325,7 +379,7 @@ -- | Check if value is not in given list. ----- === __Example usage__+-- === Examples -- -- @ -- selectSimon :: MonadIO m => ReaderT SqlBackend m [Entity User]
Database/Persist/Class.hs view
@@ -1,9 +1,23 @@ {-# LANGUAGE ConstraintKinds #-}++-- | This module exports all of the type classes in @persistent@ for operating+-- on the database backends.+--+-- @persistent@ offers methods that are abstract in the specific @backend@ type.+-- For SQL databases, this wil be 'Database.Persist.SqlBackend.SqlBackend'.+-- Other database backends will define their own types.+--+-- Methods and functions in this module have examples documented under an+-- "Example Usage" thing, that you need to click on to expand.+-- module Database.Persist.Class- ( ToBackendKey (..)+ ( -- * PersistStore- -- |+ -- | The 'PersistStore', 'PersistStoreRead', and 'PersistStoreWrite' type+ -- classes are used to define basic operations on the database. A database+ -- that implements these classes is capable of being used as a simple+ -- key-value store. -- -- All the examples present here will be explained based on these schemas, datasets and functions: --@@ -29,9 +43,7 @@ -- > +----+-------+-----+ -- > | 2 | Simon | 41 | -- > +----+-------+-----+-- , PersistCore (..)- , PersistStore+ PersistStore , PersistStoreRead (..) , PersistStoreWrite (..) , PersistRecordBackend@@ -44,7 +56,9 @@ , insertRecord -- * PersistUnique- -- |+ -- | The 'PersistUnique' type class is relevant for database backends that+ -- offer uniqueness keys. Uniquenes keys allow us to perform operations like+ -- 'getBy', 'deleteBy', as well as 'upsert' and 'putMany'. -- -- All the examples present here will be explained based on these two schemas and the dataset: --@@ -104,12 +118,15 @@ , onlyUnique -- * PersistQuery+ -- | The 'PersistQuery' type class allows us to select lists and filter+ -- database models. 'selectList' is the canonical read operation, and we+ -- can write 'updateWhere' and 'deleteWhere' to modify based on filters.+ , selectList+ , selectKeys , PersistQuery , PersistQueryRead (..) , PersistQueryWrite (..) , selectSource- , selectKeys- , selectList , selectKeysList -- * DeleteCascade@@ -133,6 +150,13 @@ , BackendCompatible (..) , withCompatibleBackend + -- * PersistCore+ -- | 'PersistCore' is a type class that defines a default database+ -- 'BackendKey' type. For SQL databases, this is currently an+ -- auto-incrementing inteer primary key. For MongoDB, it is the default+ -- ObjectID.+ , PersistCore (..)+ , ToBackendKey (..) -- * JSON utilities , keyValueEntityToJSON, keyValueEntityFromJSON , entityIdToJSON, entityIdFromJSON
Database/Persist/Class/PersistQuery.hs view
@@ -1,10 +1,10 @@ {-# LANGUAGE ExplicitForAll #-} module Database.Persist.Class.PersistQuery- ( PersistQueryRead (..)+ ( selectList+ , PersistQueryRead (..) , PersistQueryWrite (..) , selectSource , selectKeys- , selectList , selectKeysList ) where @@ -22,6 +22,12 @@ class (PersistCore backend, PersistStoreRead backend) => PersistQueryRead backend where -- | Get all records matching the given criterion in the specified order. -- Returns also the identifiers.+ --+ -- NOTE: This function returns an 'Acquire' and a 'ConduitM', which implies+ -- that it streams from the database. It does not. Please use 'selectList'+ -- to simplify the code. If you want streaming behavior, consider+ -- @persistent-pagination@ which efficiently chunks a query into ranges, or+ -- investigate a backend-specific streaming solution. selectSourceRes :: (PersistRecordBackend record backend, MonadIO m1, MonadIO m2) => [Filter record]@@ -66,6 +72,11 @@ -- | Get all records matching the given criterion in the specified order. -- Returns also the identifiers.+--+-- WARNING: This function returns a 'ConduitM', which implies 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. selectSource :: forall record backend m. (PersistQueryRead backend, MonadResource m, PersistRecordBackend record backend, MonadReader backend m) => [Filter record]@@ -78,6 +89,8 @@ release releaseKey -- | Get the 'Key's of all records matching the given criterion.+--+-- For an example, see 'selectList'. selectKeys :: forall record backend m. (PersistQueryRead backend, MonadResource m, PersistRecordBackend record backend, MonadReader backend m) => [Filter record] -> [SelectOpt record]@@ -88,11 +101,64 @@ src release releaseKey --- | Call 'selectSource' but return the result as a list.-selectList :: forall record backend m. (MonadIO m, PersistQueryRead backend, PersistRecordBackend record backend)- => [Filter record]- -> [SelectOpt record]- -> 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 'Database.Persist.>=.' 40] []+-- @+--+-- If you provide multiple values in the list, the conditions are @AND@ed+-- together.+--+-- @+-- usersWithAgeBetween30And50 :: 'SqlPersistT' 'IO' ['Entity' User]+-- usersWithAgeBetween30And50 =+-- 'selectList'+-- [ UserAge 'Database.Persist.>=.' 30+-- , UserAge 'Database.Persist.<=.' 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]+-- @+--+-- <https://use-the-index-luke.com/sql/partial-results/fetch-next-page Warning that LIMIT/OFFSET is bad for pagination!>+--+-- 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]+-- @+selectList+ :: forall record backend m. (MonadIO m, PersistQueryRead backend, PersistRecordBackend record backend)+ => [Filter record]+ -> [SelectOpt record]+ -> ReaderT backend m [Entity record] selectList filts opts = do srcRes <- selectSourceRes filts opts liftIO $ with srcRes (\src -> runConduit $ src .| CL.consume)
Database/Persist/Quasi.hs view
@@ -66,7 +66,7 @@ = 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.+The thing following the @=@ is interpreted as SQL that will be put directly into the table definition. @ User@@ -82,7 +82,7 @@ > 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:+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@@ -93,6 +93,28 @@ 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.@@ -171,11 +193,145 @@ ); @ -= Attributes+= 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!+If you use this feature, we'd definitely appreciate hearing about it and+potentially supporting your use case directly! @ User !funny@@ -196,6 +352,40 @@ -- [["sad"],["sogood"]] @ +== @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.@@ -213,6 +403,21 @@ 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.@@ -366,37 +571,6 @@ Foreign User fk_noti_user sentToFirst sentToSecond References emailFirst emailSecond @ -= 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.- = Documentation Comments The quasiquoter supports ordinary comments with @--@ and @#@.@@ -420,7 +594,7 @@ age Int @ -The documentation is present on the `entityComments` field on the `EntityDef` for the entity:+The documentation is present on the @entityComments@ field on the @EntityDef@ for the entity: @ >>> let userDefinition = entityDef (Proxy :: Proxy User)@@ -428,7 +602,7 @@ "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`:+Likewise, the field documentation is present in the @fieldComments@ field on the @FieldDef@ present in the @EntityDef@: @ >>> let userFields = entityFields userDefinition@@ -439,8 +613,292 @@ @ Unfortunately, we can't use this to create Haddocks for you, because <https://gitlab.haskell.org/ghc/ghc/issues/5467 Template Haskell does not support Haddock yet>.-`persistent` backends *can* 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.+@persistent@ backends *can* 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++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 _ (VehicycleBicycleSum _), Just (Entity _ (Bicycle brand)), _) =+ Bike brand+convert (Entity _ (VehicycleCarSum _), _, 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
Database/Persist/Sql.hs view
@@ -1,24 +1,50 @@+-- | This module is the primary entry point if you're working with @persistent@+-- on a SQL database.+--+-- = Getting Started+--+-- First, you'll want to define your database entities. You can do that with+-- "Database.Persist.Quasi."+--+-- Then, you'll use the operations module Database.Persist.Sql- ( module Database.Persist.Sql.Types- , module Database.Persist.Sql.Class+ (+ -- * 'RawSql' and 'PersistFieldSql'+ module Database.Persist.Sql.Class+ -- * Running actions+ -- | Run actions in a transaction with 'runSqlPool'. , module Database.Persist.Sql.Run+ -- * Migrations , module Database.Persist.Sql.Migration+ -- * @persistent@ combinators+ -- | We re-export "Database.Persist" here, to make it easier to use query+ -- and update combinators. Check out that module for documentation. , module Database.Persist , module Database.Persist.Sql.Orphan.PersistStore+ -- * The Escape Hatch+ -- | @persistent@ offers a set of functions that are useful for operating+ -- directly on the underlying SQL database. This can allow you to use+ -- whatever SQL features you want.+ --+ -- Consider going to <https://hackage.haskell.org/package/esqueleto+ -- esqueleto> for a more powerful SQL query library built on @persistent@. , rawQuery , rawQueryRes , rawExecute , rawExecuteCount , rawSql+ -- * SQL helpers , deleteWhereCount , updateWhereCount , filterClause , filterClauseWithVals , FilterTablePrefix (..)+ -- * Transactions , transactionSave , transactionSaveWithIsolation , transactionUndo , transactionUndoWithIsolation+ -- * Other utilities , getStmtConn , mkColumns , BackendSpecificOverrides@@ -29,6 +55,7 @@ -- * Internal , IsolationLevel(..) , decorateSQLWithLimitOffset+ , module Database.Persist.Sql.Types ) where import Control.Monad.IO.Class
Database/Persist/Sql/Migration.hs view
@@ -1,8 +1,17 @@+-- | This module documents tools and utilities for running SQL migrations.+--+-- A 'Migration' is (currently) an alias for a 'WriterT' of module Database.Persist.Sql.Migration- ( parseMigration+ (+ -- * Types+ Migration+ , CautiousMigration+ , Sql+ -- * Using a 'Migration'+ , showMigration+ , parseMigration , parseMigration' , printMigration- , showMigration , getMigration , runMigration , runMigrationQuiet@@ -11,11 +20,38 @@ , runMigrationUnsafeQuiet , migrate -- * Utilities for constructing migrations+ -- | While 'migrate' is capable of creating a 'Migration' for you, it's not+ -- the only way you can write migrations. You can use these utilities to write+ -- extra steps in your migrations.+ --+ -- As an example, let's say we want to enable the @citext@ extension on+ -- @postgres@ as part of our migrations.+ --+ -- @+ -- 'Database.Persist.TH.share' ['Database.Persist.TH.mkPersist' sqlSettings, 'Database.Persist.TH.mkMigration' "migrateAll"] ...+ --+ -- migration :: 'Migration'+ -- migration = do+ -- 'runSqlCommand' $+ -- 'rawExecute_' "CREATE EXTENSION IF NOT EXISTS \"citext\";"+ -- migrateAll+ -- @+ --+ -- For raw commands, you can also just write 'addMigration':+ --+ -- @+ -- migration :: 'Migration'+ -- migration = do+ -- 'addMigration' "CREATE EXTENSION IF NOT EXISTS \"citext\";"+ -- migrateAll+ -- @ , reportErrors , reportError , addMigrations , addMigration , runSqlCommand+ -- * If something goes wrong...+ , PersistUnsafeMigrationException(..) ) where @@ -36,9 +72,29 @@ import Database.Persist.Sql.Types import Database.Persist.Sql.Types.Internal import Database.Persist.Types+import Control.Exception (Exception(..)) +type Sql = Text++-- | A list of SQL operations, marked with a safety flag. If the 'Bool' is+-- 'True', then the operation is *unsafe* - it might be destructive, or+-- otherwise not idempotent. If the 'Bool' is 'False', then the operation+-- is *safe*, and can be run repeatedly without issues.+type CautiousMigration = [(Bool, Sql)]++-- | A 'Migration' is a four level monad stack consisting of:+--+-- * @'WriterT' ['Text']@ representing a log of errors in the migrations.+-- * @'WriterT' 'CautiousMigration'@ representing a list of migrations to+-- run, along with whether or not they are safe.+-- * @'ReaderT' 'SqlBackend'@, aka the 'SqlPersistT' transformer for+-- database interop.+-- * @'IO'@ for arbitrary IO.+type Migration = WriterT [Text] (WriterT CautiousMigration (ReaderT SqlBackend IO)) ()+ allSql :: CautiousMigration -> [Sql] allSql = map snd+ safeSql :: CautiousMigration -> [Sql] safeSql = allSql . filter (not . fst) @@ -55,7 +111,7 @@ -- | Like 'parseMigration', but instead of returning the value in an -- 'Either' value, it calls 'error' on the error values.-parseMigration' :: (HasCallStack, MonadIO m) => Migration -> ReaderT SqlBackend m (CautiousMigration)+parseMigration' :: (HasCallStack, MonadIO m) => Migration -> ReaderT SqlBackend m CautiousMigration parseMigration' m = do x <- parseMigration m case x of@@ -82,7 +138,6 @@ -- | Runs a migration. If the migration fails to parse or if any of the -- migrations are unsafe, then this throws a 'PersistUnsafeMigrationException'. runMigration :: MonadIO m- => Migration -> ReaderT SqlBackend m () runMigration m = runMigration' m False >> return ()@@ -223,3 +278,29 @@ -- @since 2.13.0.0 runSqlCommand :: SqlPersistT IO () -> Migration runSqlCommand = lift . lift++-- | An exception indicating that Persistent refused to run some unsafe+-- migrations. Contains a list of pairs where the Bool tracks whether the+-- migration was unsafe (True means unsafe), and the Sql is the sql statement+-- for the migration.+--+-- @since 2.11.1.0+newtype PersistUnsafeMigrationException+ = PersistUnsafeMigrationException [(Bool, Sql)]++-- | This 'Show' instance renders an error message suitable for printing to the+-- console. This is a little dodgy, but since GHC uses Show instances when+-- displaying uncaught exceptions, we have little choice.+instance Show PersistUnsafeMigrationException where+ show (PersistUnsafeMigrationException mig) =+ concat+ [ "\n\nDatabase migration: manual intervention required.\n"+ , "The unsafe actions are prefixed by '***' below:\n\n"+ , unlines $ map displayMigration mig+ ]+ where+ displayMigration :: (Bool, Sql) -> String+ displayMigration (True, s) = "*** " ++ unpack s ++ ";"+ displayMigration (False, s) = " " ++ unpack s ++ ";"++instance Exception PersistUnsafeMigrationException
Database/Persist/Sql/Types.hs view
@@ -61,24 +61,6 @@ type SqlPersistM = SqlPersistT (NoLoggingT (ResourceT IO)) -type Sql = Text---- | A list of SQL operations, marked with a safety flag. If the 'Bool' is--- 'True', then the operation is *unsafe* - it might be destructive, or--- otherwise not idempotent. If the 'Bool' is 'False', then the operation--- is *safe*, and can be run repeatedly without issues.-type CautiousMigration = [(Bool, Sql)]---- | A 'Migration' is a four level monad stack consisting of:------ * @'WriterT' ['Text']@ representing a log of errors in the migrations.--- * @'WriterT' 'CautiousMigration'@ representing a list of migrations to--- run, along with whether or not they are safe.--- * @'ReaderT' 'SqlBackend'@, aka the 'SqlPersistT' transformer for--- database interop.--- * @'IO'@ for arbitrary IO.-type Migration = WriterT [Text] (WriterT CautiousMigration (ReaderT SqlBackend IO)) ()- type ConnectionPool = Pool SqlBackend -- | Values to configure a pool of database connections. See "Data.Pool" for details.@@ -157,28 +139,3 @@ newtype Single a = Single {unSingle :: a} deriving (Eq, Ord, Show, Read) --- | An exception indicating that Persistent refused to run some unsafe--- migrations. Contains a list of pairs where the Bool tracks whether the--- migration was unsafe (True means unsafe), and the Sql is the sql statement--- for the migration.------ @since 2.11.1.0-newtype PersistUnsafeMigrationException- = PersistUnsafeMigrationException [(Bool, Sql)]---- | This 'Show' instance renders an error message suitable for printing to the--- console. This is a little dodgy, but since GHC uses Show instances when--- displaying uncaught exceptions, we have little choice.-instance Show PersistUnsafeMigrationException where- show (PersistUnsafeMigrationException mig) =- concat- [ "\n\nDatabase migration: manual intervention required.\n"- , "The unsafe actions are prefixed by '***' below:\n\n"- , unlines $ map displayMigration mig- ]- where- displayMigration :: (Bool, Sql) -> String- displayMigration (True, s) = "*** " ++ unpack s ++ ";"- displayMigration (False, s) = " " ++ unpack s ++ ";"--instance Exception PersistUnsafeMigrationException
Database/Persist/Sql/Util.hs view
@@ -49,10 +49,9 @@ , toPersistValue ) -import Database.Persist.Sql.Types (Sql) import Database.Persist.SqlBackend.Internal (SqlBackend(..)) -keyAndEntityColumnNames :: EntityDef -> SqlBackend -> NonEmpty Sql+keyAndEntityColumnNames :: EntityDef -> SqlBackend -> NonEmpty Text keyAndEntityColumnNames ent conn = fmap (connEscapeFieldName conn . fieldDB) (keyAndEntityFields ent)
Database/Persist/Types.hs view
@@ -1,9 +1,29 @@+-- | This module exports many types and functions for operating on+-- @persistent@'s database representation. It's a bit of a kitchen sink. In the+-- future, this module will be reorganized, and many of the dependent modules+-- will be viewable on their own for easier documentation and organization. module Database.Persist.Types- ( module Database.Persist.Types.Base- , module Database.Persist.Names+ (+ -- * Various Types of Names+ -- | There are so many kinds of names. @persistent@ defines newtype wrappers+ -- for 'Text' so you don't confuse what a name is and what it is+ -- supposed to be used for+ module Database.Persist.Names+ -- * Database Definitions+ -- ** Entity/Table Definitions+ -- | The 'EntityDef' type is used by @persistent@ to generate Haskell code,+ -- generate database migrations, and maintain metadata about entities. These+ -- are generated in the call to 'Database.Persist.TH.mkPersist'. , module Database.Persist.EntityDef+ -- ** Field definitions+ -- | The 'FieldDef' type is used to describe how a field should be+ -- represented at the Haskell and database layers. , module Database.Persist.FieldDef+ -- * Intermediate Values+ -- | The 'PersistValue' type is used as an intermediate layer between+ -- database and Haskell types. , module Database.Persist.PersistValue+ -- * Other Useful Stuff , SomePersistField (..) , Update (..) , BackendSpecificUpdate@@ -14,6 +34,8 @@ , Key , Entity (..) , OverflowNatural(..)+ -- * The rest of the types+ , module Database.Persist.Types.Base ) where import Database.Persist.Class.PersistEntity
persistent.cabal view
@@ -1,5 +1,5 @@ name: persistent-version: 2.13.1.1+version: 2.13.1.2 license: MIT license-file: LICENSE author: Michael Snoyman <michael@snoyman.com>@@ -67,8 +67,9 @@ Database.Persist.Quasi.Internal Database.Persist.Sql- Database.Persist.Sql.Util+ Database.Persist.Sql.Migration Database.Persist.Sql.Types.Internal+ Database.Persist.Sql.Util Database.Persist.SqlBackend Database.Persist.SqlBackend.Internal@@ -89,7 +90,6 @@ other-modules: Database.Persist.Types.Base - Database.Persist.Sql.Migration Database.Persist.Sql.Internal Database.Persist.Sql.Types Database.Persist.Sql.Raw