# OGDB_forge — Documentação Técnica (Alto Nível)

Este documento descreve, em alto nível, os requisitos funcionais e não funcionais da classe OGDB_forge, responsável por operações de definição e evolução de esquema de banco de dados (DDL) no projeto. O objetivo é orientar como criar/remover tabelas, adicionar/modificar/remover colunas, trabalhar com chaves e índices, e aplicar padrões de campos, sem detalhar a implementação interna nem métodos privados.


## Visão Geral

A OGDB_forge fornece uma API de alto nível para:
- Criar e remover bases de dados (quando suportado) e tabelas;
- Definir colunas com tipos e restrições comuns (tamanho, nulo, padrão, auto incremento, unsigned);
- Definir chaves primárias e índices (incluindo únicos e índices customizados, inclusive compostos);
- Definir chaves estrangeiras durante a criação da tabela ou após, ao adicionar colunas;
- Renomear tabela e alterar estrutura existente (adicionar, modificar e remover colunas);
- Aplicar padrões de campos recorrentes (timestamps, soft deletes, user tracking) e índices associados.

Dependências e contexto:
- Opera sobre uma conexão $db, usando prefixo de tabela ($this->db->dbprefix) e escape de identificadores (para segurança de nomes);
- Utiliza utilitários como RawSql (por exemplo, CURRENT_TIMESTAMP) e ArrayHelper (para filtrar colunas já existentes);
- Destina-se a ser usada em migrações e rotinas de setup, não em fluxos transacionais de negócio.


## Requisitos Funcionais

1. Criar Banco de Dados (quando suportado)
   - Método: create_database($db_name)
   - Resultado: Cria uma nova base de dados e atualiza cache interno de nomes, quando aplicável.

2. Remover Banco de Dados (quando suportado)
   - Método: drop_database($db_name)
   - Resultado: Remove uma base de dados existente e ajusta caches, quando aplicável.

3. Criar Tabela
   - Métodos principais: add_field(), add_key(), primary(), index(), unique(), addForeignKey(), create_table($table, $if_not_exists = false, array $attributes = [], $temporary = false)
   - Fluxo típico:
     - Definir campos via add_field([...]);
     - Definir chaves primárias/índices via add_key()/primary()/index()/unique();
     - Opcionalmente definir chaves estrangeiras com addForeignKey();
     - Concluir com create_table('minha_tabela', true).
   - Observações:
     - Suporta criação condicional (IF NOT EXISTS) e tabelas temporárias;
     - Atributos de criação (ex.: ENGINE, CHARSET) podem ser passados em $attributes;
     - Processa chaves primárias, índices, índices únicos e chaves estrangeiras após a criação.

4. Remover Tabela
   - Método: drop_table($table, $if_exists = false)
   - Resultado: Remove a tabela informada; pode ser condicional (IF EXISTS).

5. Renomear Tabela
   - Método: rename_table($old, $new)
   - Resultado: Altera o nome da tabela por DDL (ALTER TABLE ... RENAME TO ...).

6. Adicionar Colunas
   - Métodos: add_field(), addColumns($table, $fields, ?$_after = null, $verifyIfExists = true, array $keys = []) e/ou add_column($table, $field, $_after = null)
   - Capacidades:
     - Adiciona uma ou várias colunas;
     - Pode posicionar colunas após outra (parâmetro after);
     - Pode verificar existência prévia para evitar erros (verifyIfExists = true);
     - Pode definir chaves/índices juntos via $keys (inclui primária, único e índices compostos);
     - Permite anexar metadado 'foreign' por coluna para posterior criação da constraint (tabela, campo referenciado, ON DELETE/ON UPDATE).

7. Modificar Colunas
   - Método: modify_column($table, $field)
   - Resultado: Altera definição de coluna(s) existente(s), como tipo, tamanho, nullability, default, etc.

8. Remover Colunas
   - Método: drop_column($table, $column)
   - Resultado: Remove uma coluna específica da tabela.

9. Chaves Primárias, Índices e Unicidade
   - Chave primária: add_key($field, true) ou primary([...]) para simples/composta;
   - Índices regulares: index($field|[...], ?$name) — permite nome customizado;
   - Índices únicos: unique($field|[...], ?$name) — gera CREATE UNIQUE INDEX;
   - Índices personalizados em massa: addIndexes([...]) — aceita formatos simples e avançados.

10. Chaves Estrangeiras
    - Durante a criação: addForeignKey($field|[...], $foreignTable, $foreignField|[...], $onDelete, $onUpdate);
    - Após adicionar coluna: addColumnWithForeignKey($table, $fieldDef, $column, $refTable, $refField = 'id', $onDelete = 'RESTRICT', $onUpdate = 'CASCADE');
    - Observações:
      - Nomes de constraints são gerados automaticamente (fk_<tabela>_<indice> ou fk_<tabela>_<coluna>);
      - Suporta chaves estrangeiras compostas.

11. Padrões de Campos (Atalhos)
    - addPattern('timestamps'|'soft_deletes'|'user_tracking')
    - Atalhos dedicados: timestamps(), softDeletes(), userTracking()
    - Efeitos típicos:
      - timestamps: adiciona date_reg e date_alter com defaults CURRENT_TIMESTAMP / ON UPDATE;
      - soft_deletes: adiciona deleted_at (nulo) e índice;
      - user_tracking: adiciona oper_reg e oper_alter (int, FK para tabela de empregados) e índices associados.

12. Tipos de Campos e Atributos Comuns
    - type: VARCHAR, INT, BIGINT, DATETIME, TEXT, etc. (compatíveis com o driver em uso);
    - constraint: tamanho/precisão (por exemplo, 255, 11, etc.);
    - null: true/false;
    - default: valor padrão (string, numérico, null, ou RawSql::currentTimestamp()/currentTimestampOnUpdate());
    - unsigned: true para tipos numéricos compatíveis;
    - auto_increment: true para chaves numéricas incrementais;
    - unique: suporte em atributos de campo e/ou via unique();
    - after: posicionar coluna após outra ao adicionar.


## Exemplos de Uso (alto nível)

1) Criar uma tabela com PK, índices e FKs

```php
$this->dbforge
    ->add_field([
        'id' => ['type' => 'INT', 'constraint' => 11, 'auto_increment' => true],
        'user_id' => ['type' => 'INT', 'constraint' => 11, 'null' => false],
        'email' => ['type' => 'VARCHAR', 'constraint' => 255, 'null' => false],
        'created_at' => ['type' => 'DATETIME', 'null' => true, 'default' => RawSql::currentTimestamp()],
    ])
    ->primary('id')
    ->unique('email')
    ->index(['user_id', 'created_at'])
    ->addForeignKey('user_id', 'users', 'id', 'CASCADE', 'CASCADE')
    ->create_table('user_emails', true);
```

2) Adicionar colunas com verificação e índices

```php
$this->dbforge->addColumns(
    'orders',
    [
        'status' => ['type' => 'VARCHAR', 'constraint' => 30, 'default' => 'pending', 'after' => 'total'],
        'external_id' => ['type' => 'VARCHAR', 'constraint' => 64]
    ],
    null,
    true,
    [
        'status' => 'index',
        'external_id' => 'unique'
    ]
);
```

3) Adicionar coluna + chave estrangeira

```php
$this->dbforge->addColumnWithForeignKey(
    'posts',
    ['category_id' => ['type' => 'INT', 'constraint' => 11, 'null' => true]],
    'category_id',
    'categories',
    'id',
    'SET NULL',
    'CASCADE'
);
```

4) Aplicar padrões de campos

```php
// created_at, updated_at
$this->dbforge->timestamps();

// deleted_at
$this->dbforge->softDeletes();

// oper_reg, oper_alter com FKs e índices
$this->dbforge->userTracking();
```

5) Modificar e remover colunas

```php
// Modificar tipo e default de uma coluna
$this->dbforge->modify_column('users', [
    'email' => ['name' => 'email', 'type' => 'VARCHAR', 'constraint' => 320, 'default' => null, 'null' => true]
]);

// Remover coluna
$this->dbforge->drop_column('users', 'legacy_flag');
```


## Requisitos Não Funcionais

- Segurança de Nomes:
  - Identificadores de tabela/coluna, índices e constraints são protegidos via escape de identificadores da conexão ($this->db->escape_identifiers). Evite concatenar SQL manualmente.

- Idempotência e Robustez:
  - create_table suporta if_not_exists;
  - addColumns permite verifyIfExists para evitar falhas ao reaplicar migrações;
  - Ao possível, usar chaves e índices via métodos dedicados para evitar duplicações.

- Compatibilidade:
  - A API assume um driver de banco compatível com as sintaxes utilizadas (ex.: MySQL/MariaDB). Alguns recursos podem depender de capacidades do SGBD (p.ex., comportamento de ON UPDATE CURRENT_TIMESTAMP, chaves estrangeiras com engine que suporte FKs).

- Consistência de Esquema:
  - Prefira definir PKs, índices e FKs pela OGDB_forge, para manter padrão de nomenclatura automática (ex.: fk_<tabela>_<indice> / uk_<tabela>_<campos> / idx_<tabela>_<campos>).

- Desempenho:
  - Criação de índices e constraints pode bloquear a tabela; planeje migrações fora de horários críticos;
  - Índices compostos e únicos devem ser criados com parcimônia para evitar degradação de escrita.

- Observabilidade:
  - A classe utiliza logs auxiliares (ex.: mensagens quando faltam definições) e segue configurações de debug do driver para retornar erros amigáveis.

- Padrões e Convenções:
  - Utilize addPattern para manter consistência de colunas padrão (datas, deleção lógica, rastreamento de usuário);
  - Prefira nomes explícitos para índices/constraints quando necessário via index($fields, $name) e unique($fields, $name).

- Migrações Seguras:
  - Sempre validar existência de colunas/tabelas antes de alterar/soltar quando reexecutando migrações;
  - Testar em ambiente de staging quando há alterações destrutivas (drop_column/drop_table).


## Referência Rápida da API (seleção)

- create_database($name), drop_database($name)
- add_field($spec), add_key($field, $primary = false)
- create_table($table, $if_not_exists = false, array $attributes = [], $temporary = false)
- drop_table($table, $if_exists = false), rename_table($old, $new)
- add_column($table, $field, $_after = null), addColumns($table, $fields, ?$_after = null, $verifyIfExists = true, array $keys = [])
- modify_column($table, $field), drop_column($table, $column)
- primary($fields), index($fields, ?$name = null), unique($fields, ?$name = null), addIndexes($indexes)
- addForeignKey($field, $foreignTable, $foreignField, $onDelete = 'RESTRICT', $onUpdate = 'RESTRICT')
- addColumnWithForeignKey($table, $field, $key, $refTable, $refField = 'id', $onDelete = 'RESTRICT', $onUpdate = 'CASCADE')
- addPattern('timestamps'|'soft_deletes'|'user_tracking'), timestamps(), softDeletes(), userTracking()


## Boas Práticas de Uso

- Construir a tabela com add_field()/primary()/index()/unique()/addForeignKey() e concluir com create_table();
- Em alterações incrementais, preferir addColumns() com verifyIfExists e definição de índices junto a $keys;
- Para valores padrão baseados no SGBD, preferir RawSql::currentTimestamp() e RawSql::currentTimestampOnUpdate();
- Manter consistência de tipos e tamanhos (ex.: INT(11) para IDs, VARCHAR com limites adequados, DATETIME para registros de auditoria);
- Nomear índices/constraints críticos para facilitar manutenção futura.


## Limitações e Considerações

- Alguns recursos dependem de suporte do SGBD/engine (FKs, ON UPDATE CURRENT_TIMESTAMP, etc.);
- Em bancos com restrições de rename/drop, a operação pode variar por driver;
- Em tabelas muito grandes, operações de alteração podem ser custosas; planejar janelas de manutenção.


---

Este documento cobre a intenção e uso de alto nível da OGDB_forge, suficiente para conduzir criação e evolução de esquemas no projeto, sem expor detalhes de implementação interna ou métodos privados. Caso precise de exemplos específicos de migração no contexto deste projeto, verifique a pasta de migrações em Modules/database/migrations.

# OGDB_forge — Documentação Técnica (Alto Nível)

Este documento descreve, em alto nível, os requisitos funcionais e não funcionais da classe OGDB_forge, responsável por operações de definição e evolução de esquema de banco de dados (DDL) no projeto. O objetivo é orientar como criar/remover tabelas, adicionar/modificar/remover colunas, trabalhar com chaves e índices, e aplicar padrões de campos, sem detalhar a implementação interna nem métodos privados.


## Visão Geral

A OGDB_forge fornece uma API de alto nível para:
- Criar e remover bases de dados (quando suportado) e tabelas;
- Definir colunas com tipos e restrições comuns (tamanho, nulo, padrão, auto incremento, unsigned);
- Definir chaves primárias e índices (incluindo únicos e índices customizados, inclusive compostos);
- Definir chaves estrangeiras durante a criação da tabela ou após, ao adicionar colunas;
- Renomear tabela e alterar estrutura existente (adicionar, modificar e remover colunas);
- Aplicar padrões de campos recorrentes (timestamps, soft deletes, user tracking) e índices associados.

Dependências e contexto:
- Opera sobre uma conexão $db, usando prefixo de tabela ($this->db->dbprefix) e escape de identificadores (para segurança de nomes);
- Utiliza utilitários como RawSql (por exemplo, CURRENT_TIMESTAMP) e ArrayHelper (para filtrar colunas já existentes);
- Destina-se a ser usada em migrações e rotinas de setup, não em fluxos transacionais de negócio.


## Requisitos Funcionais

1. Criar Banco de Dados (quando suportado)
   - Método: create_database($db_name)
   - Resultado: Cria uma nova base de dados e atualiza cache interno de nomes, quando aplicável.

2. Remover Banco de Dados (quando suportado)
   - Método: drop_database($db_name)
   - Resultado: Remove uma base de dados existente e ajusta caches, quando aplicável.

3. Criar Tabela
   - Métodos principais: add_field(), add_key(), primary(), index(), unique(), addForeignKey(), create_table($table, $if_not_exists = false, array $attributes = [], $temporary = false)
   - Fluxo típico:
     - Definir campos via add_field([...]);
     - Definir chaves primárias/índices via add_key()/primary()/index()/unique();
     - Opcionalmente definir chaves estrangeiras com addForeignKey();
     - Concluir com create_table('minha_tabela', true).
   - Observações:
     - Suporta criação condicional (IF NOT EXISTS) e tabelas temporárias;
     - Atributos de criação (ex.: ENGINE, CHARSET) podem ser passados em $attributes;
     - Processa chaves primárias, índices, índices únicos e chaves estrangeiras após a criação.

4. Remover Tabela
   - Método: drop_table($table, $if_exists = false)
   - Resultado: Remove a tabela informada; pode ser condicional (IF EXISTS).

5. Renomear Tabela
   - Método: rename_table($old, $new)
   - Resultado: Altera o nome da tabela por DDL (ALTER TABLE ... RENAME TO ...).

6. Adicionar Colunas
   - Métodos: add_field(), addColumns($table, $fields, ?$_after = null, $verifyIfExists = true, array $keys = []) e/ou add_column($table, $field, $_after = null)
   - Capacidades:
     - Adiciona uma ou várias colunas;
     - Pode posicionar colunas após outra (parâmetro after);
     - Pode verificar existência prévia para evitar erros (verifyIfExists = true);
     - Pode definir chaves/índices juntos via $keys (inclui primária, único e índices compostos);
     - Permite anexar metadado 'foreign' por coluna para posterior criação da constraint (tabela, campo referenciado, ON DELETE/ON UPDATE).

7. Modificar Colunas
   - Método: modify_column($table, $field)
   - Resultado: Altera definição de coluna(s) existente(s), como tipo, tamanho, nullability, default, etc.

8. Remover Colunas
   - Método: drop_column($table, $column)
   - Resultado: Remove uma coluna específica da tabela.

9. Chaves Primárias, Índices e Unicidade
   - Chave primária: add_key($field, true) ou primary([...]) para simples/composta;
   - Índices regulares: index($field|[...], ?$name) — permite nome customizado;
   - Índices únicos: unique($field|[...], ?$name) — gera CREATE UNIQUE INDEX;
   - Índices personalizados em massa: addIndexes([...]) — aceita formatos simples e avançados.

10. Chaves Estrangeiras
    - Durante a criação: addForeignKey($field|[...], $foreignTable, $foreignField|[...], $onDelete, $onUpdate);
    - Após adicionar coluna: addColumnWithForeignKey($table, $fieldDef, $column, $refTable, $refField = 'id', $onDelete = 'RESTRICT', $onUpdate = 'CASCADE');
    - Observações:
      - Nomes de constraints são gerados automaticamente (fk_<tabela>_<indice> ou fk_<tabela>_<coluna>);
      - Suporta chaves estrangeiras compostas.

11. Padrões de Campos (Atalhos)
    - addPattern('timestamps'|'soft_deletes'|'user_tracking')
    - Atalhos dedicados: timestamps(), softDeletes(), userTracking()
    - Efeitos típicos:
      - timestamps: adiciona date_reg e date_alter com defaults CURRENT_TIMESTAMP / ON UPDATE;
      - soft_deletes: adiciona deleted_at (nulo) e índice;
      - user_tracking: adiciona oper_reg e oper_alter (int, FK para tabela de empregados) e índices associados.

12. Tipos de Campos e Atributos Comuns
    - type: VARCHAR, INT, BIGINT, DATETIME, TEXT, etc. (compatíveis com o driver em uso);
    - constraint: tamanho/precisão (por exemplo, 255, 11, etc.);
    - null: true/false;
    - default: valor padrão (string, numérico, null, ou RawSql::currentTimestamp()/currentTimestampOnUpdate());
    - unsigned: true para tipos numéricos compatíveis;
    - auto_increment: true para chaves numéricas incrementais;
    - unique: suporte em atributos de campo e/ou via unique();
    - after: posicionar coluna após outra ao adicionar.


## Exemplos de Uso (alto nível)

1) Criar uma tabela com PK, índices e FKs

```php
$this->dbforge
    ->add_field([
        'id' => ['type' => 'INT', 'constraint' => 11, 'auto_increment' => true],
        'user_id' => ['type' => 'INT', 'constraint' => 11, 'null' => false],
        'email' => ['type' => 'VARCHAR', 'constraint' => 255, 'null' => false],
        'created_at' => ['type' => 'DATETIME', 'null' => true, 'default' => RawSql::currentTimestamp()],
    ])
    ->primary('id')
    ->unique('email')
    ->index(['user_id', 'created_at'])
    ->addForeignKey('user_id', 'users', 'id', 'CASCADE', 'CASCADE')
    ->create_table('user_emails', true);
```

2) Adicionar colunas com verificação e índices

```php
$this->dbforge->addColumns(
    'orders',
    [
        'status' => ['type' => 'VARCHAR', 'constraint' => 30, 'default' => 'pending', 'after' => 'total'],
        'external_id' => ['type' => 'VARCHAR', 'constraint' => 64]
    ],
    null,
    true,
    [
        'status' => 'index',
        'external_id' => 'unique'
    ]
);
```

3) Adicionar coluna + chave estrangeira

```php
$this->dbforge->addColumnWithForeignKey(
    'posts',
    ['category_id' => ['type' => 'INT', 'constraint' => 11, 'null' => true]],
    'category_id',
    'categories',
    'id',
    'SET NULL',
    'CASCADE'
);
```

4) Aplicar padrões de campos

```php
// created_at, updated_at
$this->dbforge->timestamps();

// deleted_at
$this->dbforge->softDeletes();

// oper_reg, oper_alter com FKs e índices
$this->dbforge->userTracking();
```

5) Modificar e remover colunas

```php
// Modificar tipo e default de uma coluna
$this->dbforge->modify_column('users', [
    'email' => ['name' => 'email', 'type' => 'VARCHAR', 'constraint' => 320, 'default' => null, 'null' => true]
]);

// Remover coluna
$this->dbforge->drop_column('users', 'legacy_flag');
```


## Requisitos Não Funcionais

- Segurança de Nomes:
  - Identificadores de tabela/coluna, índices e constraints são protegidos via escape de identificadores da conexão ($this->db->escape_identifiers). Evite concatenar SQL manualmente.

- Idempotência e Robustez:
  - create_table suporta if_not_exists;
  - addColumns permite verifyIfExists para evitar falhas ao reaplicar migrações;
  - Ao possível, usar chaves e índices via métodos dedicados para evitar duplicações.

- Compatibilidade:
  - A API assume um driver de banco compatível com as sintaxes utilizadas (ex.: MySQL/MariaDB). Alguns recursos podem depender de capacidades do SGBD (p.ex., comportamento de ON UPDATE CURRENT_TIMESTAMP, chaves estrangeiras com engine que suporte FKs).

- Consistência de Esquema:
  - Prefira definir PKs, índices e FKs pela OGDB_forge, para manter padrão de nomenclatura automática (ex.: fk_<tabela>_<indice> / uk_<tabela>_<campos> / idx_<tabela>_<campos>).

- Desempenho:
  - Criação de índices e constraints pode bloquear a tabela; planeje migrações fora de horários críticos;
  - Índices compostos e únicos devem ser criados com parcimônia para evitar degradação de escrita.

- Observabilidade:
  - A classe utiliza logs auxiliares (ex.: mensagens quando faltam definições) e segue configurações de debug do driver para retornar erros amigáveis.

- Padrões e Convenções:
  - Utilize addPattern para manter consistência de colunas padrão (datas, deleção lógica, rastreamento de usuário);
  - Prefira nomes explícitos para índices/constraints quando necessário via index($fields, $name) e unique($fields, $name).

- Migrações Seguras:
  - Sempre validar existência de colunas/tabelas antes de alterar/soltar quando reexecutando migrações;
  - Testar em ambiente de staging quando há alterações destrutivas (drop_column/drop_table).


## Referência Rápida da API (seleção)

- create_database($name), drop_database($name)
- add_field($spec), add_key($field, $primary = false)
- create_table($table, $if_not_exists = false, array $attributes = [], $temporary = false)
- drop_table($table, $if_exists = false), rename_table($old, $new)
- add_column($table, $field, $_after = null), addColumns($table, $fields, ?$_after = null, $verifyIfExists = true, array $keys = [])
- modify_column($table, $field), drop_column($table, $column)
- primary($fields), index($fields, ?$name = null), unique($fields, ?$name = null), addIndexes($indexes)
- addForeignKey($field, $foreignTable, $foreignField, $onDelete = 'RESTRICT', $onUpdate = 'RESTRICT')
- addColumnWithForeignKey($table, $field, $key, $refTable, $refField = 'id', $onDelete = 'RESTRICT', $onUpdate = 'CASCADE')
- addPattern('timestamps'|'soft_deletes'|'user_tracking'), timestamps(), softDeletes(), userTracking()


## Boas Práticas de Uso

- Construir a tabela com add_field()/primary()/index()/unique()/addForeignKey() e concluir com create_table();
- Em alterações incrementais, preferir addColumns() com verifyIfExists e definição de índices junto a $keys;
- Para valores padrão baseados no SGBD, preferir RawSql::currentTimestamp() e RawSql::currentTimestampOnUpdate();
- Manter consistência de tipos e tamanhos (ex.: INT(11) para IDs, VARCHAR com limites adequados, DATETIME para registros de auditoria);
- Nomear índices/constraints críticos para facilitar manutenção futura.


## Limitações e Considerações

- Alguns recursos dependem de suporte do SGBD/engine (FKs, ON UPDATE CURRENT_TIMESTAMP, etc.);
- Em bancos com restrições de rename/drop, a operação pode variar por driver;
- Em tabelas muito grandes, operações de alteração podem ser custosas; planejar janelas de manutenção.


---

Este documento cobre a intenção e uso de alto nível da OGDB_forge, suficiente para conduzir criação e evolução de esquemas no projeto, sem expor detalhes de implementação interna ou métodos privados. Caso precise de exemplos específicos de migração no contexto deste projeto, verifique a pasta de migrações em Modules/database/migrations.



## Guia Rápido (para iniciantes)

Para quem é: Devs que nunca usaram a OGDB_forge para criar/alterar tabelas.
O que você vai aprender: criar uma tabela, adicionar campos e índices, e rodar uma migração com segurança.

1) Crie uma tabela simples

```php
$this->dbforge
    ->add_field([
        'id' => ['type' => 'INT', 'constraint' => 11, 'auto_increment' => true],
        'name' => ['type' => 'VARCHAR', 'constraint' => 120, 'null' => false],
        'date_reg' => ['type' => 'DATETIME', 'null' => true, 'default' => RawSql::currentTimestamp()],
    ])
    ->primary('id')
    ->index('name')
    ->create_table('products', true);
```

2) Adicione um campo depois que a tabela já existe

```php
$this->dbforge->addColumns('products', [
    'sku' => ['type' => 'VARCHAR', 'constraint' => 64, 'after' => 'name']
], verifyIfExists: true, keys: [
    'sku' => 'unique' // cria índice único para sku
]);
```

3) Adicione uma chave estrangeira

```php
$this->dbforge->addColumnWithForeignKey(
    'products',
    ['category_id' => ['type' => 'INT', 'constraint' => 11, 'null' => true]],
    'category_id',
    'categories',
    'id',
    'SET NULL',
    'CASCADE'
);
```

4) Padrões prontos (timestamps/soft delete)

```php
$this->dbforge->timestamps();   // date_reg, date_alter
$this->dbforge->softDeletes();  // deleted_at
```

Dica: use verifyIfExists: true ao adicionar campos para migrações idempotentes.


## Receitas 80/20 (as mais usadas)

- Chave primária composta:
```php
$this->dbforge
  ->add_field([
    'order_id' => ['type' => 'INT', 'constraint' => 11],
    'product_id' => ['type' => 'INT', 'constraint' => 11],
  ])
  ->primary(['order_id', 'product_id'])
  ->create_table('order_items', true);
```

- Índice único com nome próprio:
```php
$this->dbforge->unique(['email'], 'uk_users_email');
```

- Índice composto:
```php
$this->dbforge->index(['user_id', 'created_at'], 'idx_user_created');
```

- Campo com default do SGBD (CURRENT_TIMESTAMP):
```php
'created_at' => ['type' => 'DATETIME', 'default' => RawSql::currentTimestamp()]
```


## Checklist de Migração Segura

Antes de aplicar:
- [ ] Rodou localmente em uma base de testes?
- [ ] addColumns(..., verifyIfExists: true) quando apropriado?
- [ ] Índices/uniqueness não conflitam com dados existentes?
- [ ] FK aponta para a tabela/coluna correta e engine suporta FKs?

Depois de aplicar:
- [ ] Índices foram criados? (SHOW INDEX / DESC tabela)
- [ ] Defaults/nullable conforme esperado?
- [ ] Aplicou em staging antes de produção?


## Troubleshooting (erros comuns)

- Erro de sintaxe/driver: verifique se o tipo/atributos existem no SGBD (ex.: MySQL/MariaDB) e se o escape de identificadores é respeitado.
- Não consigo recriar coluna já existente: use verifyIfExists: true em addColumns para pular colunas existentes.
- FK falha: confirme que os tipos e collation são compatíveis e que a tabela referenciada e o índice na PK existem.
- Índice duplicado: prefira unique()/index() com nomes determinísticos (uk_/idx_) ou faça verificação prévia.


## Glossário Rápido

- DDL: Data Definition Language (comandos para estruturar o banco).
- PK/UK/FK: Primary Key / Unique Key / Foreign Key.
- Idempotente: operação que pode ser repetida sem causar erro ou efeitos duplicados.
