Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

An array of CustomTypes in action argument not cast when passed to query #1668

Open
dmitriid opened this issue Dec 20, 2024 · 4 comments
Open
Labels
bug Something isn't working

Comments

@dmitriid
Copy link
Contributor

dmitriid commented Dec 20, 2024

Describe the bug

I have a custom type, and use it in an argument to a read action. This is then used in a filter. And fails. See code for a better explanation:

Edit: there's a reproduction in this minimal project https://github.com/dmitriid/ash_custom_types_repro

> Events.Event.all_events([:error, :done])
   SELECT ... FROM event e0 WHERE e0."status"::bigint = ANY($1)
   [["error", "done"]]

  "Postgrex expected an integer in -9223372036854775808..9223372036854775807, got \"error\". ...

To Reproduce

defmodule Events.Event do

  use Ash.Resource,
    data_layer: AshPostgres.DataLayer,
    notifiers: [Ash.Notifier.PubSub],
    domain: Events

  postgres do
    table "events"
    repo Events.Repo
  end

  code_interface do
    define :all_events, args: [:status]
  end

  actions do
    read :all_events do
      argument :status, {:array, Events.Resources.Types.Status} do
        allow_nil? true
      end

      filter expr(if is_nil(^arg(:status)) or ^arg(:status) == [], do: not is_nil(status), else: status in ^arg(:status))
    end
  end

  attributes do
    uuid_primary_key :id

    attribute :status, Events.Resources.Types.Status do
      allow_nil? false
      default :processing
      public? true
    end
  end
end

Custom type:

defmodule Events.Resources.Types.Status do
  use Ash.Type

  @impl Ash.Type
  def storage_type(_), do: :integer

  @impl Ash.Type
  def cast_in_query?(_), do: true

  @impl Ash.Type
  def cast_input(value, _), do: to_type(value)

  @impl Ash.Type
  def cast_stored(value, _), do: to_type(value)

  @impl Ash.Type
  def dump_to_native(nil, _), do: {:ok, nil}
  def dump_to_native(:processing, _), do: {:ok, 0}
  def dump_to_native(:done, _), do: {:ok, 1}
  def dump_to_native(:error, _), do: {:ok, -1}

  def dump_to_native(_, _),
    do: {:error, "Invalid status value. Allowed values are :processing, :done, :error, or nil"}

  defp to_type(0), do: {:ok, :processing}
  defp to_type(1), do: {:ok, :done}
  defp to_type(-1), do: {:ok, :error}
  defp to_type(:processing), do: {:ok, :processing}
  defp to_type(:done), do: {:ok, :done}
  defp to_type(:error), do: {:ok, :error}
  defp to_type(nil), do: {:ok, nil}

  defp to_type(_),
    do: {:error, "Invalid status value. Allowed values are :processing, :done, :error, or nil"}
end

Expected behavior

I was expecting the argument to be cast to proper native type with dump_native, but this didn't happen

Runtime

  • Elixir version: Elixir 1.18.0-rc.0
  • Erlang version: Erlang/OTP 27 [erts-15.2] [source] [64-bit] [smp:12:12] [ds:12:12:10] [async-threads:1] [jit:ns]
  • OS: Ubuntu 22.04.1 LTS
  • Ash version:
    • {:ash, ">= 3.4.4"}
      locked at 3.4.46 (ash) 78cd7d1d
  • any related extension versions:
    • {:ash_postgres, "~> 2.3.0"}
      locked at 2.3.1 (ash_postgres) 886659fe

Additional context
Add any other context about the problem here.

@dmitriid dmitriid added bug Something isn't working needs review labels Dec 20, 2024
@zachdaniel
Copy link
Contributor

Interesting...

what happens if you use type/3 to explicitly type the argument in the expression?

@dmitriid
Copy link
Contributor Author

So, I tried this:

    filter expr(
        if is_nil(^arg(:status)) or ^arg(:status) == [],
        do: not is_nil(status),
        else: status in type(^arg(:status), {:array, Events.Resources.Types.Status})
      )


** (MatchError) no match of right hand side value: 
    {:error, %Ash.Error.Unknown{
      bread_crumbs: ["Error returned from: Events.Event.all_events"],  
      query: "#Query<>", 
      errors: [
          %Ash.Error.Unknown.UnknownError{
              error: "** (FunctionClauseError) no function clause matching in Keyword.update/4", 
              field: nil,
              value: nil,
              splode: Ash.Error,
              bread_crumbs: ["Error returned from: Events.Event.all_events"], 
              vars: [],
              path: [],
              stacktrace: #Splode.Stacktrace<>, class: :unknown
}]}}

Just for the heck of it I also tried this:

      filter expr(
        if is_nil(^arg(:status)) or ^arg(:status) == [],
        do: not is_nil(status),
        else: status in type(^arg(:status), Events.Resources.Types)
      )



** (MatchError) no match of right hand side value:
  {:error, %Ash.Error.Invalid{
    bread_crumbs: ["Error returned from: Events.Event.all_events"], 
    query: "#Query<>", 
    errors: [
      %Ash.Error.Query.InvalidFilterValue{
        message: nil,
        value: ["processing", "error"],
        context: #Ecto.Query<from e0 in Events.Event, as: 0, left_lateral_join: d1 in ^#Ecto.Query<from d0 in subquery(from d0 in Events.Date, 
        ... rest of query AST ...
       , where: type(as(0).status, {:parameterized, {Events.Resources.Types.Status.EctoType, []}}) in type(
  ^["processing", "error"],
        {:parameterized, {Events.Resources.Types.Status.EctoType, []
    }],
    splode: Ash.Error, 
    bread_crumbs: ["Error returned from: Events.Event.all_events"],
    vars: [],
    path: [],
    stacktrace: #Splode.Stacktrace<>,
    class: :invalid
}]}}

@zachdaniel
Copy link
Contributor

Hello! I'm super strapped for time at the moment. I'd like to fix this, but if you could create a small reproduction project that I can clone that has a failing test reproducing this issue, I'd really aprpeciate it.

@dmitriid
Copy link
Contributor Author

Oh, no worries. It's holiday season, and the issue isn't that serious (for me at least anyway).

I've created the simplest repro here: https://github.com/dmitriid/ash_custom_types_repro.

It will still be there after the holidays 🎉 So don't stress over it too much!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants