-
-
Notifications
You must be signed in to change notification settings - Fork 722
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add proper error handling and wrapping #376
Comments
What is missing? |
Is this for returning errors, so we can prevent bugs from forgetting to handle exceptions and from incorrectly guessing the error type? |
This would be super helpful for our code quality. I noticed this when Drizzle threw me an error, when I tested our API with a wrong resource ID to test if the 404 works. Postgres was already mad, because the wrong ID wasn't a valid UUIDv4. Catching this now and throwing an appropriate 404 is kinda smelly. Error codes would be nice to have! |
Another example of how error handling could improve code quality is with errors raised from constraints. For example, when see a unique containst error, we get a fairly raw looking error object in our {
code: '23505'
column: undefined
constraint: 'users_email_index'
dataType: undefined
detail: 'Key (email)=(user@example.com) already exists.'
file: 'nbtinsert.c'
hint: undefined
internalPosition: undefined
internalQuery: undefined
length: 231
line: '664'
name: 'error'
position: undefined
routine: '_bt_check_unique'
schema: 'public'
severity: 'ERROR'
table: 'users'
where: undefined
message: 'duplicate key value violates unique constraint "users_email_index"'
stack: <stacktrace_goes_here>
} We then need to check that certain properties exist with specific values to determine what type of error it was. A few options are: // Check the constraint name or message
e.constraint === 'users_email_index';
//or
e.message === 'duplicate key value violates unique constraint "users_email_index"';
// Checking the detail field with a regex
const rx = new RegExp(/Key \(email\).*already exists/);
rx.test(e.detail);
// Checking more internal specifics
e.routine === '_bt_check_unique'; It would be really nice to have some higher level type that hides the internals and allows for simpler use within a |
💎 $50 bounty created by @john-griffin |
What's the exactly scope of this? @john-griffin |
Is the issue still open? I am interested in working on this. |
Hey. Yes this is still open. From this issue we (@john-griffin and myself) are hoping to achieve a higher level error to work with that has better support for typescript. For example, looking at my comment above, all of the examples rely on checking strings for certain values in a way that doesn't allow us to capture typos at compile time. I don't have a firm solution and maybe the drizzle team can make some recommendations here, but if we could achieve a type safe way to check for expected database errors, that would achieve the scope of the bounty. Here are some rough ideas that we have discussed, but are by no means prescriptive. // Generic error class
class QueryError extends Error {
type: "NonNull" | "UniqueConstraint" | "CheckConstraint" | "ForeignKey" // etc...
table: string; // Can this be typed to all known tables
field: string; // Can this by typed to all known fields
message: string;
}
// or
// Error type specific error classes
class UniqueConstraintError extends Error {
table: string; // Can this be typed to all known tables
field: string; // Can this by typed to all known fields
message: string;
}
class NonNullError extends Error {
table: string; // Can this be typed to all known tables
field: string; // Can this by typed to all known fields
message: string;
} Something like this would allow checking for errors without dealing directly with the error class from the catch (e) {
if (e instanceof QueryError) {
if (e.type === 'unique' and e.field === 'email') { ... }
if (e.type === 'unknown_type' and e.field === 'email') { ... } // < type error
}
}
// or
catch (e) {
if (e instanceof UniqueConstraintError) {
if (e.field === 'email') { ... }
if (e.field === 'unknown_field') { ... } // < type error
}
} Again, happy to defer to the drizzle team for API specific guidance. |
add error classes fast bro |
any updates on where this is prioritized in roadmap? Seems like someone might be open to working on it, as long they get guidance from drizzle team on what would work best for drizzle's API? @Angelelz |
Bumping @afogel 's question, good error handling would be great for displaying the errors on the forms. |
Yet another |
+1 |
1 similar comment
+1 |
+1 It would really help alot with debugging and error reporting if you had a usable stacktrace. Had a time figuring out why that it was my
|
@Angelelz just a gentle bump reminder here -- any additional guidance the team can give here? |
For the ones having issues with invalid uuids, I have kind of a work around. I am using Sveltekit and put this in my +page.server.ts: if (params.uuid.length !== 36) {
throw error(404, 'Not found here');
}
const [event] = await db.select().from(eventTable).where(eq(eventTable.uuid, params.uuid));
if (!event) {
throw error(404, 'Not found here');
} You can even add some regex to check if there is a combination of 4 hyphens and 32 letters/numbers. The best solution would still be a way to handle those errors. |
I'm working with superforms and trpc. // +page.server.ts
export const actions: Actions = {
default: async ({ request, fetch }) => {
const form = await superValidate(request, zod(schema));
if (!form.valid) {
return fail(400, { form });
}
try {
const trpc = trpcOnServer(fetch);
const [newClient] = await trpc.clients.save.mutate({ name: form.data.clientName });
setMessage(form, `The project was created correctly.`);
} catch (error) {
if (error instanceof TRPCError || error instanceof TRPCClientError) {
if (error.message == 'duplicate key value violates unique constraint "client_name_unique"')
setError(form, 'clientName', 'Client name already exists.');
} else {
setMessage(form, 'Could not create the project.', {
status: 400
});
}
}
return { form };
}
}; but would be good to be able to avoid hardcoding it |
+1 on this - would be great! |
+1 would indeed be nice to have |
+1 love to see good error handling from drizzle |
It would be really good to have at least some simple examples on error handling in the docs. |
I use this helper function to help alleviate the pain: type QueryError = Error & { code?: unknown }
export async function query<D, P extends QueryPromise<D>>(promise: P) {
try {
const result = await promise
return { data: result, error: null }
} catch (e) {
if (e instanceof Error) {
return { data: null, error: e as QueryError }
} else {
throw e
}
}
} Example usage: const { data, error } = await query(
db.insert(users).values({
email,
}),
)
if (error?.code === '23505' && error.message === 'duplicate key value violates unique constraint "users_email_unique"') {
return fail(400, 'Email already in use')
} else if (!data) {
throw error
}
console.log(data) |
We can also rely on the error Unique constraint: try {
return await this.db.insert(schema.users).values(user).returning();
} catch (error) {
const code: string = error?.code;
// Unique constraint:
if (code === '23505') {
const detail: string = error?.detail;
const matches = detail.match(/\((.*?)\)/g);
if (matches) {
const [key, value] = matches.map((match) => match.replace(/\(|\)/g, ''));
throw new BadRequestException(`An entry with the value '${value}' already exists for the field '${key}'.`);
}
}
// Not-Null constraint
else if (code === '23502') {
const table: string = error?.table;
const column: string = error?.column;
throw new BadRequestException(`The column '${column}' in table '${table}' cannot be null.`);
}
} But for other validation constraints, like VARCHAR(50), the error details are a bit limited: {
message: value too long for type character varying(50)
length: 98,
severity: 'ERROR',
code: '22001',
detail: undefined,
hint: undefined,
position: undefined,
internalPosition: undefined,
internalQuery: undefined,
where: undefined,
schema: undefined,
table: undefined,
column: undefined,
dataType: undefined,
constraint: undefined,
file: 'varchar.c',
line: '638',
routine: 'varchar'
} |
+1 much needed feature |
+1 for this |
I ended creating my own middleware for drizzle, and it gives me a lot of control, including the ability to finally see errors in my application code without having to put try catch on all my queries: the code is very opinionated for a remix/express app, so really just to give inspirations more than a clear guide |
+1 here as well. |
bump |
+1, I need to do proper error handling,thanks! |
bump |
+1 |
2 similar comments
+1 |
+1 |
Just started to create logic for handle errors from drizzle in my app, so... +1 |
+1 |
1 similar comment
+1 |
please stop the "+1" comments and use the thumbs-up reactions button. thanks. |
No description provided.
The text was updated successfully, but these errors were encountered: