set_attribute(:line, arg(:line)) sets to nil when argument is not provided

When using change set_attribute(:line, arg(:line)) and using input: {} in the graphql api, the line attribute is set to nil and persisted as null in the database, which erases existing field data
I expected that it would stay the same as the documentation says:

Use arg(:argument_name) to use the value of the given argument. If the argument is not supplied then nothing happens.

I have to pass it this way to convert from geo_json to line_string, which uses AshGeo to map to PostGIS line string type

The only workaround I found is this

change fn changeset, _context ->
  if Map.has_key?(changeset.arguments, :line) do
    line = Changeset.get_argument(changeset, :line)
    changeset |> Changeset.change_attribute(:line, line)
  else
    changeset
  end
end

But I think there might be a better way to do it, or I might be missing something

Here is the model code:

defmodule MyProject.Geography.Street do
  @moduledoc false
  alias Ash.Changeset
  alias MyProject.Geography

  use Ash.Resource,
    domain: MyProject.Geography,
    data_layer: AshPostgres.DataLayer,
    extensions: [AshGraphql.Resource]

  graphql do
    type :streets
    ...

    mutations do
      create :create_street, :create
      update :update_street, :update
      ...
    end
  end
  ...

  actions do
    defaults [:read, ...]

    update :update do
      accept :*
      primary? true

      argument :line, :geo_json
      
      change set_attribute(:line, arg(:line))
    end
  end

  attributes do
    uuid_v7_primary_key :id
    attribute :name, :string, allow_nil?: false, public?: true
    attribute :line, :line_string, public?: true
    ...
  end
end

defmodule MyProject.Type.LineString do
  use AshGeo.Geometry,
    storage_type: :"geography(LineString,4326)",
    geo_types: :line_string

  def graphql_input_type(_), do: :json
  def graphql_type(_), do: :json
end

You could use Ash.Changeset — ash v3.11.3 instead I think.

Ah, I’ve fixed the docs. It just doesn’t work that way, and a custom change is likely the best way. You can do change set_attribute(:attribute, arg(:value), set_when_nil?: false) to ignore nil values, but that would prevent actually setting to nil.