[自动翻译] Generate Ecto migrations from natural language or schema descriptions. Handles tables, columns, indexes, constraints, references, enums, and partition...
The skill is an instruction-only helper for generating Ecto migrations and its requirements and instructions are consistent with that purpose.
评估建议
This skill is coherent and appears safe as an authoring helper, but remember: generated migrations change your database schema. Always review generated migration code before running it, run migrations in a development/staging environment first, take backups, and ensure patterns (primary key type, tenant_id decisions, concurrent index flags, data-migration strategies) match your application's conventions. Because the skill is instruction-only, installing it does not add code to your system, but d...
详细分析 ▾
✓用途与能力
Name/description (Ecto migrations) match the content of SKILL.md and the provided references. The skill does not request unrelated binaries, credentials, or config paths — everything is appropriate for a migration-generation helper.
✓指令范围
SKILL.md contains templates, patterns, and concrete migration snippets (indexes, constraints, multi-tenant patterns, data-migration guidance). It does not instruct the agent to read arbitrary local files, access environment variables, or send data to external endpoints. It also does not instruct the agent to execute migrations against a database (only shows mix/execute examples), so runtime scope is limited to generating code/text.
✓安装机制
No install spec and no code files that run on the host. As an instruction-only skill, it does not download or write executables to disk — lowest-risk install profile.
✓凭证需求
The skill declares no required environment variables, credentials, or config paths. That is proportionate: generating migration text does not require secrets or external service access.
✓持久化与权限
always is false and the skill does not request persistent presence or modify other skills. Autonomous invocation is allowed (platform default) but the skill's content does not raise additional privilege concerns.
Initial release of ecto-migrator.
- Generate Ecto migrations from natural language or schema descriptions.
- Supports creation and modification of tables, columns, indexes, constraints, references, enums, and partitioning.
- Handles reversible migrations, data migrations, and multi-tenant schema patterns.
- Provides naming conventions, migration templates, index and constraint strategies, and PostgreSQL extension guidance.
- Includes best practices for data migrations and enum types in Elixir projects.
Child can't exist without parent (memberships, line items)
:nilify_all
Child should survive parent deletion (optional association)
:nothing
Handle in application code (default)
:restrict
Prevent parent deletion if children exist
Multi-Tenant Patterns
Every Table Gets tenant_id
def change do
create table(:items, primary_key: false) do
add :id, :binary_id, primary_key: true
add :name, :string, null: false
add :tenant_id, :binary_id, null: false
timestamps(type: :utc_datetime_usec)
end
# Always composite index with tenant_id first
create index(:items, [:tenant_id])
create unique_index(:items, [:tenant_id, :name])
end
Adding tenant_id to Existing Tables
def change do
alter table(:items) do
add :tenant_id, :binary_id
end
# Backfill in a separate data migration, then:
# alter table(:items) do
# modify :tenant_id, :binary_id, null: false
# end
end
Data Migrations
Rule: Never mix schema changes and data changes in the same migration.
Safe Data Migration Pattern
defmodule MyApp.Repo.Migrations.BackfillUserRoles do
use Ecto.Migration
# Don't use schema modules — they may change after this migration runs
def up do
execute """
UPDATE users SET role = 'member' WHERE role IS NULL
"""
end
def down do
# Data migrations may not be reversible
:ok
end
end
Batched Data Migration (large tables)
def up do
execute """
UPDATE users SET role = 'member'
WHERE id IN (
SELECT id FROM users WHERE role IS NULL LIMIT 10000
)
"""
# For very large tables, use a Task or Oban job instead
end
Reversible vs Irreversible
Reversible (use change)
These are auto-reversible:
create table ↔ drop table
add column ↔ remove column
create index ↔ drop index
rename ↔ rename
Irreversible (use up/down)
Must define both directions:
modify column type — Ecto can't infer the old type
execute raw SQL
Data backfills
Dropping columns with data
def up do
alter table(:users) do
modify :email, :citext, from: :string # from: helps reversibility
end
end
def down do
alter table(:users) do
modify :email, :string, from: :citext
end
end
Using modify with from:
Phoenix 1.7+ supports from: for reversible modify:
def change do
alter table(:users) do
modify :email, :citext, null: false, from: {:string, null: true}
end
end
PostgreSQL Extensions
def change do
execute "CREATE EXTENSION IF NOT EXISTS citext", "DROP EXTENSION IF EXISTS citext"
execute "CREATE EXTENSION IF NOT EXISTS pgcrypto", "DROP EXTENSION IF EXISTS pgcrypto"
execute "CREATE EXTENSION IF NOT EXISTS pg_trgm", "DROP EXTENSION IF EXISTS pg_trgm"
end
Enum Types (PostgreSQL native — use sparingly)
Prefer Ecto.Enum with :string columns. If you must use Postgres enums:
def up do
execute "CREATE TYPE order_status AS ENUM ('pending', 'confirmed', 'shipped', 'delivered')"
alter table(:orders) do
add :status, :order_status, null: false, default: "pending"
end
end
def down do
alter table(:orders) do
remove :status
end
execute "DROP TYPE order_status"
end
Warning: Adding values to Postgres enums requires ALTER TYPE ... ADD VALUE which cannot run inside a transaction. Prefer :string + Ecto.Enum.
Child can't exist without parent (memberships, line items)
:nilify_all
Child should survive parent deletion (optional association)
:nothing
Handle in application code (default)
:restrict
Prevent parent deletion if children exist
Multi-Tenant Patterns
Every Table Gets tenant_id
def change do
create table(:items, primary_key: false) do
add :id, :binary_id, primary_key: true
add :name, :string, null: false
add :tenant_id, :binary_id, null: false
timestamps(type: :utc_datetime_usec)
end
# Always composite index with tenant_id first
create index(:items, [:tenant_id])
create unique_index(:items, [:tenant_id, :name])
end
Adding tenant_id to Existing Tables
def change do
alter table(:items) do
add :tenant_id, :binary_id
end
# Backfill in a separate data migration, then:
# alter table(:items) do
# modify :tenant_id, :binary_id, null: false
# end
end
Data Migrations
Rule: Never mix schema changes and data changes in the same migration.
Safe Data Migration Pattern
defmodule MyApp.Repo.Migrations.BackfillUserRoles do
use Ecto.Migration
# Don't use schema modules — they may change after this migration runs
def up do
execute """
UPDATE users SET role = 'member' WHERE role IS NULL
"""
end
def down do
# Data migrations may not be reversible
:ok
end
end
Batched Data Migration (large tables)
def up do
execute """
UPDATE users SET role = 'member'
WHERE id IN (
SELECT id FROM users WHERE role IS NULL LIMIT 10000
)
"""
# For very large tables, use a Task or Oban job instead
end
Reversible vs Irreversible
Reversible (use change)
These are auto-reversible:
create table ↔ drop table
add column ↔ remove column
create index ↔ drop index
rename ↔ rename
Irreversible (use up/down)
Must define both directions:
modify column type — Ecto can't infer the old type
execute raw SQL
Data backfills
Dropping columns with data
def up do
alter table(:users) do
modify :email, :citext, from: :string # from: helps reversibility
end
end
def down do
alter table(:users) do
modify :email, :string, from: :citext
end
end
Using modify with from:
Phoenix 1.7+ supports from: for reversible modify:
def change do
alter table(:users) do
modify :email, :citext, null: false, from: {:string, null: true}
end
end
PostgreSQL Extensions
def change do
execute "CREATE EXTENSION IF NOT EXISTS citext", "DROP EXTENSION IF EXISTS citext"
execute "CREATE EXTENSION IF NOT EXISTS pgcrypto", "DROP EXTENSION IF EXISTS pgcrypto"
execute "CREATE EXTENSION IF NOT EXISTS pg_trgm", "DROP EXTENSION IF EXISTS pg_trgm"
end
Enum Types (PostgreSQL native — use sparingly)
Prefer Ecto.Enum with :string columns. If you must use Postgres enums:
def up do
execute "CREATE TYPE order_status AS ENUM ('pending', 'confirmed', 'shipped', 'delivered')"
alter table(:orders) do
add :status, :order_status, null: false, default: "pending"
end
end
def down do
alter table(:orders) do
remove :status
end
execute "DROP TYPE order_status"
end
Warning: Adding values to Postgres enums requires ALTER TYPE ... ADD VALUE which cannot run inside a transaction. Prefer :string + Ecto.Enum.