HORIZON HASKELLDocslts/ghc-9.10.x248f8f02026-10-05Search names, modules, packages, or :: a typeCtrl K

GHC 9.10.3 · lts/ghc-9.10.x · 248f8f0 · 2026-10-05

Modulepg-entity-0.0.4.4Haskell2010

Database.PostgreSQL.Entity

A PostgreSQL database layer that does not get in your way.

See the Database.PostgreSQL.Entity.Internal.BlogPost module for an example of a data-type implementing the Entity typeclass.

  • 1 type
  • 1 class
  • 37 values

The Entity Typeclass

1 declaration
classclass Entity e where
#

An Entity stores the following information about the structure of a database table:

  • Its name

  • Its primary key

  • The fields it contains

Example

data ExampleEntity = E
  { key    :: Key
  , field1 :: Int
  , field2 :: Bool
  }
  deriving stock (Eq, Show, Generic)
  deriving anyclass (FromRow, ToRow)
  deriving Entity
     via (GenericEntity '[TableName "entities"] ExampleEntity)

When using the functions provided by this library, you will sometimes need to be explicit about the Entity you are referring to.

Methods

Instances2Entity

Associated Types

1 declaration
datadata Field
#

A wrapper for table fields.

Instances3Eq, Show, IsString
  • Eq FieldDefined in pg-entity-0.0.4.4 · Database.PostgreSQL.Entity.Internal.Unsafe
  • Show FieldDefined in pg-entity-0.0.4.4 · Database.PostgreSQL.Entity.Internal.Unsafe
  • ForbiddenIsString => IsString FieldDefined in pg-entity-0.0.4.4 · Database.PostgreSQL.Entity.Internal.Unsafe

    Using the Overloaded String syntax for Field names is forbidden.

High-level API

9 declarations

Glossary / Tips’n’Tricks

  • e, e1, e2: Represents an Entity

  • value: Represents a Haskell value that can be serialised to PostgreSQL

  • Field: Parameters of type Field can most often be passed in their textual form inside the field quasi-quoter, like [field| author_id :: uuid|]. This metaprogramming technique is here to better prevent empty fields from being passed. The PostgreSQL type annotation is optional, but necessary for arrays of UUIDs and of custom enums.

Consult the test suite to see those functions in action.

Insertion

valueupsert
  1. :: (Entity e, ToRow values, MonadIO m)
  2. => values

    Entity to insert

  3. -> Vector Field

    Fields to replace in case of conflict

  4. -> DBT m ()
#

Insert an entity with a "ON CONFLICT DO UPDATE" clause on the primary key as the conflict target

Update

valueupdate :: (Entity e, ToRow newValue, MonadIO m) => newValue -> DBT m ()
#

Update an entity.

The Id of the entity is put at the end of the query automatically through the use of UpdateRow. Examples

let newAuthor = oldAuthor{…}
update @Author newAuthor
valueupdateFieldsBy
  1. :: (Entity e, MonadIO m, ToRow v2, ToField v1)
  2. => Vector Field

    Fields to change

  3. -> (Field, v1)

    Field on which to match and its value

  4. -> v2

    New values of those fields

  5. -> DBT m Int64
#

Update rows of an entity matching the given value

Example

let newName = "Tiberus McElroy" :: Text
let oldName = "Johnson McElroy" :: Text
updateFieldsBy @Author [[field| name |]] ([field| name |], oldName) (Only newName)

Deletion

SQL Combinators API

0 declarations

Selection

value_select :: Entity e => Query
#

Produce a SELECT statement for a given entity.

Examples

Example1 expression
_select @BlogPost"SELECT blogposts.\"blogpost_id\", blogposts.\"author_id\", blogposts.\"uuid_list\", blogposts.\"title\", blogposts.\"content\", blogposts.\"created_at\" FROM \"blogposts\""

Produce a SELECT statement with explicit fields for a given entity

Examples

Example1 expression
_selectWithFields @BlogPost [ [field| blogpost_id |], [field| created_at |] ]"SELECT \"blogposts\".\"blogpost_id\", \"blogposts\".\"created_at\" FROM \"\"blogposts\"\""
value_where :: Vector Field -> Query
#

Produce a WHERE clause, given a vector of fields.

It is most useful composed with a _select or _delete, which is why these two combinations have their dedicated functions, but the user is free to compose their own queries.

The Entity constraint is required for _where in order to get any type annotation that was given in the schema. Fields that do not exist in the Entity will be kept so that PostgreSQL can report the error.

Examples

Example1 expression
_select @BlogPost <> _where [[field| blogpost_id |]]"SELECT blogposts.\"blogpost_id\", blogposts.\"author_id\", blogposts.\"uuid_list\", blogposts.\"title\", blogposts.\"content\", blogposts.\"created_at\" FROM \"blogposts\" WHERE \"blogpost_id\" = ?"
Example1 expression
_select @BlogPost <> _where [ [field| uuid_list |] ]"SELECT blogposts.\"blogpost_id\", blogposts.\"author_id\", blogposts.\"uuid_list\", blogposts.\"title\", blogposts.\"content\", blogposts.\"created_at\" FROM \"blogposts\" WHERE \"uuid_list\" = ?"
value_selectWhere :: Entity e => Vector Field -> Query
#

Produce a SELECT statement for a given entity and fields.

Examples

Example1 expression
_selectWhere @BlogPost [ [field| author_id |] ]"SELECT blogposts.\"blogpost_id\", blogposts.\"author_id\", blogposts.\"uuid_list\", blogposts.\"title\", blogposts.\"content\", blogposts.\"created_at\" FROM \"blogposts\" WHERE \"author_id\" = ?"
Example1 expression
_selectWhere @BlogPost [ [field| author_id |], [field| title |]]"SELECT blogposts.\"blogpost_id\", blogposts.\"author_id\", blogposts.\"uuid_list\", blogposts.\"title\", blogposts.\"content\", blogposts.\"created_at\" FROM \"blogposts\" WHERE \"author_id\" = ? AND \"title\" = ?"

Produce a SELECT statement where the provided fields are checked for being non-null. r

Example1 expression
_selectWhereNotNull @BlogPost [ [field| author_id |] ]"SELECT blogposts.\"blogpost_id\", blogposts.\"author_id\", blogposts.\"uuid_list\", blogposts.\"title\", blogposts.\"content\", blogposts.\"created_at\" FROM \"blogposts\" WHERE \"author_id\" IS NOT NULL"

Produce a SELECT statement where the provided fields are checked for being null.

Example1 expression
_selectWhereNull @BlogPost [ [field| author_id |] ]"SELECT blogposts.\"blogpost_id\", blogposts.\"author_id\", blogposts.\"uuid_list\", blogposts.\"title\", blogposts.\"content\", blogposts.\"created_at\" FROM \"blogposts\" WHERE \"author_id\" IS NULL"
value_selectWhereIn :: Entity e => Field -> Vector Text -> Query
#

Produce a SELECT statement where the given field is checked aginst the provided array of values .

Example1 expression
_selectWhereIn @BlogPost [field| title |] [ "Unnamed", "Mordred's Song" ]"SELECT blogposts.\"blogpost_id\", blogposts.\"author_id\", blogposts.\"uuid_list\", blogposts.\"title\", blogposts.\"content\", blogposts.\"created_at\" FROM \"blogposts\" WHERE \"title\" IN ('Unnamed', 'Mordred''s Song')"
value_joinSelect :: (Entity e1, Entity e2) => Query
#

Produce a "SELECT FROM" over two entities.

Examples

Example1 expression
_joinSelect @BlogPost @Author"SELECT blogposts.\"blogpost_id\", blogposts.\"author_id\", blogposts.\"uuid_list\", blogposts.\"title\", blogposts.\"content\", blogposts.\"created_at\", authors.\"author_id\", authors.\"name\", authors.\"created_at\" FROM \"blogposts\" INNER JOIN \"authors\" USING(author_id)"
value_innerJoin :: Entity e => Field -> Query
#

Produce a "INNER JOIN … USING(…)" fragment.

Examples

Example1 expression
_innerJoin @BlogPost [field| author_id |]" INNER JOIN \"blogposts\" USING(author_id)"

Produce a "SELECT [table1_fields, table2_fields] FROM table1 INNER JOIN table2 USING(table2_pk)" statement. The primary is used as the join point between the two tables.

Examples

Example1 expression
_joinSelectWithFields @BlogPost @Author [ [field| title |] ] [ [field| name |] ]"SELECT \"blogposts\".\"title\", \"authors\".\"name\" FROM \"blogposts\" INNER JOIN \"authors\" USING(author_id)"
value_joinSelectOneByField :: (Entity e1, Entity e2) => Field -> Field -> Query
#

Produce a "SELECT FROM" over two entities.

Examples

Example1 expression
_joinSelectOneByField @BlogPost @Author [field| author_id |] [field| name |] :: Query"SELECT blogposts.\"blogpost_id\", blogposts.\"author_id\", blogposts.\"uuid_list\", blogposts.\"title\", blogposts.\"content\", blogposts.\"created_at\" FROM \"blogposts\" INNER JOIN \"authors\" ON \"blogposts\".\"author_id\" = \"authors\".\"author_id\" WHERE authors.\"name\" = ?"

Insertion

value_insert :: Entity e => Query
#

Produce an INSERT statement for the given entity.

Examples

Example1 expression
_insert @BlogPost"INSERT INTO \"blogposts\" (\"blogpost_id\", \"author_id\", \"uuid_list\", \"title\", \"content\", \"created_at\") VALUES (?, ?, ?, ?, ?, ?)"

Produce a "ON CONFLICT (target) DO UPDATE SET …" statement.

Examples

Example1 expression
_onConflictDoUpdate [[field| blogpost_id |]] [ [field| title |], [field| content |]]" ON CONFLICT (blogpost_id) DO UPDATE SET title = EXCLUDED.title, content = EXCLUDED.content"
Example1 expression
_onConflictDoUpdate [[field| blogpost_id |], [field| author_id |]] [ [field| title |], [field| content |]]" ON CONFLICT (blogpost_id, author_id) DO UPDATE SET title = EXCLUDED.title, content = EXCLUDED.content"
Example1 expression
_insert @BlogPost <> _onConflictDoUpdate [[field| blogpost_id |]] [ [field| title |], [field| content |]]"INSERT INTO \"blogposts\" (\"blogpost_id\", \"author_id\", \"uuid_list\", \"title\", \"content\", \"created_at\") VALUES (?, ?, ?, ?, ?, ?) ON CONFLICT (blogpost_id) DO UPDATE SET title = EXCLUDED.title, content = EXCLUDED.content"

Update

value_update :: Entity e => Query
#

Produce an UPDATE statement for the given entity by primary key

Examples

Example1 expression
_update @Author"UPDATE \"authors\" SET (\"name\", \"created_at\") = ROW(?, ?) WHERE \"author_id\" = ?"
Example1 expression
_update @BlogPost"UPDATE \"blogposts\" SET (\"author_id\", \"uuid_list\", \"title\", \"content\", \"created_at\") = ROW(?, ?, ?, ?, ?) WHERE \"blogpost_id\" = ?"
value_updateBy :: Entity e => Field -> Query
#

Produce an UPDATE statement for the given entity by the given field.

Examples

Example1 expression
_updateBy @Author [field| name |]"UPDATE \"authors\" SET (\"name\", \"created_at\") = ROW(?, ?) WHERE \"name\" = ?"
value_updateFields :: Entity e => Vector Field -> Query
#

Produce an UPDATE statement for the given entity and fields, by primary key.

Example1 expression
_updateFields @Author [ [field| name |] ]"UPDATE \"authors\" SET (\"name\") = ROW(?) WHERE \"author_id\" = ?"
value_updateFieldsBy
  1. :: Entity e
  2. => Vector Field

    Field names to update

  3. -> Field

    Field on which to match

  4. -> Query
#

Produce an UPDATE statement for the given entity and fields, by the specified field.

Example1 expression
_updateFieldsBy @Author [ [field| name |] ] [field| name |]"UPDATE \"authors\" SET (\"name\") = ROW(?) WHERE \"name\" = ?"
Example1 expression
_updateFieldsBy @BlogPost [[field| author_id |], [field| title |]] [field| title |]"UPDATE \"blogposts\" SET (\"author_id\", \"title\") = ROW(?, ?) WHERE \"title\" = ?"

Deletion

value_delete :: Entity e => Query
#

Produce a DELETE statement for the given entity, with a match on the Primary Key

Examples

Example1 expression
_delete @BlogPost"DELETE FROM \"blogposts\" WHERE \"blogpost_id\" = ?"
value_deleteWhere :: Entity e => Vector Field -> Query
#

Produce a DELETE statement for the given entity and fields

Examples

Example1 expression
_deleteWhere @BlogPost [[field| title |], [field| created_at |]]"DELETE FROM \"blogposts\" WHERE \"title\" = ? AND \"created_at\" = ?"
value_orderBy :: (Field, SortKeyword) -> Query
#

Produce an ORDER BY clause with one field and a sorting keyword

Examples

Example1 expression
_orderBy ([field| title |], ASC)" ORDER BY \"title\" ASC"

Produce an ORDER BY clause with many fields and sorting keywords

Examples

Example1 expression
_orderByMany (V.fromList [([field| title |], ASC), ([field| created_at |], DESC)])" ORDER BY \"title\" ASC, \"created_at\" DESC"