2024-02-11 12:30:48 +13:00
|
|
|
defmodule PassIfOriginalDataPresent do
|
2024-02-13 04:24:59 +13:00
|
|
|
@moduledoc false
|
2024-02-11 12:30:48 +13:00
|
|
|
use Ash.Policy.SimpleCheck
|
|
|
|
|
|
|
|
def describe(_options), do: "original data present"
|
|
|
|
|
|
|
|
def match?(_, _, _) do
|
|
|
|
true
|
|
|
|
end
|
|
|
|
|
|
|
|
def requires_original_data?(_, _) do
|
|
|
|
true
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2020-09-11 12:26:47 +12:00
|
|
|
defmodule AshPostgres.Test.Post do
|
|
|
|
@moduledoc false
|
|
|
|
use Ash.Resource,
|
2024-03-28 09:52:28 +13:00
|
|
|
domain: AshPostgres.Test.Domain,
|
2023-01-29 19:05:34 +13:00
|
|
|
data_layer: AshPostgres.DataLayer,
|
|
|
|
authorizers: [
|
|
|
|
Ash.Policy.Authorizer
|
|
|
|
]
|
|
|
|
|
2024-05-21 02:06:49 +12:00
|
|
|
require Ash.Sort
|
|
|
|
|
2023-01-29 19:05:34 +13:00
|
|
|
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
|
2024-01-11 01:22:25 +13:00
|
|
|
|
|
|
|
policy action(:allow_any) do
|
|
|
|
authorize_if(always())
|
|
|
|
end
|
2024-02-11 12:30:48 +13:00
|
|
|
|
|
|
|
policy action(:requires_initial_data) do
|
|
|
|
authorize_if(PassIfOriginalDataPresent)
|
|
|
|
end
|
2024-02-15 07:56:58 +13:00
|
|
|
|
|
|
|
policy action_type(:update) do
|
2024-04-27 15:51:29 +12:00
|
|
|
authorize_if(action(:requires_initial_data))
|
2024-02-16 04:54:20 +13:00
|
|
|
authorize_if(relates_to_actor_via([:author, :authors_with_same_first_name]))
|
2024-02-15 07:56:58 +13:00
|
|
|
authorize_unless(changing_attributes(title: [from: "good", to: "bad"]))
|
|
|
|
end
|
2024-05-17 01:39:47 +12:00
|
|
|
|
|
|
|
policy action(:create) do
|
|
|
|
authorize_unless(changing_attributes(title: [to: "worst"]))
|
|
|
|
end
|
2023-01-29 19:05:34 +13:00
|
|
|
end
|
2020-09-11 12:26:47 +12:00
|
|
|
|
2024-02-15 04:25:25 +13:00
|
|
|
field_policies do
|
|
|
|
field_policy :* do
|
|
|
|
authorize_if(always())
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2020-09-11 12:26:47 +12:00
|
|
|
postgres do
|
2021-04-27 05:21:57 +12:00
|
|
|
table("posts")
|
|
|
|
repo(AshPostgres.TestRepo)
|
|
|
|
base_filter_sql("type = 'sponsored'")
|
2021-04-20 06:26:41 +12:00
|
|
|
|
|
|
|
check_constraints do
|
|
|
|
check_constraint(:price, "price_must_be_positive",
|
|
|
|
message: "yo, bad price",
|
|
|
|
check: "price > 0"
|
|
|
|
)
|
|
|
|
end
|
2022-11-26 08:06:22 +13:00
|
|
|
|
|
|
|
custom_indexes do
|
2023-02-10 10:09:44 +13:00
|
|
|
index([:uniq_custom_one, :uniq_custom_two],
|
2022-11-26 08:06:22 +13:00
|
|
|
unique: true,
|
|
|
|
concurrently: true,
|
|
|
|
message: "dude what the heck"
|
2023-02-10 10:09:44 +13:00
|
|
|
)
|
2022-11-26 08:06:22 +13:00
|
|
|
end
|
2020-09-11 12:26:47 +12:00
|
|
|
end
|
|
|
|
|
2021-02-25 07:59:49 +13:00
|
|
|
resource do
|
|
|
|
base_filter(expr(type == type(:sponsored, ^Ash.Type.Atom)))
|
|
|
|
end
|
|
|
|
|
2020-09-11 12:26:47 +12:00
|
|
|
actions do
|
2024-03-28 09:52:28 +13:00
|
|
|
default_accept(:*)
|
|
|
|
|
2024-05-04 13:25:54 +12:00
|
|
|
defaults([:read, :destroy])
|
2024-03-28 09:52:28 +13:00
|
|
|
|
2024-05-13 08:28:48 +12:00
|
|
|
destroy :destroy_only_freds do
|
|
|
|
change(filter(expr(title == "fred")))
|
|
|
|
end
|
|
|
|
|
|
|
|
update :update_only_freds do
|
|
|
|
change(filter(expr(title == "fred")))
|
|
|
|
end
|
|
|
|
|
2024-04-22 01:35:47 +12:00
|
|
|
destroy :destroy_with_confirm do
|
2024-04-22 03:11:00 +12:00
|
|
|
require_atomic?(false)
|
2024-04-22 01:35:47 +12:00
|
|
|
argument(:confirm, :string, allow_nil?: false)
|
|
|
|
|
|
|
|
change(fn changeset, _ ->
|
|
|
|
Ash.Changeset.before_action(changeset, fn changeset ->
|
|
|
|
if changeset.arguments.confirm == "CONFIRM" do
|
|
|
|
changeset
|
|
|
|
else
|
|
|
|
Ash.Changeset.add_error(changeset, field: :confirm, message: "must type CONFIRM")
|
|
|
|
end
|
|
|
|
end)
|
|
|
|
end)
|
|
|
|
end
|
|
|
|
|
|
|
|
destroy :soft_destroy_with_confirm do
|
2024-04-22 03:11:00 +12:00
|
|
|
require_atomic?(false)
|
2024-04-22 01:35:47 +12:00
|
|
|
argument(:confirm, :string, allow_nil?: false)
|
|
|
|
|
|
|
|
change(fn changeset, _ ->
|
|
|
|
Ash.Changeset.before_action(changeset, fn changeset ->
|
|
|
|
if changeset.arguments.confirm == "CONFIRM" do
|
|
|
|
changeset
|
|
|
|
else
|
|
|
|
Ash.Changeset.add_error(changeset, field: :confirm, message: "must type CONFIRM")
|
|
|
|
end
|
|
|
|
end)
|
|
|
|
end)
|
|
|
|
end
|
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
update :update do
|
|
|
|
primary?(true)
|
|
|
|
require_atomic?(false)
|
|
|
|
end
|
2022-04-20 03:08:28 +12:00
|
|
|
|
2024-04-23 10:58:57 +12:00
|
|
|
update :change_title_to_foo_unless_its_already_foo do
|
2024-04-23 12:42:11 +12:00
|
|
|
validate(attribute_does_not_equal(:title, "foo"))
|
|
|
|
change(set_attribute(:title, "foo"))
|
2024-04-23 10:58:57 +12:00
|
|
|
end
|
|
|
|
|
2024-02-25 12:08:00 +13:00
|
|
|
read :title_is_foo do
|
|
|
|
filter(expr(title == "foo"))
|
|
|
|
end
|
|
|
|
|
2024-05-17 10:28:43 +12:00
|
|
|
read :keyset do
|
|
|
|
pagination do
|
|
|
|
keyset?(true)
|
|
|
|
countable(true)
|
|
|
|
required?(false)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-01-11 01:22:25 +13:00
|
|
|
read(:allow_any)
|
|
|
|
|
2021-05-07 09:37:00 +12:00
|
|
|
read :paginated do
|
|
|
|
pagination(offset?: true, required?: true, countable: true)
|
|
|
|
end
|
2021-02-06 12:59:33 +13:00
|
|
|
|
|
|
|
create :create do
|
2022-05-09 00:08:06 +12:00
|
|
|
primary?(true)
|
2021-02-06 12:59:33 +13:00
|
|
|
argument(:rating, :map)
|
|
|
|
|
2021-02-25 07:59:49 +13:00
|
|
|
change(
|
|
|
|
manage_relationship(:rating, :ratings,
|
|
|
|
on_missing: :ignore,
|
|
|
|
on_no_match: :create,
|
|
|
|
on_match: :create
|
|
|
|
)
|
|
|
|
)
|
2021-02-06 12:59:33 +13:00
|
|
|
end
|
2023-08-29 08:18:56 +12:00
|
|
|
|
2024-05-16 01:50:36 +12:00
|
|
|
update :set_title_from_author do
|
|
|
|
change(atomic_update(:title, expr(author.first_name)))
|
|
|
|
end
|
|
|
|
|
2023-08-29 08:18:56 +12:00
|
|
|
update :increment_score do
|
|
|
|
argument(:amount, :integer, default: 1)
|
2023-09-01 03:47:15 +12:00
|
|
|
change(atomic_update(:score, expr((score || 0) + ^arg(:amount))))
|
2023-08-29 08:18:56 +12:00
|
|
|
end
|
2024-01-31 03:26:39 +13:00
|
|
|
|
2024-02-11 12:30:48 +13:00
|
|
|
update :requires_initial_data do
|
|
|
|
argument(:amount, :integer, default: 1)
|
|
|
|
change(atomic_update(:score, expr((score || 0) + ^arg(:amount))))
|
|
|
|
end
|
|
|
|
|
2024-01-31 03:26:39 +13:00
|
|
|
update :manual_update do
|
2024-03-28 09:52:28 +13:00
|
|
|
require_atomic?(false)
|
2024-01-31 03:26:39 +13:00
|
|
|
manual(AshPostgres.Test.Post.ManualUpdate)
|
|
|
|
end
|
2020-09-11 12:26:47 +12:00
|
|
|
end
|
|
|
|
|
2022-07-02 11:12:14 +12:00
|
|
|
identities do
|
2022-07-02 11:18:42 +12:00
|
|
|
identity(:uniq_one_and_two, [:uniq_one, :uniq_two])
|
2022-07-02 11:12:14 +12:00
|
|
|
end
|
|
|
|
|
2020-09-11 12:26:47 +12:00
|
|
|
attributes do
|
2021-01-27 09:07:26 +13:00
|
|
|
uuid_primary_key(:id, writable?: true)
|
2023-12-20 03:05:05 +13:00
|
|
|
|
|
|
|
attribute(:title, :string) do
|
2024-03-28 09:52:28 +13:00
|
|
|
public?(true)
|
2023-12-20 03:05:05 +13:00
|
|
|
source(:title_column)
|
|
|
|
end
|
|
|
|
|
2024-05-05 22:08:21 +12:00
|
|
|
attribute(:datetime, AshPostgres.TimestamptzUsec, public?: true)
|
2024-03-28 09:52:28 +13:00
|
|
|
attribute(:score, :integer, public?: true)
|
|
|
|
attribute(:public, :boolean, public?: true)
|
|
|
|
attribute(:category, :ci_string, public?: true)
|
|
|
|
attribute(:type, :atom, default: :sponsored, writable?: false, public?: false)
|
|
|
|
attribute(:price, :integer, public?: true)
|
|
|
|
attribute(:decimal, :decimal, default: Decimal.new(0), public?: true)
|
|
|
|
attribute(:status, AshPostgres.Test.Types.Status, public?: true)
|
|
|
|
attribute(:status_enum, AshPostgres.Test.Types.StatusEnum, public?: true)
|
|
|
|
|
|
|
|
attribute(:status_enum_no_cast, AshPostgres.Test.Types.StatusEnumNoCast,
|
|
|
|
source: :status_enum,
|
|
|
|
public?: true
|
|
|
|
)
|
|
|
|
|
|
|
|
attribute(:point, AshPostgres.Test.Point, public?: true)
|
|
|
|
attribute(:composite_point, AshPostgres.Test.CompositePoint, public?: true)
|
|
|
|
attribute(:stuff, :map, public?: true)
|
|
|
|
attribute(:list_of_stuff, {:array, :map}, public?: true)
|
|
|
|
attribute(:uniq_one, :string, public?: true)
|
|
|
|
attribute(:uniq_two, :string, public?: true)
|
|
|
|
attribute(:uniq_custom_one, :string, public?: true)
|
|
|
|
attribute(:uniq_custom_two, :string, public?: true)
|
2024-01-30 11:17:32 +13:00
|
|
|
|
|
|
|
attribute :list_containing_nils, {:array, :string} do
|
2024-03-28 09:52:28 +13:00
|
|
|
public?(true)
|
2024-01-30 11:17:32 +13:00
|
|
|
constraints(nil_items?: true)
|
|
|
|
end
|
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
create_timestamp(:created_at, writable?: true, public?: true)
|
2024-05-05 22:08:21 +12:00
|
|
|
|
|
|
|
update_timestamp(:updated_at,
|
|
|
|
type: AshPostgres.TimestamptzUsec,
|
|
|
|
writable?: true,
|
|
|
|
public?: true
|
|
|
|
)
|
2020-09-11 12:26:47 +12:00
|
|
|
end
|
|
|
|
|
2022-11-01 04:53:03 +13:00
|
|
|
code_interface do
|
2024-03-28 09:52:28 +13:00
|
|
|
define(:create, args: [:title])
|
2022-11-01 04:53:03 +13:00
|
|
|
define(:get_by_id, action: :read, get_by: [:id])
|
2023-08-29 08:18:56 +12:00
|
|
|
define(:increment_score, args: [{:optional, :amount}])
|
2024-03-28 09:52:28 +13:00
|
|
|
define(:destroy)
|
2022-11-01 04:53:03 +13:00
|
|
|
end
|
|
|
|
|
2020-09-11 12:26:47 +12:00
|
|
|
relationships do
|
2023-05-23 13:17:30 +12:00
|
|
|
belongs_to :organization, AshPostgres.Test.Organization do
|
2024-03-28 09:52:28 +13:00
|
|
|
public?(true)
|
2023-05-23 13:17:30 +12:00
|
|
|
attribute_writable?(true)
|
|
|
|
end
|
2023-01-29 19:05:34 +13:00
|
|
|
|
2024-05-02 00:27:14 +12:00
|
|
|
belongs_to(:current_user_author, AshPostgres.Test.Author) do
|
|
|
|
source_attribute(:author_id)
|
|
|
|
define_attribute?(false)
|
|
|
|
filter(expr(^actor(:id) == id))
|
|
|
|
end
|
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
belongs_to(:author, AshPostgres.Test.Author) do
|
|
|
|
public?(true)
|
|
|
|
end
|
2022-06-30 07:08:49 +12:00
|
|
|
|
2023-07-27 09:32:09 +12:00
|
|
|
has_many :posts_with_matching_title, __MODULE__ do
|
2024-03-28 09:52:28 +13:00
|
|
|
public?(true)
|
2023-07-27 09:32:09 +12:00
|
|
|
no_attributes?(true)
|
|
|
|
filter(expr(parent(title) == title and parent(id) != id))
|
|
|
|
end
|
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
has_many(:comments, AshPostgres.Test.Comment, destination_attribute: :post_id, public?: true)
|
2021-01-29 13:42:55 +13:00
|
|
|
|
2023-07-19 06:48:35 +12:00
|
|
|
has_many :comments_matching_post_title, AshPostgres.Test.Comment do
|
2024-03-28 09:52:28 +13:00
|
|
|
public?(true)
|
2023-07-19 06:48:35 +12:00
|
|
|
filter(expr(title == parent_expr(title)))
|
|
|
|
end
|
|
|
|
|
2022-02-10 05:49:19 +13:00
|
|
|
has_many :popular_comments, AshPostgres.Test.Comment do
|
2024-03-28 09:52:28 +13:00
|
|
|
public?(true)
|
2022-08-19 06:56:36 +12:00
|
|
|
destination_attribute(:post_id)
|
2022-09-14 08:27:39 +12:00
|
|
|
filter(expr(likes > 10))
|
|
|
|
end
|
|
|
|
|
|
|
|
has_many :comments_containing_title, AshPostgres.Test.Comment do
|
2024-03-28 09:52:28 +13:00
|
|
|
public?(true)
|
2022-09-14 08:27:39 +12:00
|
|
|
manual(AshPostgres.Test.Post.CommentsContainingTitle)
|
2022-02-10 05:49:19 +13:00
|
|
|
end
|
|
|
|
|
2023-10-25 05:25:23 +13:00
|
|
|
has_many :comments_with_high_rating, AshPostgres.Test.Comment do
|
2024-03-28 09:52:28 +13:00
|
|
|
public?(true)
|
2023-10-25 05:25:23 +13:00
|
|
|
filter(expr(ratings.score > 5))
|
|
|
|
end
|
|
|
|
|
2021-01-29 13:42:55 +13:00
|
|
|
has_many(:ratings, AshPostgres.Test.Rating,
|
2024-03-28 09:52:28 +13:00
|
|
|
public?: true,
|
2022-08-19 06:56:36 +12:00
|
|
|
destination_attribute: :resource_id,
|
2021-05-14 17:20:10 +12:00
|
|
|
relationship_context: %{data_layer: %{table: "post_ratings"}}
|
2021-01-29 13:42:55 +13:00
|
|
|
)
|
2021-04-30 09:31:19 +12:00
|
|
|
|
2022-12-05 07:39:58 +13:00
|
|
|
has_many(:post_links, AshPostgres.Test.PostLink,
|
2024-03-28 09:52:28 +13:00
|
|
|
public?: true,
|
2022-12-05 07:39:58 +13:00
|
|
|
destination_attribute: :source_post_id,
|
|
|
|
filter: [state: :active]
|
|
|
|
)
|
|
|
|
|
2021-04-30 09:31:19 +12:00
|
|
|
many_to_many(:linked_posts, __MODULE__,
|
2024-03-28 09:52:28 +13:00
|
|
|
public?: true,
|
2021-04-30 09:31:19 +12:00
|
|
|
through: AshPostgres.Test.PostLink,
|
2022-12-05 07:39:58 +13:00
|
|
|
join_relationship: :post_links,
|
2022-08-19 06:56:36 +12:00
|
|
|
source_attribute_on_join_resource: :source_post_id,
|
|
|
|
destination_attribute_on_join_resource: :destination_post_id
|
2021-04-30 09:31:19 +12:00
|
|
|
)
|
2023-09-06 17:18:57 +12:00
|
|
|
|
2024-02-29 15:23:15 +13:00
|
|
|
many_to_many(:followers, AshPostgres.Test.User,
|
2024-03-28 09:52:28 +13:00
|
|
|
public?: true,
|
2024-02-29 15:23:15 +13:00
|
|
|
through: AshPostgres.Test.PostFollower,
|
|
|
|
source_attribute_on_join_resource: :post_id,
|
|
|
|
destination_attribute_on_join_resource: :follower_id,
|
|
|
|
read_action: :active
|
|
|
|
)
|
|
|
|
|
2024-05-21 02:06:49 +12:00
|
|
|
has_many(:post_followers, AshPostgres.Test.PostFollower)
|
|
|
|
|
|
|
|
many_to_many(:sorted_followers, AshPostgres.Test.User,
|
|
|
|
public?: true,
|
|
|
|
through: AshPostgres.Test.PostFollower,
|
|
|
|
join_relationship: :post_followers,
|
|
|
|
source_attribute_on_join_resource: :post_id,
|
|
|
|
destination_attribute_on_join_resource: :follower_id,
|
|
|
|
sort: [Ash.Sort.expr_sort(parent(post_followers.order))]
|
|
|
|
)
|
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
has_many(:views, AshPostgres.Test.PostView) do
|
|
|
|
public?(true)
|
|
|
|
end
|
2020-09-11 12:26:47 +12:00
|
|
|
end
|
2020-12-29 13:26:04 +13:00
|
|
|
|
2023-05-23 13:17:30 +12:00
|
|
|
validations do
|
|
|
|
validate(attribute_does_not_equal(:title, "not allowed"))
|
|
|
|
end
|
|
|
|
|
2021-06-04 17:48:35 +12:00
|
|
|
calculations do
|
2024-02-29 15:23:15 +13:00
|
|
|
calculate(
|
|
|
|
:author_has_post_with_follower_named_fred,
|
|
|
|
:boolean,
|
|
|
|
expr(
|
|
|
|
exists(
|
|
|
|
author.posts,
|
|
|
|
has_follower_named_fred
|
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
2024-05-04 04:31:42 +12:00
|
|
|
calculate(:has_author, :boolean, expr(exists(author, true == true)))
|
|
|
|
|
|
|
|
calculate(:has_comments, :boolean, expr(exists(comments, true == true)))
|
|
|
|
|
2024-02-29 15:23:15 +13:00
|
|
|
calculate(
|
|
|
|
:has_no_followers,
|
|
|
|
:boolean,
|
|
|
|
expr(is_nil(author.posts.followers))
|
|
|
|
)
|
|
|
|
|
2023-08-29 08:18:56 +12:00
|
|
|
calculate(:score_after_winning, :integer, expr((score || 0) + 1))
|
2023-07-18 14:35:46 +12:00
|
|
|
calculate(:negative_score, :integer, expr(-score))
|
2022-08-06 07:27:22 +12:00
|
|
|
calculate(:category_label, :ci_string, expr("(" <> category <> ")"))
|
2023-02-13 13:09:25 +13:00
|
|
|
calculate(:score_with_score, :string, expr(score <> score))
|
2023-08-24 04:54:25 +12:00
|
|
|
calculate(:foo_bar_from_stuff, :string, expr(stuff[:foo][:bar]))
|
2022-08-06 07:27:22 +12:00
|
|
|
|
2024-02-29 15:23:15 +13:00
|
|
|
calculate(
|
|
|
|
:has_follower_named_fred,
|
|
|
|
:boolean,
|
|
|
|
expr(exists(followers, name == "fred"))
|
|
|
|
)
|
|
|
|
|
2023-11-30 03:57:10 +13:00
|
|
|
calculate(
|
|
|
|
:composite_origin,
|
|
|
|
AshPostgres.Test.CompositePoint,
|
2023-11-30 04:27:10 +13:00
|
|
|
expr(composite_type(%{x: 0, y: 0}, AshPostgres.Test.CompositePoint))
|
2023-11-30 03:57:10 +13:00
|
|
|
)
|
|
|
|
|
2023-08-23 06:51:31 +12:00
|
|
|
calculate(
|
|
|
|
:score_map,
|
|
|
|
:map,
|
|
|
|
expr(%{
|
|
|
|
negative_score: %{foo: negative_score, bar: negative_score}
|
|
|
|
})
|
|
|
|
)
|
|
|
|
|
2023-09-05 03:25:03 +12:00
|
|
|
calculate(
|
|
|
|
:count_of_comments_called_baz,
|
|
|
|
:integer,
|
|
|
|
expr(count(comments, query: [filter: expr(title == "baz")]))
|
|
|
|
)
|
|
|
|
|
2023-08-23 06:51:31 +12:00
|
|
|
calculate(
|
|
|
|
:agg_map,
|
|
|
|
:map,
|
|
|
|
expr(%{
|
|
|
|
called_foo: count(comments, query: [filter: expr(title == "foo")]),
|
2023-09-05 03:25:03 +12:00
|
|
|
called_bar: count(comments, query: [filter: expr(title == "bar")]),
|
|
|
|
called_baz: count_of_comments_called_baz
|
2023-08-23 06:51:31 +12:00
|
|
|
})
|
|
|
|
)
|
|
|
|
|
2021-06-04 17:48:35 +12:00
|
|
|
calculate(:c_times_p, :integer, expr(count_of_comments * count_of_linked_posts),
|
|
|
|
load: [:count_of_comments, :count_of_linked_posts]
|
|
|
|
)
|
2021-11-14 07:56:14 +13:00
|
|
|
|
2023-09-21 08:41:32 +12:00
|
|
|
calculate :similarity,
|
|
|
|
:boolean,
|
|
|
|
expr(fragment("(to_tsvector(?) @@ ?)", title, ^arg(:search))) do
|
|
|
|
argument(:search, AshPostgres.Tsquery, allow_expr?: true, allow_nil?: false)
|
|
|
|
end
|
|
|
|
|
|
|
|
calculate :query, AshPostgres.Tsquery, expr(fragment("to_tsquery(?)", ^arg(:search))) do
|
|
|
|
argument(:search, :string, allow_expr?: true, allow_nil?: false)
|
|
|
|
end
|
|
|
|
|
2022-09-22 05:36:18 +12:00
|
|
|
calculate(
|
|
|
|
:calc_returning_json,
|
|
|
|
AshPostgres.Test.Money,
|
|
|
|
expr(
|
|
|
|
fragment("""
|
|
|
|
'{"amount":100, "currency": "usd"}'::json
|
|
|
|
""")
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
2021-11-14 07:55:49 +13:00
|
|
|
calculate(
|
|
|
|
:has_future_arbitrary_timestamp,
|
|
|
|
:boolean,
|
|
|
|
expr(latest_arbitrary_timestamp > fragment("now()"))
|
|
|
|
)
|
|
|
|
|
2024-01-11 01:22:25 +13:00
|
|
|
calculate(
|
|
|
|
:has_future_comment,
|
|
|
|
:boolean,
|
|
|
|
expr(latest_comment_created_at > fragment("now()") || type(false, :boolean))
|
|
|
|
)
|
2022-05-21 05:22:32 +12:00
|
|
|
|
2024-01-19 18:12:50 +13:00
|
|
|
calculate(:price_times_2, :integer, expr(price * 2))
|
|
|
|
|
2022-05-21 05:22:32 +12:00
|
|
|
calculate(
|
|
|
|
:was_created_in_the_last_month,
|
|
|
|
:boolean,
|
|
|
|
expr(
|
|
|
|
# This is written in a silly way on purpose, to test a regression
|
2022-05-21 05:42:20 +12:00
|
|
|
if(
|
2022-10-20 18:08:35 +13:00
|
|
|
fragment("(? <= (? - '1 month'::interval))", now(), created_at),
|
2022-05-21 05:42:20 +12:00
|
|
|
true,
|
2022-05-21 05:22:32 +12:00
|
|
|
false
|
2022-05-21 05:42:20 +12:00
|
|
|
)
|
2022-05-21 05:22:32 +12:00
|
|
|
)
|
|
|
|
)
|
2023-04-01 05:12:13 +13:00
|
|
|
|
2023-12-23 15:14:40 +13:00
|
|
|
calculate(:author_count_of_posts, :integer, expr(author.count_of_posts_with_calc))
|
|
|
|
|
2023-12-24 04:39:54 +13:00
|
|
|
calculate(
|
|
|
|
:sum_of_author_count_of_posts,
|
|
|
|
:integer,
|
|
|
|
expr(sum(author, field: :count_of_posts))
|
|
|
|
)
|
|
|
|
|
|
|
|
calculate(:author_count_of_posts_agg, :integer, expr(author.count_of_posts))
|
|
|
|
|
2023-04-01 05:12:13 +13:00
|
|
|
calculate(
|
|
|
|
:price_string,
|
|
|
|
:string,
|
|
|
|
CalculatePostPriceString
|
|
|
|
)
|
|
|
|
|
|
|
|
calculate(
|
|
|
|
:price_string_with_currency_sign,
|
|
|
|
:string,
|
|
|
|
CalculatePostPriceStringWithSymbol
|
|
|
|
)
|
2023-10-10 11:57:06 +13:00
|
|
|
|
|
|
|
calculate(:author_first_name_calc, :string, expr(author.first_name))
|
2023-11-17 12:12:00 +13:00
|
|
|
|
|
|
|
calculate(:author_profile_description_from_agg, :string, expr(author_profile_description))
|
2021-06-04 17:48:35 +12:00
|
|
|
end
|
|
|
|
|
2020-12-29 13:26:04 +13:00
|
|
|
aggregates do
|
2021-01-13 14:22:28 +13:00
|
|
|
count(:count_of_comments, :comments)
|
2021-05-13 05:17:26 +12:00
|
|
|
count(:count_of_linked_posts, :linked_posts)
|
2020-12-29 13:26:04 +13:00
|
|
|
|
|
|
|
count :count_of_comments_called_match, :comments do
|
2021-01-13 14:22:28 +13:00
|
|
|
filter(title: "match")
|
2020-12-29 13:26:04 +13:00
|
|
|
end
|
|
|
|
|
2023-07-13 16:13:50 +12:00
|
|
|
exists :has_comment_called_match, :comments do
|
|
|
|
filter(title: "match")
|
|
|
|
end
|
|
|
|
|
2022-09-14 08:27:39 +12:00
|
|
|
count(:count_of_comments_containing_title, :comments_containing_title)
|
|
|
|
|
2020-12-29 13:26:04 +13:00
|
|
|
first :first_comment, :comments, :title do
|
2021-01-13 14:22:28 +13:00
|
|
|
sort(title: :asc_nils_last)
|
2020-12-29 13:26:04 +13:00
|
|
|
end
|
2021-04-05 08:05:41 +12:00
|
|
|
|
2023-02-08 11:43:53 +13:00
|
|
|
first :last_comment, :comments, :title do
|
2024-03-01 07:42:42 +13:00
|
|
|
sort(title: :desc, title: :asc)
|
2023-02-08 11:43:53 +13:00
|
|
|
end
|
|
|
|
|
2023-02-10 11:49:37 +13:00
|
|
|
first(:author_first_name, :author, :first_name)
|
|
|
|
|
2022-12-08 14:32:38 +13:00
|
|
|
max(:highest_comment_rating, [:comments, :ratings], :score)
|
|
|
|
min(:lowest_comment_rating, [:comments, :ratings], :score)
|
|
|
|
avg(:avg_comment_rating, [:comments, :ratings], :score)
|
|
|
|
|
|
|
|
custom(:comment_authors, [:comments, :author], :string) do
|
|
|
|
implementation({AshPostgres.Test.StringAgg, field: :first_name, delimiter: ","})
|
|
|
|
end
|
|
|
|
|
2021-11-14 07:55:49 +13:00
|
|
|
first :latest_comment_created_at, :comments, :created_at do
|
|
|
|
sort(created_at: :desc)
|
|
|
|
end
|
|
|
|
|
2021-04-27 08:45:47 +12:00
|
|
|
list :comment_titles, :comments, :title do
|
|
|
|
sort(title: :asc_nils_last)
|
2023-02-10 10:09:44 +13:00
|
|
|
end
|
|
|
|
|
|
|
|
list :uniq_comment_titles, :comments, :title do
|
|
|
|
uniq?(true)
|
|
|
|
sort(title: :asc_nils_last)
|
2021-04-27 08:45:47 +12:00
|
|
|
end
|
|
|
|
|
2023-02-18 09:21:50 +13:00
|
|
|
count :count_comment_titles, :comments do
|
|
|
|
field(:title)
|
|
|
|
end
|
|
|
|
|
|
|
|
count :count_uniq_comment_titles, :comments do
|
|
|
|
field(:title)
|
|
|
|
uniq?(true)
|
|
|
|
end
|
|
|
|
|
2024-01-19 18:12:50 +13:00
|
|
|
count(:count_of_ratings, :ratings)
|
|
|
|
|
2022-10-11 05:06:54 +13:00
|
|
|
list :comment_titles_with_5_likes, :comments, :title do
|
|
|
|
sort(title: :asc_nils_last)
|
|
|
|
filter(expr(likes >= 5))
|
|
|
|
end
|
|
|
|
|
2021-04-05 08:05:41 +12:00
|
|
|
sum(:sum_of_comment_likes, :comments, :likes)
|
2021-10-26 11:53:34 +13:00
|
|
|
sum(:sum_of_comment_likes_with_default, :comments, :likes, default: 0)
|
2021-04-05 08:05:41 +12:00
|
|
|
|
2023-01-07 11:05:23 +13:00
|
|
|
sum :sum_of_popular_comment_rating_scores, [:comments, :ratings], :score do
|
|
|
|
filter(expr(score > 5))
|
|
|
|
end
|
|
|
|
|
|
|
|
sum(:sum_of_popular_comment_rating_scores_2, [:comments, :popular_ratings], :score)
|
|
|
|
|
2021-04-05 08:05:41 +12:00
|
|
|
sum :sum_of_comment_likes_called_match, :comments, :likes do
|
|
|
|
filter(title: "match")
|
|
|
|
end
|
2021-07-03 04:41:44 +12:00
|
|
|
|
2022-02-12 10:06:51 +13:00
|
|
|
# All of them will, but we want to test a related field
|
|
|
|
count :count_of_comments_that_have_a_post, :comments do
|
|
|
|
filter(expr(not is_nil(post.id)))
|
|
|
|
end
|
|
|
|
|
2022-09-29 11:01:20 +13:00
|
|
|
# All of them will, but we want to test a related field
|
|
|
|
count :count_of_comments_that_have_a_post_with_exists, :comments do
|
|
|
|
filter(expr(exists(post, not is_nil(id))))
|
|
|
|
end
|
|
|
|
|
2022-02-15 11:44:17 +13:00
|
|
|
count :count_of_popular_comments, :comments do
|
|
|
|
filter(expr(not is_nil(popular_ratings.id)))
|
|
|
|
end
|
|
|
|
|
2022-02-10 05:49:19 +13:00
|
|
|
sum :sum_of_recent_popular_comment_likes, :popular_comments, :likes do
|
|
|
|
# not(is_nil(post_category)) is silly but its here for tests
|
|
|
|
filter(expr(created_at > ago(10, :day) and not is_nil(post_category)))
|
|
|
|
end
|
|
|
|
|
|
|
|
count :count_of_recent_popular_comments, :popular_comments do
|
|
|
|
# not(is_nil(post_category)) is silly but its here for tests
|
|
|
|
filter(expr(created_at > ago(10, :day) and not is_nil(post_category)))
|
|
|
|
end
|
|
|
|
|
2021-07-03 04:41:44 +12:00
|
|
|
count(:count_of_comment_ratings, [:comments, :ratings])
|
2021-07-06 06:12:21 +12:00
|
|
|
|
2022-12-08 14:32:38 +13:00
|
|
|
count :count_of_popular_comment_ratings, [:comments, :ratings] do
|
|
|
|
filter(expr(score > 10))
|
|
|
|
end
|
|
|
|
|
|
|
|
list :ten_most_popular_comments, [:comments, :ratings], :id do
|
|
|
|
filter(expr(score > 10))
|
|
|
|
sort(score: :desc)
|
|
|
|
end
|
|
|
|
|
2021-07-06 06:12:21 +12:00
|
|
|
first :highest_rating, [:comments, :ratings], :score do
|
|
|
|
sort(score: :desc)
|
|
|
|
end
|
2021-11-14 07:56:14 +13:00
|
|
|
|
|
|
|
first :latest_arbitrary_timestamp, :comments, :arbitrary_timestamp do
|
|
|
|
sort(arbitrary_timestamp: :desc)
|
|
|
|
end
|
2023-11-17 12:12:00 +13:00
|
|
|
|
|
|
|
first(:author_profile_description, :author, :description)
|
2020-12-29 13:26:04 +13:00
|
|
|
end
|
2020-09-11 12:26:47 +12:00
|
|
|
end
|
2023-04-01 05:12:13 +13:00
|
|
|
|
|
|
|
defmodule CalculatePostPriceString do
|
2023-04-06 04:21:35 +12:00
|
|
|
@moduledoc false
|
2024-03-28 09:52:28 +13:00
|
|
|
use Ash.Resource.Calculation
|
2023-04-01 05:12:13 +13:00
|
|
|
|
|
|
|
@impl true
|
2024-03-28 09:52:28 +13:00
|
|
|
def load(_, _, _), do: [:price]
|
2023-04-01 05:12:13 +13:00
|
|
|
|
|
|
|
@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
|
2023-04-06 04:21:35 +12:00
|
|
|
@moduledoc false
|
2024-03-28 09:52:28 +13:00
|
|
|
use Ash.Resource.Calculation
|
2023-04-01 05:12:13 +13:00
|
|
|
|
|
|
|
@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
|
2024-01-31 03:26:39 +13:00
|
|
|
|
|
|
|
defmodule AshPostgres.Test.Post.ManualUpdate do
|
2024-01-31 09:32:50 +13:00
|
|
|
@moduledoc false
|
2024-01-31 03:26:39 +13:00
|
|
|
use Ash.Resource.ManualUpdate
|
|
|
|
|
|
|
|
def update(changeset, _opts, _context) do
|
|
|
|
{
|
|
|
|
:ok,
|
|
|
|
changeset.data
|
|
|
|
|> Ash.Changeset.for_update(:update, changeset.attributes)
|
|
|
|
|> Ash.Changeset.force_change_attribute(:title, "manual")
|
2024-01-31 14:04:42 +13:00
|
|
|
|> Ash.Changeset.load(:comments)
|
2024-03-28 09:52:28 +13:00
|
|
|
|> Ash.update!()
|
2024-01-31 03:26:39 +13:00
|
|
|
}
|
|
|
|
end
|
|
|
|
end
|