Skip to content

Commit

Permalink
adds append only functions, #1
Browse files Browse the repository at this point in the history
  • Loading branch information
Danwhy committed Oct 12, 2018
1 parent e5aa7e2 commit cd4ddd3
Show file tree
Hide file tree
Showing 8 changed files with 181 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .formatter.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Used by "mix format"
[
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
]
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ erl_crash.dump
*.ez
*.beam
/config/*.secret.exs
.elixir_ls
30 changes: 30 additions & 0 deletions config/config.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# This file is responsible for configuring your application
# and its dependencies with the aid of the Mix.Config module.
use Mix.Config

# This configuration is loaded before any dependency and is restricted
# to this project. If another project depends on this project, this
# file won't be loaded nor affect the parent project. For this reason,
# if you want to provide default values for your application for
# 3rd-party users, it should be done in your "mix.exs" file.

# You can configure your application as:
#
# config :alog, key: :value
#
# and access this configuration in your application as:
#
# Application.get_env(:alog, :key)
#
# You can also configure a 3rd-party app:
#
# config :logger, level: :info
#

# It is also possible to import configuration files, relative to this
# directory. For example, you can emulate configuration per environment
# by uncommenting the line below and defining dev.exs, test.exs and such.
# Configuration from the imported file will override the ones defined
# here (which is why it is important to import them last).
#
# import_config "#{Mix.env()}.exs"
105 changes: 105 additions & 0 deletions lib/alog.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
defmodule Alog do
@moduledoc """
Behaviour that defines functions for accessing and inserting data in an
Append-Only database
"""

@callback insert(struct) :: {:ok, Ecto.Schema.t()} | {:error, Ecto.Changeset.t()}
@callback get(integer) :: Ecto.Schema.t() | nil | no_return()
@callback get_by(Keyword.t() | map) :: Ecto.Schema.t() | nil | no_return()
@callback update(Ecto.Schema.t(), struct) ::
{:ok, Ecto.Schema.t()} | {:error, Ecto.Changeset.t()}
@callback get_history(Ecto.Schema.t()) :: [Ecto.Schema.t()] | no_return()

defmacro __using__(_opts) do
quote location: :keep do
@behaviour Alog
@before_compile unquote(__MODULE__)
end
end

defmacro __before_compile__(_env) do
quote generated: true do
import Ecto.Query, only: [from: 2, subquery: 1]

@repo __MODULE__ |> Module.split() |> List.first() |> Module.concat("Repo")

def insert(attrs) do
%__MODULE__{}
|> __MODULE__.changeset(attrs)
|> @repo.insert()
end

def get(entry_id) do
sub =
from(
m in __MODULE__,
where: m.entry_id == ^entry_id,
order_by: [desc: :inserted_at],
limit: 1,
select: m
)

query = from(m in subquery(sub), where: not m.deleted, select: m)

item = @repo.one(query)
end

def get_by(clauses) do
@repo.get_by(__MODULE__, clauses)
end

def update(%__MODULE__{} = item, attrs) do
item
|> @repo.preload(__MODULE__.__schema__(:associations))
|> Map.put(:id, nil)
|> Map.put(:inserted_at, nil)
|> Map.put(:updated_at, nil)
|> __MODULE__.changeset(attrs)
|> @repo.insert()
end

def get_history(%__MODULE__{} = item) do
query =
from(m in __MODULE__,
where: m.entry_id == ^item.entry_id,
select: m
)

@repo.all(query)
end

def all do
sub =
from(m in __MODULE__,
distinct: m.entry_id,
order_by: [desc: :inserted_at],
select: m
)

query = from(m in subquery(sub), where: not m.deleted, select: m)

@repo.all(query)
end

def insert_entry_id(entry) do
case Map.fetch(entry, :entry_id) do
{:ok, nil} -> %{entry | entry_id: Ecto.UUID.generate()}
_ -> entry
end
end

def delete(item) do
item
|> @repo.preload(__MODULE__.__schema__(:associations))
|> Map.put(:id, nil)
|> Map.put(:inserted_at, nil)
|> Map.put(:updated_at, nil)
|> __MODULE__.changeset(%{deleted: true})
|> @repo.insert()
end

defoverridable Alog
end
end
end
27 changes: 27 additions & 0 deletions mix.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
defmodule Alog.MixProject do
use Mix.Project

def project do
[
app: :alog,
version: "0.1.0",
elixir: "~> 1.7",
start_permanent: Mix.env() == :prod,
deps: deps()
]
end

# Run "mix help compile.app" to learn about applications.
def application do
[
extra_applications: [:logger]
]
end

# Run "mix help deps" to learn about dependencies.
defp deps do
[
{:ecto, "~> 2.2.10"}
]
end
end
5 changes: 5 additions & 0 deletions mix.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
%{
"decimal": {:hex, :decimal, "1.5.0", "b0433a36d0e2430e3d50291b1c65f53c37d56f83665b43d79963684865beab68", [:mix], [], "hexpm"},
"ecto": {:hex, :ecto, "2.2.11", "4bb8f11718b72ba97a2696f65d247a379e739a0ecabf6a13ad1face79844791c", [:mix], [{:db_connection, "~> 1.1", [hex: :db_connection, repo: "hexpm", optional: true]}, {:decimal, "~> 1.2", [hex: :decimal, repo: "hexpm", optional: false]}, {:mariaex, "~> 0.8.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:poison, "~> 2.2 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: true]}, {:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.13.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, repo: "hexpm", optional: true]}], "hexpm"},
"poolboy": {:hex, :poolboy, "1.5.1", "6b46163901cfd0a1b43d692657ed9d7e599853b3b21b95ae5ae0a777cf9b6ca8", [:rebar], [], "hexpm"},
}
8 changes: 8 additions & 0 deletions test/alog_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
defmodule AlogTest do
use ExUnit.Case
doctest Alog

test "greets the world" do
assert Alog.hello() == :world
end
end
1 change: 1 addition & 0 deletions test/test_helper.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ExUnit.start()

0 comments on commit cd4ddd3

Please sign in to comment.