diff options
Diffstat (limited to 'packages/db/src/runtime/db-client.ts')
-rw-r--r-- | packages/db/src/runtime/db-client.ts | 58 |
1 files changed, 40 insertions, 18 deletions
diff --git a/packages/db/src/runtime/db-client.ts b/packages/db/src/runtime/db-client.ts index 50e1861f4..4518af174 100644 --- a/packages/db/src/runtime/db-client.ts +++ b/packages/db/src/runtime/db-client.ts @@ -5,6 +5,7 @@ import { drizzle as drizzleLibsql } from 'drizzle-orm/libsql'; import { type SqliteRemoteDatabase, drizzle as drizzleProxy } from 'drizzle-orm/sqlite-proxy'; import { z } from 'zod'; import { safeFetch } from './utils.js'; +import { AstroDbError } from '../utils.js'; const isWebContainer = !!process.versions?.webcontainer; @@ -55,10 +56,8 @@ export function createRemoteDatabaseClient(appToken: string, remoteDbURL: string }, body: JSON.stringify(requestBody), }, - (response) => { - throw new Error( - `Failed to execute query.\nQuery: ${sql}\nFull error: ${response.status} ${response.statusText}` - ); + async (response) => { + throw await parseRemoteError(response); } ); @@ -67,11 +66,7 @@ export function createRemoteDatabaseClient(appToken: string, remoteDbURL: string const json = await res.json(); remoteResult = remoteResultSchema.parse(json); } catch (e) { - throw new Error( - `Failed to execute query.\nQuery: ${sql}\nFull error: Unexpected JSON response. ${ - e instanceof Error ? e.message : String(e) - }` - ); + throw new AstroDbError(await getUnexpectedResponseMessage(res)); } if (method === 'run') return remoteResult; @@ -103,10 +98,8 @@ export function createRemoteDatabaseClient(appToken: string, remoteDbURL: string }, body: JSON.stringify(stmts), }, - (response) => { - throw new Error( - `Failed to execute batch queries.\nFull error: ${response.status} ${response.statusText}}` - ); + async (response) => { + throw await parseRemoteError(response); } ); @@ -115,11 +108,7 @@ export function createRemoteDatabaseClient(appToken: string, remoteDbURL: string const json = await res.json(); remoteResults = z.array(remoteResultSchema).parse(json); } catch (e) { - throw new Error( - `Failed to execute batch queries.\nFull error: Unexpected JSON response. ${ - e instanceof Error ? e.message : String(e) - }` - ); + throw new AstroDbError(await getUnexpectedResponseMessage(res)); } let results: any[] = []; for (const [idx, rawResult] of remoteResults.entries()) { @@ -149,3 +138,36 @@ export function createRemoteDatabaseClient(appToken: string, remoteDbURL: string applyTransactionNotSupported(db); return db; } + +const errorSchema = z.object({ + success: z.boolean(), + error: z.object({ + code: z.string(), + details: z.string().optional(), + }), +}); + +const KNOWN_ERROR_CODES = { + SQL_QUERY_FAILED: 'SQL_QUERY_FAILED', +}; + +const getUnexpectedResponseMessage = async (response: Response) => + `Unexpected response from remote database:\n(Status ${response.status}) ${await response.text()}`; + +async function parseRemoteError(response: Response): Promise<AstroDbError> { + let error; + try { + error = errorSchema.parse(await response.json()).error; + } catch (e) { + return new AstroDbError(await getUnexpectedResponseMessage(response)); + } + // Strip LibSQL error prefixes + let details = + error.details?.replace(/.*SQLite error: /, '') ?? + `(Code ${error.code}) \nError querying remote database.`; + let hint = `See the Astro DB guide for query and push instructions: https://docs.astro.build/en/guides/astro-db/#query-your-database`; + if (error.code === KNOWN_ERROR_CODES.SQL_QUERY_FAILED && details.includes('no such table')) { + hint = `Did you run \`astro db push\` to push your latest table schemas?`; + } + return new AstroDbError(details, hint); +} |