Packages
riptide
0.5.0-beta3
0.5.2
0.5.1
0.5.0-beta9
0.5.0-beta8
0.5.0-beta7
0.5.0-beta6
0.5.0-beta5
0.5.0-beta4
0.5.0-beta3
0.5.0-beta2
0.5.0-beta11
0.5.0-beta10
0.5.0-beta
0.4.6
0.4.5
0.4.4
0.4.3
0.4.2
0.4.1
0.4.0
0.3.13
0.3.12
0.3.11
0.3.10
0.3.9
0.3.8
0.3.7
0.3.6
0.3.5
0.3.4
0.3.3
0.3.2
0.3.1
0.3.0
0.3.0-bd63a38
0.2.79
0.2.78
0.2.74
0.2.4
0.2.3
0.2.2
0.2.1
0.2.0
0.1.15
0.1.14
0.1.13
0.1.12
0.1.11
0.1.10
0.1.9
0.1.8
0.1.7
0.1.6
0.1.5
0.1.4
0.1.3
0.1.2
0.1.1
0.1.0
A data first framework for building realtime applications
Current section
Files
Jump to
Current section
Files
lib/riptide/store/store_composite.ex
defmodule Riptide.Store.Composite do
@moduledoc """
This module provides a macro to define a store that splits up the data tree between various other stores. It is implemented via pattern matching paths that are being written or read and specifying which store to go to.
## Usage
```elixir
defmodule Todolist.Store do
use Riptide.Store.Composite
@memory {Riptide.Store.Memory, []}
@local {Riptide.Store.LMDB, directory: "data"}
@shared {Riptide.Store.Postgres, []}
def store(), do: [
@memory,
@local,
@shared,
]
# Any path starting with ["shared"] is saved in a shared postgres instance
def which_path(["shared" | _rest]), do: @shared
# Any path starting with ["tmp"] is kept only in memory
def which_path(["tmp" | _rest]), do: @memory
# Default catch all
def which_path(_), do: @local
end
```
## Configuration
```elixir
config :riptide,
store: %{
read: {Todolist.Store, []},
write: {Todolist.Store, []},
}
```
"""
@doc """
List of stores to initialize that are used by this module.
"""
@callback stores() :: any
@doc """
For a given path, return which store to use. Take advantage of pattern matching to specify broad areas.
"""
@callback which_store(path :: any()) :: {atom(), any()}
defmacro __using__(_opts) do
quote do
@behaviour Riptide.Store.Composite
@behaviour Riptide.Store
def init(_opts) do
Enum.each(stores(), fn {store, opts} ->
:ok = store.init(opts)
end)
end
def mutation(merges, deletes, _opts) do
groups =
Enum.reduce(merges, %{}, fn merge = {path, value}, collect ->
store = which_store(path)
path = [store, :merges]
existing = Dynamic.get(collect, path, [])
Dynamic.put(collect, path, [merge | existing])
end)
groups =
Enum.reduce(deletes, groups, fn delete = {path, value}, collect ->
store = which_store(path)
path = [store, :deletes]
existing = Dynamic.get(collect, path, [])
Dynamic.put(collect, path, [delete | existing])
end)
:ok =
Enum.each(groups, fn {{store, store_opts}, data} ->
merges = Map.get(data, :merges, [])
deletes = Map.get(data, :deletes, [])
store.mutation(merges, deletes, store_opts)
end)
end
def query(layers, _opts) do
groups =
Enum.reduce(layers, %{}, fn merge = {path, value}, collect ->
store = which_store(path)
existing = Map.get(collect, store, [])
Map.put(collect, store, [merge | existing])
end)
Stream.flat_map(groups, fn {{store, store_opts}, layers} ->
store.query(layers, store_opts)
end)
end
end
end
end