Skip to content

Commit

Permalink
Migrate built value example to a modular builder
Browse files Browse the repository at this point in the history
  • Loading branch information
simolus3 committed Oct 3, 2023
1 parent eb03ac5 commit fcd984f
Show file tree
Hide file tree
Showing 6 changed files with 233 additions and 234 deletions.
44 changes: 21 additions & 23 deletions docs/pages/docs/Generation options/in_other_builders.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,39 +6,37 @@ template: layouts/docs/single
---

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 configuration
and minor code changes. Put this content in a file called `build.yaml` next to your `pubspec.yaml`:
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]({{ 'modular.md' | pageUrl }}). 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`:

```yaml
targets:
$default:
# disable the default generators, we'll only use the non-shared drift generator here
drift:
auto_apply_builders: false
builders:
drift_dev|not_shared:
enabled: true
# If needed, you can configure the builder like this:
# options:
# skip_verification_code: true
# use_experimental_inference: true
# This builder is necessary for drift-file preprocessing. You can disable it if you're not
# using .drift files with type converters.
drift_dev|preparing_builder:
drift_dev:modular:
enabled: true

run_built_value:
dependencies: ['your_package_name']
$default:
dependencies:
# run drift's builder first
- ":drift"
builders:
# Disable drift builders. By default, those would run on each target
# This builder is enabled by default, but we're using the modular builder in
# its own target instead.
drift_dev:
enabled: false
drift_dev|preparing_builder:
enabled: false
# we don't need to disable drift|not_shared, because it's disabled by default

```

In all files that use generated drift code, you'll have to replace `part 'filename.g.dart'` with `part 'filename.drift.dart'`.
If you use drift _and_ another builder in the same file, you'll need both `.g.dart` and `.drift.dart` as part-files.
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](https:/simolus3/drift/tree/develop/examples/with_built_value).

Expand All @@ -53,8 +51,8 @@ and `built_value` in the same project, those part files could be called `.drift.
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 an optional builder -
`drift_dev|not_shared` - that will generate a separate part file only containing
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.

Expand Down
27 changes: 9 additions & 18 deletions examples/with_built_value/build.yaml
Original file line number Diff line number Diff line change
@@ -1,25 +1,16 @@
targets:
$default:
drift:
auto_apply_builders: false
builders:
# disables the SharedPartBuilder in favor of a PartBuilder from drift_dev
drift_dev:
enabled: false
drift_dev:preparing_builder:
enabled: true
drift_dev:not_shared:
drift_dev:modular:
enabled: true

# Run built_value_generator when drift is done (so after this target)
built_value_generator:built_value:
enabled: false

run_built_value:
dependencies: ['$default']
$default:
dependencies:
# run drift's builder first
- ":drift"
builders:
# Disable all auto-applied builders from drift
# This builder is enabled by default, but we're using the modular builder in
# its own target instead.
drift_dev:
enabled: false
drift_dev:preparing_builder:
enabled: false
build_resolvers:transitive_digests:
enabled: false
8 changes: 5 additions & 3 deletions examples/with_built_value/lib/database.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,21 @@ import 'package:built_value/built_value.dart';
import 'package:drift/drift.dart';
import 'package:drift/native.dart';

part 'database.drift.dart';
import 'database.drift.dart';
import 'tables.drift.dart';

part 'database.g.dart';

abstract class Foo implements Built<Foo, FooBuilder> {
User get moorField;
User get driftGeneratedField;

Foo._();

factory Foo([void Function(FooBuilder) updates]) = _$Foo;
}

@DriftDatabase(include: {'tables.drift'})
class Database extends _$Database {
class Database extends $Database {
Database() : super(NativeDatabase.memory());

@override
Expand Down
186 changes: 8 additions & 178 deletions examples/with_built_value/lib/database.drift.dart
Original file line number Diff line number Diff line change
@@ -1,183 +1,13 @@
// ignore_for_file: type=lint
part of 'database.dart';
import 'package:drift/drift.dart' as i0;
import 'package:with_built_value/tables.drift.dart' as i1;

class Users extends Table with TableInfo<Users, User> {
abstract class $Database extends i0.GeneratedDatabase {
$Database(i0.QueryExecutor e) : super(e);
late final i1.Users users = i1.Users(this);
@override
final GeneratedDatabase attachedDatabase;
final String? _alias;
Users(this.attachedDatabase, [this._alias]);
static const VerificationMeta _idMeta = const VerificationMeta('id');
late final GeneratedColumn<int> id = GeneratedColumn<int>(
'id', aliasedName, false,
hasAutoIncrement: true,
type: DriftSqlType.int,
requiredDuringInsert: false,
$customConstraints: 'NOT NULL PRIMARY KEY AUTOINCREMENT');
static const VerificationMeta _nameMeta = const VerificationMeta('name');
late final GeneratedColumn<String> name = GeneratedColumn<String>(
'name', aliasedName, false,
type: DriftSqlType.string,
requiredDuringInsert: true,
$customConstraints: 'NOT NULL');
Iterable<i0.TableInfo<i0.Table, Object?>> get allTables =>
allSchemaEntities.whereType<i0.TableInfo<i0.Table, Object?>>();
@override
List<GeneratedColumn> get $columns => [id, name];
@override
String get aliasedName => _alias ?? actualTableName;
@override
String get actualTableName => $name;
static const String $name = 'users';
@override
VerificationContext validateIntegrity(Insertable<User> instance,
{bool isInserting = false}) {
final context = VerificationContext();
final data = instance.toColumns(true);
if (data.containsKey('id')) {
context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta));
}
if (data.containsKey('name')) {
context.handle(
_nameMeta, name.isAcceptableOrUnknown(data['name']!, _nameMeta));
} else if (isInserting) {
context.missing(_nameMeta);
}
return context;
}

@override
Set<GeneratedColumn> get $primaryKey => {id};
@override
User map(Map<String, dynamic> data, {String? tablePrefix}) {
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';
return User(
id: attachedDatabase.typeMapping
.read(DriftSqlType.int, data['${effectivePrefix}id'])!,
name: attachedDatabase.typeMapping
.read(DriftSqlType.string, data['${effectivePrefix}name'])!,
);
}

@override
Users createAlias(String alias) {
return Users(attachedDatabase, alias);
}

@override
bool get dontWriteConstraints => true;
}

class User extends DataClass implements Insertable<User> {
final int id;
final String name;
const User({required this.id, required this.name});
@override
Map<String, Expression> toColumns(bool nullToAbsent) {
final map = <String, Expression>{};
map['id'] = Variable<int>(id);
map['name'] = Variable<String>(name);
return map;
}

UsersCompanion toCompanion(bool nullToAbsent) {
return UsersCompanion(
id: Value(id),
name: Value(name),
);
}

factory User.fromJson(Map<String, dynamic> json,
{ValueSerializer? serializer}) {
serializer ??= driftRuntimeOptions.defaultSerializer;
return User(
id: serializer.fromJson<int>(json['id']),
name: serializer.fromJson<String>(json['name']),
);
}
@override
Map<String, dynamic> toJson({ValueSerializer? serializer}) {
serializer ??= driftRuntimeOptions.defaultSerializer;
return <String, dynamic>{
'id': serializer.toJson<int>(id),
'name': serializer.toJson<String>(name),
};
}

User copyWith({int? id, String? name}) => User(
id: id ?? this.id,
name: name ?? this.name,
);
@override
String toString() {
return (StringBuffer('User(')
..write('id: $id, ')
..write('name: $name')
..write(')'))
.toString();
}

@override
int get hashCode => Object.hash(id, name);
@override
bool operator ==(Object other) =>
identical(this, other) ||
(other is User && other.id == this.id && other.name == this.name);
}

class UsersCompanion extends UpdateCompanion<User> {
final Value<int> id;
final Value<String> name;
const UsersCompanion({
this.id = const Value.absent(),
this.name = const Value.absent(),
});
UsersCompanion.insert({
this.id = const Value.absent(),
required String name,
}) : name = Value(name);
static Insertable<User> custom({
Expression<int>? id,
Expression<String>? name,
}) {
return RawValuesInsertable({
if (id != null) 'id': id,
if (name != null) 'name': name,
});
}

UsersCompanion copyWith({Value<int>? id, Value<String>? name}) {
return UsersCompanion(
id: id ?? this.id,
name: name ?? this.name,
);
}

@override
Map<String, Expression> toColumns(bool nullToAbsent) {
final map = <String, Expression>{};
if (id.present) {
map['id'] = Variable<int>(id.value);
}
if (name.present) {
map['name'] = Variable<String>(name.value);
}
return map;
}

@override
String toString() {
return (StringBuffer('UsersCompanion(')
..write('id: $id, ')
..write('name: $name')
..write(')'))
.toString();
}
}

abstract class _$Database extends GeneratedDatabase {
_$Database(QueryExecutor e) : super(e);
late final Users users = Users(this);
@override
Iterable<TableInfo<Table, Object?>> get allTables =>
allSchemaEntities.whereType<TableInfo<Table, Object?>>();
@override
List<DatabaseSchemaEntity> get allSchemaEntities => [users];
List<i0.DatabaseSchemaEntity> get allSchemaEntities => [users];
}
27 changes: 15 additions & 12 deletions examples/with_built_value/lib/database.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit fcd984f

Please sign in to comment.