We can PostgreSQL on Arch Linux for our Haskell projects with packages like persistent
and persistent-postgresql
setting up involves several steps: installing and setting up PostgreSQL, configuring your Haskell environment, and modifying your Haskell code to connect to PostgreSQL instead of SQLite.
Additionally look into the esqueleto
package for advanced SQL-specific support.
First, ensure that PostgreSQL is installed on your Arch Linux system.
sudo pacman -Syu postgresql
After installation, you need to initialize the PostgreSQL database cluster.
sudo -iu postgres initdb --locale $LANG -E UTF8 -D /var/lib/postgres/data
Start the PostgreSQL service and enable it to start automatically on boot.
sudo systemctl enable postgresql --now
Switch to the postgres
user to create a new PostgreSQL role and database.
sudo -iu postgres
Create a new PostgreSQL user (replace yourusername
and yourpassword
with your desired credentials):
--interactive createuser yourusername
You’ll be prompted to answer some questions. For most Haskell applications, you might want to grant the user superuser privileges or specific privileges as needed.
Set a password for the new user:
psqlALTER USER yourusername WITH PASSWORD 'yourpassword';
\q
Create a new database (typically the same name as your project or user):
createdb yourdatabase
Exit the postgres
user session:
exit
By default, PostgreSQL may be configured to allow only local connections. You might need to modify the pg_hba.conf
file to allow your application to connect.
Edit the pg_hba.conf
file:
sudo nano /var/lib/postgres/data/pg_hba.conf
Ensure you have a line like the following to allow local connections using MD5 (password):
# TYPE DATABASE USER ADDRESS METHOD
local all all md5
Similarly, if you need to allow TCP/IP connections, ensure listen_addresses
is set appropriately in postgresql.conf
:
sudo nano /var/lib/postgres/data/postgresql.conf
Set listen_addresses
to '*'
to allow connections from any IP (use with caution):
listen_addresses = '*'
After making changes, restart PostgreSQL:
sudo systemctl restart postgresql
Ensure that you have the necessary Haskell libraries installed for interacting with PostgreSQL via persistent
.
Add the following dependencies to your .cabal
file or package.yaml
:
dependencies:
- persistent
- persistent-postgresql
- postgresql-simple
Alternatively, if you’re using stack
, add them to your package.yaml
under dependencies
.
Then, update your package list:
cabal update
or for stack
:
stack update
Modify your Haskell code to use PostgreSQL instead of SQLite. Here’s a basic example of how to set up persistent
with PostgreSQL.
a. Define Your Models
In your models
file (commonly named models.hs
or similar), ensure you have your entities defined. For example:
{-# LANGUAGE GADTs #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
import Database.Persist.TH
"migrateAll"] [persistLowerCase|
share [mkPersist sqlSettings, mkMigrate
User
name String
email String
deriving Show |]
b. Set Up the Connection
In your main application file, set up the PostgreSQL connection. Here’s a simple example using persistent
:
{-# LANGUAGE OverloadedStrings #-}
import Control.Monad.IO.Class (liftIO)
import Database.Persist
import Database.Persist.Postgresql
import Database.Persist.TH
import Control.Monad.Logger (runStdoutLoggingT)
import qualified Data.Text as T
-- Import your models
import Models -- Replace with your actual models module
main :: IO ()
= runStdoutLoggingT $ withPostgresqlPool connStr 10 $ \pool -> liftIO $ do
main flip runSqlPersistMPool pool $ do
runMigration migrateAll
-- Example: Insert a user
<- insert $ User "John Doe" "john@example.com"
userId
-- Example: Retrieve users
<- selectList [] []
users $ print (users :: [Entity User])
liftIO
where
= "host=localhost dbname=yourdatabase user=yourusername password=yourpassword port=5432" connStr
c. Environment Variables (Optional but Recommended)
For security reasons, it’s better to manage your database credentials using environment variables instead of hard-coding them.
Modify the connection string to read from environment variables:
import System.Environment (getEnv)
main :: IO ()
= do
main <- getEnv "DB_HOST"
host <- getEnv "DB_NAME"
dbname <- getEnv "DB_USER"
user <- getEnv "DB_PASSWORD"
password let connStr = T.pack $ "host=" ++ host ++
" dbname=" ++ dbname ++
" user=" ++ user ++
" password=" ++ password ++
" port=5432"
$ withPostgresqlPool connStr 10 $ \pool -> liftIO $ do
runStdoutLoggingT flip runSqlPersistMPool pool $ do
runMigration migrateAll-- Your database operations
Then, set the environment variables in your shell or using a .env
file with a tool like direnv
.
Before integrating deeply into your application, it’s a good idea to test the connection separately to ensure everything is set up correctly.
You can use psql
to test:
psql -h localhost -U yourusername -d yourdatabase
If you can connect and perform basic operations, your PostgreSQL setup is working correctly.
If you’re transitioning an existing project from SQLite to PostgreSQL:
Backup Your SQLite Data: Export your existing SQLite data, possibly to a format like CSV or SQL.
Import into PostgreSQL: Use psql
or tools like pgloader
to import the data into your new PostgreSQL database.
Example with pgloader
:
pgloader sqlite:///path/to/sqlite.db postgresql://yourusername:yourpassword@localhost/yourdatabase
Update Your Haskell Code: Modify the connection settings as shown above to point to PostgreSQL instead of SQLite.
Security: Always ensure that your database credentials are secured and not exposed in your codebase. Use environment variables or secure configuration management.
Performance Tuning: PostgreSQL offers many configuration options for performance tuning. Depending on your application’s needs, you might want to adjust settings in postgresql.conf
.
Backup Strategy: Implement regular backups of your PostgreSQL database to prevent data loss.
Monitoring: Use tools like pgAdmin
, PostgreSQL Exporter
for Prometheus, or other monitoring tools to keep an eye on your database’s health and performance.