Skip to content

Commit

Permalink
Document custom companions better
Browse files Browse the repository at this point in the history
  • Loading branch information
simolus3 committed Nov 27, 2024
1 parent cd1eb0a commit 492d35c
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 14 deletions.
10 changes: 9 additions & 1 deletion docs/docs/dart_api/rows.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,6 @@ This class is introduced for two reasons:
To solve this problem, companions represent partial rows by using Drift's `Value` class.
`Value`s store a value (which can be nullable) or explicitly indicate that a value is _absent_:


{{ load_snippet('generated-value','lib/snippets/dart_api/dataclass.dart.excerpt.json') }}

1. Since the `id` is `autoIncrement()`, the database will pick a value for us and no value
Expand All @@ -139,6 +138,15 @@ To solve this problem, companions represent partial rows by using Drift's `Value
on companions that avoids `Value` wrappers where they are not required.
This insert could be written as `UsersCompanion.insert(username: 'user')`

### Updating with SQL expressions

Companions also provide a `.custom` method used when mixing values and SQL expressions for
updates or deletes.
For instance, this update statement changes all the names of all rows in the `users` table
to be lower-case:

{{ load_snippet('companion-custom','lib/snippets/dart_api/dataclass.dart.excerpt.json') }}

## Custom dataclass

The generated dataclass works well for most cases, but you might want to use your own class to
Expand Down
31 changes: 20 additions & 11 deletions docs/docs/dart_api/writes.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ description: Select rows or invidiual columns from tables in Dart
## Updates and deletes

You can use the generated classes to update individual fields of any row:

```dart
Future moveImportantTasksIntoCategory(Category target) {
// for updates, we use the "companion" version of a generated class. This wraps the
Expand Down Expand Up @@ -36,12 +37,12 @@ Future feelingLazy() {
return (delete(todos)..where((t) => t.id.isSmallerThanValue(10))).go();
}
```
__⚠️ Caution:__ If you don't explicitly add a `where` clause on updates or deletes,
__⚠️ Caution:__ If you don't explicitly add a `where` clause on updates or deletes,
the statement will affect all rows in the table!

!!! note "Entries, companions - why do we need all of this?"


You might have noticed that we used a `TodosCompanion` for the first update instead of
just passing a `Todo`. Drift generates the `Todo` class (also called _data
class_ for the table) to hold a __full__ row with all its data. For _partial_ data,
Expand All @@ -50,17 +51,27 @@ the statement will affect all rows in the table!
Why is that necessary? If a field was set to `null`, we wouldn't know whether we need
to set that column back to null in the database or if we should just leave it unchanged.
Fields in the companions have a special `Value.absent()` state which makes this explicit.

Companions also have a special constructor for inserts - all columns which don't have
a default value and aren't nullable are marked `@required` on that constructor. This makes
companions easier to use for inserts because you know which fields to set.


### Updating with SQL expressions

In some cases, you might want to update many rows based on their current value.
One option would be to first select the affected rows into Dart objects, create companions
based on those results and use them for updates.
If the update can be described in SQL, a more efficient way is available with `Companion.custom`:

{{ load_snippet('companion-custom','lib/snippets/dart_api/dataclass.dart.excerpt.json') }}

Here, the `name` column in the `users` table is changed to lowercase for all existing rows.
Since `.lower()` on columns is implemented in the database, the rows don't have to be loaded
into Dart during the statement.

## Inserts
You can very easily insert any valid object into tables. As some values can be absent
(like default values that we don't have to set explicitly), we again use the
(like default values that we don't have to set explicitly), we again use the
companion version.
```dart
// returns the generated id
Expand Down Expand Up @@ -112,8 +123,6 @@ This makes them suitable for bulk insert or update operations.

### Upserts



Upserts are a feature from newer sqlite3 versions that allows an insert to
behave like an update if a conflicting row already exists.

Expand Down Expand Up @@ -151,17 +160,17 @@ counter if it already exists:

!!! note "Unique constraints and conflict targets"


Both `insertOnConflictUpdate` and `onConflict: DoUpdate` use an `DO UPDATE`
upsert in sql. This requires us to provide a so-called "conflict target", a
set of columns to check for uniqueness violations. By default, drift will use
the table's primary key as conflict target. That works in most cases, but if
you have custom `UNIQUE` constraints on some columns, you'll need to use
the `target` parameter on `DoUpdate` in Dart to include those columns:

{{ load_snippet('upsert-target','lib/snippets/modular/upserts.dart.excerpt.json') }}





Expand Down
4 changes: 2 additions & 2 deletions docs/docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ description: Welcome to drift's documentation. This site shows you what drift ca
## Welcome to drift

Drift is a reactive persistence library for Dart and Flutter applications. It's built on top
of database libraries like [the sqlite3 package](https://pub.dev/packages/sqlite3), [sqflite](https://pub.dev/packages/sqflite) or [sql.js](https://github.com/sql-js/sql.js/)
and provides additional features, like:
of database libraries like [the sqlite3 package](https://pub.dev/packages/sqlite3), [sqflite](https://pub.dev/packages/sqflite) and others.
Adding to these libraries, drift provides additional features, like:

- __Type safety__: Instead of writing SQL queries manually and parsing the `List<Map<String, dynamic>>` that they
return, drift turns rows into objects of your choice.
Expand Down
6 changes: 6 additions & 0 deletions docs/lib/snippets/dart_api/dataclass.dart
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,12 @@ void _queryManager(Database db) async {
await (db.update(db.users)..where((tbl) => tbl.id.equals(1)))
.write(UsersCompanion(username: Value("Updated name")));
// #enddocregion generated-value

// #docregion companion-custom
await db
.update(db.users)
.write(UsersCompanion.custom(username: db.users.username.lower()));
// #enddocregion companion-custom
}

void _queryCore(Database db) async {
Expand Down

0 comments on commit 492d35c

Please sign in to comment.