View Source Postgrex.SimpleConnection behaviour (Postgrex v0.16.5)

A generic connection suitable for simple queries and pubsub functionality.

On its own, a SimpleConnection server only maintains a connection. To execute queries, process results, or relay notices you must implement a callback module with the SimpleConnection behaviour.

example

Example

The SimpleConnection behaviour abstracts common client/server interactions, along with optional mechanisms for running queries or relaying notifications.

Let's start with a minimal callback module that executes a query and relays the result back to the caller.

defmodule MyConnection do
  @behaviour Postgrex.SimpleConnection

  @impl true
  def init(_args) do
    {:ok, %{from: nil}}
  end

  @impl true
  def handle_call({:query, query}, from, state) do
    {:query, query, %{state | from: from}}
  end

  @impl true
  def handle_result(results, state) when is_list(results) do
    SimpleConnection.reply(state.from, results)

    {:noreply, state}
  end

  @impl true
  def handle_result(%Postgrex.Error{} = error, state) do
    SimpleConnection.reply(state.from, error)

    {:noreply, state}
  end
end

# Start the connection
{:ok, pid} = SimpleConnection.start_link(MyConnection, [], database: "demo")

# Execute a literal query
SimpleConnection.call(pid, {:query, "SELECT 1"})
# => %Postgrex.Result{rows: [["1"]]}

We start a connection by passing the callback module, callback options, and server options to SimpleConnection.start_link/3. The init/1 function receives any callback options and returns the callback state.

Queries are sent through SimpleConnection.call/2, executed on the server, and the result is handed off to handle_result/2. At that point the callback can process the result before replying back to the caller with SimpleConnection.reply/2.

building-a-pubsub-connection

Building a PubSub Connection

With the notify/3 callback you can also build a pubsub server on top of LISTEN/NOTIFY. Here's a naive pubsub implementation:

defmodule MyPubSub do
  @behaviour Postgrex.SimpleConnection

  defstruct [:from, listeners: %{}]

  @impl true
  def init(args) do
    {:ok, struct!(__MODULE__, args)}
  end

  @impl true
  def notify(channel, payload, state) do
    for pid <- state.listeners[channel] do
      send(pid, {:notice, channel, payload})
    end
  end

  @impl true
  def handle_call({:listen, channel}, {pid, _} = from, state) do
    listeners = Map.update(state.listeners, channel, [pid], &[pid | &1])

    {:query, ~s(LISTEN "#{channel}"), %{state | from: from, listeners: listeners}}
  end

  def handle_call({:query, query}, from, state) do
    {:query, query, %{state | from: from}}
  end

  @impl true
  def handle_result(_results, state) do
    SimpleConnection.reply(state.from, :ok)

    {:noreply, %{state | from: nil}}
  end
end

# Start the connection
{:ok, pid} = SimpleConnection.start_link(MyPubSub, [], database: "demo")

# Start listening to the "demo" channel
SimpleConnection.call(pid, {:listen, "demo"})
# => %Postgrex.Result{command: :listen}

# Notify all listeners
SimpleConnection.call(pid, {:query, ~s(NOTIFY "demo", 'hello')})
# => %Postgrex.Result{command: :notify}

# Check the inbox to see the notice message
flush()
# => {:notice, "demo", "hello"}

See Postgrex.Notifications for a more complex implementation that can unlisten, handle process exits, and persist across reconnection.

name-registration

Name registration

A Postgrex.SimpleConnection is bound to the same name registration rules as a GenServer. Read more about them in the GenServer docs.

Link to this section Summary

Callbacks

Callback for SimpleConnection.call/3.

Invoked after connecting or reconnecting.

Invoked after disconnection.

Callback for processing or relaying queries executed via {:query, query, state}.

Callback for process initialization.

Callback for processing or relaying pubsub notifications.

Functions

Calls the given server.

Replies to the given client.

Start the connection process and connect to Postgres.

Link to this section Types

@type query() :: iodata()
@type state() :: term()

Link to this section Callbacks

Link to this callback

handle_call(term, from, state)

View Source (optional)
@callback handle_call(term(), GenServer.from(), state()) ::
  {:noreply, state()} | {:query, query(), state()}

Callback for SimpleConnection.call/3.

Replies must be sent with SimpleConnection.reply/2.

Link to this callback

handle_connect(state)

View Source (optional)
@callback handle_connect(state()) :: {:noreply, state()} | {:query, query(), state()}

Invoked after connecting or reconnecting.

This may be called multiple times if :auto_reconnect is true.

Link to this callback

handle_disconnect(state)

View Source (optional)
@callback handle_disconnect(state()) :: {:noreply, state()}

Invoked after disconnection.

This is invoked regardless of the :auto_reconnect option.

Link to this callback

handle_info(term, state)

View Source (optional)
@callback handle_info(term(), state()) :: {:noreply, state()} | {:query, query(), state()}

Callback for Kernel.send/2.

Link to this callback

handle_result(arg1, state)

View Source (optional)
@callback handle_result([Postgrex.Result.t()] | Postgrex.Error.t(), state()) ::
  {:noreply, state()}

Callback for processing or relaying queries executed via {:query, query, state}.

Either a list of successful query results or an error will be passed to this callback. A list is passed because the simple query protocol allows multiple commands to be issued in a single query.

@callback init(term()) :: {:ok, state()}

Callback for process initialization.

This is called once and before the Postgrex connection is established.

Link to this callback

notify(binary, binary, state)

View Source
@callback notify(binary(), binary(), state()) :: :ok

Callback for processing or relaying pubsub notifications.

Link to this section Functions

Link to this function

call(server, message, timeout \\ 5000)

View Source

Calls the given server.

Wrapper for GenServer.call/3.

Replies to the given client.

Wrapper for GenServer.reply/2.

Link to this function

start_link(module, args, opts)

View Source
@spec start_link(module(), term(), Keyword.t()) ::
  {:ok, pid()} | {:error, Postgrex.Error.t() | term()}

Start the connection process and connect to Postgres.

The options that this function accepts are the same as those accepted by Postgrex.start_link/1, as well as the extra options :sync_connect, :auto_reconnect, :reconnect_backoff, and :configure.

options

Options

  • :auto_reconnect - automatically attempt to reconnect to the database in event of a disconnection. See the note about async connect and auto-reconnects above. Defaults to false, which means the process terminates.

  • :configure - A function to run before every connect attempt to dynamically configure the options as a {module, function, args}, where the current options will prepended to args. Defaults to nil.

  • :idle_interval - while also accepted on Postgrex.start_link/1, it has a default of 5000ms in Postgrex.SimpleConnection (instead of 1000ms).

  • :reconnect_backoff - time (in ms) between reconnection attempts when auto_reconnect is enabled. Defaults to 500.

  • :sync_connect - controls if the connection should be established on boot or asynchronously right after boot. Defaults to true.