Skip to content

Instantly share code, notes, and snippets.

@CyrusNuevoDia
Created July 20, 2018 16:05
defmodule Repo do
use Task
require Logger
@moduledoc """
It's hard to find the docs for the MongoDB adapter. Here's a direct link:
https://hexdocs.pm/mongodb/Mongo.html
"""
def start_link(_) do
Task.start(&setup/0)
end
def setup(commands \\ :all_commands) do
Sarlacc.Repo.Tasks.setup(commands)
end
defmacro __using__(opts \\ []) do
quote do
use Config, for: Repo
import ShorterMaps
alias Sarlacc.Repo.DB
@options Map.take(@config, [:pool, :name, :timeout, :pool_timeout]) |> Enum.into([])
def conn, do: @options[:name]
def options, do: @options
def options(opts) do
Keyword.merge(@options, opts)
end
def put_timestamps(doc_or_docs, now \\ DateTime.utc_now())
def put_timestamps(documents, now) when is_list(documents) do
Enum.map(documents, &put_timestamps(&1, now))
end
def put_timestamps(%{} = document, now) do
document |> Map.put_new(:created_at, now) |> Map.put(:updated_at, now)
end
def wrap_mongo_lookup(nil), do: {:error, :no_document}
def wrap_mongo_lookup(document) when is_map(document) do
{:ok, Map.Helpers.atomize_keys(document)}
end
def wrap_mongo_lookup_all(documents) do
Enum.map(documents, &Map.Helpers.atomize_keys/1)
end
def command(cmds, opts \\ []) do
Mongo.command(conn(), cmds, options(opts))
end
def command!(cmds, opts \\ []) do
Mongo.command!(conn(), cmds, options(opts))
end
def ids(docs) do
Enum.map(docs, &Map.get(&1, :_id))
end
def count(%{} = query), do: count(:default, query, [])
def count(%{} = query, opts), do: count(:default, query, opts)
def count(coll, %{} = query), do: count(coll, query, [])
def count(coll, %{} = query, opts) do
Mongo.count(conn(), collection_name(coll), query, options(opts))
end
def aggregate(pipeline) when is_list(pipeline), do: aggregate(:default, pipeline, [])
def aggregate(pipeline, opts) when is_list(pipeline), do: aggregate(:default, pipeline, opts)
def aggregate(coll, pipeline) when is_list(pipeline), do: aggregate(coll, pipeline, [])
def aggregate(coll, pipeline, opts) when is_list(pipeline) do
Mongo.aggregate(conn(), collection_name(coll), pipeline, options(opts))
|> wrap_mongo_lookup_all()
end
def find_one(%{} = query), do: find_one(:default, query, [])
def find_one(%{} = query, opts), do: find_one(:default, query, opts)
def find_one(coll, %{} = query), do: find_one(coll, query, [])
def find_one(coll, %{} = query, opts) do
Mongo.find_one(conn(), collection_name(coll), query, options(opts))
|> wrap_mongo_lookup()
end
def find(%{} = query), do: find(:default, query, [])
def find(%{} = query, opts), do: find(:default, query, opts)
def find(coll, %{} = query), do: find(coll, query, [])
def find(coll, %{} = query, opts) do
Mongo.find(conn(), collection_name(coll), query, options(opts))
|> wrap_mongo_lookup_all()
end
def insert_one(%{} = doc), do: insert_one(:default, doc, [])
def insert_one(%{} = doc, opts), do: insert_one(:default, doc, opts)
def insert_one(coll, %{} = doc), do: insert_one(coll, doc, [])
def insert_one(coll, %{} = doc, opts) when map_size(doc) != 0 do
Mongo.insert_one(
conn(),
collection_name(coll),
put_timestamps(doc),
options(opts)
)
end
def insert_one(_, _, _), do: {:error, :empty_document}
def insert_many(docs) when is_list(docs), do: insert_many(:default, docs, [])
def insert_many(docs, opts) when is_list(docs), do: insert_many(:default, docs, opts)
def insert_many(coll, docs) when is_list(docs), do: insert_many(coll, docs, [])
def insert_many(coll, docs, opts) when is_list(docs) do
docs =
docs
|> Enum.reject(&Enum.empty?/1)
|> put_timestamps()
Mongo.insert_many(
conn(),
collection_name(coll),
docs,
options(Keyword.merge(opts, upsert: true))
)
end
def update_one(%{} = query, %{} = changeset), do: update_one(:default, query, changeset, [])
def update_one(%{} = query, %{} = changeset, opts), do: update_one(:default, query, changeset, opts)
def update_one(coll, %{} = query, %{} = changeset), do: update_one(coll, query, changeset, [])
def update_one(coll, %{} = query, %{} = changeset, opts) when map_size(changeset) != 0 do
Mongo.update_one(
conn(),
collection_name(coll),
query,
changeset,
options(Keyword.merge(opts, upsert: true))
)
end
def update_one(_, _, _, _), do: {:error, :empty_changeset}
def update_many(%{} = query, %{} = changeset), do: update_many(:default, query, changeset, [])
def update_many(%{} = query, %{} = changeset, opts), do: update_many(:default, query, changeset, opts)
def update_many(coll, %{} = query, %{} = changeset), do: update_many(coll, query, changeset, [])
def update_many(coll, %{} = query, %{} = changeset, opts) do
Mongo.update_many(
conn(),
collection_name(coll),
query,
changeset,
options(Keyword.merge(opts, upsert: true))
)
end
def upsert_one(%{} = query, %{} = doc), do: upsert_one(:default, query, doc, [])
def upsert_one(%{} = query, %{} = doc, opts), do: upsert_one(:default, query, doc, opts)
def upsert_one(coll, %{} = query, %{} = doc), do: upsert_one(coll, query, doc, [])
def upsert_one(coll, %{} = query, %{} = doc, opts) when map_size(doc) != 0 do
Mongo.replace_one(
conn(),
collection_name(coll),
query,
put_timestamps(doc),
options(Keyword.merge(opts, upsert: true))
)
end
def upsert_one(_, _, _, _), do: {:error, :empty_document}
def delete_one(%{} = query), do: delete_one(:default, query, [])
def delete_one(%{} = query, opts), do: delete_one(:default, query, opts)
def delete_one(coll, %{} = query), do: delete_one(coll, query, [])
def delete_one(coll, %{} = query, opts) do
Mongo.find_one_and_delete(conn(), collection_name(coll), query, options(opts))
end
def delete_many(%{} = query), do: delete_many(:default, query, [])
def delete_many(%{} = query, opts), do: delete_many(:default, query, opts)
def delete_many(coll, %{} = query), do: delete_many(coll, query, [])
def delete_many(coll, %{} = query, opts) do
Mongo.delete_many(conn(), collection_name(coll), query, options(opts))
end
cond do
unquote(opts[:collection]) ->
@collection_name unquote(opts[:collection])
def collection_name(:default), do: @collection_name
unquote(opts[:collection_suffix]) ->
@collection_suffix unquote(opts[:collection_suffix])
def collection_name(base)
when is_nil(base)
when base == :default
when base == "" do
raise ArgumentError, message: "must specify collection base name"
end
def collection_name(base) do
"#{base}#{@collection_suffix}"
end
:default ->
def collection_name(coll), do: coll
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment