Kyrux
Voltar

Migrations

O Kyrux inclui um sistema de migrations baseado em arquivos .sql numerados, com rastreamento automático de quais já foram aplicadas.

Como funciona

  • Arquivos .sql ficam em database/migrations/
  • O nome segue o padrão NNNN_descricao.sql (ex: 0001_create_users.sql)
  • A tabela kyrux_migrations rastreia o que já foi aplicado — criada automaticamente no primeiro migrate
  • Cada migration é aplicada uma única vez (idempotente)
  • Se a tabela já existe no banco mesmo que o arquivo tenha sido removido, apenas registra a migration sem reexecutar o SQL

Formato do arquivo de migration

Cada arquivo .sql pode conter duas seções separadas pelo marcador -- down:

-- up (implícito — tudo antes de "-- down")
CREATE TABLE IF NOT EXISTS posts (
    id         BIGSERIAL    PRIMARY KEY,
    titulo     VARCHAR(200) NOT NULL DEFAULT '',
    publicado  BOOLEAN      NOT NULL DEFAULT FALSE
);

CREATE UNIQUE INDEX IF NOT EXISTS posts_titulo_idx ON posts (titulo);

-- down
DROP INDEX IF EXISTS posts_titulo_idx;
DROP TABLE IF EXISTS posts;

A seção up é aplicada pelo migrate. A seção down é executada pelo removemigration all para desfazer o schema com segurança antes de remover o registro.

Gerar migrations automaticamente (makemigrations)

O comando lê todos os structs com kyrux:"pk" em apps/*/models/*.go, core/security/auth/*.go e core/admin/*.go (ignorando *_test.go — fixture de teste nunca é model de verdade), compara com o schema das migrations existentes e gera o SQL com as seções up e down automaticamente:

  • Tabela nova → CREATE TABLE completo (+ índices unique/fk).
  • Campo novo em model existente → ALTER TABLE ... ADD COLUMN (autodetectado).
  • Campo removido do model → a remoção não é gerada (perda de dados); o comando avisa e escreve a sugestão -- ALTER TABLE ... DROP COLUMN ...; comentada na migration, para você descomentar após revisar.
  • Renomear campo ou mudar tipo → migration manual (o detector veria um ADD + um aviso de coluna removida).
go run main.go makemigrations

Revise o arquivo gerado antes de aplicar — índices compostos, constraints e defaults personalizados devem ser ajustados manualmente.

Aplicar migrations (migrate)

go run main.go migrate

Aplica a seção up de todos os arquivos .sql ainda não registrados em kyrux_migrations. Múltiplas instruções SQL por arquivo são suportadas (separadas por ;).

Comportamento inteligente:

  • Se o arquivo SQL ainda existe: executa normalmente e registra
  • Se o arquivo foi removido mas a tabela existe no banco: apenas registra (evita erros de "table already exists")
  • Se já foi registrada: pula (status ~)

Remover uma migration (removemigration)

# Remove apenas do disco (permite regenerar a migration)
go run main.go removemigration 0001

# Executa a seção down, remove o registro do banco e apaga o arquivo
go run main.go removemigration 0001 all

O removemigration all executa as seguintes etapas em ordem:

  1. Lê o arquivo e extrai a seção -- down
  2. Executa o SQL de reversão no banco (ex: DROP TABLE IF EXISTS ...)
  3. Remove o registro de kyrux_migrations
  4. Apaga o arquivo do disco

Se o arquivo não tiver seção -- down, o comando aborta com uma mensagem indicando o que adicionar — nunca remove silenciosamente sem desfazer o schema.

Tipos SQL gerados

Tipo Go PostgreSQL MySQL / SQLite
string (sem size) TEXT TEXT
string + kyrux:"size:N" VARCHAR(N) VARCHAR(N)
int, int32 INTEGER INTEGER
int64 BIGINT INTEGER
float32, float64 DECIMAL DECIMAL
bool BOOLEAN BOOLEAN
time.Time TIMESTAMPTZ DATETIME
campo kyrux:"pk" BIGSERIAL PRIMARY KEY INTEGER PRIMARY KEY
campo kyrux:"unique" CREATE UNIQUE INDEX CREATE UNIQUE INDEX
campo kyrux:"fk:tabela" REFERENCES tabela(id) + CREATE INDEX idem

Para fk: a tabela referenciada precisa existir antes — declare o model referenciado primeiro ou em uma migration anterior.

Campos com ponteiro (*string, *int) são gerados sem NOT NULL. Campos não-ponteiro recebem NOT NULL DEFAULT <zero>.

Migrations manuais

Para alterações que o makemigrations não cobre (ALTER TABLE, índices compostos, dados iniciais), inclua sempre a seção down:

-- database/migrations/0003_add_slug_to_posts.sql
ALTER TABLE posts ADD COLUMN IF NOT EXISTS slug VARCHAR(200) NOT NULL DEFAULT '';

CREATE UNIQUE INDEX IF NOT EXISTS posts_slug_idx ON posts (slug);

-- down
DROP INDEX IF EXISTS posts_slug_idx;
ALTER TABLE posts DROP COLUMN IF EXISTS slug;

Execute com go run main.go migrate.

Estrutura do diretório

database/
└── migrations/
    ├── 0001_create_users.sql    ← incluída pelo framework (auth.User)
    ├── 0002_auto.sql            ← gerada por makemigrations
    └── 0003_add_slug.sql        ← escrita manualmente

makemigrations não gera migrations de ALTER TABLE — apenas cria novas tabelas. Para mudanças em tabelas existentes, escreva a migration manualmente.