O que são Migrations e porque usa-las?
Tenho recebido muitas perguntas a respeito de migrations e acho que está na hora de abordar um pouco sobre isso.
Mesmo sendo um conceito simples, é realmente difícil ver desenvolvedores que se preocupam com isso e utilizam no dia a dia para tornar as aplicações mais parrudas e tolerante a falhas. Mas chega de papo, vamos lá…
O que são Migrations?
Migrations é basicamente uma forma de versionar o seu banco de dados. Uau Bruno, isso parece incrível, é como o GIT?
Bem, nem tanto. As migrations operam com três focos: Criação, Alteração e Remoção.
Dessa forma você consegue fazer alterações, criar ou mesmo remover coisas do seu banco de dados.
Mas quando eu digo remover, não digo a operação DELETE, para remover dados, eu estou querendo dizer a operação DROP, para deletar uma tabela, entende?
Porque usar Migrations?
Imagine o seguinte cenário: Você tem uma tabela no banco de dados da sua aplicação e precisa adicionar um campo novo. A maioria das pessoas poderia apenas ir direto no banco de dados e adicionar o campo lá. Mas e se você tem três ambientes? E se você não tem acesso ao banco? Tem inúmeros cenários que você simplesmente não pode chegar com a mão direto no banco e isso pode complicar.
Então neste caso o correto seria usar um script de “Alter Table” para adicionar este campo no banco de dados.
Dessa mesma forma, você pode programar um script de rollback para retornar o estado anterior da tabela. E é por isso que as migrations em geral tem duas funções:
- Up: É uma função para executar a sua mudança.
- Down: É uma função para desfazer as mudanças feitas na função Up
Veja um exemplo de Migrations
Abaixo vou deixar um exemplo de código de uma migration utilizando a biblioteca knex, em typescript.
Veja que na função UP eu faço uma alteração na tabela adicionando o campo estado e cidade. Já a função DOWN, eu uso para deletar essas colunas da tabela.
import * as Knex from "knex";
const tableName = "endereco"
export async function up(knex: Knex): Promise<void> {
const trx = await knex.transaction()
try {
await knex.schema.alterTable(tableName, table => {
table.string('estado');
table.string('cidade');
})
.transacting(trx)
trx.commit()
} catch(err){
console.log('error', err)
trx.rollback()
}
}
export async function down(knex: Knex): Promise<void> {
const trx = await knex.transaction()
try {
await knex.schema
.alterTable(tableName, table => {
table.dropColumn('estado')
table.dropColumn('cidade')
})
.transacting(trx)
trx.commit()
} catch (error) {
console.error(error)
trx.rollback()
}
}
Note que isso serve também para a criação de uma tabela, como no exemplo abaixo:
import Knex from 'knex'
export async function up (knex: Knex): Promise<void> {
const trx = await knex.transaction()
try {
await knex.schema.createTable('usuario', table => {
table.uuid('id').primary().notNullable()
table.string('cpf').notNullable()
table.string('nome').notNullable()
table.timestamps(true, true)
})
.transacting(trx)
trx.commit()
} catch(err){
console.log('error', err)
trx.rollback()
}
}
export async function down (knex: Knex): Promise<void> {
await knex.schema.dropTableIfExists('usuario')
}
Bem a conclusão é simples e clara: Usem migrations em todos os projetos que conseguirem. Isso vai garantir que seus projeto estejam com o banco de dados consistente. Inclusive quando se trata de empresas que tem mais de um desenvolvedor dedicado no mesmo projeto, é fundamental utilizar migrations para garantir a integridade né? Já pensou o seu projeto só funciona com um campo novo na tabela e o dev do seu time baixa o projeto e não tem essa informação. Tudo vai começar a quebrar e ele vai passar horas e horas tentando entender o motivo de tudo parar de funcionar.
Me conta aqui nos comentários se você curtiu e não se esquece de me seguir no Instagram para tirar qualquer dúvida que você tiver sobre typescript e desenvolvimento web, beleza?
Até a próxima e valeu!