Пропустить до содержимого

Astro DB

Astro DB — это полностью управляемая база данных SQL, специально разработанная для Astro. Разрабатывайте локально или подключайтесь к хостингу базы данных, управляемой на нашей платформе Astro Studio.

Добавьте Astro DB в новый или существующий проект Astro (требуется astro@4.5 или более поздняя версия) с помощью интеграции @astrojs/db (v0.8.1 или более поздняя версия). Astro включает встроенную команду astro add для автоматизации процесса установки.

Terminal window
npx astro add db

При желании вы можете установить @astrojs/db вручную.

Astro DB — это комплексное решение для конфигурирования, разработки и запроса ваших данных. Локальная база данных создается каждый раз, когда вы запускаете astro dev, используя LibSQL для управления вашими данными без необходимости использования Docker или сетевого подключения.

Установка @astrojs/db с помощью команды astro add создаст в вашем проекте файл db/config.ts, в котором вы определите таблицы вашей базы данных:

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

Данные в Astro DB хранятся с помощью таблиц SQL. Таблицы структурируют данные в строки и столбцы, где столбцы определяют тип значения каждой строки.

Когда вы определяете таблицу, Astro генерирует интерфейс TypeScript для запроса этой таблицы из вашего проекта. В результате вы получаете полную поддержку TypeScript при доступе к данным с автозаполнением свойств и проверкой типов.

Чтобы сконфигурировать таблицу базы данных, импортируйте и используйте утилиты defineTable() и column из astro:db.

В этом примере настраивается таблица Comment с необходимыми текстовыми колонками для author и body. Затем сделайте ее доступной для вашего проекта с помощью экспорта 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 },
})
См. справочник по конфигурации таблиц для полного описания параметров таблиц.

Данные в Astro DB хранятся с использованием таблиц SQL. Таблицы структурируют ваши данные в строки и столбцы, где столбцы определяют тип значения каждой строки. Astro DB поддерживает следующие типы столбцов:

db/config.ts
import { defineTable, column } from 'astro:db';
const Comment = defineTable({
columns: {
// Строка текста.
author: column.text(),
// Целочисленное значение.
likes: column.number(),
// Значение true или false.
flagged: column.boolean(),
// Значения даты/времени запрашиваются как объекты JavaScript Date.
published: column.date(),
// Нетипизированный JSON объект.
metadata: column.json(),
}
});
Смотрите справочник по столбцам таблицы для получения более подробной информации.

Отношения между таблицами являются распространенным шаблоном при проектировании баз данных. Например, таблица Blog может быть тесно связана с другими таблицами Comment, Author и Category.

Вы можете определить эти отношения между таблицами и сохранить их в схеме базы данных с помощью столбцов ссылок. Чтобы установить отношения, вам понадобятся:

  • Столбец идентификатора в целевой таблице. Обычно это столбец id со свойством primaryKey.
  • Столбец в базовой таблице для хранения ссылающегося id. Для этого используется свойство references, устанавливающее связь.

В этом примере столбец Comment таблицы authorId ссылается на столбец id таблицы 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(),
}
});

В процессе разработки Astro будет использовать конфигурацию вашей БД для создания локальных типов в соответствии с вашими схемами. Они будут генерироваться каждый раз при запуске dev-сервера и позволят вам запрашивать и работать с формой ваших данных с безопасностью типов и автозаполнением.

Чтобы поместить данные разработки для тестирования и отладки в ваш проект Astro, создайте файл db/seed.ts. Импортируйте объект db и любую сконфигурированную таблицу из astro:db. Используйте функцию db.insert() для создания массива объектов данных строк таблицы.

Следующий пример определяет две строки данных разработки для таблицы Comment:

db/seed.ts
import { db, Comment } from 'astro:db';
export default async function() {
await db.insert(Comment).values([
{ authorId: 1, body: 'Надеюсь, вам понравится Astro DB!' },
{ authorId: 2, body: 'Наслаждайтесь!'},
])
}

Ваш сервер разработки будет автоматически перезапускать вашу базу данных при каждом изменении этого файла, регенерируя ваши типы и заполняя ваши данные разработки из seed.ts.

Вы можете запросить вашу базу данных с любой страницы Astro или конечной точки в вашем проекте, используя предоставленные db ORM и конструктор запросов.

import { db } from 'astro:db';

Astro DB включает встроенный клиент Drizzle ORM. Для использования клиента не требуется установка или ручная настройка. Клиент Astro DB db автоматически настраивается на взаимодействие с вашей базой данных (локальной или удалённой), когда вы запускаете Astro. Он использует вашу точную конфигурацию схемы базы данных для безопасных типизированных SQL запросов с ошибками TypeScript, если вы ссылаетесь на несуществующий столбец или таблицу.

Следующий пример выбирает все строки таблицы Comment. Это возвращает полный массив заполненных данных разработки из db/seed.ts, который затем можно использовать в шаблоне страницы:

src/pages/index.astro
---
import { db, Comment } from 'astro:db';
const comments = await db.select().from(Comment);
---
<h2>Комментарии</h2>
{
comments.map(({ author, body }) => (
<article>
<p>Автор: {author}</p>
<p>{body}</p>
</article>
))
}
Полный обзор можно найти в справочнике по методу select() - Drizzle ORM.

Чтобы принимать пользовательский ввод, например, обрабатывать запросы форм и вставлять данные в удалённую базу данных, настройте проект Astro на рендеринг по запросу и добавьте адаптер SSR для вашей среды развёртывания.

В этом примере вставляется строка в таблицу Comment на основе обработанного запроса формы POST:

src/pages/index.astro
---
import { db, Comment } from 'astro:db';
if (Astro.request.method === 'POST') {
// парсинг данных формы
const formData = await Astro.request.formData();
const author = formData.get('author');
const content = formData.get('content');
if (typeof author === 'string' && typeof content === 'string') {
// вставляем данные формы в таблицу Comment
await db.insert(Comment).values({ author, content });
}
}
// выводим новый список комментариев при каждом запросе
const comments = await db.select().from(Comment);
---
<form method="POST" style="display: grid">
<label for="author">Автор</label>
<input id="author" name="author" />
<label for="content">Контент</label>
<textarea id="content" name="content"></textarea>
<button type="submit">Отправить</button>
</form>
<!--выводим `comments`-->

Вы также можете запросить базу данных из конечной точки API. В этом примере удаляется строка из таблицы Comment по параметру id:

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

Чтобы запросить результаты таблицы по определённому свойству, используйте опции Drizzle для частичных выборок. Например, добавьте вызов .where() к вашему запросу select() и передайте сравнение, которое вы хотите сделать.

Следующий пример запрашивает все строки в таблице Comment, содержащие фразу «Astro DB». Используйте оператор like(), чтобы проверить, присутствует ли фраза внутри 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%')
);
---

Все утилиты Drizzle для создания запросов доступны из модуля astro:db. Среди них:

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

Вы можете запрашивать связанные данные из нескольких таблиц с помощью SQL-запроса join. Чтобы создать запрос с объединением, расширьте оператор db.select() оператором объединения. Каждая функция принимает таблицу для объединения и условие для сопоставления строк между двумя таблицами.

В этом примере используется функция innerJoin() для объединения авторов Comment с их связанной информацией Author на основе столбца authorId. В результате возвращается массив объектов с каждой строкой Author и Comment в качестве свойств верхнего уровня:

src/pages/index.astro
---
import { db, eq, Comment, Author } from 'astro:db';
const comments = await db.select()
.from(Comment)
.innerJoin(Author, eq(Comment.authorId, Author.id));
---
<h2>Комментарии</h2>
{
comments.map(({ Author, Comment }) => (
<article>
<p>Автор: {Author.name}</p>
<p>{Comment.body}</p>
</article>
))
}

См. Справочник по соединениям Drizzle для всех доступных операторов соединения и параметров конфигурации.

Все удалённые запросы к базе данных выполняются как сетевой запрос. При выполнении большого количества запросов может потребоваться объединить их в одну транзакцию или обеспечить автоматический откат в случае неудачи какого-либо запроса.

В этом примере несколько строк обрабатываются одним запросом с помощью метода db.batch():

db/seed.ts
import { db, Author, Comment } from 'astro:db';
export default async function () {
const queries = [];
// Добавить 100 тестовых комментариев в вашу удалённую базу данных
// одним сетевым запросом.
for (let i = 0; i < 100; i++) {
queries.push(db.insert(Comment).values({ body: `Тестовый комментарий ${i}` }));
}
await db.batch(queries);
}

См. документацию по Drizzle db.batch() для получения дополнительной информации.

Особенность Studio

Astro DB может подключаться к платформе Astro Studio, чтобы быстро добавить хостинг базы данных в ваш проект. Вы можете просматривать, управлять и развёртывать новые хостинговые базы данных прямо из панели управления Astro Studio.

Чтобы создать новый проект, вы можете воспользоваться готовым шаблоном или обратиться к руководству Astro Studio.

Особенность Studio

Схема вашей таблицы будет изменяться со временем по мере роста вашего проекта. Вы можете безопасно тестировать изменения конфигурации локально и отправлять их в вашу базу данных Studio при развёртывании.

При создании проекта Studio из панели управления вы сможете создать действие CI GitHub. Это автоматически мигрирует изменения схемы при слиянии с основной веткой вашего репозитория.

Вы также можете отправлять изменения схемы через CLI, используя команду astro db push:

Terminal window
npm run astro db push

Эта команда проверит, можно ли внести изменения без потери данных, и подскажет, какие изменения схемы рекомендуется внести для разрешения конфликтов. Если изменение схемы должно быть выполнено, добавьте флаг --force-reset, чтобы сбросить все производственные данные.

Внесение критических изменений в схему

Заголовок раздела Внесение критических изменений в схему

Если вам необходимо изменить схему таблиц таким образом, чтобы она была несовместима с существующими данными, размещёнными в Astro Studio, вам придется перезагрузить свою производственную базу данных.

Чтобы отправить обновление схемы таблицы, содержащее разрушающее изменение, добавьте флаг --force-reset, чтобы сбросить все производственные данные:

Terminal window
npm run astro db push --remote --force-reset
Особенность Studio

Можно переименовать таблицу после загрузки схемы в Astro Studio.

Если у вас нет важных производственных данных, то вы можете сбросить базу данных, используя флаг --force-reset. Этот флаг сбросит все таблицы в базе данных и создаст новые, чтобы они точно соответствовали вашей текущей схеме.

Чтобы переименовать таблицу, сохранив при этом производственные данные, необходимо выполнить ряд необратимых изменений, чтобы безопасно перенести локальную схему в студию Astro.

В следующем примере таблица переименована из Comment в Feedback:

  1. В файле конфигурации базы данных добавьте свойство deprecated: true для таблицы, которую вы хотите переименовать:

    db/config.ts
    const Comment = defineTable({
    deprecated: true,
    columns: {
    author: column.text(),
    body: column.text(),
    }
    });
  2. Добавьте новую схему таблицы (точно соответствующую свойствам существующей таблицы) с новым именем:

    db/config.ts
    const Comment = defineTable({
    deprecated: true,
    columns: {
    author: column.text(),
    body: column.text(),
    }
    });
    const Feedback = defineTable({
    columns: {
    author: column.text(),
    body: column.text(),
    }
    });
  3. Отправьте изменения в Astro Studio с помощью команды astro db push --remote. Это добавит новую таблицу и пометит старую как устаревшую.

  4. Обновите любой локальный код проекта, чтобы использовать новую таблицу вместо старой. Возможно, вам также потребуется перенести данные в новую таблицу.

  5. Когда вы убедитесь, что старая таблица больше не используется в вашем проекте, вы можете удалить схему из вашего config.ts:

    db/config.ts
    const Comment = defineTable({
    deprecated: true,
    columns: {
    author: column.text(),
    body: column.text(),
    }
    });
    const Feedback = defineTable({
    columns: {
    author: column.text(),
    body: column.text(),
    }
    });
  6. Снова перейдите в Astro Studio с помощью astro db push --remote. Старая таблица будет удалена, останется только новая, переименованная таблица.

Особенность Studio

Вам может потребоваться отправить данные в вашу базу данных Studio для заполнения или миграции данных. Вы можете создать файл .ts с помощью модуля astro:db для написания типобезопасных запросов. Затем выполните этот файл в базе данных Studio с помощью команды astro db execute <file-path> --remote:

Следующие комментарии могут быть добавлены с использованием команды 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: 'Hope you like Astro DB!' },
{ authorId: 2, body: 'Enjoy!' },
])
}

См. Справочник по CLI для ознакомления с полным списком команд.

Особенность Studio

По умолчанию Astro использует локальный файл базы данных при выполнении команд dev или build. Таблицы создаются с нуля при выполнении каждой команды, и в них вставляются исходные данные для разработки.

Чтобы подключиться к вашей хостинговой базе данных Studio, вы можете добавить флаг --remote. Используйте этот флаг для развёртывания на производство с возможностью чтения и записи в вашу базу данных Studio. Это позволит вам принимать и сохранять данные пользователей.

Terminal window
# Сборка с удалённым подключением
astro build --remote
# Разработка с удалённым подключением
astro dev --remote

Чтобы использовать удалённое подключение, вам понадобится токен приложения для аутентификации в Studio. Инструкции по созданию и настройке токена можно найти на приборной панели Studio.

Когда вы будете готовы к развёртыванию, ознакомьтесь с нашим Руководством по развёртыванию с подключением к Studio.

Интеграции Astro позволяют расширить пользовательские проекты дополнительными таблицами и данными для заполнения Astro DB.

Используйте метод extendDb() в хуке astro:db:setup для регистрации дополнительных конфигурационных файлов Astro DB и файлов данных для заполнения. Вспомогательная функция defineDbIntegration() обеспечивает поддержку TypeScript и автозаполнение для хука 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',
});
},
// Другие интеграционные хуки...
},
});
}

Файлы конфигурации config и seed для интеграции следуют тому же формату, что и их пользовательские аналоги.

Типобезопасные операции в интеграциях

Заголовок раздела Типобезопасные операции в интеграциях

При работе над интеграциями вы можете не воспользоваться сгенерированными Astro типами таблиц, экспортированными из astro:db. Для обеспечения полной безопасности типов используйте утилиту asDrizzleTable() для создания объекта-ссылки на таблицу, который можно использовать для операций с базой данных.

Например, в интеграции задана следующая таблица базы данных Pets:

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

Файл данных может импортировать Pets и использовать asDrizzleTable() для вставки строк в вашу таблицу с проверкой типов:

my-integration/seed.ts
import { asDrizzleTable } from '@astrojs/db/utils';
import { db } from 'astro:db';
import { Pets } from './config';
export default async function() {
const typeSafePets = asDrizzleTable('Pets', Pets);
await db.insert(typeSafePets).values([
{ name: 'Мурка', species: 'кошка' },
{ name: 'Бублик', species: 'собака' },
]);
}

Значение, возвращаемое asDrizzleTable('Pets', Pets), эквивалентно import { Pets } из 'astro:db', но доступно даже тогда, когда генерация типов Astro не может быть запущена. Вы можете использовать его в любом коде интеграции, который требует запросов или вставок в базу данных.