mirror of
https://github.com/ash-project/ash_json_api_wrapper.git
synced 2024-09-19 04:42:52 +12:00
WIP
This commit is contained in:
parent
11c76e2bde
commit
4cf510fbd8
13 changed files with 595 additions and 32 deletions
|
@ -1,4 +1,11 @@
|
|||
# Used by "mix format"
|
||||
# THIS FILE IS AUTOGENERATED USING `mix ash.formatter`
|
||||
# DONT MODIFY IT BY HAND
|
||||
locals_without_parens = [endpoint_base: 1, entity_path: 1, field: 1, field: 2, finch: 1, path: 1]
|
||||
|
||||
[
|
||||
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
|
||||
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"],
|
||||
locals_without_parens: locals_without_parens,
|
||||
export: [
|
||||
locals_without_parens: locals_without_parens
|
||||
]
|
||||
]
|
||||
|
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -20,7 +20,7 @@ erl_crash.dump
|
|||
*.ez
|
||||
|
||||
# Ignore package tarball (built via "mix hex.build").
|
||||
ash_api_wrapper-*.tar
|
||||
ash_json_api_wrapper-*.tar
|
||||
|
||||
# Temporary files, for example, from tests.
|
||||
/tmp/
|
||||
|
|
7
.vscode/settings.json
vendored
Normal file
7
.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"workbench.colorCustomizations": {
|
||||
"activityBar.background": "#041593",
|
||||
"titleBar.activeBackground": "#061ECE",
|
||||
"titleBar.activeForeground": "#F9F9FF"
|
||||
}
|
||||
}
|
|
@ -1,21 +1,21 @@
|
|||
# AshApiWrapper
|
||||
# AshJsonApiWrapper
|
||||
|
||||
**TODO: Add description**
|
||||
|
||||
## Installation
|
||||
|
||||
If [available in Hex](https://hex.pm/docs/publish), the package can be installed
|
||||
by adding `ash_api_wrapper` to your list of dependencies in `mix.exs`:
|
||||
by adding `ash_json_api_wrapper` to your list of dependencies in `mix.exs`:
|
||||
|
||||
```elixir
|
||||
def deps do
|
||||
[
|
||||
{:ash_api_wrapper, "~> 0.1.0"}
|
||||
{:ash_json_api_wrapper, "~> 0.1.0"}
|
||||
]
|
||||
end
|
||||
```
|
||||
|
||||
Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc)
|
||||
and published on [HexDocs](https://hexdocs.pm). Once published, the docs can
|
||||
be found at [https://hexdocs.pm/ash_api_wrapper](https://hexdocs.pm/ash_api_wrapper).
|
||||
be found at [https://hexdocs.pm/ash_json_api_wrapper](https://hexdocs.pm/ash_json_api_wrapper).
|
||||
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
defmodule AshApiWrapper do
|
||||
@moduledoc """
|
||||
Documentation for `AshApiWrapper`.
|
||||
"""
|
||||
|
||||
@doc """
|
||||
Hello world.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> AshApiWrapper.hello()
|
||||
:world
|
||||
|
||||
"""
|
||||
def hello do
|
||||
:world
|
||||
end
|
||||
end
|
95
lib/ash_json_api_wrapper.ex
Normal file
95
lib/ash_json_api_wrapper.ex
Normal file
|
@ -0,0 +1,95 @@
|
|||
defmodule AshJsonApiWrapper do
|
||||
@moduledoc """
|
||||
"""
|
||||
|
||||
alias Ash.Dsl.Extension
|
||||
|
||||
@spec endpoint_base(Ash.Resource.t()) :: String.t() | nil
|
||||
def endpoint_base(resource) do
|
||||
Extension.get_opt(resource, [:json_api_wrapper, :endpoints], :base, nil, false)
|
||||
end
|
||||
|
||||
@spec finch(Ash.Resource.t()) :: module | nil
|
||||
def finch(resource) do
|
||||
Extension.get_opt(resource, [:json_api_wrapper], :finch, nil, false)
|
||||
end
|
||||
|
||||
@spec before_request(Ash.Resource.t()) :: module | nil
|
||||
def before_request(resource) do
|
||||
Extension.get_opt(resource, [:json_api_wrapper], :before_request, nil, false)
|
||||
end
|
||||
|
||||
@spec field(Ash.Resource.t(), atom) :: AshJsonApiWrapper.Field.t() | nil
|
||||
def field(resource, name) do
|
||||
resource
|
||||
|> fields()
|
||||
|> Enum.find(&(&1.name == name))
|
||||
end
|
||||
|
||||
@spec fields(Ash.Resource.t()) :: list(AshJsonApiWrapper.Field.t())
|
||||
def fields(resource) do
|
||||
Extension.get_entities(resource, [:json_api_wrapper, :fields])
|
||||
end
|
||||
|
||||
@spec endpoint(Ash.Resource.t(), atom) :: AshJsonApiWrapper.Endpoint.t() | nil
|
||||
def endpoint(resource, action) do
|
||||
default_endpoint = AshJsonApiWrapper.Endpoint.default(endpoint_base(resource))
|
||||
|
||||
resource
|
||||
|> Extension.get_entities([:json_api_wrapper, :endpoints])
|
||||
|> Enum.find(&(&1.action == action))
|
||||
|> case do
|
||||
nil ->
|
||||
default_endpoint
|
||||
endpoint ->
|
||||
if default_endpoint.path && endpoint.path do
|
||||
%{endpoint | path: default_endpoint.path <> endpoint.path}
|
||||
else
|
||||
%{endpoint | path: endpoint.path || default_endpoint.path}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@spec endpoints(Ash.Resource.t()) :: list(AshJsonApiWrapper.Endpoint.t())
|
||||
def endpoints(resource) do
|
||||
Extension.get_entities(resource, [:json_api_wrapper, :endpoints])
|
||||
end
|
||||
|
||||
@spec set_body_param(query_or_changeset, String.t(), any) :: query_or_changeset
|
||||
when query_or_changeset: Ash.Query.t() | Ash.Changeset.t()
|
||||
def set_body_param(query, key, value) do
|
||||
new_context =
|
||||
query.context
|
||||
|> Map.put_new(:data_layer, %{})
|
||||
|> Map.update!(:data_layer, fn data_layer ->
|
||||
data_layer
|
||||
|> Map.put_new(:body, %{})
|
||||
|> Map.update!(:body, &Map.put(&1, key, value))
|
||||
end)
|
||||
|
||||
%{query | context: new_context}
|
||||
end
|
||||
|
||||
@spec merge_query_params(query_or_changeset, map) :: query_or_changeset
|
||||
when query_or_changeset: Ash.Query.t() | Ash.Changeset.t()
|
||||
def merge_query_params(%Ash.Query{} = query, params) do
|
||||
Ash.Query.set_context(query, %{data_layer: %{query_params: params}})
|
||||
end
|
||||
|
||||
def merge_query_params(%Ash.Changeset{} = changeset, params) do
|
||||
Ash.Changeset.set_context(changeset, %{data_layer: %{query_params: params}})
|
||||
end
|
||||
|
||||
@spec set_query_params(query_or_changeset, map) :: query_or_changeset
|
||||
when query_or_changeset: Ash.Query.t() | Ash.Changeset.t()
|
||||
def set_query_params(query, params) do
|
||||
new_context =
|
||||
query.context
|
||||
|> Map.put_new(:data_layer, %{})
|
||||
|> Map.update!(:data_layer, fn data_layer ->
|
||||
Map.put(data_layer, :query_params, params)
|
||||
end)
|
||||
|
||||
%{query | context: new_context}
|
||||
end
|
||||
end
|
324
lib/data_layer.ex
Normal file
324
lib/data_layer.ex
Normal file
|
@ -0,0 +1,324 @@
|
|||
defmodule AshJsonApiWrapper.DataLayer do
|
||||
@field %Ash.Dsl.Entity{
|
||||
name: :field,
|
||||
target: AshJsonApiWrapper.Field,
|
||||
schema: AshJsonApiWrapper.Field.schema(),
|
||||
docs: """
|
||||
Configure an individual field's behavior, for example its path in the response.
|
||||
""",
|
||||
args: [:name]
|
||||
}
|
||||
|
||||
@fields %Ash.Dsl.Section{
|
||||
name: :fields,
|
||||
describe: "Contains configuration for individual fields in the response",
|
||||
entities: [
|
||||
@field
|
||||
]
|
||||
}
|
||||
|
||||
@endpoint %Ash.Dsl.Entity{
|
||||
name: :endpoint,
|
||||
target: AshJsonApiWrapper.Endpoint,
|
||||
schema: AshJsonApiWrapper.Endpoint.schema(),
|
||||
docs: """
|
||||
Configure the endpoint that a given action will use.
|
||||
|
||||
Accepts overrides for fields as well.
|
||||
""",
|
||||
entities: [
|
||||
fields: @field
|
||||
],
|
||||
args: [:action]
|
||||
}
|
||||
|
||||
@endpoints %Ash.Dsl.Section{
|
||||
name: :endpoints,
|
||||
describe: "Contains the configuration for the endpoints used in each action",
|
||||
schema: [
|
||||
base: [
|
||||
type: :string,
|
||||
doc: "The base endpoint to which all relative urls provided will be appended."
|
||||
]
|
||||
],
|
||||
entities: [
|
||||
@endpoint
|
||||
]
|
||||
}
|
||||
|
||||
@json_api_wrapper %Ash.Dsl.Section{
|
||||
name: :json_api_wrapper,
|
||||
describe: "Contains the configuration for the json_api_wrapper data layer",
|
||||
sections: [
|
||||
@fields,
|
||||
@endpoints
|
||||
],
|
||||
schema: [
|
||||
before_request: [
|
||||
type: :any,
|
||||
doc: """
|
||||
A function that takes the finch request and returns the finch request.
|
||||
Will be called just before the request is made for all requests, but before JSON encoding the body and query encoding the query parameters.
|
||||
"""
|
||||
],
|
||||
finch: [
|
||||
type: :atom,
|
||||
required: true,
|
||||
doc: """
|
||||
The name used when setting up your finch supervisor in your Application.
|
||||
|
||||
e.g in this example from finch's readme:
|
||||
|
||||
```elixir
|
||||
{Finch, name: MyConfiguredFinch <- this value}
|
||||
```
|
||||
"""
|
||||
]
|
||||
]
|
||||
}
|
||||
|
||||
use Ash.Dsl.Extension, sections: [@json_api_wrapper]
|
||||
|
||||
defmodule Query do
|
||||
defstruct [:request, :action]
|
||||
end
|
||||
|
||||
@behaviour Ash.DataLayer
|
||||
|
||||
@impl true
|
||||
def can?(_, :create), do: true
|
||||
def can?(_, _), do: false
|
||||
|
||||
@impl true
|
||||
def resource_to_query(resource) do
|
||||
%Query{request: Finch.build(:get, AshJsonApiWrapper.endpoint_base(resource))}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def set_context(_resource, query, context) do
|
||||
params = context[:data_layer][:query_params]
|
||||
|
||||
if params do
|
||||
{:ok, %{query | request: %{query.request | query: params}, action: context[:action]}}
|
||||
else
|
||||
{:ok, %{query | action: context[:action]}}
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
def create(resource, changeset) do
|
||||
endpoint = AshJsonApiWrapper.endpoint(resource, changeset.action.name)
|
||||
|
||||
base =
|
||||
case endpoint && endpoint.fields_in do
|
||||
:body ->
|
||||
changeset.context[:data_layer][:body] || %{}
|
||||
|
||||
:params ->
|
||||
changeset.context[:data_layer][:query_params] || %{}
|
||||
end
|
||||
|
||||
{:ok, with_attrs} =
|
||||
changeset.attributes
|
||||
|> Kernel.||(%{})
|
||||
|> Enum.reduce_while({:ok, base}, fn {key, value}, {:ok, acc} ->
|
||||
attribute = Ash.Resource.Info.attribute(resource, key)
|
||||
field = AshJsonApiWrapper.field(resource, attribute.name)
|
||||
|
||||
case Ash.Type.dump_to_embedded(
|
||||
attribute.type,
|
||||
value,
|
||||
attribute.constraints
|
||||
) do
|
||||
{:ok, dumped} ->
|
||||
path =
|
||||
if field && field.write_path do
|
||||
field.write_path
|
||||
else
|
||||
[to_string(attribute.name)]
|
||||
end
|
||||
|
||||
path =
|
||||
if endpoint.write_entity_path do
|
||||
endpoint.write_entity_path ++ path
|
||||
else
|
||||
path
|
||||
end
|
||||
|
||||
{:cont, {:ok, put_in!(acc, path, dumped)}}
|
||||
|
||||
:error ->
|
||||
{:halt,
|
||||
{:error,
|
||||
Ash.Error.Changes.InvalidAttribute.exception(
|
||||
field: attribute.name,
|
||||
message: "Could not be dumped to embedded"
|
||||
)}}
|
||||
end
|
||||
end)
|
||||
|
||||
{body, params} =
|
||||
case endpoint.fields_in do
|
||||
:params ->
|
||||
{changeset.context[:data_layer][:body] || %{}, with_attrs}
|
||||
|
||||
:body ->
|
||||
{with_attrs, changeset.context[:data_layer][:query_params] || %{}}
|
||||
end
|
||||
|
||||
:post
|
||||
|> Finch.build(
|
||||
endpoint.path || AshJsonApiWrapper.endpoint_base(resource),
|
||||
[{"Content-Type", "application/json"}, {"Accept", "application/json"}],
|
||||
body
|
||||
)
|
||||
|> Map.put(:query, params)
|
||||
|> request(resource)
|
||||
|
||||
{:ok, struct(resource, [])}
|
||||
end
|
||||
|
||||
defp put_in!(body, [key], value) do
|
||||
Map.put(body, key, value)
|
||||
end
|
||||
|
||||
defp put_in!(body, [first | rest], value) do
|
||||
body
|
||||
|> Map.put_new(first, %{})
|
||||
|> Map.update!(first, &put_in!(&1, rest, value))
|
||||
end
|
||||
|
||||
@impl true
|
||||
def run_query(query, resource) do
|
||||
endpoint = AshJsonApiWrapper.endpoint(resource, query.action.name)
|
||||
|
||||
with {:ok, %{status: status} = response} when status >= 200 and status < 300 <-
|
||||
request(query.request, resource),
|
||||
{:ok, body} <- Jason.decode(response.body),
|
||||
{:ok, entities} <- get_entities(body, endpoint) do
|
||||
process_entities(entities, resource)
|
||||
else
|
||||
{:ok, %{status: status} = response} ->
|
||||
{:error,
|
||||
"Received status code #{status} in request #{inspect(query.request)}. Response: #{inspect(response)}"}
|
||||
|
||||
other ->
|
||||
other
|
||||
end
|
||||
end
|
||||
|
||||
defp request(request, resource) do
|
||||
case AshJsonApiWrapper.before_request(resource) do
|
||||
nil ->
|
||||
request
|
||||
|> encode_query()
|
||||
|> encode_body()
|
||||
|> IO.inspect()
|
||||
|> Finch.request(AshJsonApiWrapper.finch(resource))
|
||||
|
||||
hook ->
|
||||
request
|
||||
|> hook.()
|
||||
|> encode_query()
|
||||
|> encode_body()
|
||||
|> IO.inspect()
|
||||
|> Finch.request(AshJsonApiWrapper.finch(resource))
|
||||
end
|
||||
|> IO.inspect()
|
||||
end
|
||||
|
||||
defp encode_query(%{query: query} = request) when is_map(query) do
|
||||
%{request | query: URI.encode_query(query)}
|
||||
end
|
||||
|
||||
defp encode_query(request), do: request
|
||||
|
||||
defp encode_body(%{body: body} = request) when is_map(body) do
|
||||
%{request | body: Jason.encode!(body)}
|
||||
end
|
||||
|
||||
defp encode_body(request), do: request
|
||||
|
||||
defp process_entities(entities, resource) do
|
||||
Enum.reduce_while(entities, {:ok, []}, fn entity, {:ok, entities} ->
|
||||
case process_entity(entity, resource) do
|
||||
{:ok, entity} -> {:cont, {:ok, [entity | entities]}}
|
||||
{:error, error} -> {:halt, {:error, error}}
|
||||
end
|
||||
end)
|
||||
|> case do
|
||||
{:ok, entities} -> {:ok, Enum.reverse(entities)}
|
||||
{:error, error} -> {:error, error}
|
||||
end
|
||||
end
|
||||
|
||||
defp process_entity(entity, resource) do
|
||||
resource
|
||||
|> Ash.Resource.Info.attributes()
|
||||
|> Enum.reduce_while(
|
||||
{:ok,
|
||||
struct(resource,
|
||||
__meta__: %Ecto.Schema.Metadata{
|
||||
state: :loaded
|
||||
}
|
||||
)},
|
||||
fn attr, {:ok, record} ->
|
||||
case get_field(entity, attr, resource) do
|
||||
{:ok, value} ->
|
||||
{:cont, {:ok, Map.put(record, attr.name, value)}}
|
||||
|
||||
{:error, error} ->
|
||||
{:halt, {:error, error}}
|
||||
end
|
||||
end
|
||||
)
|
||||
end
|
||||
|
||||
defp get_field(entity, attr, resource) do
|
||||
raw_value = get_raw_value(entity, attr, resource)
|
||||
|
||||
case Ash.Type.cast_stored(attr.type, raw_value, attr.constraints) do
|
||||
{:ok, value} ->
|
||||
{:ok, value}
|
||||
|
||||
_ ->
|
||||
{:error,
|
||||
AshJsonApiWrapper.Errors.InvalidData.exception(field: attr.name, value: raw_value)}
|
||||
end
|
||||
end
|
||||
|
||||
defp get_raw_value(entity, attr, resource) do
|
||||
case Enum.find(AshJsonApiWrapper.fields(resource), &(&1.name == attr.name)) do
|
||||
%{path: path} when not is_nil(path) ->
|
||||
case ExJSONPath.eval(entity, path) do
|
||||
{:ok, [value | _]} ->
|
||||
value
|
||||
|
||||
_ ->
|
||||
nil
|
||||
end
|
||||
|
||||
_ ->
|
||||
Map.get(entity, to_string(attr.name))
|
||||
end
|
||||
end
|
||||
|
||||
defp get_entities(body, endpoint) do
|
||||
case endpoint.entity_path do
|
||||
nil ->
|
||||
{:ok, List.wrap(body)}
|
||||
|
||||
path ->
|
||||
case ExJSONPath.eval(body, path) do
|
||||
{:ok, [entities | _]} ->
|
||||
{:ok, List.wrap(entities)}
|
||||
|
||||
{:ok, _} ->
|
||||
{:ok, []}
|
||||
|
||||
{:error, error} ->
|
||||
{:error, error}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
41
lib/endpoint.ex
Normal file
41
lib/endpoint.ex
Normal file
|
@ -0,0 +1,41 @@
|
|||
defmodule AshJsonApiWrapper.Endpoint do
|
||||
defstruct [:action, :path, :entity_path, :fields, :fields_in, :write_entity_path]
|
||||
|
||||
@type t :: %__MODULE__{}
|
||||
|
||||
def schema do
|
||||
[
|
||||
action: [
|
||||
type: :atom,
|
||||
required: true,
|
||||
doc: "The action this path is for"
|
||||
],
|
||||
path: [
|
||||
type: :string,
|
||||
default: "/",
|
||||
doc: "The path of the endpoint relative to the base, or an absolute path"
|
||||
],
|
||||
fields_in: [
|
||||
type: {:in, [:body, :params]},
|
||||
default: :body,
|
||||
doc: "Where to place the fields when writing them."
|
||||
],
|
||||
write_entity_path: [
|
||||
type: {:list, :string},
|
||||
doc:
|
||||
"The list path at which the entity should be placed in the body when creating/updating."
|
||||
],
|
||||
entity_path: [
|
||||
type: :string,
|
||||
doc: "A json path at which the entities can be read back from the response"
|
||||
]
|
||||
]
|
||||
end
|
||||
|
||||
def default(path) do
|
||||
%__MODULE__{
|
||||
path: path,
|
||||
fields_in: :body
|
||||
}
|
||||
end
|
||||
end
|
19
lib/errors/invalid_data.ex
Normal file
19
lib/errors/invalid_data.ex
Normal file
|
@ -0,0 +1,19 @@
|
|||
defmodule AshJsonApiWrapper.Errors.InvalidData do
|
||||
@moduledoc "Used when an invalid value is present in the response for a given attribute"
|
||||
use Ash.Error.Exception
|
||||
|
||||
def_ash_error([:field, :value], class: :invalid)
|
||||
|
||||
defimpl Ash.ErrorKind do
|
||||
def id(_), do: Ash.UUID.generate()
|
||||
|
||||
def code(_), do: "invalid_data"
|
||||
|
||||
def message(error) do
|
||||
"Invalid value provided#{for_field(error)}: #{inspect(error.value)}"
|
||||
end
|
||||
|
||||
defp for_field(%{field: field}) when not is_nil(field), do: " for #{field}"
|
||||
defp for_field(_), do: ""
|
||||
end
|
||||
end
|
23
lib/field.ex
Normal file
23
lib/field.ex
Normal file
|
@ -0,0 +1,23 @@
|
|||
defmodule AshJsonApiWrapper.Field do
|
||||
defstruct [:name, :path, :write_path]
|
||||
|
||||
@type t :: %__MODULE__{}
|
||||
|
||||
def schema do
|
||||
[
|
||||
name: [
|
||||
type: :atom,
|
||||
required: true,
|
||||
doc: "The attribute this field is configuring"
|
||||
],
|
||||
path: [
|
||||
type: :string,
|
||||
doc: "The path of the value for this field, relative to the entity's path"
|
||||
],
|
||||
write_path: [
|
||||
type: {:list, :string},
|
||||
doc: "The list path of the value for this field when writing."
|
||||
]
|
||||
]
|
||||
end
|
||||
end
|
26
mix.exs
26
mix.exs
|
@ -1,11 +1,12 @@
|
|||
defmodule AshApiWrapper.MixProject do
|
||||
defmodule AshJsonApiWrapper.MixProject do
|
||||
use Mix.Project
|
||||
|
||||
def project do
|
||||
[
|
||||
app: :ash_api_wrapper,
|
||||
app: :ash_json_api_wrapper,
|
||||
version: "0.1.0",
|
||||
elixir: "~> 1.12",
|
||||
aliases: aliases(),
|
||||
start_permanent: Mix.env() == :prod,
|
||||
deps: deps()
|
||||
]
|
||||
|
@ -18,11 +19,28 @@ defmodule AshApiWrapper.MixProject do
|
|||
]
|
||||
end
|
||||
|
||||
defp aliases do
|
||||
[
|
||||
"ash.formatter": "ash.formatter --extensions AshJsonApiWrapper.DataLayer"
|
||||
]
|
||||
end
|
||||
|
||||
# Run "mix help deps" to learn about dependencies.
|
||||
defp deps do
|
||||
[
|
||||
# {:dep_from_hexpm, "~> 0.3.0"},
|
||||
# {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}
|
||||
{:ash, "~> 1.48.0-rc.23"},
|
||||
{:finch, "~> 0.9.0"},
|
||||
{:exjsonpath, "~> 0.1"},
|
||||
# Dev/Test dependencies
|
||||
{:ex_doc, "~> 0.22", only: :dev, runtime: false},
|
||||
{:ex_check, "~> 0.12.0", only: :dev},
|
||||
{:credo, ">= 0.0.0", only: :dev, runtime: false},
|
||||
{:dialyxir, ">= 0.0.0", only: :dev, runtime: false},
|
||||
{:sobelow, ">= 0.0.0", only: :dev, runtime: false},
|
||||
{:git_ops, "~> 2.4.4", only: :dev},
|
||||
{:excoveralls, "~> 0.13.0", only: [:dev, :test]},
|
||||
{:mix_test_watch, "~> 1.0", only: :dev, runtime: false},
|
||||
{:parse_trans, "3.3.0", only: [:dev, :test], override: true}
|
||||
]
|
||||
end
|
||||
end
|
||||
|
|
47
mix.lock
Normal file
47
mix.lock
Normal file
|
@ -0,0 +1,47 @@
|
|||
%{
|
||||
"ash": {:hex, :ash, "1.48.0-rc.23", "0a41e4ad62dff764bb8ea9b4645f2f9539a596587910d1b1919f3d25a30f35e9", [:mix], [{:comparable, "~> 1.0", [hex: :comparable, repo: "hexpm", optional: false]}, {:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:ecto, "~> 3.7", [hex: :ecto, repo: "hexpm", optional: false]}, {:ets, "~> 0.8.0", [hex: :ets, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.3.5", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:picosat_elixir, "~> 0.2", [hex: :picosat_elixir, repo: "hexpm", optional: false]}, {:timex, ">= 3.0.0", [hex: :timex, repo: "hexpm", optional: false]}], "hexpm", "9cce85c4a2bcc91aaaee3b1e5d39f1218bc608974792caefe27cf56d6532cfd1"},
|
||||
"bunt": {:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", [:mix], [], "hexpm", "7af5c7e09fe1d40f76c8e4f9dd2be7cebd83909f31fee7cd0e9eadc567da8353"},
|
||||
"castore": {:hex, :castore, "0.1.12", "b5755d7668668a74c0e3c4c68df91da927e063a5cade17d693eff04e6ab64805", [:mix], [], "hexpm", "981c79528f88ec4ffd627214ad4cdd25052dc56c002996c603011ae37ec1b4b0"},
|
||||
"certifi": {:hex, :certifi, "2.8.0", "d4fb0a6bb20b7c9c3643e22507e42f356ac090a1dcea9ab99e27e0376d695eba", [:rebar3], [], "hexpm", "6ac7efc1c6f8600b08d625292d4bbf584e14847ce1b6b5c44d983d273e1097ea"},
|
||||
"combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm", "1b1dbc1790073076580d0d1d64e42eae2366583e7aecd455d1215b0d16f2451b"},
|
||||
"comparable": {:hex, :comparable, "1.0.0", "bb669e91cedd14ae9937053e5bcbc3c52bb2f22422611f43b6e38367d94a495f", [:mix], [{:typable, "~> 0.1", [hex: :typable, repo: "hexpm", optional: false]}], "hexpm", "277c11eeb1cd726e7cd41c6c199e7e52fa16ee6830b45ad4cdc62e51f62eb60c"},
|
||||
"credo": {:hex, :credo, "1.5.6", "e04cc0fdc236fefbb578e0c04bd01a471081616e741d386909e527ac146016c6", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "4b52a3e558bd64e30de62a648518a5ea2b6e3e5d2b164ef5296244753fc7eb17"},
|
||||
"decimal": {:hex, :decimal, "2.0.0", "a78296e617b0f5dd4c6caf57c714431347912ffb1d0842e998e9792b5642d697", [:mix], [], "hexpm", "34666e9c55dea81013e77d9d87370fe6cb6291d1ef32f46a1600230b1d44f577"},
|
||||
"dialyxir": {:hex, :dialyxir, "1.1.0", "c5aab0d6e71e5522e77beff7ba9e08f8e02bad90dfbeffae60eaf0cb47e29488", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "07ea8e49c45f15264ebe6d5b93799d4dd56a44036cf42d0ad9c960bc266c0b9a"},
|
||||
"earmark_parser": {:hex, :earmark_parser, "1.4.16", "607709303e1d4e3e02f1444df0c821529af1c03b8578dfc81bb9cf64553d02b9", [:mix], [], "hexpm", "69fcf696168f5a274dd012e3e305027010658b2d1630cef68421d6baaeaccead"},
|
||||
"ecto": {:hex, :ecto, "3.7.1", "a20598862351b29f80f285b21ec5297da1181c0442687f9b8329f0445d228892", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d36e5b39fc479e654cffd4dbe1865d9716e4a9b6311faff799b6f90ab81b8638"},
|
||||
"elixir_make": {:hex, :elixir_make, "0.6.3", "bc07d53221216838d79e03a8019d0839786703129599e9619f4ab74c8c096eac", [:mix], [], "hexpm", "f5cbd651c5678bcaabdbb7857658ee106b12509cd976c2c2fca99688e1daf716"},
|
||||
"erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"},
|
||||
"ets": {:hex, :ets, "0.8.1", "8ff9bcda5682b98493f8878fc9dbd990e48d566cba8cce59f7c2a78130da29ea", [:mix], [], "hexpm", "6be41b50adb5bc5c43626f25ea2d0af1f4a242fb3fad8d53f0c67c20b78915cc"},
|
||||
"ex_check": {:hex, :ex_check, "0.12.0", "c0e2919ecc06afeaf62c52d64f3d91bd4bc7dd8deaac5f84becb6278888c967a", [:mix], [], "hexpm", "cfafa8ef97c2596d45a1f19b5794cb5c7f700f25d164d3c9f8d7ec17ee67cf42"},
|
||||
"ex_doc": {:hex, :ex_doc, "0.25.5", "ac3c5425a80b4b7c4dfecdf51fa9c23a44877124dd8ca34ee45ff608b1c6deb9", [:mix], [{:earmark_parser, "~> 1.4.0", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "688cfa538cdc146bc4291607764a7f1fcfa4cce8009ecd62de03b27197528350"},
|
||||
"excoveralls": {:hex, :excoveralls, "0.13.4", "7b0baee01fe150ef81153e6ffc0fc68214737f54570dc257b3ca4da8e419b812", [:mix], [{:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "faae00b3eee35cdf0342c10b669a7c91f942728217d2a7c7f644b24d391e6190"},
|
||||
"exjsonpath": {:hex, :exjsonpath, "0.9.0", "87e593eb0deb53aa0688ca9f9edc9fb3456aca83c82245f83201ea04d696feba", [:mix], [], "hexpm", "8d7a8e9ba784e1f7a67c6f1074a3ac91a3a79a45969514ee5d95cea5bf749627"},
|
||||
"file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"},
|
||||
"finch": {:hex, :finch, "0.9.0", "8b772324aebafcaba763f1dffaa3e7f52f8c4e52485f50f48bbb2f42219a2e87", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: false]}, {:mint, "~> 1.3", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.3.5", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a93bfcad9ca50fa3cb2d459f27667d9a87cfbb7fecf9b29b2e78a50bc2ab445d"},
|
||||
"gettext": {:hex, :gettext, "0.18.2", "7df3ea191bb56c0309c00a783334b288d08a879f53a7014341284635850a6e55", [:mix], [], "hexpm", "f9f537b13d4fdd30f3039d33cb80144c3aa1f8d9698e47d7bcbcc8df93b1f5c5"},
|
||||
"git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"},
|
||||
"git_ops": {:hex, :git_ops, "2.4.5", "185a724dfde3745edd22f7571d59c47a835cf54ded67e9ccbc951920b7eec4c2", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "e323a5b01ad53bc8c19c3a444be3e61ed7803ecd2e95530446ae9327d0143ecc"},
|
||||
"hackney": {:hex, :hackney, "1.18.0", "c4443d960bb9fba6d01161d01cd81173089686717d9490e5d3606644c48d121f", [:rebar3], [{:certifi, "~>2.8.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~>6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~>1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~>1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "9afcda620704d720db8c6a3123e9848d09c87586dc1c10479c42627b905b5c5e"},
|
||||
"idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"},
|
||||
"jason": {:hex, :jason, "1.2.2", "ba43e3f2709fd1aa1dce90aaabfd039d000469c05c56f0b8e31978e03fa39052", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "18a228f5f0058ee183f29f9eae0805c6e59d61c3b006760668d8d18ff0d12179"},
|
||||
"makeup": {:hex, :makeup, "1.0.5", "d5a830bc42c9800ce07dd97fa94669dfb93d3bf5fcf6ea7a0c67b2e0e4a7f26c", [:mix], [{:nimble_parsec, "~> 0.5 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "cfa158c02d3f5c0c665d0af11512fed3fba0144cf1aadee0f2ce17747fba2ca9"},
|
||||
"makeup_elixir": {:hex, :makeup_elixir, "0.15.2", "dc72dfe17eb240552857465cc00cce390960d9a0c055c4ccd38b70629227e97c", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.1", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "fd23ae48d09b32eff49d4ced2b43c9f086d402ee4fd4fcb2d7fad97fa8823e75"},
|
||||
"makeup_erlang": {:hex, :makeup_erlang, "0.1.1", "3fcb7f09eb9d98dc4d208f49cc955a34218fc41ff6b84df7c75b3e6e533cc65f", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "174d0809e98a4ef0b3309256cbf97101c6ec01c4ab0b23e926a9e17df2077cbb"},
|
||||
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"},
|
||||
"mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"},
|
||||
"mint": {:hex, :mint, "1.4.0", "cd7d2451b201fc8e4a8fd86257fb3878d9e3752899eb67b0c5b25b180bde1212", [:mix], [{:castore, "~> 0.1.0", [hex: :castore, repo: "hexpm", optional: true]}], "hexpm", "10a99e144b815cbf8522dccbc8199d15802440fc7a64d67b6853adb6fa170217"},
|
||||
"mix_test_watch": {:hex, :mix_test_watch, "1.1.0", "330bb91c8ed271fe408c42d07e0773340a7938d8a0d281d57a14243eae9dc8c3", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}], "hexpm", "52b6b1c476cbb70fd899ca5394506482f12e5f6b0d6acff9df95c7f1e0812ec3"},
|
||||
"nimble_options": {:hex, :nimble_options, "0.3.7", "1e52dd7673d36138b1a5dede183b5d86dff175dc46d104a8e98e396b85b04670", [:mix], [], "hexpm", "2086907e6665c6b6579be54ef5001928df5231f355f71ed258f80a55e9f63633"},
|
||||
"nimble_parsec": {:hex, :nimble_parsec, "1.1.0", "3a6fca1550363552e54c216debb6a9e95bd8d32348938e13de5eda962c0d7f89", [:mix], [], "hexpm", "08eb32d66b706e913ff748f11694b17981c0b04a33ef470e33e11b3d3ac8f54b"},
|
||||
"nimble_pool": {:hex, :nimble_pool, "0.2.4", "1db8e9f8a53d967d595e0b32a17030cdb6c0dc4a451b8ac787bf601d3f7704c3", [:mix], [], "hexpm", "367e8071e137b787764e6a9992ccb57b276dc2282535f767a07d881951ebeac6"},
|
||||
"parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm", "17ef63abde837ad30680ea7f857dd9e7ced9476cdd7b0394432af4bfc241b960"},
|
||||
"picosat_elixir": {:hex, :picosat_elixir, "0.2.1", "407dcb90755167fd9e3311b60565ff32ed0d234010363406c07cdb4175b95bc5", [:make, :mix], [{:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "68f4bdb2ac3b594209e54625d3d58c9e2e98b90f2ec8e03235f66e88c9eda5fe"},
|
||||
"sobelow": {:hex, :sobelow, "0.11.1", "23438964486f8112b41e743bbfd402da3e5b296fdc9eacab29914b79c48916dd", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "9897363a7eff96f4809304a90aad819e2ad5e5d24db547af502885146746a53c"},
|
||||
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.6", "cf344f5692c82d2cd7554f5ec8fd961548d4fd09e7d22f5b62482e5aeaebd4b0", [:make, :mix, :rebar3], [], "hexpm", "bdb0d2471f453c88ff3908e7686f86f9be327d065cc1ec16fa4540197ea04680"},
|
||||
"telemetry": {:hex, :telemetry, "1.0.0", "0f453a102cdf13d506b7c0ab158324c337c41f1cc7548f0bc0e130bbf0ae9452", [:rebar3], [], "hexpm", "73bc09fa59b4a0284efb4624335583c528e07ec9ae76aca96ea0673850aec57a"},
|
||||
"timex": {:hex, :timex, "3.7.6", "502d2347ec550e77fdf419bc12d15bdccd31266bb7d925b30bf478268098282f", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 1.0", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "a296327f79cb1ec795b896698c56e662ed7210cc9eb31f0ab365eb3a62e2c589"},
|
||||
"typable": {:hex, :typable, "0.3.0", "0431e121d124cd26f312123e313d2689b9a5322b15add65d424c07779eaa3ca1", [:mix], [], "hexpm", "880a0797752da1a4c508ac48f94711e04c86156f498065a83d160eef945858f8"},
|
||||
"tzdata": {:hex, :tzdata, "1.1.0", "72f5babaa9390d0f131465c8702fa76da0919e37ba32baa90d93c583301a8359", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "18f453739b48d3dc5bcf0e8906d2dc112bb40baafe2c707596d89f3c8dd14034"},
|
||||
"unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"},
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
defmodule AshApiWrapperTest do
|
||||
defmodule AshJsonApiWrapperTest do
|
||||
use ExUnit.Case
|
||||
doctest AshApiWrapper
|
||||
doctest AshJsonApiWrapper
|
||||
|
||||
test "greets the world" do
|
||||
assert AshApiWrapper.hello() == :world
|
||||
assert AshJsonApiWrapper.hello() == :world
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue