diff options
author | 2025-06-05 14:25:23 +0000 | |
---|---|---|
committer | 2025-06-05 14:25:23 +0000 | |
commit | e586d7d704d475afe3373a1de6ae20d504f79d6d (patch) | |
tree | 7e3fa24807cebd48a86bd40f866d792181191ee9 /packages/db/test/fixtures | |
download | astro-latest.tar.gz astro-latest.tar.zst astro-latest.zip |
Sync from a8e1c0a7402940e0fc5beef669522b315052df1blatest
Diffstat (limited to 'packages/db/test/fixtures')
77 files changed, 1438 insertions, 0 deletions
diff --git a/packages/db/test/fixtures/basics/astro.config.ts b/packages/db/test/fixtures/basics/astro.config.ts new file mode 100644 index 000000000..983a6947d --- /dev/null +++ b/packages/db/test/fixtures/basics/astro.config.ts @@ -0,0 +1,10 @@ +import db from '@astrojs/db'; +import { defineConfig } from 'astro/config'; + +// https://astro.build/config +export default defineConfig({ + integrations: [db()], + devToolbar: { + enabled: false, + }, +}); diff --git a/packages/db/test/fixtures/basics/db/config.ts b/packages/db/test/fixtures/basics/db/config.ts new file mode 100644 index 000000000..010ed3a18 --- /dev/null +++ b/packages/db/test/fixtures/basics/db/config.ts @@ -0,0 +1,29 @@ +import { column, defineDb, defineTable } from 'astro:db'; +import { Themes } from './theme'; + +const Author = defineTable({ + columns: { + name: column.text(), + age2: column.number({ optional: true }), + }, +}); + +const User = defineTable({ + columns: { + id: column.text({ primaryKey: true, optional: false }), + username: column.text({ optional: false, unique: true }), + password: column.text({ optional: false }), + }, +}); + +const Session = defineTable({ + columns: { + id: column.text({ primaryKey: true, optional: false }), + expiresAt: column.number({ optional: false, name: 'expires_at' }), + userId: column.text({ optional: false, references: () => User.columns.id, name: 'user_id' }), + }, +}); + +export default defineDb({ + tables: { Author, Themes, User, Session }, +}); diff --git a/packages/db/test/fixtures/basics/db/seed.ts b/packages/db/test/fixtures/basics/db/seed.ts new file mode 100644 index 000000000..9a1ef4322 --- /dev/null +++ b/packages/db/test/fixtures/basics/db/seed.ts @@ -0,0 +1,24 @@ +import { Author, Session, User, db } from 'astro:db'; +import { asDrizzleTable } from '@astrojs/db/utils'; +import { Themes as ThemesConfig } from './theme'; + +const Themes = asDrizzleTable('Themes', ThemesConfig); +export default async function () { + await db.batch([ + db + .insert(Themes) + .values([{ name: 'dracula' }, { name: 'monokai', added: new Date() }]) + .returning({ name: Themes.name }), + db + .insert(Author) + .values([ + { name: 'Ben' }, + { name: 'Nate' }, + { name: 'Erika' }, + { name: 'Bjorn' }, + { name: 'Sarah' }, + ]), + db.insert(User).values([{ id: 'mario', username: 'Mario', password: 'itsame' }]), + db.insert(Session).values([{ id: '12345', expiresAt: new Date().valueOf(), userId: 'mario' }]), + ]); +} diff --git a/packages/db/test/fixtures/basics/db/theme.ts b/packages/db/test/fixtures/basics/db/theme.ts new file mode 100644 index 000000000..015dcc588 --- /dev/null +++ b/packages/db/test/fixtures/basics/db/theme.ts @@ -0,0 +1,15 @@ +import { NOW, column, defineTable, sql } from 'astro:db'; + +export const Themes = defineTable({ + columns: { + name: column.text(), + added: column.date({ + default: sql`CURRENT_TIMESTAMP`, + }), + updated: column.date({ + default: NOW, + }), + isDark: column.boolean({ default: sql`TRUE`, deprecated: true }), + owner: column.text({ optional: true, default: sql`NULL` }), + }, +}); diff --git a/packages/db/test/fixtures/basics/package.json b/packages/db/test/fixtures/basics/package.json new file mode 100644 index 000000000..af7cbe229 --- /dev/null +++ b/packages/db/test/fixtures/basics/package.json @@ -0,0 +1,14 @@ +{ + "name": "@test/db-aliases", + "version": "0.0.0", + "private": true, + "scripts": { + "dev": "astro dev", + "build": "astro build", + "preview": "astro preview" + }, + "dependencies": { + "@astrojs/db": "workspace:*", + "astro": "workspace:*" + } +} diff --git a/packages/db/test/fixtures/basics/src/pages/index.astro b/packages/db/test/fixtures/basics/src/pages/index.astro new file mode 100644 index 000000000..2be0c4b23 --- /dev/null +++ b/packages/db/test/fixtures/basics/src/pages/index.astro @@ -0,0 +1,27 @@ +--- +/// <reference path="../../.astro/db-types.d.ts" /> +import { Author, Themes, db } from 'astro:db'; + +const authors = await db.select().from(Author); +const themes = await db.select().from(Themes); +--- + +<h2>Authors</h2> +<ul class="authors-list"> + {authors.map((author) => <li>{author.name}</li>)} +</ul> + +<h2>Themes</h2> +<ul class="themes-list"> + { + themes.map((theme) => ( + <li> + <div class="theme-name">{theme.name}</div> + <div class="theme-added">{theme.added}</div> + <div class="theme-updated">{theme.updated}</div> + <div class="theme-dark">{theme.isDark ? 'dark' : 'light'} mode</div> + <div class="theme-owner">{theme.owner}</div> + </li> + )) + } +</ul> diff --git a/packages/db/test/fixtures/basics/src/pages/login.astro b/packages/db/test/fixtures/basics/src/pages/login.astro new file mode 100644 index 000000000..4551fc483 --- /dev/null +++ b/packages/db/test/fixtures/basics/src/pages/login.astro @@ -0,0 +1,18 @@ +--- +import { Session, User, db, eq } from 'astro:db'; + +const users = await db.select().from(User); +const sessions = await db.select().from(Session).innerJoin(User, eq(Session.userId, User.id)); +--- + +<h2>Sessions</h2> +<ul class="sessions-list"> + { + sessions.map(({ Session, User }) => ( + <li> + <div class="session-id">{Session.id}</div> + <div class="username">{User.username}</div> + </li> + )) + } +</ul> diff --git a/packages/db/test/fixtures/basics/src/pages/run.json.ts b/packages/db/test/fixtures/basics/src/pages/run.json.ts new file mode 100644 index 000000000..a86619314 --- /dev/null +++ b/packages/db/test/fixtures/basics/src/pages/run.json.ts @@ -0,0 +1,12 @@ +import { db, sql } from 'astro:db'; +/// <reference types="@astrojs/db" /> +import type { APIRoute } from 'astro'; + +export const GET: APIRoute = async () => { + const authors = await db.run(sql`SELECT * FROM Author`); + return new Response(JSON.stringify(authors), { + headers: { + 'content-type': 'application/json', + }, + }); +}; diff --git a/packages/db/test/fixtures/db-in-src/astro.config.ts b/packages/db/test/fixtures/db-in-src/astro.config.ts new file mode 100644 index 000000000..983a6947d --- /dev/null +++ b/packages/db/test/fixtures/db-in-src/astro.config.ts @@ -0,0 +1,10 @@ +import db from '@astrojs/db'; +import { defineConfig } from 'astro/config'; + +// https://astro.build/config +export default defineConfig({ + integrations: [db()], + devToolbar: { + enabled: false, + }, +}); diff --git a/packages/db/test/fixtures/db-in-src/db/config.ts b/packages/db/test/fixtures/db-in-src/db/config.ts new file mode 100644 index 000000000..44c15abe7 --- /dev/null +++ b/packages/db/test/fixtures/db-in-src/db/config.ts @@ -0,0 +1,13 @@ +import { column, defineDb, defineTable } from 'astro:db'; + +const User = defineTable({ + columns: { + id: column.text({ primaryKey: true, optional: false }), + username: column.text({ optional: false, unique: true }), + password: column.text({ optional: false }), + }, +}); + +export default defineDb({ + tables: { User }, +}); diff --git a/packages/db/test/fixtures/db-in-src/db/seed.ts b/packages/db/test/fixtures/db-in-src/db/seed.ts new file mode 100644 index 000000000..a84e63454 --- /dev/null +++ b/packages/db/test/fixtures/db-in-src/db/seed.ts @@ -0,0 +1,8 @@ +import { User, db } from 'astro:db'; +import { asDrizzleTable } from '@astrojs/db/utils'; + +export default async function () { + await db.batch([ + db.insert(User).values([{ id: 'mario', username: 'Mario', password: 'itsame' }]), + ]); +} diff --git a/packages/db/test/fixtures/db-in-src/package.json b/packages/db/test/fixtures/db-in-src/package.json new file mode 100644 index 000000000..a1580d1cb --- /dev/null +++ b/packages/db/test/fixtures/db-in-src/package.json @@ -0,0 +1,14 @@ +{ + "name": "@test/db-db-in-src", + "version": "0.0.0", + "private": true, + "scripts": { + "dev": "astro dev", + "build": "astro build", + "preview": "astro preview" + }, + "dependencies": { + "@astrojs/db": "workspace:*", + "astro": "workspace:*" + } +} diff --git a/packages/db/test/fixtures/db-in-src/pages/index.astro b/packages/db/test/fixtures/db-in-src/pages/index.astro new file mode 100644 index 000000000..4b79dba2c --- /dev/null +++ b/packages/db/test/fixtures/db-in-src/pages/index.astro @@ -0,0 +1,11 @@ +--- +/// <reference path="../.astro/db-types.d.ts" /> +import { User, db } from 'astro:db'; + +const users = await db.select().from(User); +--- + +<h2>Users</h2> +<ul class="users-list"> + {users.map((user) => <li>{user.username}</li>)} +</ul> diff --git a/packages/db/test/fixtures/error-handling/astro.config.ts b/packages/db/test/fixtures/error-handling/astro.config.ts new file mode 100644 index 000000000..983a6947d --- /dev/null +++ b/packages/db/test/fixtures/error-handling/astro.config.ts @@ -0,0 +1,10 @@ +import db from '@astrojs/db'; +import { defineConfig } from 'astro/config'; + +// https://astro.build/config +export default defineConfig({ + integrations: [db()], + devToolbar: { + enabled: false, + }, +}); diff --git a/packages/db/test/fixtures/error-handling/db/config.ts b/packages/db/test/fixtures/error-handling/db/config.ts new file mode 100644 index 000000000..bd4d6edaf --- /dev/null +++ b/packages/db/test/fixtures/error-handling/db/config.ts @@ -0,0 +1,26 @@ +import { column, defineDb, defineTable } from 'astro:db'; + +const Recipe = defineTable({ + columns: { + id: column.number({ primaryKey: true }), + title: column.text(), + description: column.text(), + }, +}); + +const Ingredient = defineTable({ + columns: { + id: column.number({ primaryKey: true }), + name: column.text(), + quantity: column.number(), + recipeId: column.number(), + }, + indexes: { + recipeIdx: { on: 'recipeId' }, + }, + foreignKeys: [{ columns: 'recipeId', references: () => [Recipe.columns.id] }], +}); + +export default defineDb({ + tables: { Recipe, Ingredient }, +}); diff --git a/packages/db/test/fixtures/error-handling/db/seed.ts b/packages/db/test/fixtures/error-handling/db/seed.ts new file mode 100644 index 000000000..1ca219f15 --- /dev/null +++ b/packages/db/test/fixtures/error-handling/db/seed.ts @@ -0,0 +1,62 @@ +import { Ingredient, Recipe, db } from 'astro:db'; + +export default async function () { + const pancakes = await db + .insert(Recipe) + .values({ + title: 'Pancakes', + description: 'A delicious breakfast', + }) + .returning() + .get(); + + await db.insert(Ingredient).values([ + { + name: 'Flour', + quantity: 1, + recipeId: pancakes.id, + }, + { + name: 'Eggs', + quantity: 2, + recipeId: pancakes.id, + }, + { + name: 'Milk', + quantity: 1, + recipeId: pancakes.id, + }, + ]); + + const pizza = await db + .insert(Recipe) + .values({ + title: 'Pizza', + description: 'A delicious dinner', + }) + .returning() + .get(); + + await db.insert(Ingredient).values([ + { + name: 'Flour', + quantity: 1, + recipeId: pizza.id, + }, + { + name: 'Eggs', + quantity: 2, + recipeId: pizza.id, + }, + { + name: 'Milk', + quantity: 1, + recipeId: pizza.id, + }, + { + name: 'Tomato Sauce', + quantity: 1, + recipeId: pizza.id, + }, + ]); +} diff --git a/packages/db/test/fixtures/error-handling/package.json b/packages/db/test/fixtures/error-handling/package.json new file mode 100644 index 000000000..e0839956b --- /dev/null +++ b/packages/db/test/fixtures/error-handling/package.json @@ -0,0 +1,14 @@ +{ + "name": "@test/error-handling", + "version": "0.0.0", + "private": true, + "scripts": { + "dev": "astro dev", + "build": "astro build", + "preview": "astro preview" + }, + "dependencies": { + "@astrojs/db": "workspace:*", + "astro": "workspace:*" + } +} diff --git a/packages/db/test/fixtures/error-handling/src/pages/foreign-key-constraint.json.ts b/packages/db/test/fixtures/error-handling/src/pages/foreign-key-constraint.json.ts new file mode 100644 index 000000000..358a9a95c --- /dev/null +++ b/packages/db/test/fixtures/error-handling/src/pages/foreign-key-constraint.json.ts @@ -0,0 +1,18 @@ +import { Ingredient, db, isDbError } from 'astro:db'; +import type { APIRoute } from 'astro'; + +export const GET: APIRoute = async () => { + try { + await db.insert(Ingredient).values({ + name: 'Flour', + quantity: 1, + // Trigger foreign key constraint error + recipeId: 42, + }); + } catch (e) { + if (isDbError(e)) { + return new Response(JSON.stringify({ message: `LibsqlError: ${e.message}`, code: e.code })); + } + } + return new Response(JSON.stringify({ message: 'Did not raise expected exception' })); +}; diff --git a/packages/db/test/fixtures/integration-only/astro.config.mjs b/packages/db/test/fixtures/integration-only/astro.config.mjs new file mode 100644 index 000000000..23f52739e --- /dev/null +++ b/packages/db/test/fixtures/integration-only/astro.config.mjs @@ -0,0 +1,8 @@ +import db from '@astrojs/db'; +import { defineConfig } from 'astro/config'; +import testIntegration from './integration'; + +// https://astro.build/config +export default defineConfig({ + integrations: [db(), testIntegration()], +}); diff --git a/packages/db/test/fixtures/integration-only/integration/config.ts b/packages/db/test/fixtures/integration-only/integration/config.ts new file mode 100644 index 000000000..71490be95 --- /dev/null +++ b/packages/db/test/fixtures/integration-only/integration/config.ts @@ -0,0 +1,8 @@ +import { defineDb } from 'astro:db'; +import { menu } from './shared'; + +export default defineDb({ + tables: { + menu, + }, +}); diff --git a/packages/db/test/fixtures/integration-only/integration/index.ts b/packages/db/test/fixtures/integration-only/integration/index.ts new file mode 100644 index 000000000..b249cc253 --- /dev/null +++ b/packages/db/test/fixtures/integration-only/integration/index.ts @@ -0,0 +1,15 @@ +import { defineDbIntegration } from '@astrojs/db/utils'; + +export default function testIntegration() { + return defineDbIntegration({ + name: 'db-test-integration', + hooks: { + 'astro:db:setup'({ extendDb }) { + extendDb({ + configEntrypoint: './integration/config.ts', + seedEntrypoint: './integration/seed.ts', + }); + }, + }, + }); +} diff --git a/packages/db/test/fixtures/integration-only/integration/seed.ts b/packages/db/test/fixtures/integration-only/integration/seed.ts new file mode 100644 index 000000000..ed2b2e2eb --- /dev/null +++ b/packages/db/test/fixtures/integration-only/integration/seed.ts @@ -0,0 +1,14 @@ +import { db } from 'astro:db'; +import { asDrizzleTable } from '@astrojs/db/utils'; +import { menu } from './shared'; + +export default async function () { + const table = asDrizzleTable('menu', menu); + + await db.insert(table).values([ + { name: 'Pancakes', price: 9.5, type: 'Breakfast' }, + { name: 'French Toast', price: 11.25, type: 'Breakfast' }, + { name: 'Coffee', price: 3, type: 'Beverages' }, + { name: 'Cappuccino', price: 4.5, type: 'Beverages' }, + ]); +} diff --git a/packages/db/test/fixtures/integration-only/integration/shared.ts b/packages/db/test/fixtures/integration-only/integration/shared.ts new file mode 100644 index 000000000..d46ae65a6 --- /dev/null +++ b/packages/db/test/fixtures/integration-only/integration/shared.ts @@ -0,0 +1,9 @@ +import { column, defineTable } from 'astro:db'; + +export const menu = defineTable({ + columns: { + name: column.text(), + type: column.text(), + price: column.number(), + }, +}); diff --git a/packages/db/test/fixtures/integration-only/package.json b/packages/db/test/fixtures/integration-only/package.json new file mode 100644 index 000000000..4229f710a --- /dev/null +++ b/packages/db/test/fixtures/integration-only/package.json @@ -0,0 +1,14 @@ +{ + "name": "@test/db-integration-only", + "version": "0.0.0", + "private": true, + "scripts": { + "dev": "astro dev", + "build": "astro build", + "preview": "astro preview" + }, + "dependencies": { + "@astrojs/db": "workspace:*", + "astro": "workspace:*" + } +} diff --git a/packages/db/test/fixtures/integration-only/src/pages/index.astro b/packages/db/test/fixtures/integration-only/src/pages/index.astro new file mode 100644 index 000000000..7b204e124 --- /dev/null +++ b/packages/db/test/fixtures/integration-only/src/pages/index.astro @@ -0,0 +1,11 @@ +--- +/// <reference path="../../.astro/db-types.d.ts" /> +import { db, menu } from 'astro:db'; + +const menuItems = await db.select().from(menu); +--- + +<h2>Menu</h2> +<ul class="menu"> + {menuItems.map((item) => <li>{item.name}</li>)} +</ul> diff --git a/packages/db/test/fixtures/integrations/astro.config.mjs b/packages/db/test/fixtures/integrations/astro.config.mjs new file mode 100644 index 000000000..23f52739e --- /dev/null +++ b/packages/db/test/fixtures/integrations/astro.config.mjs @@ -0,0 +1,8 @@ +import db from '@astrojs/db'; +import { defineConfig } from 'astro/config'; +import testIntegration from './integration'; + +// https://astro.build/config +export default defineConfig({ + integrations: [db(), testIntegration()], +}); diff --git a/packages/db/test/fixtures/integrations/db/config.ts b/packages/db/test/fixtures/integrations/db/config.ts new file mode 100644 index 000000000..b8110406a --- /dev/null +++ b/packages/db/test/fixtures/integrations/db/config.ts @@ -0,0 +1,12 @@ +import { column, defineDb, defineTable } from 'astro:db'; + +const Author = defineTable({ + columns: { + name: column.text(), + age2: column.number({ optional: true }), + }, +}); + +export default defineDb({ + tables: { Author }, +}); diff --git a/packages/db/test/fixtures/integrations/db/seed.ts b/packages/db/test/fixtures/integrations/db/seed.ts new file mode 100644 index 000000000..56ffb5668 --- /dev/null +++ b/packages/db/test/fixtures/integrations/db/seed.ts @@ -0,0 +1,13 @@ +import { Author, db } from 'astro:db'; + +export default async () => { + await db + .insert(Author) + .values([ + { name: 'Ben' }, + { name: 'Nate' }, + { name: 'Erika' }, + { name: 'Bjorn' }, + { name: 'Sarah' }, + ]); +}; diff --git a/packages/db/test/fixtures/integrations/integration/config.ts b/packages/db/test/fixtures/integrations/integration/config.ts new file mode 100644 index 000000000..71490be95 --- /dev/null +++ b/packages/db/test/fixtures/integrations/integration/config.ts @@ -0,0 +1,8 @@ +import { defineDb } from 'astro:db'; +import { menu } from './shared'; + +export default defineDb({ + tables: { + menu, + }, +}); diff --git a/packages/db/test/fixtures/integrations/integration/index.ts b/packages/db/test/fixtures/integrations/integration/index.ts new file mode 100644 index 000000000..b249cc253 --- /dev/null +++ b/packages/db/test/fixtures/integrations/integration/index.ts @@ -0,0 +1,15 @@ +import { defineDbIntegration } from '@astrojs/db/utils'; + +export default function testIntegration() { + return defineDbIntegration({ + name: 'db-test-integration', + hooks: { + 'astro:db:setup'({ extendDb }) { + extendDb({ + configEntrypoint: './integration/config.ts', + seedEntrypoint: './integration/seed.ts', + }); + }, + }, + }); +} diff --git a/packages/db/test/fixtures/integrations/integration/seed.ts b/packages/db/test/fixtures/integrations/integration/seed.ts new file mode 100644 index 000000000..ed2b2e2eb --- /dev/null +++ b/packages/db/test/fixtures/integrations/integration/seed.ts @@ -0,0 +1,14 @@ +import { db } from 'astro:db'; +import { asDrizzleTable } from '@astrojs/db/utils'; +import { menu } from './shared'; + +export default async function () { + const table = asDrizzleTable('menu', menu); + + await db.insert(table).values([ + { name: 'Pancakes', price: 9.5, type: 'Breakfast' }, + { name: 'French Toast', price: 11.25, type: 'Breakfast' }, + { name: 'Coffee', price: 3, type: 'Beverages' }, + { name: 'Cappuccino', price: 4.5, type: 'Beverages' }, + ]); +} diff --git a/packages/db/test/fixtures/integrations/integration/shared.ts b/packages/db/test/fixtures/integrations/integration/shared.ts new file mode 100644 index 000000000..d46ae65a6 --- /dev/null +++ b/packages/db/test/fixtures/integrations/integration/shared.ts @@ -0,0 +1,9 @@ +import { column, defineTable } from 'astro:db'; + +export const menu = defineTable({ + columns: { + name: column.text(), + type: column.text(), + price: column.number(), + }, +}); diff --git a/packages/db/test/fixtures/integrations/package.json b/packages/db/test/fixtures/integrations/package.json new file mode 100644 index 000000000..1bb17a8c7 --- /dev/null +++ b/packages/db/test/fixtures/integrations/package.json @@ -0,0 +1,14 @@ +{ + "name": "@test/db-integration", + "version": "0.0.0", + "private": true, + "scripts": { + "dev": "astro dev", + "build": "astro build", + "preview": "astro preview" + }, + "dependencies": { + "@astrojs/db": "workspace:*", + "astro": "workspace:*" + } +} diff --git a/packages/db/test/fixtures/integrations/src/pages/index.astro b/packages/db/test/fixtures/integrations/src/pages/index.astro new file mode 100644 index 000000000..3e9c30ef7 --- /dev/null +++ b/packages/db/test/fixtures/integrations/src/pages/index.astro @@ -0,0 +1,17 @@ +--- +/// <reference path="../../.astro/db-types.d.ts" /> +import { Author, db, menu } from 'astro:db'; + +const authors = await db.select().from(Author); +const menuItems = await db.select().from(menu); +--- + +<h2>Authors</h2> +<ul class="authors-list"> + {authors.map((author) => <li>{author.name}</li>)} +</ul> + +<h2>Menu</h2> +<ul class="menu"> + {menuItems.map((item) => <li>{item.name}</li>)} +</ul> diff --git a/packages/db/test/fixtures/libsql-remote/astro.config.ts b/packages/db/test/fixtures/libsql-remote/astro.config.ts new file mode 100644 index 000000000..983a6947d --- /dev/null +++ b/packages/db/test/fixtures/libsql-remote/astro.config.ts @@ -0,0 +1,10 @@ +import db from '@astrojs/db'; +import { defineConfig } from 'astro/config'; + +// https://astro.build/config +export default defineConfig({ + integrations: [db()], + devToolbar: { + enabled: false, + }, +}); diff --git a/packages/db/test/fixtures/libsql-remote/db/config.ts b/packages/db/test/fixtures/libsql-remote/db/config.ts new file mode 100644 index 000000000..44c15abe7 --- /dev/null +++ b/packages/db/test/fixtures/libsql-remote/db/config.ts @@ -0,0 +1,13 @@ +import { column, defineDb, defineTable } from 'astro:db'; + +const User = defineTable({ + columns: { + id: column.text({ primaryKey: true, optional: false }), + username: column.text({ optional: false, unique: true }), + password: column.text({ optional: false }), + }, +}); + +export default defineDb({ + tables: { User }, +}); diff --git a/packages/db/test/fixtures/libsql-remote/db/seed.ts b/packages/db/test/fixtures/libsql-remote/db/seed.ts new file mode 100644 index 000000000..7d9aa3292 --- /dev/null +++ b/packages/db/test/fixtures/libsql-remote/db/seed.ts @@ -0,0 +1,7 @@ +import { User, db } from 'astro:db'; + +export default async function () { + await db.batch([ + db.insert(User).values([{ id: 'mario', username: 'Mario', password: 'itsame' }]), + ]); +} diff --git a/packages/db/test/fixtures/libsql-remote/package.json b/packages/db/test/fixtures/libsql-remote/package.json new file mode 100644 index 000000000..2970a62d5 --- /dev/null +++ b/packages/db/test/fixtures/libsql-remote/package.json @@ -0,0 +1,14 @@ +{ + "name": "@test/db-libsql-remote", + "version": "0.0.0", + "private": true, + "scripts": { + "dev": "astro dev", + "build": "astro build", + "preview": "astro preview" + }, + "dependencies": { + "@astrojs/db": "workspace:*", + "astro": "workspace:*" + } +} diff --git a/packages/db/test/fixtures/libsql-remote/src/pages/index.astro b/packages/db/test/fixtures/libsql-remote/src/pages/index.astro new file mode 100644 index 000000000..f36d44bd4 --- /dev/null +++ b/packages/db/test/fixtures/libsql-remote/src/pages/index.astro @@ -0,0 +1,11 @@ +--- +/// <reference path="../../.astro/db-types.d.ts" /> +import { User, db } from 'astro:db'; + +const users = await db.select().from(User); +--- + +<h2>Users</h2> +<ul class="users-list"> + {users.map((user) => <li>{user.name}</li>)} +</ul> diff --git a/packages/db/test/fixtures/local-prod/astro.config.ts b/packages/db/test/fixtures/local-prod/astro.config.ts new file mode 100644 index 000000000..983a6947d --- /dev/null +++ b/packages/db/test/fixtures/local-prod/astro.config.ts @@ -0,0 +1,10 @@ +import db from '@astrojs/db'; +import { defineConfig } from 'astro/config'; + +// https://astro.build/config +export default defineConfig({ + integrations: [db()], + devToolbar: { + enabled: false, + }, +}); diff --git a/packages/db/test/fixtures/local-prod/db/config.ts b/packages/db/test/fixtures/local-prod/db/config.ts new file mode 100644 index 000000000..44c15abe7 --- /dev/null +++ b/packages/db/test/fixtures/local-prod/db/config.ts @@ -0,0 +1,13 @@ +import { column, defineDb, defineTable } from 'astro:db'; + +const User = defineTable({ + columns: { + id: column.text({ primaryKey: true, optional: false }), + username: column.text({ optional: false, unique: true }), + password: column.text({ optional: false }), + }, +}); + +export default defineDb({ + tables: { User }, +}); diff --git a/packages/db/test/fixtures/local-prod/db/seed.ts b/packages/db/test/fixtures/local-prod/db/seed.ts new file mode 100644 index 000000000..a84e63454 --- /dev/null +++ b/packages/db/test/fixtures/local-prod/db/seed.ts @@ -0,0 +1,8 @@ +import { User, db } from 'astro:db'; +import { asDrizzleTable } from '@astrojs/db/utils'; + +export default async function () { + await db.batch([ + db.insert(User).values([{ id: 'mario', username: 'Mario', password: 'itsame' }]), + ]); +} diff --git a/packages/db/test/fixtures/local-prod/package.json b/packages/db/test/fixtures/local-prod/package.json new file mode 100644 index 000000000..2d11d5347 --- /dev/null +++ b/packages/db/test/fixtures/local-prod/package.json @@ -0,0 +1,14 @@ +{ + "name": "@test/db-local-prod", + "version": "0.0.0", + "private": true, + "scripts": { + "dev": "astro dev", + "build": "astro build", + "preview": "astro preview" + }, + "dependencies": { + "@astrojs/db": "workspace:*", + "astro": "workspace:*" + } +} diff --git a/packages/db/test/fixtures/local-prod/src/pages/index.astro b/packages/db/test/fixtures/local-prod/src/pages/index.astro new file mode 100644 index 000000000..f36d44bd4 --- /dev/null +++ b/packages/db/test/fixtures/local-prod/src/pages/index.astro @@ -0,0 +1,11 @@ +--- +/// <reference path="../../.astro/db-types.d.ts" /> +import { User, db } from 'astro:db'; + +const users = await db.select().from(User); +--- + +<h2>Users</h2> +<ul class="users-list"> + {users.map((user) => <li>{user.name}</li>)} +</ul> diff --git a/packages/db/test/fixtures/no-apptoken/astro.config.ts b/packages/db/test/fixtures/no-apptoken/astro.config.ts new file mode 100644 index 000000000..983a6947d --- /dev/null +++ b/packages/db/test/fixtures/no-apptoken/astro.config.ts @@ -0,0 +1,10 @@ +import db from '@astrojs/db'; +import { defineConfig } from 'astro/config'; + +// https://astro.build/config +export default defineConfig({ + integrations: [db()], + devToolbar: { + enabled: false, + }, +}); diff --git a/packages/db/test/fixtures/no-apptoken/db/config.ts b/packages/db/test/fixtures/no-apptoken/db/config.ts new file mode 100644 index 000000000..44c15abe7 --- /dev/null +++ b/packages/db/test/fixtures/no-apptoken/db/config.ts @@ -0,0 +1,13 @@ +import { column, defineDb, defineTable } from 'astro:db'; + +const User = defineTable({ + columns: { + id: column.text({ primaryKey: true, optional: false }), + username: column.text({ optional: false, unique: true }), + password: column.text({ optional: false }), + }, +}); + +export default defineDb({ + tables: { User }, +}); diff --git a/packages/db/test/fixtures/no-apptoken/db/seed.ts b/packages/db/test/fixtures/no-apptoken/db/seed.ts new file mode 100644 index 000000000..ea9b101e1 --- /dev/null +++ b/packages/db/test/fixtures/no-apptoken/db/seed.ts @@ -0,0 +1 @@ +export default function () {} diff --git a/packages/db/test/fixtures/no-apptoken/package.json b/packages/db/test/fixtures/no-apptoken/package.json new file mode 100644 index 000000000..a7e17d1af --- /dev/null +++ b/packages/db/test/fixtures/no-apptoken/package.json @@ -0,0 +1,14 @@ +{ + "name": "@test/db-no-apptoken", + "version": "0.0.0", + "private": true, + "scripts": { + "dev": "astro dev", + "build": "astro build", + "preview": "astro preview" + }, + "dependencies": { + "@astrojs/db": "workspace:*", + "astro": "workspace:*" + } +} diff --git a/packages/db/test/fixtures/no-apptoken/src/pages/index.astro b/packages/db/test/fixtures/no-apptoken/src/pages/index.astro new file mode 100644 index 000000000..477e18fa3 --- /dev/null +++ b/packages/db/test/fixtures/no-apptoken/src/pages/index.astro @@ -0,0 +1,16 @@ +--- +/// <reference path="../../.astro/db-types.d.ts" /> +import { User, db } from 'astro:db'; + +// Just for the side-effect of running all the code +await db.select().from(User); +--- + +<html> + <head> + <title>Testing</title> + </head> + <body> + <h1>Testing</h1> + </body> +</html> diff --git a/packages/db/test/fixtures/no-seed/astro.config.ts b/packages/db/test/fixtures/no-seed/astro.config.ts new file mode 100644 index 000000000..5ff1200e2 --- /dev/null +++ b/packages/db/test/fixtures/no-seed/astro.config.ts @@ -0,0 +1,7 @@ +import db from '@astrojs/db'; +import { defineConfig } from 'astro/config'; + +// https://astro.build/config +export default defineConfig({ + integrations: [db()], +}); diff --git a/packages/db/test/fixtures/no-seed/db/config.ts b/packages/db/test/fixtures/no-seed/db/config.ts new file mode 100644 index 000000000..b8110406a --- /dev/null +++ b/packages/db/test/fixtures/no-seed/db/config.ts @@ -0,0 +1,12 @@ +import { column, defineDb, defineTable } from 'astro:db'; + +const Author = defineTable({ + columns: { + name: column.text(), + age2: column.number({ optional: true }), + }, +}); + +export default defineDb({ + tables: { Author }, +}); diff --git a/packages/db/test/fixtures/no-seed/package.json b/packages/db/test/fixtures/no-seed/package.json new file mode 100644 index 000000000..66a192697 --- /dev/null +++ b/packages/db/test/fixtures/no-seed/package.json @@ -0,0 +1,14 @@ +{ + "name": "@test/db-no-seed", + "version": "0.0.0", + "private": true, + "scripts": { + "dev": "astro dev", + "build": "astro build", + "preview": "astro preview" + }, + "dependencies": { + "@astrojs/db": "workspace:*", + "astro": "workspace:*" + } +} diff --git a/packages/db/test/fixtures/no-seed/src/pages/index.astro b/packages/db/test/fixtures/no-seed/src/pages/index.astro new file mode 100644 index 000000000..bacd873e1 --- /dev/null +++ b/packages/db/test/fixtures/no-seed/src/pages/index.astro @@ -0,0 +1,21 @@ +--- +/// <reference path="../../.astro/db-types.d.ts" /> +import { Author, db } from 'astro:db'; + +await db + .insert(Author) + .values([ + { name: 'Ben' }, + { name: 'Nate' }, + { name: 'Erika' }, + { name: 'Bjorn' }, + { name: 'Sarah' }, + ]); + +const authors = await db.select().from(Author); +--- + +<h2>Authors</h2> +<ul class="authors-list"> + {authors.map((author) => <li>{author.name}</li>)} +</ul> diff --git a/packages/db/test/fixtures/recipes/astro.config.ts b/packages/db/test/fixtures/recipes/astro.config.ts new file mode 100644 index 000000000..bd6088769 --- /dev/null +++ b/packages/db/test/fixtures/recipes/astro.config.ts @@ -0,0 +1,6 @@ +import astroDb from '@astrojs/db'; +import { defineConfig } from 'astro/config'; + +export default defineConfig({ + integrations: [astroDb()], +}); diff --git a/packages/db/test/fixtures/recipes/db/config.ts b/packages/db/test/fixtures/recipes/db/config.ts new file mode 100644 index 000000000..bd4d6edaf --- /dev/null +++ b/packages/db/test/fixtures/recipes/db/config.ts @@ -0,0 +1,26 @@ +import { column, defineDb, defineTable } from 'astro:db'; + +const Recipe = defineTable({ + columns: { + id: column.number({ primaryKey: true }), + title: column.text(), + description: column.text(), + }, +}); + +const Ingredient = defineTable({ + columns: { + id: column.number({ primaryKey: true }), + name: column.text(), + quantity: column.number(), + recipeId: column.number(), + }, + indexes: { + recipeIdx: { on: 'recipeId' }, + }, + foreignKeys: [{ columns: 'recipeId', references: () => [Recipe.columns.id] }], +}); + +export default defineDb({ + tables: { Recipe, Ingredient }, +}); diff --git a/packages/db/test/fixtures/recipes/db/seed.ts b/packages/db/test/fixtures/recipes/db/seed.ts new file mode 100644 index 000000000..1ca219f15 --- /dev/null +++ b/packages/db/test/fixtures/recipes/db/seed.ts @@ -0,0 +1,62 @@ +import { Ingredient, Recipe, db } from 'astro:db'; + +export default async function () { + const pancakes = await db + .insert(Recipe) + .values({ + title: 'Pancakes', + description: 'A delicious breakfast', + }) + .returning() + .get(); + + await db.insert(Ingredient).values([ + { + name: 'Flour', + quantity: 1, + recipeId: pancakes.id, + }, + { + name: 'Eggs', + quantity: 2, + recipeId: pancakes.id, + }, + { + name: 'Milk', + quantity: 1, + recipeId: pancakes.id, + }, + ]); + + const pizza = await db + .insert(Recipe) + .values({ + title: 'Pizza', + description: 'A delicious dinner', + }) + .returning() + .get(); + + await db.insert(Ingredient).values([ + { + name: 'Flour', + quantity: 1, + recipeId: pizza.id, + }, + { + name: 'Eggs', + quantity: 2, + recipeId: pizza.id, + }, + { + name: 'Milk', + quantity: 1, + recipeId: pizza.id, + }, + { + name: 'Tomato Sauce', + quantity: 1, + recipeId: pizza.id, + }, + ]); +} diff --git a/packages/db/test/fixtures/recipes/package.json b/packages/db/test/fixtures/recipes/package.json new file mode 100644 index 000000000..cd1e83c02 --- /dev/null +++ b/packages/db/test/fixtures/recipes/package.json @@ -0,0 +1,16 @@ +{ + "name": "@test/recipes", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "@astrojs/db": "workspace:*", + "astro": "workspace:*" + } +} diff --git a/packages/db/test/fixtures/recipes/src/pages/index.astro b/packages/db/test/fixtures/recipes/src/pages/index.astro new file mode 100644 index 000000000..9fd2dac41 --- /dev/null +++ b/packages/db/test/fixtures/recipes/src/pages/index.astro @@ -0,0 +1,25 @@ +--- +/// <reference path="../../.astro/db-types.d.ts" /> +import { Ingredient, Recipe, db, eq } from 'astro:db'; + +const ingredientsByRecipe = await db + .select({ + name: Ingredient.name, + recipeName: Recipe.title, + }) + .from(Ingredient) + .innerJoin(Recipe, eq(Ingredient.recipeId, Recipe.id)); + +console.log(ingredientsByRecipe); +--- + +<h2>Shopping list</h2> +<ul> + { + ingredientsByRecipe.map(({ name, recipeName }) => ( + <li> + {name} ({recipeName}) + </li> + )) + } +</ul> diff --git a/packages/db/test/fixtures/static-remote/astro.config.ts b/packages/db/test/fixtures/static-remote/astro.config.ts new file mode 100644 index 000000000..bd6088769 --- /dev/null +++ b/packages/db/test/fixtures/static-remote/astro.config.ts @@ -0,0 +1,6 @@ +import astroDb from '@astrojs/db'; +import { defineConfig } from 'astro/config'; + +export default defineConfig({ + integrations: [astroDb()], +}); diff --git a/packages/db/test/fixtures/static-remote/db/config.ts b/packages/db/test/fixtures/static-remote/db/config.ts new file mode 100644 index 000000000..8df4674d8 --- /dev/null +++ b/packages/db/test/fixtures/static-remote/db/config.ts @@ -0,0 +1,12 @@ +import { column, defineDb, defineTable } from 'astro:db'; + +const User = defineTable({ + columns: { + id: column.number({ primaryKey: true }), + name: column.text(), + }, +}); + +export default defineDb({ + tables: { User }, +}); diff --git a/packages/db/test/fixtures/static-remote/db/seed.ts b/packages/db/test/fixtures/static-remote/db/seed.ts new file mode 100644 index 000000000..2c86f02a1 --- /dev/null +++ b/packages/db/test/fixtures/static-remote/db/seed.ts @@ -0,0 +1,9 @@ +import { User, db } from 'astro:db'; + +export default async function () { + await db.insert(User).values([ + { + name: 'Houston', + }, + ]); +} diff --git a/packages/db/test/fixtures/static-remote/package.json b/packages/db/test/fixtures/static-remote/package.json new file mode 100644 index 000000000..aa2c9c23c --- /dev/null +++ b/packages/db/test/fixtures/static-remote/package.json @@ -0,0 +1,16 @@ +{ + "name": "@test/db-static-remote", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "@astrojs/db": "workspace:*", + "astro": "workspace:*" + } +} diff --git a/packages/db/test/fixtures/static-remote/src/pages/index.astro b/packages/db/test/fixtures/static-remote/src/pages/index.astro new file mode 100644 index 000000000..849e65d18 --- /dev/null +++ b/packages/db/test/fixtures/static-remote/src/pages/index.astro @@ -0,0 +1,19 @@ +--- +import { User, db } from 'astro:db'; + +const users = await db.select().from(User); +--- + +<html> + <head> + <title>Testing</title> + </head> + <body> + <h1>Testing</h1> + + <h2>Users</h2> + <ul> + {users.map((user) => <li>{user.name}</li>)} + </ul> + </body> +</html> diff --git a/packages/db/test/fixtures/static-remote/src/pages/run.astro b/packages/db/test/fixtures/static-remote/src/pages/run.astro new file mode 100644 index 000000000..2f2ac1cce --- /dev/null +++ b/packages/db/test/fixtures/static-remote/src/pages/run.astro @@ -0,0 +1,17 @@ +--- +import { User, db, sql } from 'astro:db'; + +const results = await db.run(sql`SELECT 1 as value`); +const row = results.rows[0]; +--- + +<html> + <head> + <title>Testing</title> + </head> + <body> + <h1>Testing</h1> + + <span id="row">{row.value}</span> + </body> +</html> diff --git a/packages/db/test/fixtures/ticketing-example/.gitignore b/packages/db/test/fixtures/ticketing-example/.gitignore new file mode 100644 index 000000000..ce6405d09 --- /dev/null +++ b/packages/db/test/fixtures/ticketing-example/.gitignore @@ -0,0 +1,24 @@ +# build output +dist/ + +# generated types +.astro/ + +# dependencies +node_modules/ + +# logs +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* + +# environment variables +.env +.env.production + +# macOS-specific files +.DS_Store + +# Cloudflare +.wrangler/ diff --git a/packages/db/test/fixtures/ticketing-example/README.md b/packages/db/test/fixtures/ticketing-example/README.md new file mode 100644 index 000000000..1db3fb399 --- /dev/null +++ b/packages/db/test/fixtures/ticketing-example/README.md @@ -0,0 +1,54 @@ +# Astro Starter Kit: Basics + +```sh +npm create astro@latest -- --template basics +``` + +[](https://stackblitz.com/github/withastro/astro/tree/latest/examples/basics) +[](https://codesandbox.io/p/sandbox/github/withastro/astro/tree/latest/examples/basics) +[](https://codespaces.new/withastro/astro?devcontainer_path=.devcontainer/basics/devcontainer.json) + +> 🧑🚀 **Seasoned astronaut?** Delete this file. Have fun! + + + +## 🚀 Project Structure + +Inside of your Astro project, you'll see the following folders and files: + +```text +/ +├── public/ +│ └── favicon.svg +├── src/ +│ ├── components/ +│ │ └── Card.astro +│ ├── layouts/ +│ │ └── Layout.astro +│ └── pages/ +│ └── index.astro +└── package.json +``` + +Astro looks for `.astro` or `.md` files in the `src/pages/` directory. Each page is exposed as a route based on its file name. + +There's nothing special about `src/components/`, but that's where we like to put any Astro/React/Vue/Svelte/Preact components. + +Any static assets, like images, can be placed in the `public/` directory. + +## 🧞 Commands + +All commands are run from the root of the project, from a terminal: + +| Command | Action | +| :------------------------ | :----------------------------------------------- | +| `npm install` | Installs dependencies | +| `npm run dev` | Starts local dev server at `localhost:4321` | +| `npm run build` | Build your production site to `./dist/` | +| `npm run preview` | Preview your build locally, before deploying | +| `npm run astro ...` | Run CLI commands like `astro add`, `astro check` | +| `npm run astro -- --help` | Get help using the Astro CLI | + +## 👀 Want to learn more? + +Feel free to check [our documentation](https://docs.astro.build) or jump into our [Discord server](https://astro.build/chat). diff --git a/packages/db/test/fixtures/ticketing-example/astro.config.ts b/packages/db/test/fixtures/ticketing-example/astro.config.ts new file mode 100644 index 000000000..616156f9a --- /dev/null +++ b/packages/db/test/fixtures/ticketing-example/astro.config.ts @@ -0,0 +1,14 @@ +import db from '@astrojs/db'; +import node from '@astrojs/node'; +import react from '@astrojs/react'; +import { defineConfig } from 'astro/config'; +import simpleStackForm from 'simple-stack-form'; + +// https://astro.build/config +export default defineConfig({ + integrations: [simpleStackForm(), db(), react()], + output: 'server', + adapter: node({ + mode: 'standalone', + }), +}); diff --git a/packages/db/test/fixtures/ticketing-example/db/config.ts b/packages/db/test/fixtures/ticketing-example/db/config.ts new file mode 100644 index 000000000..4c07b4c9c --- /dev/null +++ b/packages/db/test/fixtures/ticketing-example/db/config.ts @@ -0,0 +1,27 @@ +import { column, defineDb, defineTable } from 'astro:db'; + +const Event = defineTable({ + columns: { + id: column.number({ + primaryKey: true, + }), + name: column.text(), + description: column.text(), + ticketPrice: column.number(), + date: column.date(), + location: column.text(), + }, +}); + +const Ticket = defineTable({ + columns: { + eventId: column.number({ references: () => Event.columns.id }), + email: column.text(), + quantity: column.number(), + newsletter: column.boolean({ + default: true, + }), + }, +}); + +export default defineDb({ tables: { Event, Ticket } }); diff --git a/packages/db/test/fixtures/ticketing-example/db/seed.ts b/packages/db/test/fixtures/ticketing-example/db/seed.ts new file mode 100644 index 000000000..f68a0c85b --- /dev/null +++ b/packages/db/test/fixtures/ticketing-example/db/seed.ts @@ -0,0 +1,12 @@ +import { Event, db } from 'astro:db'; + +export default async function () { + await db.insert(Event).values({ + name: 'Sampha LIVE in Brooklyn', + description: + 'Sampha is on tour with his new, flawless album Lahai. Come see the live performance outdoors in Prospect Park. Yes, there will be a grand piano 🎹', + date: new Date('2024-01-01'), + ticketPrice: 10000, + location: 'Brooklyn, NY', + }); +} diff --git a/packages/db/test/fixtures/ticketing-example/package.json b/packages/db/test/fixtures/ticketing-example/package.json new file mode 100644 index 000000000..9d3bc0899 --- /dev/null +++ b/packages/db/test/fixtures/ticketing-example/package.json @@ -0,0 +1,26 @@ +{ + "name": "eventbrite-from-scratch", + "type": "module", + "version": "0.0.1", + "scripts": { + "dev": "pnpm astro dev", + "build": "astro check && astro build", + "preview": "astro preview", + "astro": "astro" + }, + "dependencies": { + "@astrojs/check": "^0.9.4", + "@astrojs/db": "workspace:*", + "@astrojs/node": "workspace:*", + "@astrojs/react": "workspace:*", + "@types/react": "^18.3.20", + "@types/react-dom": "^18.3.6", + "astro": "workspace:*", + "open-props": "^1.7.14", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "simple-stack-form": "^0.1.12", + "typescript": "^5.8.3", + "zod": "^3.24.2" + } +} diff --git a/packages/db/test/fixtures/ticketing-example/public/favicon.svg b/packages/db/test/fixtures/ticketing-example/public/favicon.svg new file mode 100644 index 000000000..f157bd1c5 --- /dev/null +++ b/packages/db/test/fixtures/ticketing-example/public/favicon.svg @@ -0,0 +1,9 @@ +<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 128 128"> + <path d="M50.4 78.5a75.1 75.1 0 0 0-28.5 6.9l24.2-65.7c.7-2 1.9-3.2 3.4-3.2h29c1.5 0 2.7 1.2 3.4 3.2l24.2 65.7s-11.6-7-28.5-7L67 45.5c-.4-1.7-1.6-2.8-2.9-2.8-1.3 0-2.5 1.1-2.9 2.7L50.4 78.5Zm-1.1 28.2Zm-4.2-20.2c-2 6.6-.6 15.8 4.2 20.2a17.5 17.5 0 0 1 .2-.7 5.5 5.5 0 0 1 5.7-4.5c2.8.1 4.3 1.5 4.7 4.7.2 1.1.2 2.3.2 3.5v.4c0 2.7.7 5.2 2.2 7.4a13 13 0 0 0 5.7 4.9v-.3l-.2-.3c-1.8-5.6-.5-9.5 4.4-12.8l1.5-1a73 73 0 0 0 3.2-2.2 16 16 0 0 0 6.8-11.4c.3-2 .1-4-.6-6l-.8.6-1.6 1a37 37 0 0 1-22.4 2.7c-5-.7-9.7-2-13.2-6.2Z" /> + <style> + path { fill: #000; } + @media (prefers-color-scheme: dark) { + path { fill: #FFF; } + } + </style> +</svg> diff --git a/packages/db/test/fixtures/ticketing-example/src/components/Form.tsx b/packages/db/test/fixtures/ticketing-example/src/components/Form.tsx new file mode 100644 index 000000000..f393d8281 --- /dev/null +++ b/packages/db/test/fixtures/ticketing-example/src/components/Form.tsx @@ -0,0 +1,119 @@ +// Generated by simple:form + +import { navigate } from 'astro:transitions/client'; +import { + type FieldErrors, + type FormState, + type FormValidator, + formNameInputProps, + getInitialFormState, + toSetValidationErrors, + toTrackAstroSubmitStatus, + toValidateField, + validateForm, +} from 'simple:form'; +import { type ComponentProps, createContext, useContext, useState } from 'react'; + +export function useCreateFormContext(validator: FormValidator, fieldErrors?: FieldErrors) { + const initial = getInitialFormState({ validator, fieldErrors }); + const [formState, setFormState] = useState<FormState>(initial); + return { + value: formState, + set: setFormState, + setValidationErrors: toSetValidationErrors(setFormState), + validateField: toValidateField(setFormState), + trackAstroSubmitStatus: toTrackAstroSubmitStatus(setFormState), + }; +} + +export function useFormContext() { + const formContext = useContext(FormContext); + if (!formContext) { + throw new Error( + 'Form context not found. `useFormContext()` should only be called from children of a <Form> component.' + ); + } + return formContext; +} + +type FormContextType = ReturnType<typeof useCreateFormContext>; + +const FormContext = createContext<FormContextType | undefined>(undefined); + +export function Form({ + children, + validator, + context, + fieldErrors, + name, + ...formProps +}: { + validator: FormValidator; + context?: FormContextType; + fieldErrors?: FieldErrors; +} & Omit<ComponentProps<'form'>, 'method' | 'onSubmit'>) { + const formContext = context ?? useCreateFormContext(validator, fieldErrors); + + return ( + <FormContext.Provider value={formContext}> + <form + {...formProps} + method="POST" + onSubmit={async (e) => { + e.preventDefault(); + e.stopPropagation(); + const formData = new FormData(e.currentTarget); + formContext.set((formState) => ({ + ...formState, + isSubmitPending: true, + submitStatus: 'validating', + })); + const parsed = await validateForm({ formData, validator }); + if (parsed.data) { + navigate(formProps.action ?? '', { formData }); + return formContext.trackAstroSubmitStatus(); + } + + formContext.setValidationErrors(parsed.fieldErrors); + }} + > + {name ? <input {...formNameInputProps} value={name} /> : null} + {children} + </form> + </FormContext.Provider> + ); +} + +export function Input(inputProps: ComponentProps<'input'> & { name: string }) { + const formContext = useFormContext(); + const fieldState = formContext.value.fields[inputProps.name]; + if (!fieldState) { + throw new Error( + `Input "${inputProps.name}" not found in form. Did you use the <Form> component?` + ); + } + + const { hasErroredOnce, validationErrors, validator } = fieldState; + return ( + <> + <input + onBlur={async (e) => { + const value = e.target.value; + if (value === '') return; + formContext.validateField(inputProps.name, value, validator); + }} + onChange={async (e) => { + if (!hasErroredOnce) return; + const value = e.target.value; + formContext.validateField(inputProps.name, value, validator); + }} + {...inputProps} + /> + {validationErrors?.map((e) => ( + <p className="error" key={e}> + {e} + </p> + ))} + </> + ); +} diff --git a/packages/db/test/fixtures/ticketing-example/src/layouts/Layout.astro b/packages/db/test/fixtures/ticketing-example/src/layouts/Layout.astro new file mode 100644 index 000000000..482f10462 --- /dev/null +++ b/packages/db/test/fixtures/ticketing-example/src/layouts/Layout.astro @@ -0,0 +1,80 @@ +--- +import { ClientRouter } from 'astro:transitions'; +import 'open-props/normalize'; +import 'open-props/style'; + +interface Props { + title: string; +} + +const { title } = Astro.props; +--- + +<!doctype html> +<html lang="en"> + <head> + <meta charset="UTF-8" /> + <meta name="description" content="Astro description" /> + <meta name="viewport" content="width=device-width" /> + <link rel="icon" type="image/svg+xml" href="/favicon.svg" /> + <meta name="generator" content={Astro.generator} /> + <title>{title}</title> + <ClientRouter handleForms /> + </head> + <body> + <slot /> + <style is:global> + main { + max-width: 600px; + margin: 0 auto; + padding: var(--size-4); + display: flex; + flex-direction: column; + gap: var(--size-4); + } + + form { + display: flex; + flex-direction: column; + gap: var(--size-2); + margin-bottom: var(--size-4); + background: var(--surface-2); + padding-inline: var(--size-4); + padding-block: var(--size-6); + border-radius: var(--radius-2); + } + + .error { + color: var(--red-6); + margin-bottom: var(--size-2); + grid-column: 1 / -1; + } + + form button { + grid-column: 1 / -1; + background: var(--orange-8); + border-radius: var(--radius-2); + padding-block: var(--size-2); + } + + .youre-going { + background: var(--surface-2); + padding: var(--size-2); + border-radius: var(--radius-2); + display: flex; + flex-direction: column; + } + + h2 { + font-size: var(--font-size-4); + margin-bottom: var(--size-2); + } + + .newsletter { + display: flex; + align-items: center; + gap: var(--size-2); + } + </style> + </body> +</html> diff --git a/packages/db/test/fixtures/ticketing-example/src/pages/[event]/_Ticket.tsx b/packages/db/test/fixtures/ticketing-example/src/pages/[event]/_Ticket.tsx new file mode 100644 index 000000000..5e488d69d --- /dev/null +++ b/packages/db/test/fixtures/ticketing-example/src/pages/[event]/_Ticket.tsx @@ -0,0 +1,40 @@ +import { createForm } from 'simple:form'; +import { useState } from 'react'; +import { z } from 'zod'; +import { Form, Input } from '../../components/Form'; + +export const ticketForm = createForm({ + email: z.string().email(), + quantity: z.number().max(10), + newsletter: z.boolean(), +}); + +export function TicketForm({ price }: { price: number }) { + const [quantity, setQuantity] = useState(1); + return ( + <> + <Form validator={ticketForm.validator}> + <h3>${(quantity * price) / 100}</h3> + + <label htmlFor="quantity">Quantity</label> + <Input + id="quantity" + {...ticketForm.inputProps.quantity} + onInput={(e) => { + const value = Number(e.currentTarget.value); + setQuantity(value); + }} + /> + + <label htmlFor="email">Email</label> + <Input id="email" {...ticketForm.inputProps.email} /> + + <div className="newsletter"> + <Input id="newsletter" {...ticketForm.inputProps.newsletter} /> + <label htmlFor="newsletter">Hear about the next event in your area</label> + </div> + <button>Buy tickets</button> + </Form> + </> + ); +} diff --git a/packages/db/test/fixtures/ticketing-example/src/pages/[event]/index.astro b/packages/db/test/fixtures/ticketing-example/src/pages/[event]/index.astro new file mode 100644 index 000000000..7c1c4e320 --- /dev/null +++ b/packages/db/test/fixtures/ticketing-example/src/pages/[event]/index.astro @@ -0,0 +1,50 @@ +--- +import { Event, Ticket, db, eq } from 'astro:db'; +import Layout from '../../layouts/Layout.astro'; +import { TicketForm, ticketForm } from './_Ticket'; + +const eventId = Number(Astro.params.event); + +if (isNaN(eventId)) return Astro.redirect('/'); + +const event = await db.select().from(Event).where(eq(Event.id, eventId)).get(); + +if (!event) return Astro.redirect('/'); + +const res = await Astro.locals.form.getData(ticketForm); + +if (res?.data) { + await db.insert(Ticket).values({ + eventId, + email: res.data.email, + quantity: res.data.quantity, + newsletter: res.data.newsletter, + }); +} + +const ticket = await db.select().from(Ticket).where(eq(Ticket.eventId, eventId)).get(); +--- + +<Layout title="Welcome to Astro."> + <main> + <h1>{event.name}</h1> + <p> + {event.description} + </p> + + <TicketForm price={event.ticketPrice} client:load /> + { + ticket && ( + <section class="youre-going"> + <h2>You're going 🙌</h2> + <p> + You have purchased {ticket.quantity} tickets for {event.name}! + </p> + <p> + Check <strong>{ticket.email}</strong> for your tickets. + </p> + </section> + ) + } + </main> +</Layout> diff --git a/packages/db/test/fixtures/ticketing-example/src/pages/index.astro b/packages/db/test/fixtures/ticketing-example/src/pages/index.astro new file mode 100644 index 000000000..c8bbcbc70 --- /dev/null +++ b/packages/db/test/fixtures/ticketing-example/src/pages/index.astro @@ -0,0 +1,17 @@ +--- +import { Event, db } from 'astro:db'; + +const firstEvent = await db.select().from(Event).get(); +--- + +<!doctype html> +<html lang="en"> + <head> + <meta charset="UTF-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Eventbrite</title> + </head> + <body> + <meta http-equiv="refresh" content={`0; url=${firstEvent!.id}`} /> + </body> +</html> diff --git a/packages/db/test/fixtures/ticketing-example/tsconfig.json b/packages/db/test/fixtures/ticketing-example/tsconfig.json new file mode 100644 index 000000000..2424dae7d --- /dev/null +++ b/packages/db/test/fixtures/ticketing-example/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "astro/tsconfigs/strict", + "compilerOptions": { + "jsx": "react-jsx", + "jsxImportSource": "react" + }, + "include": [".astro/types.d.ts", "**/*"], + "exclude": ["dist"] +} |