bamorim / typed_ecto_schema

A library to define Ecto schemas with typespecs without all the boilerplate code.
https://hexdocs.pm/typed_ecto_schema
Apache License 2.0
271 stars 18 forks source link

Expanding philosophy to moduledoc #41

Open NoBrainSkull opened 1 year ago

NoBrainSkull commented 1 year ago

Hello,

I'd love to expand this module philosophy to the documentation of the schema. Would you consider adding an option to the DSL to specify details about each field ?

Maybe something like :

defmodule Person do
  use TypedEctoSchema

  typed_schema "people", """
    Record of a customer.

   [...] Some other details about the schema.
    """ do
    field(:name, :string, enforce: true, null: false, doc: "fullname of the user")
    field(:age, :integer) :: non_neg_integer() | nil
    field(:happy, :boolean, default: true, null: false, doc: "satisfaction threshold computed from order satisfaction")
    field(:phone, :string, doc: "phone number obtained at first-order time")
    belongs_to(:company, Company)
    timestamps(type: :naive_datetime_usec)
  end
end

This would generate somehing like :

defmodule Person do
 @moduledoc """
    Record of a customer.

   [...] Some other details about the schema.

   ### Fields
   name: string - fullname of the user
   age: non_neg_integer - age
   happy: boolean - satisfaction threshold computed from order satisfaction
   phone: string - phone number obtained at first-order time
  """
  use Ecto.Schema

  @enforce_keys [:name]

  schema "people" do
    field(:name, :string)
    field(:age, :integer)
    field(:happy, :boolean, default: true)
    field(:phone, :string)
    belongs_to(:company, Company)
    timestamps(type: :naive_datetime_usec)
  end

  @type t() :: %__MODULE__{
          __meta__: Ecto.Schema.Metadata.t(),
          id: integer() | nil,
          name: String.t(),
          age: non_neg_integer() | nil,
          happy: boolean(),
          phone: String.t() | nil,
          company_id: integer() | nil,
          company: Company.t() | Ecto.Association.NotLoaded.t() | nil,
          inserted_at: NaiveDateTime.t(),
          updated_at: NaiveDateTime.t()
        }
end

As you know, we can very much define module attributes in macros. I'd be glad to do a pull request if you are open to the idea :)

Thanks

bamorim commented 1 year ago

@NoBrainSkull Although I like the idea of generating doc as well, this would go beyond the original proposal of the library and I'm not sure it would be something everyone would llke so I need to put more thought into that. Maybe that would be acceptable as an opt-in? Maybe if people specify the third argument as a string then it might make sense. Or maybe we could have something like

@schemadoc """
...
"""

That would automatically generate the @moduledoc like you described. I'm not sure how would be a good way of doing or if we should do it at all, however, I do like the idea. I think adding the ### Fields with the metadata we are already extracting can be a really good thing, so there is value to the idea.

Will have to think more about it. Thanks for the idea! Proposal PRs are welcome, but maybe we should discuss a little bit more before jumping into implementation.

NoBrainSkull commented 1 year ago

@bamorim thank you for considering the idea. To provide more fuel to it :