IHP Api Reference
Safe HaskellNone

IHP.ModelSupport

Synopsis

Documentation

type family Include (name :: Symbol) model Source #

newtype Id' (table :: Symbol) Source #

Constructors

Id (PrimaryKey table) 

Instances

Instances details
FromJSON (PrimaryKey a) => FromJSON (Id' a) Source # 
Instance details

Defined in IHP.ModelSupport

Methods

parseJSON :: Value -> Parser (Id' a) #

parseJSONList :: Value -> Parser [Id' a] #

omittedField :: Maybe (Id' a) #

ToJSON (PrimaryKey a) => ToJSON (Id' a) Source # 
Instance details

Defined in IHP.ModelSupport

Methods

toJSON :: Id' a -> Value #

toEncoding :: Id' a -> Encoding #

toJSONList :: [Id' a] -> Value #

toEncodingList :: [Id' a] -> Encoding #

omitField :: Id' a -> Bool #

(KnownSymbol table, Data (PrimaryKey table)) => Data (Id' table) Source # 
Instance details

Defined in IHP.ModelSupport

Methods

gfoldl :: (forall d b. Data d => c (d -> b) -> d -> c b) -> (forall g. g -> c g) -> Id' table -> c (Id' table) #

gunfold :: (forall b r. Data b => c (b -> r) -> c r) -> (forall r. r -> c r) -> Constr -> c (Id' table) #

toConstr :: Id' table -> Constr #

dataTypeOf :: Id' table -> DataType #

dataCast1 :: Typeable t => (forall d. Data d => c (t d)) -> Maybe (c (Id' table)) #

dataCast2 :: Typeable t => (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c (Id' table)) #

gmapT :: (forall b. Data b => b -> b) -> Id' table -> Id' table #

gmapQl :: (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> Id' table -> r #

gmapQr :: forall r r'. (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> Id' table -> r #

gmapQ :: (forall d. Data d => d -> u) -> Id' table -> [u] #

gmapQi :: Int -> (forall d. Data d => d -> u) -> Id' table -> u #

gmapM :: Monad m => (forall d. Data d => d -> m d) -> Id' table -> m (Id' table) #

gmapMp :: MonadPlus m => (forall d. Data d => d -> m d) -> Id' table -> m (Id' table) #

gmapMo :: MonadPlus m => (forall d. Data d => d -> m d) -> Id' table -> m (Id' table) #

(Read (PrimaryKey model), ParsePrimaryKey (PrimaryKey model)) => IsString (Id' model) Source #

Sometimes you have a hardcoded UUID value which represents some record id. This instance allows you to write the Id like a string:

let projectId = "ca63aace-af4b-4e6c-bcfa-76ca061dbdc6" :: Id Project
Instance details

Defined in IHP.ModelSupport

Methods

fromString :: String -> Id' model #

Show (PrimaryKey model) => Show (Id' model) Source # 
Instance details

Defined in IHP.ModelSupport

Methods

showsPrec :: Int -> Id' model -> ShowS #

show :: Id' model -> String

showList :: [Id' model] -> ShowS #

PrimaryKey table ~ UUID => Serialize (Id' table) 
Instance details

Defined in IHP.Controller.Session

Methods

put :: Putter (Id' table)

get :: Get (Id' table)

(KnownSymbol table, NFData (PrimaryKey table)) => NFData (Id' table) Source # 
Instance details

Defined in IHP.ModelSupport

Methods

rnf :: Id' table -> () #

Eq (PrimaryKey table) => Eq (Id' table) Source # 
Instance details

Defined in IHP.ModelSupport

Methods

(==) :: Id' table -> Id' table -> Bool #

(/=) :: Id' table -> Id' table -> Bool #

Ord (PrimaryKey table) => Ord (Id' table) Source # 
Instance details

Defined in IHP.ModelSupport

Methods

compare :: Id' table -> Id' table -> Ordering #

(<) :: Id' table -> Id' table -> Bool #

(<=) :: Id' table -> Id' table -> Bool #

(>) :: Id' table -> Id' table -> Bool #

(>=) :: Id' table -> Id' table -> Bool #

max :: Id' table -> Id' table -> Id' table #

min :: Id' table -> Id' table -> Id' table #

Hashable (PrimaryKey table) => Hashable (Id' table) Source # 
Instance details

Defined in IHP.ModelSupport

Methods

hashWithSalt :: Int -> Id' table -> Int #

hash :: Id' table -> Int #

InputValue (PrimaryKey table) => ApplyAttribute (Id' table) 
Instance details

Defined in IHP.ViewSupport

Methods

applyAttribute :: Text -> Text -> Id' table -> Html -> Html

ParamReader (PrimaryKey model') => ParamReader (Id' model') Source # 
Instance details

Defined in IHP.Controller.Param

IsEmpty (PrimaryKey table) => IsEmpty (Id' table) Source # 
Instance details

Defined in IHP.ModelSupport

Methods

isEmpty :: Id' table -> Bool Source #

InputValue (PrimaryKey model') => InputValue (Id' model') Source # 
Instance details

Defined in IHP.ModelSupport

Methods

inputValue :: Id' model' -> Text Source #

FromField (PrimaryKey model) => FromField (Id' model) Source # 
Instance details

Defined in IHP.ModelSupport

Methods

fromField :: FieldParser (Id' model)

ToField (PrimaryKey model) => ToField (Id' model) Source # 
Instance details

Defined in IHP.ModelSupport

Methods

toField :: Id' model -> Action

(model ~ GetModelById (Id' table), GetTableName model ~ table, FilterPrimaryKey table) => Fetchable (Id' table) model Source # 
Instance details

Defined in IHP.Fetch

Associated Types

type FetchResult (Id' table) model 
Instance details

Defined in IHP.Fetch

type FetchResult (Id' table) model = model

Methods

fetch :: Id' table -> IO (FetchResult (Id' table) model) Source #

fetchOneOrNothing :: Id' table -> IO (Maybe model) Source #

fetchOne :: Id' table -> IO model Source #

(model ~ GetModelById (Id' table), GetTableName model ~ table, FilterPrimaryKey table) => Fetchable (Maybe (Id' table)) model Source # 
Instance details

Defined in IHP.Fetch

Associated Types

type FetchResult (Maybe (Id' table)) model 
Instance details

Defined in IHP.Fetch

type FetchResult (Maybe (Id' table)) model = [model]

Methods

fetch :: Maybe (Id' table) -> IO (FetchResult (Maybe (Id' table)) model) Source #

fetchOneOrNothing :: Maybe (Id' table) -> IO (Maybe model) Source #

fetchOne :: Maybe (Id' table) -> IO model Source #

(model ~ GetModelById (Id' table), GetModelByTableName table ~ model, GetTableName model ~ table) => Fetchable [Id' table] model Source # 
Instance details

Defined in IHP.Fetch

Associated Types

type FetchResult [Id' table] model 
Instance details

Defined in IHP.Fetch

type FetchResult [Id' table] model = [model]

Methods

fetch :: [Id' table] -> IO (FetchResult [Id' table] model) Source #

fetchOneOrNothing :: [Id' table] -> IO (Maybe model) Source #

fetchOne :: [Id' table] -> IO model Source #

(TypeError (('Text "Looks like you forgot to pass a " ':<>: 'ShowType (GetModelByTableName record)) ':<>: 'Text " id to this data constructor.") :: Constraint) => Eq (Id' record -> controller) Source # 
Instance details

Defined in IHP.ViewSupport

Methods

(==) :: (Id' record -> controller) -> (Id' record -> controller) -> Bool #

(/=) :: (Id' record -> controller) -> (Id' record -> controller) -> Bool #

type FetchResult (Id' table) model Source # 
Instance details

Defined in IHP.Fetch

type FetchResult (Id' table) model = model
type FetchResult (Maybe (Id' table)) model Source # 
Instance details

Defined in IHP.Fetch

type FetchResult (Maybe (Id' table)) model = [model]
type FetchResult [Id' table] model Source # 
Instance details

Defined in IHP.Fetch

type FetchResult [Id' table] model = [model]

type family PrimaryKey (tableName :: Symbol) Source #

Provides the primary key type for a given table. The instances are usually declared by the generated haskell code in Generated.Types

Example: Defining the primary key for a users table

type instance PrimaryKey "users" = UUID

Example: Defining the primary key for a table with a SERIAL pk

type instance PrimaryKey "projects" = Int

type family GetModelByTableName (tableName :: Symbol) Source #

class KnownSymbol (GetTableName record) => Table record where Source #

Access meta data for a database table

Methods

tableName :: Text Source #

Returns the table name of a given model.

Example:

>>> tableName @User
"users"

tableNameByteString :: ByteString Source #

Returns the table name of a given model as a bytestring.

Example:

>>> tableNameByteString @User
"users"

columnNames :: [ByteString] Source #

Returns the list of column names for a given model

Example:

>>> columnNames @User
["id", "email", "created_at"]

primaryKeyColumnNames :: [ByteString] Source #

Returns the list of column names, that are contained in the primary key for a given model

Example:

>>> primaryKeyColumnNames @User
["id"]
>>> primaryKeyColumnNames @PostTagging
["post_id", "tag_id"]

primaryKeyConditionForId :: Id record -> Action Source #

Returns the parameters for a WHERE conditions to match an entity by it's primary key, given the entities id

For tables with a simple primary key this simply the id:

>>> primaryKeyConditionForId project.id
Plain "d619f3cf-f355-4614-8a4c-e9ea4f301e39"

If the table has a composite primary key, this returns multiple elements:

>>> primaryKeyConditionForId postTag.id
Many [Plain "(", Plain "0ace9270-568f-4188-b237-3789aa520588", Plain ",", Plain "0b58fdf5-4bbb-4e57-a5b7-aa1c57148e1c", Plain ")"]

The order of the elements for a composite primary key must match the order of the columns returned by primaryKeyColumnNames

data FieldWithDefault valueType Source #

Represents fields that have a default value in an SQL schema

The Default constructor represents the default value from the schema, while the NonDefault constructor holds some other value for the field

Constructors

Default 
NonDefault valueType 

Instances

Instances details
Show valueType => Show (FieldWithDefault valueType) Source # 
Instance details

Defined in IHP.ModelSupport

Methods

showsPrec :: Int -> FieldWithDefault valueType -> ShowS #

show :: FieldWithDefault valueType -> String

showList :: [FieldWithDefault valueType] -> ShowS #

Eq valueType => Eq (FieldWithDefault valueType) Source # 
Instance details

Defined in IHP.ModelSupport

Methods

(==) :: FieldWithDefault valueType -> FieldWithDefault valueType -> Bool #

(/=) :: FieldWithDefault valueType -> FieldWithDefault valueType -> Bool #

ToField valueType => ToField (FieldWithDefault valueType) Source # 
Instance details

Defined in IHP.ModelSupport

Methods

toField :: FieldWithDefault valueType -> Action

class Record model where Source #

Methods

newRecord :: model Source #

data Violation Source #

The error message of a validator can be either a plain text value or a HTML formatted value

Constructors

TextViolation

Plain text validation error, like "cannot be empty"

Fields

HtmlViolation

HTML formatted, already pre-escaped validation error, like "Invalid, please href="http://example.com"check the documentation/a"

Fields

Instances

Instances details
Show Violation Source # 
Instance details

Defined in IHP.ModelSupport

Methods

showsPrec :: Int -> Violation -> ShowS #

show :: Violation -> String

showList :: [Violation] -> ShowS #

Eq Violation Source # 
Instance details

Defined in IHP.ModelSupport

SetField "annotations" MetaBag [(Text, Violation)] Source # 
Instance details

Defined in IHP.ModelSupport

getModelName :: KnownSymbol (GetModelName model) => Text Source #

Returns the model name of a given model as Text

Example:

>>> modelName @User
"User"
>>> modelName @Project
"Project"

class InputValue a where Source #

Methods

inputValue :: a -> Text Source #

Instances

Instances details
InputValue Value Source # 
Instance details

Defined in IHP.ModelSupport

InputValue PGInterval Source # 
Instance details

Defined in IHP.ModelSupport

InputValue JobStatus Source # 
Instance details

Defined in IHP.Job.Queue

InputValue Scientific Source # 
Instance details

Defined in IHP.ModelSupport

Methods

inputValue :: Scientific -> Text Source #

InputValue Text Source # 
Instance details

Defined in IHP.ModelSupport

Methods

inputValue :: Text -> Text Source #

InputValue Day Source # 
Instance details

Defined in IHP.ModelSupport

Methods

inputValue :: Day -> Text Source #

InputValue UTCTime Source # 
Instance details

Defined in IHP.ModelSupport

InputValue LocalTime Source # 
Instance details

Defined in IHP.ModelSupport

InputValue TimeOfDay Source # 
Instance details

Defined in IHP.ModelSupport

InputValue UUID Source # 
Instance details

Defined in IHP.ModelSupport

Methods

inputValue :: UUID -> Text Source #

InputValue Integer Source # 
Instance details

Defined in IHP.ModelSupport

InputValue () Source # 
Instance details

Defined in IHP.ModelSupport

Methods

inputValue :: () -> Text Source #

InputValue Bool Source # 
Instance details

Defined in IHP.ModelSupport

Methods

inputValue :: Bool -> Text Source #

InputValue Double Source # 
Instance details

Defined in IHP.ModelSupport

InputValue Float Source # 
Instance details

Defined in IHP.ModelSupport

InputValue Int Source # 
Instance details

Defined in IHP.ModelSupport

Methods

inputValue :: Int -> Text Source #

InputValue (PrimaryKey model') => InputValue (Id' model') Source # 
Instance details

Defined in IHP.ModelSupport

Methods

inputValue :: Id' model' -> Text Source #

InputValue fieldType => InputValue (Maybe fieldType) Source # 
Instance details

Defined in IHP.ModelSupport

Methods

inputValue :: Maybe fieldType -> Text Source #

InputValue value => InputValue [value] Source # 
Instance details

Defined in IHP.ModelSupport

Methods

inputValue :: [value] -> Text Source #

isNew :: HasField "meta" model MetaBag => model -> Bool Source #

Returns True when the record has not been saved to the database yet. Returns False otherwise.

Example: Returns True when a record has not been inserted yet.

>>> let project = newRecord @Project
>>> isNew project
True

Example: Returns False after inserting a record.

>>> project <- createRecord project
>>> isNew project
False

Example: Returns False for records which have been fetched from the database.

>>> book <- query @Book |> fetchOne
>>> isNew book
False

didTouchField :: forall (fieldName :: Symbol) fieldValue record. (KnownSymbol fieldName, HasField fieldName record fieldValue, HasField "meta" record MetaBag, Eq fieldValue, Typeable record) => Proxy fieldName -> record -> Bool Source #

Returns True if set was called on that field

Example: Returns False for freshly fetched records

>>> let projectId = "227fbba3-0578-4eb8-807d-b9b692c3644f" :: Id Project
>>> project <- fetch projectId
>>> didTouchField #name project
False

Example: Returns True after setting a field

>>> let projectId = "227fbba3-0578-4eb8-807d-b9b692c3644f" :: Id Project
>>> project <- fetch projectId
>>> project |> set #name project.name |> didTouchField #name
True

withTransaction :: (?modelContext :: ModelContext) => ((?modelContext :: ModelContext) => IO a) -> IO a Source #

Executes the given block with a database transaction

Example:

withTransaction do
   company <- newRecord @Company |> createRecord

   -- When creating the user fails, there will be no company left over
   user <- newRecord @User
       |> set #companyId company.id
       |> createRecord

   company <- company
       |> set #ownerId user.id
       |> updateRecord

type Id model = Id' (GetTableName model) Source #

We need to map the model to its table name to prevent infinite recursion in the model data definition E.g. `type Project = Project' { id :: Id Project }` will not work But `type Project = Project' { id :: Id "projects" }` will

sqlQuery :: (?modelContext :: ModelContext, ToRow q, FromRow r) => Query -> q -> IO [r] Source #

Runs a raw sql query

Example:

users <- sqlQuery "SELECT id, firstname, lastname FROM users" ()

Take a look at IHP.QueryBuilder for a typesafe approach on building simple queries.

  • AutoRefresh:* When using sqlQuery with AutoRefresh, you need to use trackTableRead to let AutoRefresh know that you have accessed a certain table. Otherwise AutoRefresh will not watch table of your custom sql query.

Use sqlQuerySingleRow if you expect only a single row to be returned.

sqlQueryScalar :: (?modelContext :: ModelContext, ToRow q, FromField value) => Query -> q -> IO value Source #

Runs a raw sql query which results in a single scalar value such as an integer or string

Example:

usersCount <- sqlQueryScalar "SELECT COUNT(*) FROM users"

Take a look at IHP.QueryBuilder for a typesafe approach on building simple queries.

data ModelContext Source #

Provides the db connection and some IHP-specific db configuration

Constructors

ModelContext 

Fields

class CanUpdate a where Source #

Minimal complete definition

updateRecord

Methods

updateRecord :: a -> IO a Source #

updateRecordDiscardResult :: a -> IO () Source #

Like updateRecord but doesn't return the updated record

type NormalizeModel model = GetModelByTableName (GetTableName model) Source #

Helper type to deal with models where relations are included or that are only partially fetched Examples:

>>> NormalizeModel (Include "author_id" Post)
Post
>>> NormalizeModel Post
Post

type family GetTableName model :: Symbol Source #

type family GetModelName model :: Symbol Source #

createRecord :: (?modelContext :: ModelContext, CanCreate model) => model -> IO model Source #

deleteRecord :: forall record (table :: Symbol). (?modelContext :: ModelContext, Table record, Show (PrimaryKey table), HasField "id" record (Id record), GetTableName record ~ table, record ~ GetModelByTableName table) => record -> IO () Source #

Runs a DELETE query for a record.

>>> let project :: Project = ...
>>> deleteRecord project
DELETE FROM projects WHERE id = '..'

Use deleteRecords if you want to delete multiple records.

data MetaBag Source #

Every IHP database record has a magic meta field which keeps a MetaBag inside. This data structure is used e.g. to keep track of the validation errors that happend.

Constructors

MetaBag 

Fields

  • annotations :: ![(Text, Violation)]

    Stores validation failures, as a list of (field name, error) pairs. E.g. annotations = [ ("name", TextViolation "cannot be empty") ]

  • touchedFields :: ![Text]

    Whenever a set is callled on a field, it will be marked as touched. Only touched fields are saved to the database when you call updateRecord

  • originalDatabaseRecord :: Maybe Dynamic

    When the record has been fetched from the database, we save the initial database record here. This is used by didChange to check if a field value is different from the initial database value.

Instances

Instances details
Show MetaBag Source # 
Instance details

Defined in IHP.ModelSupport

Methods

showsPrec :: Int -> MetaBag -> ShowS #

show :: MetaBag -> String

showList :: [MetaBag] -> ShowS #

Default MetaBag Source # 
Instance details

Defined in IHP.ModelSupport

Methods

def :: MetaBag #

Eq MetaBag Source # 
Instance details

Defined in IHP.ModelSupport

Methods

(==) :: MetaBag -> MetaBag -> Bool #

(/=) :: MetaBag -> MetaBag -> Bool #

SetField "annotations" MetaBag [(Text, Violation)] Source # 
Instance details

Defined in IHP.ModelSupport

SetField "touchedFields" MetaBag [Text] Source # 
Instance details

Defined in IHP.ModelSupport

Methods

setField :: [Text] -> MetaBag -> MetaBag Source #

class CanCreate a where Source #

Minimal complete definition

create, createMany

Methods

create :: a -> IO a Source #

createMany :: [a] -> IO [a] Source #

createRecordDiscardResult :: a -> IO () Source #

Like createRecord but doesn't return the created record

data RowLevelSecurityContext Source #

When row level security is enabled at runtime, this keeps track of the current logged in user and the postgresql role to switch to.

Constructors

RowLevelSecurityContext 

Fields

  • rlsAuthenticatedRole :: Text

    Default is ihp_authenticated. This value comes from the IHP_RLS_AUTHENTICATED_ROLE env var.

  • rlsUserId :: Action

    The user id of the current logged in user

notConnectedModelContext :: Logger -> ModelContext Source #

Provides a mock ModelContext to be used when a database connection is not available

type family GetModelById id where ... Source #

Equations

GetModelById (Maybe (Id' tableName)) = Maybe (GetModelByTableName tableName) 
GetModelById (Id' tableName) = GetModelByTableName tableName 

unpackId :: forall (model :: Symbol). Id' model -> PrimaryKey model Source #

Unwraps a Id value into an UUID

>>> unpackId ("296e5a50-b237-4ee9-83b0-17fb1e6f208f" :: Id User)
"296e5a50-b237-4ee9-83b0-17fb1e6f208f" :: UUID

recordToInputValue :: (HasField "id" entity (Id entity), Show (PrimaryKey (GetTableName entity))) => entity -> Text Source #

packId :: forall (model :: Symbol). PrimaryKey model -> Id' model Source #

Turns an UUID into a Id type

let uuid :: UUID = "5240e79c-97ff-4a5f-8567-84112541aaba"
let userId :: Id User = packId uuid

data LabeledData a b Source #

Record type for objects of model types labeled with values from different database tables. (e.g. comments labeled with the IDs of the posts they belong to).

Constructors

LabeledData 

Fields

Instances

Instances details
(Show a, Show b) => Show (LabeledData a b) Source # 
Instance details

Defined in IHP.ModelSupport

Methods

showsPrec :: Int -> LabeledData a b -> ShowS #

show :: LabeledData a b -> String

showList :: [LabeledData a b] -> ShowS #

(FromField label, FromRow a) => FromRow (LabeledData label a) Source # 
Instance details

Defined in IHP.ModelSupport

Methods

fromRow :: RowParser (LabeledData label a)

class ParsePrimaryKey primaryKey where Source #

Methods

parsePrimaryKey :: Text -> Maybe primaryKey Source #

Instances

Instances details
ParsePrimaryKey Text Source # 
Instance details

Defined in IHP.ModelSupport

ParsePrimaryKey UUID Source # 
Instance details

Defined in IHP.ModelSupport

textToId :: forall (model :: Symbol) text. (HasCallStack, ParsePrimaryKey (PrimaryKey model), ConvertibleStrings text Text) => text -> Id' model Source #

Transforms a text, bytestring or string into an Id. Throws an exception if the input is invalid.

Example:

let projectIdText = "7cbc76e2-1c4f-49b6-a7d9-5015e7575a9b" :: Text
let projectId = (textToId projectIdText) :: Id Project

In case your UUID value is hardcoded, there is also an IsString instance, so you can just write it like:

let projectId = "ca63aace-af4b-4e6c-bcfa-76ca061dbdc6" :: Id Project

measureTimeIfLogging :: (?modelContext :: ModelContext, ToRow q) => IO a -> Query -> q -> IO a Source #

Measure and log the query time for a given query action if the log level is Debug. If the log level is greater than debug, just perform the query action without measuring time.

logQuery :: (?modelContext :: ModelContext, ToRow parameters) => Query -> parameters -> NominalDiffTime -> IO () Source #

withDatabaseConnection :: (?modelContext :: ModelContext) => (Connection -> IO a) -> IO a Source #

enhanceSqlError :: ToRow parameters => Query -> parameters -> IO a -> IO a Source #

Catches SqlError and wraps them in EnhancedSqlError

withRLSParams :: (?modelContext :: ModelContext, ToRow params) => (Query -> [Action] -> result) -> Query -> params -> result Source #

Wraps the query with Row level security boilerplate, if a row level security context was provided

Example:

If a row level security context is given, this will turn a query like the following

withRLSParams runQuery "SELECT * FROM projects WHERE id = ?" (Only "..")

Into the following equivalent:

runQuery "SET LOCAL ROLE ?; SET LOCAL rls.ihp_user_id = ?; SELECT * FROM projects WHERE id = ?" ["ihp_authenticated", "<user id>", .."]

sqlQuerySingleRow :: (?modelContext :: ModelContext, ToRow query, FromRow record) => Query -> query -> IO record Source #

Runs a raw sql query, that is expected to return a single result row

Like sqlQuery, but useful when you expect only a single row as the result

Example:

user <- sqlQuerySingleRow "SELECT id, firstname, lastname FROM users WHERE id = ?" (Only user.id)

Take a look at IHP.QueryBuilder for a typesafe approach on building simple queries.

  • AutoRefresh:* When using sqlQuerySingleRow with AutoRefresh, you need to use trackTableRead to let AutoRefresh know that you have accessed a certain table. Otherwise AutoRefresh will not watch table of your custom sql query.

sqlExec :: (?modelContext :: ModelContext, ToRow q) => Query -> q -> IO Int64 Source #

Runs a sql statement (like a CREATE statement)

Example:

sqlExec "CREATE TABLE users ()" ()

sqlExecDiscardResult :: (?modelContext :: ModelContext, ToRow q) => Query -> q -> IO () Source #

Runs a sql statement (like a CREATE statement), but doesn't return any result

Example:

sqlExecDiscardResult "CREATE TABLE users ()" ()

sqlQueryScalarOrNothing :: (?modelContext :: ModelContext, ToRow q, FromField value) => Query -> q -> IO (Maybe value) Source #

Runs a raw sql query which results in a single scalar value such as an integer or string, or nothing

Example:

usersCount <- sqlQueryScalarOrNothing "SELECT COUNT(*) FROM users"

Take a look at IHP.QueryBuilder for a typesafe approach on building simple queries.

withTransactionConnection :: (?modelContext :: ModelContext) => ((?modelContext :: ModelContext) => IO a) -> IO a Source #

withRowLevelSecurityDisabled :: (?modelContext :: ModelContext) => ((?modelContext :: ModelContext) => IO a) -> IO a Source #

Executes the given block with the main database role and temporarly sidesteps the row level security policies.

This is used e.g. by IHP AutoRefresh to be able to set up it's database triggers. When trying to set up a database trigger from the ihp_authenticated role, it typically fails because it's missing permissions. Using withRowLevelSecurityDisabled we switch to the main role which is allowed to set up database triggers.

SQL queries run from within the passed block are executed in their own transaction.

Example:

-- SQL code executed here might be run from the ihp_authenticated role
withRowLevelSecurityDisabled do
   -- SQL code executed here is run as the main IHP db role
   sqlExec "CREATE OR REPLACE FUNCTION .." ()

transactionConnectionOrError :: (?modelContext :: ModelContext) => Connection Source #

Returns the postgres connection when called within a withTransaction block

Throws an error if called from outside a withTransaction

commitTransaction :: (?modelContext :: ModelContext) => IO () Source #

rollbackTransaction :: (?modelContext :: ModelContext) => IO () Source #

primaryKeyConditionColumnSelector :: Table record => ByteString Source #

Returns ByteString, that represents the part of an SQL where clause, that matches on a tuple consisting of all the primary keys For table with simple primary keys this simply returns the name of the primary key column, without wrapping in a tuple >>> primaryKeyColumnSelector PostTag "(post_tags.post_id, post_tags.tag_id)" >>> primaryKeyColumnSelector Post "post_tags.post_id"

primaryKeyCondition :: (HasField "id" record (Id record), Table record) => record -> Action Source #

Returns WHERE conditions to match an entity by it's primary key

For tables with a simple primary key this returns a tuple with the id:

>>> primaryKeyCondition project
Plain "d619f3cf-f355-4614-8a4c-e9ea4f301e39"

If the table has a composite primary key, this returns multiple elements:

>>> primaryKeyCondition postTag
Many [Plain "(", Plain "0ace9270-568f-4188-b237-3789aa520588", Plain ",", Plain "0b58fdf5-4bbb-4e57-a5b7-aa1c57148e1c", Plain ")"]

deleteRecordById :: forall record (table :: Symbol). (?modelContext :: ModelContext, Table record, Show (PrimaryKey table), GetTableName record ~ table, record ~ GetModelByTableName table) => Id' table -> IO () Source #

Like deleteRecord but using an Id

>>> let project :: Id Project = ...
>>> delete projectId
DELETE FROM projects WHERE id = '..'

deleteRecords :: forall record (table :: Symbol). (?modelContext :: ModelContext, Show (PrimaryKey table), Table record, HasField "id" record (Id' table), GetTableName record ~ table, record ~ GetModelByTableName table) => [record] -> IO () Source #

Runs a DELETE query for a list of records.

>>> let projects :: [Project] = ...
>>> deleteRecords projects
DELETE FROM projects WHERE id IN (..)

deleteRecordByIds :: forall record (table :: Symbol). (?modelContext :: ModelContext, Show (PrimaryKey table), Table record, GetTableName record ~ table, record ~ GetModelByTableName table) => [Id' table] -> IO () Source #

Like deleteRecordById but for a list of Ids.

>>> let projectIds :: [ Id Project ] = ...
>>> delete projectIds
DELETE FROM projects WHERE id IN ('..')

ids :: HasField "id" record id => [record] -> [id] Source #

Returns the ids for a list of models

Shorthand for map (.id) records.

>>> users <- query @User |> fetch
>>> ids users
[227fbba3-0578-4eb8-807d-b9b692c3644f, 9d7874f2-5343-429b-bcc4-8ee62a5a6895, ...] :: [Id User]

deleteAll :: (?modelContext :: ModelContext, Table record) => IO () Source #

Runs a DELETE query to delete all rows in a table.

>>> deleteAll @Project
DELETE FROM projects

type family Include' (name :: [Symbol]) model where ... Source #

Equations

Include' ('[] :: [Symbol]) model = model 
Include' (x ': xs) model = Include' xs (Include x model) 

didChangeRecord :: HasField "meta" record MetaBag => record -> Bool Source #

Returns True if any fields of the record have unsaved changes

Example: Returns False for freshly fetched records

>>> let projectId = "227fbba3-0578-4eb8-807d-b9b692c3644f" :: Id Project
>>> project <- fetch projectId
>>> didChangeRecord project
False

Example: Returns True after setting a field

>>> let projectId = "227fbba3-0578-4eb8-807d-b9b692c3644f" :: Id Project
>>> project <- fetch projectId
>>> project |> set #name "New Name" |> didChangeRecord
True

didChange :: forall (fieldName :: Symbol) fieldValue record. (KnownSymbol fieldName, HasField fieldName record fieldValue, HasField "meta" record MetaBag, Eq fieldValue, Typeable record) => Proxy fieldName -> record -> Bool Source #

Returns True if the specific field of the record has unsaved changes

Example: Returns False for freshly fetched records

>>> let projectId = "227fbba3-0578-4eb8-807d-b9b692c3644f" :: Id Project
>>> project <- fetch projectId
>>> didChange #name project
False

Example: Returns True after setting a field

>>> let projectId = "227fbba3-0578-4eb8-807d-b9b692c3644f" :: Id Project
>>> project <- fetch projectId
>>> project |> set #name "New Name" |> didChange #name
True

Example: Setting a flash message after updating the profile picture

when (user |> didChange #profilePictureUrl) (setSuccessMessage "Your Profile Picture has been updated. It might take a few minutes until it shows up everywhere")

fieldWithDefault :: forall (name :: Symbol) model value. (KnownSymbol name, HasField name model value, HasField "meta" model MetaBag) => Proxy name -> model -> FieldWithDefault value Source #

Construct a FieldWithDefault

Use the default SQL value when the field hasn't been touched since the record was created. This information is stored in the touchedFields attribute of the meta field.

data FieldWithUpdate (name :: k) value Source #

Represents fields that may have been updated

The NoUpdate constructor represents the existing value in the database, while the Update constructor holds some new value for the field

Constructors

NoUpdate (Proxy name) 
Update value 

Instances

Instances details
Show value => Show (FieldWithUpdate name value) Source # 
Instance details

Defined in IHP.ModelSupport

Methods

showsPrec :: Int -> FieldWithUpdate name value -> ShowS #

show :: FieldWithUpdate name value -> String

showList :: [FieldWithUpdate name value] -> ShowS #

Eq value => Eq (FieldWithUpdate name value) Source # 
Instance details

Defined in IHP.ModelSupport

Methods

(==) :: FieldWithUpdate name value -> FieldWithUpdate name value -> Bool #

(/=) :: FieldWithUpdate name value -> FieldWithUpdate name value -> Bool #

(KnownSymbol name, ToField value) => ToField (FieldWithUpdate name value) Source # 
Instance details

Defined in IHP.ModelSupport

Methods

toField :: FieldWithUpdate name value -> Action

fieldWithUpdate :: forall (name :: Symbol) model value. (KnownSymbol name, HasField name model value, HasField "meta" model MetaBag) => Proxy name -> model -> FieldWithUpdate name value Source #

Construct a FieldWithUpdate

Use the current database value when the field hasn't been touched since the record was accessed. This information is stored in the touchedFields attribute of the meta field.

data EnhancedSqlError Source #

Whenever calls to query or execute raise an SqlError exception, we wrap that exception in this data structure. This allows us to show the actual database query that has triggered the error.

Constructors

EnhancedSqlError 

Fields

trackTableRead :: (?modelContext :: ModelContext) => ByteString -> IO () Source #

Useful to manually mark a table read when doing a custom sql query inside AutoRefresh or withTableReadTracker.

When using fetch on a query builder, this function is automatically called. That's why you only need to call it yourself when using sqlQuery to run a custom query.

Example:

action MyAction = autoRefresh do
    users <- sqlQuery "SELECT * FROM users WHERE .."
    trackTableRead "users"

    render MyView { .. }

withTableReadTracker :: (?modelContext :: ModelContext) => ((?modelContext :: ModelContext, ?touchedTables :: IORef (Set ByteString)) => IO ()) -> IO () Source #

Track all tables in SELECT queries executed within the given IO action.

You can read the touched tables by this function by accessing the variable ?touchedTables inside your given IO action.

Example:

withTableReadTracker do
    project <- query @Project |> fetchOne
    user <- query @User |> fetchOne

    tables <- readIORef ?touchedTables
    -- tables = Set.fromList ["projects", "users"]

onlyWhere :: forall record (fieldName :: Symbol) value. (KnownSymbol fieldName, HasField fieldName record value, Eq value) => Proxy fieldName -> value -> [record] -> [record] Source #

Shorthand filter function

In IHP code bases you often write filter functions such as these:

getUserPosts user posts =
    filter (\p -> p.userId == user.id) posts

This can be written in a shorter way using onlyWhere:

getUserPosts user posts =
    posts |> onlyWhere #userId user.id

Because the userId field is an Id, we can use onlyWhereReferences to make it even shorter:

getUserPosts user posts =
    posts |> onlyWhereReferences #userId user

If the Id field is nullable, we need to use onlyWhereReferencesMaybe:

getUserTasks user tasks =
    tasks |> onlyWhereReferencesMaybe #optionalUserId user

onlyWhereReferences :: forall record (fieldName :: Symbol) value referencedRecord. (KnownSymbol fieldName, HasField fieldName record value, Eq value, HasField "id" referencedRecord value) => Proxy fieldName -> referencedRecord -> [record] -> [record] Source #

Shorthand filter function for Id fields

In IHP code bases you often write filter functions such as these:

getUserPosts user posts =
    filter (\p -> p.userId == user.id) posts

This can be written in a shorter way using onlyWhereReferences:

getUserPosts user posts =
    posts |> onlyWhereReferences #userId user

If the Id field is nullable, we need to use onlyWhereReferencesMaybe:

getUserTasks user tasks =
    tasks |> onlyWhereReferencesMaybe #optionalUserId user

See onlyWhere for more details.

onlyWhereReferencesMaybe :: forall record (fieldName :: Symbol) value referencedRecord. (KnownSymbol fieldName, HasField fieldName record (Maybe value), Eq value, HasField "id" referencedRecord value) => Proxy fieldName -> referencedRecord -> [record] -> [record] Source #

Shorthand filter function for nullable Id fields

In IHP code bases you often write filter functions such as these:

getUserTasks user tasks =
    filter (\task -> task.optionalUserId == Just user.id) tasks

This can be written in a shorter way using onlyWhereReferencesMaybe:

getUserTasks user tasks =
    tasks |> onlyWhereReferencesMaybe #optionalUserId user

See onlyWhere for more details.

isValid :: HasField "meta" record MetaBag => record -> Bool Source #

Returns True when a record has no validation errors attached from a previous validation call

Example:

isValidProject :: Project -> Bool
isValidProject project =
    project
    |> validateField #name isNonEmpty
    |> isValid

copyRecord :: (Table record, SetField "id" record id, Default id, SetField "meta" record MetaBag) => record -> record Source #

Copies all the fields (except the id field) into a new record

Example: Duplicate a database record (except the primary key of course)

project <- fetch projectId
duplicatedProject <- createRecord (copyRecord project)

data Point #

Constructors

Point 

Fields

Instances

Instances details
FromJSON Point 
Instance details

Defined in IHP.Postgres.Point

Methods

parseJSON :: Value -> Parser Point #

parseJSONList :: Value -> Parser [Point] #

omittedField :: Maybe Point #

ToJSON Point 
Instance details

Defined in IHP.Postgres.Point

Show Point 
Instance details

Defined in IHP.Postgres.Point

Methods

showsPrec :: Int -> Point -> ShowS #

show :: Point -> String

showList :: [Point] -> ShowS #

Default Point Source # 
Instance details

Defined in IHP.ModelSupport

Methods

def :: Point #

Eq Point 
Instance details

Defined in IHP.Postgres.Point

Methods

(==) :: Point -> Point -> Bool #

(/=) :: Point -> Point -> Bool #

Ord Point 
Instance details

Defined in IHP.Postgres.Point

Methods

compare :: Point -> Point -> Ordering #

(<) :: Point -> Point -> Bool #

(<=) :: Point -> Point -> Bool #

(>) :: Point -> Point -> Bool #

(>=) :: Point -> Point -> Bool #

max :: Point -> Point -> Point #

min :: Point -> Point -> Point #

ParamReader Point Source # 
Instance details

Defined in IHP.Controller.Param

FromField Point 
Instance details

Defined in IHP.Postgres.Point

Methods

fromField :: FieldParser Point

ToField Point 
Instance details

Defined in IHP.Postgres.Point

Methods

toField :: Point -> Action

serializePoint :: Point -> Action #

data Polygon #

Constructors

Polygon 

Fields

Instances

Instances details
Show Polygon 
Instance details

Defined in IHP.Postgres.Polygon

Methods

showsPrec :: Int -> Polygon -> ShowS #

show :: Polygon -> String

showList :: [Polygon] -> ShowS #

Default Polygon Source # 
Instance details

Defined in IHP.ModelSupport

Methods

def :: Polygon #

Eq Polygon 
Instance details

Defined in IHP.Postgres.Polygon

Methods

(==) :: Polygon -> Polygon -> Bool #

(/=) :: Polygon -> Polygon -> Bool #

Ord Polygon 
Instance details

Defined in IHP.Postgres.Polygon

ParamReader Polygon Source # 
Instance details

Defined in IHP.Controller.Param

FromField Polygon 
Instance details

Defined in IHP.Postgres.Polygon

Methods

fromField :: FieldParser Polygon

ToField Polygon 
Instance details

Defined in IHP.Postgres.Polygon

Methods

toField :: Polygon -> Action

data TSVector #

Constructors

TSVector [Lexeme] 

Instances

Instances details
Show TSVector 
Instance details

Defined in IHP.Postgres.TSVector

Methods

showsPrec :: Int -> TSVector -> ShowS #

show :: TSVector -> String

showList :: [TSVector] -> ShowS #

Default TSVector Source # 
Instance details

Defined in IHP.ModelSupport

Methods

def :: TSVector #

Eq TSVector 
Instance details

Defined in IHP.Postgres.TSVector

Ord TSVector 
Instance details

Defined in IHP.Postgres.TSVector

FromField TSVector 
Instance details

Defined in IHP.Postgres.TSVector

Methods

fromField :: FieldParser TSVector

ToField TSVector 
Instance details

Defined in IHP.Postgres.TSVector

Methods

toField :: TSVector -> Action

data Lexeme #

Constructors

Lexeme 

Fields

Instances

Instances details
Show Lexeme 
Instance details

Defined in IHP.Postgres.TSVector

Methods

showsPrec :: Int -> Lexeme -> ShowS #

show :: Lexeme -> String

showList :: [Lexeme] -> ShowS #

Eq Lexeme 
Instance details

Defined in IHP.Postgres.TSVector

Methods

(==) :: Lexeme -> Lexeme -> Bool #

(/=) :: Lexeme -> Lexeme -> Bool #

Ord Lexeme 
Instance details

Defined in IHP.Postgres.TSVector

newtype PGInterval #

Constructors

PGInterval ByteString 

Instances

Instances details
Show PGInterval 
Instance details

Defined in IHP.Postgres.TimeParser

Methods

showsPrec :: Int -> PGInterval -> ShowS #

show :: PGInterval -> String

showList :: [PGInterval] -> ShowS #

Default PGInterval Source # 
Instance details

Defined in IHP.ModelSupport

Methods

def :: PGInterval #

Eq PGInterval 
Instance details

Defined in IHP.Postgres.TimeParser

ParamReader PGInterval Source # 
Instance details

Defined in IHP.Controller.Param

InputValue PGInterval Source # 
Instance details

Defined in IHP.ModelSupport

data PGTimeInterval #

Instances

Instances details
Show PGTimeInterval 
Instance details

Defined in IHP.Postgres.TimeParser

Eq PGTimeInterval 
Instance details

Defined in IHP.Postgres.TimeParser

pClockTime :: Parser (Int, Int, Pico) #

seconds :: Parser Pico #

toPico :: Integer -> Pico #

Orphan instances

Default Value Source # 
Instance details

Methods

def :: Value #

Default Point Source # 
Instance details

Methods

def :: Point #

Default Polygon Source # 
Instance details

Methods

def :: Polygon #

Default TSVector Source # 
Instance details

Methods

def :: TSVector #

Default PGInterval Source # 
Instance details

Methods

def :: PGInterval #

Default Scientific Source # 
Instance details

Methods

def :: Scientific #

Default Text Source # 
Instance details

Methods

def :: Text #

Default Day Source # 
Instance details

Methods

def :: Day #

Default NominalDiffTime Source # 
Instance details

Default UTCTime Source # 
Instance details

Methods

def :: UTCTime #

Default LocalTime Source # 
Instance details

Methods

def :: LocalTime #

Default TimeOfDay Source # 
Instance details

Methods

def :: TimeOfDay #

Default Bool Source # 
Instance details

Methods

def :: Bool #

Default (Binary ByteString) Source # 
Instance details

Methods

def :: Binary ByteString #

(FromField value, Typeable value) => FromField [value] Source #

This instancs allows us to avoid wrapping lists with PGArray when using sql types such as INT[]

Instance details

Methods

fromField :: FieldParser [value]

ToField value => ToField [value] Source #

This instance allows us to avoid wrapping lists with PGArray when using sql types such as INT[]

Instance details

Methods

toField :: [value] -> Action