2019-10-03 16:08:36 +13:00
|
|
|
defmodule Ash do
|
2019-10-07 09:36:06 +13:00
|
|
|
alias Ash.Resource.Relationships.{BelongsTo, HasOne, HasMany, ManyToMany}
|
|
|
|
|
|
|
|
@type record :: struct
|
|
|
|
@type cardinality_one_relationship() :: HasOne.t() | BelongsTo.t()
|
|
|
|
@type cardinality_many_relationship() :: HasMany.t() | ManyToMany.t()
|
|
|
|
@type relationship :: cardinality_one_relationship() | cardinality_many_relationship()
|
2019-10-31 04:10:01 +13:00
|
|
|
@type query :: struct
|
2019-10-07 09:36:06 +13:00
|
|
|
@type resource :: module
|
|
|
|
@type error :: struct
|
2019-11-29 19:54:11 +13:00
|
|
|
@type filter :: map()
|
2019-11-30 05:36:01 +13:00
|
|
|
@type sort :: Keyword.t()
|
2019-11-28 10:36:25 +13:00
|
|
|
@type side_loads :: Keyword.t()
|
2019-10-07 09:36:06 +13:00
|
|
|
|
2019-10-03 20:18:07 +13:00
|
|
|
def resources() do
|
|
|
|
Application.get_env(:ash, :resources) || []
|
|
|
|
end
|
|
|
|
|
2019-11-03 09:36:46 +13:00
|
|
|
def primary_key(resource) do
|
|
|
|
resource.primary_key()
|
|
|
|
end
|
|
|
|
|
2019-11-30 05:36:01 +13:00
|
|
|
def relationship(resource, relationship_name) when is_bitstring(relationship_name) do
|
|
|
|
Enum.find(resource.relationships(), &(to_string(&1.name) == relationship_name))
|
|
|
|
end
|
|
|
|
|
2019-10-31 04:10:01 +13:00
|
|
|
def relationship(resource, relationship_name) do
|
2019-11-28 10:36:25 +13:00
|
|
|
# TODO: Make this happen at compile time
|
|
|
|
Enum.find(resource.relationships(), &(&1.name == relationship_name))
|
2019-10-31 04:10:01 +13:00
|
|
|
end
|
|
|
|
|
2019-10-04 15:33:55 +13:00
|
|
|
def relationships(resource) do
|
|
|
|
resource.relationships()
|
|
|
|
end
|
|
|
|
|
2019-11-25 13:01:21 +13:00
|
|
|
def primary_action(resource, type) do
|
|
|
|
resource
|
|
|
|
|> actions()
|
2019-11-28 10:36:25 +13:00
|
|
|
|> Enum.filter(&(&1.type == type))
|
|
|
|
|> case do
|
|
|
|
[action] -> action
|
|
|
|
actions -> Enum.find(actions, & &1.primary?)
|
|
|
|
end
|
2019-11-25 13:01:21 +13:00
|
|
|
end
|
|
|
|
|
2019-11-28 10:36:25 +13:00
|
|
|
def action(resource, name, type) do
|
|
|
|
Enum.find(resource.actions(), &(&1.name == name && &1.type == type))
|
2019-10-31 04:10:01 +13:00
|
|
|
end
|
|
|
|
|
2019-10-03 20:18:07 +13:00
|
|
|
def actions(resource) do
|
|
|
|
resource.actions()
|
|
|
|
end
|
|
|
|
|
2019-11-30 05:36:01 +13:00
|
|
|
def attribute(resource, name) when is_bitstring(name) do
|
|
|
|
Enum.find(resource.attributes, &(to_string(&1.name) == name))
|
|
|
|
end
|
|
|
|
|
2019-11-28 10:36:25 +13:00
|
|
|
def attribute(resource, name) do
|
|
|
|
Enum.find(resource.attributes, &(&1.name == name))
|
|
|
|
end
|
|
|
|
|
2019-10-03 20:18:07 +13:00
|
|
|
def attributes(resource) do
|
|
|
|
resource.attributes()
|
|
|
|
end
|
|
|
|
|
|
|
|
def name(resource) do
|
|
|
|
resource.name()
|
|
|
|
end
|
2019-10-03 20:40:37 +13:00
|
|
|
|
|
|
|
def type(resource) do
|
|
|
|
resource.type()
|
|
|
|
end
|
2019-10-07 09:36:06 +13:00
|
|
|
|
|
|
|
def data_layer(resource) do
|
|
|
|
resource.data_layer()
|
|
|
|
end
|
|
|
|
|
2019-11-27 06:38:47 +13:00
|
|
|
def get(resource, id, params \\ %{}) do
|
2019-11-25 13:01:21 +13:00
|
|
|
# TODO: Figure out this interface
|
|
|
|
params_with_filter =
|
|
|
|
params
|
|
|
|
|> Map.put_new(:filter, %{})
|
|
|
|
|> Map.update!(:filter, &Map.put(&1, :id, id))
|
2019-11-27 11:33:23 +13:00
|
|
|
|> Map.put(:page, %{limit: 2})
|
2019-11-25 13:01:21 +13:00
|
|
|
|
2019-11-27 11:33:23 +13:00
|
|
|
case read(resource, params_with_filter) do
|
2019-11-25 13:01:21 +13:00
|
|
|
{:ok, %{results: [single_result]}} ->
|
|
|
|
{:ok, single_result}
|
|
|
|
|
|
|
|
{:ok, %{results: []}} ->
|
|
|
|
{:ok, nil}
|
|
|
|
|
|
|
|
{:error, error} ->
|
|
|
|
{:error, error}
|
|
|
|
|
|
|
|
{:ok, %{results: results}} when is_list(results) ->
|
|
|
|
{:error, :too_many_results}
|
|
|
|
end
|
2019-10-31 04:10:01 +13:00
|
|
|
end
|
|
|
|
|
2019-11-26 19:50:53 +13:00
|
|
|
def read(resource, params \\ %{}) do
|
2019-11-28 18:24:29 +13:00
|
|
|
case Map.get(params, :action) || primary_action(resource, :read) do
|
|
|
|
nil ->
|
|
|
|
{:error, "no action provided, and no primary action found"}
|
|
|
|
|
|
|
|
action ->
|
|
|
|
Ash.DataLayer.Actions.run_read_action(resource, action, params)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def create(resource, params) do
|
|
|
|
case Map.get(params, :action) || primary_action(resource, :create) do
|
|
|
|
nil ->
|
|
|
|
{:error, "no action provided, and no primary action found"}
|
|
|
|
|
|
|
|
action ->
|
|
|
|
Ash.DataLayer.Actions.run_create_action(resource, action, params)
|
|
|
|
end
|
2019-11-27 11:33:23 +13:00
|
|
|
end
|
|
|
|
|
|
|
|
# # TODO: auth
|
|
|
|
# def create(resource, attributes, relationships, params \\ %{}) do
|
|
|
|
# action = Map.get(params, :action) || primary_action(resource, :create)
|
|
|
|
# Ash.DataLayer.Actions.run_create_action(resource, action, attributes, relationships, params)
|
|
|
|
# end
|
|
|
|
|
|
|
|
# # TODO: auth
|
|
|
|
# def update(%resource{} = record, attributes, relationships, params \\ %{}) do
|
|
|
|
# action = Map.get(params, :action) || primary_action(resource, :update)
|
|
|
|
# Ash.DataLayer.Actions.run_update_action(record, action, attributes, relationships, params)
|
|
|
|
# end
|
|
|
|
|
|
|
|
# # TODO: auth
|
|
|
|
# def destroy(%resource{} = record, params \\ %{}) do
|
|
|
|
# action = Map.get(params, :action) || primary_action(resource, :destroy)
|
|
|
|
# Ash.DataLayer.Actions.run_destroy_action(record, action, params)
|
|
|
|
# end
|
2019-11-03 09:36:46 +13:00
|
|
|
|
2019-10-31 04:10:01 +13:00
|
|
|
# TODO: Implement a to_resource protocol, like ecto's to query logic
|
2019-10-07 09:36:06 +13:00
|
|
|
def to_resource(%resource{}), do: resource
|
|
|
|
def to_resource(resource) when is_atom(resource), do: resource
|
|
|
|
|
|
|
|
## Datalayer shit TODO move this elsewhere
|
2019-10-03 16:08:36 +13:00
|
|
|
end
|