Skip to content

Commit

Permalink
update the SQLite foreign key example
Browse files Browse the repository at this point in the history
The previous example didn't demonstrate how to
enable proper pooling -- only one underlying
connection was ever actually opened, despite the
pool size specified. This corrects it to open
a new connection every time a new SqlBackend is
requested from the pool.
  • Loading branch information
ianthehenry committed Jun 22, 2016
1 parent 7ab4ee9 commit b8082fc
Showing 1 changed file with 14 additions and 12 deletions.
26 changes: 14 additions & 12 deletions cookbook/Activate-foreign-key-checking-in-Sqlite.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,21 @@ In SQLite, foreign keys checks [are not enabled by default](https://www.sqlite.o
PRAGMA foreign_keys = ON;
```

The command to issue foreign keys is [a noop if done inside of a transaction](https://www.sqlite.org/foreignkeys.html#fk_enable), so it is necessary to enable them outside of one. Persistent functions like `runSqlPersistMPool` wrap your statements inside of a transaction, necessitating dropping down to the underlying Database.Sqlite package to enable foreign keys. To do this, add the following imports and functions to `Application.hs`:
The command to issue foreign keys is [a noop if done inside of a transaction](https://www.sqlite.org/foreignkeys.html#fk_enable), so it is necessary to enable them outside of one. Persistent functions like `runSqlPersistMPool` wrap your statements inside of a transaction, necessitating dropping down to the underlying `Database.Sqlite` package to enable foreign keys. To do this, add the following imports and functions to `Application.hs`:

```haskell
import qualified Database.Sqlite as Sqlite
import Database.Persist.Sqlite (createSqlPool, wrapConnection)
import Database.Persist.Sqlite (createSqlPool, wrapConnection)

rawConnection :: Text -> IO Sqlite.Connection
rawConnection t = Sqlite.open t
enableForeignKeys :: Sqlite.Connection -> IO ()
enableForeignKeys conn = Sqlite.prepare conn "PRAGMA foreign_keys = ON;" >>= void . Sqlite.step

createSqliteBackend :: Text -> LogFunc -> IO SqlBackend
createSqliteBackend connStr logFunc = do
conn <- Sqlite.open connStr
enableForeignKeys conn
wrapConnection conn logFunc

disableForeignKeys :: Sqlite.Connection -> IO ()
disableForeignKeys conn = Sqlite.prepare conn "PRAGMA foreign_keys = ON;" >>= void . Sqlite.step
```

Then, in the `makeFoundation` function, replace this code:
Expand All @@ -30,18 +34,16 @@ pool <- flip runLoggingT logFunc $ createSqlitePool
with this:

```
sqliteConn <- rawConnection (sqlDatabase $ appDatabaseConf appSettings)
disableForeignKeys sqliteConn
pool <- flip runLoggingT logFunc $ createSqlPool
(wrapConnection sqliteConn)
let dbPath = sqlDatabase (appDatabaseConf appSettings)
pool <- flip runLoggingT logFunc $ createSqlPool
(createSqliteBackend dbPath)
(sqlPoolSize $ appDatabaseConf appSettings)
```

You can then verify that foreign keys are enabled by sending `PRAGMA foreign_keys` to SQLite:

```haskell
import Database.Persist.Sql (SqlBackend, rawSql, unSingle)
import Database.Persist.Sql (SqlBackend, rawSql, unSingle)

fksEnabled :: MonadIO m => ReaderT SqlBackend m Bool
fksEnabled = do
Expand Down

0 comments on commit b8082fc

Please sign in to comment.