I would like to propose an alternative approach for using NanoID, or something like ULID, UUID.
The overall goal is to not modify too much of the generators.
Take ULID as an example.
1. setup at migration level
Setup primary key for migrations:
config :paper, Paper.Repo, migration_primary_key: [name: :id, type: :binary_id]
2. setup at schema level
Create a Ecto.Schema
wrapper for setting up primary keys and foreign keys:
# Define a module to be used as base
defmodule Paper.Schema do
defmacro __using__(_) do
quote do
use Ecto.Schema
@primary_key {:id, Ecto.ULID, autogenerate: true}
@foreign_key_type Ecto.ULID
end
end
end
3. generate a schema using the generator
Use the generators to generate a schema. Let’s say:
$ mix phx.gen.context Accounts User users name:string age:integer
Above command will generate a schema like this:
defmodule Paper.Accounts.User do
use Ecto.Schema
import Ecto.Changeset
schema "users" do
field :age, :integer
field :name, :string
timestamps()
end
# ...
end
4. tune the generated schema
Replace Ecto.Schema
with Paper.Schema
manually:
defmodule Paper.Accounts.User do
use Paper.Schema # here it is
import Ecto.Changeset
schema "users" do
field :age, :integer
field :name, :string
timestamps()
end
# ...
end
In all the 4 steps:
- 1 and 2 will be done only once, I think that’s acceptable.
- 3 and 4 can be merged into one step. I think that’s improvable. But how? Maybe, provides an option
--schema
, which allows developers to specify a customized schema. For example:
$ mix phx.gen.context Accounts User users name:string age:integer --schema Paper.Schema
It can also support a config, such as:
config :paper,
generators: [schema: Paper.Schema]
Through this approach, we can gain a balance between flexibility and complexity of generator.
This is just my personal opinion, perhaps it can be further considered and refined.