persistent-mysql-haskell

A pure haskell backend for the persistent library using MySQL database server.

http://www.yesodweb.com/book/persistent

Version on this page:0.5.2
LTS Haskell 14.27:0.5.2
Stackage Nightly 2019-08-07:0.5.2
Latest on Hackage:0.6.0

See all snapshots persistent-mysql-haskell appears in

MIT licensed by Naushadh, Felipe Lessa, Michael Snoyman
Maintained by Naushadh
This version can be pinned in stack with:persistent-mysql-haskell-0.5.2@sha256:e3119000465a1facbf4d3cad111f816c5008eb9182d4c4a6b8d8a4a2a5ded1b5,2847

Module documentation for 0.5.2

persistent-mysql-haskell

hackage version Build Status

A pure haskell backend for persistent using the MySQL database server. Internally it uses the mysql-haskell driver in order to access the database.

See example/Main.hs for how this MySQL backend can be used with Persistent.

Motivation

persistent-mysql uses mysql (via mysql-simple) as the database driver. mysql is a haskell FFI wrapper for mysqlclient written in C.

Reasons to use a pure haskell driver:

Personal experience on replacing mysql-simple with mysql-haskell in a project:

  • Performance gains consistent with benchmark.

  • Smoother deployment to AWS, since mysql appears to have a hard dependency on the oracle version of libmysqlclient that does not work with the open source variant that is available by default on Amazon Linux (and possibly on other Linux distros).

Potential issues moving from persistent-mysql to persistent-mysql-haskell

ConnectInfo and defaultConnectInfo are not the same between mysql and mysql-haskell, therefore this package is not a 100% drop in replacement for persistent-mysql from the connection configuration perspective.

  • mysql-haskell does not allow provide an API for the entirety of mysqlclient options. Therefore neither can this package.

  • Given the inevitable incompatibility with persistent-mysql, and in the interest of providing a forward-compatible API, ConnectInfo internals and defaultConnectInfo have been deprecated. However the similar utility can be achieved like so:

    import Database.Persist.MySQL
    
    connectInfo :: MySQLConnectInfo
    - connectInfo = defaultConnectInfo
    -             { connectHost     = "localhost"
    -             , connectUser     = "test"
    -             , connectPassword = "test"
    -             , connectDatabase = "test"
    -             }
    + connectInfo = mkMySQLConnectInfo "localhost" "test" "test" "test"
    
    connectInfoNewPort :: MySQLConnectInfo
    - connectInfoNewPort = connectInfo { connectPort = 3307 }
    + connectInfoNewPort = setMySQLConnectInfoPort 3307 connectInfo
    
    connectInfoNewCharSet :: MySQLConnectInfo
    - connectInfoNewCharSet = connectInfo { connectOptions = [CharsetName "utf8"] }
    + connectInfoNewCharSet = setMySQLConnectInfoCharset 33 connectInfo
    
    
  • mysql-haskell and mysql have different APIs/mechanisms for securing the connection to MySQL. persistent-mysql-haskell exposes an API to utilize TLS client params that ships with mysql-haskell.

    connectInfoCustomCaStore :: MySQLConnectInfo
    - connectInfoCustomCaStore = connectInfo { connectSSL = Just customCaParams }
    + connectInfoCustomCaStore = setMySQLConnectInfoTLS customCaParams connectInfo
        where
    -         customCaParams = defaultSSLInfo { sslCAPath = "foobar.pem" }
    +         customCaParams = makeClientParams $ CustomCAStore "foobar.pem"
    

Aside from connection configuration, persistent-mysql-haskell is functionally on par with persistent-mysql (as of writing this). This can be seen by comparing persistent-test between this fork and upstream.

Yesod

In order to use persistent-mysql-haskell with yesod you have to modify Settings.hs:

- import Database.Persist.MySQL     (MySQLConf (..))
+ import Database.Persist.MySQL     (MySQLConf, mkMySQLConf, myConnInfo, myPoolSize, setMySQLConnectInfoCharset)
- import qualified Database.MySQL.Base as MySQL
-         -- This code enables MySQL's strict mode, without which MySQL will truncate data.
-         -- See https://github.com/yesodweb/persistent/wiki/Database-Configuration#strict-mode for details
-         -- If you choose to keep strict mode enabled, it's recommended that you enable it in your my.cnf file so that it's also enabled for your MySQL console sessions.
-         -- (If you enable it in your my.cnf file, you can delete this code).
-         let appDatabaseConf = fromYamlAppDatabaseConf { myConnInfo = (myConnInfo fromYamlAppDatabaseConf) {
-                 MySQL.connectOptions =
-                   ( MySQL.connectOptions (myConnInfo fromYamlAppDatabaseConf)) ++ [MySQL.InitCommand "SET SESSION sql_mode = 'STRICT_ALL_TABLES';\0"]
-               }
-             }

And in Application.hs:

- import qualified Database.MySQL.Base as MySQL
  import Network.Wai.Handler.Warp             (Settings, defaultSettings,
                                               defaultShouldDisplayException,
                                               runSettings, setHost,
-                                              setFork, setOnOpen, setOnClose,
+                                              setFork,
                                               setOnException, setPort, getPort)
-     -- See http://www.yesodweb.com/blog/2016/11/use-mysql-safely-in-yesod
-     MySQL.initLibrary
-     $ setOnOpen (const $ MySQL.initThread >> return True)
-     $ setOnClose (const MySQL.endThread)

Optionally you may enable the MYSQL strict mode (in each transaction) by modifying Foundation.hs (or editing the my.cnf server configuration):

- import Database.Persist.Sql (ConnectionPool, runSqlPool)
+ import Database.Persist.Sql (ConnectionPool, rawExecute, runSqlPool)
-         runSqlPool action $ appConnPool master
+         runSqlPool
+           (rawExecute "SET SESSION sql_mode = 'STRICT_ALL_TABLES'" [] >> action)
+           (appConnPool master)

FAQs

Why isn’t this part of the main/upstream persistent repo?

persistent-mysql supports X but persistent-mysql-haskell API doesn’t. Why?

  • Internals (getters/setters) of MySQLConnectInfo and defaultConnectInfo are intentionally masked for forward compatibility.

  • For all others, feel free to open an issue and/or submit a PR.

Does persistent-mysql-haskell ship with tests?

  • It does! :) persistent-test is fully re-used with an additional flag to specifically test persistent-mysql-haskell.

    stack test persistent-test --flag persistent-test:mysql_haskell --exec persistent-test
    

Changes

ChangeLog for persistent-mysql-haskell

0.5.2

0.5.1

  • #9 Add insertEntityOnDuplicateKeyUpdate and insertEntityManyOnDuplicateKeyUpdate functions

0.5.0

  • Port #812 from persistent-mysql: Add support for SQL isolation levels
  • Port #833 from persistent-mysql: repsertMany now matches mapM_ (uncurry repsert) and is atomic.

0.4.2

  • #7 Fix boolean conversion bug.

0.4.1

  • Fix #2: Better compatibility with yesod scaffold.

0.4.0

  • Port #770 from persistent-mysql: Performance enhancements for bulk writes.
  • Port #773 from persistent-mysql: Support new conduit release. Includes bundled changes from other PRs.
    • #723 More BackendCompatible generalizations.
    • #760 Rename SomeField type to HandleUpdateCollision.

0.3.6

  • Port #752 from persistent-mysql: Fix mysql sqltype migrations.

0.3.5

  • Updated selectSource implementation to stream results instead of loading everything into memory.

0.3.4.1

  • Fix a haddock issue down-streamed from #693.

0.3.4

  • Port #693 from persistent-mysql: Extend the SomeField type to allow insertManyOnDuplicateKeyUpdate to conditionally copy values.
  • Port #702 from persistent-mysql: Fix behavior of insertManyOnDuplicateKeyUpdate to ignore duplicate key exceptions when no updates specified.
  • Bumped TLS bounds to be in sync with mysql-haskell and land ourselves back on stackage.

0.3.3

  • Port from persistent-mysql: MySQL on duplicate key update #674.

0.3.2.1

  • Port from persistent-mysql: Prevent spurious no-op migrations when default=NULL is specified - revised version #672 (which fixes bug #671 introduced by the earlier attempt #641).

0.3.2.0

  • Added conditional declaration of Show instance for mysql-haskell’s ConnectInfo for compatibility with mysql-haskell-0.8.1.0+.

0.3.1.0

  • Fixed compiler warnings in stack --pedantic mode so the project can run upstream tests on Travis.
  • Minor README enhancements for badges and fixed URL for example when viewing outside of Github.

0.3.0.0

0.2.1.0

  • Bumped up version to update README.

0.2.0.0

  • Added APIs for setting port number and character encoding.
  • Updated type signature for mkMySQLConnectInfo to align with mysql-haskell.

0.1.1.0

  • Bumped up version to include README and example.

0.1.0.0