Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
# Changelog

## v4.0.0 - Unreleased

- Starting a pool no longer generates an atom, instead a name is taken as an
argument.
- The `Connection` type has been removed. A subject is now used instead.
- `connect` and `disconnect` have been removed in favour of `start` and `supervised`.
- `url_config` and `default_config` now take a name parameter.
- The `default_timeout` function has been removed.
- The callback given to the `transaction` function now receives the connection
as an argument. Queries made using this connection will be in the
transaction, while the pool can still be used to run queries outside the
transaction.
- The `gleam_time` package is now used for time types and functions.
- The `TransactionError` type is now parameterised with an error type rather
being specific to strings.

## v3.3.0 - 2025-07-03

- Updated `result.then` to `result.try` to resolve deprecation warnings.
Expand Down
86 changes: 40 additions & 46 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,44 @@ A PostgreSQL database client for Gleam, based on [PGO][erlang-pgo].
[erlang-pgo]: https://github.com/erleans/pgo

```gleam
gleam add pog@4
```

Add a pool to your OTP supervision tree, before any siblings that will need to
use the database.

Pools are named with a `Name` from `gleam/erlang/process`, so create one
outside of your supervision tree and pass it down to the creation of the pool.

```gleam
import gleam/otp/static_supervisor
import pog
import gleam/dynamic/decode
import gleeunit/should

pub fn main() {
// Start a database connection pool.
// Typically you will want to create one pool for use in your program
let db =
pog.default_config()
pub fn start_application_supervisor(pool_name: process.Name(pog.Message)) {
let pool_child =
pog.defaut_config(pool_name)
|> pog.host("localhost")
|> pog.database("my_database")
|> pog.pool_size(15)
|> pog.connect
|> pog.supervised

supervisor.new(supervisor.RestForOne)
|> supervisor.add(pool_child)
// |> supervisor.add(other)
// |> supervisor.add(application)
// |> supervisor.add(children)
|> supervisor.start
}
```

Then in your application you can use a connection created from that name with
the `pog.named_connection` to make queries:

```gleam
import pog
import gleam/dynamic/decode

pub fn run(db: pog.Connection) {
// An SQL statement to run. It takes one int as a parameter
let sql_query = "
select
Expand All @@ -39,28 +63,18 @@ pub fn main() {

// Run the query against the PostgreSQL database
// The int `1` is given as a parameter
let assert Ok(response) =
let assert Ok(data) =
pog.query(sql_query)
|> pog.parameter(pog.int(1))
|> pog.returning(row_decoder)
|> pog.execute(db)

// And then do something with the returned results
response.count
|> should.equal(2)
response.rows
|> should.equal([
#("Nubi", 3, "black", ["Al", "Cutlass"]),
])
assert data.count == 2
assert data.rows == [#("Nubi", 3, "black", ["Al", "Cutlass"])])
}
```

## Installation

```sh
gleam add pog
```

## Support of connection URI

Configuring a Postgres connection is done by using `Config` type in `pog`.
Expand All @@ -76,15 +90,14 @@ connection URI from the environment.

```gleam
import envoy
import gleam/erlang/process.{type Name}
import pog

/// Read the DATABASE_URL environment variable.
/// Generate the pog.Config from that database URL.
/// Finally, connect to database.
pub fn read_connection_uri() -> Result(pog.Connection, Nil) {
/// Read the DATABASE_URL environment variable and then
/// build the pog.Config from that database URL.
pub fn read_connection_uri(name: Name(pog.Message)) -> Result(pog.Config, Nil) {
use database_url <- result.try(envoy.get("DATABASE_URL"))
use config <- result.try(pog.url_config(database_url))
Ok(pog.connect(config))
pog.url_config(name, database_url)
}
```

Expand Down Expand Up @@ -112,15 +125,6 @@ By default, `pgo` will return every selected value from your query as a tuple.
In case you want a different output, you can activate `rows_as_maps` in `Config`.
Once activated, every returned rows will take the form of a `Dict`.

## Atom generation

Creating a connection pool with the `pog.connect` function dynamically generates
an Erlang atom. Atoms are not garbage collected and only a certain number of
them can exist in an Erlang VM instance, and hitting this limit will result in
the VM crashing. Due to this limitation you should not dynamically open new
connection pools, instead create the pools you need when your application starts
and reuse them throughout the lifetime of your program.

## SSL

As for the rest of the web, you should try to use SSL connections with any
Expand Down Expand Up @@ -172,16 +176,6 @@ in `pog.Config`. The different options are `SslDisabled`, `SslUnverified` &
to your database should be highly secured to protect you against man-in-the-middle
attacks, you should always try to use the most secured setting.

```gleam
import pog

pub fn connect() {
pog.default_config()
|> pog.ssl(pog.SslVerified)
|> pog.connect
}
```

### Need some help?

You tried to setup a secured connection, but it does not work? Your container
Expand Down
12 changes: 7 additions & 5 deletions gleam.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name = "pog"
version = "3.3.0"
gleam = ">= 1.4.0"
version = "4.0.0"
gleam = ">= 1.11.0"
licences = ["Apache-2.0"]
description = "A PostgreSQL database client for Gleam, based on PGO"

Expand All @@ -16,13 +16,15 @@ pages = [
]

[dependencies]
gleam_erlang = ">= 1.2.0 and < 2.0.0"
gleam_otp = ">= 1.0.0 and < 2.0.0"
gleam_stdlib = ">= 0.51.0 and < 2.0.0"
pgo = ">= 0.12.0 and < 2.0.0"
gleam_time = ">= 1.0.0 and < 2.0.0"
exception = ">= 2.1.0 and < 3.0.0"
pgo = ">= 0.14.0 and < 1.0.0"

[dev-dependencies]
gleeunit = ">= 1.0.0 and < 2.0.0"
exception = ">= 2.0.0 and < 3.0.0"
gleam_erlang = ">= 0.30.0 and < 1.0.0"

[erlang]
# Starting an SSL connection relies on ssl application to be started.
Expand Down
18 changes: 11 additions & 7 deletions manifest.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,22 @@

packages = [
{ name = "backoff", version = "1.1.6", build_tools = ["rebar3"], requirements = [], otp_app = "backoff", source = "hex", outer_checksum = "CF0CFFF8995FB20562F822E5CC47D8CCF664C5ECDC26A684CBE85C225F9D7C39" },
{ name = "exception", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "exception", source = "hex", outer_checksum = "F5580D584F16A20B7FCDCABF9E9BE9A2C1F6AC4F9176FA6DD0B63E3B20D450AA" },
{ name = "gleam_erlang", version = "0.33.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "A1D26B80F01901B59AABEE3475DD4C18D27D58FA5C897D922FCB9B099749C064" },
{ name = "gleam_stdlib", version = "0.51.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "14AFA8D3DDD7045203D422715DBB822D1725992A31DF35A08D97389014B74B68" },
{ name = "gleeunit", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "F7A7228925D3EE7D0813C922E062BFD6D7E9310F0BEE585D3A42F3307E3CFD13" },
{ name = "exception", version = "2.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "exception", source = "hex", outer_checksum = "329D269D5C2A314F7364BD2711372B6F2C58FA6F39981572E5CA68624D291F8C" },
{ name = "gleam_erlang", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "F91CE62A2D011FA13341F3723DB7DB118541AAA5FE7311BD2716D018F01EF9E3" },
{ name = "gleam_otp", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "7020E652D18F9ABAC9C877270B14160519FA0856EE80126231C505D719AD68DA" },
{ name = "gleam_stdlib", version = "0.61.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "3DC407D6EDA98FCE089150C11F3AD892B6F4C3CA77C87A97BAE8D5AB5E41F331" },
{ name = "gleam_time", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_time", source = "hex", outer_checksum = "D71F1AFF7FEB534FF55E5DC58E534E9201BA75A444619788A2E4DEA4EBD87D16" },
{ name = "gleeunit", version = "1.6.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "63022D81C12C17B7F1A60E029964E830A4CBD846BBC6740004FC1F1031AE0326" },
{ name = "opentelemetry_api", version = "1.4.0", build_tools = ["rebar3", "mix"], requirements = [], otp_app = "opentelemetry_api", source = "hex", outer_checksum = "3DFBBFAA2C2ED3121C5C483162836C4F9027DEF469C41578AF5EF32589FCFC58" },
{ name = "pg_types", version = "0.4.0", build_tools = ["rebar3"], requirements = [], otp_app = "pg_types", source = "hex", outer_checksum = "B02EFA785CAECECF9702C681C80A9CA12A39F9161A846CE17B01FB20AEEED7EB" },
{ name = "pgo", version = "0.14.0", build_tools = ["rebar3"], requirements = ["backoff", "opentelemetry_api", "pg_types"], otp_app = "pgo", source = "hex", outer_checksum = "71016C22599936E042DC0012EE4589D24C71427D266292F775EBF201D97DF9C9" },
]

[requirements]
exception = { version = ">= 2.0.0 and < 3.0.0" }
gleam_erlang = { version = ">= 0.30.0 and < 1.0.0" }
exception = { version = ">= 2.1.0 and < 3.0.0" }
gleam_erlang = { version = ">= 1.2.0 and < 2.0.0" }
gleam_otp = { version = ">= 1.0.0 and < 2.0.0" }
gleam_stdlib = { version = ">= 0.51.0 and < 2.0.0" }
gleam_time = { version = ">= 1.0.0 and < 2.0.0" }
gleeunit = { version = ">= 1.0.0 and < 2.0.0" }
pgo = { version = ">= 0.12.0 and < 2.0.0" }
pgo = { version = ">= 0.14.0 and < 1.0.0" }
Loading