Saltar al contenido
base de datos / · 4 min

Un esquema de Postgres por aplicacion, y la migracion que truena sin avisar

Laravel deja poner el search_path en una variable de entorno. Lo que no hace es crear el esquema, asi que la primera migracion falla con un mensaje que no menciona la palabra esquema.

Administrador · Desarrollador Laravel
Un esquema de Postgres por aplicacion, y la migracion que truena sin avisar

En mi punto de venta las tablas de Laravel no están en public. Están en un esquema llamado pos. En la aplicación que desplegué la semana pasada, en uno llamado hm_agency. Y las dos veces la primera migración falló.

Vale la pena, pero hay que saber dos cosas que la documentación menciona de pasada.

Qué es el search_path y por qué lo muevo

Postgres organiza las tablas en esquemas. Por omisión todo cae en public, que es el equivalente a dejar todos los archivos en el escritorio: funciona hasta que hay treinta.

Laravel lo expone directo en la configuración:

// config/database.php
'pgsql' => [
    // ...
    'search_path' => env('DB_SCHEMA', 'public'),
],

Con eso, en el .env:

DB_DATABASE=hm_agency
DB_SCHEMA=hm_agency

Lo que gano no es orden estético. Son tres cosas concretas:

Un pg_dump por aplicación, no por servidor. pg_dump --schema=pos me da exactamente las tablas de esa aplicación, sin arrastrar extensiones ni tablas de otra cosa que casualmente comparte la base.

Los permisos se otorgan por esquema. Un usuario de solo lectura para reportes se resuelve con un GRANT USAGE ON SCHEMA y no hay forma de que se asome a lo que no es suyo.

Las extensiones no se mezclan con tus tablas. PostGIS instala decenas de funciones y tablas de sistema. En public, conviven con las tuyas y un \dt deja de ser útil. Con PostGIS en public y la aplicación en su esquema, cada \dt pos.* enseña solo lo que escribiste tú.

La migración que truena

Aquí está el detalle que cuesta la tarde: Postgres no crea el esquema solo. Laravel tampoco. Pones DB_SCHEMA=hm_agency, corres php artisan migrate y obtienes esto:

SQLSTATE[3F000]: Invalid schema name: 7 ERROR: no schema has been selected to create in

El mensaje no dice "el esquema hm_agency no existe". Dice que no hay ninguno seleccionado, que suena a un problema de conexión. Se pierde tiempo buscando en el lugar equivocado.

La solución es una línea, pero tiene que correr antes de la primera migración. En un stack con Docker el lugar natural es el directorio de inicialización de Postgres, que la imagen oficial ejecuta la primera vez que arranca con el volumen vacío:

db:
  image: postgres:17-alpine
  volumes:
    - pgdata:/var/lib/postgresql/data
    - ./sql:/docker-entrypoint-initdb.d:ro

Y en sql/01_schema.sql:

CREATE SCHEMA IF NOT EXISTS hm_agency AUTHORIZATION hm;

Dos advertencias sobre ese directorio:

  • Solo corre con el volumen vacío. Si ya arrancaste la base una vez, agregar el archivo no hace nada. Hay que entrar con psql y crearlo a mano, o borrar el volumen si todavía no hay datos.
  • Si vas a restaurar un pg_dump, quita el montaje. El respaldo ya trae los CREATE, y el script de inicio los va a intentar de nuevo. Es una de esas fallas que solo aparecen al migrar de servidor, o sea el peor momento.

El tropiezo de cliente que nadie espera

Uno más, y este no tiene que ver con Laravel. Consulto esa base desde pgAdmin en Windows, a través del túnel SSH que trae integrado. La primera vez fallaba con autenticación password falló para el usuario pos, con la contraseña correcta.

Mi Windows tiene un PostgreSQL local escuchando en el 5432. Cuando el túnel no está activo, pgAdmin se conecta a ese y falla — pero el mensaje habla de credenciales, no de que estés hablando con el servidor equivocado.

Si alguna vez ves una contraseña buena rechazada, antes de dudar de la contraseña comprueba con quién estás hablando:

psql -h 127.0.0.1 -p 5432 -U pos -c "select inet_server_addr(), current_database();"

Si contesta y no es la máquina que crees, ya sabes.

#laravel #postgresql #arquitectura
Comentarios 0

Nadie ha comentado todavía. Estrena la sección.

Deja tu comentario
Tu correo no se publica. Reviso los comentarios antes de publicarlos.

Seguir leyendo