How use nanoid as primary key? Where can I find the source code this generator?

With the mix phx.new --binary-id flag this is generate in my config.exs file.

config :my_app,
  ecto_repos: [MyApp.Repo],
  generators: [binary_id: true]

I would like to be able to do a simple generators: [nano_id: true] and have Ecto generate the migrations/schemas for me.

Looks like when done manually:

@primary_key {:id, :string, autogenerate: {Ecto.Nanoid, :autogenerate, []}}
@foreign_key_type :string
schema "listings" do
  field(:description, :string)
  # snip ***

Where can I find the source code for that generator? I would like to submit a patch

2 Likes

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.

2 Likes