Digital Ocean es la plataforma que uso para hostear la mayoría de mis proyectos, incluido este blog, por lo que puedo recomendártelo sinceramente, usar este enlace no generará un costo extra sobre ti, me ayuda a mantener bajos los costos del blog y tú obtendrás $200 USD en crédito, válidos por 2 meses (60 días)
Índice del contenido
Tutorial de migraciones en Go con migrate
Tutorial de migraciones en Go con migrate
En frameworks como Django, las migraciones se crean automáticamente , a partir de los modelos. Sin embargo en lenguajes como go, siempre y cuando no estemos usando un ORM, las migraciones se realizarán de manera manual.
¿Qué es una migración de una base de datos?
Una migración es una abstracción para manejar el estado y los cambios que ocurren en una base de datos. En lugar de ejecutar las sentencias SQL una por una de manera manual, automatizamos el proceso escribiendo todo el SQL necesario y corriéndolo de manera automática.
Una migración consiste en dos archivos con instrucciones SQL:
- archivo up: Para realizar cambios en la base de datos
- archivo down: Para revertir cambios en la base de datos
Para este caso se llaman up y down, pero podrías ponerle cualquier otros nombres; como forward y backward, o adelante y atrás.
Por ejemplo:
Las migraciones son complementarias
Observa como las migraciones son reversibles y complementarias; una realiza una acción y la otra la elimina.
Siguiendo esta lógica podemos realizar cambios en la base de datos y luego revertirlos.
Estos dos archivos pueden ser generados automáticamente (como en el caso de Django, a partir de los modelos) o podemos escribirlos nosotros directamente en SQL, como en el caso de go.
Instalación de migrate
Para manejar las migraciones vamos a usar la herramienta una herramienta llamada migrate, escrita en go.
Migrate se descarga directo desde su sección releases en github .
curl -L https://github.com/golang-migrate/migrate/releases/download/v4.15.2/migrate.linux-amd64.tar.gz | tar xvz
mv migrate.linux-amd64 $GOPATH/bin/migrate
Tras esto deberás poder ver la versión que tienes instalada.
migrate -version
4.15.2
Creación de archivos de migración con migrate en Go
Para crear el par de archivos de migración, de los que te hable anteriormente, corremos el siguiente comando:
migrate create -seq -ext=.sql -dir=./migrations <nombre_de_la_migración>
Te explico que hace cada flag:
- seq: indica que será secuencial, para que empiece por 000001 y continue hasta 00000n; el total de migraciones que tengamos.
- dir: indicará el directorio
- ext: la extensión del archivo, en este caso sql
- Al final el nombre que queremos que tenga la migración. Yo usaré create_first_table para este ejemplo.
Tras la ejecución del comando, tendrás dos archivos de migración, uno con extensión .up.sql y el otro con extensión .down.sql dentro de la carpeta migrations.
ls
000001_create_first_table.up.sql 000001_create_first_table.down.sql
Estos archivos hay que editarlos de manera manual, y colocar en su interior las sentencias SQL que querramos.
Ejemplo de migraciones en go con postgres
Por ejemplo, para crear una hipotética tabla users en una base de datos en postgres:
Para el archivo up:
CREATE TABLE "users" ("id" serial NOT NULL PRIMARY KEY, "name" varchar(50) NOT NULL);
Y, para revertir lo anterior, está el archivo down:
DROP TABLE "users";
Nuevamente, aprecia como ambas instrucciones SQL son complementarias; una crea una tabla y la otra la elimina. Pero puedes poner más de una instrucción y estas pueden ser lo que quieras, un index, un constraint, una rutina, etc.
Ejecutar migraciones con migrate en Go
Hasta ahora solo hemos creado los archivos de migraciones, pero no le hemos hecho saber al programa donde está la base de datos.
Antes de realizar cualquier cambio en la base de datos necesitaremos indicarle la dirección de acceso, a esta última, en el siguiente formato [motor]://[usuario]:[contraseña]@[dominio]/[base de datos]
Y, obviamente, lo más cómodo y seguro será guardar esta dirección en una variable de entorno .
BASE_DE_DATOS=[motor]://[usuario]:[contraseña]@[dominio]/[base de datos]
Ahora ya tenemos una base de datos a la cual conectarnos.
Aplicar migraciones
Para aplicar todas las migraciones usaremos el comando up. Migrate detectará automáticamente la numeración y ejecutará todas las migraciones up en orden ascendente.
migrate -path=./migrations -database=$BASE_DE_DATOS up
Revetir migraciones
Por otro lado, para revertir todas las migraciones usaremos el comando down. Migrate detectará automáticamente la numeración y ejecutará todas las migraciones down en orden descendente.
migrate -path=./migrations -database=$BASE_DE_DATOS down
Ir a una migración específica
Mientras que, si queremos ir a una migración en específico, usaremos el comando goto seguido del número de migración al que queremos llevar la base de datos.
migrate -path=./migrations -database=$BASE_DE_DATOS goto <numero de migración>
Migrate detectará la migración activa y ejecutará las migraciones up or down correspondientes para llevar la base de datos a ese estado.
La tabla de migraciones
¿Y cómo sabe la herramienta en que migración se encuentra? Tras cada cambio que efectuemos a la base de datos, la herramienta migrate guardará el estado de nuestra base de datos en una tabla llamada schema_migrations que luce de la siguiente manera:
Columna version
Observa como la columna versión guarda el estado de la migración actual. De esta manera migrate registra en que versión de las migraciones se encuentra.
Columna dirty
Además, esta tabla también contiene una columna llamada dirty que índica si hubo algún conflicto en la migración. En este último caso será necesario repararlo manualmente y forzar un nuevo estado en la tabla.
migrate -path=./migrations -database=$BASE_DE_DATOS force 1
Migraciones a bases de datos remotas
La herramienta Migrate también soporta migraciones remotas tales como:
- Filesystem
- io/fs
- Go-Bindata
- pkger
- GitHub
- GitHub Enterprise
- Bitbucket
- Gitlab
- AWS S3
- Google Cloud Storage
Cada uno de estos endpoints requiere una sintaxis específica. Por ejemplo, el de Amazon S3 luce así:
migrate -source="s3://<bucket>/<path>" -database=$BASE_DE_DATOS up
Con esto ya sabes lo básico sobre migraciones y probablemente también valores mucho más herramientas y ORMs que se encargan de esto de manera automática, como Django , Ruby on Rails, South, etc.