### Haskell Persistent Quickstart with SQLite Source: https://github.com/yesodweb/persistent/blob/master/README.md This snippet demonstrates a basic Persistent setup in Haskell using the SQLite backend. It defines a 'Person' entity with 'name' and 'age' fields, sets up the database schema, performs insert, select, and delete operations, and prints the results. It requires the 'persistent', 'persistent-sqlite', 'text', and 'base' Haskell packages. ```haskell {-# 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] ``` -------------------------------- ### Haskell API Documentation Example Source: https://github.com/yesodweb/persistent/blob/master/CONTRIBUTING.md An example of Haddock documentation for a Haskell function in the Persistent library. It includes a description, usage examples, and version information, following the project's documentation standards. ```haskell -- | Retrieve a list of a certain 'Entity' from the database -- -- ==== __Examples__ -- -- @ -- selectUsers :: 'MonadIO' m => 'ReaderT' 'SqlBackend' m ['Entity' User] -- selectUsers = 'selectList' [UserAge <-. [40, 41]] [] -- @ -- -- @since 1.5.4 selectList :: (MonadIO m, PersistQueryRead backend, PersistRecordBackend record backend) => [Filter record] -- ^ Options to filter the query result; see "Query filter combinators" in the Database.Persist documetation -> [SelectOpt record] -- ^ Options to limit and sort the returned records. -> ReaderT backend m [Entity record] selectList = ... ``` -------------------------------- ### MySQL Database Setup for Testing Source: https://github.com/yesodweb/persistent/blob/master/persistent-mysql/README.md This snippet demonstrates the SQL commands required to set up a MySQL database named 'test' with a user 'test' for development and testing purposes. It ensures the necessary privileges are granted for the test user. ```sql mysql -u root # MySQL root username and password may vary CREATE DATABASE test; CREATE USER 'test'@'localhost' IDENTIFIED BY 'test'; GRANT ALL on test.* TO 'test'@'localhost'; ``` -------------------------------- ### Configure Stack for Local Development Source: https://github.com/yesodweb/persistent/blob/master/CONTRIBUTING.md Provides an example of how to configure the `stack.yaml` file to build against a local copy of a Persistent subproject. This is useful for testing changes in a full application context. ```yaml packages: - '/path/to/this/repo/persistent-postgresql' ``` -------------------------------- ### PostgreSQL Connection Pool Management Source: https://context7.com/yesodweb/persistent/llms.txt Illustrates setting up and using a PostgreSQL connection pool for production environments. It uses `withPostgresqlPool` for managing the pool within a scope and `createPostgresqlPool` for creating a pool that can be used across multiple actions. Includes examples of running migrations and querying data. ```haskell #{-# LANGUAGE OverloadedStrings #-} import Control.Monad.Logger (runStderrLoggingT) import Database.Persist.Postgresql import Data.ByteString.Char8 (ByteString) connStr :: ByteString connStr = "host=localhost dbname=mydb user=postgres password=secret port=5432" main :: IO () main = runStderrLoggingT $ withPostgresqlPool connStr 10 $ \pool -> do liftIO $ flip runSqlPersistMPool pool $ do runMigration migrateAll -- Insert a user userId <- insert $ User "john@example.com" "johndoe" -- Query users users <- selectList [UserEmail ==. "john@example.com"] [] liftIO $ print users -- Alternative: Create pool and use it multiple times createAppPool :: IO (Pool SqlBackend) createAppPool = runStderrLoggingT $ createPostgresqlPool connStr 10 runDbAction :: Pool SqlBackend -> SqlPersistM a -> IO a runDbAction pool action = runSqlPersistMPool action pool ``` -------------------------------- ### Connection Pool Management with Persistent Source: https://context7.com/yesodweb/persistent/llms.txt Configure and manage database connection pools for production applications using Persistent. Examples demonstrate SQLite and PostgreSQL pool creation with custom configurations. ```haskell {-# LANGUAGE OverloadedStrings #-} import Control.Monad.Logger import Database.Persist.Sql import Database.Persist.Sqlite import Database.Persist.Postgresql import Data.Pool (Pool) -- SQLite pool sqlitePoolExample :: IO () sqlitePoolExample = runStderrLoggingT $ do pool <- createSqlitePool "mydb.sqlite3" 10 liftIO $ runSqlPool (runMigration migrateAll) pool -- PostgreSQL with custom config postgresPoolExample :: IO () postgresPoolExample = runStderrLoggingT $ do let config = defaultConnectionPoolConfig { connectionPoolConfigSize = 20 , connectionPoolConfigIdleTimeout = 600 -- 10 minutes , connectionPoolConfigStripes = 2 } withPostgresqlPoolWithConf connStr config $ \pool -> do liftIO $ runSqlPool someAction pool where connStr = "host=localhost dbname=mydb user=postgres" -- Use withSqlPool for bracket-style resource management bracketExample :: IO () bracketExample = runStderrLoggingT $ withSqlitePool "mydb.sqlite3" 5 $ \pool -> do -- Pool is automatically cleaned up after this block liftIO $ runSqlPool myDatabaseAction pool myDatabaseAction :: SqlPersistM () myDatabaseAction = do runMigration migrateAll insert_ $ Person "Test" (Just 25) someAction :: SqlPersistM () someAction = return () ``` -------------------------------- ### Run SQLite Database Operations Source: https://context7.com/yesodweb/persistent/llms.txt Demonstrates how to perform basic SQLite database operations using `runSqlite`. This function handles connection management and runs migrations. It includes examples of inserting records, retrieving a single record by its key, and fetching all records of a specific type. ```haskell import Control.Monad.IO.Class (liftIO) import Database.Persist.Sqlite main :: IO () main = runSqlite ":memory:" $ do -- Run migrations to create tables runMigration migrateAll -- Insert records johnId <- insert $ Person "John Doe" (Just 35) janeId <- insert $ Person "Jane Doe" Nothing -- Insert a blog post referencing John _ <- insert $ BlogPost "Hello World" johnId True -- Read a single record by key mJohn <- get johnId liftIO $ print mJohn -- Output: Just (Person {personName = "John Doe", personAge = Just 35}) -- Fetch all persons allPersons <- selectList [] [] liftIO $ print (allPersons :: [Entity Person]) ``` -------------------------------- ### Using Pre-existing Entity Definitions with mkPersistWith (Haskell) Source: https://github.com/yesodweb/persistent/blob/master/persistent/ChangeLog.md Introduces `mkPersistWith`, enabling the use of a list of pre-existing `EntityDef` during persistence setup. This improves foreign key detection and allows for splitting models across multiple modules. ```haskell mkPersistWith [existingEntityDef1, existingEntityDef2] settings myModel ``` -------------------------------- ### Haskell Package Dependencies for Persistent Source: https://github.com/yesodweb/persistent/blob/master/README.md This YAML snippet outlines the necessary package dependencies for a Haskell project using Persistent. It specifies versions for 'base', 'text', 'persistent', and 'persistent-sqlite', ensuring compatibility and proper setup for database operations. ```yaml dependencies: - base ^>= 4.17 - text ^>= 2 - persistent ^>= 2.14 - persistent-sqlite ^>= 2.13 ``` -------------------------------- ### Haskell: Get Operations with Persistent ORM Source: https://context7.com/yesodweb/persistent/llms.txt Illustrates various methods for retrieving records by their primary key in Haskell using the Persistent ORM. It covers safe retrieval with 'get' and 'getEntity', unsafe retrieval with 'getJust' and 'getJustEntity', fetching multiple records with 'getMany', and foreign key lookups with 'belongsTo'. ```haskell import Database.Persist import Database.Persist.Sqlite getExamples :: SqlPersistM () getExamples = do johnId <- insert $ Person "John" (Just 30) -- Get Maybe record (safe, returns Nothing if not found) mPerson <- get johnId case mPerson of Just person -> liftIO $ print person Nothing -> liftIO $ putStrLn "Not found" -- Get Entity (key + record) mEntity <- getEntity johnId -- Get record, throw exception if not found (unsafe) person <- getJust johnId -- Get Entity, throw exception if not found entity <- getJustEntity johnId -- Get many records by keys let keys = [johnId] personsMap <- getMany keys -- Returns Map (Key Person) Person -- Helper for foreign key lookups -- Assuming BlogPost has authorId :: PersonId let blogPost = BlogPost "Title" johnId True mAuthor <- belongsTo blogPostAuthorId blogPost return () ``` -------------------------------- ### Haskell: Raw SQL Queries with Persistent ORM Source: https://context7.com/yesodweb/persistent/llms.txt Shows how to execute raw SQL queries in Haskell using the Persistent ORM when ORM abstractions are insufficient. It covers executing queries without results, getting affected row counts, querying entities, single values, multiple columns, and performing join queries. ```haskell {-# LANGUAGE OverloadedStrings #-} import Database.Persist import Database.Persist.Sql import Data.Text (Text) rawSqlExamples :: SqlPersistM () rawSqlExamples = do -- Execute raw SQL without results rawExecute "UPDATE person SET age = age + 1 WHERE name = ?" [PersistText "John"] -- Execute and get affected row count rowCount <- rawExecuteCount "DELETE FROM person WHERE age < ?" [PersistInt64 18] liftIO $ print rowCount -- Query with entity placeholder (??) persons :: [Entity Person] <- rawSql "SELECT ?? FROM person WHERE age > ?" [PersistInt64 25] -- Query single values ages :: [Single Int] <- rawSql "SELECT age FROM person WHERE name = ?" [PersistText "John"] -- Query multiple columns results :: [(Single Text, Single Int)] <- rawSql "SELECT name, age FROM person WHERE age > ?" [PersistInt64 20] -- Join query with multiple entities postsWithAuthors :: [(Entity Person, Entity BlogPost)] <- rawSql "SELECT ??, ?? FROM person \ \INNER JOIN blog_post ON person.id = blog_post.author_id" [] return () ``` -------------------------------- ### Run Persistent Subproject Tests with Stack Source: https://github.com/yesodweb/persistent/blob/master/CONTRIBUTING.md Illustrates how to execute the test suite for a specific Persistent subproject, such as persistent-postgresql, using Stack. This is crucial for verifying changes and ensuring code correctness. ```bash stack test persistent-postgresql ``` -------------------------------- ### Build a Persistent Subproject with Stack Source: https://github.com/yesodweb/persistent/blob/master/CONTRIBUTING.md Demonstrates how to build a specific subproject within the Persistent mega-repo using Stack. This command is useful for local development and testing of individual components. ```bash stack build persistent-mysql ``` -------------------------------- ### Create PostgreSQL Database for Testing Source: https://github.com/yesodweb/persistent/blob/master/persistent-postgresql/README.md This snippet demonstrates how to create a PostgreSQL database named 'test' using either the psql command-line interface or the createdb tool. This is a prerequisite for running tests for the persistent-postgresql library. ```bash psql -d postgres postgres=# CREATE DATABASE test; CREATE DATABASE -- or, createdb test ``` -------------------------------- ### SqlBackend Construction with Smart Constructor (Haskell) Source: https://github.com/yesodweb/persistent/blob/master/persistent/ChangeLog.md Demonstrates the refactored API for constructing a SqlBackend using `mkSqlBackend` and `MkSqlBackendArgs`. This change aims to improve the management of backend-specific configurations and optional functionalities. ```haskell ```diff -SqlBackend +mkSqlBackend MkSqlBackendArgs { connInsertSql = ... , connCommit = ... , connEscapeFieldName = ... , connEscapeTableName = ... , etc } ``` ``` -------------------------------- ### Generate Haddock Documentation with Stack Source: https://github.com/yesodweb/persistent/blob/master/CONTRIBUTING.md Shows how to generate Haddock documentation for the Persistent project using Stack. This command is essential for developers who need to inspect or generate documentation for the library. ```bash stack haddock persistent ``` -------------------------------- ### SQLite URI Filename Modes Source: https://github.com/yesodweb/persistent/blob/master/docs/Database-Configuration.md Demonstrates SQLite's URI filename syntax for database connections, allowing for additional configuration options via query parameters. The 'mode' parameter controls the connection's read/write access and creation behavior. ```text Conventional style: "sqlite3.db" URI filename style, relative path, read-only: "file:sqlite3.db?mode=ro" ``` -------------------------------- ### Running Arbitrary SQL during Migrations (Haskell) Source: https://github.com/yesodweb/persistent/blob/master/persistent/ChangeLog.md Introduces the `runSqlCommand` function, allowing developers to execute arbitrary SQL statements directly within the migration process. This provides more flexibility for complex database schema changes. ```haskell runSqlCommand "CREATE TABLE new_table (id INT)" ``` -------------------------------- ### Haskell: Select Queries with Filters and Options Source: https://context7.com/yesodweb/persistent/llms.txt Demonstrates how to query records from a database using the Persistent library. It showcases various filter combinators for equality, comparison, and list membership, along with select options for ordering and pagination. Dependencies include Database.Persist and Database.Persist.Sqlite. ```haskell import Database.Persist import Database.Persist.Sqlite queryExamples :: SqlPersistM () queryExamples = do -- Equality filter spj <- selectList [PersonName ==. "SPJ"] [] -- Age comparison adults <- selectList [PersonAge >=. Just 18] [] -- Multiple filters (AND) result <- selectList [ PersonAge >=. Just 30, PersonAge <=. Just 50 ] [] -- IN clause - check if value is in list specific <- selectList [PersonName <-. ["John", "Jane", "Bob"]] [] -- NOT IN clause others <- selectList [PersonName /<-. ["Admin", "System"]] [] -- OR clause using ||. combined <- selectList ([PersonAge >. Just 25, PersonAge <. Just 30] ||. [PersonName ==. "VIP"]) [] -- With ordering and pagination pagedResults <- selectList [] [ Asc PersonName, LimitTo 10, OffsetBy 20 ] -- Get first matching record only mFirst <- selectFirst [PersonAge >=. Just 21] [Desc PersonAge] -- Count records totalAdults <- count [PersonAge >=. Just 18] -- Check if any record exists hasAdults <- exists [PersonAge >=. Just 18] return () ``` -------------------------------- ### Output Template Haskell Splices to File Source: https://github.com/yesodweb/persistent/blob/master/persistent-template/README.md This command demonstrates how to use GHC options to dump Template Haskell splices to a file during testing. This is useful for inspecting the generated code. It requires the `stack` build tool. ```shell stack test persistent-template --ghc-options='-ddump-splices -ddump-to-file' ``` -------------------------------- ### Haskell: Standalone Show Instance for Uniques Source: https://github.com/yesodweb/persistent/blob/master/persistent/ChangeLog.md This snippet demonstrates how to derive a `Show` instance for `Unique` types in Persistent when needed. Previously, `Show` was derived automatically, but this has been removed to avoid potential issues. Users can now explicitly derive it if required. ```haskell {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DeriveAnyClass #-} import GHC.Generics (Generic) import Data.Aeson (ToJSON, FromJSON) -- Assuming a User entity with a Unique constraint -- data User = User { userName :: Text, userEmail :: Text } deriving (Eq, Show, Generic) -- instance ToJSON User -- instance FromJSON User -- Define a Unique constraint for User -- uniqueUserEmail :: Unique User -- uniqueUserEmail = unique "user_email" [UserEmail.] -- To get a Show instance for the Unique type, you can now explicitly derive it: deriving stock instance Show (Unique User) ``` -------------------------------- ### Haskell: Configuring Connection Pool Options Source: https://github.com/yesodweb/persistent/blob/master/persistent/ChangeLog.md This snippet illustrates how to configure connection pool options in Persistent, including the number of stripes and idle timeout. It introduces `ConnectionPoolConfig` and related functions like `defaultConnectionPoolConfig`, `createSqlPoolWithConfig`, and `withSqlPoolWithConfig`. ```haskell import Database.Persist.Sql import Data.Pool (Pool) -- Define connection pool configuration data ConnectionPoolConfig = ConnectionPoolConfig { connectionPoolMaxConnections :: Int , connectionPoolIdleTimeout :: Int -- in seconds , connectionPoolStripes :: Int } -- Default configuration with bumped idle timeout to 600 seconds defaultConnectionPoolConfig :: ConnectionPoolConfig defaultConnectionPoolConfig = ConnectionPoolConfig { connectionPoolMaxConnections = 10 , connectionPoolIdleTimeout = 600 , connectionPoolStripes = 1 } -- Function to create a SQL pool with custom configuration createSqlPoolWithConfig :: ConnectionPoolConfig -> IO (Pool SqlBackend) createSqlPoolWithConfig config = createSqlPool ("your_database_connection_string") (connectionPoolMaxConnections config) -- Other pool creation parameters would be set here, potentially using config values -- Function to use a SQL pool with custom configuration withSqlPoolWithConfig :: ConnectionPoolConfig -> (Pool SqlBackend -> IO a) -> IO a withSqlPoolWithConfig config f = do pool <- createSqlPoolWithConfig config withAcquire pool f ``` -------------------------------- ### TH-Free Migration Facility (Haskell) Source: https://github.com/yesodweb/persistent/blob/master/persistent/ChangeLog.md Presents the `migrateModels` function as a Template Haskell-free alternative for database migrations. This simplifies the migration process by removing the dependency on TH for defining migration logic. ```haskell migrateModels [model1, model2] ``` -------------------------------- ### Find Dump Splice Files Source: https://github.com/yesodweb/persistent/blob/master/persistent-template/README.md This command helps locate the generated Template Haskell splice output files within the `.stack-work` directory. It's a utility for finding the output generated by the previous command. ```shell find .stack-work -type f -name '*.dump-splices' ``` -------------------------------- ### Expose parseReferences Logic for Runtime Migrations in Persistent Source: https://github.com/yesodweb/persistent/blob/master/persistent-template/ChangeLog.md Version 2.7.2 exposes the knot-tying logic of `parseReferences`. This allows users to construct migrations at runtime from independently defined entities, offering greater flexibility in dynamic schema management. ```haskell import Database.Persist.Migration (parseReferences) -- Assuming parseReferences is exported import Database.Persist.Types (EntityDef) -- Assuming EntityDef is the type for entity definitions -- Example of how parseReferences might be used: -- let entityDefs :: [EntityDef] -- entityDefs = [...] -- List of independently defined entities -- let migration = parseReferences entityDefs -- Constructing migration at runtime ``` -------------------------------- ### Persistent Key Show/Read Deriving Strategy Change Source: https://github.com/yesodweb/persistent/blob/master/persistent-template/ChangeLog.md Version 2.9 reverted the `Show`/`Read` deriving strategy for keys to the "stock" strategy, fixing a regression introduced in 2.8.0. This change affects how keys are represented as strings, potentially causing breaking changes if string representations were previously relied upon for storage or parsing. ```haskell -- Example schema definition -- Person -- name Text -- CustomPrimary -- anInt Int -- Primary anInt -- name Text -- Before 2.8.0 and after 2.8.3.1: -- PersonKey 1 might show as: "PersonKey {unPersonKey = SqlBackendKey {unSqlBackendKey = 1}}" -- CustomPrimaryKey 1 might show as: "CustomPrimaryKey {unCustomPrimaryKey = 1}" -- Between 2.8.0 and 2.8.3.1: -- PersonKey 1 might show as: "SqlBackendKey {unSqlBackendKey = 1}" -- CustomPrimaryKey 1 might show as: "1" -- Example of deriving Show and Read -- data PersonKey = PersonKey Int deriving (Show, Read) -- data CustomPrimaryKey = CustomPrimaryKey Int deriving (Show, Read) ``` -------------------------------- ### Haskell: Insert Operations Source: https://context7.com/yesodweb/persistent/llms.txt Illustrates various methods for inserting records into a database using the Persistent library. It covers inserting single records, multiple records in batches, and inserting with specific keys, returning auto-generated keys or full entities. Dependencies include Database.Persist and Database.Persist.Sqlite. ```haskell import Database.Persist import Database.Persist.Sqlite insertExamples :: SqlPersistM () insertExamples = do -- Insert and get the auto-generated key johnId <- insert $ Person "John" (Just 30) -- Insert without returning key (slightly more efficient) insert_ $ Person "Jane" (Just 25) -- Insert many records at once (batch insert) userIds <- insertMany [ Person "Alice" (Just 28), Person "Bob" (Just 32), Person "Carol" (Just 27) ] -- Insert many without returning keys insertMany_ [ Person "Dave" (Just 40), Person "Eve" (Just 35) ] -- Insert and return the full Entity (key + record) johnEntity <- insertEntity $ Person "John Jr" (Just 5) liftIO $ print (entityKey johnEntity) -- PersonKey liftIO $ print (entityVal johnEntity) -- Person record -- Insert with a specific key let customKey = toSqlKey 1000 :: Key Person insertKey customKey $ Person "Custom" (Just 50) return () ``` -------------------------------- ### Allow User-Provided Derived Instances in Persistent Source: https://github.com/yesodweb/persistent/blob/master/persistent-template/ChangeLog.md Version 2.8.1 allows users to specify instances that should be derived for record and key types. This provides greater flexibility in customizing the behavior of generated types. ```haskell -- Example of how a user might specify derived instances -- $(persistFileWith settings "models.cfg") -- In models.cfg, a user could specify derived instances like: -- Person -- name Text -- deriving Show Eq -- Key types could also have derived instances specified: -- Person -- name Text -- deriving instance Show (Key Person) ``` -------------------------------- ### Haskell: Customizing Field and Constraint Labels with TH Source: https://github.com/yesodweb/persistent/blob/master/persistent/ChangeLog.md This snippet demonstrates how to customize field and constraint labels generated by Template Haskell (TH) in the Persistent library. It replaces the deprecated `mpsPrefixFields` with more flexible customization functions. ```haskell {-# LANGUAGE TemplateHaskell #-} import Database.Persist.TH -- Example of customizing field and constraint labels -- Instead of mpsPrefixFields, use custom functions for flexibility. -- This is a conceptual example, actual implementation would involve defining custom label generation functions. -- data MyEntity = MyEntity { ... } -- $(derivePersistFieldHashes ''MyEntity) -- $(makePersist "MyEntity" "my_entity" [ ... ]) -- Customization would involve passing functions to makePersist or similar TH functions -- to control how labels like "fieldOne" and "uniqueUserEmail" are generated. ``` -------------------------------- ### Discovering Entity Definitions (Haskell) Source: https://github.com/yesodweb/persistent/blob/master/persistent/ChangeLog.md Adds the `discoverEntities` function, which automatically discovers instances of the `PersistEntity` class and returns their corresponding entity definitions. This aids in introspection and dynamic schema management. ```haskell discoverEntities :: (PersistEntity a, PersistStore backend) => backend -> IO [EntityDef] ``` -------------------------------- ### Define Entity Relationships and Foreign Keys in Haskell Source: https://context7.com/yesodweb/persistent/llms.txt Illustrates how to define relationships between database entities using foreign keys in Haskell's Persistent library. Covers one-to-many, self-referencing, and many-to-many relationships with cascade options and unique constraints. ```haskell #{-# LANGUAGE TemplateHaskell #-} import Database.Persist.TH share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase| Author name Text email Text UniqueAuthorEmail email deriving Show Book title Text authorId AuthorId OnDeleteCascade OnUpdateCascade deriving Show -- Self-referencing relationship Category name Text parentId CategoryId Maybe deriving Show -- Many-to-many via junction table Tag name Text UniqueTagName name deriving Show BookTag bookId BookId OnDeleteCascade tagId TagId OnDeleteCascade UniqueBookTag bookId tagId deriving Show |] -- Working with relationships relationshipExamples :: SqlPersistM () relationshipExamples = do -- Create author and book authorId <- insert $ Author "Jane Austen" "jane@example.com" bookId <- insert $ Book "Pride and Prejudice" authorId -- Get book with author mBook <- get bookId case mBook of Just book -> do mAuthor <- get (bookAuthorId book) liftIO $ print (book, mAuthor) Nothing -> return () -- Using belongsTo helper books <- selectList [] [] forM_ books $ \(Entity _ book) -> do mAuthor <- belongsTo (Just . bookAuthorId) book liftIO $ print mAuthor -- Create tags for a book tagId1 <- insert $ Tag "Fiction" tagId2 <- insert $ Tag "Romance" insert_ $ BookTag bookId tagId1 insert_ $ BookTag bookId tagId2 return () ``` -------------------------------- ### Optimize to/fromPersistValue for Entities in Persistent Source: https://github.com/yesodweb/persistent/blob/master/persistent-template/ChangeLog.md Version 2.8.0.1 includes a small optimization to reduce the size of generated Template Haskell code. This specifically targets the `toPersistValue` and `fromPersistValue` implementations for Entities, potentially improving compilation times. ```haskell -- This change is an internal optimization to the generated TH code. -- The user-facing impact is reduced code size and potentially faster compilation. -- Example of toPersistValue (simplified): -- toPersistValue :: Entity -> PersistValue -- toPersistValue entity = PersistMap [...] -- Optimized implementation -- Example of fromPersistValue (simplified): -- fromPersistValue :: PersistValue -> Either Text Entity -- fromPersistValue pv = ... -- Optimized implementation ``` -------------------------------- ### Haskell: Update Operations Source: https://context7.com/yesodweb/persistent/llms.txt Demonstrates how to update records in the database using the Persistent library. It covers updating specific fields by key, incrementing/decrementing values, updating matching records based on filters, and replacing or upserting entire records. Dependencies include Database.Persist and Database.Persist.Sqlite. ```haskell import Database.Persist import Database.Persist.Sqlite updateExamples :: SqlPersistM () updateExamples = do johnId <- insert $ Person "John" (Just 30) -- Update specific fields by key update johnId [PersonAge =. Just 31] -- Increment age by 1 update johnId [PersonAge +=. Just 1] -- Update and return the modified record updatedJohn <- updateGet johnId [PersonName =. "John Smith"] liftIO $ print updatedJohn -- Update all matching records updateWhere [PersonAge <. Just 18] -- Filter: age less than 18 [PersonName =. "Minor"] -- Update: set name to "Minor" -- Arithmetic updates updateWhere [PersonName ==. "John"] [PersonAge +=. Just 1] -- Add updateWhere [PersonName ==. "Jane"] [PersonAge -=. Just 1] -- Subtract -- Replace entire record (must exist) replace johnId $ Person "John Doe" (Just 35) -- Repsert: Replace if exists, insert if not repsert johnId $ Person "John Doe Updated" (Just 36) return () ``` -------------------------------- ### Enable MySQL Strict Mode Source: https://github.com/yesodweb/persistent/blob/master/docs/Database-Configuration.md Enables MySQL strict mode to prevent data truncation and ensure data integrity. This can be configured via the my.cnf file or directly in the MySQL console. ```sql sql_mode="STRICT_ALL_TABLES" ``` ```sql SET GLOBAL sql_mode = 'STRICT_ALL_TABLES'; ``` -------------------------------- ### Haskell: Unique Constraints and Upsert with Persistent Source: https://context7.com/yesodweb/persistent/llms.txt Demonstrates using unique constraints for conflict detection and performing upsert (insert or update) operations in Haskell with the Persistent ORM. It covers functions like insertUnique, insertBy, getBy, existsBy, upsert, upsertBy, and checkUnique. ```haskell import Database.Persist import Database.Persist.Sqlite uniqueExamples :: SqlPersistM () uniqueExamples = do -- Insert only if unique constraint is satisfied mUserId <- insertUnique $ User "john@example.com" "johndoe" case mUserId of Just userId -> liftIO $ putStrLn "User inserted" Nothing -> liftIO $ putStrLn "Email or username already exists" -- Insert or return existing (Left = existing, Right = new key) result <- insertBy $ User "jane@example.com" "janedoe" case result of Left (Entity existingKey _) -> liftIO $ putStrLn "User already exists" Right newKey -> liftIO $ putStrLn "New user created" -- Get by unique key mUser <- getBy $ UniqueEmail "john@example.com" -- Check if unique key exists emailExists <- existsBy $ UniqueEmail "john@example.com" -- Upsert: Insert new or update existing (for single unique key entities) entity <- upsert (User "bob@example.com" "bob") -- Record to insert [UserUsername =. "bobby"] -- Updates if exists -- UpsertBy: Specify which unique key to match on entity2 <- upsertBy (UniqueEmail "alice@example.com") -- Unique key to check (User "alice@example.com" "alice") -- Record to insert [UserUsername =. "alice_updated"] -- Updates if exists -- Check for conflicts before inserting mConflict <- checkUnique $ User "john@example.com" "newuser" case mConflict of Just uniqueKey -> liftIO $ putStrLn "Would violate unique constraint" Nothing -> liftIO $ putStrLn "Safe to insert" return () ``` -------------------------------- ### PersistValue Instance for Scientific Type Source: https://github.com/yesodweb/persistent/blob/master/docs/PersistValue instances.md Implements PersistField and PersistFieldSql for the Scientific type. It handles conversions to and from various PersistValue constructors and defines the SQL type as SqlNumeric. This is useful for financial and scientific data. ```haskell instance PersistField Scientific where toPersistValue = PersistRational . toRational fromPersistValue (PersistRational r) = Right $ fromRational r fromPersistValue (PersistDouble d) = Right $ fromFloatDigits d fromPersistValue (PersistInt64 i) = Right $ fromIntegral i fromPersistValue x = Left $ T.pack "PersistField Scientific: Expected Scientific, received: " <> T.pack (show x) instance PersistFieldSql Scientific where sqlType _ = SqlNumeric 32 20 -- Use your own judgement here ``` -------------------------------- ### Database Migrations with Persistent Source: https://context7.com/yesodweb/persistent/llms.txt Manage database schema changes automatically using Persistent's migration functions. Supports safe, silent, unsafe, and preview migrations, along with custom SQL commands. ```haskell import Database.Persist.Sql import Database.Persist.Sqlite migrationExamples :: SqlPersistM () migrationExamples = do -- Run safe migrations (errors on unsafe operations) runMigration migrateAll -- Run migrations silently, return SQL statements statements <- runMigrationQuiet migrateAll liftIO $ mapM_ print statements -- Run including unsafe migrations (use with caution!) runMigrationUnsafe migrateAll -- Preview migrations without executing printMigration migrateAll -- Get migration SQL as list sqlStatements <- showMigration migrateAll liftIO $ mapM_ putStrLn (map T.unpack sqlStatements) -- Custom migration with raw SQL customMigration :: Migration customMigration = do -- Add custom SQL command addMigration False "CREATE INDEX idx_person_name ON person(name)" -- Run arbitrary SQL during migration runSqlCommand $ rawExecute "CREATE EXTENSION IF NOT EXISTS \"uuid-ossp\"" [] -- Then run auto-generated migrations migrateAll ``` -------------------------------- ### Haskell: Using PersistLiteral for Unescaped SQL Literals Source: https://github.com/yesodweb/persistent/blob/master/persistent/ChangeLog.md This snippet introduces `PersistLiteral ByteString` as a new constructor for `PersistValue`. This allows for unescaped SQL literals, but it is highly unsafe and should not be used with user input due to potential SQL injection vulnerabilities. ```haskell import Database.Persist.Class import qualified Data.ByteString.Char8 as BS -- Example of using PersistLiteral (highly discouraged with user input) -- let unsafeLiteral = PersistLiteral (BS.pack "1=1") -- This would be used in a context where a PersistValue is expected, e.g., in a raw SQL query. -- Example: rawSql "SELECT * FROM users WHERE " [unsafeLiteral] -- WARNING: This is extremely dangerous if the ByteString comes from an untrusted source. ``` -------------------------------- ### PersistValue Instance for Integer (Fixed-Length Hexadecimal) Source: https://github.com/yesodweb/persistent/blob/master/docs/PersistValue instances.md Provides an alternative PersistField and PersistFieldSql implementation for Integer, storing it as a fixed-length hexadecimal string (char(30)) in the database. This ensures a consistent format for inline storage. It includes a helper function `showHexFixed` for padding. ```haskell -- Alternatively, for a fixed length integer, pad the hexadecimal with zeros showHexFixed :: (Integral a, Show a) => Int -> a -> String showHexFixed len val = padZeros $ showHex val "" where padZeros s = if length s >= len then s else padZeros ('0' : s) instance PersistField Integer where toPersistValue i = PersistText . T.pack $ showHexFixed 30 i fromPersistValue (PersistText s) = read $ "0x" <> T.unpack s fromPersistValue x = Left $ T.pack "PersistField Integer: Expected hexadecimal char(30), received: " <> T.pack (show x) instance PersistFieldSql Integer where sqlType _ = SqlOther $ T.pack "char(30)" -- fixed length character string, stored inline ``` -------------------------------- ### Define Database Entities with Template Haskell Source: https://context7.com/yesodweb/persistent/llms.txt Defines database models (entities) using the `persistLowerCase` quasi-quoter. This generates Haskell datatypes, database migration functions, and PersistEntity instances. It requires several Template Haskell extensions and imports from the Persistent library. ```haskell #{-# LANGUAGE EmptyDataDecls #-} #{-# LANGUAGE FlexibleContexts #-} #{-# LANGUAGE GADTs #-} #{-# LANGUAGE GeneralizedNewtypeDeriving #-} #{-# LANGUAGE MultiParamTypeClasses #-} #{-# LANGUAGE OverloadedStrings #-} #{-# LANGUAGE QuasiQuotes #-} #{-# LANGUAGE TemplateHaskell #-} #{-# LANGUAGE TypeFamilies #-} import Database.Persist import Database.Persist.TH import Database.Persist.Sqlite import Data.Text (Text) share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase| Person name Text age Int Maybe deriving Show BlogPost title Text authorId PersonId published Bool default=false deriving Show User email Text username Text UniqueEmail email UniqueUsername username deriving Show |] -- This generates: -- data Person = Person { personName :: Text, personAge :: Maybe Int } -- data BlogPost = BlogPost { blogPostTitle :: Text, blogPostAuthorId :: PersonId, blogPostPublished :: Bool } -- data User = User { userEmail :: Text, userUsername :: Text } -- Plus: Key types, EntityField types, migration functions, PersistEntity instances ``` -------------------------------- ### PersistValue Instance for Integer (Hexadecimal Storage) Source: https://github.com/yesodweb/persistent/blob/master/docs/PersistValue instances.md Implements PersistField and PersistFieldSql for the Integer type, storing it as a hexadecimal string in the database. This makes large integers easier to inspect. It handles conversions from PersistText and defines the SQL type as SqlString. ```haskell import Numeric (showHex) -- Store a large integer in hexadecimal format (which is easier to inspect in the database) instance PersistField Integer where toPersistValue i = PersistText . T.pack $ showHex i "" fromPersistValue (PersistText s) = read $ "0x" <> T.unpack s fromPersistValue x = Left $ T.pack "PersistField Integer: Expected hexadecimal text, received: " <> T.pack (show x) instance PersistFieldSql Integer where sqlType _ = SqlString ``` -------------------------------- ### Add Lift Instances for Cascade Types in Persistent Source: https://github.com/yesodweb/persistent/blob/master/persistent-template/ChangeLog.md Version 2.8.3.0 adds `Lift` instances for cascade types, utilizing `DeriveLift` for implementation. This provides `liftTyped` implementations on `template-haskell-2.16` and later, enhancing type-level programming capabilities. ```haskell {-# LANGUAGE DeriveLift {-# LANGUAGE TemplateHaskell #-} import Language.Haskell.TH.Syntax (Lift) -- Assuming 'Cascade' is a data type representing cascade operations -- data Cascade = CascadeOne | CascadeMany -- The DeriveLift extension automatically generates a Lift instance -- for the data type if it derives Lift. -- @deriving instance Lift Cascade -- This allows for lifting values of type Cascade into the TH environment. -- For example: -- liftTyped CascadeOne :: Q T.Exp ``` -------------------------------- ### SQLite Foreign Key Constraints Source: https://github.com/yesodweb/persistent/blob/master/docs/Database-Configuration.md Enables foreign key checks in SQLite, which are disabled by default. This ensures referential integrity between tables. Refer to the provided wiki page for detailed instructions on enabling this feature within the Persistent/Yesod framework. ```text Refer to https://github.com/yesodweb/yesod-cookbook/blob/master/cookbook/Activate-foreign-key-checking-in-Sqlite.md for instructions. ``` -------------------------------- ### Haskell: Delete Operations Source: https://context7.com/yesodweb/persistent/llms.txt Shows how to remove records from the database using the Persistent library. It covers deleting records by their unique key, deleting all records that match a specific filter, and deleting records based on a unique constraint. Dependencies include Database.Persist and Database.Persist.Sqlite. ```haskell import Database.Persist import Database.Persist.Sqlite deleteExamples :: SqlPersistM () deleteExamples = do johnId <- insert $ Person "John" (Just 30) janeId <- insert $ Person "Jane" (Just 25) -- Delete by key delete johnId -- Delete all records matching filter deleteWhere [PersonAge <. Just 18] -- Delete by unique key (for entities with Unique constraints) deleteBy $ UniqueEmail "old@example.com" return () ``` -------------------------------- ### Automatic SymbolToField Instances for OverloadedLabels in Persistent Source: https://github.com/yesodweb/persistent/blob/master/persistent-template/ChangeLog.md In version 2.9.1.0, Persistent introduced automatic generation of `SymbolToField` instances for datatypes. This enhancement allows the use of `OverloadedLabels` with the `EntityField` type, simplifying field access and improving developer experience. ```haskell {-# LANGUAGE DataKinds {-# LANGUAGE PolyKinds #} {-# LANGUAGE TypeFamilies #-} import GHC.TypeLits -- Represents a field in an entity data EntityField record field -- Type family to convert a symbol (field name) to an EntityField type family SymbolToField (symbol :: Symbol) :: EntityField record field -- Example of how OverloadedLabels might be used with EntityField -- (This is a conceptual example, actual implementation depends on GHC extensions) -- Assume 'Person' is a data type with fields like 'name' -- data Person = Person { name :: Text, age :: Int } -- With OverloadedLabels and SymbolToField, you could potentially write: -- let personNameField = #name :: SymbolToField "name" -- This would resolve to an appropriate EntityField type for the 'name' field of 'Person'. ``` -------------------------------- ### Add mkEntityDefList Function in Persistent Source: https://github.com/yesodweb/persistent/blob/master/persistent-template/ChangeLog.md Version 2.7.1 introduces the `mkEntityDefList` function to address issue [#902](https://github.com/yesodweb/persistent/issues/902). This function likely assists in the creation or manipulation of `EntityDef` lists, providing a workaround for specific scenarios. ```haskell import Database.Persist.TH (mkEntityDefList) -- Assuming mkEntityDefList is exported import Database.Persist.Types (EntityDef) -- Assuming EntityDef is the type for entity definitions -- Example usage of mkEntityDefList: -- let entityDefs :: [EntityDef] -- entityDefs = mkEntityDefList [ -- -- ... definitions of entities ... -- ] ``` -------------------------------- ### Define Custom PersistField Types in Haskell Source: https://context7.com/yesodweb/persistent/llms.txt Learn to create custom database types by implementing the PersistField typeclass. This includes deriving for simple enums, using derivePersistFieldJSON for JSON-serializable types, and manual implementation for complex types with specific database mappings. ```haskell #{-# LANGUAGE TemplateHaskell #-} import Database.Persist import Database.Persist.TH import Data.Text (Text) import qualified Data.Text as T -- Simple enum type data Status = Active | Inactive | Pending deriving (Show, Read, Eq) -- Use derivePersistField for simple enums derivePersistField "Status" -- For JSON-serializable types data Settings = Settings { settingsTheme :: Text , settingsNotifications :: Bool } deriving (Show, Eq, Generic) instance ToJSON Settings instance FromJSON Settings derivePersistFieldJSON "Settings" -- Manual implementation for complex types data Priority = Low | Medium | High | Critical deriving (Show, Read, Eq, Ord) instance PersistField Priority where toPersistValue Low = PersistInt64 0 toPersistValue Medium = PersistInt64 1 toPersistValue High = PersistInt64 2 toPersistValue Critical = PersistInt64 3 fromPersistValue (PersistInt64 0) = Right Low fromPersistValue (PersistInt64 1) = Right Medium fromPersistValue (PersistInt64 2) = Right High fromPersistValue (PersistInt64 3) = Right Critical fromPersistValue x = Left $ T.pack $ "Invalid Priority: " ++ show x instance PersistFieldSql Priority where sqlType _ = SqlInt32 -- Now use in entity definitions share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase| Task title Text status Status priority Priority settings Settings Maybe deriving Show |] ``` -------------------------------- ### Haskell: Defining Generated Columns in Persistent DSL Source: https://github.com/yesodweb/persistent/blob/master/persistent/ChangeLog.md This snippet shows how to define generated columns within the Persistent DSL using the `generated` attribute. It supports backend-specific generated columns, allowing expressions like `COALESCE(field_one, field_two)` to be defined directly in the schema. ```haskell {-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE TemplateHaskell #-} import Database.Persist.TH import Data.Text (Text) -- Example of a data type with a generated column -- The 'generated' attribute specifies the SQL expression for the column. -- This is backend-specific and requires appropriate database support. $(persistFileWith upperCaseRecDef "config/models.cfg") -- In models.cfg: -- GeneratedColumnExample -- fieldOne Text Maybe -- fieldTwo Text Maybe -- fieldThree Text Maybe generated=COALESCE(field_one,field_two) -- This translates to a table definition where fieldThree is computed based on fieldOne and fieldTwo. ``` -------------------------------- ### Reduce Template Haskell Code Generation in Persistent Source: https://github.com/yesodweb/persistent/blob/master/persistent-template/ChangeLog.md Version 2.8.0 significantly reduces the amount of code generated by Template Haskell, changing the complexity from O(N^2) to a more efficient form with respect to the number of fields. This results in dramatic improvements in compilation benchmarks for Persistent models. Support for GHC 8.0 was dropped to enable the use of `DerivingStrategies`. ```haskell -- The primary impact of this change is on compilation performance. -- User code defining Persistent entities remains largely the same, but the -- underlying generated code is more efficient. -- Example of a Persistent entity definition: -- $(persistFileWith lowerCaseConfig "models.{(.| -- Person -- name Text -- age Int -- -- ... other fields -- )}") -- This change also requires enabling specific GHC extensions: -- {-# LANGUAGE DerivingStrategies #-} -- {-# LANGUAGE GeneralizedNewtypeDeriving #-} -- {-# LANGUAGE StandaloneDeriving #-} ``` -------------------------------- ### Fix SqlType for Shared Primary Keys in Persistent Source: https://github.com/yesodweb/persistent/blob/master/persistent-template/ChangeLog.md Version 2.9.1.0 addresses a bug where the `SqlType` for a shared primary key was incorrectly set to `SqlString`. This fix ensures that the `SqlType` is correctly set to match the target primary key's SQL type, preventing potential issues with data storage and retrieval. ```haskell -- Example of SqlType definition (not directly from changelog, but illustrative) data SqlType = SqlString | SqlInt | SqlReal | SqlBool | SqlDay | SqlTime | SqlBlob deriving (Show, Eq) -- Hypothetical function demonstrating the fix updateSqlTypeForSharedPrimaryKey :: SqlType -> SqlType updateSqlTypeForSharedPrimaryKey incorrectType = if incorrectType == SqlString then -- Logic to determine the correct SqlType based on the target primary key SqlInt -- Placeholder for the correct type else incorrectType ``` -------------------------------- ### Add fieldValue to Database.Persist.TH Export List Source: https://github.com/yesodweb/persistent/blob/master/persistent-template/ChangeLog.md In version 2.8.2, the `fieldError` function was added to the export list of `Database.Persist.TH`. This makes `fieldError` directly accessible for use in Template Haskell code generation related to Persistent entities. ```haskell module Database.Persist.TH ( -- ... other exports fieldError -- Added in 2.8.2 ) where -- ... implementation details ... fieldError :: String -> String fieldError msg = "Error: " ++ msg ```