Using drift classes in other builders
It is possible to use classes generated by drift in other builders.
Due to technicalities related to Dart's build system and source_gen
, this approach requires a custom build configuration.
For complex builds like this, we recommend running drift in it's modular mode. This more is more efficient for larger builds and can be enabled by putting this
content in a file called build.yaml
next to your pubspec.yaml
:
targets:
drift:
auto_apply_builders: false
builders:
drift_dev:analyzer:
enabled: true
options: &options
# Drift build options, as per https://drift.simonbinder.eu/docs/advanced-features/builder_options/
store_date_time_values_as_text: true
named_parameters: true
sql:
dialect: sqlite
options:
version: "3.39"
modules: [fts5]
drift_dev:modular:
enabled: true
# We use yaml anchors to give the two builders the same options
options: *options
$default:
dependencies:
# run drift's builder first
- ":drift"
builders:
# This builder is enabled by default, but we're using the modular builder in
# its own target instead.
drift_dev:
enabled: false
With modular generation, you'll have to replace the part
statement in the database file with an
import to filename.drift.dart
. Also, your database class now extends from $DatabaseName
, without
a leading underscore.
By generating independent libraries, drift can manage imports on its own. By declaring a dependency in
build.yaml
, the build system also ensures that drift-generated files are ready before built_value
or other builders that need to see them are running.
A full example is available as part of the drift repo.
If you run into any problems with this approach, feel free to open an issue on drift.
The technicalities, explained¶
Almost all code generation packages use a so called "shared part file" approach provided by source_gen
.
It's a common protocol that allows unrelated builders to write into the same .g.dart
file.
For this to work, each builder first writes a .part
file with its name. For instance, if you used drift
and built_value
in the same project, those part files could be called .drift.part
and .built_value.part
.
Later, the common source_gen
package would merge the part files into a single .g.dart
file.
This works great for most use cases, but a downside is that each builder can't see the final .g.dart
file, or use any classes or methods defined in it. To fix that, drift offers other builders -
drift_dev|not_shared
and drift_dev|modular
- those will generate a separate file only containing
code generated by drift. So most of the work resolves around disabling the default generator of drift
and use the non-shared generator instead.
Finally, we need to the build system to run drift first, and all the other builders otherwise. This is why we split the builders up into multiple targets. The first target will only run drift, the second target has a dependency on the first one and will run all the other builders.
Using drift_dev:not_shared
¶
For complex build setups like those requiring other builders to see drift code, the drift_dev:modular
builder is recommended.
However, enabling the modular builder requires other code modifications like replacing part
statements
with imports. A simpler change may be the not_shared
builder offered by drift_dev
. It works like the
default setup, except that it emits a .drift.dart
part file instead of a shared .g.dart
file - so you
only have to change a single part
statement to migrate.
To enable this builder, also enable the drift_dev:analyzer
builder and the has_separate_analyzer
option:
targets:
drift:
auto_apply_builders: false
builders:
drift_dev:analyzer:
enabled: true
options: &options
has_separate_analyzer: true # always enable this option when using `not_shared`
# remaining options...
drift_dev:not_shared:
enabled: true
# We use yaml anchors to give the two builders the same options
options: *options
$default:
dependencies:
# run drift's builder first
- ":drift"
builders:
# This builder is enabled by default, but we're using the modular builder in
# its own target instead.
drift_dev:
enabled: false