-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Type-safe, multi-backend data serialization. -- -- Hackage documentation generation is not reliable. For up to date -- documentation, please see: -- http://www.stackage.org/package/persistent. @package persistent @version 2.12.1.2 module Database.Persist.Types data PersistUpdate Assign :: PersistUpdate Add :: PersistUpdate Subtract :: PersistUpdate Multiply :: PersistUpdate Divide :: PersistUpdate BackendSpecificUpdate :: Text -> PersistUpdate data OnlyUniqueException OnlyUniqueException :: String -> OnlyUniqueException data UpdateException KeyNotFound :: String -> UpdateException UpsertError :: String -> UpdateException data PersistFilter Eq :: PersistFilter Ne :: PersistFilter Gt :: PersistFilter Lt :: PersistFilter Ge :: PersistFilter Le :: PersistFilter In :: PersistFilter NotIn :: PersistFilter BackendSpecificFilter :: Text -> PersistFilter -- | A SQL data type. Naming attempts to reflect the underlying Haskell -- datatypes, eg SqlString instead of SqlVarchar. Different SQL databases -- may have different translations for these types. data SqlType SqlString :: SqlType SqlInt32 :: SqlType SqlInt64 :: SqlType SqlReal :: SqlType SqlNumeric :: Word32 -> Word32 -> SqlType SqlBool :: SqlType SqlDay :: SqlType SqlTime :: SqlType -- | Always uses UTC timezone SqlDayTime :: SqlType SqlBlob :: SqlType -- | a backend-specific name SqlOther :: Text -> SqlType -- | A type that determines how a backend should handle the literal. data LiteralType -- | The accompanying value will be escaped before inserting into the -- database. This is the correct default choice to use. Escaped :: LiteralType -- | The accompanying value will not be escaped when inserting into the -- database. This is potentially dangerous - use this with care. Unescaped :: LiteralType -- | The DbSpecific constructor corresponds to the legacy -- PersistDbSpecific constructor. We need to keep this around -- because old databases may have serialized JSON representations that -- reference this. We don't want to break the ability of a database to -- load rows. DbSpecific :: LiteralType -- | A raw value which can be stored in any backend and can be marshalled -- to and from a PersistField. data PersistValue PersistText :: Text -> PersistValue PersistByteString :: ByteString -> PersistValue PersistInt64 :: Int64 -> PersistValue PersistDouble :: Double -> PersistValue PersistRational :: Rational -> PersistValue PersistBool :: Bool -> PersistValue PersistDay :: Day -> PersistValue PersistTimeOfDay :: TimeOfDay -> PersistValue PersistUTCTime :: UTCTime -> PersistValue PersistNull :: PersistValue PersistList :: [PersistValue] -> PersistValue PersistMap :: [(Text, PersistValue)] -> PersistValue -- | Intended especially for MongoDB backend PersistObjectId :: ByteString -> PersistValue -- | Intended especially for PostgreSQL backend for text arrays PersistArray :: [PersistValue] -> PersistValue -- | This constructor is used to specify some raw literal value for the -- backend. The LiteralType value specifies how the value should -- be escaped. This can be used to make special, custom types avaialable -- in the back end. PersistLiteral_ :: LiteralType -> ByteString -> PersistValue data PersistException -- | Generic Exception PersistError :: Text -> PersistException PersistMarshalError :: Text -> PersistException PersistInvalidField :: Text -> PersistException PersistForeignConstraintUnmet :: Text -> PersistException PersistMongoDBError :: Text -> PersistException PersistMongoDBUnsupported :: Text -> PersistException -- | An action that might happen on a deletion or update on a foreign key -- change. data CascadeAction Cascade :: CascadeAction Restrict :: CascadeAction SetNull :: CascadeAction SetDefault :: CascadeAction -- | This datatype describes how a foreign reference field cascades deletes -- or updates. -- -- This type is used in both parsing the model definitions and performing -- migrations. A Nothing in either of the field values means that -- the user has not specified a CascadeAction. An unspecified -- CascadeAction is defaulted to Restrict when doing -- migrations. data FieldCascade FieldCascade :: !Maybe CascadeAction -> !Maybe CascadeAction -> FieldCascade [fcOnUpdate] :: FieldCascade -> !Maybe CascadeAction [fcOnDelete] :: FieldCascade -> !Maybe CascadeAction data ForeignDef ForeignDef :: !EntityNameHS -> !EntityNameDB -> !ConstraintNameHS -> !ConstraintNameDB -> !FieldCascade -> ![(ForeignFieldDef, ForeignFieldDef)] -> ![Attr] -> Bool -> Bool -> ForeignDef [foreignRefTableHaskell] :: ForeignDef -> !EntityNameHS [foreignRefTableDBName] :: ForeignDef -> !EntityNameDB [foreignConstraintNameHaskell] :: ForeignDef -> !ConstraintNameHS [foreignConstraintNameDBName] :: ForeignDef -> !ConstraintNameDB -- | Determine how the field will cascade on updates and deletions. [foreignFieldCascade] :: ForeignDef -> !FieldCascade [foreignFields] :: ForeignDef -> ![(ForeignFieldDef, ForeignFieldDef)] [foreignAttrs] :: ForeignDef -> ![Attr] [foreignNullable] :: ForeignDef -> Bool -- | Determines if the reference is towards a Primary Key or not. [foreignToPrimary] :: ForeignDef -> Bool -- | Used instead of FieldDef to generate a smaller amount of code type ForeignFieldDef = (FieldNameHS, FieldNameDB) data CompositeDef CompositeDef :: ![FieldDef] -> ![Attr] -> CompositeDef [compositeFields] :: CompositeDef -> ![FieldDef] [compositeAttrs] :: CompositeDef -> ![Attr] data UniqueDef UniqueDef :: !ConstraintNameHS -> !ConstraintNameDB -> ![(FieldNameHS, FieldNameDB)] -> ![Attr] -> UniqueDef [uniqueHaskell] :: UniqueDef -> !ConstraintNameHS [uniqueDBName] :: UniqueDef -> !ConstraintNameDB [uniqueFields] :: UniqueDef -> ![(FieldNameHS, FieldNameDB)] [uniqueAttrs] :: UniqueDef -> ![Attr] -- | An ConstraintNameHS represents the Haskell-side name that -- persistent will use for a constraint. newtype ConstraintNameHS ConstraintNameHS :: Text -> ConstraintNameHS [unConstraintNameHS] :: ConstraintNameHS -> Text -- | A ConstraintNameDB represents the datastore-side name that -- persistent will use for a constraint. newtype ConstraintNameDB ConstraintNameDB :: Text -> ConstraintNameDB [unConstraintNameDB] :: ConstraintNameDB -> Text -- | An EmbedFieldDef is the same as a FieldDef But it is only used for -- embeddedFields so it only has data needed for embedding data EmbedFieldDef EmbedFieldDef :: !FieldNameDB -> Maybe EmbedEntityDef -> Maybe EntityNameHS -> EmbedFieldDef [emFieldDB] :: EmbedFieldDef -> !FieldNameDB [emFieldEmbed] :: EmbedFieldDef -> Maybe EmbedEntityDef -- | emFieldEmbed can create a cycle (issue #311) when a cycle is -- detected, emFieldEmbed will be Nothing and emFieldCycle -- will be Just [emFieldCycle] :: EmbedFieldDef -> Maybe EntityNameHS -- | An EmbedEntityDef is the same as an EntityDef But it is only used for -- fieldReference so it only has data needed for embedding data EmbedEntityDef EmbedEntityDef :: !EntityNameHS -> ![EmbedFieldDef] -> EmbedEntityDef [embeddedHaskell] :: EmbedEntityDef -> !EntityNameHS [embeddedFields] :: EmbedEntityDef -> ![EmbedFieldDef] -- | There are 3 kinds of references 1) composite (to fields that exist in -- the record) 2) single field 3) embedded data ReferenceDef NoReference :: ReferenceDef -- | A ForeignRef has a late binding to the EntityDef it references via -- name and has the Haskell type of the foreign key in the form of -- FieldType ForeignRef :: !EntityNameHS -> !FieldType -> ReferenceDef EmbedRef :: EmbedEntityDef -> ReferenceDef CompositeRef :: CompositeDef -> ReferenceDef -- | A SelfReference stops an immediate cycle which causes non-termination -- at compile-time (issue #311). SelfReference :: ReferenceDef -- | A FieldDef represents the inormation that persistent -- knows about a field of a datatype. This includes information used to -- parse the field out of the database and what the field corresponds to. data FieldDef FieldDef :: !FieldNameHS -> !FieldNameDB -> !FieldType -> !SqlType -> ![FieldAttr] -> !Bool -> !ReferenceDef -> !FieldCascade -> !Maybe Text -> !Maybe Text -> FieldDef -- | The name of the field. Note that this does not corresponds to the -- record labels generated for the particular entity - record labels are -- generated with the type name prefixed to the field, so a -- FieldDef that contains a FieldNameHS "name" for -- a type User will have a record field userName. [fieldHaskell] :: FieldDef -> !FieldNameHS -- | The name of the field in the database. For SQL databases, this -- corresponds to the column name. [fieldDB] :: FieldDef -> !FieldNameDB -- | The type of the field in Haskell. [fieldType] :: FieldDef -> !FieldType -- | The type of the field in a SQL database. [fieldSqlType] :: FieldDef -> !SqlType -- | User annotations for a field. These are provided with the ! -- operator. [fieldAttrs] :: FieldDef -> ![FieldAttr] -- | If this is True, then the Haskell datatype will have a strict -- record field. The default value for this is True. [fieldStrict] :: FieldDef -> !Bool [fieldReference] :: FieldDef -> !ReferenceDef -- | Defines how operations on the field cascade on to the referenced -- tables. This doesn't have any meaning if the fieldReference is -- set to NoReference or SelfReference. The cascade option -- here should be the same as the one obtained in the -- fieldReference. [fieldCascade] :: FieldDef -> !FieldCascade -- | Optional comments for a Field. There is not currently a way -- to attach comments to a field in the quasiquoter. [fieldComments] :: FieldDef -> !Maybe Text -- | Whether or not the field is a GENERATED column, and -- additionally the expression to use for generation. [fieldGenerated] :: FieldDef -> !Maybe Text -- | A FieldNameHS represents the Haskell-side name that -- persistent will use for a field. newtype FieldNameHS FieldNameHS :: Text -> FieldNameHS [unFieldNameHS] :: FieldNameHS -> Text -- | An EntityNameDB represents the datastore-side name that -- persistent will use for an entity. newtype FieldNameDB FieldNameDB :: Text -> FieldNameDB [unFieldNameDB] :: FieldNameDB -> Text -- | A FieldType describes a field parsed from the QuasiQuoter and -- is used to determine the Haskell type in the generated code. -- -- name Text parses into FTTypeCon Nothing Text -- -- name T.Text parses into FTTypeCon (Just T -- Text) -- -- name (Jsonb User) parses into: -- --
-- FTApp (FTTypeCon Nothing Jsonb) (FTTypeCon Nothing User) --data FieldType -- | Optional module and name. FTTypeCon :: Maybe Text -> Text -> FieldType FTTypePromoted :: Text -> FieldType FTApp :: FieldType -> FieldType -> FieldType FTList :: FieldType -> FieldType -- | Attributes that may be attached to fields that can affect migrations -- and serialization in backend-specific ways. -- -- While we endeavor to, we can't forsee all use cases for all backends, -- and so FieldAttr is extensible through its constructor -- FieldAttrOther. data FieldAttr FieldAttrMaybe :: FieldAttr FieldAttrNullable :: FieldAttr FieldAttrMigrationOnly :: FieldAttr FieldAttrSafeToRemove :: FieldAttr FieldAttrNoreference :: FieldAttr FieldAttrReference :: Text -> FieldAttr FieldAttrConstraint :: Text -> FieldAttr FieldAttrDefault :: Text -> FieldAttr FieldAttrSqltype :: Text -> FieldAttr FieldAttrMaxlen :: Integer -> FieldAttr FieldAttrOther :: Text -> FieldAttr type Attr = Text type ExtraLine = [Text] -- | An EntityDef represents the information that -- persistent knows about an Entity. It uses this information to -- generate the Haskell datatype, the SQL migrations, and other relevant -- conversions. data EntityDef EntityDef :: !EntityNameHS -> !EntityNameDB -> !FieldDef -> ![Attr] -> ![FieldDef] -> ![UniqueDef] -> ![ForeignDef] -> ![Text] -> !Map Text [ExtraLine] -> !Bool -> !Maybe Text -> EntityDef -- | The name of the entity as Haskell understands it. [entityHaskell] :: EntityDef -> !EntityNameHS -- | The name of the database table corresponding to the entity. [entityDB] :: EntityDef -> !EntityNameDB -- | The entity's primary key or identifier. [entityId] :: EntityDef -> !FieldDef -- | The persistent entity syntax allows you to add arbitrary -- Attrs to an entity using the ! operator. Those -- attributes are stored in this list. [entityAttrs] :: EntityDef -> ![Attr] -- | The fields for this entity. Note that the ID field will not be present -- in this list. To get all of the fields for an entity, use -- keyAndEntityFields. [entityFields] :: EntityDef -> ![FieldDef] -- | The Uniqueness constraints for this entity. [entityUniques] :: EntityDef -> ![UniqueDef] -- | The foreign key relationships that this entity has to other entities. [entityForeigns] :: EntityDef -> ![ForeignDef] -- | A list of type classes that have been derived for this entity. [entityDerives] :: EntityDef -> ![Text] [entityExtra] :: EntityDef -> !Map Text [ExtraLine] -- | Whether or not this entity represents a sum type in the database. [entitySum] :: EntityDef -> !Bool -- | Optional comments on the entity. [entityComments] :: EntityDef -> !Maybe Text -- | An EntityNameHS represents the Haskell-side name that -- persistent will use for an entity. newtype EntityNameHS EntityNameHS :: Text -> EntityNameHS [unEntityNameHS] :: EntityNameHS -> Text -- | An EntityNameDB represents the datastore-side name that -- persistent will use for an entity. newtype EntityNameDB EntityNameDB :: Text -> EntityNameDB [unEntityNameDB] :: EntityNameDB -> Text -- | Convenience operations for working with '-NameDB' types. class DatabaseName a escapeWith :: DatabaseName a => (Text -> str) -> a -> str -- | The reason why a field is nullable is very important. A field -- that is nullable because of a Maybe tag will have its type -- changed from A to Maybe A. OTOH, a field that is -- nullable because of a nullable tag will remain with the same -- type. data WhyNullable ByMaybeAttr :: WhyNullable ByNullableAttr :: WhyNullable data IsNullable Nullable :: !WhyNullable -> IsNullable NotNullable :: IsNullable -- | A Checkmark should be used as a field type whenever a -- uniqueness constraint should guarantee that a certain kind of record -- may appear at most once, but other kinds of records may appear any -- number of times. -- -- NOTE: You need to mark any Checkmark fields as -- nullable (see the following example). -- -- For example, suppose there's a Location entity that -- represents where a user has lived: -- --
-- Location -- user UserId -- name Text -- current Checkmark nullable -- -- UniqueLocation user current ---- -- The UniqueLocation constraint allows any number of -- Inactive Locations to be current. However, -- there may be at most one current Location per user -- (i.e., either zero or one per user). -- -- This data type works because of the way that SQL treats -- NULLable fields within uniqueness constraints. The SQL -- standard says that NULL values should be considered -- different, so we represent Inactive as SQL NULL, thus -- allowing any number of Inactive records. On the other hand, we -- represent Active as TRUE, so the uniqueness constraint -- will disallow more than one Active record. -- -- Note: There may be DBMSs that do not respect the SQL standard's -- treatment of NULL values on uniqueness constraints, please -- check if this data type works before relying on it. -- -- The SQL BOOLEAN type is used because it's the smallest data -- type available. Note that we never use FALSE, just -- TRUE and NULL. Provides the same behavior Maybe -- () would if () was a valid PersistField. data Checkmark -- | When used on a uniqueness constraint, there may be at most one -- Active record. Active :: Checkmark -- | When used on a uniqueness constraint, there may be any number of -- Inactive records. Inactive :: Checkmark -- | This pattern synonym used to be a data constructor on -- PersistValue, but was changed into a catch-all pattern synonym -- to allow backwards compatiblity with database types. See the -- documentation on PersistDbSpecific for more details. pattern PersistLiteral :: ByteString -> PersistValue -- | This pattern synonym used to be a data constructor on -- PersistValue, but was changed into a catch-all pattern synonym -- to allow backwards compatiblity with database types. See the -- documentation on PersistDbSpecific for more details. pattern PersistLiteralEscaped :: ByteString -> PersistValue -- | This pattern synonym used to be a data constructor for the -- PersistValue type. It was changed to be a pattern so that -- JSON-encoded database values could be parsed into their corresponding -- values. You should not use this, and instead prefer to pattern match -- on PersistLiteral_ directly. -- -- If you use this, it will overlap a patern match on the -- 'PersistLiteral_, PersistLiteral, and -- PersistLiteralEscaped patterns. If you need to disambiguate -- between these constructors, pattern match on PersistLiteral_ -- directly. -- | Deprecated: Deprecated since 2.11 because of inconsistent escaping -- behavior across backends. The Postgres backend escapes these values, -- while the MySQL backend does not. If you are using this, please switch -- to PersistLiteral_ and provide a relevant LiteralType -- for your conversion. pattern PersistDbSpecific :: ByteString -> PersistValue entitiesPrimary :: EntityDef -> Maybe [FieldDef] entityPrimary :: EntityDef -> Maybe CompositeDef entityKeyFields :: EntityDef -> [FieldDef] keyAndEntityFields :: EntityDef -> [FieldDef] -- | Parse raw field attributes into structured form. Any unrecognized -- attributes will be preserved, identically as they are encountered, as -- FieldAttrOther values. parseFieldAttrs :: [Text] -> [FieldAttr] isFieldNotGenerated :: FieldDef -> Bool toEmbedEntityDef :: EntityDef -> EmbedEntityDef -- | A FieldCascade that does nothing. noCascade :: FieldCascade -- | Renders a FieldCascade value such that it can be used in SQL -- migrations. renderFieldCascade :: FieldCascade -> Text -- | Render a CascadeAction to Text such that it can be used -- in a SQL command. renderCascadeAction :: CascadeAction -> Text fromPersistValueText :: PersistValue -> Either Text Text -- | A raw value which can be stored in any backend and can be marshalled -- to and from a PersistField. data PersistValue PersistText :: Text -> PersistValue PersistByteString :: ByteString -> PersistValue PersistInt64 :: Int64 -> PersistValue PersistDouble :: Double -> PersistValue PersistRational :: Rational -> PersistValue PersistBool :: Bool -> PersistValue PersistDay :: Day -> PersistValue PersistTimeOfDay :: TimeOfDay -> PersistValue PersistUTCTime :: UTCTime -> PersistValue PersistNull :: PersistValue PersistList :: [PersistValue] -> PersistValue PersistMap :: [(Text, PersistValue)] -> PersistValue -- | Intended especially for MongoDB backend PersistObjectId :: ByteString -> PersistValue -- | Intended especially for PostgreSQL backend for text arrays PersistArray :: [PersistValue] -> PersistValue -- | This constructor is used to specify some raw literal value for the -- backend. The LiteralType value specifies how the value should -- be escaped. This can be used to make special, custom types avaialable -- in the back end. PersistLiteral_ :: LiteralType -> ByteString -> PersistValue -- | This pattern synonym used to be a data constructor on -- PersistValue, but was changed into a catch-all pattern synonym -- to allow backwards compatiblity with database types. See the -- documentation on PersistDbSpecific for more details. pattern PersistLiteral :: ByteString -> PersistValue -- | This pattern synonym used to be a data constructor on -- PersistValue, but was changed into a catch-all pattern synonym -- to allow backwards compatiblity with database types. See the -- documentation on PersistDbSpecific for more details. pattern PersistLiteralEscaped :: ByteString -> PersistValue -- | This pattern synonym used to be a data constructor for the -- PersistValue type. It was changed to be a pattern so that -- JSON-encoded database values could be parsed into their corresponding -- values. You should not use this, and instead prefer to pattern match -- on PersistLiteral_ directly. -- -- If you use this, it will overlap a patern match on the -- 'PersistLiteral_, PersistLiteral, and -- PersistLiteralEscaped patterns. If you need to disambiguate -- between these constructors, pattern match on PersistLiteral_ -- directly. -- | Deprecated: Deprecated since 2.11 because of inconsistent escaping -- behavior across backends. The Postgres backend escapes these values, -- while the MySQL backend does not. If you are using this, please switch -- to PersistLiteral_ and provide a relevant LiteralType -- for your conversion. pattern PersistDbSpecific :: ByteString -> PersistValue -- | A type that determines how a backend should handle the literal. data LiteralType -- | The accompanying value will be escaped before inserting into the -- database. This is the correct default choice to use. Escaped :: LiteralType -- | The accompanying value will not be escaped when inserting into the -- database. This is potentially dangerous - use this with care. Unescaped :: LiteralType -- | The DbSpecific constructor corresponds to the legacy -- PersistDbSpecific constructor. We need to keep this around -- because old databases may have serialized JSON representations that -- reference this. We don't want to break the ability of a database to -- load rows. DbSpecific :: LiteralType data SomePersistField SomePersistField :: a -> SomePersistField -- | Updating a database entity. -- -- Persistent users use combinators to create these. data Update record Update :: EntityField record typ -> typ -> PersistUpdate -> Update record [updateField] :: Update record -> EntityField record typ [updateValue] :: Update record -> typ [updateUpdate] :: Update record -> PersistUpdate BackendUpdate :: BackendSpecificUpdate (PersistEntityBackend record) record -> Update record type family BackendSpecificUpdate backend record -- | Query options. -- -- Persistent users use these directly. data SelectOpt record Asc :: EntityField record typ -> SelectOpt record Desc :: EntityField record typ -> SelectOpt record OffsetBy :: Int -> SelectOpt record LimitTo :: Int -> SelectOpt record -- | Filters which are available for select, updateWhere -- and deleteWhere. Each filter constructor specifies the field -- being filtered on, the type of comparison applied (equals, not equals, -- etc) and the argument for the comparison. -- -- Persistent users use combinators to create these. -- -- Note that it's important to be careful about the PersistFilter -- that you are using, if you use this directly. For example, using the -- In PersistFilter requires that you have an array- or -- list-shaped EntityField. It is possible to construct values -- using this that will create malformed runtime values. data Filter record Filter :: EntityField record typ -> FilterValue typ -> PersistFilter -> Filter record [filterField] :: Filter record -> EntityField record typ [filterValue] :: Filter record -> FilterValue typ [filterFilter] :: Filter record -> PersistFilter -- | convenient for internal use, not needed for the API FilterAnd :: [Filter record] -> Filter record FilterOr :: [Filter record] -> Filter record BackendFilter :: BackendSpecificFilter (PersistEntityBackend record) record -> Filter record -- | Value to filter with. Highly dependant on the type of filter used. data FilterValue typ [FilterValue] :: typ -> FilterValue typ [FilterValues] :: [typ] -> FilterValue typ [UnsafeValue] :: forall a typ. PersistField a => a -> FilterValue typ type family BackendSpecificFilter backend record -- | By default, a backend will automatically generate the key Instead you -- can specify a Primary key made up of unique values. data family Key record -- | Datatype that represents an entity, with both its Key and its -- Haskell record representation. -- -- When using a SQL-based backend (such as SQLite or PostgreSQL), an -- Entity may take any number of columns depending on how many -- fields it has. In order to reconstruct your entity on the Haskell -- side, persistent needs all of your entity columns and in the -- right order. Note that you don't need to worry about this when using -- persistent's API since everything is handled correctly behind -- the scenes. -- -- However, if you want to issue a raw SQL command that returns an -- Entity, then you have to be careful with the column order. -- While you could use SELECT Entity.* WHERE ... and that would -- work most of the time, there are times when the order of the columns -- on your database is different from the order that persistent -- expects (for example, if you add a new field in the middle of you -- entity definition and then use the migration code -- -- persistent will expect the column to be in the middle, but -- your DBMS will put it as the last column). So, instead of using a -- query like the one above, you may use rawSql (from the -- Database.Persist.GenericSql module) with its /entity selection -- placeholder/ (a double question mark ??). Using -- rawSql the query above must be written as SELECT ?? WHERE -- ... Then rawSql will replace ?? with the list -- of all columns that we need from your entity in the right order. If -- your query returns two entities (i.e. (Entity backend a, Entity -- backend b)), then you must you use SELECT ??, ?? WHERE -- ..., and so on. data Entity record Entity :: Key record -> record -> Entity record [entityKey] :: Entity record -> Key record [entityVal] :: Entity record -> record -- | Prior to persistent-2.11.0, we provided an instance of -- PersistField for the Natural type. This was in error, -- because Natural represents an infinite value, and databases -- don't have reasonable types for this. -- -- The instance for Natural used the Int64 underlying type, -- which will cause underflow and overflow errors. This type has the -- exact same code in the instances, and will work seamlessly. -- -- A more appropriate type for this is the Word series of types -- from Data.Word. These have a bounded size, are guaranteed to be -- non-negative, and are quite efficient for the database to store. newtype OverflowNatural OverflowNatural :: Natural -> OverflowNatural [unOverflowNatural] :: OverflowNatural -> Natural -- | 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.
--
-- -- User -- name String -- age Int -- deriving Eq Show -- deriving Ord ---- --
-- User -- name String -- age Int -- -- UniqueUserName name ---- -- This will put a unique index on the user table and the -- name field. -- --
-- 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.
--
-- -- 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 ---- --
-- 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. -- --
-- User sql=big_user_table -- fullName String sql=name -- age Int ---- -- This will alter the generated SQL to be: -- --
-- CREATE TABEL big_user_table ( -- id SERIAL PRIMARY KEY, -- name VARCHAR, -- age INT -- ); ---- --
-- 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"]] ---- --
-- 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. -- --
-- 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 $(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. -- --
-- 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. -- --
-- 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 ---- --
-- -- | 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." ---- -- Unfortunately, we can't use this to create Haddocks for you, because -- Template Haskell does not support Haddock yet. -- persistent backends *can* use this to generate SQL -- COMMENTs, which are useful for a database perspective, and -- you can use the @persistent-documentation@ library to render a -- Markdown document of the entity definitions. module Database.Persist.Quasi -- | Parses a quasi-quoted syntax into a list of entity definitions. parse :: PersistSettings -> Text -> [EntityDef] data PersistSettings PersistSettings :: !Text -> Text -> !Bool -> !Text -> PersistSettings [psToDBName] :: PersistSettings -> !Text -> Text -- | Whether fields are by default strict. Default value: True. [psStrictFields] :: PersistSettings -> !Bool -- | The name of the id column. Default value: id The name of the -- id column can also be changed on a per-model basis -- https://github.com/yesodweb/persistent/wiki/Persistent-entity-syntax [psIdName] :: PersistSettings -> !Text upperCaseSettings :: PersistSettings lowerCaseSettings :: PersistSettings nullable :: [FieldAttr] -> IsNullable instance GHC.Show.Show a => GHC.Show.Show (Database.Persist.Quasi.ParseState a) instance GHC.Classes.Eq Database.Persist.Quasi.Token instance GHC.Show.Show Database.Persist.Quasi.Token instance GHC.Show.Show Database.Persist.Quasi.Line instance GHC.Classes.Eq Database.Persist.Quasi.Line instance GHC.Show.Show Database.Persist.Quasi.LinesWithComments instance GHC.Classes.Eq Database.Persist.Quasi.LinesWithComments module Database.Persist.Class -- | ToBackendKey converts a PersistEntity Key into a -- BackendKey This can be used by each backend to convert between -- a Key and a plain Haskell type. For Sql, that is done with -- toSqlKey and fromSqlKey. -- -- By default, a PersistEntity uses the default BackendKey -- for its Key and is an instance of ToBackendKey -- -- A Key that instead uses a custom type will not be an instance -- of ToBackendKey. class (PersistEntity record, PersistEntityBackend record ~ backend, PersistCore backend) => ToBackendKey backend record toBackendKey :: ToBackendKey backend record => Key record -> BackendKey backend fromBackendKey :: ToBackendKey backend record => BackendKey backend -> Key record class PersistCore backend where { data family BackendKey backend; } -- | A backwards-compatible alias for those that don't care about -- distinguishing between read and write queries. It signifies the -- assumption that, by default, a backend can write as well as read. type PersistStore a = PersistStoreWrite a class (Show (BackendKey backend), Read (BackendKey backend), Eq (BackendKey backend), Ord (BackendKey backend), PersistCore backend, PersistField (BackendKey backend), ToJSON (BackendKey backend), FromJSON (BackendKey backend)) => PersistStoreRead backend -- | Get a record by identifier, if available. -- --
-- getSpj :: MonadIO m => ReaderT SqlBackend m (Maybe User) -- getSpj = get spjId ---- --
-- mspj <- getSpj ---- -- The above query when applied on dataset-1, will get this: -- --
-- +------+-----+ -- | name | age | -- +------+-----+ -- | SPJ | 40 | -- +------+-----+ --get :: forall record m. (PersistStoreRead backend, MonadIO m, PersistRecordBackend record backend) => Key record -> ReaderT backend m (Maybe record) -- | Get many records by their respective identifiers, if available. -- --
-- getUsers :: MonadIO m => ReaderT SqlBackend m (Map (Key User) User) -- getUsers = getMany allkeys ---- --
-- musers <- getUsers ---- -- The above query when applied on dataset-1, will get these -- records: -- --
-- +----+-------+-----+ -- | id | name | age | -- +----+-------+-----+ -- | 1 | SPJ | 40 | -- +----+-------+-----+ -- | 2 | Simon | 41 | -- +----+-------+-----+ --getMany :: forall record m. (PersistStoreRead backend, MonadIO m, PersistRecordBackend record backend) => [Key record] -> ReaderT backend m (Map (Key record) record) class (Show (BackendKey backend), Read (BackendKey backend), Eq (BackendKey backend), Ord (BackendKey backend), PersistStoreRead backend, PersistField (BackendKey backend), ToJSON (BackendKey backend), FromJSON (BackendKey backend)) => PersistStoreWrite backend -- | Create a new record in the database, returning an automatically -- created key (in SQL an auto-increment id). -- --
-- insertJohn :: MonadIO m => ReaderT SqlBackend m (Key User) -- insertJohn = insert $ User "John" 30 ---- --
-- johnId <- insertJohn ---- -- The above query when applied on dataset-1, will produce this: -- --
-- +-----+------+-----+ -- |id |name |age | -- +-----+------+-----+ -- |1 |SPJ |40 | -- +-----+------+-----+ -- |2 |Simon |41 | -- +-----+------+-----+ -- |3 |John |30 | -- +-----+------+-----+ --insert :: forall record m. (PersistStoreWrite backend, MonadIO m, PersistRecordBackend record backend) => record -> ReaderT backend m (Key record) -- | Same as insert, but doesn't return a Key. -- --
-- insertJohn :: MonadIO m => ReaderT SqlBackend m (Key User) -- insertJohn = insert_ $ User "John" 30 ---- -- The above query when applied on dataset-1, will produce this: -- --
-- +-----+------+-----+ -- |id |name |age | -- +-----+------+-----+ -- |1 |SPJ |40 | -- +-----+------+-----+ -- |2 |Simon |41 | -- +-----+------+-----+ -- |3 |John |30 | -- +-----+------+-----+ --insert_ :: forall record m. (PersistStoreWrite backend, MonadIO m, PersistRecordBackend record backend) => record -> ReaderT backend m () -- | Create multiple records in the database and return their Keys. -- -- If you don't need the inserted Keys, use insertMany_. -- -- The MongoDB and PostgreSQL backends insert all records and retrieve -- their keys in one database query. -- -- The SQLite and MySQL backends use the slow, default implementation of -- mapM insert. -- --
-- insertUsers :: MonadIO m => ReaderT SqlBackend m [Key User] -- insertUsers = insertMany [User "John" 30, User "Nick" 32, User "Jane" 20] ---- --
-- userIds <- insertUsers ---- -- The above query when applied on dataset-1, will produce this: -- --
-- +-----+------+-----+ -- |id |name |age | -- +-----+------+-----+ -- |1 |SPJ |40 | -- +-----+------+-----+ -- |2 |Simon |41 | -- +-----+------+-----+ -- |3 |John |30 | -- +-----+------+-----+ -- |4 |Nick |32 | -- +-----+------+-----+ -- |5 |Jane |20 | -- +-----+------+-----+ --insertMany :: forall record m. (PersistStoreWrite backend, MonadIO m, PersistRecordBackend record backend) => [record] -> ReaderT backend m [Key record] -- | Same as insertMany, but doesn't return any Keys. -- -- The MongoDB, PostgreSQL, SQLite and MySQL backends insert all records -- in one database query. -- --
-- insertUsers_ :: MonadIO m => ReaderT SqlBackend m () -- insertUsers_ = insertMany_ [User "John" 30, User "Nick" 32, User "Jane" 20] ---- -- The above query when applied on dataset-1, will produce this: -- --
-- +-----+------+-----+ -- |id |name |age | -- +-----+------+-----+ -- |1 |SPJ |40 | -- +-----+------+-----+ -- |2 |Simon |41 | -- +-----+------+-----+ -- |3 |John |30 | -- +-----+------+-----+ -- |4 |Nick |32 | -- +-----+------+-----+ -- |5 |Jane |20 | -- +-----+------+-----+ --insertMany_ :: forall record m. (PersistStoreWrite backend, MonadIO m, PersistRecordBackend record backend) => [record] -> ReaderT backend m () -- | Same as insertMany_, but takes an Entity instead of just -- a record. -- -- Useful when migrating data from one entity to another and want to -- preserve ids. -- -- The MongoDB, PostgreSQL, SQLite and MySQL backends insert all records -- in one database query. -- --
-- insertUserEntityMany :: MonadIO m => ReaderT SqlBackend m () -- insertUserEntityMany = insertEntityMany [SnakeEntity, EvaEntity] ---- -- The above query when applied on dataset-1, will produce this: -- --
-- +-----+------+-----+ -- |id |name |age | -- +-----+------+-----+ -- |1 |SPJ |40 | -- +-----+------+-----+ -- |2 |Simon |41 | -- +-----+------+-----+ -- |3 |Snake |38 | -- +-----+------+-----+ -- |4 |Eva |38 | -- +-----+------+-----+ --insertEntityMany :: forall record m. (PersistStoreWrite backend, MonadIO m, PersistRecordBackend record backend) => [Entity record] -> ReaderT backend m () -- | Create a new record in the database using the given key. -- --
-- insertAliceKey :: MonadIO m => Key User -> ReaderT SqlBackend m () -- insertAliceKey key = insertKey key $ User "Alice" 20 ---- --
-- insertAliceKey $ UserKey {unUserKey = SqlBackendKey {unSqlBackendKey = 3}}
--
--
-- The above query when applied on dataset-1, will produce this:
--
-- -- +-----+------+-----+ -- |id |name |age | -- +-----+------+-----+ -- |1 |SPJ |40 | -- +-----+------+-----+ -- |2 |Simon |41 | -- +-----+------+-----+ -- |3 |Alice |20 | -- +-----+------+-----+ --insertKey :: forall record m. (PersistStoreWrite backend, MonadIO m, PersistRecordBackend record backend) => Key record -> record -> ReaderT backend m () -- | Put the record in the database with the given key. Unlike -- replace, if a record with the given key does not exist then a -- new record will be inserted. -- --
-- insertPhilip :: MonadIO m => ReaderT SqlBackend m (Key User) -- insertPhilip = insert $ User "Philip" 42 ---- --
-- philipId <- insertPhilip ---- -- This query will produce: -- --
-- +-----+------+-----+ -- |id |name |age | -- +-----+------+-----+ -- |1 |SPJ |40 | -- +-----+------+-----+ -- |2 |Simon |41 | -- +-----+------+-----+ -- |3 |Philip|42 | -- +-----+------+-----+ ---- --
-- repsertHaskell :: MonadIO m => Key record -> ReaderT SqlBackend m () -- repsertHaskell id = repsert id $ User "Haskell" 81 ---- --
-- repsertHaskell philipId ---- -- This query will replace Philip's record with Haskell's one: -- --
-- +-----+-----------------+--------+ -- |id |name |age | -- +-----+-----------------+--------+ -- |1 |SPJ |40 | -- +-----+-----------------+--------+ -- |2 |Simon |41 | -- +-----+-----------------+--------+ -- |3 |Philip -> Haskell|42 -> 81| -- +-----+-----------------+--------+ ---- -- repsert inserts the given record if the key doesn't exist. -- --
-- repsertXToUnknown :: MonadIO m => ReaderT SqlBackend m () -- repsertXToUnknown = repsert unknownId $ User "X" 999 ---- -- For example, applying the above query to dataset-1 will produce -- this: -- --
-- +-----+------+-----+ -- |id |name |age | -- +-----+------+-----+ -- |1 |SPJ |40 | -- +-----+------+-----+ -- |2 |Simon |41 | -- +-----+------+-----+ -- |3 |X |999 | -- +-----+------+-----+ --repsert :: forall record m. (PersistStoreWrite backend, MonadIO m, PersistRecordBackend record backend) => Key record -> record -> ReaderT backend m () -- | Put many entities into the database. -- -- Batch version of repsert for SQL backends. -- -- Useful when migrating data from one entity to another and want to -- preserve ids. -- --
-- repsertManyUsers :: MonadIO m =>ReaderT SqlBackend m () -- repsertManyusers = repsertMany [(simonId, User "Philip" 20), (unknownId999, User "Mr. X" 999)] ---- -- The above query when applied on dataset-1, will produce this: -- --
-- +-----+----------------+---------+ -- |id |name |age | -- +-----+----------------+---------+ -- |1 |SPJ |40 | -- +-----+----------------+---------+ -- |2 |Simon -> Philip |41 -> 20 | -- +-----+----------------+---------+ -- |999 |Mr. X |999 | -- +-----+----------------+---------+ --repsertMany :: forall record m. (PersistStoreWrite backend, MonadIO m, PersistRecordBackend record backend) => [(Key record, record)] -> ReaderT backend m () -- | Replace the record in the database with the given key. Note that the -- result is undefined if such record does not exist, so you must use -- insertKey or repsert in these cases. -- --
-- replaceSpj :: MonadIO m => User -> ReaderT SqlBackend m () -- replaceSpj record = replace spjId record ---- -- The above query when applied on dataset-1, will produce this: -- --
-- +-----+------+-----+ -- |id |name |age | -- +-----+------+-----+ -- |1 |Mike |45 | -- +-----+------+-----+ -- |2 |Simon |41 | -- +-----+------+-----+ --replace :: forall record m. (PersistStoreWrite backend, MonadIO m, PersistRecordBackend record backend) => Key record -> record -> ReaderT backend m () -- | Delete a specific record by identifier. Does nothing if record does -- not exist. -- --
-- deleteSpj :: MonadIO m => ReaderT SqlBackend m () -- deleteSpj = delete spjId ---- -- The above query when applied on dataset-1, will produce this: -- --
-- +-----+------+-----+ -- |id |name |age | -- +-----+------+-----+ -- |2 |Simon |41 | -- +-----+------+-----+ --delete :: forall record m. (PersistStoreWrite backend, MonadIO m, PersistRecordBackend record backend) => Key record -> ReaderT backend m () -- | Update individual fields on a specific record. -- --
-- updateSpj :: MonadIO m => [Update User] -> ReaderT SqlBackend m () -- updateSpj updates = update spjId updates ---- --
-- updateSpj [UserAge +=. 100] ---- -- The above query when applied on dataset-1, will produce this: -- --
-- +-----+------+-----+ -- |id |name |age | -- +-----+------+-----+ -- |1 |SPJ |140 | -- +-----+------+-----+ -- |2 |Simon |41 | -- +-----+------+-----+ --update :: forall record m. (PersistStoreWrite backend, MonadIO m, PersistRecordBackend record backend) => Key record -> [Update record] -> ReaderT backend m () -- | Update individual fields on a specific record, and retrieve the -- updated value from the database. -- -- Note that this function will throw an exception if the given key is -- not found in the database. -- --
-- updateGetSpj :: MonadIO m => [Update User] -> ReaderT SqlBackend m User -- updateGetSpj updates = updateGet spjId updates ---- --
-- spj <- updateGetSpj [UserAge +=. 100] ---- -- The above query when applied on dataset-1, will produce this: -- --
-- +-----+------+-----+ -- |id |name |age | -- +-----+------+-----+ -- |1 |SPJ |140 | -- +-----+------+-----+ -- |2 |Simon |41 | -- +-----+------+-----+ --updateGet :: forall record m. (PersistStoreWrite backend, MonadIO m, PersistRecordBackend record backend) => Key record -> [Update record] -> ReaderT backend m record -- | A convenient alias for common type signatures type PersistRecordBackend record backend = (PersistEntity record, PersistEntityBackend record ~ BaseBackend backend) -- | Same as get, but for a non-null (not Maybe) foreign key. Unsafe -- unless your database is enforcing that the foreign key is valid. -- --
-- getJustSpj :: MonadIO m => ReaderT SqlBackend m User -- getJustSpj = getJust spjId ---- --
-- spj <- getJust spjId ---- -- The above query when applied on dataset-1, will get this -- record: -- --
-- +----+------+-----+ -- | id | name | age | -- +----+------+-----+ -- | 1 | SPJ | 40 | -- +----+------+-----+ ---- --
-- getJustUnknown :: MonadIO m => ReaderT SqlBackend m User -- getJustUnknown = getJust unknownId ---- -- mrx <- getJustUnknown -- -- This just throws an error. getJust :: forall record backend m. (PersistStoreRead backend, PersistRecordBackend record backend, MonadIO m) => Key record -> ReaderT backend m record -- | Same as getJust, but returns an Entity instead of just -- the record. -- --
-- getJustEntitySpj :: MonadIO m => ReaderT SqlBackend m (Entity User) -- getJustEntitySpj = getJustEntity spjId ---- --
-- spjEnt <- getJustEntitySpj ---- -- The above query when applied on dataset-1, will get this -- entity: -- --
-- +----+------+-----+ -- | id | name | age | -- +----+------+-----+ -- | 1 | SPJ | 40 | -- +----+------+-----+ --getJustEntity :: forall record backend m. (PersistEntityBackend record ~ BaseBackend backend, MonadIO m, PersistEntity record, PersistStoreRead backend) => Key record -> ReaderT backend m (Entity record) -- | Like get, but returns the complete Entity. -- --
-- getSpjEntity :: MonadIO m => ReaderT SqlBackend m (Maybe (Entity User)) -- getSpjEntity = getEntity spjId ---- --
-- mSpjEnt <- getSpjEntity ---- -- The above query when applied on dataset-1, will get this -- entity: -- --
-- +----+------+-----+ -- | id | name | age | -- +----+------+-----+ -- | 1 | SPJ | 40 | -- +----+------+-----+ --getEntity :: forall e backend m. (PersistStoreRead backend, PersistRecordBackend e backend, MonadIO m) => Key e -> ReaderT backend m (Maybe (Entity e)) -- | Curry this to make a convenience function that loads an associated -- model. -- --
-- foreign = belongsTo foreignId --belongsTo :: forall ent1 ent2 backend m. (PersistStoreRead backend, PersistEntity ent1, PersistRecordBackend ent2 backend, MonadIO m) => (ent1 -> Maybe (Key ent2)) -> ent1 -> ReaderT backend m (Maybe ent2) -- | Same as belongsTo, but uses getJust and therefore is -- similarly unsafe. belongsToJust :: forall ent1 ent2 backend m. (PersistStoreRead backend, PersistEntity ent1, PersistRecordBackend ent2 backend, MonadIO m) => (ent1 -> Key ent2) -> ent1 -> ReaderT backend m ent2 -- | Like insert, but returns the complete Entity. -- --
-- insertHaskellEntity :: MonadIO m => ReaderT SqlBackend m (Entity User) -- insertHaskellEntity = insertEntity $ User "Haskell" 81 ---- --
-- haskellEnt <- insertHaskellEntity ---- -- The above query when applied on dataset-1, will produce this: -- --
-- +----+---------+-----+ -- | id | name | age | -- +----+---------+-----+ -- | 1 | SPJ | 40 | -- +----+---------+-----+ -- | 2 | Simon | 41 | -- +----+---------+-----+ -- | 3 | Haskell | 81 | -- +----+---------+-----+ --insertEntity :: forall e backend m. (PersistStoreWrite backend, PersistRecordBackend e backend, MonadIO m) => e -> ReaderT backend m (Entity e) -- | Like insertEntity but just returns the record instead of -- Entity. -- --
-- insertDaveRecord :: MonadIO m => ReaderT SqlBackend m User -- insertDaveRecord = insertRecord $ User "Dave" 50 ---- --
-- dave <- insertDaveRecord ---- -- The above query when applied on dataset-1, will produce this: -- --
-- +-----+------+-----+ -- |id |name |age | -- +-----+------+-----+ -- |1 |SPJ |40 | -- +-----+------+-----+ -- |2 |Simon |41 | -- +-----+------+-----+ -- |3 |Dave |50 | -- +-----+------+-----+ --insertRecord :: forall record backend m. (PersistEntityBackend record ~ BaseBackend backend, PersistEntity record, MonadIO m, PersistStoreWrite backend) => record -> ReaderT backend m record -- | A backwards-compatible alias for those that don't care about -- distinguishing between read and write queries. It signifies the -- assumption that, by default, a backend can write as well as read. type PersistUnique a = PersistUniqueWrite a -- | Queries against Unique keys (other than the id Key). -- -- Please read the general Persistent documentation to learn how to -- create Unique keys. -- -- Using this with an Entity without a Unique key leads to undefined -- behavior. A few of these functions require a single -- Unique, so using an Entity with multiple Uniques is also -- undefined. In these cases persistent's goal is to throw an exception -- as soon as possible, but persistent is still transitioning to that. -- -- SQL backends automatically create uniqueness constraints, but for -- MongoDB you must manually place a unique index on a field to have a -- uniqueness constraint. class (PersistCore backend, PersistStoreRead backend) => PersistUniqueRead backend -- | Get a record by unique key, if available. Returns also the identifier. -- --
-- getBySpjName :: MonadIO m => ReaderT SqlBackend m (Maybe (Entity User)) -- getBySpjName = getBy $ UniqueUserName "SPJ" ---- --
-- mSpjEnt <- getBySpjName ---- -- The above query when applied on dataset-1, will get this -- entity: -- --
-- +----+------+-----+ -- | id | name | age | -- +----+------+-----+ -- | 1 | SPJ | 40 | -- +----+------+-----+ --getBy :: forall record m. (PersistUniqueRead backend, MonadIO m, PersistRecordBackend record backend) => Unique record -> ReaderT backend m (Maybe (Entity record)) -- | Some functions in this module (insertUnique, insertBy, -- and replaceUnique) first query the unique indexes to check for -- conflicts. You could instead optimistically attempt to perform the -- operation (e.g. replace instead of replaceUnique). -- However, -- --
-- deleteBySpjName :: MonadIO m => ReaderT SqlBackend m () -- deleteBySpjName = deleteBy UniqueUserName "SPJ" ---- -- The above query when applied on dataset-1, will produce this: -- --
-- +-----+------+-----+ -- |id |name |age | -- +-----+------+-----+ -- |2 |Simon |41 | -- +-----+------+-----+ --deleteBy :: forall record m. (PersistUniqueWrite backend, MonadIO m, PersistRecordBackend record backend) => Unique record -> ReaderT backend m () -- | Like insert, but returns Nothing when the record -- couldn't be inserted because of a uniqueness constraint. -- --
-- linusId <- insertUnique $ User "Linus" 48 -- spjId <- insertUnique $ User "SPJ" 90 ---- --
-- +-----+------+-----+ -- |id |name |age | -- +-----+------+-----+ -- |1 |SPJ |40 | -- +-----+------+-----+ -- |2 |Simon |41 | -- +-----+------+-----+ -- |3 |Linus |48 | -- +-----+------+-----+ ---- -- Linus's record was inserted to dataset-1, while SPJ wasn't -- because SPJ already exists in dataset-1. insertUnique :: forall record m. (PersistUniqueWrite backend, MonadIO m, PersistRecordBackend record backend) => record -> ReaderT backend m (Maybe (Key record)) -- | Update based on a uniqueness constraint or insert: -- --
-- upsertSpj :: MonadIO m => [Update User] -> ReaderT SqlBackend m (Maybe (Entity User)) -- upsertSpj updates = upsert (User "SPJ" 999) upadtes ---- --
-- mSpjEnt <- upsertSpj [UserAge +=. 15] ---- -- The above query when applied on dataset-1, will produce this: -- --
-- +-----+-----+--------+ -- |id |name |age | -- +-----+-----+--------+ -- |1 |SPJ |40 -> 55| -- +-----+-----+--------+ -- |2 |Simon|41 | -- +-----+-----+--------+ ---- --
-- upsertX :: MonadIO m => [Update User] -> ReaderT SqlBackend m (Maybe (Entity User)) -- upsertX updates = upsert (User "X" 999) updates ---- --
-- mXEnt <- upsertX [UserAge +=. 15] ---- -- The above query when applied on dataset-1, will produce this: -- --
-- +-----+-----+--------+ -- |id |name |age | -- +-----+-----+--------+ -- |1 |SPJ |40 | -- +-----+-----+--------+ -- |2 |Simon|41 | -- +-----+-----+--------+ -- |3 |X |999 | -- +-----+-----+--------+ ---- -- Next, what if the schema has two uniqueness constraints? Let's check -- it out using schema-2: -- --
-- mSpjEnt <- upsertSpj [UserAge +=. 15] ---- -- This fails with a compile-time type error alerting us to the fact that -- this record has multiple unique keys, and suggests that we look for -- upsertBy to select the unique key we want. upsert :: forall record m. (PersistUniqueWrite backend, MonadIO m, PersistRecordBackend record backend, OnlyOneUniqueKey record) => record -> [Update record] -> ReaderT backend m (Entity record) -- | Update based on a given uniqueness constraint or insert: -- --
-- upsertBySpjName :: MonadIO m => User -> [Update User] -> ReaderT SqlBackend m (Entity User) -- upsertBySpjName record updates = upsertBy (UniqueUserName "SPJ") record updates ---- --
-- mSpjEnt <- upsertBySpjName (Person "X" 999) [PersonAge += .15] ---- -- The above query will alter dataset-1 to: -- --
-- +-----+-----+--------+ -- |id |name |age | -- +-----+-----+--------+ -- |1 |SPJ |40 -> 55| -- +-----+-----+--------+ -- |2 |Simon|41 | -- +-----+-----+--------+ ---- --
-- upsertBySimonAge :: MonadIO m => User -> [Update User] -> ReaderT SqlBackend m (Entity User) -- upsertBySimonAge record updates = upsertBy (UniqueUserName "SPJ") record updates ---- --
-- mPhilipEnt <- upsertBySimonAge (User "X" 999) [UserName =. "Philip"] ---- -- The above query will alter dataset-1 to: -- --
-- +----+-----------------+-----+ -- | id | name | age | -- +----+-----------------+-----+ -- | 1 | SPJ | 40 | -- +----+-----------------+-----+ -- | 2 | Simon -> Philip | 41 | -- +----+-----------------+-----+ ---- --
-- upsertByUnknownName :: MonadIO m => User -> [Update User] -> ReaderT SqlBackend m (Entity User) -- upsertByUnknownName record updates = upsertBy (UniqueUserName "Unknown") record updates ---- --
-- mXEnt <- upsertByUnknownName (User "X" 999) [UserAge +=. 15] ---- -- This query will alter dataset-1 to: -- --
-- +-----+-----+-----+ -- |id |name |age | -- +-----+-----+-----+ -- |1 |SPJ |40 | -- +-----+-----+-----+ -- |2 |Simon|41 | -- +-----+-----+-----+ -- |3 |X |999 | -- +-----+-----+-----+ --upsertBy :: forall record m. (PersistUniqueWrite backend, MonadIO m, PersistRecordBackend record backend) => Unique record -> record -> [Update record] -> ReaderT backend m (Entity record) -- | Put many records into db -- --
-- mSpjEnt <- getBySpjValue ---- -- The above query when applied on dataset-1, will get this -- record: -- --
-- +----+------+-----+ -- | id | name | age | -- +----+------+-----+ -- | 1 | SPJ | 40 | -- +----+------+-----+ --getByValue :: forall record m backend. (MonadIO m, PersistUniqueRead backend, PersistRecordBackend record backend, AtLeastOneUniqueKey record) => record -> ReaderT backend m (Maybe (Entity record)) -- | Insert a value, checking for conflicts with any unique constraints. If -- a duplicate exists in the database, it is returned as Left. -- Otherwise, the new 'Key is returned as Right. -- --
-- l1 <- insertBy $ User "SPJ" 20 -- l2 <- insertBy $ User "XXX" 41 -- l3 <- insertBy $ User "SPJ" 40 -- r1 <- insertBy $ User "XXX" 100 ---- -- First three lines return Left because there're duplicates in -- given record's uniqueness constraints. While the last line returns a -- new key as Right. insertBy :: forall record backend m. (MonadIO m, PersistUniqueWrite backend, PersistRecordBackend record backend, AtLeastOneUniqueKey record) => record -> ReaderT backend m (Either (Entity record) (Key record)) -- | Like insertEntity, but returns Nothing when the record -- couldn't be inserted because of a uniqueness constraint. -- --
-- insertUniqueSpjEntity :: MonadIO m => ReaderT SqlBackend m (Maybe (Entity User)) -- insertUniqueSpjEntity = insertUniqueEntity $ User "SPJ" 50 ---- --
-- mSpjEnt <- insertUniqueSpjEntity ---- -- The above query results Nothing as SPJ already exists. -- --
-- insertUniqueAlexaEntity :: MonadIO m => ReaderT SqlBackend m (Maybe (Entity User)) -- insertUniqueAlexaEntity = insertUniqueEntity $ User "Alexa" 3 ---- --
-- mAlexaEnt <- insertUniqueSpjEntity ---- -- Because there's no such unique keywords of the given record, the above -- query when applied on dataset-1, will produce this: -- --
-- +----+-------+-----+ -- | id | name | age | -- +----+-------+-----+ -- | 1 | SPJ | 40 | -- +----+-------+-----+ -- | 2 | Simon | 41 | -- +----+-------+-----+ -- | 3 | Alexa | 3 | -- +----+-------+-----+ --insertUniqueEntity :: forall record backend m. (MonadIO m, PersistRecordBackend record backend, PersistUniqueWrite backend) => record -> ReaderT backend m (Maybe (Entity record)) -- | Attempt to replace the record of the given key with the given new -- record. First query the unique fields to make sure the replacement -- maintains uniqueness constraints. -- -- Return Nothing if the replacement was made. If uniqueness is -- violated, return a Just with the Unique violation replaceUnique :: forall record backend m. (MonadIO m, Eq (Unique record), PersistRecordBackend record backend, PersistUniqueWrite backend) => Key record -> record -> ReaderT backend m (Maybe (Unique record)) -- | Check whether there are any conflicts for unique keys with this entity -- and existing entities in the database. -- -- Returns Nothing if the entity would be unique, and could thus -- safely be inserted. on a conflict returns the conflicting key -- --
-- mAlanConst <- checkUnique $ User "Alan" 70 ---- -- While this would be Just because SPJ already exists: -- --
-- mSpjConst <- checkUnique $ User "SPJ" 60 --checkUnique :: forall record backend m. (MonadIO m, PersistRecordBackend record backend, PersistUniqueRead backend) => record -> ReaderT backend m (Maybe (Unique record)) -- | Check whether there are any conflicts for unique keys with this entity -- and existing entities in the database. -- -- Returns Nothing if the entity would stay unique, and could thus -- safely be updated. on a conflict returns the conflicting key -- -- This is similar to checkUnique, except it's useful for updating -- - when the particular entity already exists, it would normally -- conflict with itself. This variant ignores those conflicts -- --
-- mAlanConst <- checkUnique $ User "Alan" 70 ---- -- While this would be Just because SPJ already exists: -- --
-- mSpjConst <- checkUnique $ User "SPJ" 60 --checkUniqueUpdateable :: forall record backend m. (MonadIO m, PersistRecordBackend record backend, PersistUniqueRead backend) => Entity record -> ReaderT backend m (Maybe (Unique record)) -- | Return the single unique key for a record. -- --
-- onlySimonConst :: MonadIO m => ReaderT SqlBackend m (Unique User) -- onlySimonConst = onlyUnique $ User "Simon" 999 ---- --
-- mSimonConst <- onlySimonConst ---- -- mSimonConst would be Simon's uniqueness constraint. Note that -- onlyUnique doesn't work if there're more than two -- constraints. It will fail with a type error instead. onlyUnique :: forall record backend m. (MonadIO m, PersistUniqueWrite backend, PersistRecordBackend record backend, OnlyOneUniqueKey record) => record -> ReaderT backend m (Unique record) -- | A backwards-compatible alias for those that don't care about -- distinguishing between read and write queries. It signifies the -- assumption that, by default, a backend can write as well as read. type PersistQuery a = PersistQueryWrite a -- | Backends supporting conditional read operations. class (PersistCore backend, PersistStoreRead backend) => PersistQueryRead backend -- | Get all records matching the given criterion in the specified order. -- Returns also the identifiers. selectSourceRes :: (PersistQueryRead backend, PersistRecordBackend record backend, MonadIO m1, MonadIO m2) => [Filter record] -> [SelectOpt record] -> ReaderT backend m1 (Acquire (ConduitM () (Entity record) m2 ())) -- | Get just the first record for the criterion. selectFirst :: (PersistQueryRead backend, MonadIO m, PersistRecordBackend record backend) => [Filter record] -> [SelectOpt record] -> ReaderT backend m (Maybe (Entity record)) -- | Get the Keys of all records matching the given criterion. selectKeysRes :: (PersistQueryRead backend, MonadIO m1, MonadIO m2, PersistRecordBackend record backend) => [Filter record] -> [SelectOpt record] -> ReaderT backend m1 (Acquire (ConduitM () (Key record) m2 ())) -- | The total number of records fulfilling the given criterion. count :: (PersistQueryRead backend, MonadIO m, PersistRecordBackend record backend) => [Filter record] -> ReaderT backend m Int -- | Check if there is at least one record fulfilling the given criterion. exists :: (PersistQueryRead backend, MonadIO m, PersistRecordBackend record backend) => [Filter record] -> ReaderT backend m Bool -- | Backends supporting conditional write operations class (PersistQueryRead backend, PersistStoreWrite backend) => PersistQueryWrite backend -- | Update individual fields on any record matching the given criterion. updateWhere :: (PersistQueryWrite backend, MonadIO m, PersistRecordBackend record backend) => [Filter record] -> [Update record] -> ReaderT backend m () -- | Delete all records matching the given criterion. deleteWhere :: (PersistQueryWrite backend, MonadIO m, PersistRecordBackend record backend) => [Filter record] -> ReaderT backend m () -- | Get all records matching the given criterion in the specified order. -- Returns also the identifiers. selectSource :: forall record backend m. (PersistQueryRead backend, MonadResource m, PersistRecordBackend record backend, MonadReader backend m) => [Filter record] -> [SelectOpt record] -> ConduitM () (Entity record) m () -- | Get the Keys of all records matching the given criterion. selectKeys :: forall record backend m. (PersistQueryRead backend, MonadResource m, PersistRecordBackend record backend, MonadReader backend m) => [Filter record] -> [SelectOpt record] -> ConduitM () (Key record) m () -- | 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] -- | Call selectKeys but return the result as a list. selectKeysList :: forall record backend m. (MonadIO m, PersistQueryRead backend, PersistRecordBackend record backend) => [Filter record] -> [SelectOpt record] -> ReaderT backend m [Key record] -- | For combinations of backends and entities that support -- cascade-deletion. “Cascade-deletion” means that entries that depend on -- other entries to be deleted will be deleted as well. class (PersistStoreWrite backend, PersistEntity record, BaseBackend backend ~ PersistEntityBackend record) => DeleteCascade record backend -- | Perform cascade-deletion of single database entry. deleteCascade :: (DeleteCascade record backend, MonadIO m) => Key record -> ReaderT backend m () -- | Cascade-deletion of entries satisfying given filters. deleteCascadeWhere :: forall record backend m. (MonadIO m, DeleteCascade record backend, PersistQueryWrite backend) => [Filter record] -> ReaderT backend m () -- | Persistent serialized Haskell records to the database. A Database -- Entity (A row in SQL, a document in MongoDB, etc) corresponds -- to a Key plus a Haskell record. -- -- For every Haskell record type stored in the database there is a -- corresponding PersistEntity instance. An instance of -- PersistEntity contains meta-data for the record. PersistEntity also -- helps abstract over different record types. That way the same query -- interface can return a PersistEntity, with each query returning -- different types of Haskell records. -- -- Some advanced type system capabilities are used to make this process -- type-safe. Persistent users usually don't need to understand the class -- associated data and functions. class (PersistField (Key record), ToJSON (Key record), FromJSON (Key record), Show (Key record), Read (Key record), Eq (Key record), Ord (Key record)) => PersistEntity record where { -- | Persistent allows multiple different backends (databases). type family PersistEntityBackend record; -- | By default, a backend will automatically generate the key Instead you -- can specify a Primary key made up of unique values. data family Key record; -- | An EntityField is parameterised by the Haskell record it -- belongs to and the additional type of that field. -- -- As of persistent-2.11.0.0, it's possible to use the -- OverloadedLabels language extension to refer to -- EntityField values polymorphically. See the documentation on -- SymbolToField for more information. data family EntityField record :: * -> *; -- | Unique keys besides the Key. data family Unique record; } -- | A lower-level key operation. keyToValues :: PersistEntity record => Key record -> [PersistValue] -- | A lower-level key operation. keyFromValues :: PersistEntity record => [PersistValue] -> Either Text (Key record) -- | A meta-operation to retrieve the Key EntityField. persistIdField :: PersistEntity record => EntityField record (Key record) -- | Retrieve the EntityDef meta-data for the record. entityDef :: PersistEntity record => proxy record -> EntityDef -- | Return meta-data for a given EntityField. persistFieldDef :: PersistEntity record => EntityField record typ -> FieldDef -- | A meta-operation to get the database fields of a record. toPersistFields :: PersistEntity record => record -> [SomePersistField] -- | A lower-level operation to convert from database values to a Haskell -- record. fromPersistValues :: PersistEntity record => [PersistValue] -> Either Text record -- | A meta operation to retrieve all the Unique keys. persistUniqueKeys :: PersistEntity record => record -> [Unique record] -- | A lower level operation. persistUniqueToFieldNames :: PersistEntity record => Unique record -> [(FieldNameHS, FieldNameDB)] -- | A lower level operation. persistUniqueToValues :: PersistEntity record => Unique record -> [PersistValue] -- | Use a PersistField as a lens. fieldLens :: PersistEntity record => EntityField record field -> forall f. Functor f => (field -> f field) -> Entity record -> f (Entity record) -- | Extract a Key record from a record value. -- Currently, this is only defined for entities using the -- Primary syntax for natural/composite keys. In a future -- version of persistent which incorporates the ID directly into -- the entity, this will always be Just. keyFromRecordM :: PersistEntity record => Maybe (record -> Key record) -- | This type class is used with the OverloadedLabels extension -- to provide a more convenient means of using the EntityField -- type. EntityField definitions are prefixed with the type name -- to avoid ambiguity, but this ambiguity can result in verbose code. -- -- If you have a table User with a name Text field, -- then the corresponding EntityField is UserName. With -- this, we can write #name :: EntityField User Text. -- -- What's more fun is that the type is more general: it's actually -- #name :: (SymbolToField "name" rec typ) => EntityField rec -- typ -- -- Which means it is *polymorphic* over the actual record. This allows -- you to write code that can be generic over the tables, provided they -- have the right fields. class SymbolToField (sym :: Symbol) rec typ | sym rec -> typ symbolToField :: SymbolToField sym rec typ => EntityField rec typ -- | This class teaches Persistent how to take a custom type and marshal it -- to and from a PersistValue, allowing it to be stored in a -- database. -- --
-- {-# LANGUAGE GeneralizedNewtypeDeriving #-}
--
-- newtype HashedPassword = HashedPassword ByteString
-- deriving (Eq, Show, PersistField, PersistFieldSql)
--
--
--
-- {-# LANGUAGE GeneralizedNewtypeDeriving #-}
-- import qualified Data.Text as T
-- import qualified Data.Char as C
--
-- -- | An American Social Security Number
-- newtype SSN = SSN Text
-- deriving (Eq, Show, PersistFieldSql)
--
-- mkSSN :: Text -> Either Text SSN
-- mkSSN t = if (T.length t == 9) && (T.all C.isDigit t)
-- then Right $ SSN t
-- else Left $ "Invalid SSN: " <> t
--
-- instance PersistField SSN where
-- toPersistValue (SSN t) = PersistText t
-- fromPersistValue (PersistText t) = mkSSN t
-- -- Handle cases where the database does not give us PersistText
-- fromPersistValue x = Left $ "File.hs: When trying to deserialize an SSN: expected PersistText, received: " <> T.pack (show x)
--
--
-- Tips:
--
-- -- foo :: -- ( PersistEntity record -- , PeristEntityBackend record ~ BaseBackend backend -- , IsSqlBackend backend -- ) ---- -- this can be replaced with: -- --
-- foo :: -- ( PersistEntity record, -- , PersistEntityBackend record ~ backend -- , BackendCompatible SqlBackend backend -- ) ---- -- This works for SqlReadBackend because of the instance -- BackendCompatible SqlBackend -- SqlReadBackend, without needing to go through the -- BaseBackend type family. -- -- Likewise, functions that are currently hardcoded to use -- SqlBackend can be generalized: -- --
-- -- before: -- asdf :: ReaderT SqlBackend m () -- asdf = pure () -- -- -- after: -- asdf' :: BackendCompatible SqlBackend backend => ReaderT backend m () -- asdf' = withCompatibleBackend asdf --class BackendCompatible sup sub projectBackend :: BackendCompatible sup sub => sub -> sup -- | Run a query against a compatible backend, by projecting the backend -- -- This is a helper for using queries which run against a specific -- backend type that your backend is compatible with. withCompatibleBackend :: BackendCompatible sup sub => ReaderT sup m a -> ReaderT sub m a -- | Predefined toJSON. The resulting JSON looks like {"key": -- 1, "value": {"name": ...}}. -- -- The typical usage is: -- --
-- instance ToJSON (Entity User) where -- toJSON = keyValueEntityToJSON --keyValueEntityToJSON :: (PersistEntity record, ToJSON record) => Entity record -> Value -- | Predefined parseJSON. The input JSON looks like {"key": -- 1, "value": {"name": ...}}. -- -- The typical usage is: -- --
-- instance FromJSON (Entity User) where -- parseJSON = keyValueEntityFromJSON --keyValueEntityFromJSON :: (PersistEntity record, FromJSON record) => Value -> Parser (Entity record) -- | Predefined toJSON. The resulting JSON looks like {"id": -- 1, "name": ...}. -- -- The typical usage is: -- --
-- instance ToJSON (Entity User) where -- toJSON = entityIdToJSON --entityIdToJSON :: (PersistEntity record, ToJSON record) => Entity record -> Value -- | Predefined parseJSON. The input JSON looks like {"id": 1, -- "name": ...}. -- -- The typical usage is: -- --
-- instance FromJSON (Entity User) where -- parseJSON = entityIdFromJSON --entityIdFromJSON :: (PersistEntity record, FromJSON record) => Value -> Parser (Entity record) -- | Convenience function for getting a free PersistField instance -- from a type with JSON instances. -- -- Example usage in combination with fromPersistValueJSON: -- --
-- instance PersistField MyData where -- fromPersistValue = fromPersistValueJSON -- toPersistValue = toPersistValueJSON --toPersistValueJSON :: ToJSON a => a -> PersistValue -- | Convenience function for getting a free PersistField instance -- from a type with JSON instances. The JSON parser used will accept JSON -- values other that object and arrays. So, if your instance serializes -- the data to a JSON string, this will still work. -- -- Example usage in combination with toPersistValueJSON: -- --
-- instance PersistField MyData where -- fromPersistValue = fromPersistValueJSON -- toPersistValue = toPersistValueJSON --fromPersistValueJSON :: FromJSON a => PersistValue -> Either Text a module Database.Persist.Sql.Types.Internal -- | Class which allows the plucking of a BaseBackend backend from -- some larger type. For example, instance HasPersistBackend -- (SqlReadBackend, Int) where type BaseBackend (SqlReadBackend, Int) = -- SqlBackend persistBackend = unSqlReadBackend . fst class HasPersistBackend backend where { type family BaseBackend backend; } persistBackend :: HasPersistBackend backend => backend -> BaseBackend backend -- | Class which witnesses that backend is essentially the same as -- BaseBackend backend. That is, they're isomorphic and -- backend is just some wrapper over BaseBackend -- backend. class (HasPersistBackend backend) => IsPersistBackend backend -- | This function is how we actually construct and tag a backend as having -- read or write capabilities. It should be used carefully and only when -- actually constructing a backend. Careless use allows us to -- accidentally run a write query against a read-only database. mkPersistBackend :: IsPersistBackend backend => BaseBackend backend -> backend -- | An SQL backend which can only handle read queries -- -- The constructor was exposed in 2.10.0. newtype SqlReadBackend SqlReadBackend :: SqlBackend -> SqlReadBackend [unSqlReadBackend] :: SqlReadBackend -> SqlBackend -- | An SQL backend which can handle read or write queries -- -- The constructor was exposed in 2.10.0 newtype SqlWriteBackend SqlWriteBackend :: SqlBackend -> SqlWriteBackend [unSqlWriteBackend] :: SqlWriteBackend -> SqlBackend -- | Useful for running a read query against a backend with unknown -- capabilities. readToUnknown :: Monad m => ReaderT SqlReadBackend m a -> ReaderT SqlBackend m a -- | Useful for running a read query against a backend with read and write -- capabilities. readToWrite :: Monad m => ReaderT SqlReadBackend m a -> ReaderT SqlWriteBackend m a -- | Useful for running a write query against an untagged backend with -- unknown capabilities. writeToUnknown :: Monad m => ReaderT SqlWriteBackend m a -> ReaderT SqlBackend m a type LogFunc = Loc -> LogSource -> LogLevel -> LogStr -> IO () data InsertSqlResult ISRSingle :: Text -> InsertSqlResult ISRInsertGet :: Text -> Text -> InsertSqlResult ISRManyKeys :: Text -> [PersistValue] -> InsertSqlResult data Statement Statement :: IO () -> IO () -> ([PersistValue] -> IO Int64) -> (forall m. MonadIO m => [PersistValue] -> Acquire (ConduitM () [PersistValue] m ())) -> Statement [stmtFinalize] :: Statement -> IO () [stmtReset] :: Statement -> IO () [stmtExecute] :: Statement -> [PersistValue] -> IO Int64 [stmtQuery] :: Statement -> forall m. MonadIO m => [PersistValue] -> Acquire (ConduitM () [PersistValue] m ()) -- | Please refer to the documentation for the database in question for a -- full overview of the semantics of the varying isloation levels data IsolationLevel ReadUncommitted :: IsolationLevel ReadCommitted :: IsolationLevel RepeatableRead :: IsolationLevel Serializable :: IsolationLevel makeIsolationLevelStatement :: (Monoid s, IsString s) => IsolationLevel -> s -- | A SqlBackend represents a handle or connection to a database. -- It contains functions and values that allow databases to have more -- optimized implementations, as well as references that benefit -- performance and sharing. -- -- A SqlBackend is *not* thread-safe. You should not assume that a -- SqlBackend can be shared among threads and run concurrent -- queries. This *will* result in problems. Instead, you should create a -- Pool SqlBackend, known as a -- ConnectionPool, and pass that around in multi-threaded -- applications. -- -- To run actions in the persistent library, you should use the -- runSqlConn function. If you're using a multithreaded -- application, use the runSqlPool function. data SqlBackend SqlBackend :: (Text -> IO Statement) -> (EntityDef -> [PersistValue] -> InsertSqlResult) -> Maybe (EntityDef -> [[PersistValue]] -> InsertSqlResult) -> Maybe (EntityDef -> NonEmpty (FieldNameHS, FieldNameDB) -> Text -> Text) -> Maybe (EntityDef -> Int -> Text) -> IORef (Map Text Statement) -> IO () -> ([EntityDef] -> (Text -> IO Statement) -> EntityDef -> IO (Either [Text] [(Bool, Text)])) -> ((Text -> IO Statement) -> Maybe IsolationLevel -> IO ()) -> ((Text -> IO Statement) -> IO ()) -> ((Text -> IO Statement) -> IO ()) -> (FieldNameDB -> Text) -> (EntityDef -> Text) -> (Text -> Text) -> Text -> Text -> ((Int, Int) -> Bool -> Text -> Text) -> LogFunc -> Maybe Int -> Maybe (EntityDef -> Int -> Text) -> SqlBackend -- | This function should prepare a Statement in the target -- database, which should allow for efficient query reuse. [connPrepare] :: SqlBackend -> Text -> IO Statement -- | This function generates the SQL and values necessary for performing an -- insert against the database. [connInsertSql] :: SqlBackend -> EntityDef -> [PersistValue] -> InsertSqlResult -- | SQL for inserting many rows and returning their primary keys, for -- backends that support this functionality. If Nothing, rows will -- be inserted one-at-a-time using connInsertSql. [connInsertManySql] :: SqlBackend -> Maybe (EntityDef -> [[PersistValue]] -> InsertSqlResult) -- | Some databases support performing UPSERT _and_ RETURN entity in a -- single call. -- -- This field when set will be used to generate the UPSERT+RETURN sql -- given * an entity definition * updates to be run on unique key(s) -- collision -- -- When left as Nothing, we find the unique key from entity def -- before * trying to fetch an entity by said key * perform an update -- when result found, else issue an insert * return new entity from db [connUpsertSql] :: SqlBackend -> Maybe (EntityDef -> NonEmpty (FieldNameHS, FieldNameDB) -> Text -> Text) -- | Some databases support performing bulk UPSERT, specifically "insert or -- replace many records" in a single call. -- -- This field when set, given * an entity definition * number of records -- to be inserted should produce a PUT MANY sql with placeholders for -- records -- -- When left as Nothing, we default to using -- defaultPutMany. [connPutManySql] :: SqlBackend -> Maybe (EntityDef -> Int -> Text) -- | A reference to the cache of statements. Statements are keyed by -- the Text queries that generated them. [connStmtMap] :: SqlBackend -> IORef (Map Text Statement) -- | Close the underlying connection. [connClose] :: SqlBackend -> IO () -- | This function returns the migrations required to include the -- EntityDef parameter in the [EntityDef] -- database. This might include creating a new table if the entity is not -- present, or altering an existing table if it is. [connMigrateSql] :: SqlBackend -> [EntityDef] -> (Text -> IO Statement) -> EntityDef -> IO (Either [Text] [(Bool, Text)]) -- | A function to begin a transaction for the underlying database. [connBegin] :: SqlBackend -> (Text -> IO Statement) -> Maybe IsolationLevel -> IO () -- | A function to commit a transaction to the underlying database. [connCommit] :: SqlBackend -> (Text -> IO Statement) -> IO () -- | A function to roll back a transaction on the underlying database. [connRollback] :: SqlBackend -> (Text -> IO Statement) -> IO () -- | A function to extract and escape the name of the column corresponding -- to the provided field. [connEscapeFieldName] :: SqlBackend -> FieldNameDB -> Text -- | A function to extract and escape the name of the table corresponding -- to the provided entity. PostgreSQL uses this to support schemas. [connEscapeTableName] :: SqlBackend -> EntityDef -> Text -- | A function to escape raw DB identifiers. MySQL uses backticks, while -- PostgreSQL uses quotes, and so on. [connEscapeRawName] :: SqlBackend -> Text -> Text [connNoLimit] :: SqlBackend -> Text -- | A tag displaying what database the SqlBackend is for. Can be -- used to differentiate features in downstream libraries for different -- database backends. [connRDBMS] :: SqlBackend -> Text -- | Attach a 'LIMIT/OFFSET' clause to a SQL query. Note that LIMIT/OFFSET -- is problematic for performance, and indexed range queries are the -- superior way to offer pagination. [connLimitOffset] :: SqlBackend -> (Int, Int) -> Bool -> Text -> Text -- | A log function for the SqlBackend to use. [connLogFunc] :: SqlBackend -> LogFunc -- | Some databases (probably only Sqlite) have a limit on how many -- question-mark parameters may be used in a statement [connMaxParams] :: SqlBackend -> Maybe Int -- | Some databases support performing bulk an atomic+bulk INSERT where -- constraint conflicting entities can replace existing entities. -- -- This field when set, given * an entity definition * number of records -- to be inserted should produce a INSERT sql with placeholders for -- primary+record fields -- -- When left as Nothing, we default to using -- defaultRepsertMany. [connRepsertManySql] :: SqlBackend -> Maybe (EntityDef -> Int -> Text) -- | A constraint synonym which witnesses that a backend is SQL and can run -- read queries. type SqlBackendCanRead backend = (BackendCompatible SqlBackend backend, PersistQueryRead backend, PersistStoreRead backend, PersistUniqueRead backend) -- | A constraint synonym which witnesses that a backend is SQL and can run -- read and write queries. type SqlBackendCanWrite backend = (SqlBackendCanRead backend, PersistQueryWrite backend, PersistStoreWrite backend, PersistUniqueWrite backend) -- | Like SqlPersistT but compatible with any SQL backend which -- can handle read queries. type SqlReadT m a = forall backend. (SqlBackendCanRead backend) => ReaderT backend m a -- | Like SqlPersistT but compatible with any SQL backend which -- can handle read and write queries. type SqlWriteT m a = forall backend. (SqlBackendCanWrite backend) => ReaderT backend m a -- | A backend which is a wrapper around SqlBackend. type IsSqlBackend backend = (IsPersistBackend backend, BaseBackend backend ~ SqlBackend) instance GHC.Enum.Bounded Database.Persist.Sql.Types.Internal.IsolationLevel instance GHC.Classes.Ord Database.Persist.Sql.Types.Internal.IsolationLevel instance GHC.Enum.Enum Database.Persist.Sql.Types.Internal.IsolationLevel instance GHC.Classes.Eq Database.Persist.Sql.Types.Internal.IsolationLevel instance GHC.Show.Show Database.Persist.Sql.Types.Internal.IsolationLevel instance Database.Persist.Class.PersistStore.HasPersistBackend Database.Persist.Sql.Types.Internal.SqlWriteBackend instance Database.Persist.Class.PersistStore.IsPersistBackend Database.Persist.Sql.Types.Internal.SqlWriteBackend instance Database.Persist.Class.PersistStore.HasPersistBackend Database.Persist.Sql.Types.Internal.SqlReadBackend instance Database.Persist.Class.PersistStore.IsPersistBackend Database.Persist.Sql.Types.Internal.SqlReadBackend instance Database.Persist.Class.PersistStore.HasPersistBackend Database.Persist.Sql.Types.Internal.SqlBackend instance Database.Persist.Class.PersistStore.IsPersistBackend Database.Persist.Sql.Types.Internal.SqlBackend module Database.Persist -- | Assign a field a value. -- --
-- updateAge :: MonadIO m => ReaderT SqlBackend m () -- updateAge = updateWhere [UserName ==. "SPJ" ] [UserAge =. 45] ---- -- Similar to updateWhere which is shown in the above example you -- can use other functions present in the module -- Database.Persist.Class. Note that the first parameter of -- updateWhere is [Filter val] and second parameter is -- [Update val]. By comparing this with the type of ==. and -- =., you can see that they match up in the above usage. -- -- The above query when applied on dataset-1, will produce this: -- --
-- +-----+-----+--------+ -- |id |name |age | -- +-----+-----+--------+ -- |1 |SPJ |40 -> 45| -- +-----+-----+--------+ -- |2 |Simon|41 | -- +-----+-----+--------+ --(=.) :: forall v typ. PersistField typ => EntityField v typ -> typ -> Update v infixr 3 =. -- | Assign a field by addition (+=). -- --
-- addAge :: MonadIO m => ReaderT SqlBackend m () -- addAge = updateWhere [UserName ==. "SPJ" ] [UserAge +=. 1] ---- -- The above query when applied on dataset-1, will produce this: -- --
-- +-----+-----+---------+ -- |id |name |age | -- +-----+-----+---------+ -- |1 |SPJ |40 -> 41 | -- +-----+-----+---------+ -- |2 |Simon|41 | -- +-----+-----+---------+ --(+=.) :: forall v typ. PersistField typ => EntityField v typ -> typ -> Update v infixr 3 +=. -- | Assign a field by subtraction (-=). -- --
-- subtractAge :: MonadIO m => ReaderT SqlBackend m () -- subtractAge = updateWhere [UserName ==. "SPJ" ] [UserAge -=. 1] ---- -- The above query when applied on dataset-1, will produce this: -- --
-- +-----+-----+---------+ -- |id |name |age | -- +-----+-----+---------+ -- |1 |SPJ |40 -> 39 | -- +-----+-----+---------+ -- |2 |Simon|41 | -- +-----+-----+---------+ --(-=.) :: forall v typ. PersistField typ => EntityField v typ -> typ -> Update v infixr 3 -=. -- | Assign a field by multiplication (*=). -- --
-- multiplyAge :: MonadIO m => ReaderT SqlBackend m () -- multiplyAge = updateWhere [UserName ==. "SPJ" ] [UserAge *=. 2] ---- -- The above query when applied on dataset-1, will produce this: -- --
-- +-----+-----+--------+ -- |id |name |age | -- +-----+-----+--------+ -- |1 |SPJ |40 -> 80| -- +-----+-----+--------+ -- |2 |Simon|41 | -- +-----+-----+--------+ --(*=.) :: forall v typ. PersistField typ => EntityField v typ -> typ -> Update v infixr 3 *=. -- | Assign a field by division (/=). -- --
-- divideAge :: MonadIO m => ReaderT SqlBackend m () -- divideAge = updateWhere [UserName ==. "SPJ" ] [UserAge /=. 2] ---- -- The above query when applied on dataset-1, will produce this: -- --
-- +-----+-----+---------+ -- |id |name |age | -- +-----+-----+---------+ -- |1 |SPJ |40 -> 20 | -- +-----+-----+---------+ -- |2 |Simon|41 | -- +-----+-----+---------+ --(/=.) :: forall v typ. PersistField typ => EntityField v typ -> typ -> Update v infixr 3 /=. -- | Check for equality. -- --
-- selectSPJ :: MonadIO m => ReaderT SqlBackend m [Entity User] -- selectSPJ = selectList [UserName ==. "SPJ" ] [] ---- -- The above query when applied on dataset-1, will produce this: -- --
-- +-----+-----+-----+ -- |id |name |age | -- +-----+-----+-----+ -- |1 |SPJ |40 | -- +-----+-----+-----+ --(==.) :: forall v typ. PersistField typ => EntityField v typ -> typ -> Filter v infix 4 ==. -- | Non-equality check. -- --
-- selectSimon :: MonadIO m => ReaderT SqlBackend m [Entity User] -- selectSimon = selectList [UserName !=. "SPJ" ] [] ---- -- The above query when applied on dataset-1, will produce this: -- --
-- +-----+-----+-----+ -- |id |name |age | -- +-----+-----+-----+ -- |2 |Simon|41 | -- +-----+-----+-----+ --(!=.) :: forall v typ. PersistField typ => EntityField v typ -> typ -> Filter v infix 4 !=. -- | Less-than check. -- --
-- selectLessAge :: MonadIO m => ReaderT SqlBackend m [Entity User] -- selectLessAge = selectList [UserAge <. 41 ] [] ---- -- The above query when applied on dataset-1, will produce this: -- --
-- +-----+-----+-----+ -- |id |name |age | -- +-----+-----+-----+ -- |1 |SPJ |40 | -- +-----+-----+-----+ --(<.) :: forall v typ. PersistField typ => EntityField v typ -> typ -> Filter v infix 4 <. -- | Greater-than check. -- --
-- selectGreaterAge :: MonadIO m => ReaderT SqlBackend m [Entity User] -- selectGreaterAge = selectList [UserAge >. 40 ] [] ---- -- The above query when applied on dataset-1, will produce this: -- --
-- +-----+-----+-----+ -- |id |name |age | -- +-----+-----+-----+ -- |2 |Simon|41 | -- +-----+-----+-----+ --(>.) :: forall v typ. PersistField typ => EntityField v typ -> typ -> Filter v infix 4 >. -- | Less-than or equal check. -- --
-- selectLessEqualAge :: MonadIO m => ReaderT SqlBackend m [Entity User] -- selectLessEqualAge = selectList [UserAge <=. 40 ] [] ---- -- The above query when applied on dataset-1, will produce this: -- --
-- +-----+-----+-----+ -- |id |name |age | -- +-----+-----+-----+ -- |1 |SPJ |40 | -- +-----+-----+-----+ --(<=.) :: forall v typ. PersistField typ => EntityField v typ -> typ -> Filter v infix 4 <=. -- | Greater-than or equal check. -- --
-- selectGreaterEqualAge :: MonadIO m => ReaderT SqlBackend m [Entity User] -- selectGreaterEqualAge = selectList [UserAge >=. 41 ] [] ---- -- The above query when applied on dataset-1, will produce this: -- --
-- +-----+-----+-----+ -- |id |name |age | -- +-----+-----+-----+ -- |2 |Simon|41 | -- +-----+-----+-----+ --(>=.) :: forall v typ. PersistField typ => EntityField v typ -> typ -> Filter v infix 4 >=. -- | Check if value is in given list. -- --
-- selectUsers :: MonadIO m => ReaderT SqlBackend m [Entity User] -- selectUsers = selectList [UserAge <-. [40, 41]] [] ---- -- The above query when applied on dataset-1, will produce this: -- --
-- +-----+-----+-----+ -- |id |name |age | -- +-----+-----+-----+ -- |1 |SPJ |40 | -- +-----+-----+-----+ -- |2 |Simon|41 | -- +-----+-----+-----+ ---- --
-- selectSPJ :: MonadIO m => ReaderT SqlBackend m [Entity User] -- selectSPJ = selectList [UserAge <-. [40]] [] ---- -- The above query when applied on dataset-1, will produce this: -- --
-- +-----+-----+-----+ -- |id |name |age | -- +-----+-----+-----+ -- |1 |SPJ |40 | -- +-----+-----+-----+ --(<-.) :: forall v typ. PersistField typ => EntityField v typ -> [typ] -> Filter v infix 4 <-. -- | Check if value is not in given list. -- --
-- selectSimon :: MonadIO m => ReaderT SqlBackend m [Entity User] -- selectSimon = selectList [UserAge /<-. [40]] [] ---- -- The above query when applied on dataset-1, will produce this: -- --
-- +-----+-----+-----+ -- |id |name |age | -- +-----+-----+-----+ -- |2 |Simon|41 | -- +-----+-----+-----+ --(/<-.) :: forall v typ. PersistField typ => EntityField v typ -> [typ] -> Filter v infix 4 /<-. -- | The OR of two lists of filters. For example: -- --
-- selectList -- ([ PersonAge >. 25 -- , PersonAge <. 30 ] ||. -- [ PersonIncome >. 15000 -- , PersonIncome <. 25000 ]) -- [] ---- -- will filter records where a person's age is between 25 and 30 -- or a person's income is between (15000 and 25000). -- -- If you are looking for an (&&.) operator to do (A -- AND B AND (C OR D)) you can use the (++) operator -- instead as there is no (&&.). For example: -- --
-- selectList -- ([ PersonAge >. 25 -- , PersonAge <. 30 ] ++ -- ([PersonCategory ==. 1] ||. -- [PersonCategory ==. 5])) -- [] ---- -- will filter records where a person's age is between 25 and 30 -- and (person's category is either 1 or 5). (||.) :: forall v. [Filter v] -> [Filter v] -> [Filter v] infixl 3 ||. -- | Convert list of PersistValues into textual representation of -- JSON object. This is a type-constrained synonym for toJsonText. listToJSON :: [PersistValue] -> Text -- | Convert map (list of tuples) into textual representation of JSON -- object. This is a type-constrained synonym for toJsonText. mapToJSON :: [(Text, PersistValue)] -> Text -- | A more general way to convert instances of ToJSON type class to -- strict text Text. toJsonText :: ToJSON j => j -> Text -- | FIXME Add documentation to that. getPersistMap :: PersistValue -> Either Text [(Text, PersistValue)] -- | FIXME What's this exactly? limitOffsetOrder :: PersistEntity val => [SelectOpt val] -> (Int, Int, [SelectOpt val]) module Database.Persist.Sql.Util parseEntityValues :: PersistEntity record => EntityDef -> [PersistValue] -> Either Text (Entity record) entityColumnNames :: EntityDef -> SqlBackend -> [Sql] keyAndEntityColumnNames :: EntityDef -> SqlBackend -> [Sql] entityColumnCount :: EntityDef -> Int isIdField :: PersistEntity record => EntityField record typ -> Bool -- | Deprecated as of 2.11. See hasNaturalKey or -- hasCompositePrimaryKey for replacements. -- | Deprecated: hasCompositeKey is misleading - it returns True if the -- entity is defined with the Primary keyword. See issue #685 for -- discussion. If you want the same behavior, use hasNaturalKey. -- If you want to know if the key has multiple fields, use -- hasCompositePrimaryKey. This function will be removed in the -- next major version. hasCompositeKey :: EntityDef -> Bool -- | Returns True if the provided entity has a custom composite -- primary key. Composite keys have multiple fields in them. -- --
-- User -- email String -- name String -- Primary userId -- -- Profile -- personId PersonId -- email String -- Primary personId email -- -- Person -- Id UUID -- name String -- -- Follower -- name String ---- -- Given these entity definitions, only Profile would return -- True, because it is the only entity with multiple columns in -- the primary key. User has a single column natural key. -- Person has a custom single column surrogate key defined with -- Id. And Follower has a default single column -- surrogate key. hasCompositePrimaryKey :: EntityDef -> Bool -- | Returns True if the entity has a natural key defined with the -- Primary keyword. -- -- A natural key is a key that is inherent to the record, and is part of -- the actual Haskell record. The opposite of a natural key is a -- "surrogate key", which is not part of the normal domain object. -- Automatically generated ID columns are the most common surrogate ID, -- while an email address is a common natural key. -- --
-- User -- email String -- name String -- Primary email -- -- Person -- Id UUID -- name String -- -- Follower -- name String ---- -- Given these entity definitions, User would return -- True, because the Primary keyword sets the -- email column to be the primary key. The generated Haskell -- type would look like this: -- --
-- data User = User
-- { userEmail :: String
-- , userName :: String
-- }
--
--
-- Person would be false. While the Id syntax allows
-- you to define a custom ID type for an entity, the Id column
-- is a surrogate key.
--
-- The same is true for Follower. The automatically generated
-- autoincremented integer primary key is a surrogate key.
--
-- There's nothing preventing you from defining a Primary
-- definition that refers to a surrogate key. This is totally fine.
hasNaturalKey :: EntityDef -> Bool
dbIdColumns :: SqlBackend -> EntityDef -> [Text]
dbIdColumnsEsc :: (FieldNameDB -> Text) -> EntityDef -> [Text]
dbColumns :: SqlBackend -> EntityDef -> [Text]
-- | Gets the FieldDef for an Update.
updateFieldDef :: PersistEntity v => Update v -> FieldDef
updatePersistValue :: Update v -> PersistValue
mkUpdateText :: PersistEntity record => SqlBackend -> Update record -> Text
mkUpdateText' :: PersistEntity record => (FieldNameDB -> Text) -> (Text -> Text) -> Update record -> Text
commaSeparated :: [Text] -> Text
parenWrapped :: Text -> Text
-- | Make a list PersistValue suitable for database inserts. Pairs
-- nicely with the function mkInsertPlaceholders.
--
-- Does not include generated columns.
mkInsertValues :: PersistEntity rec => rec -> [PersistValue]
-- | Returns a list of escaped field names and "?" placeholder
-- values for performing inserts. This does not include generated
-- columns.
--
-- Does not include generated columns.
mkInsertPlaceholders :: EntityDef -> (FieldNameDB -> Text) -> [(Text, Text)]
module Database.Persist.Compatible
-- | A newtype wrapper for compatible backends, mainly useful for
-- DerivingVia.
--
-- When writing a new backend that is BackendCompatible with an
-- existing backend, instances for the new backend can be naturally
-- defined in terms of the instances for the existing backend.
--
-- For example, if you decide to augment the SqlBackend with
-- some additional features:
--
--
-- data BetterSqlBackend = BetterSqlBackend { sqlBackend :: SqlBackend, ... }
--
-- instance BackendCompatible SqlBackend BetterSqlBackend where
-- projectBackend = sqlBackend
--
--
-- Then you can use DerivingVia to automatically get instances
-- like:
--
-- -- deriving via (Compatible SqlBackend BetterSqlBackend) instance PersistStoreRead BetterSqlBackend -- deriving via (Compatible SqlBackend BetterSqlBackend) instance PersistStoreWrite BetterSqlBackend -- ... ---- -- These instances will go through the compatible backend (in this case, -- SqlBackend) for all their queries. -- -- These instances require that both backends have the same -- BaseBackend, but deriving HasPersistBackend will enforce -- that for you. -- --
-- deriving via (Compatible SqlBackend BetterSqlBackend) instance HasPersistBackend BetterSqlBackend --newtype Compatible b s Compatible :: s -> Compatible b s [unCompatible] :: Compatible b s -> s -- | Gives a bunch of useful instance declarations for a backend based on -- its compatibility with another backend, using Compatible. -- -- The argument should be a type of the form forall v1 ... vn. -- Compatible b s (Quantification is optional, but supported -- because TH won't let you have unbound type variables in a type -- splice). The instance is produced for s based on the instance -- defined for b, which is constrained in the instance head to -- exist. -- -- v1 ... vn are implicitly quantified in the instance, which is -- derived via Compatible b s. makeCompatibleInstances :: Q Type -> Q [Dec] -- | Gives a bunch of useful instance declarations for a backend key based -- on its compatibility with another backend & key, using -- Compatible. -- -- The argument should be a type of the form forall v1 ... vn. -- Compatible b s (Quantification is optional, but supported -- because TH won't let you have unbound type variables in a type -- splice). The instance is produced for BackendKey s -- based on the instance defined for BackendKey b, which -- is constrained in the instance head to exist. -- -- v1 ... vn are implicitly quantified in the instance, which is -- derived via BackendKey (Compatible b s). makeCompatibleKeyInstances :: Q Type -> Q [Dec] module Database.Persist.Sql -- | 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. newtype PersistUnsafeMigrationException PersistUnsafeMigrationException :: [(Bool, Sql)] -> PersistUnsafeMigrationException -- | A single column (see rawSql). Any PersistField may -- be used here, including PersistValue (which does not do any -- processing). newtype Single a Single :: a -> Single a [unSingle] :: Single a -> a -- | Values to configure a pool of database connections. See -- Data.Pool for details. data ConnectionPoolConfig ConnectionPoolConfig :: Int -> NominalDiffTime -> Int -> ConnectionPoolConfig -- | How many stripes to divide the pool into. See Data.Pool for -- details. Default: 1. [connectionPoolConfigStripes] :: ConnectionPoolConfig -> Int -- | How long connections can remain idle before being disposed of, in -- seconds. Default: 600 [connectionPoolConfigIdleTimeout] :: ConnectionPoolConfig -> NominalDiffTime -- | How many connections should be held in the connection pool. Default: -- 10 [connectionPoolConfigSize] :: ConnectionPoolConfig -> Int type ConnectionPool = Pool SqlBackend -- | A Migration is a four level monad stack consisting of: -- --
-- data Switch = On | Off -- deriving (Show, Eq) -- -- instance PersistField Switch where -- toPersistValue s = case s of -- On -> PersistBool True -- Off -> PersistBool False -- fromPersistValue (PersistBool b) = if b then Right On else Right Off -- fromPersistValue x = Left $ "File.hs: When trying to deserialize a Switch: expected PersistBool, received: " <> T.pack (show x) -- -- instance PersistFieldSql Switch where -- sqlType _ = SqlBool ---- --
-- import qualified Data.UUID as UUID -- instance PersistField UUID where -- toPersistValue = PersistLiteralEncoded . toASCIIBytes -- fromPersistValue (PersistLiteralEncoded uuid) = -- case fromASCIIBytes uuid of -- Nothing -> Left $ "Model/CustomTypes.hs: Failed to deserialize a UUID; received: " <> T.pack (show uuid) -- Just uuid' -> Right uuid' -- fromPersistValue x = Left $ "File.hs: When trying to deserialize a UUID: expected PersistLiteralEncoded, received: "-- > <> T.pack (show x) -- -- instance PersistFieldSql UUID where -- sqlType _ = SqlOther "uuid" ---- --
-- CREATE DOMAIN ssn AS text
-- CHECK ( value ~ '^[0-9]{9}$');
--
--
-- -- instance PersistFieldSQL SSN where -- sqlType _ = SqlOther "ssn" ---- --
-- CREATE TYPE rainbow_color AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet');
--
--
-- -- instance PersistFieldSQL RainbowColor where -- sqlType _ = SqlOther "rainbow_color" --class PersistField a => PersistFieldSql a sqlType :: PersistFieldSql a => Proxy a -> SqlType -- | This newtype wrapper is useful when selecting an entity out of the -- database and you want to provide a prefix to the table being selected. -- -- Consider this raw SQL query: -- --
-- SELECT ?? -- FROM my_long_table_name AS mltn -- INNER JOIN other_table AS ot -- ON mltn.some_col = ot.other_col -- WHERE ... ---- -- We don't want to refer to my_long_table_name every time, so -- we create an alias. If we want to select it, we have to tell the raw -- SQL quasi-quoter that we expect the entity to be prefixed with some -- other name. -- -- We can give the above query a type with this, like: -- --
-- getStuff :: SqlPersistM [EntityWithPrefix "mltn" MyLongTableName] -- getStuff = rawSql queryText [] ---- -- The EntityWithPrefix bit is a boilerplate newtype wrapper, so -- you can remove it with unPrefix, like this: -- --
-- getStuff :: SqlPersistM [Entity MyLongTableName] -- getStuff = unPrefix @"mltn" <$> rawSql queryText [] ---- -- The symbol is a "type application" and requires the -- TypeApplications@ language extension. newtype EntityWithPrefix (prefix :: Symbol) record EntityWithPrefix :: Entity record -> EntityWithPrefix (prefix :: Symbol) record [unEntityWithPrefix] :: EntityWithPrefix (prefix :: Symbol) record -> Entity record -- | A helper function to tell GHC what the EntityWithPrefix prefix -- should be. This allows you to use a type application to specify the -- prefix, instead of specifying the etype on the result. -- -- As an example, here's code that uses this: -- --
-- myQuery :: SqlPersistM [Entity Person] -- myQuery = map (unPrefix @"p") $ rawSql query [] -- where -- query = "SELECT ?? FROM person AS p" --unPrefix :: forall prefix record. EntityWithPrefix prefix record -> Entity record -- | Get a connection from the pool, run the given action, and then return -- the connection to the pool. -- -- This function performs the given action in a transaction. If an -- exception occurs during the action, then the transaction is rolled -- back. -- -- Note: This function previously timed out after 2 seconds, but this -- behavior was buggy and caused more problems than it solved. Since -- version 2.1.2, it performs no timeout checks. runSqlPool :: forall backend m a. (MonadUnliftIO m, BackendCompatible SqlBackend backend) => ReaderT backend m a -> Pool backend -> m a -- | Like runSqlPool, but supports specifying an isolation level. runSqlPoolWithIsolation :: forall backend m a. (MonadUnliftIO m, BackendCompatible SqlBackend backend) => ReaderT backend m a -> Pool backend -> IsolationLevel -> m a -- | Like runSqlPool, but does not surround the action in a -- transaction. This action might leave your database in a weird state. runSqlPoolNoTransaction :: forall backend m a. (MonadUnliftIO m, BackendCompatible SqlBackend backend) => ReaderT backend m a -> Pool backend -> Maybe IsolationLevel -> m a -- | This function is how runSqlPool and -- runSqlPoolNoTransaction are defined. In addition to the action -- to be performed and the Pool of conections to use, we give you -- the opportunity to provide three actions - initialize, afterwards, and -- onException. runSqlPoolWithHooks :: forall backend m a before after onException. (MonadUnliftIO m, BackendCompatible SqlBackend backend) => ReaderT backend m a -> Pool backend -> Maybe IsolationLevel -> (backend -> m before) -> (backend -> m after) -> (backend -> SomeException -> m onException) -> m a -- | Starts a new transaction on the connection. When the acquired -- connection is released the transaction is committed and the connection -- returned to the pool. -- -- Upon an exception the transaction is rolled back and the connection -- destroyed. -- -- This is equivalent to 'runSqlConn but does not incur the -- MonadUnliftIO constraint, meaning it can be used within, for -- example, a Conduit pipeline. acquireSqlConn :: (MonadReader backend m, BackendCompatible SqlBackend backend) => m (Acquire backend) -- | Like acquireSqlConn, but lets you specify an explicit isolation -- level. acquireSqlConnWithIsolation :: (MonadReader backend m, BackendCompatible SqlBackend backend) => IsolationLevel -> m (Acquire backend) runSqlConn :: forall backend m a. (MonadUnliftIO m, BackendCompatible SqlBackend backend) => ReaderT backend m a -> backend -> m a -- | Like runSqlConn, but supports specifying an isolation level. runSqlConnWithIsolation :: forall backend m a. (MonadUnliftIO m, BackendCompatible SqlBackend backend) => ReaderT backend m a -> backend -> IsolationLevel -> m a runSqlPersistM :: BackendCompatible SqlBackend backend => ReaderT backend (NoLoggingT (ResourceT IO)) a -> backend -> IO a runSqlPersistMPool :: BackendCompatible SqlBackend backend => ReaderT backend (NoLoggingT (ResourceT IO)) a -> Pool backend -> IO a liftSqlPersistMPool :: forall backend m a. (MonadIO m, BackendCompatible SqlBackend backend) => ReaderT backend (NoLoggingT (ResourceT IO)) a -> Pool backend -> m a withSqlPool :: forall backend m a. (MonadLoggerIO m, MonadUnliftIO m, BackendCompatible SqlBackend backend) => (LogFunc -> IO backend) -> Int -> (Pool backend -> m a) -> m a -- | Creates a pool of connections to a SQL database which can be used by -- the Pool backend -> m a function. After the function -- completes, the connections are destroyed. withSqlPoolWithConfig :: forall backend m a. (MonadLoggerIO m, MonadUnliftIO m, BackendCompatible SqlBackend backend) => (LogFunc -> IO backend) -> ConnectionPoolConfig -> (Pool backend -> m a) -> m a createSqlPool :: forall backend m. (MonadLoggerIO m, MonadUnliftIO m, BackendCompatible SqlBackend backend) => (LogFunc -> IO backend) -> Int -> m (Pool backend) -- | Creates a pool of connections to a SQL database. createSqlPoolWithConfig :: forall m backend. (MonadLoggerIO m, MonadUnliftIO m, BackendCompatible SqlBackend backend) => (LogFunc -> IO backend) -> ConnectionPoolConfig -> m (Pool backend) -- | Create a connection and run sql queries within it. This function -- automatically closes the connection on it's completion. -- --
-- {-# LANGUAGE GADTs #-}
-- {-# LANGUAGE ScopedTypeVariables #-}
-- {-# LANGUAGE OverloadedStrings #-}
-- {-# LANGUAGE MultiParamTypeClasses #-}
-- {-# LANGUAGE TypeFamilies#-}
-- {-# LANGUAGE TemplateHaskell#-}
-- {-# LANGUAGE QuasiQuotes#-}
-- {-# LANGUAGE GeneralizedNewtypeDeriving #-}
--
-- import Control.Monad.IO.Class (liftIO)
-- import Control.Monad.Logger
-- import Conduit
-- import Database.Persist
-- import Database.Sqlite
-- import Database.Persist.Sqlite
-- import Database.Persist.TH
--
-- share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase|
-- Person
-- name String
-- age Int Maybe
-- deriving Show
-- |]
--
-- openConnection :: LogFunc -> IO SqlBackend
-- openConnection logfn = do
-- conn <- open "/home/sibi/test.db"
-- wrapConnection conn logfn
--
-- main :: IO ()
-- main = do
-- runNoLoggingT $ runResourceT $ withSqlConn openConnection (\backend ->
-- flip runSqlConn backend $ do
-- runMigration migrateAll
-- insert_ $ Person "John doe" $ Just 35
-- insert_ $ Person "Divya" $ Just 36
-- (pers :: [Entity Person]) <- selectList [] []
-- liftIO $ print pers
-- return ()
-- )
--
--
-- On executing it, you get this output:
--
--
-- Migrating: CREATE TABLE "person"("id" INTEGER PRIMARY KEY,"name" VARCHAR NOT NULL,"age" INTEGER NULL)
-- [Entity {entityKey = PersonKey {unPersonKey = SqlBackendKey {unSqlBackendKey = 1}}, entityVal = Person {personName = "John doe", personAge = Just 35}},Entity {entityKey = PersonKey {unPersonKey = SqlBackendKey {unSqlBackendKey = 2}}, entityVal = Person {personName = "Hema", personAge = Just 36}}]
--
withSqlConn :: forall backend m a. (MonadUnliftIO m, MonadLoggerIO m, BackendCompatible SqlBackend backend) => (LogFunc -> IO backend) -> (backend -> m a) -> m a
close' :: BackendCompatible SqlBackend backend => backend -> IO ()
-- | Given a Migration, this parses it and returns either a list of
-- errors associated with the migration or a list of migrations to do.
parseMigration :: (HasCallStack, MonadIO m) => Migration -> ReaderT SqlBackend m (Either [Text] CautiousMigration)
-- | 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
-- | Prints a migration.
printMigration :: (HasCallStack, MonadIO m) => Migration -> ReaderT SqlBackend m ()
-- | Convert a Migration to a list of Text values
-- corresponding to their Sql statements.
showMigration :: (HasCallStack, MonadIO m) => Migration -> ReaderT SqlBackend m [Text]
-- | Return all of the Sql values associated with the given
-- migration. Calls error if there's a parse error on any
-- migration.
getMigration :: (MonadIO m, HasCallStack) => Migration -> ReaderT SqlBackend m [Sql]
-- | 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 ()
-- | Same as runMigration, but does not report the individual
-- migrations on stderr. Instead it returns a list of the executed SQL
-- commands.
--
-- This is a safer/more robust alternative to runMigrationSilent,
-- but may be less silent for some persistent implementations, most
-- notably persistent-postgresql
runMigrationQuiet :: MonadIO m => Migration -> ReaderT SqlBackend m [Text]
-- | Same as runMigration, but returns a list of the SQL commands
-- executed instead of printing them to stderr.
--
-- This function silences the migration by remapping stderr. As a
-- result, it is not thread-safe and can clobber output from other parts
-- of the program. This implementation method was chosen to also silence
-- postgresql migration output on stderr, but is not recommended!
runMigrationSilent :: MonadUnliftIO m => Migration -> ReaderT SqlBackend m [Text]
-- | Like runMigration, but this will perform the unsafe database
-- migrations instead of erroring out.
runMigrationUnsafe :: MonadIO m => Migration -> ReaderT SqlBackend m ()
-- | Same as runMigrationUnsafe, but returns a list of the SQL
-- commands executed instead of printing them to stderr.
runMigrationUnsafeQuiet :: (HasCallStack, MonadIO m) => Migration -> ReaderT SqlBackend m [Text]
-- | Given a list of old entity definitions and a new EntityDef in
-- val, this creates a Migration to update the old list
-- of definitions with the new one.
migrate :: [EntityDef] -> EntityDef -> Migration
-- | Report multiple errors in a Migration.
reportErrors :: [Text] -> Migration
-- | Report a single error in a Migration.
reportError :: Text -> Migration
-- | Add a CautiousMigration (aka a [(Bool,
-- Text)]) to the migration plan.
addMigrations :: CautiousMigration -> Migration
-- | Add a migration to the migration plan.
addMigration :: Bool -> Sql -> Migration
withRawQuery :: MonadIO m => Text -> [PersistValue] -> ConduitM [PersistValue] Void IO a -> ReaderT SqlBackend m a
data family BackendKey backend
toSqlKey :: ToBackendKey SqlBackend record => Int64 -> Key record
fromSqlKey :: ToBackendKey SqlBackend record => Key record -> Int64
-- | get the SQL string for the field that an EntityField represents Useful
-- for raw SQL queries
--
-- Your backend may provide a more convenient fieldName function which
-- does not operate in a Monad
getFieldName :: forall record typ m backend. (PersistEntity record, PersistEntityBackend record ~ SqlBackend, BackendCompatible SqlBackend backend, Monad m) => EntityField record typ -> ReaderT backend m Text
-- | get the SQL string for the table that a PeristEntity represents Useful
-- for raw SQL queries
--
-- Your backend may provide a more convenient tableName function which
-- does not operate in a Monad
getTableName :: forall record m backend. (PersistEntity record, BackendCompatible SqlBackend backend, Monad m) => record -> ReaderT backend m Text
-- | useful for a backend to implement tableName by adding escaping
tableDBName :: PersistEntity record => record -> EntityNameDB
-- | useful for a backend to implement fieldName by adding escaping
fieldDBName :: forall record typ. PersistEntity record => EntityField record typ -> FieldNameDB
rawQuery :: (MonadResource m, MonadReader env m, BackendCompatible SqlBackend env) => Text -> [PersistValue] -> ConduitM () [PersistValue] m ()
rawQueryRes :: (MonadIO m1, MonadIO m2, BackendCompatible SqlBackend env) => Text -> [PersistValue] -> ReaderT env m1 (Acquire (ConduitM () [PersistValue] m2 ()))
-- | Execute a raw SQL statement
rawExecute :: (MonadIO m, BackendCompatible SqlBackend backend) => Text -> [PersistValue] -> ReaderT backend m ()
-- | Execute a raw SQL statement and return the number of rows it has
-- modified.
rawExecuteCount :: (MonadIO m, BackendCompatible SqlBackend backend) => Text -> [PersistValue] -> ReaderT backend m Int64
-- | Execute a raw SQL statement and return its results as a list. If you
-- do not expect a return value, use of rawExecute is recommended.
--
-- If you're using Entitys (which is quite likely), then
-- you must use entity selection placeholders (double question
-- mark, ??). These ?? placeholders are then replaced
-- for the names of the columns that we need for your entities. You'll
-- receive an error if you don't use the placeholders. Please see the
-- Entitys documentation for more details.
--
-- You may put value placeholders (question marks, ?) in your
-- SQL query. These placeholders are then replaced by the values you pass
-- on the second parameter, already correctly escaped. You may want to
-- use toPersistValue to help you constructing the placeholder
-- values.
--
-- Since you're giving a raw SQL statement, you don't get any guarantees
-- regarding safety. If rawSql is not able to parse the results of
-- your query back, then an exception is raised. However, most common
-- problems are mitigated by using the entity selection placeholder
-- ??, and you shouldn't see any error at all if you're not
-- using Single.
--
-- Some example of rawSql based on this schema:
--
-- -- share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase| -- Person -- name String -- age Int Maybe -- deriving Show -- BlogPost -- title String -- authorId PersonId -- deriving Show -- |] ---- -- Examples based on the above schema: -- --
-- getPerson :: MonadIO m => ReaderT SqlBackend m [Entity Person] -- getPerson = rawSql "select ?? from person where name=?" [PersistText "john"] -- -- getAge :: MonadIO m => ReaderT SqlBackend m [Single Int] -- getAge = rawSql "select person.age from person where name=?" [PersistText "john"] -- -- getAgeName :: MonadIO m => ReaderT SqlBackend m [(Single Int, Single Text)] -- getAgeName = rawSql "select person.age, person.name from person where name=?" [PersistText "john"] -- -- getPersonBlog :: MonadIO m => ReaderT SqlBackend m [(Entity Person, Entity BlogPost)] -- getPersonBlog = rawSql "select ??,?? from person,blog_post where person.id = blog_post.author_id" [] ---- -- Minimal working program for PostgreSQL backend based on the above -- concepts: -- --
-- {-# LANGUAGE EmptyDataDecls #-}
-- {-# LANGUAGE FlexibleContexts #-}
-- {-# LANGUAGE GADTs #-}
-- {-# LANGUAGE GeneralizedNewtypeDeriving #-}
-- {-# LANGUAGE MultiParamTypeClasses #-}
-- {-# LANGUAGE OverloadedStrings #-}
-- {-# LANGUAGE QuasiQuotes #-}
-- {-# LANGUAGE TemplateHaskell #-}
-- {-# LANGUAGE TypeFamilies #-}
--
-- import Control.Monad.IO.Class (liftIO)
-- import Control.Monad.Logger (runStderrLoggingT)
-- import Database.Persist
-- import Control.Monad.Reader
-- import Data.Text
-- import Database.Persist.Sql
-- import Database.Persist.Postgresql
-- import Database.Persist.TH
--
-- share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase|
-- Person
-- name String
-- age Int Maybe
-- deriving Show
-- |]
--
-- conn = "host=localhost dbname=new_db user=postgres password=postgres port=5432"
--
-- getPerson :: MonadIO m => ReaderT SqlBackend m [Entity Person]
-- getPerson = rawSql "select ?? from person where name=?" [PersistText "sibi"]
--
-- liftSqlPersistMPool y x = liftIO (runSqlPersistMPool y x)
--
-- main :: IO ()
-- main = runStderrLoggingT $ withPostgresqlPool conn 10 $ liftSqlPersistMPool $ do
-- runMigration migrateAll
-- xs <- getPerson
-- liftIO (print xs)
--
rawSql :: (RawSql a, MonadIO m, BackendCompatible SqlBackend backend) => Text -> [PersistValue] -> ReaderT backend m [a]
-- | Same as deleteWhere, but returns the number of rows affected.
deleteWhereCount :: (PersistEntity val, MonadIO m, PersistEntityBackend val ~ SqlBackend, BackendCompatible SqlBackend backend) => [Filter val] -> ReaderT backend m Int64
-- | Same as updateWhere, but returns the number of rows affected.
updateWhereCount :: (PersistEntity val, MonadIO m, SqlBackend ~ PersistEntityBackend val, BackendCompatible SqlBackend backend) => [Filter val] -> [Update val] -> ReaderT backend m Int64
-- | Render a [Filter record] into a Text value
-- suitable for inclusion into a SQL query.
filterClause :: PersistEntity val => Maybe FilterTablePrefix -> SqlBackend -> [Filter val] -> Text
-- | Render a [Filter record] into a Text value
-- suitable for inclusion into a SQL query, as well as the
-- [PersistValue] to properly fill in the ?
-- place holders.
filterClauseWithVals :: PersistEntity val => Maybe FilterTablePrefix -> SqlBackend -> [Filter val] -> (Text, [PersistValue])
-- | Used when determining how to prefix a column name in a WHERE
-- clause.
data FilterTablePrefix
-- | Prefix the column with the table name. This is useful if the column
-- name might be ambiguous.
PrefixTableName :: FilterTablePrefix
-- | Prefix the column name with the EXCLUDED keyword. This is
-- used with the Postgresql backend when doing ON CONFLICT DO
-- UPDATE clauses - see the documentation on upsertWhere
-- and upsertManyWhere.
PrefixExcluded :: FilterTablePrefix
-- | Commit the current transaction and begin a new one. This is used when
-- a transaction commit is required within the context of
-- runSqlConn (which brackets its provided action with a
-- transaction begin/commit pair).
transactionSave :: MonadIO m => ReaderT SqlBackend m ()
-- | Commit the current transaction and begin a new one with the specified
-- isolation level.
transactionSaveWithIsolation :: MonadIO m => IsolationLevel -> ReaderT SqlBackend m ()
-- | Roll back the current transaction and begin a new one. This rolls back
-- to the state of the last call to transactionSave or the
-- enclosing runSqlConn call.
transactionUndo :: MonadIO m => ReaderT SqlBackend m ()
-- | Roll back the current transaction and begin a new one with the
-- specified isolation level.
transactionUndoWithIsolation :: MonadIO m => IsolationLevel -> ReaderT SqlBackend m ()
-- | Please refer to the documentation for the database in question for a
-- full overview of the semantics of the varying isloation levels
data IsolationLevel
ReadUncommitted :: IsolationLevel
ReadCommitted :: IsolationLevel
RepeatableRead :: IsolationLevel
Serializable :: IsolationLevel
getStmtConn :: SqlBackend -> Text -> IO Statement
-- | Create the list of columns for the given entity.
mkColumns :: [EntityDef] -> EntityDef -> BackendSpecificOverrides -> ([Column], [UniqueDef], [ForeignDef])
defaultAttribute :: [FieldAttr] -> Maybe Text
-- | Record of functions to override the default behavior in
-- mkColumns. It is recommended you initialize this with
-- emptyBackendSpecificOverrides and override the default values,
-- so that as new fields are added, your code still compiles.
data BackendSpecificOverrides
BackendSpecificOverrides :: Maybe (EntityNameDB -> FieldNameDB -> ConstraintNameDB) -> BackendSpecificOverrides
[backendSpecificForeignKeyName] :: BackendSpecificOverrides -> Maybe (EntityNameDB -> FieldNameDB -> ConstraintNameDB)
-- | Creates an empty BackendSpecificOverrides (i.e. use the default
-- behavior; no overrides)
emptyBackendSpecificOverrides :: BackendSpecificOverrides
-- | Generates sql for limit and offset for postgres, sqlite and mysql.
decorateSQLWithLimitOffset :: Text -> (Int, Int) -> Bool -> Text -> Text
-- | This module provides the tools for defining your database schema and
-- using it to generate Haskell data types and migrations.
module Database.Persist.TH
-- | Converts a quasi-quoted syntax into a list of entity definitions, to
-- be used as input to the template haskell generation code (mkPersist).
persistWith :: PersistSettings -> QuasiQuoter
-- | Apply persistWith to upperCaseSettings.
persistUpperCase :: QuasiQuoter
-- | Apply persistWith to lowerCaseSettings.
persistLowerCase :: QuasiQuoter
-- | Same as persistWith, but uses an external file instead of a
-- quasiquotation. The recommended file extension is
-- .persistentmodels.
persistFileWith :: PersistSettings -> FilePath -> Q Exp
-- | Same as persistFileWith, but uses several external files
-- instead of one. Splitting your Persistent definitions into multiple
-- modules can potentially dramatically speed up compile times.
--
-- The recommended file extension is .persistentmodels.
--
-- -- -- Model1.hs -- share -- [mkPersist sqlSettings] -- $(persistFileWith lowerCaseSettings "models1") ---- --
-- -- Model2.hs -- share -- [mkPersist sqlSettings] -- $(persistFileWith lowerCaseSettings "models2") ---- -- Use persistManyFileWith to create your migrations: -- --
-- -- Migrate.hs -- share -- [mkMigrate "migrateAll"] -- $(persistManyFileWith lowerCaseSettings ["models1.persistentmodels","models2.persistentmodels"]) ---- -- Tip: To get the same import behavior as if you were declaring all your -- models in one file, import your new files as Name into -- another file, then export module Name. -- -- This approach may be used in the future to reduce memory usage during -- compilation, but so far we've only seen mild reductions. -- -- See persistent#778 and persistent#791 for more details. persistManyFileWith :: PersistSettings -> [FilePath] -> Q Exp -- | Create data types and appropriate PersistEntity instances for -- the given EntityDefs. Works well with the persist quasi-quoter. mkPersist :: MkPersistSettings -> [EntityDef] -> Q [Dec] -- | Settings to be passed to the mkPersist function. data MkPersistSettings -- | Which database backend we're using. -- -- When generating data types, each type is given a generic version- -- which works with any backend- and a type synonym for the commonly used -- backend. This is where you specify that commonly used backend. mpsBackend :: MkPersistSettings -> Type -- | Create generic types that can be used with multiple backends. Good for -- reusable code, but makes error messages harder to understand. Default: -- False. mpsGeneric :: MkPersistSettings -> Bool -- | Prefix field names with the model name. Default: True. -- -- Note: this field is deprecated. Use the mpsFieldLabelModifier and -- mpsConstraintLabelModifier instead. mpsPrefixFields :: MkPersistSettings -> Bool -- | Customise the field accessors and lens names using the entity and -- field name. Both arguments are upper cased. -- -- Default: appends entity and field. -- -- Note: this setting is ignored if mpsPrefixFields is set to False. -- @since 2.11.0.0 mpsFieldLabelModifier :: MkPersistSettings -> Text -> Text -> Text -- | Customise the Constraint names using the entity and field name. The -- result should be a valid haskell type (start with an upper cased -- letter). -- -- Default: appends entity and field -- -- Note: this setting is ignored if mpsPrefixFields is set to False. -- @since 2.11.0.0 mpsConstraintLabelModifier :: MkPersistSettings -> Text -> Text -> Text -- | Generate ToJSON/FromJSON instances for each model -- types. If it's Nothing, no instances will be generated. -- Default: -- --
-- Just EntityJSON
-- { entityToJSON = 'entityIdToJSON
-- , entityFromJSON = 'entityIdFromJSON
-- }
--
mpsEntityJSON :: MkPersistSettings -> Maybe EntityJSON
-- | Instead of generating normal field accessors, generator lens-style
-- accessors.
--
-- Default: False
mpsGenerateLenses :: MkPersistSettings -> Bool
-- | Automatically derive these typeclass instances for all record and key
-- types.
--
-- Default: []
mpsDeriveInstances :: MkPersistSettings -> [Name]
data EntityJSON
EntityJSON :: Name -> Name -> EntityJSON
-- | Name of the toJSON implementation for Entity a.
[entityToJSON] :: EntityJSON -> Name
-- | Name of the fromJSON implementation for Entity a.
[entityFromJSON] :: EntityJSON -> Name
-- | Create an MkPersistSettings with default values.
mkPersistSettings :: Type -> MkPersistSettings
-- | Use the SqlPersist backend.
sqlSettings :: MkPersistSettings
-- | Creates a single function to perform all migrations for the entities
-- defined here. One thing to be aware of is dependencies: if you have
-- entities with foreign references, make sure to place those definitions
-- after the entities they reference.
mkMigrate :: String -> [EntityDef] -> Q [Dec]
-- | Save the EntityDefs passed in under the given name.
mkSave :: String -> [EntityDef] -> Q [Dec]
-- | Generate a DeleteCascade instance for the given
-- EntityDefs.
mkDeleteCascade :: MkPersistSettings -> [EntityDef] -> Q [Dec]
-- | Creates a declaration for the [EntityDef] from the
-- persistent schema. This is necessary because the Persistent
-- QuasiQuoter is unable to know the correct type of ID fields, and
-- assumes that they are all Int64.
--
-- Provide this in the list you give to share, much like
-- mkMigrate.
--
-- -- share [mkMigrate "migrateAll", mkEntityDefList "entityDefs"] [...] --mkEntityDefList :: String -> [EntityDef] -> Q [Dec] -- | Apply the given list of functions to the same EntityDefs. -- -- This function is useful for cases such as: -- --
-- >>> share [mkSave "myDefs", mkPersist sqlSettings] [persistLowerCase|...|] --share :: [[EntityDef] -> Q [Dec]] -> [EntityDef] -> Q [Dec] -- | Automatically creates a valid PersistField instance for any -- datatype that has valid Show and Read instances. Can be -- very convenient for Enum types. derivePersistField :: String -> Q [Dec] -- | Automatically creates a valid PersistField instance for any -- datatype that has valid ToJSON and FromJSON instances. -- For a datatype T it generates instances similar to these: -- --
-- instance PersistField T where -- toPersistValue = PersistByteString . L.toStrict . encode -- fromPersistValue = (left T.pack) . eitherDecodeStrict' <=< fromPersistValue -- instance PersistFieldSql T where -- sqlType _ = SqlString --derivePersistFieldJSON :: String -> Q [Dec] -- | Produce code similar to the following: -- --
-- instance PersistEntity e => PersistField e where -- toPersistValue = entityToPersistValueHelper -- fromPersistValue = entityFromPersistValueHelper ["col1", "col2"] -- sqlType _ = SqlString --persistFieldFromEntity :: MkPersistSettings -> EntityDef -> Q [Dec] lensPTH :: (s -> a) -> (s -> b -> t) -> Lens s t a b parseReferences :: PersistSettings -> Text -> Q Exp -- | Takes a list of (potentially) independently defined entities and -- properly links all foreign keys to reference the right -- EntityDef, tying the knot between entities. -- -- Allows users to define entities indepedently or in separate modules -- and then fix the cross-references between them at runtime to create a -- Migration. embedEntityDefs :: [EntityDef] -> [EntityDef] -- | Render an error message based on the tableName and -- fieldName with the provided message. fieldError :: Text -> Text -> Text -> Text -- | This class is used to ensure that functions requring at least one -- unique key are not called with records that have 0 unique keys. The -- quasiquoter automatically writes working instances for appropriate -- entities, and generates TypeError instances for records that -- have 0 unique keys. class PersistEntity record => AtLeastOneUniqueKey record requireUniquesP :: AtLeastOneUniqueKey record => record -> NonEmpty (Unique record) -- | This class is used to ensure that upsert is only called on -- records that have a single Unique key. The quasiquoter -- automatically generates working instances for appropriate records, and -- generates TypeError instances for records that have 0 or -- multiple unique keys. class PersistEntity record => OnlyOneUniqueKey record onlyUniqueP :: OnlyOneUniqueKey record => record -> Unique record -- | Returns True if the key definition has more than 1 field. pkNewtype :: MkPersistSettings -> EntityDef -> Bool instance GHC.Show.Show Database.Persist.TH.SqlTypeExp instance GHC.Show.Show Database.Persist.TH.EntityDefSqlTypeExp instance GHC.Show.Show Database.Persist.TH.FTTypeConDescr instance Language.Haskell.TH.Syntax.Lift Database.Persist.TH.FieldsSqlTypeExp instance Language.Haskell.TH.Syntax.Lift Database.Persist.TH.FieldSqlTypeExp instance Language.Haskell.TH.Syntax.Lift Database.Persist.TH.EntityDefSqlTypeExp instance Language.Haskell.TH.Syntax.Lift Database.Persist.TH.SqlTypeExp