Documentation for Sofa, a test-driven idiomatic Apache CouchDB client.

If the only tool you have is CouchDB, then everything looks like {:ok, :relax}

Examples

iex> Sofa.init() |> Sofa.client() |> Sofa.connect!()

%{
  "couchdb" => "Welcome",
  "features" => ["access-ready", "partitioned", "pluggable-storage-engines",
    "reshard", "scheduler"],
  "git_sha" => "ce596c65d",
  "uuid" => "59c032d3a6adcd5b44315137a124bf69",
  "vendor" => %{"name" => "FreeBSD"},
  "version" => "3.1.1"
}

Summary

Functions

Get _active_tasks. Only available to admin users.

List all databases. Only available to admin users.

Returns user & password credentials extracted from a typical %URI{} userinfo field, as basic auth credentials. Currently only supports BasicAuth user:password combination.

Builds a reusable Req.Request HTTP client, with basic auth credentials taken from the URI, and stores it in the supplied %Sofa{} struct.

Given an existing %Sofa{} struct, or a prepared URI, attempts to connect to the CouchDB instance, and returns an updated %Sofa{} to use in future connections to this server, using the same HTTP credentials.

Bang! wrapper around Sofa.connect/1. Raises exceptions on error.

Takes an optional parameter, the CouchDB uri, and returns a struct containing the usual CouchDB server properties. The URI may be given as a string or as a %URI struct.

Minimal wrapper around native CouchDB HTTP API, allowing an escape hatch for raw functionality, and as the core abstraction layer for Sofa itself.

Bang! wrapper around Sofa.raw/1 raises exceptions on error.

Types

t()

@type t() :: %Sofa{
  auth: any(),
  client: nil | Req.Request.t(),
  database: nil | binary(),
  features: nil | list(),
  timeout: nil | integer(),
  uri: nil | URI.t(),
  uuid: nil | binary(),
  vendor: nil | map(),
  version: nil | binary()
}

Functions

active_tasks(sofa)

@spec active_tasks(t()) :: {:error, any()} | {:ok, [map()]}

Get _active_tasks. Only available to admin users.

all_dbs(sofa)

@spec all_dbs(t()) :: {:error, any()} | {:ok, [String.t()]}

List all databases. Only available to admin users.

auth_info(info)

@spec auth_info(nil | String.t()) ::
  %{} | %{username: String.t(), password: String.t()}

Returns user & password credentials extracted from a typical %URI{} userinfo field, as basic auth credentials. Currently only supports BasicAuth user:password combination.

Examples

iex> Sofa.auth_info("admin:password")
%{username: "admin", password: "password"}

iex> Sofa.auth_info("blank:")
%{username: "blank", password: ""}

iex> Sofa.auth_info("garbage")
%{}

client(couch, opts \\ [])

@spec client(t(), keyword()) :: t()

Builds a reusable Req.Request HTTP client, with basic auth credentials taken from the URI, and stores it in the supplied %Sofa{} struct.

Any Req.new/1 options may be passed to override the defaults, for example receive_timeout: 5_000, plug: MyPlug for Req.Test, or inet6: false to disable the default IPv6-first, IPv4-fallback connection behaviour.

Retries are disabled, as CouchDB responses are expected to be fast and callers typically want to see errors immediately.

connect(sofa)

@spec connect(String.t() | t()) :: {:ok, t()} | {:error, any()}

Given an existing %Sofa{} struct, or a prepared URI, attempts to connect to the CouchDB instance, and returns an updated %Sofa{} to use in future connections to this server, using the same HTTP credentials.

Returns an updated {:ok, %Sofa{}} on success, or {:error, reason}, if for example, the URL is unreachable, times out, supplied credentials are rejected by CouchDB, or returns unexpected HTTP status codes.

connect!(sofa)

@spec connect!(String.t() | t()) :: t()

Bang! wrapper around Sofa.connect/1. Raises exceptions on error.

init(uri \\ "http://admin:passwd@localhost:5984/")

@spec init(uri :: String.t() | URI.t()) :: t()

Takes an optional parameter, the CouchDB uri, and returns a struct containing the usual CouchDB server properties. The URI may be given as a string or as a %URI struct.

This should be piped into Sofa.client/1 to create the HTTP client, which is stored inside the struct with correct authentication information.

Examples

iex> Sofa.init("https://very:Secure@foreignho.st:6984/")

%Sofa{
  auth: "very:Secure",
  features: nil,
  uri: %URI{
    authority: "very:Secure@foreignho.st:6984",
    fragment: nil,
    host: "foreignho.st",
    path: "/",
    port: 6984,
    query: nil,
    scheme: "https",
    userinfo: "very:Secure"
  },
  uuid: nil,
  vendor: nil,
  version: nil
}

raw(sofa, path \\ "", method \\ :get, query \\ [], body \\ "", headers \\ [], opts \\ [])

@spec raw(
  t(),
  String.t(),
  atom(),
  keyword() | map(),
  map() | binary(),
  [{String.t(), String.t()}] | map(),
  keyword()
) :: {:error, any()} | {:ok, t(), Sofa.Response.t()}

Minimal wrapper around native CouchDB HTTP API, allowing an escape hatch for raw functionality, and as the core abstraction layer for Sofa itself.

A map body is sent as JSON, a binary body is sent as-is. JSON responses are decoded into maps, and CouchDB error responses, those with both an error and a reason key, are returned as {:error, %Sofa.Response{}}. Transport failures such as :econnrefused or :timeout are returned as {:error, %Req.TransportError{}}.

Any further Req.request/2 options go last, for the few requests that are not JSON in and out: raw: true keeps a body as bytes, into: streams it to a sink, and body: sends an enumerable as a chunked upload. The path is sent as given. See Sofa.Cushion.path/1 for encoding its segments.

raw!(sofa, path \\ "", method \\ :get, query \\ [], body \\ "")

@spec raw!(t(), String.t(), atom(), keyword() | map(), map() | binary()) ::
  Sofa.Response.t()

Bang! wrapper around Sofa.raw/1 raises exceptions on error.