From 6d7f8c62f6fa6fe147148c374da0bd6e03f93090 Mon Sep 17 00:00:00 2001 From: Matthew Phillips Date: Wed, 27 Mar 2024 09:17:05 -0400 Subject: [PATCH 1/4] Provide guidance when --remote is omitted --- .changeset/neat-stingrays-judge.md | 7 +++ packages/db/src/core/integration/index.ts | 10 ++++ .../db/src/core/integration/vite-plugin-db.ts | 3 +- packages/db/test/basics.test.js | 1 + .../test/fixtures/local-prod/astro.config.ts | 10 ++++ .../db/test/fixtures/local-prod/db/config.ts | 13 +++++ .../db/test/fixtures/local-prod/db/seed.ts | 8 ++++ .../db/test/fixtures/local-prod/package.json | 14 ++++++ .../fixtures/local-prod/src/pages/index.astro | 11 +++++ packages/db/test/local-prod.test.js | 47 +++++++++++++++++++ pnpm-lock.yaml | 9 ++++ 11 files changed, 132 insertions(+), 1 deletion(-) create mode 100644 .changeset/neat-stingrays-judge.md create mode 100644 packages/db/test/fixtures/local-prod/astro.config.ts create mode 100644 packages/db/test/fixtures/local-prod/db/config.ts create mode 100644 packages/db/test/fixtures/local-prod/db/seed.ts create mode 100644 packages/db/test/fixtures/local-prod/package.json create mode 100644 packages/db/test/fixtures/local-prod/src/pages/index.astro create mode 100644 packages/db/test/local-prod.test.js diff --git a/.changeset/neat-stingrays-judge.md b/.changeset/neat-stingrays-judge.md new file mode 100644 index 000000000000..d461ca81102a --- /dev/null +++ b/.changeset/neat-stingrays-judge.md @@ -0,0 +1,7 @@ +--- +"@astrojs/db": patch +--- + +Provide guidance when --remote is missing + +When running the build `astro build` without the `--remote`, either require a `DATABASE_FILE` variable be defined, which means you are going expert-mode and having your own database, or error suggesting to use the `--remote` flag. diff --git a/packages/db/src/core/integration/index.ts b/packages/db/src/core/integration/index.ts index e48b95c09002..487dfc0013cd 100644 --- a/packages/db/src/core/integration/index.ts +++ b/packages/db/src/core/integration/index.ts @@ -13,6 +13,7 @@ import { fileURLIntegration } from './file-url.js'; import { typegenInternal } from './typegen.js'; import { type LateSeedFiles, type LateTables, vitePluginDb } from './vite-plugin-db.js'; import { vitePluginInjectEnvTs } from './vite-plugin-inject-env-ts.js'; +import { loadEnv } from 'vite'; function astroDBIntegration(): AstroIntegration { let connectToStudio = false; @@ -111,6 +112,10 @@ function astroDBIntegration(): AstroIntegration { }); }, 'astro:build:start': async ({ logger }) => { + if(!connectToStudio && !databaseFileEnvDefined()) { + throw new Error(`Attempting to build without the --remote flag or the DATABASE_FILE environment variable defined. You probably want to pass --remote to astro build.`) + } + logger.info('database: ' + (connectToStudio ? yellow('remote') : blue('local database.'))); }, 'astro:build:done': async ({}) => { @@ -120,6 +125,11 @@ function astroDBIntegration(): AstroIntegration { }; } +function databaseFileEnvDefined() { + const env = loadEnv('', process.cwd()); + return env.DATABASE_FILE != null || process.env.DATABASE_FILE != null; +} + export function integration(): AstroIntegration[] { return [astroDBIntegration(), fileURLIntegration()]; } diff --git a/packages/db/src/core/integration/vite-plugin-db.ts b/packages/db/src/core/integration/vite-plugin-db.ts index 60a9b753979b..9b4b79e8d861 100644 --- a/packages/db/src/core/integration/vite-plugin-db.ts +++ b/packages/db/src/core/integration/vite-plugin-db.ts @@ -118,7 +118,8 @@ import { asDrizzleTable, createLocalDatabaseClient } from ${RUNTIME_IMPORT}; ${shouldSeed ? `import { seedLocal } from ${RUNTIME_IMPORT};` : ''} ${shouldSeed ? integrationSeedImportStatements.join('\n') : ''} -const dbUrl = ${JSON.stringify(dbUrl)}; +const dbUrl = import.meta.env.DATABASE_FILE ?? ${JSON.stringify(dbUrl)}; + export const db = createLocalDatabaseClient({ dbUrl }); ${ diff --git a/packages/db/test/basics.test.js b/packages/db/test/basics.test.js index 348e9066c1b6..d944b1c48a00 100644 --- a/packages/db/test/basics.test.js +++ b/packages/db/test/basics.test.js @@ -183,6 +183,7 @@ describe('astro:db', () => { }); after(async () => { + process.env.ASTRO_STUDIO_APP_TOKEN = ''; await remoteDbServer?.stop(); }); 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 000000000000..983a6947d115 --- /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 000000000000..44c15abe7567 --- /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 000000000000..7ff9f5f30dc8 --- /dev/null +++ b/packages/db/test/fixtures/local-prod/db/seed.ts @@ -0,0 +1,8 @@ +import { asDrizzleTable } from '@astrojs/db/utils'; +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/local-prod/package.json b/packages/db/test/fixtures/local-prod/package.json new file mode 100644 index 000000000000..2d11d53479bf --- /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 000000000000..1e2bdc7b975a --- /dev/null +++ b/packages/db/test/fixtures/local-prod/src/pages/index.astro @@ -0,0 +1,11 @@ +--- +/// +import { db, User } from 'astro:db'; + +const users = await db.select().from(User); +--- + +

Users

+ diff --git a/packages/db/test/local-prod.test.js b/packages/db/test/local-prod.test.js new file mode 100644 index 000000000000..29a4fa8b2b3b --- /dev/null +++ b/packages/db/test/local-prod.test.js @@ -0,0 +1,47 @@ +import { expect } from 'chai'; +import testAdapter from '../../astro/test/test-adapter.js'; +import { loadFixture } from '../../astro/test/test-utils.js'; + +describe('astro:db local database', () => { + let fixture; + before(async () => { + fixture = await loadFixture({ + root: new URL('./fixtures/local-prod/', import.meta.url), + output: 'server', + adapter: testAdapter(), + }); + }); + + describe('build (not remote) with DATABASE_FILE env', () => { + const prodDbPath = new URL('./fixtures/basics/dist/astro.db', import.meta.url).toString(); + before(async () => { + process.env.DATABASE_FILE = prodDbPath; + await fixture.build(); + }); + + after(async () => { + delete process.env.DATABASE_FILE; + }); + + it('Can render page', async () => { + const app = await fixture.loadTestAdapterApp(); + const request = new Request('http://example.com/'); + const response = await app.render(request); + expect(response.status).to.equal(200); + }); + }); + + describe('build (not remote)', () => { + it('should throw during the build', async () => { + delete process.env.DATABASE_FILE; + let buildError = null; + try { + await fixture.build(); + } catch(err) { + buildError = err; + } + + expect(buildError).to.be.an('Error'); + }); + }); +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 06c90798a02d..57b8ccc4e194 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3948,6 +3948,15 @@ importers: specifier: workspace:* version: link:../../../../astro + packages/db/test/fixtures/local-prod: + dependencies: + '@astrojs/db': + specifier: workspace:* + version: link:../../.. + astro: + specifier: workspace:* + version: link:../../../../astro + packages/db/test/fixtures/no-apptoken: dependencies: '@astrojs/db': From 32ba90a9c96c02df298afbe75e0475a8aeb126ca Mon Sep 17 00:00:00 2001 From: Matthew Phillips Date: Wed, 27 Mar 2024 09:24:36 -0400 Subject: [PATCH 2/4] Only restrict to server mode --- packages/db/src/core/integration/index.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/db/src/core/integration/index.ts b/packages/db/src/core/integration/index.ts index 487dfc0013cd..8d4e9b41a122 100644 --- a/packages/db/src/core/integration/index.ts +++ b/packages/db/src/core/integration/index.ts @@ -1,7 +1,7 @@ import { existsSync } from 'fs'; import { dirname } from 'path'; import { fileURLToPath } from 'url'; -import type { AstroIntegration } from 'astro'; +import type { AstroConfig, AstroIntegration } from 'astro'; import { mkdir, writeFile } from 'fs/promises'; import { blue, yellow } from 'kleur/colors'; import parseArgs from 'yargs-parser'; @@ -34,12 +34,14 @@ function astroDBIntegration(): AstroIntegration { }, }; let command: 'dev' | 'build' | 'preview'; + let output: AstroConfig['output'] = 'server'; return { name: 'astro:db', hooks: { 'astro:config:setup': async ({ updateConfig, config, command: _command, logger }) => { command = _command; root = config.root; + output = config.output; if (command === 'preview') return; @@ -112,7 +114,7 @@ function astroDBIntegration(): AstroIntegration { }); }, 'astro:build:start': async ({ logger }) => { - if(!connectToStudio && !databaseFileEnvDefined()) { + if(!connectToStudio && !databaseFileEnvDefined() && output === 'server') { throw new Error(`Attempting to build without the --remote flag or the DATABASE_FILE environment variable defined. You probably want to pass --remote to astro build.`) } From 895c4d47354d0329ebb4e618aa598dbb7c773a59 Mon Sep 17 00:00:00 2001 From: Matthew Phillips Date: Wed, 27 Mar 2024 14:59:33 -0400 Subject: [PATCH 3/4] Use an AstroError --- packages/db/src/core/integration/index.ts | 9 +++++--- packages/db/test/local-prod.test.js | 26 +++++++++++++++++++---- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/packages/db/src/core/integration/index.ts b/packages/db/src/core/integration/index.ts index 8d4e9b41a122..e58b823891f1 100644 --- a/packages/db/src/core/integration/index.ts +++ b/packages/db/src/core/integration/index.ts @@ -2,6 +2,7 @@ import { existsSync } from 'fs'; import { dirname } from 'path'; import { fileURLToPath } from 'url'; import type { AstroConfig, AstroIntegration } from 'astro'; +import { AstroError } from 'astro/errors'; import { mkdir, writeFile } from 'fs/promises'; import { blue, yellow } from 'kleur/colors'; import parseArgs from 'yargs-parser'; @@ -114,8 +115,10 @@ function astroDBIntegration(): AstroIntegration { }); }, 'astro:build:start': async ({ logger }) => { - if(!connectToStudio && !databaseFileEnvDefined() && output === 'server') { - throw new Error(`Attempting to build without the --remote flag or the DATABASE_FILE environment variable defined. You probably want to pass --remote to astro build.`) + if(!connectToStudio && !databaseFileEnvDefined() && (output === 'server' || output === 'hybrid')) { + const message = `Attempting to build without the --remote flag or the DATABASE_FILE environment variable defined. You probably want to pass --remote to astro build.`; + const hint = 'Learn more connecting to Studio: https://docs.astro.build/en/guides/astro-db/#connect-to-astro-studio'; + throw new AstroError(message, hint); } logger.info('database: ' + (connectToStudio ? yellow('remote') : blue('local database.'))); @@ -129,7 +132,7 @@ function astroDBIntegration(): AstroIntegration { function databaseFileEnvDefined() { const env = loadEnv('', process.cwd()); - return env.DATABASE_FILE != null || process.env.DATABASE_FILE != null; + return env.ASTRO_DATABASE_FILE != null || process.env.ASTRO_DATABASE_FILE != null; } export function integration(): AstroIntegration[] { diff --git a/packages/db/test/local-prod.test.js b/packages/db/test/local-prod.test.js index 29a4fa8b2b3b..16682d57aaf9 100644 --- a/packages/db/test/local-prod.test.js +++ b/packages/db/test/local-prod.test.js @@ -15,12 +15,12 @@ describe('astro:db local database', () => { describe('build (not remote) with DATABASE_FILE env', () => { const prodDbPath = new URL('./fixtures/basics/dist/astro.db', import.meta.url).toString(); before(async () => { - process.env.DATABASE_FILE = prodDbPath; + process.env.ASTRO_DATABASE_FILE = prodDbPath; await fixture.build(); }); after(async () => { - delete process.env.DATABASE_FILE; + delete process.env.ASTRO_DATABASE_FILE; }); it('Can render page', async () => { @@ -32,8 +32,8 @@ describe('astro:db local database', () => { }); describe('build (not remote)', () => { - it('should throw during the build', async () => { - delete process.env.DATABASE_FILE; + it('should throw during the build for server output', async () => { + delete process.env.ASTRO_DATABASE_FILE; let buildError = null; try { await fixture.build(); @@ -43,5 +43,23 @@ describe('astro:db local database', () => { expect(buildError).to.be.an('Error'); }); + + it('should throw during the build for hybrid output', async () => { + let fixture2 = await loadFixture({ + root: new URL('./fixtures/local-prod/', import.meta.url), + output: 'hybrid', + adapter: testAdapter(), + }); + + delete process.env.ASTRO_DATABASE_FILE; + let buildError = null; + try { + await fixture2.build(); + } catch(err) { + buildError = err; + } + + expect(buildError).to.be.an('Error'); + }); }); }); From db47e234eec78d237c19ca7c267bea7486f97e20 Mon Sep 17 00:00:00 2001 From: Matthew Phillips Date: Wed, 27 Mar 2024 15:00:43 -0400 Subject: [PATCH 4/4] Update code --- packages/db/src/core/integration/index.ts | 2 +- packages/db/src/core/integration/vite-plugin-db.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/db/src/core/integration/index.ts b/packages/db/src/core/integration/index.ts index e58b823891f1..d288475a5d79 100644 --- a/packages/db/src/core/integration/index.ts +++ b/packages/db/src/core/integration/index.ts @@ -116,7 +116,7 @@ function astroDBIntegration(): AstroIntegration { }, 'astro:build:start': async ({ logger }) => { if(!connectToStudio && !databaseFileEnvDefined() && (output === 'server' || output === 'hybrid')) { - const message = `Attempting to build without the --remote flag or the DATABASE_FILE environment variable defined. You probably want to pass --remote to astro build.`; + const message = `Attempting to build without the --remote flag or the ASTRO_DATABASE_FILE environment variable defined. You probably want to pass --remote to astro build.`; const hint = 'Learn more connecting to Studio: https://docs.astro.build/en/guides/astro-db/#connect-to-astro-studio'; throw new AstroError(message, hint); } diff --git a/packages/db/src/core/integration/vite-plugin-db.ts b/packages/db/src/core/integration/vite-plugin-db.ts index 9b4b79e8d861..34685e958fd5 100644 --- a/packages/db/src/core/integration/vite-plugin-db.ts +++ b/packages/db/src/core/integration/vite-plugin-db.ts @@ -118,7 +118,7 @@ import { asDrizzleTable, createLocalDatabaseClient } from ${RUNTIME_IMPORT}; ${shouldSeed ? `import { seedLocal } from ${RUNTIME_IMPORT};` : ''} ${shouldSeed ? integrationSeedImportStatements.join('\n') : ''} -const dbUrl = import.meta.env.DATABASE_FILE ?? ${JSON.stringify(dbUrl)}; +const dbUrl = import.meta.env.ASTRO_DATABASE_FILE ?? ${JSON.stringify(dbUrl)}; export const db = createLocalDatabaseClient({ dbUrl });