defmodule BarrelEx.Document do @moduledoc """ API for interacting with a BarrelDB document. """ alias BarrelEx.Request ## TODO: some header args like x-barrel-id-match and ETag ## are in headers, accept them too ## GET - ALL DOCUMENTS @doc """ Get all documents from the database `db`, filtered by a map of `options`. Returns also the response status. """ @spec get(String.t(), list | map | none) :: {atom, map} def get(db, options \\ []) do case is_map(options) do true -> with options <- Map.to_list(options), opts <- options |> atomize_keys() do get(db, opts) end false -> with url <- make_url(db) do Request.get(url, [], params: options) end end end @doc """ Get all documents from the database `db`, filtered by a map of options or a list of `options` tuples. """ @spec get!(String.t(), list | map | none) :: map def get!(db, options \\ []) do case is_map(options) do true -> with options <- Map.to_list(options), opts <- options |> atomize_keys() do get!(db, opts) end false -> with url <- make_url(db) do Request.get!(url, [], params: options) end end end ## GET - ONE DOCUMENT @doc """ Get the document with a given `doc_id` from the database `db`, filtered by an optional list of options. Returns also the response status. """ @spec get_one(String.t(), String.t(), list | none) :: {atom, map} def get_one(db, doc_id, options \\ []) do with url <- make_url(db, doc_id) do Request.get(url, [], options) end end @doc """ Get the document with a given `doc_id` from the database `db`, filtered by an optional list of options. """ @spec get_one!(String.t(), String.t(), list | none) :: map def get_one!(db, doc_id, options \\ []) do with url <- make_url(db, doc_id) do Request.get!(url, [], options) end end ## CREATE @doc """ Create a new document `doc` in the database `db`. Returns also the response status. """ @spec create(String.t(), map | none) :: {atom, map} def create(db, doc \\ %{}) do with url <- make_url(db) do Request.post(url, doc) end end @doc """ Create a new document `doc` in the database `db`. """ @spec create!(String.t(), map | none) :: map def create!(db, doc \\ %{}) do with url <- make_url(db) do Request.post!(url, doc) end end ## DELETE @doc """ Delete a document `doc` in the database `db`. Returns also the response status. """ @spec delete(String.t(), String.t(), String.t() | none) :: {atom, map} def delete(db, doc_id, e_tag \\ "") do with url <- make_url(db, doc_id), headers <- make_e_tag(e_tag) do Request.delete(url, headers) end end @doc """ Delete a document `doc` in the database `db`. """ @spec delete!(String.t(), String.t(), String.t() | none) :: map def delete!(db, doc_id, e_tag \\ "") do with url <- make_url(db, doc_id), headers <- make_e_tag(e_tag) do Request.delete!(url, headers) end end ## UPDATE @doc """ Update a document `doc` in the database `db`. Returns also the response status. """ @spec update(String.t(), String.t(), map, String.t(), boolean) :: {atom, map} def update(db, doc_id, doc, e_tag \\ "", edit \\ false) do with url <- make_url(db, doc_id) do # to add doc_id to body if doesn't exist doc = Map.put_new(doc, "id", doc_id) Request.put(url, doc, make_e_tag(e_tag), edit: edit) end end @doc """ Update a document `doc` in the database `db`. """ @spec update!(String.t(), String.t(), map, String.t(), boolean) :: map def update!(db, doc_id, doc, e_tag \\ "", edit \\ false) do with url <- make_url(db, doc_id) do # to add doc_id to body if doesn't exist doc = Map.put_new(doc, "id", doc_id) Request.put!(url, doc, make_e_tag(e_tag), edit: edit) end end ## HISTORY @doc """ Check for differences in documents history in the database `db`. Returns also the response status. """ @spec revsdiff(String.t(), map) :: {atom, map} def revsdiff(db, doc) do with url <- make_revsdiff_url(db) do Request.post(url, doc) end end @doc """ Check for differences in documents history in the database `db`. """ @spec revsdiff!(String.t(), map) :: map def revsdiff!(db, doc) do with url <- make_revsdiff_url(db) do Request.post!(url, doc) end end ## UTILS defp make_e_tag(e_tag) do case is_bitstring(e_tag) do true -> ["ETag: " <> e_tag] _ -> [] end end defp make_id_match(doc_ids) do case is_list(doc_ids) do # TODO: test this header true -> ["x-barrel-id-match: " <> Enum.join(doc_ids, ", ")] _ -> [] end end defp make_url(db) do "dbs/" <> db <> "/docs/" end defp make_url(db, doc_id) do make_url(db) <> doc_id end defp make_revsdiff_url(db) do "dbs/" <> db <> "/revsdiff/" end defp atomize_keys(list) do Enum.map(list, fn {k, v} -> {String.to_atom(k), v} end) end end