Persistent

repository·master·Indexed 19 days ago

https://github.com/yesodweb/persistent

A Haskell datastore library (ORM) providing type-safe database interactions to catch errors at compile-time and reduce serialization boilerplate. It features a backend-agnostic architecture supporting PostgreSQL, MySQL, SQLite, MongoDB, and Redis. The ecosystem includes persistent-qq for raw SQL, esqueleto for complex queries, and persistent-typed-db for multi-database access.

Tokens
5.1K
Snippets
15
Records
29
Agent score
67%

What's inside Persistent

  1. Use sqlQQ and executeQQ in persistent-qq

    master

    The persistent-qq package provides two primary functions for executing raw SQL queries within the Persistent framework:

    1. sqlQQ: Likely used for querying the database and returning results (selection).
    2. executeQQ: Likely used for executing raw SQL commands that do not return a result set (execution/mutation).

    These functions allow you to bypass the standard Persistent DSL to run arbitrary SQL while remaining integrated with your existing database connections.

  2. Status of persistent-mongoDB

    master
    The persistent-mongoDB backend is currently on hiatus due to complexities involving EmbedEntityDef. A future version of persistent is planned to resolve these issues and make the MongoDB backend easier to use. If you require MongoDB support immediately, the maintainers welcome Pull Requests to improve the current implementation.
  3. Use persistent-mysql as a backend for Persistent

    master
    persistent-mysql is a backend implementation for the persistent database library that allows you to use the MySQL database server as your storage engine. It provides the necessary integration to use MySQL with Persistent's type-safe querying and entity management features.
  4. Use persistent-redis for Redis backend support

    master

    The persistent-redis package provides a Redis backend implementation for the Yesod Persistent library.

    Supported Data Types: Currently, this backend only supports the following types:

    • String
    • Bool
    • Double
    • Integer

    Compatibility: This version is compatible with persistent 2.1.

  5. Use esqueleto for complex SQL queries

    master
    While Persistent provides a high-level API for basic CRUD operations, you can use the esqueleto library to perform more complex SQL queries (such as joins and advanced filtering) while still leveraging Persistent's backend types.
  6. Understand Persistent's backend agnostic architecture

    master

    Persistent is designed to be adaptable to various datastores, allowing multiple backends to be used simultaneously. It separates the serialization layer from the query layer.

    Supported Backends

    • SQL Databases: PostgreSQL, SQLite, and others via persistent-odbc.
    • Key-Value Stores: Redis and ZooKeeper (Note: Key-value stores typically only implement the PersistStore API for basic operations, rather than the full PersistQuery API).

    Key Architectural Concepts

    • Serialization vs. Querying: The serialization layer is adaptable to any datastore. While SQL databases support complex queries, Persistent's universal query layer has limitations, such as not providing direct joins.
    • Extending SQL Queries: For complex SQL operations like joins, it is recommended to use Esqueleto alongside Persistent's serialization to maintain type safety.
    • Fallback Mechanism: If Persistent's abstraction is too limiting for a specific task, you can fall back to using raw database drivers or lower-level libraries, using Persistent specifically for un-serializing database responses into Haskell records.
  7. Quickstart with Persistent and SQLite

    master

    To use Persistent, you need to define your data models using Template Haskell quasi-quotes and then run migrations to set up your schema. Persistent provides type-safe interactions for inserting, reading, and deleting data.

    Dependencies

    Add the following to your package.yaml:

    dependencies:
    - base ^>= 4.17
    - text ^>= 2
    - persistent ^>= 2.14
    - persistent-sqlite ^>= 2.13

    Basic Usage Example

    This example demonstrates defining a Person model, running a migration on an in-memory SQLite database, inserting records, querying them, and deleting them.

    {-# LANGUAGE EmptyDataDecls             #-}
    {-# LANGUAGE FlexibleContexts           #-}
    {-# LANGUAGE GADTs                      #-}
    {-# LANGUAGE GeneralizedNewtypeDeriving #-}
    {-# LANGUAGE MultiParamTypeClasses      #-}
    {-# LANGUAGE OverloadedStrings          #-}
    {-# LANGUAGE QuasiQuotes                #-}
    {-# LANGUAGE TemplateHaskell            #-}
    {-# LANGUAGE TypeFamilies               #-}
    import           Control.Monad.IO.Class  (liftIO)
    import           Database.Persist
    import           Database.Persist.Sqlite
    import           Database.Persist.TH
    import           Data.Text
    
    share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase|
    Person
        name Text
        age Int Maybe
        deriving Show
    |]
    
    main :: IO ()
    main = runSqlite ":memory:" $ do
        -- setup db schema
        runMigration migrateAll
        
        -- write to db
        insert $ Person "Jane Doe" Nothing
        johnId <- insert $ Person "John Doe" $ Just 35
    
        -- read from db
        john1 <- selectList [PersonId ==. johnId] [LimitTo 1]
        john2 <- get johnId
    
        liftIO $ print (john1 :: [Entity Person])
        liftIO $ print (john2 :: Maybe Person)
        
        -- delete from db
        delete johnId
        deleteWhere [PersonId ==. johnId]
  8. Build Persistent from source

    master

    To build the Persistent project from source, clone the repository and use stack:

    stack build

    If you only need to build against a specific subset of backends, refer to the development.md file for instructions.