Support generating database accessors in modular mode

This commit is contained in:
Simon Binder 2022-11-25 14:49:14 +01:00
parent 3891d63283
commit 15edd501aa
No known key found for this signature in database
GPG Key ID: 7891917E4147B8C0
14 changed files with 99 additions and 23 deletions

View File

@ -112,7 +112,7 @@ class DartAccessorResolver
final declaration = DriftDeclaration.dartElement(element);
if (discovered.isDatabase) {
final accessorTypes = <AnnotatedDartCode>[];
final accessors = <DatabaseAccessor>[];
final rawDaos = annotation.getField('daos')!.toListValue()!;
for (final value in rawDaos) {
final type = value.toTypeValue()!;
@ -129,7 +129,10 @@ class DartAccessorResolver
continue;
}
accessorTypes.add(AnnotatedDartCode.type(type));
final dao = await resolveDartReferenceOrReportError<DatabaseAccessor>(
type.element,
(msg) => DriftAnalysisError.forDartElement(element, msg));
if (dao != null) accessors.add(dao);
}
return DriftDatabase(
@ -140,7 +143,7 @@ class DartAccessorResolver
declaredIncludes: includes,
declaredQueries: queries,
schemaVersion: await _readSchemaVersion(),
accessorTypes: accessorTypes,
accessors: accessors,
);
} else {
final dbType = element.allSupertypes
@ -165,6 +168,7 @@ class DartAccessorResolver
declaredViews: views,
declaredIncludes: includes,
declaredQueries: queries,
ownType: AnnotatedDartCode.type(element.thisType),
databaseClass: AnnotatedDartCode.type(dbImpl),
);
}

View File

@ -54,7 +54,7 @@ class DriftDatabase extends BaseDriftAccessor {
/// versioned file.
final int? schemaVersion;
final List<AnnotatedDartCode> accessorTypes;
final List<DatabaseAccessor> accessors;
DriftDatabase({
required super.id,
@ -64,7 +64,7 @@ class DriftDatabase extends BaseDriftAccessor {
required super.declaredIncludes,
required super.declaredQueries,
this.schemaVersion,
this.accessorTypes = const [],
this.accessors = const [],
});
}
@ -74,6 +74,8 @@ class DatabaseAccessor extends BaseDriftAccessor {
/// The database class this dao belongs to.
final AnnotatedDartCode databaseClass;
final AnnotatedDartCode ownType;
DatabaseAccessor({
required super.id,
required super.declaration,
@ -82,6 +84,7 @@ class DatabaseAccessor extends BaseDriftAccessor {
required super.declaredIncludes,
required super.declaredQueries,
required this.databaseClass,
required this.ownType,
});
}

View File

@ -132,11 +132,15 @@ class ElementSerializer {
for (final include in element.declaredIncludes) include.toString()
],
'queries': element.declaredQueries,
if (element is DatabaseAccessor)
if (element is DatabaseAccessor) ...{
'type': element.ownType.toJson(),
'database': element.databaseClass.toJson(),
},
if (element is DriftDatabase) ...{
'schema_version': element.schemaVersion,
'daos': element.accessorTypes,
'daos': [
for (final dao in element.accessors) _serializeElementReference(dao)
],
}
};
} else {
@ -652,9 +656,10 @@ class ElementDeserializer {
declaredIncludes: includes,
declaredQueries: queries,
schemaVersion: json['schema_version'] as int?,
accessorTypes: [
accessors: [
for (final dao in json['daos'])
AnnotatedDartCode.fromJson(dao as Map)
await readDriftElement(DriftElementId.fromJson(dao as Map))
as DatabaseAccessor,
],
);
} else {
@ -668,6 +673,7 @@ class ElementDeserializer {
declaredIncludes: includes,
declaredQueries: queries,
databaseClass: AnnotatedDartCode.fromJson(json['database'] as Map),
ownType: AnnotatedDartCode.fromJson(json['type'] as Map),
);
}
default:

View File

@ -256,6 +256,11 @@ class _DriftBuildRun {
entrypointState.fileAnalysis!.resolvedDatabases[result.id]!;
final input = DatabaseGenerationInput(result, resolved, const {});
DatabaseWriter(input, writer.child()).write();
} else if (result is DatabaseAccessor) {
final resolved =
entrypointState.fileAnalysis!.resolvedDatabases[result.id]!;
final input = AccessorGenerationInput(result, resolved, const {});
AccessorWriter(input, writer.child()).write();
}
}

View File

@ -38,7 +38,7 @@ class IdentifyDatabases extends MoorCommand {
if (element is DriftDatabase) {
final daos =
element.accessorTypes.map((e) => e.toString()).join(', ');
element.accessors.map((e) => e.ownType.toString()).join(', ');
message
..writeln()
..write('Schema version: ${element.schemaVersion}, daos: $daos');

View File

@ -124,10 +124,10 @@ class DatabaseWriter {
}
// Write fields to access an dao. We use a lazy getter for that.
for (final dao in db.accessorTypes) {
final typeName = firstLeaf.dartCode(dao);
final getterName = ReCase(typeName).camelCase;
final databaseImplName = db.id.name;
for (final dao in db.accessors) {
final typeName = firstLeaf.dartCode(dao.ownType);
final getterName = ReCase(dao.ownType.toString()).camelCase;
final databaseImplName = scope.dartCode(dao.databaseClass);
writeMemoizedGetter(
buffer: dbScope.leaf().buffer,

View File

@ -13,16 +13,22 @@ class AccessorWriter {
final classScope = scope.child();
final daoName = input.accessor.declaration.name!;
final dbTypeName = classScope.dartCode(input.accessor.databaseClass);
classScope.leaf().write('mixin _\$${daoName}Mixin on '
'DatabaseAccessor<$dbTypeName> {\n');
final prefix = scope.generationOptions.isModular ? '' : r'_';
classScope.leaf()
..write('mixin $prefix\$${daoName}Mixin on ')
..writeDriftRef('DatabaseAccessor<')
..writeDart(input.accessor.databaseClass)
..writeln('> {');
for (final entity in input.resolvedAccessor.availableElements
.whereType<DriftElementWithResultSet>()) {
final infoType = entity.entityInfoName;
final infoType = scope.entityInfoType(entity);
final getterName = entity.dbGetterName;
classScope.leaf().write(
'$infoType get $getterName => attachedDatabase.$getterName;\n');
classScope.leaf()
..writeDart(infoType)
..writeln(' get $getterName => attachedDatabase.$getterName;');
}
for (final query in input.availableRegularQueries) {

View File

@ -1,8 +1,12 @@
import 'package:drift/native.dart';
import 'package:modular/database.dart';
import 'package:modular/src/users.drift.dart';
void main() async {
final database = Database(NativeDatabase.memory(logStatements: true));
database.usersDrift.findUsers().watch().listen(print);
await database.myAccessor
.addUser(user: UsersCompanion.insert(name: 'first_user'));
}

View File

@ -0,0 +1,12 @@
import 'package:drift/drift.dart';
import 'accessor.drift.dart';
import 'database.dart';
@DriftAccessor(
include: {'src/users.drift'},
queries: {'addUser': r'INSERT INTO users $user;'},
)
class MyAccessor extends DatabaseAccessor<Database> with $MyAccessorMixin {
MyAccessor(super.attachedDatabase);
}

View File

@ -0,0 +1,20 @@
// ignore_for_file: type=lint
import 'package:drift/drift.dart' as i0;
import 'package:modular/database.dart' as i1;
import 'package:modular/src/users.drift.dart' as i2;
mixin $MyAccessorMixin on i0.DatabaseAccessor<i1.Database> {
i2.Users get users => attachedDatabase.users;
i2.Follows get follows => attachedDatabase.follows;
Future<int> addUser({required i0.Insertable<i2.User> user}) {
var $arrayStartIndex = 1;
final generateduser =
$writeInsertable(this.users, user, startIndex: $arrayStartIndex);
$arrayStartIndex += generateduser.amountOfVariables;
return customInsert(
'INSERT INTO users ${generateduser.sql}',
variables: [...generateduser.introducedVariables],
updates: {users},
);
}
}

View File

@ -1,12 +1,15 @@
import 'package:drift/drift.dart';
import 'accessor.dart';
import 'database.drift.dart';
@DriftDatabase(include: {
'src/users.drift',
'src/posts.drift',
'src/search.drift',
})
}, daos: [
MyAccessor
])
class Database extends $Database {
Database(super.e);

View File

@ -3,7 +3,9 @@ import 'package:drift/drift.dart' as i0;
import 'package:modular/src/users.drift.dart' as i1;
import 'package:modular/src/posts.drift.dart' as i2;
import 'package:modular/src/search.drift.dart' as i3;
import 'package:drift/internal/modular.dart' as i4;
import 'package:modular/accessor.dart' as i4;
import 'package:modular/database.dart' as i5;
import 'package:drift/internal/modular.dart' as i6;
abstract class $Database extends i0.GeneratedDatabase {
$Database(i0.QueryExecutor e) : super(e);
@ -12,8 +14,13 @@ abstract class $Database extends i0.GeneratedDatabase {
late final i3.SearchInPosts searchInPosts = i3.SearchInPosts(this);
late final i2.Likes likes = i2.Likes(this);
late final i1.Follows follows = i1.Follows(this);
late final i4.MyAccessor myAccessor = i4.MyAccessor(this as i5.Database);
i1.UsersDrift get usersDrift =>
i4.ReadDatabaseContainer(this).accessor<i1.UsersDrift>(i1.UsersDrift.new);
i6.ReadDatabaseContainer(this).accessor<i1.UsersDrift>(i1.UsersDrift.new);
i2.PostsDrift get postsDrift =>
i6.ReadDatabaseContainer(this).accessor<i2.PostsDrift>(i2.PostsDrift.new);
i3.SearchDrift get searchDrift => i6.ReadDatabaseContainer(this)
.accessor<i3.SearchDrift>(i3.SearchDrift.new);
@override
Iterable<i0.TableInfo<i0.Table, Object?>> get allTables =>
allSchemaEntities.whereType<i0.TableInfo<i0.Table, Object?>>();
@ -26,6 +33,7 @@ abstract class $Database extends i0.GeneratedDatabase {
i3.postsUpdate,
i3.postsDelete,
likes,
i1.usersName,
follows
];
@override

View File

@ -4,6 +4,8 @@ CREATE TABLE users (
biography TEXT
);
CREATE INDEX users_name ON users (name);
CREATE TABLE follows (
followed INTEGER NOT NULL REFERENCES users (id),
follower INTEGER NOT NULL REFERENCES users (id),

View File

@ -219,6 +219,9 @@ class Users extends i0.Table with i0.TableInfo<Users, i1.User> {
bool get dontWriteConstraints => true;
}
i0.Index get usersName =>
i0.Index('users_name', 'CREATE INDEX users_name ON users (name)');
class Follow extends i0.DataClass implements i0.Insertable<i1.Follow> {
final int followed;
final int follower;