Generate DAO classes

This commit is contained in:
Simon Binder 2019-03-03 19:06:24 +01:00
parent 5c1d320b34
commit 062deccb12
No known key found for this signature in database
GPG Key ID: B807FDF954BA00CF
8 changed files with 95 additions and 14 deletions

View File

@ -11,9 +11,13 @@ import 'package:sally/src/runtime/statements/update.dart';
/// This comes in handy to structure large amounts of database code better: The
/// migration logic can live in the main [GeneratedDatabase] class, but code
/// can be extracted into [DatabaseAccessor]s outside of that database.
abstract class DatabaseAccessor extends DatabaseConnectionUser
abstract class DatabaseAccessor<T extends GeneratedDatabase> extends DatabaseConnectionUser
with QueryEngine {
DatabaseAccessor(GeneratedDatabase db) : super.delegate(db);
@protected
final T db;
DatabaseAccessor(this.db) : super.delegate(db);
}
/// Mediocre class name for something that manages a typesystem to map between

View File

@ -43,9 +43,9 @@ class TodoEntry {
other.category == category);
}
class _$TodosTable extends Todos implements TableInfo<Todos, TodoEntry> {
class $TodosTable extends Todos implements TableInfo<Todos, TodoEntry> {
final GeneratedDatabase _db;
_$TodosTable(this._db);
$TodosTable(this._db);
@override
GeneratedIntColumn get id =>
GeneratedIntColumn('id', false, hasAutoIncrement: true);
@ -132,10 +132,10 @@ class Category {
(other is Category && other.id == id && other.description == description);
}
class _$CategoriesTable extends Categories
class $CategoriesTable extends Categories
implements TableInfo<Categories, Category> {
final GeneratedDatabase _db;
_$CategoriesTable(this._db);
$CategoriesTable(this._db);
@override
GeneratedIntColumn get id =>
GeneratedIntColumn('id', false, hasAutoIncrement: true);
@ -176,10 +176,10 @@ class _$CategoriesTable extends Categories
abstract class _$Database extends GeneratedDatabase {
_$Database(QueryExecutor e) : super(const SqlTypeSystem.withDefaults(), e);
_$TodosTable get todos => _$TodosTable(this);
_$CategoriesTable get categories => _$CategoriesTable(this);
$TodosTable get todos => $TodosTable(this);
$CategoriesTable get categories => $CategoriesTable(this);
TodosDao _todosDao;
TodosDao get todosDao => _todosDao ??= TodosDao(this);
TodosDao get todosDao => _todosDao ??= TodosDao(this as Database);
@override
List<TableInfo> get allTables => [todos, categories];
}

View File

@ -3,9 +3,11 @@ import 'dart:async';
import 'package:sally/sally.dart';
import 'database.dart';
part 'todos_dao.g.dart';
@UseDao(tables: [Todos])
class TodosDao extends DatabaseAccessor {
TodosDao(GeneratedDatabase db) : super(db);
class TodosDao extends DatabaseAccessor<Database> with _TodosDaoMixin {
TodosDao(Database db) : super(db);
Stream<List<TodoEntry>> todosWithoutCategory() {
return null;

View File

@ -0,0 +1,11 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'todos_dao.dart';
// **************************************************************************
// DaoGenerator
// **************************************************************************
mixin _TodosDaoMixin on DatabaseAccessor<Database> {
$TodosTable get todos => db.todos;
}

View File

@ -1,6 +1,7 @@
import 'package:build/build.dart';
import 'package:sally_generator/src/dao_generator.dart';
import 'package:source_gen/source_gen.dart';
import 'package:sally_generator/src/sally_generator.dart';
Builder sallyBuilder(BuilderOptions _) =>
SharedPartBuilder([SallyGenerator()], 'sally');
SharedPartBuilder([SallyGenerator(), DaoGenerator()], 'sally');

View File

@ -0,0 +1,58 @@
import 'package:analyzer/dart/element/element.dart';
import 'package:build/build.dart';
import 'package:recase/recase.dart';
import 'package:sally/sally.dart';
import 'package:sally_generator/src/model/specified_table.dart';
import 'package:source_gen/source_gen.dart';
class DaoGenerator extends GeneratorForAnnotation<UseDao> {
@override
generateForAnnotatedElement(
Element element, ConstantReader annotation, BuildStep buildStep) {
final tableTypes =
annotation.peek('tables').listValue.map((obj) => obj.toTypeValue());
if (element is! ClassElement) {
throw InvalidGenerationSourceError(
'This annotation can only be used on classes',
element: element);
}
final enclosingClass = element as ClassElement;
final dbType = enclosingClass.supertype;
if (dbType.name != 'DatabaseAccessor') {
throw InvalidGenerationSourceError(
'This class must directly inherit from DatabaseAccessor',
element: element);
}
// inherits from DatabaseAccessor<T>, we want to know which T
final dbImpl = dbType.typeArguments.single;
if (dbImpl.isDynamic) {
throw InvalidGenerationSourceError(
'This class must inherit from DatabaseAccessor<T>, where T is an '
'actual type of a database.',
element: element);
}
// finally, we can write the mixin
final buffer = StringBuffer();
final daoName = enclosingClass.displayName;
buffer.write('mixin _${daoName}Mixin on '
'DatabaseAccessor<${dbImpl.displayName}> {\n');
for (var table in tableTypes) {
final infoType = tableInfoNameForTableClass(table.element as ClassElement);
final getterName = ReCase(table.name).camelCase;
buffer.write('$infoType get $getterName => db.$getterName;\n');
}
buffer.write('}');
return buffer.toString();
}
}

View File

@ -9,7 +9,7 @@ class SpecifiedTable {
/// The name for the data class associated with this table
final String dartTypeName;
String get tableInfoName => '_\$${fromClass.name}Table';
String get tableInfoName => tableInfoNameForTableClass(fromClass);
// todo support primary keys
Set<SpecifiedColumn> get primaryKey => <SpecifiedColumn>{};
@ -17,3 +17,5 @@ class SpecifiedTable {
const SpecifiedTable(
{this.fromClass, this.columns, this.sqlName, this.dartTypeName});
}
String tableInfoNameForTableClass(ClassElement fromClass) => '\$${fromClass.name}Table';

View File

@ -39,9 +39,12 @@ class DatabaseWriter {
final getterName = ReCase(typeName).camelCase;
final fieldName = '_$getterName';
final databaseImplName = db.fromClass.name;
buffer
..write('$typeName $fieldName;\n')
..write('$typeName get $getterName => $fieldName ??= $typeName(this);');
..write('$typeName get $getterName => $fieldName ??= '
'$typeName(this as $databaseImplName);');
}
// Write List of tables, close bracket for class