Saltar al contenido principal

AstroDB y Turso

Instalación

  • Es necesario tener alguna integración para SSR, como Node o Cloudflare
#bunx astro add db cloudflare
bunx astro add db

Tablas

  • Se definen en el archivo de config.ts
db\config.ts
import { column, defineDb, defineTable, NOW } from "astro:db";

const User = defineTable({
  columns: {
    id: column.text({ primaryKey: true }),
    name: column.text(),
    email: column.text({ unique: true }),
    password: column.text(),
    role: column.text({ references: () => Role.columns.id, default: "user" }),
  },
});

const Role = defineTable({
  columns: {
    id: column.text({ primaryKey: true }),
    name: column.text(),
  },
});

const Product = defineTable({
  columns: {
    id: column.number({ primaryKey: true }),
    name: column.text(),
    price: column.number(),
    visible: column.boolean({ default: true }),
    updatedAt: column.date({ default: NOW }),
  },
});

// https://astro.build/db/config
export default defineDb({
  tables: {
    User,
    Role,
    Product,
  },
});

Seed

  • Solo funciona en local o pruebas de desarrollo
db\seed.ts
import { db, Role, User } from "astro:db";
import bcrypt from "bcryptjs";
import { v4 as UUID } from "uuid";

// https://astro.build/db/seed
export default async function seed() {
  const roles = [
    { id: "admin", name: "Admin" },
    { id: "user", name: "User" },
  ];

  const users = [
    {
      id: UUID(),
      name: "First Admin",
      email: "[email protected]",
      password: bcrypt.hashSync("123456"),
      role: "admin",
    },
  ];

  await db.insert(Role).values(roles);
  await db.insert(User).values(users);
}

Ejemplo uso

src\actions\index.ts
import { defineAction } from "astro:actions";
import { db, eq, User } from "astro:db";
import { z } from "astro:schema";
import bcrypt from "bcryptjs";
import { v4 as UUID } from "uuid";

export const register = defineAction({
  accept: "form",
  input: z.object({
    name: z.string().min(2).max(50),
    email: z.string().email(),
    password: z.string().min(6).max(50),
  }),
  handler: async ({ name, email, password }) => {
    // Check if email is already registered
    const [user] = await db.select().from(User).where(eq(User.email, email));
    if (user) throw new Error("Email already registered");

    // Create user
    await db.insert(User).values({
      id: UUID(),
      name,
      email,
      password: bcrypt.hashSync(password),
      role: "user",
    });

    return true;
  },
});

export const server = {
  register,
};
src\pages\api\posts\likes[id].ts
export const PUT: APIRoute = async ({ request, params }) => {
  const postId = params.id ?? "";
  const { likes = 0 } = await request.json();

  const posts = await db.select().from(Posts).where(eq(Posts.id, postId));

  if (posts.length === 0) {
    const newPost = {
      id: postId,
      likes: 0,
    };
    await db.insert(Posts).values(newPost);
    posts.push(newPost);
  }

  const post = posts.at(0)!;
  post.likes += Number(likes);
  await db.update(Posts).set(post).where(eq(Posts.id, postId));

  return new Response("Ok", { status: 200 });
};

Turso

  1. Crear base de datos en el dashboard de Turso
  2. Obtener URL y token de la nueva base de datos
  3. Pegar las variables en el archivo .env
.env
ASTRO_DB_REMOTE_URL=libsql://abc.turso.io
ASTRO_DB_APP_TOKEN=abc123
  1. Enviar cambios (nueva tabla, actualizaciones, etc.) a la base de datos
bun astro db push --remote
bun astro db push --remote --force-reset
  1. Usar la base de datos de la nube durante el desarrollo
bun dev --remote

Despliegue

  • El comando de despliegue a producción debe tener la bandera --remote
package.json
{
  "name": "astro-app",
  "scripts": {
    //"dev": "astro dev --remote",
    "build": "astro build --remote", // <=====
  },
  "dependencies": {
  }
}