Skip to content

Commit

Permalink
Cache API based on Ok/Error tuples (Nebulex v3)
Browse files Browse the repository at this point in the history
- Remove deprecated module `Nebulex.Hook`
- Use NimbleOptions for defining and validating cache options
- Replace `:ttl` field by `:exp` in local adapter
- Replace `Mock` with `Mimic`
- Add `:dynamic_cache` to set the cache instance dynamically in runtime
  • Loading branch information
cabol committed Nov 14, 2022
1 parent efca644 commit 5ffc3ab
Show file tree
Hide file tree
Showing 87 changed files with 4,760 additions and 3,394 deletions.
4 changes: 2 additions & 2 deletions .credo.exs
Original file line number Diff line number Diff line change
Expand Up @@ -117,9 +117,9 @@
## Refactoring Opportunities
#
{Credo.Check.Refactor.CondStatements, []},
{Credo.Check.Refactor.CyclomaticComplexity, []},
{Credo.Check.Refactor.CyclomaticComplexity, [max_complexity: 40]},
{Credo.Check.Refactor.FunctionArity, []},
{Credo.Check.Refactor.LongQuoteBlocks, [max_line_count: 300, ignore_comments: true]},
{Credo.Check.Refactor.LongQuoteBlocks, [max_line_count: 200]},
# {Credo.Check.Refactor.MapInto, []},
{Credo.Check.Refactor.MatchInCondition, []},
{Credo.Check.Refactor.NegatedConditionsInUnless, []},
Expand Down
23 changes: 22 additions & 1 deletion .formatter.exs
Original file line number Diff line number Diff line change
@@ -1,5 +1,26 @@
locals_without_parens = [
# Nebulex.Helpers
unwrap_or_raise: 1,
wrap_ok: 1,
wrap_error: 1,
wrap_error: 2,

# Nebulex.Cache
dynamic_cache: 2,

# Tests
deftests: 1,
deftests: 2,
setup_with_cache: 1,
setup_with_cache: 2,
setup_with_dynamic_cache: 2,
setup_with_dynamic_cache: 3
]

[
import_deps: [:stream_data],
inputs: ["{mix,.formatter}.exs", "{config,lib,test,benchmarks}/**/*.{ex,exs}"],
line_length: 100
line_length: 100,
locals_without_parens: locals_without_parens,
export: [locals_without_parens: locals_without_parens]
]
4 changes: 1 addition & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@ jobs:
- elixir: 1.11.x
otp: 23.x
inch-report: true
- elixir: 1.9.x
otp: 22.x

env:
GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
Expand Down Expand Up @@ -101,7 +99,7 @@ jobs:
id: plt-cache
with:
path: priv/plts
key: ${{ runner.os }}-${{ matrix.otp }}-${{ matrix.elixir }}-plt-v1
key: ${{ runner.os }}-${{ matrix.otp }}-${{ matrix.elixir }}-plt-v3-1
if: ${{ matrix.dialyzer }}

- name: Create PLTs
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,4 @@ erl_crash.dump
/priv
.sobelow*
/config
Elixir*
27 changes: 0 additions & 27 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,33 +4,6 @@ All notable changes to this project will be documented in this file.

This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [v2.4.2](https://github.com/cabol/nebulex/tree/v2.4.2) (2022-11-04)

[Full Changelog](https://github.com/cabol/nebulex/compare/v2.4.1...v2.4.2)

**Closed issues:**

- Adapter configuration per-env?
[#171](https://github.com/cabol/nebulex/issues/171)
- On-change handler for write-through decorators
[#165](https://github.com/cabol/nebulex/issues/165)
- Document test env setup with decorators?
[#155](https://github.com/cabol/nebulex/issues/155)
- Managing Failovers in the cluster
[#131](https://github.com/cabol/nebulex/issues/131)

**Merged pull requests:**

- Make Multilevel adapter apply deletes in reverse order
[#174](https://github.com/cabol/nebulex/pull/174)
([martosaur](https://github.com/martosaur))
- Use import Bitwise instead of use Bitwise
[#172](https://github.com/cabol/nebulex/pull/172)
([ryvasquez](https://github.com/ryvasquez))
- Fix result of getting value by non existent key
[#166](https://github.com/cabol/nebulex/pull/166)
([fuelen](https://github.com/fuelen))

## [v2.4.1](https://github.com/cabol/nebulex/tree/v2.4.1) (2022-07-10)

[Full Changelog](https://github.com/cabol/nebulex/compare/v2.4.0...v2.4.1)
Expand Down
5 changes: 2 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,20 +47,19 @@ Partitioned | [Nebulex.Adapters.Partitioned][pa] | Built-In
Replicated | [Nebulex.Adapters.Replicated][ra] | Built-In
Multilevel | [Nebulex.Adapters.Multilevel][ma] | Built-In
Nil (special adapter that disables the cache) | [Nebulex.Adapters.Nil][nil] | Built-In
Cachex | Nebulex.Adapters.Cachex | [nebulex_adapters_cachex][nbx_cachex]
Redis | NebulexRedisAdapter | [nebulex_redis_adapter][nbx_redis]
Cachex | Nebulex.Adapters.Cachex | [nebulex_adapters_cachex][nbx_cachex]
Distributed with Horde | Nebulex.Adapters.Horde | [nebulex_adapters_horde][nbx_horde]

[la]: http://hexdocs.pm/nebulex/Nebulex.Adapters.Local.html
[pa]: http://hexdocs.pm/nebulex/Nebulex.Adapters.Partitioned.html
[ra]: http://hexdocs.pm/nebulex/Nebulex.Adapters.Replicated.html
[ma]: http://hexdocs.pm/nebulex/Nebulex.Adapters.Multilevel.html
[nil]: http://hexdocs.pm/nebulex/Nebulex.Adapters.Nil.html
[nbx_cachex]: https://github.com/cabol/nebulex_adapters_cachex
[nbx_redis]: https://github.com/cabol/nebulex_redis_adapter
[nbx_cachex]: https://github.com/cabol/nebulex_adapters_cachex
[nbx_horde]: https://github.com/eliasdarruda/nebulex_adapters_horde


For example, if you want to use a built-in cache, add to your `mix.exs` file:

```elixir
Expand Down
4 changes: 2 additions & 2 deletions benchmarks/bench_helper.exs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ defmodule BenchHelper do
"take" => fn input ->
cache.take(input)
end,
"has_key?" => fn input ->
cache.has_key?(input)
"exists?" => fn input ->
cache.exists?(input)
end,
"count_all" => fn _input ->
cache.count_all()
Expand Down
1 change: 1 addition & 0 deletions coveralls.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
},

"skip_files": [
"lib/nebulex/cache/options.ex",
"test/support/*",
"test/dialyzer/*"
]
Expand Down
66 changes: 43 additions & 23 deletions guides/creating-new-adapter.md
Original file line number Diff line number Diff line change
Expand Up @@ -231,10 +231,10 @@ mix test
54) test put_all/2 puts the given entries using different data types at once (NebulexMemoryAdapterTest)
test/nebulex_memory_adapter_test.exs:128
** (UndefinedFunctionError) function NebulexMemoryAdapter.TestCache.delete_all/0 is undefined or private. Did you mean:

* delete/1
* delete/2

stacktrace:
(nebulex_memory_adapter 0.1.0) NebulexMemoryAdapter.TestCache.delete_all()
test/nebulex_memory_adapter_test.exs:9: NebulexMemoryAdapterTest.__ex_unit_setup_0/1
Expand All @@ -256,21 +256,25 @@ defmodule NebulexMemoryAdapter do
@behaviour Nebulex.Adapter
@behaviour Nebulex.Adapter.Queryable

import Nebulex.Helpers

@impl Nebulex.Adapter
defmacro __before_compile__(_env), do: :ok

@impl Nebulex.Adapter
def init(_opts) do
child_spec = Supervisor.child_spec({Agent, fn -> %{} end}, id: {Agent, 1})

{:ok, child_spec, %{}}
end

@impl Nebulex.Adapter.Queryable
def execute(adapter_meta, :delete_all, query, opts) do
deleted = Agent.get(adapter_meta.pid, &map_size/1)

Agent.update(adapter_meta.pid, fn _state -> %{} end)

deleted
wrap_ok deleted
end
end
```
Expand Down Expand Up @@ -304,23 +308,26 @@ defmodule NebulexMemoryAdapter do
@behaviour Nebulex.Adapter.Entry
@behaviour Nebulex.Adapter.Queryable

import Nebulex.Helpers

@impl Nebulex.Adapter
defmacro __before_compile__(_env), do: :ok

@impl Nebulex.Adapter
def init(_opts) do
child_spec = Supervisor.child_spec({Agent, fn -> %{} end}, id: {Agent, 1})

{:ok, child_spec, %{}}
end

@impl Nebulex.Adapter.Entry
def get(adapter_meta, key, _opts) do
Agent.get(adapter_meta.pid, &Map.get(&1, key))
def fetch(adapter_meta, key, _opts) do
wrap_ok Agent.get(adapter_meta.pid, &Map.get(&1, key))
end

@impl Nebulex.Adapter.Entry
def get_all(adapter_meta, keys, _opts) do
Agent.get(adapter_meta.pid, &Map.take(&1, keys))
wrap_ok Agent.get(adapter_meta.pid, &Map.take(&1, keys))
end

@impl Nebulex.Adapter.Entry
Expand All @@ -331,48 +338,58 @@ defmodule NebulexMemoryAdapter do
put(adapter_meta, key, value, ttl, :put, opts)
true
end
|> wrap_ok()
end

def put(adapter_meta, key, value, ttl, :replace, opts) do
if get(adapter_meta, key, []) do
put(adapter_meta, key, value, ttl, :put, opts)

true
else
false
end
|> wrap_ok()
end

def put(adapter_meta, key, value, _ttl, _on_write, _opts) do
Agent.update(adapter_meta.pid, &Map.put(&1, key, value))
true

wrap_ok true
end

@impl Nebulex.Adapter.Entry
def put_all(adapter_meta, entries, ttl, :put_new, opts) do
if get_all(adapter_meta, Map.keys(entries), []) == %{} do
put_all(adapter_meta, entries, ttl, :put, opts)

true
else
false
end
|> wrap_ok()
end

def put_all(adapter_meta, entries, _ttl, _on_write, _opts) do
entries = Map.new(entries)

Agent.update(adapter_meta.pid, &Map.merge(&1, entries))
true

wrap_ok true
end

@impl Nebulex.Adapter.Entry
def delete(adapter_meta, key, _opts) do
Agent.update(adapter_meta.pid, &Map.delete(&1, key))
wrap_ok Agent.update(adapter_meta.pid, &Map.delete(&1, key))
end

@impl Nebulex.Adapter.Entry
def take(adapter_meta, key, _opts) do
value = get(adapter_meta, key, [])

delete(adapter_meta, key, [])
value

wrap_ok value
end

@impl Nebulex.Adapter.Entry
Expand All @@ -381,48 +398,51 @@ defmodule NebulexMemoryAdapter do
Map.update(state, key, default + amount, fn v -> v + amount end)
end)

get(adapter_meta, key, [])
wrap_ok get(adapter_meta, key, [])
end

@impl Nebulex.Adapter.Entry
def has_key?(adapter_meta, key) do
Agent.get(adapter_meta.pid, &Map.has_key?(&1, key))
def exists?(adapter_meta, key, _opts) do
wrap_ok Agent.get(adapter_meta.pid, &Map.has_key?(&1, key))
end

@impl Nebulex.Adapter.Entry
def ttl(_adapter_meta, _key) do
nil
def ttl(_adapter_meta, _key, _opts) do
wrap_ok nil
end

@impl Nebulex.Adapter.Entry
def expire(_adapter_meta, _key, _ttl) do
true
def expire(_adapter_meta, _key, _ttl, _opts) do
wrap_ok true
end

@impl Nebulex.Adapter.Entry
def touch(_adapter_meta, _key) do
true
def touch(_adapter_meta, _key, _opts) do
wrap_ok true
end

@impl Nebulex.Adapter.Queryable
def execute(adapter_meta, :delete_all, _query, _opts) do
deleted = execute(adapter_meta, :count_all, nil, [])

Agent.update(adapter_meta.pid, fn _state -> %{} end)

deleted
wrap_ok deleted
end

def execute(adapter_meta, :count_all, _query, _opts) do
Agent.get(adapter_meta.pid, &map_size/1)
wrap_ok Agent.get(adapter_meta.pid, &map_size/1)
end

def execute(adapter_meta, :all, _query, _opts) do
Agent.get(adapter_meta.pid, &Map.values/1)
wrap_ok Agent.get(adapter_meta.pid, &Map.values/1)
end

@impl Nebulex.Adapter.Queryable
def stream(_adapter_meta, :invalid_query, _opts) do
raise Nebulex.QueryError, message: "foo", query: :invalid_query

wrap_error Nebulex.QueryError, message: "foo", query: :invalid_query
end

def stream(adapter_meta, _query, opts) do
Expand All @@ -438,7 +458,7 @@ defmodule NebulexMemoryAdapter do
&Map.keys/1
end

Agent.get(adapter_meta.pid, fun)
wrap_ok Agent.get(adapter_meta.pid, fun)
end
end
```
Expand Down
6 changes: 3 additions & 3 deletions guides/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -257,13 +257,13 @@ iex> for key <- 1..3 do
["Galileo", "Charles", "Albert"]
```

There is a function `has_key?` to check if a key exist in cache:
There is a function `exists?` to check if a key exist in cache:

```elixir
iex> Blog.Cache.has_key?(1)
iex> Blog.Cache.exists?(1)
true

iex> Blog.Cache.has_key?(10)
iex> Blog.Cache.exists?(10)
false
```

Expand Down

0 comments on commit 5ffc3ab

Please sign in to comment.