mirror of
https://github.com/ash-project/ash_sqlite.git
synced 2024-09-20 13:23:25 +12:00
236 lines
5.8 KiB
Elixir
236 lines
5.8 KiB
Elixir
defmodule AshSqlite.Test.Post do
|
|
@moduledoc false
|
|
use Ash.Resource,
|
|
data_layer: AshSqlite.DataLayer,
|
|
authorizers: [
|
|
Ash.Policy.Authorizer
|
|
]
|
|
|
|
policies do
|
|
bypass action_type(:read) do
|
|
# Check that the post is in the same org as actor
|
|
authorize_if(relates_to_actor_via([:organization, :users]))
|
|
end
|
|
end
|
|
|
|
sqlite do
|
|
table("posts")
|
|
repo(AshSqlite.TestRepo)
|
|
base_filter_sql("type = 'sponsored'")
|
|
|
|
check_constraints do
|
|
check_constraint(:price, "price_must_be_positive",
|
|
message: "yo, bad price",
|
|
check: "price > 0"
|
|
)
|
|
end
|
|
|
|
custom_indexes do
|
|
index([:uniq_custom_one, :uniq_custom_two],
|
|
unique: true,
|
|
concurrently: true,
|
|
message: "dude what the heck"
|
|
)
|
|
end
|
|
end
|
|
|
|
resource do
|
|
base_filter(expr(type == type(:sponsored, ^Ash.Type.Atom)))
|
|
end
|
|
|
|
actions do
|
|
defaults([:update, :destroy])
|
|
|
|
read :read do
|
|
primary?(true)
|
|
end
|
|
|
|
read :paginated do
|
|
pagination(offset?: true, required?: true, countable: true)
|
|
end
|
|
|
|
create :create do
|
|
primary?(true)
|
|
argument(:rating, :map)
|
|
|
|
change(
|
|
manage_relationship(:rating, :ratings,
|
|
on_missing: :ignore,
|
|
on_no_match: :create,
|
|
on_match: :create
|
|
)
|
|
)
|
|
end
|
|
|
|
update :increment_score do
|
|
argument(:amount, :integer, default: 1)
|
|
change(atomic_update(:score, expr((score || 0) + ^arg(:amount))))
|
|
end
|
|
end
|
|
|
|
identities do
|
|
identity(:uniq_one_and_two, [:uniq_one, :uniq_two])
|
|
end
|
|
|
|
attributes do
|
|
uuid_primary_key(:id, writable?: true)
|
|
attribute(:title, :string)
|
|
attribute(:score, :integer)
|
|
attribute(:public, :boolean)
|
|
attribute(:category, :string)
|
|
attribute(:type, :atom, default: :sponsored, private?: true, writable?: false)
|
|
attribute(:price, :integer)
|
|
attribute(:decimal, :decimal, default: Decimal.new(0))
|
|
attribute(:status, AshSqlite.Test.Types.Status)
|
|
attribute(:status_enum, AshSqlite.Test.Types.StatusEnum)
|
|
attribute(:status_enum_no_cast, AshSqlite.Test.Types.StatusEnumNoCast, source: :status_enum)
|
|
attribute(:point, AshSqlite.Test.Point)
|
|
attribute(:stuff, :map)
|
|
attribute(:uniq_one, :string)
|
|
attribute(:uniq_two, :string)
|
|
attribute(:uniq_custom_one, :string)
|
|
attribute(:uniq_custom_two, :string)
|
|
create_timestamp(:created_at)
|
|
update_timestamp(:updated_at)
|
|
end
|
|
|
|
code_interface do
|
|
define_for(AshSqlite.Test.Api)
|
|
define(:get_by_id, action: :read, get_by: [:id])
|
|
define(:increment_score, args: [{:optional, :amount}])
|
|
end
|
|
|
|
relationships do
|
|
belongs_to :organization, AshSqlite.Test.Organization do
|
|
attribute_writable?(true)
|
|
end
|
|
|
|
belongs_to(:author, AshSqlite.Test.Author)
|
|
|
|
has_many :posts_with_matching_title, __MODULE__ do
|
|
no_attributes?(true)
|
|
filter(expr(parent(title) == title and parent(id) != id))
|
|
end
|
|
|
|
has_many(:comments, AshSqlite.Test.Comment, destination_attribute: :post_id)
|
|
|
|
has_many :comments_matching_post_title, AshSqlite.Test.Comment do
|
|
filter(expr(title == parent_expr(title)))
|
|
end
|
|
|
|
has_many :popular_comments, AshSqlite.Test.Comment do
|
|
destination_attribute(:post_id)
|
|
filter(expr(likes > 10))
|
|
end
|
|
|
|
has_many :comments_containing_title, AshSqlite.Test.Comment do
|
|
manual(AshSqlite.Test.Post.CommentsContainingTitle)
|
|
end
|
|
|
|
has_many(:ratings, AshSqlite.Test.Rating,
|
|
destination_attribute: :resource_id,
|
|
relationship_context: %{data_layer: %{table: "post_ratings"}}
|
|
)
|
|
|
|
has_many(:post_links, AshSqlite.Test.PostLink,
|
|
destination_attribute: :source_post_id,
|
|
filter: [state: :active]
|
|
)
|
|
|
|
many_to_many(:linked_posts, __MODULE__,
|
|
through: AshSqlite.Test.PostLink,
|
|
join_relationship: :post_links,
|
|
source_attribute_on_join_resource: :source_post_id,
|
|
destination_attribute_on_join_resource: :destination_post_id
|
|
)
|
|
|
|
has_many(:views, AshSqlite.Test.PostView)
|
|
end
|
|
|
|
validations do
|
|
validate(attribute_does_not_equal(:title, "not allowed"))
|
|
end
|
|
|
|
calculations do
|
|
calculate(:score_after_winning, :integer, expr((score || 0) + 1))
|
|
calculate(:negative_score, :integer, expr(-score))
|
|
calculate(:category_label, :string, expr("(" <> category <> ")"))
|
|
calculate(:score_with_score, :string, expr(score <> score))
|
|
calculate(:foo_bar_from_stuff, :string, expr(stuff[:foo][:bar]))
|
|
|
|
calculate(
|
|
:score_map,
|
|
:map,
|
|
expr(%{
|
|
negative_score: %{foo: negative_score, bar: negative_score}
|
|
})
|
|
)
|
|
|
|
calculate(
|
|
:calc_returning_json,
|
|
AshSqlite.Test.Money,
|
|
expr(
|
|
fragment("""
|
|
'{"amount":100, "currency": "usd"}'::json
|
|
""")
|
|
)
|
|
)
|
|
|
|
calculate(
|
|
:was_created_in_the_last_month,
|
|
:boolean,
|
|
expr(
|
|
# This is written in a silly way on purpose, to test a regression
|
|
if(
|
|
fragment("(? <= (? - '1 month'::interval))", now(), created_at),
|
|
true,
|
|
false
|
|
)
|
|
)
|
|
)
|
|
|
|
calculate(
|
|
:price_string,
|
|
:string,
|
|
CalculatePostPriceString
|
|
)
|
|
|
|
calculate(
|
|
:price_string_with_currency_sign,
|
|
:string,
|
|
CalculatePostPriceStringWithSymbol
|
|
)
|
|
end
|
|
end
|
|
|
|
defmodule CalculatePostPriceString do
|
|
@moduledoc false
|
|
use Ash.Calculation
|
|
|
|
@impl true
|
|
def select(_, _, _), do: [:price]
|
|
|
|
@impl true
|
|
def calculate(records, _, _) do
|
|
Enum.map(records, fn %{price: price} ->
|
|
dollars = div(price, 100)
|
|
cents = rem(price, 100)
|
|
"#{dollars}.#{cents}"
|
|
end)
|
|
end
|
|
end
|
|
|
|
defmodule CalculatePostPriceStringWithSymbol do
|
|
@moduledoc false
|
|
use Ash.Calculation
|
|
|
|
@impl true
|
|
def load(_, _, _), do: [:price_string]
|
|
|
|
@impl true
|
|
def calculate(records, _, _) do
|
|
Enum.map(records, fn %{price_string: price_string} ->
|
|
"#{price_string}$"
|
|
end)
|
|
end
|
|
end
|