mirror of
https://github.com/nikita-volkov/hasql.git
synced 2024-12-25 11:11:36 +03:00
Adds a basic README file
This commit is contained in:
parent
d34c06a4eb
commit
d38acbe88c
123
README.md
Normal file
123
README.md
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
# Hasql [![Build Status](https://travis-ci.org/nikita-volkov/hasql.svg?branch=master)](https://travis-ci.org/nikita-volkov/hasql)
|
||||||
|
|
||||||
|
|
||||||
|
Hasql provides a robust and concise yet powerful API for communication with arbitrary relational databases using SQL.
|
||||||
|
|
||||||
|
Currently the only backend available is for PostgreSQL ([which can yield great performance improvements](https://nikita-volkov.github.io/hasql-benchmarks/) over HDBC or postgresql-simple).
|
||||||
|
|
||||||
|
The code used here file is the [demo found in the repository](https://github.com/nikita-volkov/hasql/blob/master/demo/Main.hs)
|
||||||
|
|
||||||
|
## Openning a connection
|
||||||
|
|
||||||
|
For greater convenience the Hasql has a built-in connection pool. All interactions with the database backend are done within the context of such a pool.
|
||||||
|
|
||||||
|
So we have functions to create a pool and one to release all resources held by the pool:
|
||||||
|
|
||||||
|
```haskell
|
||||||
|
H.acquirePool
|
||||||
|
:: Hasql.Backend.Cx c =>
|
||||||
|
Hasql.Backend.CxSettings c -> H.PoolSettings -> IO (H.Pool c)
|
||||||
|
```
|
||||||
|
|
||||||
|
and
|
||||||
|
|
||||||
|
```haskell
|
||||||
|
H.releasePool :: H.Pool c -> IO ()
|
||||||
|
```
|
||||||
|
|
||||||
|
To create the pool we need to pass the connection settings (which are backend dependent) and the pool settings. The code sample below will open a connection to a PostgreSQL database.
|
||||||
|
|
||||||
|
```haskell
|
||||||
|
{-# LANGUAGE QuasiQuotes, ScopedTypeVariables, OverloadedStrings #-}
|
||||||
|
|
||||||
|
-- Import the API from the "hasql" library
|
||||||
|
import qualified Hasql as H
|
||||||
|
|
||||||
|
-- Import the backend API from the "hasql-postgres" library
|
||||||
|
import qualified Hasql.Postgres as HP
|
||||||
|
let postgresSettings = HP.ParamSettings "localhost" 5432 "postgres" "" "postgres"
|
||||||
|
|
||||||
|
-- Prepare the pool settings with a smart constructor,
|
||||||
|
-- which checks the inputted values on correctness.
|
||||||
|
-- Set the connection pool size to 6 and the timeout to 30 seconds.
|
||||||
|
poolSettings <- maybe (fail "Improper session settings") return $
|
||||||
|
H.poolSettings 6 30
|
||||||
|
|
||||||
|
-- Acquire the database connections pool.
|
||||||
|
-- Gotta help the compiler with the type signature of the pool a bit.
|
||||||
|
pool :: H.Pool HP.Postgres
|
||||||
|
<- H.acquirePool postgresSettings poolSettings
|
||||||
|
```
|
||||||
|
|
||||||
|
## Executing a statement
|
||||||
|
|
||||||
|
To execute statements we will use a ```Session```, which is just a wrapper for the ```ReaderT``` monad.
|
||||||
|
This allow us to use the pool for all our session sub-computations.
|
||||||
|
|
||||||
|
So the ```session``` function, is a wrapper for the ```runReaderT```, and besides a parameter with the pool,
|
||||||
|
we need to pass a function with the return type in ```H.Session``` monad. And as the return we get
|
||||||
|
either a ```SessionError``` or the result of our function.
|
||||||
|
|
||||||
|
The function we will use to actually execute the transactions is the ```tx```
|
||||||
|
which conveniently enough receives a transaction mode, the transactions we want to execute (along with their session context)
|
||||||
|
and returns the type ```H.Session c m r```.
|
||||||
|
|
||||||
|
It is **important** to notice that running ```IO``` in ```Tx``` is prohibited.
|
||||||
|
|
||||||
|
let's take a look at the signatures proceding:
|
||||||
|
|
||||||
|
```haskell
|
||||||
|
H.session
|
||||||
|
:: H.Pool c -> H.Session c m a -> m (Either (H.SessionError c) a)
|
||||||
|
|
||||||
|
H.tx
|
||||||
|
:: (Control.Monad.Trans.Control.MonadBaseControl IO m,
|
||||||
|
Hasql.Backend.CxTx c) =>
|
||||||
|
H.TxMode -> (forall s. H.Tx c s r) -> H.Session c m r
|
||||||
|
```
|
||||||
|
|
||||||
|
The following code excerpt shows us how the demo code uses these functions to open a
|
||||||
|
session and start a transaction to create a new table:
|
||||||
|
|
||||||
|
```haskell
|
||||||
|
-- Provide a context for execution of transactions.
|
||||||
|
-- 'Session' is merely a convenience wrapper around 'ReaderT'.
|
||||||
|
H.session pool $ do
|
||||||
|
|
||||||
|
-- Execute a group of statements without any locking and ACID guarantees:
|
||||||
|
H.tx Nothing $ do
|
||||||
|
H.unitEx [H.stmt|DROP TABLE IF EXISTS a|]
|
||||||
|
H.unitEx [H.stmt|CREATE TABLE a (id SERIAL NOT NULL, balance INT8, PRIMARY KEY (id))|]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Transactions (isolation levels and transaction modes)
|
||||||
|
|
||||||
|
You have probably noticed that the first parameter of ```tx``` belongs to the type ```TxMode```.
|
||||||
|
This parameter deserves some consideration, for it will determine the behaviour of our transaction.
|
||||||
|
Let's take a look at its type definition:
|
||||||
|
|
||||||
|
```haskell
|
||||||
|
type TxMode = Maybe (TxIsolationLevel, TxWriteMode)
|
||||||
|
|
||||||
|
data TxIsolationLevel =
|
||||||
|
RepeatableReads |
|
||||||
|
Serializable |
|
||||||
|
ReadCommitted |
|
||||||
|
ReadUncommitted
|
||||||
|
|
||||||
|
type TxWriteMode = Maybe Bool
|
||||||
|
```
|
||||||
|
|
||||||
|
So when the ```mode``` is ```Nothing```, no transaction is explicitly estabilished on the server.
|
||||||
|
In PostgreSQL's case this means all commands be commited immediatly after execution
|
||||||
|
and their isolation level will be *Read Committed*.
|
||||||
|
|
||||||
|
If we pass the tuple, the first element will be the transaction isolation level, you can read more about
|
||||||
|
[transaction isolation levels on wikipedia](https://en.wikipedia.org/wiki/Isolation_(database_systems)#Isolation_levels).
|
||||||
|
|
||||||
|
The second element is the write mode, which will be interpreted as:
|
||||||
|
|
||||||
|
* ```Nothing``` indicates a "read" mode.
|
||||||
|
* ```Just True``` indicates a "write" mode.
|
||||||
|
* ```Just False``` indicates a "write" mode without committing (can be useful for testing purposes).
|
||||||
|
|
Loading…
Reference in New Issue
Block a user