Databases Migrations
Tags: migrations, node, mysql, beginners
Published: 2022-06-16 04:24:25

# Introdução
Esse trimestre estou estudando a disciplina de DBRE(Database Reliability Engineer) no curso de Pós Graduação [DevOps and Cloud Solutions do Mackenzie](https://www.mackenzie.br/pos-graduacao/especializacao/sao-paulo-higienopolis/tecnologia-da-informacao/devops-engineering-and-cloud-solutions) que está sendo ministrada pelo professor [Walter](https://www.linkedin.com/in/walterpcarvalho/) o qual solicitou um trabalho acadêmico sobre migrations. Então porque não escrever um pequeno artigo sobre esse assunto, let's go! ✍🏼

# Afinal que são databases Migrations?
Sendo bem direto ao ponto, migrations trata-se do gerenciamento de mudanças incrementais e reversíveis no seu _schema_(estrutura) de banco de dados, ou seja, um controle de versionamento do seu banco de dados em repositório de código como o [github](https://github.com/) por exemplo.

## O que é um seeder?
Seeders são semeadores, são utilizados para popular a base de dados. Normalmente é muito utilizado para inserir dados padrões no banco de dados para o funcionamento correto da aplicação ou para inserção de dados _fake_ em um ambiente de dev para execução de testes.

## Método Up()
O método **up** é utilizado para executar uma migration que foi criada e alterar propriamente dito o _schema_ do seu banco de dados. Criar uma nova coluna, criar uma nova tabela por exemplo.

## Médoto Down()
O método **down** é utilizado para reverter uma migration para a posição anterior, como se fosse um _rollback_ na estrutura do seu banco de dados. Remover uma coluna que foi criada, remover uma nova tabela que foi criada por exemplo.

# Mão na massa! 💻 
Para exemplificar tudo que foi dito até agora, vamos executar um projeto bem simples. Trata-se de uma aplicação de catálogo de livros, que foi escrita em [Node](https://nodejs.org/en/) utilizando como migrations a biblioteca [mysql-migrations] (https://www.npmjs.com/package/mysql-migrations), todos os detalhes estão no repositório no [github.com/santospedroh/dbre-migration](https://github.com/santospedroh/dbre-migration).

## Executando a migration inicial
Faça o clone do projeto executando o comando: `git clone https://github.com/santospedroh/dbre-migration.git` observe que existe um diretório chamado `src/migrations` e dentro dele temos dois arquivos: **1655316346150_create_table_books.js** e o **1655323973586_create_books.js**. Esse _hash_ numérico que vemos no início do nome do arquivo é um _timestamp_ o qual a migrations utiliza para fazer o controle de versionamento.

```shell
➜  migrations git:(main) ls -ltr
total 16
-rw-r--r--  1 santospedroh  staff  199 15 Jun 19:52 1655316346150_create_table_books.js
-rw-r--r--  1 santospedroh  staff  377 15 Jun 19:52 1655323973586_create_books.js
```

O arquivo `_create_table_books.js` trata-se da **migration** inicial com a criação da tabela de livros.

```javascript
module.exports = {
    "up": "CREATE TABLE books (id INT NOT NULL AUTO_INCREMENT, UNIQUE KEY id (id), capa TEXT, nome varchar(255), editora varchar(255), link TEXT)",
    "down": "DROP TABLE books"
}
```

O arquivo `_create_books.js` trata-se do **seeder** com a inserção de um registro de livro para a base não iniciar vazia. 

```javascript
module.exports = {
    "up": "INSERT INTO books (capa, nome, editora, link) VALUES ('https://lh3.googleusercontent.com/JvM0JKKuZNJMWAC5iZPm4j-mdS9ORpZbpEWzg0zmJ0i2_xgIcju0OLXJ-zmnvz_GtFFGHe9qZ9Dz-6W0u5fRLFQaRlOI_hGzbetw','Site Reliability Engineering','O Reilly Media','https://sre.google/books/');",
    "down": "DELETE FROM books WHERE nome='Site Reliability Engineering';"
}
```
Vou considerar que você já tem o [Docker](https://www.docker.com/) instalado em seu computador, caso você não tenha o docker instalado siga o passo a passo descrito no [README.md](https://github.com/santospedroh/dbre-migration#docker) do projeto.

Execute o seguinte comando docker: `docker run --rm -p 3306:3306 --name mysql -e MYSQL_ROOT_PASSWORD=rootpass -e MYSQL_USER=db_user -e MYSQL_PASSWORD=db_pass -e MYSQL_DATABASE=library -d mysql:5.6.51`

Este comando irá criar um container docker com banco de dados MySQL 5.6 onde executaremos as migrations e a aplicação irá utilizar.

```shell
➜  ~ docker ps
CONTAINER ID   IMAGE          COMMAND                  CREATED       STATUS       PORTS                    NAMES
0a806d5d41a8   mysql:5.6.51   "docker-entrypoint.s…"   2 hours ago   Up 2 hours   0.0.0.0:3306->3306/tcp   mysql
```

Agora para criar o _schema_ basta executar o comando: `node ./src/migration.js up`

![migration-up-step-1](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kz1mouwyrnyqkd8wgkff.gif)

Para executar a aplicação e verificar se deu tudo certo execute o comando: `node ./src/app_books.js`

![app-step-1](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xgvr44sok48s5dl6zmxg.gif)

## Alterando a aplicação, adicionando colunas na tabela
Agora vamos acessar a branch `release-1.0` do projeto o qual existe uma alteração que adiciona os novos campos **autor** e **número de páginas** para a entidade livros (tabela books).

### Criando a nova migration e o novo seeder
Será necessário criar mais uma migration, para adicionar as colunas na tabela e mais um seeder, para atualizar o registro exemplo do livro.

Para criar a nova migration execute: 

```shell
➜  migrations git:(main) node .src/migration.js add migration add_columns_books
```
Para criar o novo seeder execute:

```shell
➜  migrations git:(main) node .src/migration.js add seed add_autor_pags
```
Mais dois arquivos serão criados dentro do diretório `src/migrations` com os métodos **up** e **down**. 

![migration-step-2](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6cjs7t69utie7ouz9ac8.gif)

Precisamos inserir as instruções SQL nestes arquivos conforme abaixo:

O arquivo `_add_columns_books.js` trata-se da **migration** para adicionar as novas colunas.

```javascript
module.exports = {
    "up": "ALTER TABLE books ADD COLUMN autor varchar(255), ADD COLUMN num_pags INT",
    "down": "ALTER TABLE books DROP COLUMN autor, DROP COLUMN num_pags"
}
```

O arquivo `_add_autor_pags.js` trata-se do **seeder** com a inserção do autor e número de páginas para registro do livro. 

```javascript
module.exports = {
    "up": "UPDATE books SET autor='Betsy Beyer, Chris Jones, Jennifer Petoff, Niall Richard Murphy', num_pags=524 WHERE nome='Site Reliability Engineering';",
    "down": "UPDATE books SET autor=NULL, num_pags=NULL WHERE nome='Site Reliability Engineering';"
}
```

![migration-step-3](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hhp96jtttl8puobbn5oa.gif)

### Executando a nova migration
Agora para alterar o _schema_ basta executar novamente o comando: `node ./src/migration.js up`

![migration-step-4](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ezc6tyx1qg3i1ndx89wc.gif)

Para executar a aplicação e verificar se deu tudo certo execute o comando: `node ./src/app_books.js`

![app-step-2](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oo3ap0j6bzgxf4evpkp4.gif)

## Voltar versão anterior do schema
Para voltar para o estado anterior do schema do banco de dados basta executar o comando: `node ./src/migration.js down` 2 vezes, a primeira irá reverter o **seeder** com os dados dos campos autor e número de páginas e a segunda irá reverter a **migration** removendo as colunas autor e num_pags da tabela books.

```shell
➜  dbre-migration git:(release-1.0) ✗ node ./src/migration.js down
Run: true Type: DOWN: UPDATE books SET autor=NULL, num_pags=NULL WHERE nome='Site Reliability Engineering';
No more DOWN migrations to run
finished running migrations
➜  dbre-migration git:(release-1.0) ✗ node ./src/migration.js down
Run: true Type: DOWN: ALTER TABLE books DROP COLUMN autor, DROP COLUMN num_pags
No more DOWN migrations to run
finished running migrations
```

![migration-step-5](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m7nov2tdjp8sblcwwkc0.gif)

## Conclusão
Migrations é uma ótima maneira de versionar o schema da sua base de dados junto com o código fonte da sua aplicação no repositório git. Para este _hands-on_ eu utilizei a biblioteca do npm [mysql-migration](https://www.npmjs.com/package/mysql-migrations) que é bem simples porém vários frameworks em várias linguagens já tem suporte nativo a migrations.