Packages

Provides JSON data integration for the Mjolnir MUD Engine.

Current section

Files

Jump to
mjolnir_json_datasource lib mjolnir_json_datasource.ex
Raw

lib/mjolnir_json_datasource.ex

defmodule MjolnirJsonDatasource do
@moduledoc """
Provides data from json files.
"""
use Mjolnir.Datasource
alias Mjolnir.Entity
@impl true
def find(spec) when is_binary(spec) do
spec |> parse_pathspec() |> find(spec)
end
def find(pathspec) when is_struct(pathspec, Entity.Pathspec) do
find(pathspec, pathspec |> to_path())
end
def find(pathspec, spec) do
case all(pathspec) do
{:ok, entities} ->
entity =
Enum.filter(entities, fn entity ->
entity.id == spec
end)
|> List.first()
if is_nil(entity) do
{:error, :notfound}
else
{:ok, entity}
end
{:error, error} ->
{:error, error}
end
end
@impl true
def all(spec) when is_binary(spec) do
spec |> parse_pathspec |> all()
end
def all(pathspec) when is_struct(pathspec, Entity.Pathspec) do
marshall_from_pathspec(pathspec)
end
@impl true
def create(entity) do
pathspec = entity.id |> parse_pathspec()
case find(pathspec) do
{:ok, entity} ->
{:error, "an entity with id of' '#{entity.id}' already exists"}
{:error, :notfound} ->
unmarshall_to_pathspec(entity, pathspec)
end
end
@impl true
def update(entity) do
pathspec = entity.id |> parse_pathspec()
case find(pathspec) do
{:ok, _entity} ->
unmarshall_and_replace_in_pathspec(entity, pathspec)
{:error, :notfound} ->
{:error, :notfound}
end
end
@impl true
def destroy(entity) do
pathspec = entity.id |> parse_pathspec()
case find(pathspec) do
{:ok, _entity} ->
unmarshall_and_remove_from_pathspec(pathspec)
{:error, :notfound} ->
{:error, :notfound}
end
end
defp unmarshall_and_replace_in_pathspec(entity, pathspec) do
case all(pathspec) do
{:ok, entities} ->
entities =
Enum.filter(entities, fn entity ->
entity.pathspec.id != pathspec.id
end)
unmarshall_and_encode(entities ++ [entity], pathspec)
{:error, message} ->
{:error, message}
end
end
defp unmarshall_and_remove_from_pathspec(pathspec) do
case all(pathspec) do
{:ok, entities} ->
entities =
Enum.filter(entities, fn entity ->
entity.pathspec.id != pathspec.id
end)
unmarshall_and_encode(entities, pathspec)
{:error, message} ->
{:error, message}
end
end
defp unmarshall_to_pathspec(entity, pathspec) do
case all(pathspec) do
{:ok, entities} ->
unmarshall_and_encode(entities ++ [entity], pathspec)
{:error, error} ->
{:error, error}
end
end
defp unmarshall_and_encode(entities, pathspec) do
entities =
Enum.reduce(entities, [], fn entity, acc ->
acc ++ [Entity.unmarshall(entity)]
end)
case Jason.encode(entities) do
{:ok, encoded} ->
File.write("#{pathspec.path}.json", encoded)
{:error, message} ->
{:error, message}
end
end
defp marshall_from_pathspec(pathspec) do
case File.read("#{pathspec.path}.json") do
{:ok, content} ->
decode_and_marshall(content, pathspec)
{:error, _message} ->
{:error, "The file at '#{pathspec.path}' could not be read"}
end
end
defp decode_and_marshall(content, pathspec) do
case Jason.decode(content) do
{:ok, maps} ->
{:ok,
Enum.reduce(maps, [], fn map, acc ->
acc ++ [Entity.marshall(map, pathspec)]
end)}
{:error, message} ->
{:error, message}
end
end
defp parse_pathspec(spec) do
Entity.parse_pathspec(spec)
end
defp to_path(pathspec) do
Entity.Pathspec.to_path(pathspec)
end
end