2019-10-03 16:08:36 +13:00
defmodule Ash do
2019-12-05 20:18:13 +13:00
@moduledoc """
2020-07-08 11:28:31 +12:00
Ash Framework
2019-12-05 20:18:13 +13:00
2020-06-14 18:39:11 +12:00
! [ Logo ] ( https :/ / github . com / ash - project / ash / blob / master / logos / cropped - for - header . png? raw = true )
2020-07-25 09:55:19 +12:00
## ALPHA NOTICE
Ash is in alpha . The package version is 1.0 . 0 + , and most of the time that means stable , but in this case it _does not_ . The 2.0 release will be the stable release .
2020-06-14 18:39:11 +12:00
## Quick Links
2020-08-09 05:55:36 +12:00
- [ Resource DSL Documentation ] ( Ash.Resource.Dsl . html )
2020-07-15 17:38:42 +12:00
- [ Api DSL Documentation ] ( Ash.Api.Dsl . html )
- [ Api interface documentation ] ( Ash.Api . html )
- [ Query Documentation ] ( Ash.Query . html )
- [ Changeset Documentation ] ( Ash.Changeset . html )
- [ Guides ] ( getting_started . html )
2020-06-14 18:39:11 +12:00
## Introduction
Traditional MVC Frameworks ( Rails , Django , . Net , Phoenix , etc ) leave it up to the user to build the glue between requests for data ( HTTP requests in various forms as well as server - side domain logic ) and their respective ORMs . In that space , there is an incredible amount of boilerplate code that must get written from scratch for each application ( authentication , authorization , sorting , filtering , sideloading relationships , serialization , etc ) .
Ash is an opinionated yet configurable framework designed to reduce boilerplate in an Elixir application . Ash does this by providing a layer of abstraction over your system ' s data layer(s) with `Resources`. It is designed to be used in conjunction with a phoenix application, or on its own.
To riff on a famous JRR Tolkien quote , a ` Resource ` is " One Interface to rule them all, One Interface to find them " and will become an indispensable place to define contracts for interacting with data throughout your application .
To start using Ash , first declare your ` Resources ` using the Ash ` Resource ` DSL . You could technically stop there , and just leverage the Ash Elixir API to avoid writing boilerplate . More likely , you would use extensions like Ash.JsonApi or Ash.GraphQL with Phoenix to add external interfaces to those resources without having to write any extra code at all .
Ash is an open - source project and draws inspiration from similar ideas in other frameworks and concepts . The goal of Ash is to lower the barrier to adopting and using Elixir and Phoenix , and in doing so help these amazing communities attract new developers , projects , and companies .
## Example Resource
` ` ` elixir
defmodule Post do
use Ash.Resource
actions do
read :default
create :default
end
attributes do
attribute :name , :string
end
relationships do
belongs_to :author , Author
end
end
` ` `
2020-07-08 12:30:49 +12:00
See the [ getting started guide ] ( getting_started . html ) for more information .
2020-06-14 18:42:44 +12:00
For those looking to add ash extensions :
* see ` Ash.Dsl.Extension ` for adding configuration .
* If you are looking to write a new data source , also see the ` Ash.DataLayer ` documentation .
* If you are looking to write a new authorizer , see ` Ash.Authorizer `
* If you are looking to write a " front end " , something powered by Ash resources , a guide on
2020-06-14 18:39:11 +12:00
building those kinds of tools is in the works .
2019-12-05 20:18:13 +13:00
"""
2020-06-02 17:47:25 +12:00
alias Ash.Resource.Actions . { Create , Destroy , Read , Update }
alias Ash.Resource.Relationships . { BelongsTo , HasMany , HasOne , ManyToMany }
2020-01-14 07:16:24 +13:00
2020-07-15 17:38:42 +12:00
@type action :: Create . t ( ) | Read . t ( ) | Update . t ( ) | Destroy . t ( )
@type action_type :: :read | :create | :update | :destroy
@type actor :: Ash . record ( )
2020-08-25 16:49:07 +12:00
@type aggregate :: Ash.Query.Aggregate . t ( ) | Ash.Resource.Aggregate . t ( )
2020-08-09 05:55:36 +12:00
@type aggregate_kind :: Ash.Query.Aggregate . kind ( )
2020-07-15 17:38:42 +12:00
@type api :: module
@type attribute :: Ash.Resource.Attribute . t ( )
2020-08-25 16:49:07 +12:00
@type calculation :: Ash.Resource.Calculation . t ( )
2019-10-07 09:36:06 +13:00
@type cardinality_many_relationship ( ) :: HasMany . t ( ) | ManyToMany . t ( )
2020-07-15 17:38:42 +12:00
@type cardinality_one_relationship ( ) :: HasOne . t ( ) | BelongsTo . t ( )
@type changeset :: Ash.Changeset . t ( )
2019-12-05 20:18:13 +13:00
@type data_layer :: module
2020-05-14 03:54:44 +12:00
@type data_layer_query :: struct
2019-10-07 09:36:06 +13:00
@type error :: struct
2020-08-09 05:55:36 +12:00
@type filter :: Ash.Filter . t ( )
2019-12-23 17:28:40 +13:00
@type params :: Keyword . t ( )
2020-07-17 11:17:01 +12:00
@type primary_key :: record ( ) | map | term
2020-05-14 03:54:44 +12:00
@type query :: Ash.Query . t ( )
2020-07-15 17:38:42 +12:00
@type record :: struct
@type relationship :: cardinality_one_relationship ( ) | cardinality_many_relationship ( )
@type relationship_cardinality :: :many | :one
@type resource :: module
2020-08-14 09:49:33 +12:00
@type side_loads :: term
2020-07-15 17:38:42 +12:00
@type sort :: Keyword . t ( )
@type validation :: Ash.Resource.Validation . t ( )
2020-05-21 10:59:58 +12:00
2020-06-14 18:39:11 +12:00
require Ash.Dsl.Extension
2019-10-04 15:33:55 +13:00
2020-06-15 18:40:33 +12:00
def implements_behaviour? ( module , behaviour ) do
2020-06-05 14:43:51 +12:00
:attributes
|> module . module_info ( )
2020-06-15 18:40:33 +12:00
|> Enum . flat_map ( fn
{ :behaviour , value } -> List . wrap ( value )
_ -> [ ]
end )
|> Enum . any? ( & ( &1 == behaviour ) )
end
2020-09-04 16:59:32 +12:00
def uuid do
Ecto.UUID . generate ( )
end
2020-07-15 17:38:42 +12:00
@doc " Returns all extensions of a resource or api "
@spec extensions ( resource ( ) | api ( ) ) :: [ module ]
2020-06-14 18:39:11 +12:00
def extensions ( resource ) do
:persistent_term . get ( { resource , :extensions } , [ ] )
2019-10-03 20:18:07 +13:00
end
2019-10-03 16:08:36 +13:00
end