Saltearse al contenido

Astro DB

Astro DB es una base de datos SQL de gestión integral diseñada exclusivamente para Astro. Desarrolla localmente o conéctate a una base de datos alojada gestionada en nuestra plataforma Astro Studio.

Añade Astro DB a un proyecto de Astro nuevo o existente (requiere astro@4.5 o posterior) con la integración @astrojs/db (v0.8.0 o posterior). Astro incluye un comando astro add incorporado para automatizar este proceso de configuración por ti.

Ventana de terminal
npx astro add db

Si lo prefieres, puedes instalar @astrojs/db manualmente en su lugar.

Astro DB es una solución completa para configurar, desarrollar y consultar tus datos. Se crea una base de datos local cada vez que ejecutas astro dev, utilizando LibSQL para administrar tus datos sin la necesidad de Docker o una conexión de red.

La instalación de @astrojs/db con el comando astro add creará un archivo db/config.ts en tu proyecto, donde definirás las tablas de tu base de datos:

db/config.ts
import { defineDb } from 'astro:db';
export default defineDb({
tables: { },
})

Los datos en Astro DB se almacenan utilizando tablas SQL. Las tablas estructuran tus datos en filas y columnas, donde las columnas hacen cumplir el tipo de cada valor de fila. Astro DB admite los siguientes tipos de columnas:

db/config.ts
const Comment = defineTable({
columns: {
// Una cadena de texto.
author: column.text(),
// Un valor entero.
likes: column.number(),
// Un valor verdadero o falso.
flagged: column.boolean(),
// Valores de fecha/hora consultados como objetos de fecha de JavaScript.
published: column.date(),
// Un objeto JSON sin tipo.
metadata: column.json(),
}
});

Las tablas potencian los tipados automáticos de TypeScript de Astro para tu contenido. Cuando defines una tabla, Astro generará y aplicará automáticamente una interfaz de TypeScript a la misma. El resultado es un soporte completo de TypeScript cuando consultas tus datos, incluyendo autocompletado de propiedades y comprobación de tipos.

Para configurar una tabla de base de datos individual, importa y utiliza las utilidades defineTable() y column de astro:db.

Este ejemplo configura una tabla Comment con columnas de texto requeridas para author y body y luego la pone disponible para tu proyecto a través de la exportación defineDb().

db/config.ts
import { defineDb, defineTable, column } from 'astro:db';
const Comment = defineTable({
columns: {
author: column.text(),
body: column.text(),
}
})
export default defineDb({
tables: { Comment },
})
Ver la referencia de configuración de la tabla para una referencia completa de las opciones de la tabla.

Las relaciones entre tablas son un patrón común en el diseño de bases de datos. Por ejemplo, una tabla Blog puede estar estrechamente relacionada con otras tablas como Comment, Author y Category.

Puedes definir estas relaciones entre tablas y guardarlas en el esquema de tu base de datos usando columnas de referencia. Para establecer una relación, necesitarás:

  • Una columna de identificador en la tabla referenciada. Esta suele ser una columna id con la propiedad primaryKey.
  • Una columna en la tabla base para almacenar el id referenciado. Esto utiliza la propiedad references para establecer una relación.

Este ejemplo muestra la columna authorId de una tabla Comment haciendo referencia a la columna id de una tabla Author.

db/config.ts
const Author = defineTable({
columns: {
id: column.number({ primaryKey: true }),
name: column.text(),
}
});
const Comment = defineTable({
columns: {
authorId: column.number({ references: () => Author.columns.id }),
content: column.text(),
}
});

En desarrollo, Astro utilizará la configuración de tu base de datos para generar tipos locales según tus esquemas. Estos se generarán frescos cada vez que se inicie el servidor de desarrollo, y te permitirán consultar y trabajar con la forma de tus datos con seguridad de tipos y autocompletado.

Para sembrar datos de desarrollo para pruebas y depuración en tu proyecto de Astro, crea un archivo db/seed.ts. Importa tanto el objeto db como cualquier tabla configurada desde astro:db. Utiliza la función db.insert() para proporcionar una matriz de objetos de datos de filas de tabla.

El siguiente ejemplo define dos filas de datos de desarrollo para una tabla Comment:

db/seed.ts
import { db, Comment } from 'astro:db';
export default async function() {
await db.insert(Comment).values([
{ authorId: 1, body: 'Espero que te guste Astro DB!' },
{ authorId: 2, body: 'Disfruta!'},
])
}

Tu servidor de desarrollo reiniciará automáticamente tu base de datos cada vez que este archivo cambie, regenerando tus tipos y sembrando tus datos de desarrollo desde seed.ts.

Puedes consultar tu base de datos desde cualquier página de Astro o endpoint en tu proyecto utilizando el ORM db proporcionado y el generador de consultas.

import { db } from 'astro:db';

Astro DB incluye un cliente incorporado de Drizzle ORM. No se requiere instalación ni configuración manual para usar el cliente. El cliente db de Astro DB se configura automáticamente para comunicarse con tu base de datos (local o remota) cuando ejecutas Astro. Utiliza la definición exacta de tu esquema de base de datos para consultas SQL seguras con tipos, y muestra errores de TypeScript cuando haces referencia a una columna o tabla que no existe.

El siguiente ejemplo selecciona todas las filas de una tabla Comentario. Esto devuelve la matriz completa de datos de desarrollo sembrados desde db/seed.ts, la cual luego está disponible para su uso en tu plantilla de página:

src/pages/index.astro
---
import { db, Comment } from 'astro:db';
const comentarios = await db.select().from(Comment);
---
<h2>Comentarios</h2>
{
comentarios.map(({ author, body }) => (
<article>
<p>Autor: {author}</p>
<p>{body}</p>
</article>
))
}
Consulta la referencia de API select() de Drizzle para obtener una descripción completa.

Para aceptar las entradas del usuario, como manejar solicitudes de formulario e insertar datos en tu base de datos alojada remotamente, configura tu proyecto Astro para el renderizado bajo demanda y añade un adaptador SSR para tu entorno de implementación.

Este ejemplo inserta una fila en una tabla Comment basada en una solicitud POST de formulario analizada:

src/pages/index.astro
---
import { db, Comment } from 'astro:db';
if (Astro.request.method === 'POST') {
// Analizar datos de formulario
const formData = await Astro.request.formData();
const author = formData.get('author');
const content = formData.get('content');
if (typeof author === 'string' && typeof content === 'string') {
// Insertar datos de formulario en un Comment
await db.insert(Comment).values({ author, content });
}
}
//Renderizar una nueva lista de comentarios en cada petición
const comments = await db.select().from(Comment);
---
<form method="POST" style="display: grid">
<label for="author">Autor</label>
<input id="author" name="author" />
<textarea name="content"></textarea>
<button type="submit">Enviar</button>
</form>
<!--renderizar `comments`-->

Puedes también consultar tu base de datos desde un endpoint de API. Este ejemplo elimina una fila de la tabla Comment utilizando el parámetro id.

src/pages/api/comments/[id].ts
import type { APIRoute } from "astro";
import { db, Comment } from 'astro:db';
export const DELETE: APIRoute = async (ctx) => {
await db.delete(Comment).where({ id: ctx.params.id });
return new Response(null, { status: 204 });
}

Consulta la referencia de API insert() de Drizzle para obtener una descripción completa.

Para consultar resultados de tabla por una propiedad específica, utiliza las opciones de Drizzle para selecciones parciales. Por ejemplo, añade una llamada .where() a tu consulta select() y pasa la comparación que deseas realizar.

El siguiente ejemplo consulta todas las filas en una tabla Comment que contienen la frase “Astro DB”. Utiliza el operador like() para verificar si una frase está presente dentro del body:

src/pages/index.astro
---
import { db, Comment, like } from 'astro:db';
const comments = await db.select().from(Comment).where(
like(Comment.body, '%Astro DB%')
);
---

Todas las utilidades de Drizzle para construir consultas están expuestas en el módulo astro:db. Esto incluye:

import { eq, gt, count, sql } from 'astro:db';

Puedes consultar datos relacionados de múltiples tablas utilizando un join SQL. Para crear una consulta join, extiende tu declaración db.select() con un operador join. Cada función acepta una tabla para unir y una condición para hacer coincidir filas entre las dos tablas.

Este ejemplo utiliza una función innerJoin() para unir los autores de Comentarios con su información de Autor relacionada basada en la columna authorId. Esto devuelve una matriz de objetos con cada fila de Autor y Comentario como propiedades de nivel superior:

src/pages/index.astro
---
import { db, eq, Comment, Author } from 'astro:db';
const comentarios = await db.select()
.from(Comment)
.innerJoin(Author, eq(Comment.authorId, Author.id));
---
<h2>Comentarios</h2>
{
comentarios.map(({ Author, Comment }) => (
<article>
<p>Autor: {Author.name}</p>
<p>{Comment.body}</p>
</article>
))
}

Consulta la referencia de joins de Drizzle para ver todos los operadores de join y opciones de configuración disponibles.

Todas las consultas a la base de datos remota se realizan como una solicitud de red. Es posible que necesites “agrupar” consultas en una sola transacción cuando realices un gran número de consultas, o para tener retrocesos automáticos si alguna consulta falla.

Este ejemplo siembra varias filas en una sola solicitud utilizando el método db.batch():

db/seed.ts
import { db, Author, Comment } from 'astro:db';
export default async function () {
let queries;
// Sembrar 100 comentarios de muestra en tu base de datos remota
// con una única solicitud de red.
for (let i = 0; i < 100; i++) {
queries.push(db.insert(Comment).values({ body: `Comentario test ${i}` }));
}
await db.batch(queries);
}

Consulta la documentación de Drizzle db.batch() para más detalles.

Característica de Studio

Astro DB puede conectarse a la plataforma Astro Studio para agregar rápidamente una base de datos alojada a tu proyecto. Puedes ver, gestionar y implementar nuevas bases de datos alojadas, todo desde el portal web de Astro Studio.

Hay dos formas de crear un proyecto en Astro Studio:

  1. A través del CLI de Astro Studio utilizando astro link
  2. A través de la interfaz de usuario web de Astro Studio

Para crear una nueva base de datos en la interfaz web de Astro Studio, haz clic en el botón “crear proyecto” en el encabezado y sigue las instrucciones presentadas. Astro Studio te guiará a través de los pasos necesarios, y al final del proceso tendrás una base de datos alojada configurada para tu proyecto.

Característica de Studio

El esquema de tu tabla cambiará con el tiempo a medida que tu proyecto crezca. Puedes probar cambios de configuración de forma segura localmente y subirlos a tu base de datos de Studio cuando implementes.

Cuando crees un proyecto de Studio desde el panel, tendrás la opción de crear una acción de CI de GitHub. Esto migrará automáticamente los cambios de esquema al fusionar con la rama principal de tu repositorio.

También puedes subir cambios de esquema a través del CLI usando el comando astro db push:

Ventana de terminal
npm run astro db push

Este comando verificará que los cambios puedan realizarse sin pérdida de datos y guiará sobre cambios de esquema recomendados para resolver conflictos. Si se debe realizar un cambio de esquema que rompa, añade la bandera --force-reset para restablecer todos los datos de producción.

Característica de Studio

Es posible que necesites subir datos a tu base de datos de Studio para sembrar o migrar datos. Puedes crear un archivo .ts con el módulo astro:db para escribir consultas seguras de tipos. Luego, ejecuta el archivo contra tu base de datos de Studio utilizando el comando astro db execute <ruta-del-archivo> --remote:

Los siguientes comentarios pueden ser sembrados utilizando el comando astro db execute db/seed.ts --remote:

db/seed.ts
import { Comment } from 'astro:db';
export default async function () {
await db.insert(Comment).values([
{ authorId: 1, body: 'Espero que disfrutes Astro DB!' },
{ authorId: 2, body: 'Disfruta!' },
])
}

Consulta la referencia del CLI para obtener una lista completa de comandos.

Característica de Studio

Por defecto, Astro utilizará un archivo de base de datos local cada vez que ejecutes los comandos dev o build. Las tablas se recrean desde cero cuando se ejecuta cada comando, y se insertarán datos de desarrollo sembrados.

Para conectarte a tu base de datos de Studio alojada, puedes añadir la bandera --remote. Usa esta bandera para implementaciones en producción y así tener acceso tanto de lectura como de escritura a tu base de datos de Studio. Esto te permitirá aceptar y persistir datos de usuario.

Ventana de terminal
# Compilar con una conexión remota
astro build --remote
# Desarrollar con una conexión remota
astro dev --remote

Para usar una conexión remota, necesitarás un token de aplicación para autenticarte con Studio. Visita el panel de Studio para obtener instrucciones sobre cómo crear y configurar un token.

Cuando estés listo para implementar, consulta nuestra guía de Implementación con una Conexión a Studio.

Construyendo integraciones de Astro DB

Sección titulada Construyendo integraciones de Astro DB

Las integraciones de Astro pueden extender los proyectos de los usuarios con tablas y datos sembrados adicionales de Astro DB.

Utiliza el método extendDb() en el gancho astro:db:setup para registrar configuraciones adicionales de Astro DB y archivos de semilla. El ayudante defineDbIntegration() proporciona soporte TypeScript y autocompletado para el gancho astro:db:setup.

my-integration/index.ts
import { defineDbIntegration } from '@astrojs/db/utils';
export default function MyIntegration() {
return defineDbIntegration({
name: 'my-astro-db-powered-integration',
hooks: {
'astro:db:setup': ({ extendDb }) => {
extendDb({
configEntrypoint: '@astronaut/my-package/config',
seedEntrypoint: '@astronaut/my-package/seed',
});
},
// Otros hooks...
},
});
}

Los archivos de configuración y semilla de integración siguen el mismo formato que sus equivalentes definidos por el usuario.

Operaciones seguras de tipos en integraciones

Sección titulada Operaciones seguras de tipos en integraciones

Mientras trabajas en integraciones, es posible que no puedas beneficiarte de los tipos de tabla generados por Astro exportados desde astro:db. Para obtener una seguridad completa de tipos, utiliza la utilidad asDrizzleTable() para crear un objeto de referencia de tabla que puedas utilizar para operaciones de base de datos.

Por ejemplo, dado una integración configurando la siguiente tabla de base de datos Mascotas:

my-integration/config.ts
import { defineDb, defineTable, column } from 'astro:db';
export const Mascotas = defineTable({
columns: {
name: column.text(),
species: column.text(),
},
});
export default defineDb({ tables: { Mascotas } });

El archivo de semilla puede importar Mascotas y utilizar asDrizzleTable() para insertar filas en tu tabla con verificación de tipos:

my-integration/seed.ts
import { asDrizzleTable } from '@astrojs/db/utils';
import { db } from 'astro:db';
import { Mascotas } from './config';
export default async function() {
const typeSafePets = asDrizzleTable('Mascotas', Mascotas);
await db.insert(typeSafePets).values([
{ name: 'Palomita', species: 'cat' },
{ name: 'Pan', species: 'dog' },
]);
}

El valor devuelto por asDrizzleTable('Mascotas', Mascotas) es equivalente a import { Mascotas } from 'astro:db', pero está disponible incluso cuando la generación de tipos de Astro no puede ejecutarse. Puedes usarlo en cualquier código de integración que necesite consultar o insertar en la base de datos.