Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add update methods code generation #21

Merged
merged 1 commit into from
Feb 1, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions example/lib/database.dart
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@ abstract class MyDatabase extends FloorDatabase {

@insert
Future<void> insertTask(Task task);

@update
Future<void> updateTask(Task task);

@update
Future<void> updatePerson(Person person);
}

Future<void> main() async {
Expand Down
8 changes: 8 additions & 0 deletions floor/lib/src/annotations.dart
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,11 @@ class Insert {

/// Marks a method as an insert method.
const insert = Insert();

/// Marks a method as an update method.
class Update {
const Update();
}

/// Marks a method as an update method.
const update = Update();
2 changes: 2 additions & 0 deletions floor_generator/lib/misc/annotation_expression.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ class AnnotationExpression extends CodeExpression {

AnnotationExpression(this.annotation) : super(Code(annotation));
}

final overrideAnnotationExpression = AnnotationExpression('override');
2 changes: 2 additions & 0 deletions floor_generator/lib/misc/constants.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@ abstract class Annotation {
static const DATABASE = 'Database';
static const COLUMN_INFO = 'ColumnInfo';
static const PRIMARY_KEY = 'PrimaryKey';

static const QUERY = 'Query';
static const INSERT = 'Insert';
static const UPDATE = 'Update';
}

abstract class AnnotationField {
Expand Down
4 changes: 4 additions & 0 deletions floor_generator/lib/misc/type_utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ bool isInsertAnnotation(ElementAnnotation annotation) {
return _getAnnotationName(annotation) == Annotation.INSERT;
}

bool isUpdateAnnotation(ElementAnnotation annotation) {
return _getAnnotationName(annotation) == Annotation.UPDATE;
}

DartType flattenList(DartType type) {
return (type as ParameterizedType).typeArguments.first;
}
Expand Down
8 changes: 8 additions & 0 deletions floor_generator/lib/model/database.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'package:floor_generator/misc/type_utils.dart';
import 'package:floor_generator/model/entity.dart';
import 'package:floor_generator/model/insert_method.dart';
import 'package:floor_generator/model/query_method.dart';
import 'package:floor_generator/model/update_method.dart';
import 'package:source_gen/source_gen.dart';

class Database {
Expand All @@ -28,6 +29,13 @@ class Database {
.toList();
}

List<UpdateMethod> get updateMethods {
return methods
.where((method) => method.metadata.any(isUpdateAnnotation))
.map((method) => UpdateMethod(method))
.toList();
}

List<Entity> getEntities(LibraryReader library) {
return library.classes
.where((clazz) =>
Expand Down
51 changes: 51 additions & 0 deletions floor_generator/lib/model/update_method.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:floor_generator/misc/type_utils.dart';
import 'package:floor_generator/model/entity.dart';
import 'package:source_gen/source_gen.dart';

class UpdateMethod {
final MethodElement method;

UpdateMethod(this.method);

DartType get returnType => method.returnType;

String get name => method.displayName;

ParameterElement get parameter {
final parameters = method.parameters;
if (parameters.isEmpty) {
throw InvalidGenerationSourceError(
'There is no parameter supplied for an update method. Please add one.',
element: method,
);
} else if (parameters.length > 1) {
throw InvalidGenerationSourceError(
'Only one parameter is allowed on update methods.',
element: method,
);
}
return parameters.first;
}

Entity getEntity(LibraryReader library) {
final entityClass = _getEntities(library).firstWhere(
(entity) => entity.displayName == parameter.type.displayName);

return Entity(entityClass);
}

bool insertsEntity(LibraryReader library) {
return _getEntities(library)
.map((clazz) => clazz.displayName)
.any((entity) => entity == parameter.type.displayName);
}

List<ClassElement> _getEntities(LibraryReader library) {
return library.classes
.where((clazz) =>
!clazz.isAbstract && clazz.metadata.any(isEntityAnnotation))
.toList();
}
}
26 changes: 17 additions & 9 deletions floor_generator/lib/writer/database_writer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import 'package:floor_generator/model/database.dart';
import 'package:floor_generator/model/entity.dart';
import 'package:floor_generator/model/insert_method.dart';
import 'package:floor_generator/model/query_method.dart';
import 'package:floor_generator/model/update_method.dart';
import 'package:floor_generator/writer/insert_method_writer.dart';
import 'package:floor_generator/writer/query_method_writer.dart';
import 'package:floor_generator/writer/update_method_writer.dart';
import 'package:floor_generator/writer/writer.dart';
import 'package:source_gen/source_gen.dart';
import 'package:code_builder/code_builder.dart';
Expand Down Expand Up @@ -74,14 +76,20 @@ class DatabaseWriter implements Writer {

final databaseName = database.name;

return Class(
(builder) => builder
..name = '_\$$databaseName'
..extend = refer(databaseName)
..methods.add(_generateOpenMethod(databaseName, createTableStatements))
..methods.addAll(_generateQueryMethods(database.queryMethods))
..methods.addAll(_generateInsertMethods(database.insertMethods)),
);
return Class((builder) => builder
..name = '_\$$databaseName'
..extend = refer(databaseName)
..methods.add(_generateOpenMethod(databaseName, createTableStatements))
..methods.addAll(_generateQueryMethods(database.queryMethods))
..methods.addAll(_generateInsertMethods(database.insertMethods))
..methods.addAll(_generateUpdateMethods(database.updateMethods)));
}

List<Method> _generateUpdateMethods(List<UpdateMethod> updateMethods) {
return updateMethods
.map(
(updateMethod) => UpdateMethodWriter(library, updateMethod).write())
.toList();
}

Method _generateOpenMethod(
Expand All @@ -90,7 +98,7 @@ class DatabaseWriter implements Writer {
) {
return Method((builder) => builder
..name = 'open'
..annotations.add(AnnotationExpression('override'))
..annotations.add(overrideAnnotationExpression)
..returns = refer('Future<sqflite.Database>')
..modifier = MethodModifier.async
..body = Code('''
Expand Down
2 changes: 1 addition & 1 deletion floor_generator/lib/writer/insert_method_writer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class InsertMethodWriter implements Writer {
_assertInsertsEntity();

return Method((builder) => builder
..annotations.add(AnnotationExpression('override'))
..annotations.add(overrideAnnotationExpression)
..returns = refer(insertMethod.returnType.displayName)
..name = insertMethod.name
..requiredParameters.add(_generateParameter())
Expand Down
2 changes: 1 addition & 1 deletion floor_generator/lib/writer/query_method_writer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class QueryMethodWriter implements Writer {
_assertReturnsEntity();

return Method((builder) => builder
..annotations.add(AnnotationExpression('override'))
..annotations.add(overrideAnnotationExpression)
..returns = refer(queryMethod.rawReturnType.displayName)
..name = queryMethod.name
..requiredParameters.addAll(_generateMethodParameters())
Expand Down
48 changes: 48 additions & 0 deletions floor_generator/lib/writer/update_method_writer.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import 'package:code_builder/code_builder.dart';
import 'package:floor_generator/misc/annotation_expression.dart';
import 'package:floor_generator/model/update_method.dart';
import 'package:floor_generator/writer/writer.dart';
import 'package:source_gen/source_gen.dart';

class UpdateMethodWriter implements Writer {
final LibraryReader library;
final UpdateMethod updateMethod;

UpdateMethodWriter(this.library, this.updateMethod);

@override
Method write() {
return _generateUpdateMethod();
}

Method _generateUpdateMethod() {
// TODO assert is entity

return Method((builder) => builder
..annotations.add(overrideAnnotationExpression)
..returns = refer(updateMethod.returnType.displayName)
..name = updateMethod.name
..requiredParameters.add(_generateParameter())
..modifier = MethodModifier.async
..body = Code(_generateMethodBody()));
}

Parameter _generateParameter() {
final parameter = updateMethod.parameter;

return Parameter((builder) => builder
..name = parameter.name
..type = refer(parameter.type.displayName));
}

String _generateMethodBody() {
final entity = updateMethod.getEntity(library);
final primaryKeyColumn =
entity.columns.firstWhere((column) => column.isPrimaryKey);
final methodHeadParameterName = updateMethod.parameter.name;

return '''
await this.database.rawDelete('DELETE FROM ${entity.name} WHERE ${primaryKeyColumn.name} = \${$methodHeadParameterName.${primaryKeyColumn.field.displayName}}');
''';
}
}