Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/06-concepts/06-database/05-crud.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,8 @@ var updatedCompany = await Company.db.updateById(

The `updateById` method updates only the specified columns for the row with the given ID. The method returns the updated row, or throws a `DatabaseUpdateRowException` if no row with the given ID exists. At least one column must be specified in the `columnValues` parameter, otherwise an `ArgumentError` will be thrown.

See [Database exceptions](./exceptions) for the full set of database exception types and when they are thrown.

You can also update columns to null values:

```dart
Expand Down
92 changes: 92 additions & 0 deletions docs/06-concepts/06-database/15-exceptions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# Database exceptions

Serverpod wraps database failures in exceptions that implement `DatabaseException`.
This gives you one common type to catch for database failures and more specific
types when you want to handle a known operation failure.

```dart
try {
await Company.db.updateById(
session,
companyId,
columnValues: (t) => [t.name('New name')],
);
} on DatabaseUpdateRowException {
// No row with the provided id was updated.
} on DatabaseQueryException catch (e) {
session.log(
'Database query failed with code ${e.code}',
exception: e,
);
} on DatabaseException catch (e) {
session.log('Database operation failed', exception: e);
}
```

When a database exception is not caught inside an endpoint, it follows
Serverpod's normal endpoint exception handling and is logged as an uncaught
server exception. Serverpod does not serialize database exception details and
send them to the client; those details stay server-side in the logs.

## Exception types

| Exception | When it is thrown |
| --- | --- |
| `DatabaseException` | The common interface for database exceptions. Catch this when you want one handler for any database failure. |
| `DatabaseQueryException` | A query failed in the database adapter, often because the database rejected the SQL or a constraint was violated. |
| `DatabaseInsertRowException` | A single-row insert operation did not insert exactly one row. |
| `DatabaseUpdateRowException` | A single-row update operation did not update the expected row, for example when `updateById` receives an id that does not exist. |
| `DatabaseDeleteRowException` | A single-row delete operation did not delete the expected row. |
| `DatabaseUpsertRowException` | A single-row upsert operation unexpectedly returned more than one row. |
| `SqliteForeignKeyViolationException` | A SQLite foreign key integrity check found one or more violating rows. |
Comment on lines +33 to +41

## Query exception details

`DatabaseQueryException` exposes optional fields from the underlying database
adapter. These fields are useful for logging and for handling known database
errors:

- `code`
- `detail`
- `hint`
- `tableName`
- `columnName`
- `constraintName`
- `position`

For example, PostgreSQL constraint errors can include a database error code and
the violated constraint name. These values are database-adapter details, so
write defensive code that handles `null` values.

```dart
try {
await Company.db.insertRow(session, company);
} on DatabaseQueryException catch (e) {
if (e.constraintName == 'company_name_key') {
// Handle a duplicate company name here.
return;
}
// Let unexpected database query errors keep their original stack trace.
rethrow;
}
```

## Operation exceptions

The row-level operation exceptions describe cases where Serverpod expected one
row to be affected but the database result did not match that expectation. For
example, `updateById` throws a `DatabaseUpdateRowException` when no row exists
for the id you pass in.

Batch and filtered operations have their own documented behavior. Some methods,
such as `updateWhere` or `deleteWhere`, can validly affect zero rows and return
an empty list instead of throwing a row-level exception.

## SQLite foreign key checks

When using the client-side SQLite database, Serverpod can run a SQLite foreign
key integrity check when it verifies database integrity, such as after applying
migrations in debug mode. If SQLite reports invalid foreign key references,
Serverpod throws `SqliteForeignKeyViolationException`. The exception contains
the violating rows returned by SQLite's `PRAGMA foreign_key_check`.
Loading