Pevensie Postgres Driver

Package Version Hex Docs

The official PostgreSQL driver for Pevensie. It provides driver implementations for Pevensie modules to be used with Postgres databases.

Currently provides drivers for:

Getting Started

Configure your driver to connect to your database using the PostgresConfig type. You can use the default_config function to get a default configuration for connecting to a local Postgres database with sensible concurrency defaults.

import pevensie/postgres.{type PostgresConfig}

pub fn main() {
  let config = PostgresConfig(
    ..postgres.default_config(),
    host: "db.pevensie.dev",
    database: "my_database",
  )
  // ...
}

Create a new driver using one of the new_<driver>_driver functions provided by this module. You can then use the driver with Pevensie modules.

import pevensie/postgres.{type PostgresConfig}
import pevensie/auth.{type PevensieAuth}

pub fn main() {
  let config = PostgresConfig(
    ..postgres.default_config(),
    host: "db.pevensie.dev",
    database: "my_database",
  )
  let driver = postgres.new_auth_driver(config)
  let pevensie_auth = auth.new(
    driver:,
    user_metadata_decoder:,
    user_metadata_encoder:,
    cookie_key: "super secret signing key",
  )
  // ...
}

Connection Management

When called with the Postgres driver, the connect function provided by Pevensie Auth will create a connection pool for the database. This can be called once on boot, and will be reused for the lifetime of the application.

The disconnect function will close the connection pool.

Tables

This driver creates tables in the pevensie schema to store user data, sessions, and cache data.

The current tables created by this driver are:

Table NameDescription
cacheStores cache data. This table is unlogged, so data will be lost when the database stops.
one_time_tokenStores one time tokens. Uses soft deletions.
sessionStores session data.
userStores user data. Uses soft deletions.
module_versionStores the current versions of the tables required by this driver. Versions are stored as dates.

Types

Generally, the Postgres driver makes a best effort to map the types used by Pevensie to best-practice Postgres types. Generally, columns are non-nullable unless the Gleam type is Option(a). The following types are mapped to Postgres types:

Gleam TypePostgres Type
Any resource IDUUID (generated as UUIDv7)
Stringtext
tempo.DateTime (from gtempo)timestamptz
Record types (e.g. user_metadata)jsonb
pevensie/net.IpAddrinet

Migrations

You can run migrations against your database using the provided CLI:

gleam run -m pevensie/postgres migrate --addr=<connection_string> auth cache

The required SQL statements will be printed to the console for use with other migration tools like dbmate. Alternatively, you can apply the migrations directly using the --apply flag.

Implementation Details

This driver uses the pog library for interacting with Postgres.

All IDs are stored as UUIDs, and are generated using using a UUIDv7 implementation made available by Fabio Lima under the MIT license. The implementation is available here.

Pevensie Auth

The user table follows the structure of the User type. The user_metadata column is a JSONB column, and is used to store any custom user metadata.

It also contains a deleted_at column, which is used to mark users as deleted, rather than deleting the row from the database.

Alongside the primary key, the user table has unique indexes on the email and phone_number columns. These are partial, and only index where values are provided. They also include the deleted_at column, so users can sign up with the same email if a user with that email has been deleted.

The session table follows the structure of the Session type. The user_id column is a foreign key referencing the user table. If an expired session is read, the get_session function will return None, and delete the expired session from the database.

Searching for users

The list_users function provided by Pevensie Auth allows you to search for users by ID, email or phone number. With the Postgres driver, the lists in you UserSearchFields argument are processed using a like any() where clause. This means that you can search for users by providing a list of values, and the driver will search for users with any of those values.

You can also use Postgres like wildcards in your search values. For example, if you search for users with an email ending in @example.com, you can use %@example.com as the search value.

Pevensie Cache

The cache table is an unlogged table. This ensures that writes are fast, but data is lost when the database is stopped. Do not use Pevensie Cache for data you need to keep indefinitely.

The table’s primary key is a composite of the resource_type and key columns. This allows you to store multiple values for a given key, and retrieve them all at once.

Writes to the cache will overwrite any existing value for the given resource type and key. This driver does not keep a version history.

If an expired value is read, the get function will return None, and delete the expired value from the cache.

Custom Queries

If you wish to query the user or session tables directly, this driver provides helper utilities for doing so.

The user_decoder and session_decoder functions can be used to decode selections from the user and session tables, respectively.

The user_select_fields and session_select_fields variables contain the SQL used to select fields from the user and session tables for use with the user_decoder and session_decoder functions.

Search Document