PostgresqlUri (postgresql_uri v0.1.0) View Source

Parse PostgreSQL connection URIs of the form:

postgresql://[user[:password]@][netloc][:port][,...][/dbname][?param1=value1&...]

and returns a keyword list ready for use with Postgrex.start_link/1.

The URI format largely follows the description at https://www.postgresql.org/docs/13/libpq-connect.html#id-1.7.3.8.3.6, with parameter keywords as listed at https://www.postgresql.org/docs/13/libpq-connect.html#LIBPQ-PARAMKEYWORDS .

There is only partial correspondence between the PostgreSQL parameters and the Postgrex options. No validation is performed and unrecognized/unsupported URL parameter keywords are passed verbatim. This means that you may be able to stuff simple string parameters into the URL to pass them on to Postgrex, but URIs crafted this way may not be compatible with libpq.

In particular, the following PostgreSQL URL phenomena are unhandled/untranslated:

  • Parameter keywords marked as deprectated in the PostgreSQL documentation.
  • Things related to the TCP connection beyond connect_timeout (read timeouts, keepalives, ...).
  • Failover (specifying multiple hosts).
  • Advanced SSL configuration (beyond simply turning it on or off)

Related project: https://github.com/s-m-i-t-a/database_url — gives you an Ecto adapter rather than a keyword list.

See the documentation of parse/1, the only exposed function, for more details and some examples.

Link to this section Summary

Functions

Parse a PostgreSQL URI into a keyword list.

Link to this section Functions

Specs

parse(nonempty_charlist()) :: keyword()

Parse a PostgreSQL URI into a keyword list.

Examples

These examples should (with suitably chosen values) also work as an argument to the psql command-line client and make it attempt to do the same thing as Postgrex would.

Quotidian case

iex> PostgresqlUri.parse("postgresql://someuser:somepassword@some.ser.ver:2345/somedb")
[
  hostname: "some.ser.ver",
  database: "somedb",
  port: 2345,
  username: "someuser",
  password: "somepassword",
]

No-frills SSL

For the sslmode keyword, any value but "disable" will result in enabling SSL.

iex> PostgresqlUri.parse("postgresql://someuser:somepassword@some.ser.ver/somedb?sslmode=yesplease")
[
  hostname: "some.ser.ver",
  database: "somedb",
  username: "someuser",
  password: "somepassword",
  ssl: true
]

Unix socket

PostgreSQL has the concept of a "socket directory" which can hold different Unix sockets, named after port numbers. So, in order to specify a socket belonging to a server listening on a port different from the default (5432), you need to pass in a port number, even though you won't be connecting over TCP.

iex> PostgresqlUri.parse("postgresql:///somedb?user=someuser&password=somepassword&host=/path/to/socketdir&port=2345")
[
  database: "somedb",
  socket_dir: "/path/to/socketdir",
  password: "somepassword",
  port: 2345,
  username: "someuser",
]

Minimal case - local Unix socket, peer authentication.

Theoretically, postgresql:///somedb should work. However, Postgrex.start_link/1 works differently from psql here. psql, absent host specification, will try to use a Unix socket, perusing the libpq compile-time default socket directory. Yet Postgrex will fail for this URI (demanding a password), as it doesn't know what socket directory to use. So, to make things work for Postgrex, we will have to pass the socket directory explicitly. The resulting URI still works as intended for psql.

iex> PostgresqlUri.parse("postgresql:///some_db?host=/run/postgresql")
[
  database: "some_db",
  socket_dir: "/run/postgresql",
]