Skip to content

feat: allow custom field mappings#19

Open
kepi wants to merge 1 commit intoenoonan:mainfrom
kepi:feat/custom-field-mappings
Open

feat: allow custom field mappings#19
kepi wants to merge 1 commit intoenoonan:mainfrom
kepi:feat/custom-field-mappings

Conversation

@kepi
Copy link
Contributor

@kepi kepi commented Jan 8, 2026

I would like to have some custom fields consistently through whole application and I didn't find any way how to currently do this.

My reasoning is that writing AshBackpex resources should be as brief as possible and I really hate the idea of adding module to i.e. each field with date.

Ideal solution would be to have :field_mappings in Application config which would be found by AshBackpex. But I suppose libraries shouldn't be based on anything in application so I'm introducing new "attribute" for resource named field_mappings working like this:

field_mappings(%{
  Ash.Type.UtcDatetime => MyappWeb.Backpex.Fields.RelativeDateTime,
  Ash.Type.UtcDatetimeUsec => MyappWeb.Backpex.Fields.RelativeDateTime,
  Ash.Type.DateTime => MyappWeb.Backpex.Fields.RelativeDateTime,
  Ash.Type.NaiveDateTime => MyappWeb.Backpex.Fields.RelativeDateTime
})

That way I can use my custom module with backpex macro which set this as default for all my admin pages.

Simple test covering the functionality is included.

Let me know if you have any objections or if I should improve something.

@kepi kepi force-pushed the feat/custom-field-mappings branch from 435d6cc to 175b6dd Compare January 8, 2026 19:31
I would like to have some custom fields consistently through whole
application and I didn't find any way how to currently do this.

My reasoning is that writing AshBackpex resources should be as brief as
possible and I really hate the idea of adding `module` to i.e. each
field with date.

Ideal solution would be to have :field_mappings in Application config
which would be found by AshBackpex. But I suppose libraries shouldn't be
based on anything in application so I'm introducing new "attribute" for
resource named field_mappings working like this:

    field_mappings(%{
      Ash.Type.UtcDatetime => MyappWeb.Backpex.Fields.RelativeDateTime,
      Ash.Type.UtcDatetimeUsec => MyappWeb.Backpex.Fields.RelativeDateTime,
      Ash.Type.DateTime => MyappWeb.Backpex.Fields.RelativeDateTime,
      Ash.Type.NaiveDateTime => MyappWeb.Backpex.Fields.RelativeDateTime
    })

That way I can use my custom module with backpex macro which set this as
default for all my admin pages.

Simple test covering the functionality is included.
@kepi kepi force-pushed the feat/custom-field-mappings branch from 175b6dd to accc71e Compare January 8, 2026 20:19
@enoonan
Copy link
Owner

enoonan commented Jan 9, 2026

This is an interesting idea but I need a bit of time to think about it.

I think your initial instinct to set it as an application-wide config may have been correct. Many libraries use application-level configs. And if we don't do that, you end up having to repeat this same field_mapping on every LiveResource.

AshBackpex maps Ash field types to Backpex field types, but that mapping is inherently opinionated, so it does make sense to offer an escape hatch.

I'm going to see if I can get other opinions about the API design for this in the Ash Discord. There's an Ash Backpex channel there, you should join it!

@kepi
Copy link
Contributor Author

kepi commented Jan 10, 2026

TBH I originally wrote it with apple wide config but I didn't find any reasonable possibility how to create test with different application configs in one test suite :) That was what made me to do some research and what brought me to Elixir library recommendations where this is frown upon :)

In my application, I don't want to repeat this in every LiveResource ofc, so I ended up with using custom module:

defmodule EldorWeb.AdminLiveResource do
  @moduledoc """
  Base module for admin LiveResources with common field mappings.

  Usage:
      defmodule EldorWeb.Admin.Orders.OrderAdminLive do
        use EldorWeb.AdminLiveResource

        backpex do
          resource Eldor.Orders.Order
          # field_mappings is automatically added
          # ...
        end
      end
  """

  @default_field_mappings %{
    Ash.Type.UtcDatetime => EldorWeb.Backpex.Fields.RelativeDateTime,
    Ash.Type.UtcDatetimeUsec => EldorWeb.Backpex.Fields.RelativeDateTime,
    Ash.Type.DateTime => EldorWeb.Backpex.Fields.RelativeDateTime,
    Ash.Type.NaiveDateTime => EldorWeb.Backpex.Fields.RelativeDateTime
  }

  def default_field_mappings, do: @default_field_mappings

  defmacro __using__(_opts) do
    quote do
      use AshBackpex.LiveResource
      import AshBackpex.LiveResource.Dsl, except: [backpex: 1]
      import EldorWeb.AdminLiveResource, only: [backpex: 1]
    end
  end

  @doc """
  Wrapper around AshBackpex `backpex` that automatically adds field_mappings.

  All options from `backpex` are supported.
  """
  defmacro backpex(do: block) do
    field_mappings = @default_field_mappings

    quote do
      AshBackpex.LiveResource.Dsl.backpex do
        field_mappings(unquote(Macro.escape(field_mappings)))
        unquote(block)
      end
    end
  end
end

I would like to join Ash Backpex channel somewhere but I'm quite hesitant to do that on Discord as a platform. But as I have two more ideas which I don't want would be OK to integrate into Ash Backpex, I may have to :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

Comments