Skip to content

Commit

Permalink
Add delete methods code generation and fix update methods (#22)
Browse files Browse the repository at this point in the history
  • Loading branch information
vitusortner authored Feb 2, 2019
1 parent 0649b90 commit 4d74404
Show file tree
Hide file tree
Showing 9 changed files with 174 additions and 15 deletions.
3 changes: 3 additions & 0 deletions example/lib/database.dart
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ abstract class MyDatabase extends FloorDatabase {

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

@delete
Future<void> deletePerson(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 @@ -62,3 +62,11 @@ class Update {

/// Marks a method as an update method.
const update = Update();

/// Marks a method as a delete method.
class Delete {
const Delete();
}

/// Marks a method as a delete method.
const delete = Delete();
1 change: 1 addition & 0 deletions floor_generator/lib/misc/constants.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ abstract class Annotation {
static const QUERY = 'Query';
static const INSERT = 'Insert';
static const UPDATE = 'Update';
static const DELETE = 'Delete';
}

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 @@ -60,6 +60,10 @@ bool isUpdateAnnotation(ElementAnnotation annotation) {
return _getAnnotationName(annotation) == Annotation.UPDATE;
}

bool isDeleteAnnotation(ElementAnnotation annotation) {
return _getAnnotationName(annotation) == Annotation.DELETE;
}

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
@@ -1,5 +1,6 @@
import 'package:analyzer/dart/element/element.dart';
import 'package:floor_generator/misc/type_utils.dart';
import 'package:floor_generator/model/delete_method.dart';
import 'package:floor_generator/model/entity.dart';
import 'package:floor_generator/model/insert_method.dart';
import 'package:floor_generator/model/query_method.dart';
Expand Down Expand Up @@ -36,6 +37,13 @@ class Database {
.toList();
}

List<DeleteMethod> get deleteMethods {
return methods
.where((method) => method.metadata.any(isDeleteAnnotation))
.map((method) => DeleteMethod(method))
.toList();
}

List<Entity> getEntities(LibraryReader library) {
return library.classes
.where((clazz) =>
Expand Down
51 changes: 51 additions & 0 deletions floor_generator/lib/model/delete_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 DeleteMethod {
final MethodElement method;

DeleteMethod(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();
}
}
29 changes: 18 additions & 11 deletions floor_generator/lib/writer/database_writer.dart
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import 'package:floor_generator/misc/annotation_expression.dart';
import 'package:floor_generator/misc/type_utils.dart';
import 'package:floor_generator/model/database.dart';
import 'package:floor_generator/model/delete_method.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/delete_method_writer.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';
Expand Down Expand Up @@ -82,14 +84,8 @@ class DatabaseWriter implements Writer {
..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();
..methods.addAll(_generateUpdateMethods(database.updateMethods))
..methods.addAll(_generateDeleteMethods(database.deleteMethods)));
}

Method _generateOpenMethod(
Expand All @@ -116,14 +112,25 @@ class DatabaseWriter implements Writer {

List<Method> _generateInsertMethods(List<InsertMethod> insertMethods) {
return insertMethods
.map(
(insertMethod) => InsertMethodWriter(library, insertMethod).write())
.map((method) => InsertMethodWriter(library, method).write())
.toList();
}

List<Method> _generateQueryMethods(List<QueryMethod> queryMethods) {
return queryMethods
.map((queryMethod) => QueryMethodWriter(library, queryMethod).write())
.map((method) => QueryMethodWriter(library, method).write())
.toList();
}

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

List<Method> _generateDeleteMethods(List<DeleteMethod> deleteMethods) {
return deleteMethods
.map((method) => DeleteMethodWriter(library, method).write())
.toList();
}

Expand Down
48 changes: 48 additions & 0 deletions floor_generator/lib/writer/delete_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/delete_method.dart';
import 'package:floor_generator/writer/writer.dart';
import 'package:source_gen/source_gen.dart';

class DeleteMethodWriter implements Writer {
final LibraryReader library;
final DeleteMethod deleteMethod;

DeleteMethodWriter(this.library, this.deleteMethod);

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

Method _generateDeleteMethod() {
// TODO assert deletes entity

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

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

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

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

return '''
await this.database.rawDelete('DELETE FROM ${entity.name} WHERE ${primaryKeyColumn.name} = \${$methodHeadParameterName.${primaryKeyColumn.field.displayName}}');
''';
}
}
37 changes: 33 additions & 4 deletions floor_generator/lib/writer/update_method_writer.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import 'package:analyzer/dart/element/element.dart';
import 'package:code_builder/code_builder.dart';
import 'package:floor_generator/misc/annotation_expression.dart';
import 'package:floor_generator/misc/type_utils.dart';
import 'package:floor_generator/model/update_method.dart';
import 'package:floor_generator/writer/writer.dart';
import 'package:source_gen/source_gen.dart';
Expand Down Expand Up @@ -36,13 +38,40 @@ class UpdateMethodWriter implements Writer {
}

String _generateMethodBody() {
final parameter = updateMethod.parameter;
final methodHeadParameterName = parameter.displayName;

final keyValueList = (parameter.type.element as ClassElement)
.constructors
.first
.parameters
.map((parameter) {
final valueMapping = _getValueMapping(parameter, methodHeadParameterName);

return "'${parameter.displayName}': $valueMapping";
}).join(', ');

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

// TODO exclude id?
return '''
await this.database.rawDelete('DELETE FROM ${entity.name} WHERE ${primaryKeyColumn.name} = \${$methodHeadParameterName.${primaryKeyColumn.field.displayName}}');
final values = <String, dynamic>{
$keyValueList
};
await this.database.update('${entity.name}', values);
''';
}

String _getValueMapping(
ParameterElement parameter,
String methodParameterName,
) {
final parameterName = parameter.displayName;

if (isBool(parameter.type)) {
return '$methodParameterName.$parameterName ? 1 : 0';
} else {
return '$methodParameterName.$parameterName';
}
}
}

0 comments on commit 4d74404

Please sign in to comment.