ihp-typed-sql-1.7.0: Compile-time typed SQL quasiquoter for IHP
Safe HaskellNone
LanguageGHC2021

IHP.TypedSql

Synopsis

Documentation

typedSql :: QuasiQuoter Source #

QuasiQuoter entry point for typed SQL. Disallows SELECT * and SELECT table.* by default to prevent production errors when the schema changes. Use typedSqlStar to opt in to star selects.

typedSqlStar :: QuasiQuoter Source #

Like typedSql but allows SELECT * and SELECT table.* patterns. Use this when you understand that star selects can break at runtime if the schema changes between compilation and deployment.

data QueryCardinality Source #

What the SQL parser can prove about how many rows a query returns.

data QueryExecResult Source #

What kind of result an SQL statement has.

This marker is separate from QueryCardinality because statements without result columns can still have different execution results: DML statements report affected rows, while utility statements such as SET CONSTRAINTS do not report a row count.

data TypedQuery (cardinality :: QueryCardinality) (execResult :: QueryExecResult) result Source #

Prepared query with a custom row parser. High-level: this is the runtime value produced by the typed SQL quasiquoter.

Constructors

TypedQuery 

Fields

type family TypedQueryResult (cardinality :: QueryCardinality) result where ... Source #

The result shape returned by sqlQueryTyped.

Equations

TypedQueryResult 'ManyRows result = [result] 
TypedQueryResult 'AtMostOneRow result = Maybe result 
TypedQueryResult 'ExactlyOneRow result = result 

type family SqlExecTypedResult (execResult :: QueryExecResult) where ... Source #

The result returned by sqlExecTyped.

Equations

SqlExecTypedResult 'ReturnsAffectedRows = Int64 
SqlExecTypedResult 'ReturnsNoResult = () 
SqlExecTypedResult 'ReturnsRows = TypeError ('Text "sqlExecTyped cannot run SQL statements that return rows. Use sqlQueryTyped instead.") :: Type 

class DecodeTypedQuery (cardinality :: QueryCardinality) Source #

Minimal complete definition

typedQueryResultDecoder

Instances

Instances details
DecodeTypedQuery 'AtMostOneRow Source # 
Instance details

Defined in IHP.TypedSql

DecodeTypedQuery 'ExactlyOneRow Source # 
Instance details

Defined in IHP.TypedSql

DecodeTypedQuery 'ManyRows Source # 
Instance details

Defined in IHP.TypedSql

class RunTypedExec (execResult :: QueryExecResult) Source #

Minimal complete definition

runTypedExec

Instances

Instances details
RunTypedExec 'ReturnsAffectedRows Source # 
Instance details

Defined in IHP.TypedSql

RunTypedExec 'ReturnsNoResult Source # 
Instance details

Defined in IHP.TypedSql

(TypeError ('Text "sqlExecTyped cannot run SQL statements that return rows. Use sqlQueryTyped instead.") :: Constraint) => RunTypedExec 'ReturnsRows Source # 
Instance details

Defined in IHP.TypedSql

sqlQueryTyped :: forall (cardinality :: QueryCardinality) result. (?modelContext :: ModelContext, DecodeTypedQuery cardinality) => TypedQuery cardinality 'ReturnsRows result -> IO (TypedQueryResult cardinality result) Source #

Run a typed SELECT query.

Also works with INSERT/UPDATE/DELETE ... RETURNING statements that return rows.

The return type is inferred from the query cardinality:

  • many rows: [result]
  • at most one row: Maybe result
  • exactly one row: result
users <- sqlQueryTyped [typedSql| SELECT name FROM users |] -- IO [Text]
total <- sqlQueryTyped [typedSql| SELECT count(*) FROM users |] -- IO Int64

sqlQueryTypedRows :: (?modelContext :: ModelContext) => TypedQuery 'ManyRows 'ReturnsRows result -> IO [result] Source #

Run a typed query that can return many rows.

This is equivalent to sqlQueryTyped, but fixes the expected cardinality in the function name. It can make type errors easier to read when migrating code from the old list-shaped sqlQueryTyped result.

sqlQueryTypedOneOrNothing :: (?modelContext :: ModelContext) => TypedQuery 'AtMostOneRow 'ReturnsRows result -> IO (Maybe result) Source #

Run a typed query that can return at most one row.

This is equivalent to sqlQueryTyped, but fixes the expected cardinality in the function name.

sqlQueryTypedSingle :: (?modelContext :: ModelContext) => TypedQuery 'ExactlyOneRow 'ReturnsRows result -> IO result Source #

Run a typed query that must return exactly one row.

This is equivalent to sqlQueryTyped, but fixes the expected cardinality in the function name.

sqlQueryTypedMaybeColumn :: (?modelContext :: ModelContext) => TypedQuery 'AtMostOneRow 'ReturnsRows (Maybe result) -> IO (Maybe result) Source #

Run an at-most-one-row query selecting a nullable single column and flatten the two independent failure modes into one Maybe.

Useful for queries like:

email <- sqlQueryTypedMaybeColumn [typedSql|
    SELECT optional_email FROM users WHERE id = ${userId}
|]

Without this helper, the precise sqlQueryTyped result is Maybe (Maybe Text): the outer Maybe is "no row", the inner Maybe is "the selected column was NULL".

sqlQueryTypedPipelined :: forall (cardinality :: QueryCardinality) result. DecodeTypedQuery cardinality => TypedQuery cardinality 'ReturnsRows result -> Pipeline (TypedQueryResult cardinality result) Source #

Pipeline variant of sqlQueryTyped.

Compose this with pipeline to run independent typed SQL queries in one PostgreSQL pipeline batch.

sqlExecTyped :: forall (cardinality :: QueryCardinality) (execResult :: QueryExecResult) result. (?modelContext :: ModelContext, RunTypedExec execResult) => TypedQuery cardinality execResult result -> IO (SqlExecTypedResult execResult) Source #

Run a typed statement.

Use sqlQueryTyped instead if your statement has a RETURNING clause. Known utility statements without a row-count result, such as SET CONSTRAINTS, are run with Hasql's no-result decoder and return ().

rowsAffected <- sqlExecTyped [typedSql| DELETE FROM items WHERE id = ${itemId} |]
sqlExecTyped [typedSql| SET CONSTRAINTS ALL DEFERRED |] -- IO ()