summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--.changeset/tidy-cows-change.md5
-rw-r--r--packages/db/src/runtime/db-client.ts31
-rw-r--r--packages/db/src/runtime/drizzle.ts25
-rw-r--r--packages/db/src/runtime/utils.ts17
-rw-r--r--packages/db/test/error-handling.test.js20
-rw-r--r--packages/db/test/fixtures/error-handling/src/pages/foreign-key-constraint.json.ts4
-rw-r--r--packages/db/test/test-utils.js7
7 files changed, 66 insertions, 43 deletions
diff --git a/.changeset/tidy-cows-change.md b/.changeset/tidy-cows-change.md
new file mode 100644
index 000000000..21438fcbd
--- /dev/null
+++ b/.changeset/tidy-cows-change.md
@@ -0,0 +1,5 @@
+---
+"@astrojs/db": patch
+---
+
+Fix `isDbError()` returning `false` for remote database errors. Astro will now return a `LibsqlError` in development and production.
diff --git a/packages/db/src/runtime/db-client.ts b/packages/db/src/runtime/db-client.ts
index d52af72fc..3bea14b0a 100644
--- a/packages/db/src/runtime/db-client.ts
+++ b/packages/db/src/runtime/db-client.ts
@@ -4,7 +4,7 @@ import type { LibSQLDatabase } from 'drizzle-orm/libsql';
import { drizzle as drizzleLibsql } from 'drizzle-orm/libsql';
import { type SqliteRemoteDatabase, drizzle as drizzleProxy } from 'drizzle-orm/sqlite-proxy';
import { z } from 'zod';
-import { AstroDbError, safeFetch } from './utils.js';
+import { DetailedLibsqlError, safeFetch } from './utils.js';
const isWebContainer = !!process.versions?.webcontainer;
@@ -65,7 +65,10 @@ export function createRemoteDatabaseClient(appToken: string, remoteDbURL: string
const json = await res.json();
remoteResult = remoteResultSchema.parse(json);
} catch (e) {
- throw new AstroDbError(await getUnexpectedResponseMessage(res));
+ throw new DetailedLibsqlError({
+ message: await getUnexpectedResponseMessage(res),
+ code: KNOWN_ERROR_CODES.SQL_QUERY_FAILED,
+ });
}
if (method === 'run') return remoteResult;
@@ -107,7 +110,10 @@ export function createRemoteDatabaseClient(appToken: string, remoteDbURL: string
const json = await res.json();
remoteResults = z.array(remoteResultSchema).parse(json);
} catch (e) {
- throw new AstroDbError(await getUnexpectedResponseMessage(res));
+ throw new DetailedLibsqlError({
+ message: await getUnexpectedResponseMessage(res),
+ code: KNOWN_ERROR_CODES.SQL_QUERY_FAILED,
+ });
}
let results: any[] = [];
for (const [idx, rawResult] of remoteResults.entries()) {
@@ -151,22 +157,25 @@ const KNOWN_ERROR_CODES = {
};
const getUnexpectedResponseMessage = async (response: Response) =>
- `Unexpected response from remote database:\n(Status ${response.status}) ${await response.text()}`;
+ `Unexpected response from remote database:\n(Status ${response.status}) ${await response.clone().text()}`;
-async function parseRemoteError(response: Response): Promise<AstroDbError> {
+async function parseRemoteError(response: Response): Promise<DetailedLibsqlError> {
let error;
try {
- error = errorSchema.parse(await response.json()).error;
+ error = errorSchema.parse(await response.clone().json()).error;
} catch (e) {
- return new AstroDbError(await getUnexpectedResponseMessage(response));
+ return new DetailedLibsqlError({
+ message: await getUnexpectedResponseMessage(response),
+ code: KNOWN_ERROR_CODES.SQL_QUERY_FAILED,
+ });
}
// Strip LibSQL error prefixes
- let details =
- error.details?.replace(/.*SQLite error: /, '') ??
- `(Code ${error.code}) \nError querying remote database.`;
+ let baseDetails = error.details?.replace(/.*SQLite error: /, '') ?? 'Error querying remote database.';
+ // Remove duplicated "code" in details
+ const details = baseDetails.slice(baseDetails.indexOf(':') + 1).trim();
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);
+ return new DetailedLibsqlError({ message: details, code: error.code, hint });
}
diff --git a/packages/db/src/runtime/drizzle.ts b/packages/db/src/runtime/drizzle.ts
deleted file mode 100644
index d2dfa9e32..000000000
--- a/packages/db/src/runtime/drizzle.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-// Drizzle utilities we expose directly from `astro:db`
-export {
- sql,
- eq,
- gt,
- gte,
- lt,
- lte,
- ne,
- isNull,
- isNotNull,
- inArray,
- notInArray,
- exists,
- notExists,
- between,
- notBetween,
- like,
- notIlike,
- not,
- asc,
- desc,
- and,
- or,
-} from 'drizzle-orm';
diff --git a/packages/db/src/runtime/utils.ts b/packages/db/src/runtime/utils.ts
index 2fe837d8f..0c2e820e0 100644
--- a/packages/db/src/runtime/utils.ts
+++ b/packages/db/src/runtime/utils.ts
@@ -1,3 +1,4 @@
+import { LibsqlError } from '@libsql/client';
import { AstroError } from 'astro/errors';
const isWindows = process?.platform === 'win32';
@@ -25,6 +26,22 @@ export class AstroDbError extends AstroError {
name = 'Astro DB Error';
}
+export class DetailedLibsqlError extends LibsqlError {
+ name = 'Astro DB Error';
+ hint?: string;
+
+ constructor({
+ message,
+ code,
+ hint,
+ rawCode,
+ cause,
+ }: { message: string; code: string; hint?: string; rawCode?: number; cause?: Error }) {
+ super(message, code, rawCode, cause);
+ this.hint = hint;
+ }
+}
+
function slash(path: string) {
const isExtendedLengthPath = path.startsWith('\\\\?\\');
diff --git a/packages/db/test/error-handling.test.js b/packages/db/test/error-handling.test.js
index d67bd161b..9d40507b2 100644
--- a/packages/db/test/error-handling.test.js
+++ b/packages/db/test/error-handling.test.js
@@ -1,5 +1,6 @@
import { expect } from 'chai';
import { loadFixture } from '../../astro/test/test-utils.js';
+import { setupRemoteDbServer } from './test-utils.js';
const foreignKeyConstraintError =
'LibsqlError: SQLITE_CONSTRAINT_FOREIGNKEY: FOREIGN KEY constraint failed';
@@ -25,18 +26,31 @@ describe('astro:db - error handling', () => {
it('Raises foreign key constraint LibsqlError', async () => {
const json = await fixture.fetch('/foreign-key-constraint.json').then((res) => res.json());
- expect(json.error).to.equal(foreignKeyConstraintError);
+ expect(json).to.deep.equal({
+ message: foreignKeyConstraintError,
+ code: 'SQLITE_CONSTRAINT_FOREIGNKEY',
+ });
});
});
- describe('build', () => {
+ describe('build --remote', () => {
+ let remoteDbServer;
+
before(async () => {
+ remoteDbServer = await setupRemoteDbServer(fixture.config);
await fixture.build();
});
+ after(async () => {
+ await remoteDbServer?.stop();
+ });
+
it('Raises foreign key constraint LibsqlError', async () => {
const json = await fixture.readFile('/foreign-key-constraint.json');
- expect(JSON.parse(json).error).to.equal(foreignKeyConstraintError);
+ expect(JSON.parse(json)).to.deep.equal({
+ message: foreignKeyConstraintError,
+ code: 'SQLITE_CONSTRAINT_FOREIGNKEY',
+ });
});
});
});
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
index 8e6bad8c3..358a9a95c 100644
--- 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
@@ -11,8 +11,8 @@ export const GET: APIRoute = async () => {
});
} catch (e) {
if (isDbError(e)) {
- return new Response(JSON.stringify({ error: `LibsqlError: ${e.message}` }));
+ return new Response(JSON.stringify({ message: `LibsqlError: ${e.message}`, code: e.code }));
}
}
- return new Response(JSON.stringify({ error: 'Did not raise expected exception' }));
+ return new Response(JSON.stringify({ message: 'Did not raise expected exception' }));
};
diff --git a/packages/db/test/test-utils.js b/packages/db/test/test-utils.js
index 8be80a879..9f5ba6d9d 100644
--- a/packages/db/test/test-utils.js
+++ b/packages/db/test/test-utils.js
@@ -1,5 +1,5 @@
import { createServer } from 'node:http';
-import { createClient } from '@libsql/client';
+import { LibsqlError, createClient } from '@libsql/client';
import { z } from 'zod';
import { cli } from '../dist/core/cli/index.js';
import { resolveDbConfig } from '../dist/core/load-file.js';
@@ -112,7 +112,10 @@ function createRemoteDbServer() {
res.end(
JSON.stringify({
success: false,
- message: e.message,
+ error: {
+ code: e instanceof LibsqlError ? e.code : 'SQLITE_QUERY_FAILED',
+ details: e.message,
+ }
})
);
}