| Safe Haskell | None |
|---|---|
| Language | GHC2021 |
IHP.ModelSupport
Contents
Synopsis
- class KnownSymbol (GetTableName record) => Table record where
- tableName :: Text
- columnNames :: [Text]
- primaryKeyColumnNames :: [Text]
- isValid :: HasField "meta" record MetaBag => record -> Bool
- ids :: HasField "id" record id => [record] -> [id]
- commitTransaction :: (?modelContext :: ModelContext) => IO ()
- withTransaction :: (?modelContext :: ModelContext) => ((?modelContext :: ModelContext) => IO a) -> IO a
- class Record model where
- newRecord :: model
- getModelName :: KnownSymbol (GetModelName model) => Text
- isNew :: HasField "meta" model MetaBag => model -> Bool
- didTouchField :: forall (fieldName :: Symbol) fieldValue record. (KnownSymbol fieldName, HasField fieldName record fieldValue, HasField "meta" record MetaBag, Eq fieldValue, Typeable record, FieldBit fieldName record) => Proxy fieldName -> record -> Bool
- notConnectedModelContext :: Logger -> ModelContext
- withModelContext :: ByteString -> Logger -> (ModelContext -> IO a) -> IO a
- createRecord :: (?modelContext :: ModelContext, CanCreate model) => model -> IO model
- deleteRecord :: forall record (table :: Symbol). (?modelContext :: ModelContext, Table record, Show (PrimaryKey table), HasField "id" record (Id record), GetTableName record ~ table, record ~ GetModelByTableName table, DefaultParamEncoder (Id' table)) => record -> IO ()
- createModelContext :: ByteString -> Logger -> IO ModelContext
- unpackId :: forall (model :: Symbol). Id' model -> PrimaryKey model
- sqlQueryHasql :: (?modelContext :: ModelContext) => Pool -> Snippet -> Result a -> IO a
- didChange :: forall (fieldName :: Symbol) fieldValue record. (KnownSymbol fieldName, HasField fieldName record fieldValue, HasField "meta" record MetaBag, Eq fieldValue, Typeable record, FieldBit fieldName record) => Proxy fieldName -> record -> Bool
- releaseModelContext :: ModelContext -> IO ()
- recordToInputValue :: (HasField "id" entity (Id entity), Show (PrimaryKey (GetTableName entity))) => entity -> Text
- packId :: forall (model :: Symbol). PrimaryKey model -> Id' model
- textToId :: forall (model :: Symbol) text. (HasCallStack, ParsePrimaryKey (PrimaryKey model), ConvertibleStrings text Text) => text -> Id' model
- unsafeSqlQuery :: (?modelContext :: ModelContext, ToSnippetParams q, FromRowHasql r) => Query -> q -> IO [r]
- sqlQuery :: (?modelContext :: ModelContext, ToSnippetParams q, FromRowHasql r) => Query -> q -> IO [r]
- unsafeSqlQuerySingleRow :: (?modelContext :: ModelContext, ToSnippetParams query, FromRowHasql record) => Query -> query -> IO record
- sqlQuerySingleRow :: (?modelContext :: ModelContext, ToSnippetParams query, FromRowHasql record) => Query -> query -> IO record
- unsafeSqlExec :: (?modelContext :: ModelContext, ToSnippetParams q) => Query -> q -> IO Int64
- sqlExecHasqlCount :: (?modelContext :: ModelContext) => Pool -> Snippet -> IO Int64
- sqlExec :: (?modelContext :: ModelContext, ToSnippetParams q) => Query -> q -> IO Int64
- unsafeSqlExecDiscardResult :: (?modelContext :: ModelContext, ToSnippetParams q) => Query -> q -> IO ()
- sqlExecHasql :: (?modelContext :: ModelContext) => Pool -> Snippet -> IO ()
- sqlExecDiscardResult :: (?modelContext :: ModelContext, ToSnippetParams q) => Query -> q -> IO ()
- setRLSConfigStatement :: Statement (Text, Text) ()
- sqlStatementHasql :: (?modelContext :: ModelContext) => Pool -> a -> Statement a b -> IO b
- logQueryTiming :: (?context :: ModelContext) => LogLevel -> Text -> IO a -> IO a
- truncateQuery :: Text -> Text
- sqlExecStatement :: (?modelContext :: ModelContext) => Pool -> a -> Statement a () -> IO ()
- runSessionHasql :: (?modelContext :: ModelContext) => Pool -> Session () -> IO ()
- data SessionRequest where
- SessionRequest :: forall a. Session a -> MVar (Either SessionError a) -> SessionRequest
- processRequests :: MVar (Maybe SessionRequest) -> Session ()
- unsafeSqlQueryScalar :: (?modelContext :: ModelContext, ToSnippetParams q, HasqlDecodeColumn value) => Query -> q -> IO value
- sqlQueryScalar :: (?modelContext :: ModelContext, ToSnippetParams q, HasqlDecodeColumn value) => Query -> q -> IO value
- unsafeSqlQueryScalarOrNothing :: (?modelContext :: ModelContext, ToSnippetParams q, HasqlDecodeColumn value) => Query -> q -> IO (Maybe value)
- sqlQueryScalarOrNothing :: (?modelContext :: ModelContext, ToSnippetParams q, HasqlDecodeColumn value) => Query -> q -> IO (Maybe value)
- withRowLevelSecurityDisabled :: (?modelContext :: ModelContext) => ((?modelContext :: ModelContext) => IO a) -> IO a
- rollbackTransaction :: (?modelContext :: ModelContext) => IO ()
- primaryKeyConditionColumnSelector :: Table record => Text
- deleteRecordById :: forall record (table :: Symbol). (?modelContext :: ModelContext, Table record, Show (PrimaryKey table), GetTableName record ~ table, record ~ GetModelByTableName table, DefaultParamEncoder (Id' table)) => Id' table -> IO ()
- deleteRecords :: forall record (table :: Symbol). (?modelContext :: ModelContext, Show (PrimaryKey table), Table record, HasField "id" record (Id' table), GetTableName record ~ table, record ~ GetModelByTableName table, DefaultParamEncoder [Id' table]) => [record] -> IO ()
- deleteRecordByIds :: forall record (table :: Symbol). (?modelContext :: ModelContext, Show (PrimaryKey table), Table record, GetTableName record ~ table, record ~ GetModelByTableName table, DefaultParamEncoder [Id' table]) => [Id' table] -> IO ()
- deleteAll :: (?modelContext :: ModelContext, Table record) => IO ()
- didChangeRecord :: HasField "meta" record MetaBag => record -> Bool
- trackTableRead :: (?modelContext :: ModelContext) => Text -> IO ()
- withTableReadTracker :: (?modelContext :: ModelContext) => ((?modelContext :: ModelContext, ?touchedTables :: IORef (Set Text)) => IO a) -> IO a
- onlyWhere :: forall record (fieldName :: Symbol) value. (KnownSymbol fieldName, HasField fieldName record value, Eq value) => Proxy fieldName -> value -> [record] -> [record]
- onlyWhereReferences :: forall record (fieldName :: Symbol) value referencedRecord. (KnownSymbol fieldName, HasField fieldName record value, Eq value, HasField "id" referencedRecord value) => Proxy fieldName -> referencedRecord -> [record] -> [record]
- 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]
- copyRecord :: (Table record, SetField "id" record id, Default id, SetField "meta" record MetaBag) => record -> record
- withoutQueryLogging :: (?modelContext :: ModelContext) => ((?modelContext :: ModelContext) => result) -> result
- module IHP.ModelSupport.Types
- data Point = Point Double Double
- fromCoordinates :: Double -> Double -> Point
- toX :: Point -> Double
- toY :: Point -> Double
- data Polygon
- refineFromPointList :: [(Double, Double)] -> Maybe Polygon
- refineFromPointVector :: Vector (Double, Double) -> Maybe Polygon
- toPointList :: Polygon -> [(Double, Double)]
- toPointVector :: Polygon -> Vector (Double, Double)
- fold :: (Word32 -> Word8 -> a) -> (Word32 -> Word32 -> Word32 -> Word32 -> Word8 -> a) -> Inet -> a
- data Inet
- normalizeFromV4 :: Word32 -> Word8 -> Inet
- normalizeFromV6 :: Word32 -> Word32 -> Word32 -> Word32 -> Word8 -> Inet
- refineFromV4 :: Word32 -> Word8 -> Maybe Inet
- refineFromV6 :: Word32 -> Word32 -> Word32 -> Word32 -> Word8 -> Maybe Inet
- refineToV4 :: Inet -> Maybe (Word32, Word8)
- refineToV6 :: Inet -> Maybe (Word32, Word32, Word32, Word32, Word8)
- data Weight
- data Tsvector
- normalizeFromLexemeList :: [(Text, [(Word16, Weight)])] -> Tsvector
- refineFromLexemeList :: [(Text, [(Word16, Weight)])] -> Maybe Tsvector
- toLexemeList :: Tsvector -> [(Text, [(Word16, Weight)])]
- data Interval
- toMicroseconds :: Interval -> Int64
- normalizeFromDiffTime :: DiffTime -> Interval
- normalizeFromMicrosecondsInTotal :: Integer -> Interval
- normalizeFromMonthsDaysAndMicroseconds :: Int32 -> Int32 -> Int64 -> Interval
- normalizeToDiffTime :: Interval -> DiffTime
- normalizeToMicrosecondsInTotal :: Interval -> Integer
- refineFromDiffTime :: DiffTime -> Maybe Interval
- refineFromMicrosecondsInTotal :: Integer -> Maybe Interval
- refineFromMonthsDaysAndMicroseconds :: Int32 -> Int32 -> Int64 -> Maybe Interval
- toDays :: Interval -> Int32
- toMonths :: Interval -> Int32
- module IHP.InputValue
Documentation
class KnownSymbol (GetTableName record) => Table record where Source #
Access meta data for a database table
Minimal complete definition
Methods
Returns the table name of a given model.
Example:
>>>tableName @User"users"
columnNames :: [Text] Source #
Returns the list of column names for a given model
Example:
>>>columnNames @User["id", "email", "created_at"]
primaryKeyColumnNames :: [Text] 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"]
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
|> isValidids :: 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]
commitTransaction :: (?modelContext :: ModelContext) => IO () Source #
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
|> updateRecordgetModelName :: KnownSymbol (GetModelName model) => Text Source #
Returns the model name of a given model as Text
Example:
>>>modelName @User"User"
>>>modelName @Project"Project"
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 projectTrue
Example: Returns False after inserting a record.
>>>project <- createRecord project>>>isNew projectFalse
Example: Returns False for records which have been fetched from the database.
>>>book <- query @Book |> fetchOne>>>isNew bookFalse
didTouchField :: forall (fieldName :: Symbol) fieldValue record. (KnownSymbol fieldName, HasField fieldName record fieldValue, HasField "meta" record MetaBag, Eq fieldValue, Typeable record, FieldBit fieldName 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 projectFalse
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 #nameTrue
notConnectedModelContext :: Logger -> ModelContext Source #
Provides a mock ModelContext to be used when a database connection is not available
withModelContext :: ByteString -> Logger -> (ModelContext -> IO a) -> IO a Source #
Bracket-style wrapper around createModelContext that ensures the database
pool is released when the callback completes (or throws an exception).
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, DefaultParamEncoder (Id' table)) => record -> IO () Source #
Runs a DELETE query for a record.
>>>let project :: Project = ...>>>deleteRecord projectDELETE FROM projects WHERE id = '..'
Use deleteRecords if you want to delete multiple records.
createModelContext :: ByteString -> Logger -> IO ModelContext Source #
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
sqlQueryHasql :: (?modelContext :: ModelContext) => Pool -> Snippet -> Result a -> IO a Source #
Runs a query built from a dynamic Snippet.
Converts the snippet to a Statement and delegates to sqlStatementHasql.
Example:
users <- sqlQueryHasql pool snippet (Decoders.rowList userDecoder)
didChange :: forall (fieldName :: Symbol) fieldValue record. (KnownSymbol fieldName, HasField fieldName record fieldValue, HasField "meta" record MetaBag, Eq fieldValue, Typeable record, FieldBit fieldName 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 projectFalse
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 #nameTrue
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")
releaseModelContext :: ModelContext -> IO () Source #
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
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
unsafeSqlQuery :: (?modelContext :: ModelContext, ToSnippetParams q, FromRowHasql r) => Query -> q -> IO [r] Source #
Runs a raw sql query. Untyped escape hatch — prefer the typed
[typedSql| ... |] quasi quoter (from IHP.TypedSql) when the query is
known at compile time.
Example:
users <- unsafeSqlQuery "SELECT id, firstname, lastname FROM users" ()
Take a look at IHP.QueryBuilder for a typesafe approach on building simple queries.
- AutoRefresh:* When using
unsafeSqlQuerywith AutoRefresh, you need to usetrackTableReadto let AutoRefresh know that you have accessed a certain table. Otherwise AutoRefresh will not watch table of your custom sql query.
Use unsafeSqlQuerySingleRow if you expect only a single row to be returned.
sqlQuery :: (?modelContext :: ModelContext, ToSnippetParams q, FromRowHasql r) => Query -> q -> IO [r] Source #
Deprecated: Use the typed quasi quoter '[typedSql| ... |]' with sqlQueryTyped (from IHP.TypedSql) for compile-time type checking. If you really need untyped raw SQL (e.g. dynamic table names), use unsafeSqlQuery instead.
Deprecated alias of unsafeSqlQuery. Prefer [typedSql| ... |] via sqlQueryTyped.
unsafeSqlQuerySingleRow :: (?modelContext :: ModelContext, ToSnippetParams query, FromRowHasql record) => Query -> query -> IO record Source #
Runs a raw sql query, that is expected to return a single result row.
Untyped escape hatch — prefer the typed [typedSql| ... |] quasi quoter.
Like unsafeSqlQuery, but useful when you expect only a single row as the result.
Example:
user <- unsafeSqlQuerySingleRow "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
unsafeSqlQuerySingleRowwith AutoRefresh, you need to usetrackTableReadto let AutoRefresh know that you have accessed a certain table. Otherwise AutoRefresh will not watch table of your custom sql query.
sqlQuerySingleRow :: (?modelContext :: ModelContext, ToSnippetParams query, FromRowHasql record) => Query -> query -> IO record Source #
Deprecated: Use the typed quasi quoter '[typedSql| ... |]' with sqlQueryTyped (from IHP.TypedSql) for compile-time type checking. If you really need untyped raw SQL, use unsafeSqlQuerySingleRow instead.
Deprecated alias of unsafeSqlQuerySingleRow.
unsafeSqlExec :: (?modelContext :: ModelContext, ToSnippetParams q) => Query -> q -> IO Int64 Source #
Runs a sql statement (like a CREATE statement). Untyped escape hatch —
prefer the typed [typedSql| ... |] quasi quoter via sqlExecTyped.
Example:
unsafeSqlExec "CREATE TABLE users ()" ()
sqlExecHasqlCount :: (?modelContext :: ModelContext) => Pool -> Snippet -> IO Int64 Source #
Like sqlExecHasql but returns the number of affected rows
When RLS is enabled, the statement is wrapped in a transaction that first sets the
role and user id via setRLSConfigStatement.
sqlExec :: (?modelContext :: ModelContext, ToSnippetParams q) => Query -> q -> IO Int64 Source #
Deprecated: Use the typed quasi quoter '[typedSql| ... |]' with sqlExecTyped (from IHP.TypedSql) for compile-time type checking. If you really need untyped raw SQL (e.g. DDL statements), use unsafeSqlExec instead.
Deprecated alias of unsafeSqlExec.
unsafeSqlExecDiscardResult :: (?modelContext :: ModelContext, ToSnippetParams q) => Query -> q -> IO () Source #
Runs a sql statement (like a CREATE statement), but doesn't return any result.
Untyped escape hatch — prefer the typed [typedSql| ... |] quasi quoter via sqlExecTyped.
Example:
unsafeSqlExecDiscardResult "CREATE TABLE users ()" ()
sqlExecHasql :: (?modelContext :: ModelContext) => Pool -> Snippet -> IO () Source #
Like sqlQueryHasql but for statements that don't return results (DELETE, etc.)
When RLS is enabled, the statement is wrapped in a transaction that first sets the
role and user id via setRLSConfigStatement.
sqlExecDiscardResult :: (?modelContext :: ModelContext, ToSnippetParams q) => Query -> q -> IO () Source #
Deprecated: Use the typed quasi quoter '[typedSql| ... |]' with sqlExecTyped (from IHP.TypedSql) for compile-time type checking. If you really need untyped raw SQL (e.g. DDL statements), use unsafeSqlExecDiscardResult instead.
Deprecated alias of unsafeSqlExecDiscardResult.
setRLSConfigStatement :: Statement (Text, Text) () Source #
Prepared statement that sets the RLS role and user id using set_config().
Uses set_config(setting, value, is_local) which is a regular SQL function
that supports parameterized values in the extended query protocol, unlike
SET LOCAL which is a utility command that cannot be parameterized.
The third argument true makes the setting local to the current transaction,
equivalent to SET LOCAL.
sqlStatementHasql :: (?modelContext :: ModelContext) => Pool -> a -> Statement a b -> IO b Source #
Runs a hasql Statement directly on the pool.
Core execution function that handles session construction, RLS wrapping,
pool execution, cached plan error retry, and debug logging.
Works with both prepared (preparable) and unprepared statements.
Example:
result <- sqlStatementHasql pool someId myPreparedStatement
logQueryTiming :: (?context :: ModelContext) => LogLevel -> Text -> IO a -> IO a Source #
Run an IO action, logging its duration when the log level is Debug.
The label is prepended to the timing message, e.g. "🔍 SELECT ...".
truncateQuery :: Text -> Text Source #
sqlExecStatement :: (?modelContext :: ModelContext) => Pool -> a -> Statement a () -> IO () Source #
Like sqlStatementHasql but for write operations (DELETE, UPDATE, INSERT without results).
Uses Write for RLS transactions (vs Read in sqlStatementHasql).
Takes a Statement directly — use this when you have a pre-built statement
rather than a Snippet.
Example:
sqlExecStatement pool workerId myUpdateStatement
runSessionHasql :: (?modelContext :: ModelContext) => Pool -> Session () -> IO () Source #
Like sqlExecHasql but for raw Session values (e.g. multi-statement DDL via sql)
Use this instead of sqlExecHasql when you need the simple protocol (no prepared statements),
e.g. for multi-statement SQL like trigger creation.
Example:
runSessionHasql pool (Hasql.sql "BEGIN; CREATE ...; COMMIT;")
data SessionRequest where Source #
Existential wrapper for sub-session requests in a transaction
Constructors
| SessionRequest :: forall a. Session a -> MVar (Either SessionError a) -> SessionRequest |
processRequests :: MVar (Maybe SessionRequest) -> Session () Source #
Loop that reads sub-session requests from an MVar and executes them
on the current transaction's connection. Stops when it receives Nothing.
unsafeSqlQueryScalar :: (?modelContext :: ModelContext, ToSnippetParams q, HasqlDecodeColumn value) => Query -> q -> IO value Source #
Runs a raw sql query which results in a single scalar value such as an integer or string.
Untyped escape hatch — prefer the typed [typedSql| ... |] quasi quoter.
Example:
usersCount <- unsafeSqlQueryScalar "SELECT COUNT(*) FROM users" ()
Take a look at IHP.QueryBuilder for a typesafe approach on building simple queries.
sqlQueryScalar :: (?modelContext :: ModelContext, ToSnippetParams q, HasqlDecodeColumn value) => Query -> q -> IO value Source #
Deprecated: Use the typed quasi quoter '[typedSql| ... |]' with sqlQueryTyped (from IHP.TypedSql) for compile-time type checking. If you really need untyped raw SQL, use unsafeSqlQueryScalar instead.
Deprecated alias of unsafeSqlQueryScalar.
unsafeSqlQueryScalarOrNothing :: (?modelContext :: ModelContext, ToSnippetParams q, HasqlDecodeColumn 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.
Untyped escape hatch — prefer the typed [typedSql| ... |] quasi quoter.
Example:
usersCount <- unsafeSqlQueryScalarOrNothing "SELECT COUNT(*) FROM users" ()
Take a look at IHP.QueryBuilder for a typesafe approach on building simple queries.
sqlQueryScalarOrNothing :: (?modelContext :: ModelContext, ToSnippetParams q, HasqlDecodeColumn value) => Query -> q -> IO (Maybe value) Source #
Deprecated: Use the typed quasi quoter '[typedSql| ... |]' with sqlQueryTyped (from IHP.TypedSql) for compile-time type checking. If you really need untyped raw SQL, use unsafeSqlQueryScalarOrNothing instead.
Deprecated alias of unsafeSqlQueryScalarOrNothing.
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 .." ()
rollbackTransaction :: (?modelContext :: ModelContext) => IO () Source #
primaryKeyConditionColumnSelector :: Table record => Text 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"
deleteRecordById :: forall record (table :: Symbol). (?modelContext :: ModelContext, Table record, Show (PrimaryKey table), GetTableName record ~ table, record ~ GetModelByTableName table, DefaultParamEncoder (Id' table)) => Id' table -> IO () Source #
Like deleteRecord but using an Id
>>>let project :: Id Project = ...>>>delete projectIdDELETE 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, DefaultParamEncoder [Id' table]) => [record] -> IO () Source #
Runs a DELETE query for a list of records.
>>>let projects :: [Project] = ...>>>deleteRecords projectsDELETE FROM projects WHERE id IN (..)
deleteRecordByIds :: forall record (table :: Symbol). (?modelContext :: ModelContext, Show (PrimaryKey table), Table record, GetTableName record ~ table, record ~ GetModelByTableName table, DefaultParamEncoder [Id' table]) => [Id' table] -> IO () Source #
Like deleteRecordById but for a list of Ids.
>>>let projectIds :: [ Id Project ] = ...>>>delete projectIdsDELETE FROM projects WHERE id IN ('..')
deleteAll :: (?modelContext :: ModelContext, Table record) => IO () Source #
Runs a DELETE query to delete all rows in a table.
>>>deleteAll @ProjectDELETE FROM projects
didChangeRecord :: HasField "meta" record MetaBag => record -> Bool Source #
Returns True if the named field has been touched (is in touchedFields).
Used by generated Update statement modules to determine which columns to send.
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 projectFalse
Example: Returns True after setting a field
>>>let projectId = "227fbba3-0578-4eb8-807d-b9b692c3644f" :: Id Project>>>project <- fetch projectId>>>project |> set #name "New Name" |> didChangeRecordTrue
trackTableRead :: (?modelContext :: ModelContext) => Text -> 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 Text)) => IO a) -> IO a 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) postsThis can be written in a shorter way using onlyWhere:
getUserPosts user posts =
posts |> onlyWhere #userId user.idBecause the userId field is an Id, we can use onlyWhereReferences to make it even shorter:
getUserPosts user posts =
posts |> onlyWhereReferences #userId userIf the Id field is nullable, we need to use onlyWhereReferencesMaybe:
getUserTasks user tasks =
tasks |> onlyWhereReferencesMaybe #optionalUserId useronlyWhereReferences :: 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) postsThis can be written in a shorter way using onlyWhereReferences:
getUserPosts user posts =
posts |> onlyWhereReferences #userId userIf the Id field is nullable, we need to use onlyWhereReferencesMaybe:
getUserTasks user tasks =
tasks |> onlyWhereReferencesMaybe #optionalUserId userSee 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) tasksThis can be written in a shorter way using onlyWhereReferencesMaybe:
getUserTasks user tasks =
tasks |> onlyWhereReferencesMaybe #optionalUserId userSee onlyWhere for more details.
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)
withoutQueryLogging :: (?modelContext :: ModelContext) => ((?modelContext :: ModelContext) => result) -> result Source #
Runs sql queries without logging them
Example:
users <- withoutQueryLogging (sqlQuery "SELECT * FROM users" ())
module IHP.ModelSupport.Types
Instances
fromCoordinates :: Double -> Double -> Point #
Instances
toPointList :: Polygon -> [(Double, Double)] #
fold :: (Word32 -> Word8 -> a) -> (Word32 -> Word32 -> Word32 -> Word32 -> Word8 -> a) -> Inet -> a #
Instances
normalizeFromV4 :: Word32 -> Word8 -> Inet #
Instances
Instances
toMicroseconds :: Interval -> Int64 #
normalizeToDiffTime :: Interval -> DiffTime #
refineFromDiffTime :: DiffTime -> Maybe Interval #
module IHP.InputValue