defmodule Bid do use Ecto.Schema import Ecto.Changeset alias NeonVertigoService.Repo import Ecto.Query, only: [from: 2] @primary_key false schema "bids" do belongs_to :auction, Auction, foreign_key: :auction_gid, references: :gid, type: :string, primary_key: true field :bid_timestamp, :utc_datetime_usec, primary_key: true field :bidder_gid, :string, primary_key: true field :bid, :decimal end def changeset(bid, params \\ %{}) do bid |> cast(params, [:auction_gid, :bidder_gid, :bid]) |> validate_required([:auction_gid, :bidder_gid, :bid]) |> validate_number(:bid, greater_than_or_equal_to: 0) |> validate_bid_value_max |> validate_bid_value_more_than_auction_starting_price |> put_change(:bid_timestamp, DateTime.utc_now) |> foreign_key_constraint(:auction_gid) end defp validate_bid_value_max(changeset) do auction_gid = get_field(changeset, :auction_gid) new_bid = get_field(changeset, :bid) existing_bid = Repo.one( from b in Bid, where: b.auction_gid == ^auction_gid, order_by: [desc: :bid_timestamp], limit: 1, select: b.bid ) if is_nil(existing_bid) or Decimal.compare(existing_bid, new_bid) == :lt do changeset else add_error(changeset, :bid, "smaller than last bid") end end defp validate_bid_value_more_than_auction_starting_price(changeset) do auction_gid = get_field(changeset, :auction_gid) auction = Repo.one!(from a in Auction, where: a.gid == ^auction_gid, select: a) if Decimal.compare(auction.starting_price, get_field(changeset, :bid)) == :lt do changeset else add_error(changeset, :bid, "smaller than auction's starting price") end end end