Building Monica: construimos el navegador de base de datos que queríamos para Laravel
Mientras reconstruíamos Monica, creamos un pequeño navegador de base de datos de solo lectura para Laravel y decidimos publicarlo como un paquete independiente.
Este es otro artículo de la serie Building Monica, donde escribo sobre el proceso de reconstruir Monica desde cero. La mayoría de los artículos de esta serie tratarán probablemente sobre el producto en sí: las relaciones, los recordatorios, la personalización, las actividades, la privacidad y todas las preguntas que surgen al intentar representar la vida de las personas en un software. Pero reconstruir una aplicación grande también produce cosas más pequeñas por el camino. LaraDB es una de ellas.
Mientras trabajaba en Monica v3, me di cuenta de que pasaba mucho tiempo mirando directamente la base de datos. Esto no es especialmente raro cuando se construye una aplicación Laravel. Creas un contacto y compruebas qué se ha escrito. Creas una relación e inspeccionas las filas relacionadas. Cambias un recordatorio y verificas las fechas. Ejecutas una acción, actualizas los datos, sigues una clave foránea y repites el proceso muchas veces al día.
Ya existen muchas buenas formas de hacerlo. Tinker es útil, pero no es sencillo ni rápido de usar. Aplicaciones como TablePlus, DBeaver, phpMyAdmin o Adminer pueden ser muy útiles, pero no para una consulta rápida. Uso TablePlus con regularidad, sobre todo cuando necesito escribir consultas, editar datos o inspeccionar el esquema en detalle. Pero la mayor parte del tiempo, mientras desarrollaba Monica, no necesitaba una herramienta de gestión de bases de datos. Solo quería una forma rápida de ver qué había en la base de datos sin salir de la aplicación en la que ya estaba trabajando.
Esa fue la idea inicial detrás de LaraDB. Instalar una dependencia de desarrollo, visitar /db y ver la base de datos.
composer require --dev monicahq/laradb
Lo que obtienes es muy simple. Las tablas se muestran a la izquierda, las filas a la derecha, y la página se ejecuta dentro de la propia aplicación Laravel. LaraDB es compatible con SQLite, MySQL y MariaDB, y PostgreSQL.

Un navegador y no un gestor de bases de datos
La decisión más importante que tomamos fue mantener LaraDB de solo lectura. No tiene botón de editar, ni botón de eliminar, ni formulario de inserción, ni consola SQL. Las dos rutas que expone el paquete son rutas GET, y el paquete solo emite sentencias SELECT.
En parte es una decisión de seguridad, pero sobre todo es una cuestión de alcance. Ya existen herramientas maduras para gestionar bases de datos, y reproducir un subconjunto de sus funciones dentro de Laravel no haría que LaraDB fuese más útil para el problema que intentábamos resolver.
El paquete también evita aceptar identificadores o consultas arbitrarias procedentes del navegador. Una tabla solicitada debe existir primero en el esquema descubierto por el controlador. Los identificadores se escapan según el motor de base de datos. Los valores que se usan al seguir claves foráneas se pasan como parámetros vinculados. No hay una interfaz para enviar SQL arbitrario porque el SQL arbitrario no forma parte del propósito del paquete.
Una herramienta pequeña puede seguir siendo comprensible si tiene un trabajo muy preciso. LaraDB pretende responder qué hay actualmente en la base de datos y cómo se relacionan esas filas entre sí. No pretende convertirse en un sustituto de un cliente de base de datos completo.
Lo que acabamos necesitando
La interfaz refleja ese alcance limitado. LaraDB enumera las tablas del esquema actual y muestra sus filas en una tabla densa. Se indican los tipos de columna, se identifican las claves primarias y foráneas, los valores NULL se distinguen visualmente de las cadenas vacías, y los valores largos se truncan para que las columnas grandes de texto o JSON no vuelvan la página inservible.
Las claves foráneas resultaron ser una de las funciones más útiles para Monica. Si una columna referencia otra tabla, se puede seguir su valor directamente. Al hacer clic se abre la tabla referenciada, filtrada por la fila correspondiente. Esto es especialmente útil en Monica v3, porque cada vez más dominios se representan mediante relaciones explícitas entre varias tablas en lugar de registros grandes y autocontenidos.
La página también expone algo de contexto sobre la base de datos y la consulta actuales. Según lo que ponga a disposición el motor de base de datos, LaraDB puede mostrar el motor y su versión, el nombre de la base de datos, su tamaño, el número de índices y otros metadatos propios del motor. Para la página actual, también muestra la sentencia SQL que produjo el resultado y cuánto tardó la consulta.
También hay una representación en JSON de una tabla. Fue barata de añadir una vez separada la capa de base de datos del renderizado HTML, y ha resultado útil para inspeccionar datos fuera de la propia página.
El frontend es deliberadamente autónomo. El paquete incluye su propio CSS y su propio JavaScript, y no depende de la cadena de assets de la aplicación anfitriona. Instalar LaraDB no debería obligar a añadir una configuración de Tailwind, una dependencia de Alpine u otro paso de compilación a un proyecto existente.
La abstracción de la base de datos acabó siendo el trabajo de verdad
Mostrar filas en un navegador es sencillo. Dar soporte a SQLite, MySQL y PostgreSQL de forma coherente es donde acabó estando la mayor parte del trabajo interesante.
Los motores difieren bastante en la manera de exponer el esquema y los metadatos de la base de datos. Listar tablas, describir columnas, encontrar claves primarias, resolver claves foráneas, contar filas y obtener información a nivel de base de datos requieren consultas distintas según el motor. Incluso detalles como el escapado de identificadores hay que tratarlos correctamente en lugar de como una operación SQL genérica.
LaraDB oculta esas diferencias detrás de una pequeña interfaz de controlador. La capa de Laravel pide tablas, columnas, filas y metadatos sin necesidad de saber si la conexión subyacente es SQLite, MySQL o PostgreSQL.
Una parte simplificada del contrato tiene este aspecto:
public function listTables(): array;
public function getColumns(string $table): array;
public function getRowCount(
string $table,
?RowFilter $filter = null,
): int;
public function getRows(
string $table,
int $page,
int $perPage,
?RowFilter $filter = null,
): TablePage;
public function getForeignKeys(string $table): array;
Cada controlador de base de datos implementa esas operaciones de forma distinta, mientras que el resto de LaraDB trabaja con los objetos de resultado comunes que devuelve la interfaz.
Una consecuencia interesante de este diseño es que el núcleo del código que lee la base de datos no depende de Laravel en absoluto. Funciona directamente con PDO. Laravel se encarga del descubrimiento del paquete, la configuración, el enrutado y el renderizado, pero la inspección de la base de datos puede usarse por separado.
use LaraDb\DriverFactory;
$pdo = new PDO('sqlite:database.sqlite');
$driver = DriverFactory::fromPdo($pdo);
foreach ($driver->listTables() as $table) {
echo $table->name;
}
Solo lectura no es lo mismo que inofensivo
Que el paquete sea de solo lectura impide que corrompa la base de datos, pero no hace que exponer la base de datos sea inofensivo. Un navegador de base de datos puede revelar todas las filas de todas las tablas a cualquiera que pueda llegar hasta él, lo que evidentemente es un problema serio para una aplicación como Monica.
Por eso LaraDB está pensado para instalarse como dependencia de desarrollo.
composer require --dev monicahq/laradb
Un despliegue normal de producción con composer install --no-dev no contendrá el paquete. LaraDB también está desactivado por defecto fuera del entorno local, y sus rutas usan por defecto los middleware web y auth cuando están activadas.
Cosas pequeñas que salen de una reconstrucción grande
Cuando empecé la serie Building Monica, esperaba que la mayor parte de lo escrito se centrara en las grandes decisiones de arquitectura y de producto detrás de Monica v3. Eso seguirá siendo así. Pero también quiero documentar algunas de las herramientas e ideas más pequeñas que salen de la reconstrucción, porque también forman parte del trabajo.
LaraDB no es una parte importante de Monica v3, y no intenta convertirse en un producto importante por sí mismo. Es simplemente una pequeña herramienta de desarrollo que nos quitó una molestia recurrente. El paquete es útil precisamente porque su alcance es limitado, y me gustaría que siguiera siendo así.
Si trabajas con aplicaciones Laravel y a menudo abres un cliente de base de datos solo para inspeccionar lo que tu código acaba de escribir, puede que LaraDB también te resulte útil.
composer require --dev monicahq/laradb
Después visita /db.
El código fuente está disponible en github.com/monicahq/laradb.