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 delete methods code generation and fix update methods #22

Merged
merged 1 commit into from
Feb 2, 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
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';
}
}
}