Pevensie Postgres Driver
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 Name | Description |
---|---|
cache | Stores cache data. This table is unlogged, so data will be lost when the database stops. |
one_time_token | Stores one time tokens. Uses soft deletions. |
session | Stores session data. |
user | Stores user data. Uses soft deletions. |
module_version | Stores 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 Type | Postgres Type |
---|---|
Any resource ID | UUID (generated as UUIDv7) |
String | text |
tempo.DateTime (from gtempo ) | timestamptz |
Record types (e.g. user_metadata ) | jsonb |
pevensie/net.IpAddr | inet |
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.