---
name: migration_up
kind: function
lang: go
domain: infra
version: "1.0.0"
purity: impure
signature: "func MigrationUp(db *sql.DB, dir string) ([]Migration, error)"
description: "Lee los archivos .sql del directorio, crea la tabla _migrations si no existe, y ejecuta las migraciones pendientes en orden de version. Cada migracion corre en su propia transaccion. Retorna la lista de migraciones aplicadas en esta llamada."
tags: [migration, database, sql, schema, sqlite, apply, up]
uses_functions: [migration_parse_go_infra]
uses_types: [Migration_go_infra]
returns: [Migration_go_infra]
returns_optional: false
error_type: "error_go_core"
imports: ["database/sql", "fmt", "os", "path/filepath", "sort", "strings"]
params:
  - name: db
    desc: "conexion *sql.DB abierta a la base de datos SQLite donde aplicar las migraciones"
  - name: dir
    desc: "path al directorio que contiene los archivos .sql de migracion (ej: apps/my_app/migrations)"
output: "slice de Migration con las migraciones que fueron aplicadas en esta llamada (puede estar vacio si todo ya estaba aplicado)"
tested: true
tests:
  - "base de datos vacia aplica todas las migraciones"
  - "migraciones ya aplicadas se omiten"
  - "migracion con SQL invalido retorna error y deja las anteriores aplicadas"
  - "directorio sin archivos sql no aplica nada"
test_file_path: "functions/infra/migration_up_test.go"
file_path: "functions/infra/migration_up.go"
---

## Ejemplo

```go
db, _ := SQLiteOpen("", "apps/my_app/operations.db")
defer db.Close()

applied, err := MigrationUp(db, "apps/my_app/migrations")
if err != nil {
    log.Fatalf("migration failed: %v", err)
}
for _, m := range applied {
    fmt.Printf("Applied: %03d_%s\n", m.Version, m.Name)
}
// Applied: 001_create_users
// Applied: 002_add_roles
```

## Notas

Crea `_migrations` con `CREATE TABLE IF NOT EXISTS` — es idempotente. Cada migracion se ejecuta en una transaccion independiente: si falla la migracion 3, las 1 y 2 ya aplicadas permanecen. El `up_sql` y `down_sql` se guardan en `_migrations` para que el rollback funcione aunque el archivo sea modificado o eliminado posteriormente. SQLite con el driver mattn/go-sqlite3 soporta multiples sentencias en un solo `Exec`.
