Skip to content

Commit

Permalink
[#1] Nebulex.Adapter behaviour
Browse files Browse the repository at this point in the history
  • Loading branch information
cabol committed Dec 26, 2020
1 parent 099bbcc commit da9dbcc
Show file tree
Hide file tree
Showing 12 changed files with 511 additions and 5 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}"]
]
84 changes: 84 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
name: CI

on:
push:
branches:
- main
pull_request:
branches:
- main

jobs:
nebulex_test:
name: 'NebulexCachexAdapter Test (Elixir ${{ matrix.elixir }} OTP ${{ matrix.otp }})'
runs-on: ubuntu-latest

strategy:
matrix:
include:
- elixir: 1.10.x
otp: 23.x
- elixir: 1.10.x
otp: 22.x
- elixir: 1.9.x
otp: 22.x

env:
GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
MIX_ENV: test
NBX_TEST: true

steps:
- uses: actions/checkout@v2

- uses: actions/setup-elixir@v1
with:
otp-version: '${{ matrix.otp }}'
elixir-version: '${{ matrix.elixir }}'

- uses: actions/cache@v1
with:
path: deps
key: >-
${{ runner.os }}-${{ matrix.otp }}-${{ matrix.elixir }}-mix-${{
hashFiles(format('{0}{1}', github.workspace, '/mix.lock')) }}
restore-keys: |
${{ runner.os }}-${{ matrix.otp }}-${{ matrix.elixir }}-mix-
- uses: actions/cache@v1
with:
path: _build
key: >-
${{ runner.os }}-${{ matrix.otp }}-${{ matrix.elixir }}-build-${{
hashFiles(format('{0}{1}', github.workspace, '/mix.lock')) }}
restore-keys: |
${{ runner.os }}-${{ matrix.otp }}-${{ matrix.elixir }}-build-
- name: Install Dependencies
run: |
mix local.hex --force
mix local.rebar --force
mix deps.get
- name: Run style and code consistency checks
run: |
mix compile --warnings-as-errors
mix format --check-formatted
mix credo --strict
- name: Run tests
run: |
epmd -daemon
mix coveralls.github
- uses: actions/cache@v1
with:
path: priv/plts
key: '${{ runner.os }}-${{ matrix.otp }}-${{ matrix.elixir }}-plt-v1'
restore-keys: |
${{ runner.os }}-${{ matrix.otp }}-${{ matrix.elixir }}-plt-v1
- name: Run static analysis checks
run: |
mix sobelow --exit --skip
mix dialyzer --format short
33 changes: 31 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,10 +1,39 @@
# The directory Mix will write compiled artifacts to.
/_build

# If you run "mix test --cover", coverage assets end up here.
/cover

# The directory Mix downloads your dependencies sources to.
/deps

# Where 3rd-party dependencies like ExDoc output generated docs.
/doc
/docs
/benchmarks/output

# Ignore .fetch files in case you like to edit your project deps locally.
/.fetch

# Dialyzer
/priv

# If the VM crashes, it generates a dump, let's ignore it too.
erl_crash.dump

# Also ignore archive artifacts (built via "mix archive.build").
*.ez

# Others
*.o
*.beam
/config/*.secret.exs
.elixir_ls/
*.plt
erl_crash.dump
.DS_Store
._*
/tmp*
.elixir*
.vs*
/priv
.sobelow*
mix.lock
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
SOFTWARE.
22 changes: 20 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,20 @@
# nebulex_cachex_adapter
Nebulex adapter for Cachex
# NebulexCachexAdapter
> ### Nebulex adapter for [Cachex][Cachex].
[Cachex]: https://github.com/whitfin/cachex

![CI](https://github.com/cabol/nebulex_cachex_adapter/workflows/CI/badge.svg)

*Still WIP*

## Installation

Add `nebulex_cachex_adapter` to your list of dependencies in `mix.exs`:

```elixir
def deps do
[
{:nebulex_cachex_adapter, "~> 0.1.0"}
]
end
```
9 changes: 9 additions & 0 deletions coveralls.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"coverage_options": {
"minimum_coverage": 100
},

"skip_files": [
"test/support/*"
]
}
158 changes: 158 additions & 0 deletions lib/nebulex_cachex_adapter.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
defmodule NebulexCachexAdapter do
@moduledoc """
Nebulex adapter for Cachex.
"""

# Provide Cache Implementation
@behaviour Nebulex.Adapter

import Nebulex.Helpers

@compile {:inline, to_ttl: 1}

## Adapter

@impl true
defmacro __before_compile__(_), do: :ok

@impl true
def init(opts) do
name =
normalize_module_name([
opts[:name] || Keyword.fetch!(opts, :cache),
Cachex
])

child_spec =
opts
|> Keyword.put(:name, name)
|> Cachex.child_spec()

{:ok, child_spec, %{name: name}}
end

@impl true
def get(%{name: name}, key, _opts) do
Cachex.get!(name, key)
end

@impl true
def get_all(%{name: name}, keys, _opts) do
Enum.reduce(keys, %{}, fn key, acc ->
if value = Cachex.get!(name, key) do
Map.put(acc, key, value)
else
acc
end
end)
end

@impl true
def put(%{name: name}, key, value, ttl, :put, _opts) do
Cachex.put!(name, key, value, ttl: to_ttl(ttl))
end

def put(%{name: name}, key, value, ttl, :replace, _opts) do
Cachex.update!(name, key, value, ttl: to_ttl(ttl))
end

def put(%{name: name}, key, value, ttl, :put_new, _opts) do
if Cachex.get!(name, key) do
false
else
Cachex.put!(name, key, value, ttl: to_ttl(ttl))
end
end

@impl true
def put_all(adapter_meta, entries, ttl, on_write, opts) when is_map(entries) do
put_all(adapter_meta, :maps.to_list(entries), ttl, on_write, opts)
end

def put_all(%{name: name}, entries, ttl, :put, _opts) when is_list(entries) do
Cachex.put_many!(name, entries, ttl: to_ttl(ttl))
end

def put_all(%{name: name}, entries, ttl, :put_new, _opts) when is_list(entries) do
{keys, _} = Enum.unzip(entries)

Cachex.transaction!(name, keys, fn worker ->
if Enum.any?(keys, &(worker |> Cachex.exists?(&1) |> elem(1))) do
false
else
Cachex.put_many!(worker, entries, ttl: to_ttl(ttl))
end
end)
end

@impl true
def delete(%{name: name}, key, _opts) do
true = Cachex.del!(name, key)
:ok
end

@impl true
def take(%{name: name}, key, _opts) do
Cachex.take!(name, key)
end

@impl true
def has_key?(%{name: name}, key) do
{:ok, bool} = Cachex.exists?(name, key)
bool
end

@impl true
def ttl(%{name: name}, key) do
cond do
ttl = Cachex.ttl!(name, key) ->
ttl

Cachex.get!(name, key) ->
:infinity

true ->
nil
end
end

@impl true
def expire(%{name: name}, key, ttl) do
Cachex.expire!(name, key, to_ttl(ttl))
end

@impl true
def touch(%{name: name}, key) do
Cachex.touch!(name, key)
end

@impl true
def incr(%{name: name}, key, incr, :infinity, opts) do
Cachex.incr!(name, key, incr, initial: opts[:default] || 0)
end

def incr(%{name: name}, key, incr, ttl, opts) do
Cachex.transaction!(name, [key], fn worker ->
counter = Cachex.incr!(worker, key, incr, initial: opts[:default] || 0)
if ttl = to_ttl(ttl), do: Cachex.expire!(worker, key, ttl)
counter
end)
end

@impl true
def size(%{name: name}) do
Cachex.size!(name)
end

@impl true
def flush(%{name: name}) do
size = Cachex.size!(name)
true = Cachex.reset!(name)
size
end

## Private Functions

defp to_ttl(:infinity), do: nil
defp to_ttl(ttl), do: ttl
end
Loading

0 comments on commit da9dbcc

Please sign in to comment.