Перейти к содержимому

23. Astro DB

Astro DB — это полноценная SQL-база данных, интегрированная непосредственно в экосистему Astro. Под капотом работает libSQL (форк SQLite от Turso), что обеспечивает высокую производительность как локально, так и в продакшне через Astro Studio.

Astro DB решает типичную проблему небольших проектов: нужна база данных, но настраивать отдельный сервис PostgreSQL или MySQL слишком накладно. Astro DB даёт вам:

  • Локальную SQLite-базу для разработки
  • Облачную libSQL-базу через Astro Studio для продакшна
  • Типобезопасный Drizzle ORM для запросов
  • Встроенные миграции и сидинг

Установка: npx astro add db

Схема базы данных описывается в специальном файле с помощью хелперов Astro DB:

db/config.ts
import { defineDb, defineTable, column } from 'astro:db';
const User = defineTable({
columns: {
id: column.number({ primaryKey: true }),
name: column.text(),
email: column.text({ unique: true }),
role: column.text({ default: 'user' }),
createdAt: column.date({ default: new Date() }),
},
});
const Post = defineTable({
columns: {
id: column.number({ primaryKey: true }),
title: column.text(),
slug: column.text({ unique: true }),
body: column.text(),
authorId: column.number({ references: () => User.columns.id }),
published: column.boolean({ default: false }),
publishedAt: column.date({ optional: true }),
},
});
const Comment = defineTable({
columns: {
id: column.number({ primaryKey: true }),
body: column.text(),
postId: column.number({ references: () => Post.columns.id }),
authorId: column.number({ references: () => User.columns.id }),
},
});
export default defineDb({
tables: { User, Post, Comment },
});

Файл сидинга запускается при astro dev для заполнения локальной базы тестовыми данными:

db/seed.ts
import { db, User, Post, Comment } from 'astro:db';
export default async function seed() {
await db.insert(User).values([
{ id: 1, name: 'Алексей', email: '[email protected]', role: 'admin' },
{ id: 2, name: 'Мария', email: '[email protected]', role: 'user' },
]);
await db.insert(Post).values([
{
id: 1,
title: 'Знакомство с Astro DB',
slug: 'astro-db-intro',
body: 'Astro DB — это...',
authorId: 1,
published: true,
publishedAt: new Date('2024-01-15'),
},
]);
}

Astro DB использует Drizzle ORM — типобезопасный SQL-конструктор запросов:

import { db, User, Post, Comment, eq, and, desc, count } from 'astro:db';
// SELECT — получение всех опубликованных постов
const posts = await db
.select()
.from(Post)
.where(eq(Post.published, true))
.orderBy(desc(Post.publishedAt));
// JOIN — посты с информацией об авторе
const postsWithAuthors = await db
.select({ post: Post, author: User })
.from(Post)
.innerJoin(User, eq(Post.authorId, User.id));
// INSERT — создание нового пользователя
const newUser = await db.insert(User).values({
name: 'Иван',
}).returning();
// UPDATE — обновление роли
await db.update(User)
.set({ role: 'moderator' })
.where(eq(User.email, '[email protected]'));
// DELETE — удаление комментария
await db.delete(Comment).where(eq(Comment.id, 42));
// Агрегация — подсчёт комментариев к посту
const [{ total }] = await db
.select({ total: count() })
.from(Comment)
.where(eq(Comment.postId, 1));
src/pages/api/posts.ts
import type { APIRoute } from 'astro';
import { db, Post } from 'astro:db';
export const GET: APIRoute = async () => {
const posts = await db.select().from(Post)
.where(eq(Post.published, true));
return new Response(JSON.stringify(posts), {
headers: { 'Content-Type': 'application/json' },
});
};

Для продакшна используется Astro Studio — облачный хостинг для libSQL баз. Подключение:

Окно терминала
npx astro db link # Связать проект с Astro Studio
npx astro db push # Применить изменения схемы
npx astro db execute src/db/migration.sql # Выполнить произвольный SQL