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

Support accessing individual field's type #39

Open
mattste opened this issue Feb 28, 2023 · 2 comments
Open

Support accessing individual field's type #39

mattste opened this issue Feb 28, 2023 · 2 comments

Comments

@mattste
Copy link

mattste commented Feb 28, 2023

I'm looking for a way to access an individual field's type.

Given the following schema:

defmodule OrganizationMembership do
  @primary_key false
  typed_schema "organizations_memberships" do
    belongs_to :organization, Organization
    belongs_to :user, User

    field(:role, Ecto.Enum, values: [:admin, :billing, :content_editor, :content_viewer])

    timestamps()
  end
end

I was hoping to find a way to do something like OrganizationMembership.role() so typespecs in other modules can use it. My current workaround is to manually define a role type and have the field use that. Perhaps there is already a way but it's not public surface area?

@dvic
Copy link
Collaborator

dvic commented Mar 1, 2023

Unfortunately this is not supported as far as I know, for now the workaround is indeed to use

@role_values [:admin, :billing, :content_editor, :content_viewer]
@type role :: :admin | :billing | :content_editor | :content_viewer

defmodule OrganizationMembership do
  typed_schema "organizations_memberships" do

    field(:role, Ecto.Enum, values: @role_values) :: role()

  end
end

In my project I do use a macro to simplify this:

defmodule OrganizationMembership do
  import UnionType

  @role_values [:admin, :billing, :content_editor, :content_viewer]

  union_type(role :: @role_values)

  typed_schema "organizations_memberships" do

    field(:role, Ecto.Enum, values: @role_values) :: role()

  end
end

where

defmodule UnionType do
  defmacro union_type({:"::", _, [{name, _, _}, data]}) do
    quote bind_quoted: [data: data, name: name] do
      @type unquote(name)() :: unquote(UnionType.union_type_ast(data))
    end
  end

  def union_type_ast([item]), do: item
  def union_type_ast([head | tail]), do: {:|, [], [head, union_type_ast(tail)]}
end

@bamorim
Copy link
Owner

bamorim commented Mar 1, 2023

That could be a nice feature to have. Not sure the ergonomics, but it could be interesting to automatically generate types for Ecto.Enum types. That would need to be opt-in though, as it has a possibility of conflicting with other types or need to be "prefixed", which might not yield the nicest type names.

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

No branches or pull requests

3 participants