Move more content over

This commit is contained in:
Simon Binder
2025-10-05 18:02:20 +02:00
parent e12a13a3ba
commit 29e9a7fc8f
41 changed files with 0 additions and 403 deletions
-184
View File
@@ -1,184 +0,0 @@
---
title: FAQ
---
## Using the database
If you've created a `MyDatabase` class by following the [getting started guide](setup.md), you
still need to somehow obtain an instance of it. It's recommended to only have one (singleton) instance of your database,
so you could store that instance in a global variable:
### Vanilla flutter
```dart
late MyDatabase database;
void main() {
database = MyDatabase();
runApp(MyFlutterApp());
}
```
It would be cleaner to use `InheritedWidgets` for that, and the `provider` package helps here:
### Provider
If you're using the [provider](https://pub.dev/packages/provider) package, you can wrap your top-level widget in a
provider that manages the database instance:
```dart
void main() {
runApp(
Provider<MyDatabase>(
create: (context) => MyDatabase(),
child: MyFlutterApp(),
dispose: (context, db) => db.close(),
),
);
}
```
Your widgets would then have access to the database using `Provider.of<MyDatabase>(context)`.
### GetX
If you're using the [GetX](https://pub.dev/packages/get) package, you can add it as a service that manages the database instance:.
```dart
void main() {
Get.put(MyDatabase());
runApp(MyFlutterApp());
}
```
Your widgets would then have access to the database using `Get.find<MyDatabase>().your_method`.
### A more complex architecture
If you're strict on keeping your business logic out of the widget layer, you probably use some dependency injection
framework like `kiwi` or `get_it` to instantiate services and view models. Creating a singleton instance of `MyDatabase`
in your favorite dependency injection framework for flutter hence solves this problem for you.
## Why am I getting no such table errors?
If you add another table after your app has already been installed, you need to write a [migration](Migrations/index.md)
that covers creating that table. If you're in the process of developing your app and want to use un- and reinstall your app
instead of writing migrations, that's fine too. Please note that your apps data might be backed up on Android, so
manually deleting your app's data instead of a reinstall is necessary on some devices.
## How do I fix lints in generated files?
Based on your linter settings, you might see some warnings in the `.g.dart` files generated by drift. Since lints are mainly used for
human-written code, we recommend to disable static analysis on generated files. For that, generate a top-level file called
`analysis_options.yaml` in your project and add this content:
```yaml
analyzer:
exclude:
- "**/*.g.dart"
```
You might have to restart your IDE for the changes to apply.
## How can I inspect generated SQL?
All database implementations (`NativeDatabase`, `FlutterQueryExecutor`, ...) have a `logStatements` parameter that
you can set to `true`. When enabled, drift will print the statements it runs.
## How do I insert data on the first app start?
You can populate the database on the first start of your app with a custom [migration strategy](Migrations/index.md).
To insert data when the database is created (which usually happens when the app is first run), you can use this:
```dart
MigrationStrategy(
onCreate: (m) async {
await m.createAll(); // create all tables
await into(myTable).insert(...); // insert on first run.
}
)
```
You can even use transactions or batches in the `onCreate` callback.
Another approach is to include a pre-populated database in your app's asset and use that one:
```dart
QueryExecutor databaseWithDefaultAsset(File file, String asset) {
// A LazyDatabase lets us do async initialization work.
return LazyDatabase(() async {
if (!await file.exists()) {
// Database does not exist yet, use default from asset
final content = await rootBundle.load(asset);
await file.parent.create(recursive: true);
await file.writeAsBytes(content.buffer.asUint8List(0));
}
});
}
```
## My generated code is using another class with the same name
When you have an imported a class with the same name as the should-be generated
ones on your `database.dart` file and your run `build_runner` there is a known
problem about it using the imported class instead of the generated ones.
To solve that, if you can, you can enable
[modular code generation](./generation_options/modular.md).
It slightly changes how drift is used, but you probably will only have to update
a few files to change parts to imports. The big difference is that it allows drift
to emit a standalone library file instead of a part - that can have its own imports,
so this is much easier and we'll use the correct imports even when the same name
classes are imported in your `database.dart` file.
## How does drift compare to X?
There are a variety of good persistence libraries for Dart and Flutter.
That said, here's an incomplete (and obviously biased) list of great libraries and how drift compares to them.
If you have experience with any of these (or other) libraries and want to share how they compare to drift, please
feel invited to contribute to this page.
### sqflite, sqlite3
Sqflite is a Flutter package that provides bindings to the sqlite api for both iOS and Android. It's well maintained
and has stable api. In fact, the `moor_flutter` or `drift_sqflite` variants are built on top of sqflite. But even though sqflite
has an api to construct some simple queries in Dart, drift goes a bit further by
* Generating type-safe mapping code for your queries
* Providing auto-updating streams for queries
* Managing `CREATE TABLE` statements and most schema migrations
* A more fluent api to compose queries
Still, for most apps that don't need these features, sqflite can be a very fitting persistence library.
The same thing applies to the `sqlite3` package - `package:drift/native.dart` uses that library, but provides
additional services on top.
### sqlcool
Sqlcool is a lightweight library around sqflite that makes writing queries and schema management easier, it also has
auto-updating streams. It can be a decent alternative to drift if you don't want/need generated code to parse the
result of your queries.
### floor
Floor also has a lot of convenience features like auto-updating queries and schema migrations. Similar to drift, you
define the structure of your database in Dart. Then, you have write queries in sql - the mapping code if generated
by floor. Drift has a [similar feature](sql_api/custom_queries.md), but it can also verify that your queries are valid at compile time. Drift
additionally has an api that lets you write some queries in Dart instead of sql.
A difference between these two is that Floor lets you write your own classes and generates mapping code around that.
By default, drift generates most classes for you, which can make it easier to use, but makes the api less flexible in some
instances.
Drift can also be used with [custom row classes](dart_api/rows.md#custom-dataclass) though.
### firebase
Both the Realtime Database and Cloud Datastore are easy to use persistence libraries that can sync across devices while
still working offline. Both of them feature auto-updating streams and a simple query api. However, neither of them is
a relational database, so they don't support useful sql features like aggregate functions, joins, or complex filters.
Firebase is a very good option when
- your data model can be expressed as documents instead of relations
- you don't have your own backend, but still need to synchronize data
## Can I view a drift database?
Yes! Drift stores its data in a sqlite3 database file that can be extracted from the device and inspected locally.
To inspect a drift database directly in your app, you can use the [`drift_db_viewer`](https://pub.dev/packages/drift_db_viewer)
package by Koen Van Looveren.
There is also an under-development DevTools Extension that comes when you add `drift` to your app. Open DevTools and try it out! Contributions and feedback are definitely welcome!
-219
View File
@@ -1,219 +0,0 @@
---
title: Setup
description: All you need to know about adding drift to your project.
---
Drift is a powerful database library for Dart and Flutter applications. To
support its advanced capabilities like type-safe SQL queries, verification of
your database and migrations, it uses a builder and command-line tooling that
runs at compile-time.
This means that the setup involves a little more than just adding a single
dependency to your pubspec. This page explains how to add drift to your project
and gives pointers to the next steps.
If you're stuck adding drift, or have questions or feedback about the project,
please share that with the community by [starting a discussion on GitHub](https://github.com/simolus3/drift/discussions).
If you want to look at an example app for inspiration, a cross-platform Flutter app using drift is available
[as part of the drift repository](https://github.com/simolus3/drift/tree/develop/examples/app).
## The dependencies
First, let's add drift to your project's `pubspec.yaml`.
In addition to the core drift dependencies (`drift` and `drift_dev` to generate code), we're also
adding a package to open database on the respective platform.
=== "Flutter (sqlite3)"
```yaml
dependencies:
drift: ^{{ versions.drift }}
drift_flutter: ^{{ versions.drift_flutter }}
path_provider: ^{{ versions.path_provider }}
dev_dependencies:
drift_dev: ^{{ versions.drift_dev }}
build_runner: ^{{ versions.build_runner }}
```
Alternatively, you can achieve the same result using the following command:
```
dart pub add drift drift_flutter path_provider dev:drift_dev dev:build_runner
```
=== "Dart (sqlite3)"
```yaml
dependencies:
drift: ^{{ versions.drift }}
sqlite3: ^{{ versions.sqlite3 }}
dev_dependencies:
drift_dev: ^{{ versions.drift_dev }}
build_runner: ^{{ versions.build_runner }}
```
Alternatively, you can achieve the same result using the following command:
```
dart pub add drift sqlite3 dev:drift_dev dev:build_runner
```
=== "Dart (Postgres)"
```yaml
dependencies:
drift: ^{{ versions.drift }}
postgres: ^{{ versions.postgres }}
drift_postgres: ^{{ versions.drift_postgres }}
dev_dependencies:
drift_dev: ^{{ versions.drift_dev }}
build_runner: ^{{ versions.build_runner }}
```
Alternatively, you can achieve the same result using the following command:
```
dart pub add drift postgres drift_postgres dev:drift_dev dev:build_runner
```
Drift only generates code for sqlite3 by default. So, also create a `build.yaml`
to [configure](generation_options/index.md) `drift_dev`:
```yaml
targets:
$default:
builders:
drift_dev:
options:
sql:
dialects:
- postgres
# Uncomment if you need to support both
# - sqlite
```
## Database class
Every project using drift needs at least one class to access a database. This class references all the
tables you want to use and is the central entry point for drift's code generator.
In this example, we'll assume that this database class is defined in a file called `database.dart` and
somewhere under `lib/`. Of course, you can put this class in any Dart file you like.
To make the database useful, we'll also add a simple table to it. This table, `TodoItems`, can be used
to store todo items for a todo list app.
Everything there is to know about defining tables in Dart is described on the [Dart tables](dart_api/tables.md) page.
If you prefer using SQL to define your tables, drift supports that too! You can read all about that [here](sql_api/index.md).
For now, populate the contents of `database.dart` with these tables which could form the persistence
layer of a simple todolist application:
{{ load_snippet('before_generation','lib/snippets/setup/database.dart.excerpt.json') }}
You will get an analyzer warning on the `part` statement and on `extends _$AppDatabase`. This is
expected because drift's generator did not run yet.
You can do that by invoking [build_runner](https://pub.dev/packages/build_runner):
- `dart run build_runner build` generates all the required code once.
- `dart run build_runner watch` watches for changes in your sources and generates code with
incremental rebuilds. This is suitable for development sessions.
After running either command, the `database.g.dart` file containing the generated `_$AppDatabase`
class will have been generated.
You will now see errors related to missing overrides and a missing constructor. The constructor
is responsible for telling drift how to open the database. The `schemaVersion` getter is relevant
for migrations after changing the database, we can leave it at `1` for now. Update `database.dart`
so it now looks like this:
<a name="open"></a>
=== "Flutter (sqlite3)"
{{ load_snippet('flutter','lib/snippets/setup/database.dart.excerpt.json',indent=4) }}
If you need to customize how databases are opened, you can also set the connection
up manually:
??? note "Manual database setup"
```dart
import 'dart:io';
import 'package:drift/native.dart';
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart' as p;
import 'package:sqlite3/sqlite3.dart';
import 'package:sqlite3_flutter_libs/sqlite3_flutter_libs.dart';
LazyDatabase _openConnection() {
// the LazyDatabase util lets us find the right location for the file async.
return LazyDatabase(() async {
// put the database file, called db.sqlite here, into the documents folder
// for your app.
final dbFolder = await getApplicationDocumentsDirectory();
final file = File(p.join(dbFolder.path, 'db.sqlite'));
// Also work around limitations on old Android versions
if (Platform.isAndroid) {
await applyWorkaroundToOpenSqlite3OnOldAndroidVersions();
}
// Make sqlite3 pick a more suitable location for temporary files - the
// one from the system may be inaccessible due to sandboxing.
final cachebase = (await getTemporaryDirectory()).path;
// We can't access /tmp on Android, which sqlite3 would try by default.
// Explicitly tell it about the correct temporary directory.
sqlite3.tempDirectory = cachebase;
return NativeDatabase.createInBackground(file);
});
}
```
The Android-specific workarounds are necessary because sqlite3 attempts to use `/tmp` to store
private data on unix-like systems, which is forbidden on Android. We also use this opportunity
to work around a problem some older Android devices have with loading custom libraries through
`dart:ffi`.
=== "Dart (sqlite3)"
{{ load_snippet('sqlite3','lib/snippets/setup/database.dart.excerpt.json',indent=4) }}
=== "Dart (Postgres)"
{{ load_snippet('postgres','lib/snippets/setup/database.dart.excerpt.json',indent=4) }}
## Next steps
Congratulations! With this setup complete, your project is ready to use drift.
This short snippet shows how the database can be opened and how to run inserts and selects:
{{ load_snippet('use','lib/snippets/setup/database.dart.excerpt.json') }}
But drift can do so much more! These pages provide more information useful when getting
started with drift:
- [Dart tables](dart_api/tables.md): This page describes how to define your own tables in Dart.
For an overview of the classes drift generates for tables, check out [row classes](dart_api/rows.md).
- For new drift users or users not familiar with SQL, the [manager](dart_api/manager.md) APIs
for tables allows writing most queries with a syntax you're likely familiar with from ORMs or other
packages.
- Writing queries: Drift-generated classes support writing the most common SQL statements, like
[selects](dart_api/select.md) or [inserts, updates and deletes](dart_api/writes.md).
- Something to keep in mind for later: When changing the database, for instance by adding new columns
or tables, you need to write a migration so that existing databases are transformed to the new
format. Drift's extensive [migration tools](Migrations/index.md) help with that.
- Take a look at our [FAQ](./faq.md)! It will help you with the most common questions about drift projects.
Once you're familiar with the basics, the [overview here](index.md) shows what
more drift has to offer.
This includes transactions, automated tooling to help with migrations, multi-platform support
and more.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 58 KiB