### Example ServerError Details Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/08-errors.md Provides an example of structured server error details, including SQLSTATE code, message, and other relevant information. ```text code: 23505 message: duplicate key value violates unique constraint "users_email_key" detail: Key (email)=(john@example.com) already exists. hint: NULL position: Nothing ``` -------------------------------- ### OtherConnectionError Example Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/08-errors.md Provides an example of a generic connection error, serving as a catch-all for uncategorized issues from libpq. ```text Connection error while connecting to the database reason: Unknown error from libpq ``` -------------------------------- ### UnexpectedColumnCountStatementError Example Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/08-errors.md Provides an example error message for UnexpectedColumnCountStatementError, detailing the expected and actual number of columns. ```text Unexpected number of columns expected: 3 actual: 4 ``` -------------------------------- ### AuthenticationConnectionError Example Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/08-errors.md Shows the details for an authentication error, highlighting issues with credentials or user permissions. ```text Authentication error while connecting to the database reason: password authentication failed for user "postgres" ``` -------------------------------- ### CompatibilityConnectionError Example Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/08-errors.md Presents the details for a compatibility error, indicating version or protocol mismatches between client and server. ```text Compatibility error while connecting to the database reason: Server version is lower than 9: 8.4.22 ``` -------------------------------- ### Complex Result Decoding Example Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/07-decoders.md Example demonstrating how to decode a complex result set including UUID, Text, Maybe Text, and a Vector of Text. This setup is useful for queries returning multiple columns with varying types and nested structures. ```haskell import qualified Hasql.Decoders as Decoders import qualified Hasql.Statement as Statement import Data.Vector (Vector) import Data.UUID (UUID) data User = User { userId :: UUID , userName :: Text , userEmail :: Maybe Text , userTags :: Vector Text } deriving (Show) userRowDecoder :: Decoders.Row User userRowDecoder = User <$> Decoders.column (Decoders.nonNullable Decoders.uuid) <*> Decoders.column (Decoders.nonNullable Decoders.text) <*> Decoders.column (Decoders.nullable Decoders.text) <*> Decoders.column (Decoders.nonNullable $ Decoders.vectorArray (Decoders.nonNullable Decoders.text)) selectUsersStatement :: Statement.Statement () (Vector User) selectUsersStatement = Statement.preparable "SELECT id, name, email, tags FROM users" Encoders.noParams (Decoders.rowVector userRowDecoder) ``` -------------------------------- ### StatementSessionError Example Details Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/08-errors.md Provides an example of the detailed fields for a StatementSessionError, indicating an issue during statement execution. ```text Unexpected number of rows totalStatements: 1 statementIndex: 0 sql: SELECT * FROM users WHERE id = $1 parameters: 42 prepared: true expectedMin: 1 expectedMax: 1 actual: 0 ``` -------------------------------- ### Full Session Workflow Example Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/03-session.md Demonstrates a complete session workflow, including defining statements, creating a session, and executing it with error handling. Ensure you have a PostgreSQL server running on localhost:5432 with a database named 'mydb' and user 'postgres'. ```haskell import qualified Hasql.Connection as Connection import qualified Hasql.Connection.Settings as Settings import qualified Hasql.Session as Session import qualified Hasql.Statement as Statement import qualified Hasql.Encoders as Encoders import qualified Hasql.Decoders as Decoders import Data.Int (Int64) -- Define statements sumStmt :: Statement.Statement (Int64, Int64) Int64 sumStmt = Statement.preparable "SELECT $1 + $2" ((fst >$< Encoders.param (Encoders.nonNullable Encoders.int8)) <> (snd >$< Encoders.param (Encoders.nonNullable Encoders.int8))) (Decoders.singleRow (Decoders.column (Decoders.nonNullable Decoders.int8))) -- Create session mySession :: Session Int64 mySession = do Session.script "SET application_name TO 'my-app'" result <- Session.statement (10, 20) sumStmt pure result -- Execute main :: IO () main = do let settings = Settings.hostAndPort "localhost" 5432 <> Settings.user "postgres" <> Settings.dbname "mydb" Right conn <- Connection.acquire settings result <- Connection.use conn mySession Connection.release conn case result of Right sum -> print sum Left err -> putStrLn $ "Error: " <> show err ``` -------------------------------- ### UnexpectedRowCountStatementError Example Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/08-errors.md Illustrates an example error message for UnexpectedRowCountStatementError, showing the expected and actual number of rows returned by a statement. ```text Unexpected number of rows expectedMin: 1 expectedMax: 1 actual: 0 ``` -------------------------------- ### ConnectionSessionError Example Details Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/08-errors.md Shows an example of ConnectionSessionError details, indicating a loss of connection or the connection becoming unusable during a session. ```text Connection error reason: Connection was closed ``` -------------------------------- ### Hasql Parameter Encoding Examples Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/05-statement.md Demonstrates various ways to specify parameter encoders for Hasql statements, including no parameters, single parameters, multiple parameters using Monoid/Semigroup, and using contravariance to extract fields. ```haskell -- No parameters Encoders.noParams ``` ```haskell -- Single parameter Encoders.param (Encoders.nonNullable Encoders.int8) ``` ```haskell -- Multiple parameters (using Monoid/Semigroup) Encoders.param (Encoders.nonNullable Encoders.int8) <> Encoders.param (Encoders.nonNullable Encoders.text) ``` ```haskell -- Using contravariance to extract fields (fst >$< Encoders.param (Encoders.nonNullable Encoders.int8)) <> (snd >$< Encoders.param (Encoders.nonNullable Encoders.text)) ``` -------------------------------- ### DriverSessionError Example Details Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/08-errors.md Presents an example of DriverSessionError details, which signifies an internal driver error, potentially indicating a bug in Hasql. ```text Driver error reason: Unexpected message type received from server ``` -------------------------------- ### MissingTypesSessionError Example Details Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/08-errors.md An example of MissingTypesSessionError details, listing custom types referenced in a statement that could not be found in the database. ```text Types not found in database missingTypes: public.status_enum, pg_temp.my_type ``` -------------------------------- ### Hasql Result Decoding Examples Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/05-statement.md Illustrates different methods for decoding results from Hasql statements, including no result, single row, multiple rows (vector, list, maybe), and rows affected count. ```haskell -- No result Decoders.noResult ``` ```haskell -- Single row Decoders.singleRow rowDecoder ``` ```haskell -- Multiple rows Decoders.rowVector rowDecoder Decoders.rowList rowDecoder Decoders.rowMaybe rowDecoder ``` ```haskell -- Row affected count Decoders.rowsAffected ``` -------------------------------- ### ScriptSessionError Example Details Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/08-errors.md Illustrates the detailed fields for a ScriptSessionError, showing a server-side error during script execution, such as a SQL syntax error. ```text Server error sql: CREATE TABLE users (id SERIAL) code: 42P01 message: syntax error at or near "SERIAL" ``` -------------------------------- ### UnexpectedColumnTypeStatementError Example Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/08-errors.md Shows an example error message for UnexpectedColumnTypeStatementError, including the column index and the expected and actual PostgreSQL type OIDs. ```text Unexpected column type columnIndex: 1 expectedOid: 23 actualOid: 25 ``` -------------------------------- ### Define a statement with no parameters Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/06-encoders.md Use `noParams` for statements that do not require any input parameters. This example shows how to construct a `Statement` that selects all users. ```haskell import qualified Hasql.Statement as Statement import qualified Hasql.Encoders as Encoders import qualified Hasql.Decoders as Decoders selectAllUsers :: Statement.Statement () [User] selectAllUsers = Statement.preparable "SELECT id, name FROM users" Encoders.noParams (Decoders.rowList userRowDecoder) ``` -------------------------------- ### NetworkingConnectionError Example Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/08-errors.md Illustrates the details provided for a networking-related connection error, indicating network-level connectivity issues. ```text Networking error while connecting to the database reason: could not connect to server: Connection refused ``` -------------------------------- ### Example DeserializationCellError Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/08-errors.md Shows a deserialization error, indicating a failure to convert binary cell data to the expected type. ```text Failed to deserialize cell reason: Invalid byte sequence for int8 ``` -------------------------------- ### Conditional Insertion with ApplicativeDo Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/04-pipeline.md Implement conditional logic, such as inserting data only if it doesn't already exist, using the ApplicativeDo extension for cleaner syntax. This example runs two queries in one pipeline. ```haskell {-# LANGUAGE ApplicativeDo #-} import qualified Hasql.Pipeline as Pipeline import qualified Hasql.Session as Session selectExists :: Statement.Statement Int64 Bool selectExists = ... insertNew :: Statement.Statement Text Int64 insertNew = ... -- Insert if not exists (both queries run in one pipeline) insertIfNotExists :: Text -> Session (Maybe Int64) insertIfNotExists name = Session.pipeline $ do exists <- Pipeline.statement (hash name) selectExists if exists then pure Nothing else Just <$> Pipeline.statement name insertNew ``` -------------------------------- ### Establish and Use Connection in Haskell Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/README.md Demonstrates setting up connection settings, acquiring a connection, defining a parameterized SQL statement with encoders and decoders, executing it within a session, and releasing the connection. Ensure you have a PostgreSQL server running and accessible. ```haskell import qualified Hasql.Connection as Connection import qualified Hasql.Connection.Settings as Settings import qualified Hasql.Session as Session import qualified Hasql.Statement as Statement import qualified Hasql.Encoders as Encoders import qualified Hasql.Decoders as Decoders -- Setup let settings = Settings.hostAndPort "localhost" 5432 <> Settings.user "postgres" <> Settings.dbname "mydb" Right conn <- Connection.acquire settings -- Define statement let selectById = Statement.preparable "SELECT id, name FROM users WHERE id = $1" (Encoders.param (Encoders.nonNullable Encoders.int8)) (Decoders.rowMaybe userDecoder) -- Execute result <- Connection.use conn $ do Session.statement 42 selectById Connection.release conn ``` -------------------------------- ### Establish Hasql Connection Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/00-index.md Configure connection settings and acquire a connection. Handle potential connection errors using `Either`. ```haskell settings = Settings.hostAndPort "host" 5432 <> Settings.user "user" <> Settings.dbname "db" Right conn <- Connection.acquire settings result <- Connection.use conn session Connection.release conn ``` -------------------------------- ### acquire Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/01-connection.md Establishes a connection to the database using the provided settings. It performs version validation, sets encoding and message levels, and initializes the statement cache. ```APIDOC ## acquire ### Description Establish a connection to the database according to the provided settings. ### Method `acquire :: Settings.Settings -> IO (Either ConnectionError Connection)` ### Parameters #### Path Parameters - **settings** (`Settings`): Required - Connection configuration including host, port, user, password, and database name ### Return Type `IO (Either ConnectionError Connection)` Returns `Right connection` on success, or `Left error` on failure. The error is categorized as networking, authentication, compatibility, or other errors to facilitate error handling. ### Connection Setup - Validates the PostgreSQL server version (must be 9 or later) - Sets client encoding to UTF-8 - Sets client minimum messages to WARNING - Initializes the statement cache (unless `noPreparedStatements` is enabled) ### Request Example ```haskell import qualified Hasql.Connection as Connection import qualified Hasql.Connection.Settings as Settings main :: IO () main = do let settings = Settings.hostAndPort "localhost" 5432 <> Settings.user "postgres" <> Settings.password "secret" <> Settings.dbname "mydb" result <- Connection.acquire settings case result of Right conn -> putStrLn "Connected!" Left err -> print err ``` ``` -------------------------------- ### Basic Usage Pattern in Haskell Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/00-index.md Demonstrates the fundamental pattern for establishing a connection, defining a parameterized statement, executing it within a session, and releasing the connection. Ensure all necessary Hasql modules are imported. ```haskell import qualified Hasql.Connection as Connection import qualified Hasql.Connection.Settings as Settings import qualified Hasql.Session as Session import qualified Hasql.Statement as Statement import qualified Hasql.Encoders as Encoders import qualified Hasql.Decoders as Decoders -- Create settings let settings = Settings.hostAndPort "localhost" 5432 <> Settings.user "postgres" <> Settings.password "password" <> Settings.dbname "mydb" -- Acquire connection Right conn <- Connection.acquire settings -- Define a statement selectUserById :: Statement.Statement Int64 (Maybe User) selectUserById = Statement.preparable "SELECT id, name FROM users WHERE id = $1" (Encoders.param (Encoders.nonNullable Encoders.int8)) (Decoders.rowMaybe userRowDecoder) -- Execute a session result <- Connection.use conn $ do user <- Session.statement 42 selectUserById pure user -- Clean up Connection.release conn ``` -------------------------------- ### Acquire Database Connection Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/01-connection.md Establishes a connection to the database using provided settings. Validates server version, sets encoding to UTF-8, and initializes the statement cache. Returns either a connection or a connection error. ```haskell acquire :: Settings.Settings -> IO (Either ConnectionError Connection) ``` ```haskell import qualified Hasql.Connection as Connection import qualified Hasql.Connection.Settings as Settings main :: IO () main = do let settings = Settings.hostAndPort "localhost" 5432 <> Settings.user "postgres" <> Settings.password "secret" <> Settings.dbname "mydb" result <- Connection.acquire settings case result of Right conn -> putStrLn "Connected!" Left err -> print err ``` -------------------------------- ### connectionString Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/02-connection-settings.md Constructs settings from a PostgreSQL connection string. ```APIDOC ## connectionString ### Description Constructs settings from a PostgreSQL connection string. ### Signature connectionString :: Text -> Settings ### Parameters #### Path Parameters - **str** (Text) - Required - Connection string in URI or key-value format ### Accepted Formats - URI format: `postgresql://user:password@host:port/dbname` - Key-value format: `host=localhost port=5432 user=myuser dbname=mydb` ### Note If the connection string is invalid, it is treated as empty and does not cause an error. ### Example ```haskell connectionString "postgresql://postgres:secret@localhost:5432/mydb" connectionString "host=localhost port=5432 user=postgres dbname=mydb" ``` ``` -------------------------------- ### Construct Settings from Connection Strings Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/02-connection-settings.md With OverloadedStrings enabled, Settings can be constructed directly from connection strings in various formats. The rightmost setting takes precedence if multiple are combined. ```haskell "host=localhost port=5432 user=myuser dbname=mydb" :: Settings ``` ```haskell "postgresql://myuser@localhost:5432/mydb" :: Settings ``` -------------------------------- ### Construct Settings from Connection String Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/02-connection-settings.md Use this function to construct connection settings from a PostgreSQL connection string. It accepts both URI format and key-value format. Invalid strings are treated as empty. ```haskell connectionString :: Text -> Settings connectionString "postgresql://postgres:secret@localhost:5432/mydb" connectionString "host=localhost port=5432 user=postgres dbname=mydb" ``` -------------------------------- ### Define and Execute Hasql Statements Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/00-index.md Create a prepared statement with SQL, encoders, and decoders, then execute it within a session. ```haskell stmt = Statement.preparable sql encoder decoder result <- Session.statement params stmt ``` -------------------------------- ### Example UnexpectedNullCellError Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/08-errors.md Illustrates an unexpected null value error, typically occurring when a non-nullable column receives a NULL. ```text Unexpected null value ``` -------------------------------- ### Configure Database Connection Settings Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/09-types.md Configuration for database connection. Forms a monoid via composition of individual settings. ```haskell newtype Settings deriving (Eq, IsString, Show, Semigroup, Monoid) ``` -------------------------------- ### Define Type-Safe Results in Haskell Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/00-index.md Specify how results from SQL statements are decoded using applicative specifications. This example decodes an `int8` and a `text` column. ```haskell decoder = (,) <$> Decoders.column (Decoders.nonNullable Decoders.int8) <*> Decoders.column (Decoders.nonNullable Decoders.text) ``` -------------------------------- ### Bulk Inserts with unnest in Hasql Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/00-index.md Shows how to use `unnest` with array parameters for efficient bulk inserts, which is more performant than pipeline for very large batches. Alternatively, pipeline can be used for medium-sized batches. ```sql "INSERT INTO table (a, b, c) SELECT * FROM unnest($1, $2, $3)" ``` -------------------------------- ### Specify Alternate Hosts for Failover Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/02-connection-settings.md Configure multiple hosts for failover by combining multiple `hostAndPort` calls. PostgreSQL will attempt to connect to each host in the order specified. ```haskell let settings = hostAndPort "primary.example.com" 5432 <> hostAndPort "secondary.example.com" 5432 <> user "postgres" <> dbname "mydb" in Connection.acquire settings ``` -------------------------------- ### Define Type-Safe Parameters in Haskell Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/00-index.md Specify how parameters for SQL statements are encoded using contravariant specifications. This example shows encoding for an `int8` and a `text` type. ```haskell encoder = Encoders.param (Encoders.nonNullable Encoders.int8) <> Encoders.param (Encoders.nonNullable Encoders.text) ``` -------------------------------- ### Decode Multiple Columns Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/07-decoders.md Combine multiple `column` decoders using Applicative functors to decode several columns into a tuple. This example shows decoding three columns of different types. ```haskell -- Single column Decoders.column (Decoders.nonNullable Decoders.int8) -- Multiple columns (using Applicative) (,,) <$> Decoders.column (Decoders.nonNullable Decoders.int8) <*> Decoders.column (Decoders.nonNullable Decoders.text) <*> Decoders.column (Decoders.nullable Decoders.text) ``` -------------------------------- ### Using ANY and ALL for IN/NOT IN Operators in Hasql Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/05-statement.md Shows how to use PostgreSQL's `ANY` and `<> ALL` operators with array parameters for efficient `IN` and `NOT IN` operations, respectively. Avoids incorrect direct array-to-list mapping. ```haskell "SELECT * FROM users WHERE status = ANY($1)" ``` ```haskell "SELECT * FROM users WHERE status <> ALL($1)" ``` ```haskell "SELECT * FROM users WHERE id IN ($1, $2, $3)" -- Wrong! ``` -------------------------------- ### Complex Parameter Encoding for INSERT Statement Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/06-encoders.md Defines a Hasql encoder for a `CreateOrder` data type, mapping its fields to corresponding SQL columns in an INSERT statement. This example demonstrates encoding a UUID, Int64, Scientific, and a Vector of Int32s, including a nested foldable array. ```haskell import qualified Hasql.Encoders as Encoders import qualified Hasql.Statement as Statement import Data.Functor.Contravariant ((>$<)) import Data.UUID (UUID) import Data.Int (Int64, Int32) data CreateOrder = CreateOrder { orderId :: UUID, userId :: Int64, total :: Scientific, items :: Vector Int32 } insertOrderEncoder :: Encoders.Params CreateOrder insertOrderEncoder = (.orderId) >$< Encoders.param (Encoders.nonNullable Encoders.uuid) <> (.userId) >$< Encoders.param (Encoders.nonNullable Encoders.int8) <> (.total) >$< Encoders.param (Encoders.nonNullable Encoders.numeric) <> (.items) >$< Encoders.param (Encoders.nonNullable $ Encoders.foldableArray (Encoders.nonNullable Encoders.int4)) createOrderStatement :: Statement.Statement CreateOrder OrderId createOrderStatement = Statement.preparable "INSERT INTO orders (id, user_id, total, item_ids) VALUES ($1, $2, $3, $4) RETURNING id" insertOrderEncoder (Decoders.singleRow (OrderId <$> Decoders.column (Decoders.nonNullable Decoders.uuid))) ``` -------------------------------- ### Positional vs. Named Parameters in Hasql Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/05-statement.md Illustrates the correct usage of PostgreSQL's positional notation ($1, $2) for parameters in Hasql statements, contrasting it with unsupported named parameters and question mark syntax. ```haskell "SELECT * FROM users WHERE id = $1 AND status = $2" ``` ```haskell "SELECT * FROM users WHERE id = $name AND status = $status" ``` ```haskell "SELECT * FROM users WHERE id = ? AND status = ?" ``` -------------------------------- ### Hasql.Connection.Settings.Settings Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/09-types.md Configuration for database connection. Forms a monoid via composition of individual settings. ```APIDOC ## Hasql.Connection.Settings.Settings ### Description Configuration for database connection. Forms a monoid via composition of individual settings. ### Constructors - `Settings.host :: Text -> Settings` - `Settings.hostAndPort :: Text -> Word16 -> Settings` - `Settings.user :: Text -> Settings` - `Settings.password :: Text -> Settings` - `Settings.dbname :: Text -> Settings` - `Settings.applicationName :: Text -> Settings` - `Settings.other :: Text -> Text -> Settings` - `Settings.noPreparedStatements :: Bool -> Settings` - `Settings.connectionString :: Text -> Settings` ``` -------------------------------- ### use Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/01-connection.md Executes a session (sequence of operations) with exclusive access to the connection. It handles concurrency safely and manages connection state during exceptions. ```APIDOC ## use ### Description Execute a session (sequence of operations) with exclusive access to the connection. ### Method `use :: Connection -> Session.Session a -> IO (Either SessionError a)` ### Parameters #### Path Parameters - **connection** (`Connection`): Required - The database connection to use - **session** (`Session a`): Required - The sequence of operations to execute ### Return Type `IO (Either SessionError a)` Returns `Right result` on success, or `Left error` if any operation in the session fails. ### Concurrency - Blocks until the connection is available if another thread is using it - Uses `mask` to handle async exceptions safely - If an exception occurs during the session, the connection is cleaned up and returned to idle state without resetting, preserving session-local state - If cleanup fails after an exception, the connection is closed and the statement cache is reset ### Request Example ```haskell import qualified Hasql.Connection as Connection import qualified Hasql.Session as Session result <- Connection.use conn $ do Session.statement (5, 3) addStatement Session.script "COMMIT" pure () case result of Right () -> putStrLn "Success" Left err -> putStrLn $ "Error: " <> show err ``` ``` -------------------------------- ### Compose Multiple Statements in a Pipeline Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/04-pipeline.md Demonstrates composing multiple independent SQL statements into a single pipeline for efficient batch execution. Both 'selectUser' and 'selectPosts' are added to the pipeline, and they will be executed together in a single network roundtrip if possible. The results are combined into a tuple. ```haskell import qualified Hasql.Pipeline as Pipeline import qualified Hasql.Statement as Statement import qualified Hasql.Session as Session selectUser :: Statement.Statement Int64 (Maybe User) selectUser = ... selectPosts :: Statement.Statement Int64 [Post] selectPosts = ... -- Both statements execute in a single pipeline pipeline :: Pipeline (Maybe User, [Post]) pipeline = do user <- Pipeline.statement 42 selectUser posts <- Pipeline.statement 42 selectPosts pure (user, posts) -- Lift into a session session :: Session (Maybe User, [Post]) session = Session.pipeline pipeline ``` -------------------------------- ### Batching Queries with Pipeline in Hasql Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/00-index.md Compares an inefficient approach using multiple roundtrips for separate statements with an efficient approach using `Session.pipeline` for a single roundtrip. Use pipeline for independent queries. ```haskell -- Inefficient: 3 roundtrips Session.statement p1 stmt1 Session.statement p2 stmt2 Session.statement p3 stmt3 -- Efficient: 1 roundtrip Session.pipeline $ (,,) <$> Pipeline.statement p1 stmt1 <*> Pipeline.statement p2 stmt2 <*> Pipeline.statement p3 stmt3 ``` -------------------------------- ### dbname Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/02-connection-settings.md Sets the database name to connect to. ```APIDOC ## dbname ### Description Sets the database name to connect to. ### Signature dbname :: Text -> Settings ### Parameters #### Path Parameters - **name** (Text) - Required - Database name (e.g., "myapp", "postgres") ### Example ```haskell dbname "myapp_db" ``` ``` -------------------------------- ### Bulk Insert with unnest in Hasql Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/05-statement.md Demonstrates an efficient method for bulk inserts using the `unnest` function with array parameters. This recipe is suitable for inserting multiple rows into a table. ```haskell insertMultipleLocations :: Statement.Statement (Vector UUID, Vector Double, Vector Double) () insertMultipleLocations = Statement.preparable "INSERT INTO location (id, x, y) SELECT * FROM unnest ($1, $2, $3)" (contrazip3 (Encoders.param $ Encoders.nonNullable $ Encoders.foldableArray $ Encoders.nonNullable Encoders.uuid) (Encoders.param $ Encoders.nonNullable $ Encoders.foldableArray $ Encoders.nonNullable Encoders.float8) (Encoders.param $ Encoders.nonNullable $ Encoders.foldableArray $ Encoders.nonNullable Encoders.float8)) Decoders.noResult ``` -------------------------------- ### Haskell Application with Hasql for Arithmetic Operations Source: https://github.com/nikita-volkov/hasql/blob/master/README.md This snippet demonstrates a full Haskell application that connects to a PostgreSQL database using Hasql, defines and executes SQL statements for arithmetic operations (sum, division, modulo), and prints the results. It includes connection settings and session definitions. ```haskell {-# LANGUAGE OverloadedStrings, QuasiQuotes #-} import Data.Functor.Contravariant import Data.Int import Hasql.Session (Session) import Prelude import qualified Hasql.Connection as Connection import qualified Hasql.Connection.Settings as Settings import qualified Hasql.Decoders as Decoders import qualified Hasql.Encoders as Encoders import qualified Hasql.Session as Session import qualified Hasql.Statement as Statement main :: IO () main = do Right connection <- Connection.acquire connectionSettings result <- Connection.use connection (sumAndDivModSession 3 8 3) print result where connectionSettings = mconcat [ Settings.hostAndPort "localhost" 5432, Settings.user "postgres", Settings.password "postgres", Settings.dbname "postgres" -- Prepared statements are enabled by default. -- To disable them (e.g., for pgbouncer compatibility): -- Settings.noPreparedStatements True ] -- * Sessions -- Session abstracts over the execution of operations on a database connection. -- It is composable and has a Monad instance. ------------------------- sumAndDivModSession :: Int64 -> Int64 -> Int64 -> Session (Int64, Int64) sumAndDivModSession a b c = do -- Get the sum of a and b sumOfAAndB <- Session.statement (a, b) sumStatement -- Divide the sum by c and get the modulo as well Session.statement (sumOfAAndB, c) divModStatement -- * Statements -- Statement is a definition of an individual SQL-statement, -- accompanied by a specification of how to encode its parameters and -- decode its result. ------------------------- -- | A statement with two integer parameters and an integer result. sumStatement :: Statement.Statement (Int64, Int64) Int64 sumStatement = Statement.preparable sql encoder decoder where -- The SQL of the statement, with $1, $2, ... placeholders for parameters. sql = "select $1 + $2" -- Specification of how to encode the parameters of the statement -- where the association with placeholders is achieved by order. encoder = mconcat [ -- Encoder of the first parameter as a non-nullable int8. -- It extracts the first element of the tuple using the contravariant functor -- instance. fst >$< Encoders.param (Encoders.nonNullable Encoders.int8), -- Encoder of the second parameter, -- which extracts the second element of the tuple. snd >$< Encoders.param (Encoders.nonNullable Encoders.int8) ] -- Specification of how to decode the result of the statement. -- States that we expect a single row with a single non-nullable int8 column. decoder = Decoders.singleRow (Decoders.column (Decoders.nonNullable Decoders.int8)) divModStatement :: Statement.Statement (Int64, Int64) (Int64, Int64) divModStatement = Statement.preparable sql encoder decoder where sql = "select $1 / $2, $1 % $2" encoder = mconcat [ fst >$< Encoders.param (Encoders.nonNullable Encoders.int8), snd >$< Encoders.param (Encoders.nonNullable Encoders.int8) ] -- Decoder that expects a single row with two non-nullable int8 columns, -- returning the result as a tuple. -- Uses the applicative functor instance to combine two column decoders. decoder = Decoders.singleRow ( (,) <$> Decoders.column (Decoders.nonNullable Decoders.int8) <*> Decoders.column (Decoders.nonNullable Decoders.int8) ) ``` -------------------------------- ### host Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/02-connection-settings.md Sets only the host without specifying a port. PostgreSQL will use the default port (5432) unless specified separately. ```APIDOC ## host ### Description Sets only the host without specifying a port. PostgreSQL will use the default port (5432) unless specified separately. ### Signature host :: Text -> Settings ### Parameters #### Path Parameters - **host** (Text) - Required - Hostname or IP address ### Example ```haskell host "db.example.com" ``` ``` -------------------------------- ### Statement Caching in Hasql Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/00-index.md Demonstrates the difference between the first execution of a statement (which involves preparation) and subsequent executions using the cached prepared statement. Statement caching is enabled by default. ```haskell -- First execution: extra roundtrip to prepare Session.statement p1 stmt -- Subsequent executions: use cached prepared statement Session.statement p2 stmt ``` -------------------------------- ### Batch Insert with Pipeline Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/00-index.md Perform batch inserts efficiently using `Session.pipeline`. This is suitable for inserting multiple records in a single database round trip. ```haskell insertOrders :: [OrderDetails] -> Session [OrderId] insertOrders orders = Session.pipeline $ for orders $ \order -> Pipeline.statement order insertOrderStmt ``` -------------------------------- ### Handling Connection Errors Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/08-errors.md Demonstrates how to acquire a connection and handle potential errors using the IsError typeclass for detailed error reporting. ```haskell import qualified Hasql.Errors as Errors import qualified Hasql.Connection as Connection result <- Connection.acquire settings case result of Left err -> putStrLn $ Errors.toDetailedText err Right conn -> ... ``` -------------------------------- ### hostAndPort Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/02-connection-settings.md Sets the host domain name/IP address and port for the connection. ```APIDOC ## hostAndPort ### Description Sets the host domain name/IP address and port for the connection. ### Signature hostAndPort :: Text -> Word16 -> Settings ### Parameters #### Path Parameters - **host** (Text) - Required - Hostname or IP address (e.g., "localhost", "127.0.0.1") - **port** (Word16) - Required - TCP port number (typically 5432 for PostgreSQL) ### Example ```haskell hostAndPort "db.example.com" 5432 ``` ``` -------------------------------- ### Import Hasql Modules Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/00-index.md Import necessary modules for Hasql operations. Ensure these are included at the beginning of your Haskell file. ```haskell import qualified Hasql.Connection as Connection import qualified Hasql.Connection.Settings as Settings import qualified Hasql.Session as Session import qualified Hasql.Statement as Statement import qualified Hasql.Encoders as Encoders import qualified Hasql.Decoders as Decoders import qualified Hasql.Pipeline as Pipeline import qualified Hasql.Errors as Errors ``` -------------------------------- ### Compose Connection Settings Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/02-connection-settings.md Combine multiple connection settings using the monoid append operator (<>). Rightmost settings take precedence. ```haskell let settings = hostAndPort "localhost" 5432 <> user "postgres" <> password "secret" <> dbname "mydb" <> applicationName "my-app" <> other "sslmode" "require" in Connection.acquire settings ``` -------------------------------- ### Execute a Prepared Statement Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/03-session.md Executes a single prepared or unprepared statement with given parameters. Subsequent executions of preparable statements reuse cached prepared statements on the server. ```haskell import qualified Hasql.Session as Session import qualified Hasql.Statement as Statement import qualified Hasql.Encoders as Encoders import qualified Hasql.Decoders as Decoders import Data.Int (Int64) selectSum :: Statement.Statement (Int64, Int64) Int64 selectSum = Statement.preparable "SELECT $1 + $2" ((fst >$< Encoders.param (Encoders.nonNullable Encoders.int8)) <> (snd >$< Encoders.param (Encoders.nonNullable Encoders.int8))) (Decoders.singleRow (Decoders.column (Decoders.nonNullable Decoders.int8))) session :: Session Int64 session = Session.statement (3, 5) selectSum ``` -------------------------------- ### onLibpqConnection Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/03-session.md Provides a low-level escape hatch for direct libpq operations, allowing custom connection logic or access to libpq-specific features. Use with caution as it bypasses Hasql's type safety. ```APIDOC ## onLibpqConnection ### Description Low-level escape hatch for direct libpq operations. ### Method `onLibpqConnection` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body * **callback** (`Pq.Connection -> IO a`) - Required - Function receiving the raw libpq connection. ### Request Example ```haskell Session.onLibpqConnection $ \conn -> do -- Perform custom operations on the libpq connection pure () ``` ### Response #### Success Response `Session a` - Returns the result of the callback function. #### Response Example (See Haskell example in source) ``` -------------------------------- ### Access Raw libpq Connection Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/03-session.md Provides a low-level escape hatch to perform direct libpq operations using a raw connection. Use with caution as it bypasses Hasql's type safety and error handling. ```haskell Session.onLibpqConnection :: (Pq.Connection -> IO a) -> Session a ``` -------------------------------- ### Hasql Type Mappings Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/09-types.md Illustrates how Hasql maps external types from standard libraries to its internal representations for various data types including text, binary data, numbers, dates, times, and JSON. ```markdown | External Type | Module | |---------------|--------| | `Text` | `Data.Text` | | `ByteString` | `Data.ByteString` | | `Scientific` | `Data.Scientific` | | `Day` | `Data.Time` | | `LocalTime` | `Data.Time` | | `UTCTime` | `Data.Time` | | `TimeOfDay` | `Data.Time` | | `UUID` | `Data.UUID` | | `IPv4`, `IPv6` | `Data.IP` | | `Vector` | `Data.Vector` | | `HashMap` | `Data.HashMap.Strict` | | `Value` | `Data.Aeson` | | `Either` | `Prelude` | | `Maybe` | `Prelude` | | `Monad`, etc. | `Control.Monad` | ``` -------------------------------- ### Set Password Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/02-connection-settings.md Use this function to set the password for database authentication. Passwords are transmitted to libpq, which handles them according to PostgreSQL's authentication protocol. ```haskell password :: Text -> Settings ``` -------------------------------- ### Execute a Raw SQL Script Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/03-session.md Runs a raw SQL script that cannot be parameterized or prepared. This is useful for schema changes, setting session variables, or managing transactions. ```haskell import qualified Hasql.Session as Session setTimeoutSession :: Session () setTimeoutSession = do Session.statement () selectOneStatement Session.script "SET statement_timeout TO 30000" -- 30 seconds Session.statement 42 insertUserStatement ``` -------------------------------- ### Set Application Name Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/02-connection-settings.md Use this function to set a name for your application, which will be visible in PostgreSQL logs and monitoring tools. This helps in identifying and managing connections. ```haskell applicationName :: Text -> Settings applicationName "my-haskell-app" ``` -------------------------------- ### Dynamic SQL Generation Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/00-index.md Use `unpreparable` statements for dynamically generated SQL. This is useful when the SQL structure needs to change based on runtime conditions. ```haskell selectWithDynamicFilter :: String -> Statement.Statement () [User] selectWithDynamicFilter filter = Statement.unpreparable ("SELECT * FROM users WHERE " <> filter) Encoders.noParams (Decoders.rowList userDecoder) ``` -------------------------------- ### password Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/02-connection-settings.md Sets the password for database authentication. ```APIDOC ## password ### Description Sets the password for database authentication. ### Signature password :: Text -> Settings ### Parameters #### Path Parameters - **pass** (Text) - Required - Database password ### Security Note Passwords are transmitted to libpq, which handles them according to PostgreSQL's authentication protocol. ### Example ```haskell password "secret_password" ``` ``` -------------------------------- ### applicationName Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/02-connection-settings.md Sets the application name visible in PostgreSQL logs and monitoring tools. ```APIDOC ## applicationName ### Description Sets the application name visible in PostgreSQL logs and monitoring tools. ### Signature applicationName :: Text -> Settings ### Parameters #### Path Parameters - **name** (Text) - Required - Application name for identification ### Example ```haskell applicationName "my-haskell-app" ``` ``` -------------------------------- ### preparable Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/05-statement.md Creates a preparable statement for queries that will be executed multiple times. The statement is marked for preparation on the server, leading to a faster execution on subsequent calls by reusing a cached prepared statement. ```APIDOC ## preparable ### Description Creates a preparable statement for queries executed multiple times. The statement is marked for preparation on the server, with the first execution incurring an extra roundtrip to parse and plan the query, while subsequent executions reuse the cached prepared statement for improved performance. The statement cache is per-connection and persists across sessions. ### Parameters #### Path Parameters - **sql** (Text) - Required - SQL template with positional parameters ($1, $2, ...) - **encoder** (Encoders.Params params) - Required - Specification for encoding parameters - **decoder** (Decoders.Result result) - Required - Specification for decoding results ### Return Type Statement params result ### Example ```haskell import qualified Hasql.Statement as Statement import qualified Hasql.Encoders as Encoders import qualified Hasql.Decoders as Decoders import Data.Int (Int64) selectUserById :: Statement.Statement Int64 (Maybe User) selectUserById = Statement.preparable "SELECT id, name, email FROM users WHERE id = $1" (Encoders.param (Encoders.nonNullable Encoders.int8)) (Decoders.rowMaybe $ (,,) <$> Decoders.column (Decoders.nonNullable Decoders.int8) <*> Decoders.column (Decoders.nonNullable Decoders.text) <*> Decoders.column (Decoders.nonNullable Decoders.text)) ``` ``` -------------------------------- ### Manage Connection Lifecycle in Haskell Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/00-index.md Acquire, use, and release a database connection. Connections are thread-safe and concurrent access is serialized. ```haskell -- 1. Acquire a connection Right connection <- Connection.acquire settings -- 2. Execute operations result <- Connection.use connection mySession -- 3. Release the connection Connection.release connection ``` -------------------------------- ### Simple Success/Failure Reporting Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/08-errors.md Use this pattern to log a simple success message with the returned value or an error message if an error occurs. ```haskell result <- Connection.use conn session case result of Right value -> putStrLn $ "Success: " ++ show value Left err -> putStrLn $ "Error: " ++ show err ``` -------------------------------- ### Set Database Name Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/02-connection-settings.md Use this function to specify the name of the database to connect to. This is a required parameter for establishing a connection. ```haskell dbname :: Text -> Settings ``` -------------------------------- ### Batch Insert with Hasql Pipeline Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/04-pipeline.md Use this pattern for efficiently inserting multiple rows into a database table. It requires a pre-defined 'insertOrder' statement. ```haskell import qualified Hasql.Pipeline as Pipeline import qualified Hasql.Session as Session import Data.Foldable (for_) -- Single insert statement insertOrder :: Statement.Statement OrderDetails OrderId insertOrder = ... -- Batch insert using pipeline insertOrders :: [OrderDetails] -> Session [OrderId] insertOrders orders = Session.pipeline $ for orders $ \order -> Pipeline.statement order insertOrder ``` -------------------------------- ### other Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/02-connection-settings.md Sets any arbitrary PostgreSQL connection parameter. ```APIDOC ## other ### Description Sets any arbitrary PostgreSQL connection parameter. ### Signature other :: Text -> Text -> Settings ### Parameters #### Path Parameters - **key** (Text) - Required - Parameter name (e.g., "sslmode", "statement_timeout") - **value** (Text) - Required - Parameter value ### Example ```haskell other "sslmode" "require" other "statement_timeout" "30000" -- 30 seconds in milliseconds ``` ``` -------------------------------- ### user Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/02-connection-settings.md Sets the PostgreSQL user name for authentication. ```APIDOC ## user ### Description Sets the PostgreSQL user name for authentication. ### Signature user :: Text -> Settings ### Parameters #### Path Parameters - **name** (Text) - Required - PostgreSQL user name (e.g., "postgres", "myapp_user") ### Example ```haskell user "postgres" ``` ``` -------------------------------- ### Define a Database Connection Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/09-types.md Represents a single database connection. Used with `Connection.acquire` and `Connection.use`. ```haskell newtype Connection ``` -------------------------------- ### script Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/03-session.md Executes a raw SQL script that cannot be parameterized or prepared. This is useful for commands like setting session variables, schema changes, or managing transactions. ```APIDOC ## script ### Description Executes a raw SQL script that cannot be parameterized or prepared. ### Method `script` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body * **sql** (`Text`) - Required - SQL script as text (may contain multiple statements). ### Request Example ```haskell Session.script "SET statement_timeout TO 30000" ``` ### Response #### Success Response `Session ()` - Returns unit on success. #### Response Example (See Haskell example in source) ``` -------------------------------- ### param Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/06-encoders.md Lifts a value encoder into a parameter position within a `Params` specification. This allows you to define how individual parameters should be encoded. ```APIDOC ## param ### Description Lift a value encoder into a parameter position. ### Signature ```haskell param :: NullableOrNot Value a -> Params a ``` ### Parameters #### Request Body - **encoder** (`NullableOrNot Value a`) - Required - The value encoder for this parameter ### Return Type `Params a` ### Example ```haskell Encoders.param (Encoders.nonNullable Encoders.int8) Encoders.param (Encoders.nullable Encoders.text) ``` ``` -------------------------------- ### Set Host and Port Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/02-connection-settings.md Use this function to specify both the hostname/IP address and the TCP port for the PostgreSQL connection. The port is typically 5432 for PostgreSQL. ```haskell hostAndPort :: Text -> Word16 -> Settings hostAndPort "db.example.com" 5432 ``` -------------------------------- ### Querying Related Data with Pipeline Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/00-index.md Fetch related data, such as a user and their posts, in a single database round trip using `Session.pipeline`. This improves performance by reducing network latency. ```haskell selectUserWithPosts :: UserId -> Session (Maybe User, [Post]) selectUserWithPosts userId = Session.pipeline $ (,) <$> Pipeline.statement userId selectUserStmt <*> Pipeline.statement userId selectPostsStmt ``` -------------------------------- ### Haskell Statements using Hasql-TH Source: https://github.com/nikita-volkov/hasql/blob/master/README.md This snippet shows an alternative way to define Hasql statements using the 'hasql-th' library. It leverages compile-time validation and automatic codec generation for SQL statements, providing a more concise and robust implementation compared to manual definition. ```haskell import qualified Hasql.TH as TH -- from "hasql-th" sumStatement :: Statement.Statement (Int64, Int64) Int64 sumStatement = [TH.singletonStatement| select ($1 :: int8 + $2 :: int8) :: int8 |] divModStatement :: Statement.Statement (Int64, Int64) (Int64, Int64) divModStatement = [TH.singletonStatement| select (($1 :: int8) / ($2 :: int8)) :: int8, (($1 :: int8) % ($2 :: int8)) :: int8 |] ``` -------------------------------- ### noPreparedStatements Source: https://github.com/nikita-volkov/hasql/blob/master/_autodocs/02-connection-settings.md Disables prepared statement caching (default: False). ```APIDOC ## noPreparedStatements ### Description Disables prepared statement caching (default: False). ### Signature noPreparedStatements :: Bool -> Settings ### Parameters #### Path Parameters - **disable** (Bool) - Required - `True` to disable prepared statements, `False` to enable (default) ### When to Use - Set to `True` for compatibility with statement proxying applications like pgbouncer - pgbouncer versions < 1.21.0 did not support prepared statements - pgbouncer 1.21.0+ now supports prepared statements, so this may not be necessary for new deployments - Disabling prepared statements reduces performance due to lack of query plan caching ### Example ```haskell noPreparedStatements True ``` ```