Where to write custom changeset validation functions which rely on current database values / records?

Here is an example of a custom validation:

@our_url "https://our-bucket.s3.amazon.com"
def changeset(struct, params \\ %{}) do
  struct
  |> cast(params, @required_fields)
  |> validate_required(@required_fields)
  |> validate_from_s3_bucket(:url)
end
def validate_from_s3_bucket(changeset, field, options \\ []) do
  validate_change(changeset, field, fn _, url ->
    case String.starts_with?(url, @our_url) do
      true -> []
      false -> [{field, options[:message] || "Unexpected URL"}]
    end
  end)
end

This can be written in the schema definition file. But where to write custom changeset validation functions which test database tables (of other models) for certain values and based on that data flag the transaction as valid or not? I guess making Ecto queries for B inside schema definition of A is not the correct way to do it. Any ideas? Thank you.

Example / Clarification

I have this in my schema definition:

  def changeset(record, attrs) do
    record
    |> cast(attrs, [:issued_at, :due_for_return, :returned_at, :fee, :fee_paid_at, :book_id])
    |> validate_required([])
    |> validate_book(:book_id)
  end


  defp validate_book(changeset, field) do
    case changeset.valid? do
      true ->
        book_id = get_field(changeset, field)
        case  Repo.get(Mango.Books.Book, book_id) do
          nil -> add_error(changeset, :book_id, "Book not found..")
          book -> {:ok, book}
            case book.status do
              :available -> changeset
              _ -> add_error(changeset, :book_id, "Book is already out..")
            end
        end
      _ ->
        changeset
    end
  end

As you can see I am doing some Repo query validation against some other model (books). My question is this the place do this or should I move all of this outside of my schema definition?