From 46293ec1f782024ed474d34f52b082b6c7141905 Mon Sep 17 00:00:00 2001 From: Markus Richter <8398165+mqus@users.noreply.github.com> Date: Sun, 14 Jun 2020 15:30:40 +0200 Subject: [PATCH 1/6] Change ForeignKeyAction from untyped strings to be an enum in the generator --- floor_annotation/lib/src/foreign_key.dart | 10 +++---- .../lib/misc/foreign_key_action.dart | 30 ++++++++++++------- .../lib/processor/entity_processor.dart | 13 ++++++-- .../error/entity_processor_error.dart | 12 +++++++- .../lib/value_object/foreign_key.dart | 9 +++--- .../test/misc/foreign_key_action_test.dart | 28 +++++++++++------ .../test/processor/entity_processor_test.dart | 5 ++-- .../test/value_object/entity_test.dart | 9 +++--- .../test/value_object/foreign_key_test.dart | 9 +++--- 9 files changed, 84 insertions(+), 41 deletions(-) diff --git a/floor_annotation/lib/src/foreign_key.dart b/floor_annotation/lib/src/foreign_key.dart index c774557f..3e662c0a 100644 --- a/floor_annotation/lib/src/foreign_key.dart +++ b/floor_annotation/lib/src/foreign_key.dart @@ -41,7 +41,7 @@ abstract class ForeignKeyAction { /// When a parent key is modified or deleted from the database, no special /// action is taken. This means that SQLite will not make any effort to fix /// the constraint failure, instead, reject the change. - static const noAction = 1; + static const noAction = 0; /// Possible value for [ForeignKey.onDelete] or [ForeignKey.onUpdate]. /// @@ -57,7 +57,7 @@ abstract class ForeignKeyAction { /// Even if the foreign key constraint it is attached to is deferred(), /// configuring a RESTRICT action causes SQLite to return an error immediately /// if a parent key with dependent child keys is deleted or modified. - static const restrict = 2; + static const restrict = 1; /// Possible value for [ForeignKey.onDelete] or [ForeignKey.onUpdate]. /// @@ -65,14 +65,14 @@ abstract class ForeignKeyAction { /// (for [ForeignKey.onDelete]) or modified (for [ForeignKey.onUpdate]), the /// child key columns of all rows in the child table that mapped to the parent /// key are set to contain NULL values. - static const setNull = 3; + static const setNull = 2; /// Possible value for [ForeignKey.onDelete] or [ForeignKey.onUpdate]. /// /// The 'SET DEFAULT' actions are similar to SET_NULL, except that each of the /// child key columns is set to contain the columns default value instead of /// NULL. - static const setDefault = 4; + static const setDefault = 3; /// Possible value for [ForeignKey.onDelete] or [ForeignKey.onUpdate]. /// @@ -82,5 +82,5 @@ abstract class ForeignKeyAction { /// deleted parent row is also deleted. For an [ForeignKey.onUpdate] action, /// it means that the values stored in each dependent child key are modified /// to match the new parent key values. - static const cascade = 5; + static const cascade = 4; } diff --git a/floor_generator/lib/misc/foreign_key_action.dart b/floor_generator/lib/misc/foreign_key_action.dart index 4623255c..51f4384f 100644 --- a/floor_generator/lib/misc/foreign_key_action.dart +++ b/floor_generator/lib/misc/foreign_key_action.dart @@ -1,15 +1,13 @@ import 'package:floor_generator/misc/annotations.dart'; -abstract class ForeignKeyAction { - static const noAction = 1; - static const restrict = 2; - static const setNull = 3; - static const setDefault = 4; - static const cascade = 5; +enum ForeignKeyAction { noAction, restrict, setNull, setDefault, cascade } +extension AnnotationConverter on ForeignKeyAction { @nonNull - static String getString(final int action) { - switch (action) { + String get toSQL { + switch (this) { + case ForeignKeyAction.noAction: + return 'NO ACTION'; case ForeignKeyAction.restrict: return 'RESTRICT'; case ForeignKeyAction.setNull: @@ -18,9 +16,21 @@ abstract class ForeignKeyAction { return 'SET DEFAULT'; case ForeignKeyAction.cascade: return 'CASCADE'; - case ForeignKeyAction.noAction: default: - return 'NO ACTION'; + assert(false, 'Unexpected enum case $this'); + return null; } } + + static ForeignKeyAction fromInt(int i) { + // the position of the value in this list has to match the + // integer of the annotation. + return [ + ForeignKeyAction.noAction, + ForeignKeyAction.restrict, + ForeignKeyAction.setNull, + ForeignKeyAction.setDefault, + ForeignKeyAction.cascade + ][i]; + } } diff --git a/floor_generator/lib/processor/entity_processor.dart b/floor_generator/lib/processor/entity_processor.dart index 7ed4756e..9a66de94 100644 --- a/floor_generator/lib/processor/entity_processor.dart +++ b/floor_generator/lib/processor/entity_processor.dart @@ -88,11 +88,14 @@ class EntityProcessor extends QueryableProcessor { final onUpdateAnnotationValue = foreignKeyObject.getField(ForeignKeyField.onUpdate)?.toIntValue(); - final onUpdate = ForeignKeyAction.getString(onUpdateAnnotationValue); + _assertForeignKeyActionValue(onUpdateAnnotationValue, isUpdate: true); + final onUpdate = AnnotationConverter.fromInt(onUpdateAnnotationValue); final onDeleteAnnotationValue = foreignKeyObject.getField(ForeignKeyField.onDelete)?.toIntValue(); - final onDelete = ForeignKeyAction.getString(onDeleteAnnotationValue); + _assertForeignKeyActionValue(onDeleteAnnotationValue, + isUpdate: false); + final onDelete = AnnotationConverter.fromInt(onDeleteAnnotationValue); return ForeignKey( parentName, @@ -221,4 +224,10 @@ class EntityProcessor extends QueryableProcessor { .toBoolValue() ?? false; } + + void _assertForeignKeyActionValue(int foreignKeyAction, {bool isUpdate}) { + if (foreignKeyAction < 0 || foreignKeyAction > 4) { + throw _processorError.wrongForeignKeyAction(foreignKeyAction, isUpdate); + } + } } diff --git a/floor_generator/lib/processor/error/entity_processor_error.dart b/floor_generator/lib/processor/error/entity_processor_error.dart index f7aabb43..89896aee 100644 --- a/floor_generator/lib/processor/error/entity_processor_error.dart +++ b/floor_generator/lib/processor/error/entity_processor_error.dart @@ -70,11 +70,21 @@ class EntityProcessorError { ); } + InvalidGenerationSourceError wrongForeignKeyAction( + int foreignKeyAction, bool isUpdate) { + return InvalidGenerationSourceError( + 'No ForeignKeyAction with the value $foreignKeyAction exists for the on${isUpdate ? 'Update' : 'Delete'} trigger.', + todo: + 'Make sure to add a correct ForeignKeyAction like `ForeignKeyAction.noAction` or leave it out entirely.', + element: _classElement, + ); + } + InvalidGenerationSourceError get autoIncrementInWithoutRowid { return InvalidGenerationSourceError( 'autoGenerate is not allowed in WITHOUT ROWID tables', todo: - 'Remove autoGenerate in @PrimaryKey() or withoutRowid in @Entity().', + 'Remove autoGenerate in @PrimaryKey() or withoutRowid in @Entity().', element: _classElement, ); } diff --git a/floor_generator/lib/value_object/foreign_key.dart b/floor_generator/lib/value_object/foreign_key.dart index 6c464582..d88129c3 100644 --- a/floor_generator/lib/value_object/foreign_key.dart +++ b/floor_generator/lib/value_object/foreign_key.dart @@ -1,12 +1,13 @@ import 'package:collection/collection.dart'; import 'package:floor_generator/misc/annotations.dart'; +import 'package:floor_generator/misc/foreign_key_action.dart'; class ForeignKey { final String parentName; final List parentColumns; final List childColumns; - final String onUpdate; - final String onDelete; + final ForeignKeyAction onUpdate; + final ForeignKeyAction onDelete; ForeignKey( this.parentName, @@ -25,8 +26,8 @@ class ForeignKey { return 'FOREIGN KEY ($escapedChildColumns)' ' REFERENCES `$parentName` ($escapedParentColumns)' - ' ON UPDATE $onUpdate' - ' ON DELETE $onDelete'; + ' ON UPDATE ${onUpdate.toSQL}' + ' ON DELETE ${onDelete.toSQL}'; } final _listEquality = const ListEquality(); diff --git a/floor_generator/test/misc/foreign_key_action_test.dart b/floor_generator/test/misc/foreign_key_action_test.dart index 43112af2..455773c3 100644 --- a/floor_generator/test/misc/foreign_key_action_test.dart +++ b/floor_generator/test/misc/foreign_key_action_test.dart @@ -1,42 +1,52 @@ import 'package:floor_generator/misc/foreign_key_action.dart'; +import 'package:floor_annotation/floor_annotation.dart' as annotations; import 'package:test/test.dart'; void main() { group('foreign key action strings', () { test('NO ACTION', () { - final actual = ForeignKeyAction.getString(ForeignKeyAction.noAction); - + final actual = + AnnotationConverter.fromInt(annotations.ForeignKeyAction.noAction) + .toSQL; expect(actual, equals('NO ACTION')); }); test('RESTRICT', () { - final actual = ForeignKeyAction.getString(ForeignKeyAction.restrict); + final actual = + AnnotationConverter.fromInt(annotations.ForeignKeyAction.restrict) + .toSQL; expect(actual, equals('RESTRICT')); }); test('SET NULL', () { - final actual = ForeignKeyAction.getString(ForeignKeyAction.setNull); + final actual = + AnnotationConverter.fromInt(annotations.ForeignKeyAction.setNull) + .toSQL; expect(actual, equals('SET NULL')); }); test('SET DEFAULT', () { - final actual = ForeignKeyAction.getString(ForeignKeyAction.setDefault); + final actual = + AnnotationConverter.fromInt(annotations.ForeignKeyAction.setDefault) + .toSQL; expect(actual, equals('SET DEFAULT')); }); test('CASCADE', () { - final actual = ForeignKeyAction.getString(ForeignKeyAction.cascade); + final actual = + AnnotationConverter.fromInt(annotations.ForeignKeyAction.cascade) + .toSQL; expect(actual, equals('CASCADE')); }); - test('falls back to NO ACTION if action not known', () { - final actual = ForeignKeyAction.getString(12345); + test('errors out if action not known', () { + final conversion = () => AnnotationConverter.fromInt(12345).toSQL; - expect(actual, equals('NO ACTION')); + expect(conversion, throwsRangeError); }); }); } diff --git a/floor_generator/test/processor/entity_processor_test.dart b/floor_generator/test/processor/entity_processor_test.dart index 70786a26..4c908c53 100644 --- a/floor_generator/test/processor/entity_processor_test.dart +++ b/floor_generator/test/processor/entity_processor_test.dart @@ -1,5 +1,6 @@ import 'package:analyzer/dart/element/element.dart'; import 'package:build_test/build_test.dart'; +import 'package:floor_generator/misc/foreign_key_action.dart'; import 'package:floor_generator/processor/entity_processor.dart'; import 'package:floor_generator/processor/field_processor.dart'; import 'package:floor_generator/value_object/entity.dart'; @@ -126,8 +127,8 @@ void main() { 'Person', ['id'], ['owner_id'], - 'CASCADE', - 'SET NULL', + ForeignKeyAction.cascade, + ForeignKeyAction.setNull, ); expect(actual, equals(expected)); }); diff --git a/floor_generator/test/value_object/entity_test.dart b/floor_generator/test/value_object/entity_test.dart index be008e08..50c70f9b 100644 --- a/floor_generator/test/value_object/entity_test.dart +++ b/floor_generator/test/value_object/entity_test.dart @@ -1,4 +1,5 @@ import 'package:floor_generator/misc/constants.dart'; +import 'package:floor_generator/misc/foreign_key_action.dart'; import 'package:floor_generator/value_object/entity.dart'; import 'package:floor_generator/value_object/field.dart'; import 'package:floor_generator/value_object/foreign_key.dart'; @@ -114,8 +115,8 @@ void main() { 'parentName', ['parentColumn'], ['childColumn'], - 'foo', - 'bar', + ForeignKeyAction.cascade, + ForeignKeyAction.noAction, ); final primaryKey = PrimaryKey([nullableField], true); final entity = Entity( @@ -136,8 +137,8 @@ void main() { 'FOREIGN KEY (`${foreignKey.childColumns[0]}`) ' 'REFERENCES `${foreignKey.parentName}` ' '(`${foreignKey.parentColumns[0]}`) ' - 'ON UPDATE ${foreignKey.onUpdate} ' - 'ON DELETE ${foreignKey.onDelete}' + 'ON UPDATE ${foreignKey.onUpdate.toSQL} ' + 'ON DELETE ${foreignKey.onDelete.toSQL}' ')'; expect(actual, equals(expected)); }); diff --git a/floor_generator/test/value_object/foreign_key_test.dart b/floor_generator/test/value_object/foreign_key_test.dart index 324d9f4b..53b92772 100644 --- a/floor_generator/test/value_object/foreign_key_test.dart +++ b/floor_generator/test/value_object/foreign_key_test.dart @@ -1,3 +1,4 @@ +import 'package:floor_generator/misc/foreign_key_action.dart'; import 'package:floor_generator/value_object/foreign_key.dart'; import 'package:test/test.dart'; @@ -8,8 +9,8 @@ void main() { 'Person', ['id'], ['owner_id'], - 'CASCADE', - 'SET NULL', + ForeignKeyAction.cascade, + ForeignKeyAction.setNull, ); final actual = foreignKey.getDefinition(); @@ -26,8 +27,8 @@ void main() { 'Person', ['id', 'foo'], ['owner_id', 'bar'], - 'CASCADE', - 'SET NULL', + ForeignKeyAction.cascade, + ForeignKeyAction.setNull, ); final actual = foreignKey.getDefinition(); From 0464699ce182661841be0c56d9b3b17ffe233c1a Mon Sep 17 00:00:00 2001 From: Markus Richter <8398165+mqus@users.noreply.github.com> Date: Sun, 14 Jun 2020 15:46:54 +0200 Subject: [PATCH 2/6] Add a test for wrong ForeignKeyAction annotations --- .../test/processor/entity_processor_test.dart | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/floor_generator/test/processor/entity_processor_test.dart b/floor_generator/test/processor/entity_processor_test.dart index 4c908c53..c7c68319 100644 --- a/floor_generator/test/processor/entity_processor_test.dart +++ b/floor_generator/test/processor/entity_processor_test.dart @@ -2,6 +2,7 @@ import 'package:analyzer/dart/element/element.dart'; import 'package:build_test/build_test.dart'; import 'package:floor_generator/misc/foreign_key_action.dart'; import 'package:floor_generator/processor/entity_processor.dart'; +import 'package:floor_generator/processor/error/entity_processor_error.dart'; import 'package:floor_generator/processor/field_processor.dart'; import 'package:floor_generator/value_object/entity.dart'; import 'package:floor_generator/value_object/foreign_key.dart'; @@ -132,6 +133,50 @@ void main() { ); expect(actual, equals(expected)); }); + + test('error with wrong onUpdate Annotation', () async { + final classElements = await _createClassElements(''' + @entity + class Person { + @primaryKey + final int id; + + final String name; + + Person(this.id, this.name); + } + + @Entity( + foreignKeys: [ + ForeignKey( + childColumns: ['owner_id'], + parentColumns: ['id'], + entity: Person, + onUpdate: 6 + onDelete: ForeignKeyAction.setNull, + ) + ], + ) + class Dog { + @primaryKey + final int id; + + final String name; + + @ColumnInfo(name: 'owner_id') + final int ownerId; + + Dog(this.id, this.name, this.ownerId); + } + '''); + + final processor = EntityProcessor(classElements[1]); + expect( + processor.process, + throwsInvalidGenerationSourceError( + EntityProcessorError(classElements[1]) + .wrongForeignKeyAction(6, true))); + }); }); test('Process entity with "WITHOUT ROWID"', () async { From 377680331a8e191a0eaa69997de9b155df0b30bb Mon Sep 17 00:00:00 2001 From: Markus Richter <8398165+mqus@users.noreply.github.com> Date: Wed, 17 Jun 2020 01:27:37 +0200 Subject: [PATCH 3/6] Use ForeignKeyAction from Annotations --- floor_annotation/lib/src/foreign_key.dart | 16 ++++----- .../misc/extension/dart_object_extension.dart | 14 +++++++- .../misc/extension/foreign_key_action.dart | 22 ++++++++++++ .../lib/misc/foreign_key_action.dart | 36 ------------------- .../lib/processor/entity_processor.dart | 36 ++++++++++++------- .../error/entity_processor_error.dart | 5 +-- .../lib/value_object/foreign_key.dart | 5 ++- .../test/misc/foreign_key_action_test.dart | 33 +++++------------ floor_generator/test/mocks.dart | 6 ++++ .../test/processor/entity_processor_test.dart | 6 ++-- .../test/value_object/entity_test.dart | 2 +- .../test/value_object/foreign_key_test.dart | 1 - 12 files changed, 92 insertions(+), 90 deletions(-) create mode 100644 floor_generator/lib/misc/extension/foreign_key_action.dart delete mode 100644 floor_generator/lib/misc/foreign_key_action.dart diff --git a/floor_annotation/lib/src/foreign_key.dart b/floor_annotation/lib/src/foreign_key.dart index 3e662c0a..1e76b89c 100644 --- a/floor_annotation/lib/src/foreign_key.dart +++ b/floor_annotation/lib/src/foreign_key.dart @@ -15,13 +15,13 @@ class ForeignKey { /// Action to take when the parent [Entity] is updated from the database. /// /// By default, [ForeignKeyAction.noAction] is used. - final int onUpdate; + final ForeignKeyAction onUpdate; /// [ForeignKeyAction] /// Action to take when the parent [Entity] is deleted from the database. /// /// By default, [ForeignKeyAction.noAction] is used. - final int onDelete; + final ForeignKeyAction onDelete; /// Declares a foreign key on another [Entity]. const ForeignKey({ @@ -35,13 +35,13 @@ class ForeignKey { /// Constants definition for values that can be used in /// [ForeignKey.onDelete] and [ForeignKey.onUpdate] -abstract class ForeignKeyAction { +enum ForeignKeyAction { /// Possible value for [ForeignKey.onDelete] or [ForeignKey.onUpdate]. /// /// When a parent key is modified or deleted from the database, no special /// action is taken. This means that SQLite will not make any effort to fix /// the constraint failure, instead, reject the change. - static const noAction = 0; + noAction, /// Possible value for [ForeignKey.onDelete] or [ForeignKey.onUpdate]. /// @@ -57,7 +57,7 @@ abstract class ForeignKeyAction { /// Even if the foreign key constraint it is attached to is deferred(), /// configuring a RESTRICT action causes SQLite to return an error immediately /// if a parent key with dependent child keys is deleted or modified. - static const restrict = 1; + restrict, /// Possible value for [ForeignKey.onDelete] or [ForeignKey.onUpdate]. /// @@ -65,14 +65,14 @@ abstract class ForeignKeyAction { /// (for [ForeignKey.onDelete]) or modified (for [ForeignKey.onUpdate]), the /// child key columns of all rows in the child table that mapped to the parent /// key are set to contain NULL values. - static const setNull = 2; + setNull, /// Possible value for [ForeignKey.onDelete] or [ForeignKey.onUpdate]. /// /// The 'SET DEFAULT' actions are similar to SET_NULL, except that each of the /// child key columns is set to contain the columns default value instead of /// NULL. - static const setDefault = 3; + setDefault, /// Possible value for [ForeignKey.onDelete] or [ForeignKey.onUpdate]. /// @@ -82,5 +82,5 @@ abstract class ForeignKeyAction { /// deleted parent row is also deleted. For an [ForeignKey.onUpdate] action, /// it means that the values stored in each dependent child key are modified /// to match the new parent key values. - static const cascade = 4; + cascade, } diff --git a/floor_generator/lib/misc/extension/dart_object_extension.dart b/floor_generator/lib/misc/extension/dart_object_extension.dart index 7c2fc4ab..73c0cf12 100644 --- a/floor_generator/lib/misc/extension/dart_object_extension.dart +++ b/floor_generator/lib/misc/extension/dart_object_extension.dart @@ -1,5 +1,8 @@ import 'package:analyzer/dart/constant/value.dart'; import 'package:analyzer/dart/element/type.dart'; +import 'package:floor_annotation/floor_annotation.dart'; + +import '../annotations.dart'; extension DartObjectExtension on DartObject { String toEnumValueString() { @@ -7,8 +10,17 @@ extension DartObjectExtension on DartObject { final enumValue = interfaceType.element.fields .where((element) => element.isEnumConstant) .map((fieldElement) => fieldElement.name) - .singleWhere((valueName) => getField(valueName) != null); + .singleWhere((valueName) => getField(valueName) != null, + orElse: () => null); return '$interfaceType.$enumValue'; } + + @nullable + ForeignKeyAction toForeignKeyAction() { + final enumValueString = toEnumValueString(); + return ForeignKeyAction.values.singleWhere( + (foreignKeyAction) => foreignKeyAction.toString() == enumValueString, + orElse: () => null); + } } diff --git a/floor_generator/lib/misc/extension/foreign_key_action.dart b/floor_generator/lib/misc/extension/foreign_key_action.dart new file mode 100644 index 00000000..87be7fde --- /dev/null +++ b/floor_generator/lib/misc/extension/foreign_key_action.dart @@ -0,0 +1,22 @@ +import 'package:floor_annotation/floor_annotation.dart'; +import 'package:floor_generator/misc/annotations.dart'; + +extension ToSQL on ForeignKeyAction { + @nonNull + String get toSQL { + switch (this) { + case ForeignKeyAction.noAction: + return 'NO ACTION'; + case ForeignKeyAction.restrict: + return 'RESTRICT'; + case ForeignKeyAction.setNull: + return 'SET NULL'; + case ForeignKeyAction.setDefault: + return 'SET DEFAULT'; + case ForeignKeyAction.cascade: + return 'CASCADE'; + default: + return null; + } + } +} diff --git a/floor_generator/lib/misc/foreign_key_action.dart b/floor_generator/lib/misc/foreign_key_action.dart deleted file mode 100644 index 51f4384f..00000000 --- a/floor_generator/lib/misc/foreign_key_action.dart +++ /dev/null @@ -1,36 +0,0 @@ -import 'package:floor_generator/misc/annotations.dart'; - -enum ForeignKeyAction { noAction, restrict, setNull, setDefault, cascade } - -extension AnnotationConverter on ForeignKeyAction { - @nonNull - String get toSQL { - switch (this) { - case ForeignKeyAction.noAction: - return 'NO ACTION'; - case ForeignKeyAction.restrict: - return 'RESTRICT'; - case ForeignKeyAction.setNull: - return 'SET NULL'; - case ForeignKeyAction.setDefault: - return 'SET DEFAULT'; - case ForeignKeyAction.cascade: - return 'CASCADE'; - default: - assert(false, 'Unexpected enum case $this'); - return null; - } - } - - static ForeignKeyAction fromInt(int i) { - // the position of the value in this list has to match the - // integer of the annotation. - return [ - ForeignKeyAction.noAction, - ForeignKeyAction.restrict, - ForeignKeyAction.setNull, - ForeignKeyAction.setDefault, - ForeignKeyAction.cascade - ][i]; - } -} diff --git a/floor_generator/lib/processor/entity_processor.dart b/floor_generator/lib/processor/entity_processor.dart index 9a66de94..ed6fc866 100644 --- a/floor_generator/lib/processor/entity_processor.dart +++ b/floor_generator/lib/processor/entity_processor.dart @@ -1,9 +1,9 @@ import 'package:analyzer/dart/constant/value.dart'; import 'package:analyzer/dart/element/element.dart'; import 'package:floor_annotation/floor_annotation.dart' as annotations; +import 'package:floor_generator/misc/extension/dart_object_extension.dart'; import 'package:floor_generator/misc/annotations.dart'; import 'package:floor_generator/misc/constants.dart'; -import 'package:floor_generator/misc/foreign_key_action.dart'; import 'package:floor_generator/misc/type_utils.dart'; import 'package:floor_generator/processor/error/entity_processor_error.dart'; import 'package:floor_generator/processor/queryable_processor.dart'; @@ -12,6 +12,7 @@ import 'package:floor_generator/value_object/field.dart'; import 'package:floor_generator/value_object/foreign_key.dart'; import 'package:floor_generator/value_object/index.dart'; import 'package:floor_generator/value_object/primary_key.dart'; +import 'package:meta/meta.dart'; class EntityProcessor extends QueryableProcessor { final EntityProcessorError _processorError; @@ -86,16 +87,11 @@ class EntityProcessor extends QueryableProcessor { throw _processorError.missingParentColumns; } - final onUpdateAnnotationValue = - foreignKeyObject.getField(ForeignKeyField.onUpdate)?.toIntValue(); - _assertForeignKeyActionValue(onUpdateAnnotationValue, isUpdate: true); - final onUpdate = AnnotationConverter.fromInt(onUpdateAnnotationValue); + final onUpdate = + _getForeignKeyAction(foreignKeyObject, isUpdate: true); - final onDeleteAnnotationValue = - foreignKeyObject.getField(ForeignKeyField.onDelete)?.toIntValue(); - _assertForeignKeyActionValue(onDeleteAnnotationValue, - isUpdate: false); - final onDelete = AnnotationConverter.fromInt(onDeleteAnnotationValue); + final onDelete = + _getForeignKeyAction(foreignKeyObject, isUpdate: false); return ForeignKey( parentName, @@ -225,9 +221,23 @@ class EntityProcessor extends QueryableProcessor { false; } - void _assertForeignKeyActionValue(int foreignKeyAction, {bool isUpdate}) { - if (foreignKeyAction < 0 || foreignKeyAction > 4) { - throw _processorError.wrongForeignKeyAction(foreignKeyAction, isUpdate); + @nonNull + annotations.ForeignKeyAction _getForeignKeyAction(DartObject foreignKeyObject, + {@required bool isUpdate}) { + final fieldName = + isUpdate ? ForeignKeyField.onUpdate : ForeignKeyField.onDelete; + + final field = foreignKeyObject.getField(fieldName); + if (field == null) { + // field was not defined, return default value + return annotations.ForeignKeyAction.noAction; + } + + final fka = field.toForeignKeyAction(); + if (fka == null) { + // field was not defined correctly + throw _processorError.wrongForeignKeyAction(field, isUpdate); } + return fka; } } diff --git a/floor_generator/lib/processor/error/entity_processor_error.dart b/floor_generator/lib/processor/error/entity_processor_error.dart index 89896aee..f034af11 100644 --- a/floor_generator/lib/processor/error/entity_processor_error.dart +++ b/floor_generator/lib/processor/error/entity_processor_error.dart @@ -1,3 +1,4 @@ +import 'package:analyzer/dart/constant/value.dart'; import 'package:analyzer/dart/element/element.dart'; import 'package:source_gen/source_gen.dart'; @@ -71,9 +72,9 @@ class EntityProcessorError { } InvalidGenerationSourceError wrongForeignKeyAction( - int foreignKeyAction, bool isUpdate) { + DartObject field, bool isUpdate) { return InvalidGenerationSourceError( - 'No ForeignKeyAction with the value $foreignKeyAction exists for the on${isUpdate ? 'Update' : 'Delete'} trigger.', + 'No ForeignKeyAction with the value $field exists for the on${isUpdate ? 'Update' : 'Delete'} trigger.', todo: 'Make sure to add a correct ForeignKeyAction like `ForeignKeyAction.noAction` or leave it out entirely.', element: _classElement, diff --git a/floor_generator/lib/value_object/foreign_key.dart b/floor_generator/lib/value_object/foreign_key.dart index d88129c3..a2b5c11d 100644 --- a/floor_generator/lib/value_object/foreign_key.dart +++ b/floor_generator/lib/value_object/foreign_key.dart @@ -1,6 +1,9 @@ import 'package:collection/collection.dart'; +import 'package:floor_annotation/floor_annotation.dart' show ForeignKeyAction; import 'package:floor_generator/misc/annotations.dart'; -import 'package:floor_generator/misc/foreign_key_action.dart'; +import 'package:floor_generator/misc/extension/foreign_key_action.dart'; + +export 'package:floor_annotation/floor_annotation.dart' show ForeignKeyAction; class ForeignKey { final String parentName; diff --git a/floor_generator/test/misc/foreign_key_action_test.dart b/floor_generator/test/misc/foreign_key_action_test.dart index 455773c3..e55e5f1f 100644 --- a/floor_generator/test/misc/foreign_key_action_test.dart +++ b/floor_generator/test/misc/foreign_key_action_test.dart @@ -1,52 +1,37 @@ -import 'package:floor_generator/misc/foreign_key_action.dart'; +import 'package:floor_generator/misc/extension/foreign_key_action.dart'; import 'package:floor_annotation/floor_annotation.dart' as annotations; import 'package:test/test.dart'; void main() { group('foreign key action strings', () { test('NO ACTION', () { - final actual = - AnnotationConverter.fromInt(annotations.ForeignKeyAction.noAction) - .toSQL; + final actual = annotations.ForeignKeyAction.noAction.toSQL; expect(actual, equals('NO ACTION')); }); test('RESTRICT', () { - final actual = - AnnotationConverter.fromInt(annotations.ForeignKeyAction.restrict) - .toSQL; - + final actual = annotations.ForeignKeyAction.restrict.toSQL; expect(actual, equals('RESTRICT')); }); test('SET NULL', () { - final actual = - AnnotationConverter.fromInt(annotations.ForeignKeyAction.setNull) - .toSQL; - + final actual = annotations.ForeignKeyAction.setNull.toSQL; expect(actual, equals('SET NULL')); }); test('SET DEFAULT', () { - final actual = - AnnotationConverter.fromInt(annotations.ForeignKeyAction.setDefault) - .toSQL; - + final actual = annotations.ForeignKeyAction.setDefault.toSQL; expect(actual, equals('SET DEFAULT')); }); test('CASCADE', () { - final actual = - AnnotationConverter.fromInt(annotations.ForeignKeyAction.cascade) - .toSQL; - + final actual = annotations.ForeignKeyAction.cascade.toSQL; expect(actual, equals('CASCADE')); }); - test('errors out if action not known', () { - final conversion = () => AnnotationConverter.fromInt(12345).toSQL; - - expect(conversion, throwsRangeError); + test('null annotation returns null', () { + final actual = null.toSQL; + expect(actual, isNull); }); }); } diff --git a/floor_generator/test/mocks.dart b/floor_generator/test/mocks.dart index 76b45536..e39c0b35 100644 --- a/floor_generator/test/mocks.dart +++ b/floor_generator/test/mocks.dart @@ -1,3 +1,4 @@ +import 'package:analyzer/dart/constant/value.dart'; import 'package:analyzer/dart/element/element.dart'; import 'package:analyzer/dart/element/type.dart'; import 'package:mockito/mockito.dart'; @@ -7,3 +8,8 @@ class MockClassElement extends Mock implements ClassElement {} class MockFieldElement extends Mock implements FieldElement {} class MockDartType extends Mock implements DartType {} + +class MockDartObject extends Mock implements DartObject { + @override + String toString() => 'Null (null)'; +} diff --git a/floor_generator/test/processor/entity_processor_test.dart b/floor_generator/test/processor/entity_processor_test.dart index c7c68319..a6a9199e 100644 --- a/floor_generator/test/processor/entity_processor_test.dart +++ b/floor_generator/test/processor/entity_processor_test.dart @@ -1,6 +1,5 @@ import 'package:analyzer/dart/element/element.dart'; import 'package:build_test/build_test.dart'; -import 'package:floor_generator/misc/foreign_key_action.dart'; import 'package:floor_generator/processor/entity_processor.dart'; import 'package:floor_generator/processor/error/entity_processor_error.dart'; import 'package:floor_generator/processor/field_processor.dart'; @@ -11,6 +10,7 @@ import 'package:floor_generator/value_object/primary_key.dart'; import 'package:source_gen/source_gen.dart'; import 'package:test/test.dart'; +import '../mocks.dart'; import '../test_utils.dart'; void main() { @@ -152,7 +152,7 @@ void main() { childColumns: ['owner_id'], parentColumns: ['id'], entity: Person, - onUpdate: 6 + onUpdate: null onDelete: ForeignKeyAction.setNull, ) ], @@ -175,7 +175,7 @@ void main() { processor.process, throwsInvalidGenerationSourceError( EntityProcessorError(classElements[1]) - .wrongForeignKeyAction(6, true))); + .wrongForeignKeyAction(MockDartObject(), true))); }); }); diff --git a/floor_generator/test/value_object/entity_test.dart b/floor_generator/test/value_object/entity_test.dart index 50c70f9b..60d2a2f3 100644 --- a/floor_generator/test/value_object/entity_test.dart +++ b/floor_generator/test/value_object/entity_test.dart @@ -1,5 +1,5 @@ import 'package:floor_generator/misc/constants.dart'; -import 'package:floor_generator/misc/foreign_key_action.dart'; +import 'package:floor_generator/misc/extension/foreign_key_action.dart'; import 'package:floor_generator/value_object/entity.dart'; import 'package:floor_generator/value_object/field.dart'; import 'package:floor_generator/value_object/foreign_key.dart'; diff --git a/floor_generator/test/value_object/foreign_key_test.dart b/floor_generator/test/value_object/foreign_key_test.dart index 53b92772..20d1cd2b 100644 --- a/floor_generator/test/value_object/foreign_key_test.dart +++ b/floor_generator/test/value_object/foreign_key_test.dart @@ -1,4 +1,3 @@ -import 'package:floor_generator/misc/foreign_key_action.dart'; import 'package:floor_generator/value_object/foreign_key.dart'; import 'package:test/test.dart'; From 52d9f2175ce8a2ab4ee1a733035f0689661cd4d9 Mon Sep 17 00:00:00 2001 From: Markus Richter <8398165+mqus@users.noreply.github.com> Date: Sat, 20 Jun 2020 14:10:43 +0200 Subject: [PATCH 4/6] Resolve issues from review in #359 and add new tests for wrong onConflict values --- .../misc/extension/dart_object_extension.dart | 16 ++++++------- .../misc/extension/foreign_key_action.dart | 7 +++--- .../lib/processor/entity_processor.dart | 23 +++++++------------ .../error/entity_processor_error.dart | 4 ++-- .../processor/insertion_method_processor.dart | 8 +++++-- .../processor/update_method_processor.dart | 8 +++++-- .../lib/value_object/foreign_key.dart | 4 ++-- .../test/misc/foreign_key_action_test.dart | 15 ++++++------ .../test/processor/entity_processor_test.dart | 5 ++-- .../insertion_method_processor_test.dart | 15 ++++++++++++ .../update_method_processor_test.dart | 15 ++++++++++++ .../test/value_object/entity_test.dart | 4 ++-- 12 files changed, 78 insertions(+), 46 deletions(-) diff --git a/floor_generator/lib/misc/extension/dart_object_extension.dart b/floor_generator/lib/misc/extension/dart_object_extension.dart index 73c0cf12..8bb7e6e6 100644 --- a/floor_generator/lib/misc/extension/dart_object_extension.dart +++ b/floor_generator/lib/misc/extension/dart_object_extension.dart @@ -1,26 +1,26 @@ import 'package:analyzer/dart/constant/value.dart'; import 'package:analyzer/dart/element/type.dart'; import 'package:floor_annotation/floor_annotation.dart'; - -import '../annotations.dart'; +import 'package:meta/meta.dart'; extension DartObjectExtension on DartObject { - String toEnumValueString() { + /// get the String representation of the enum value, or the result of + /// [orElse] if the enum was not valid. [orElse] + String toEnumValueString({@required String orElse()}) { final interfaceType = type as InterfaceType; final enumValue = interfaceType.element.fields .where((element) => element.isEnumConstant) .map((fieldElement) => fieldElement.name) .singleWhere((valueName) => getField(valueName) != null, - orElse: () => null); + orElse: orElse); return '$interfaceType.$enumValue'; } - @nullable - ForeignKeyAction toForeignKeyAction() { - final enumValueString = toEnumValueString(); + ForeignKeyAction toForeignKeyAction({@required ForeignKeyAction orElse()}) { + final enumValueString = toEnumValueString(orElse: () => null); return ForeignKeyAction.values.singleWhere( (foreignKeyAction) => foreignKeyAction.toString() == enumValueString, - orElse: () => null); + orElse: orElse); } } diff --git a/floor_generator/lib/misc/extension/foreign_key_action.dart b/floor_generator/lib/misc/extension/foreign_key_action.dart index 87be7fde..0dd63dba 100644 --- a/floor_generator/lib/misc/extension/foreign_key_action.dart +++ b/floor_generator/lib/misc/extension/foreign_key_action.dart @@ -3,7 +3,7 @@ import 'package:floor_generator/misc/annotations.dart'; extension ToSQL on ForeignKeyAction { @nonNull - String get toSQL { + String toSql() { switch (this) { case ForeignKeyAction.noAction: return 'NO ACTION'; @@ -15,8 +15,9 @@ extension ToSQL on ForeignKeyAction { return 'SET DEFAULT'; case ForeignKeyAction.cascade: return 'CASCADE'; - default: - return null; + default: // can only match null + throw ArgumentError('toSql() should not be called on a null value. ' + 'This is a bug in floor.'); } } } diff --git a/floor_generator/lib/processor/entity_processor.dart b/floor_generator/lib/processor/entity_processor.dart index ed6fc866..42dcfd6d 100644 --- a/floor_generator/lib/processor/entity_processor.dart +++ b/floor_generator/lib/processor/entity_processor.dart @@ -12,7 +12,6 @@ import 'package:floor_generator/value_object/field.dart'; import 'package:floor_generator/value_object/foreign_key.dart'; import 'package:floor_generator/value_object/index.dart'; import 'package:floor_generator/value_object/primary_key.dart'; -import 'package:meta/meta.dart'; class EntityProcessor extends QueryableProcessor { final EntityProcessorError _processorError; @@ -88,10 +87,10 @@ class EntityProcessor extends QueryableProcessor { } final onUpdate = - _getForeignKeyAction(foreignKeyObject, isUpdate: true); + _getForeignKeyAction(foreignKeyObject, ForeignKeyField.onUpdate); final onDelete = - _getForeignKeyAction(foreignKeyObject, isUpdate: false); + _getForeignKeyAction(foreignKeyObject, ForeignKeyField.onDelete); return ForeignKey( parentName, @@ -222,22 +221,16 @@ class EntityProcessor extends QueryableProcessor { } @nonNull - annotations.ForeignKeyAction _getForeignKeyAction(DartObject foreignKeyObject, - {@required bool isUpdate}) { - final fieldName = - isUpdate ? ForeignKeyField.onUpdate : ForeignKeyField.onDelete; - - final field = foreignKeyObject.getField(fieldName); + annotations.ForeignKeyAction _getForeignKeyAction( + DartObject foreignKeyObject, String triggerName) { + final field = foreignKeyObject.getField(triggerName); if (field == null) { // field was not defined, return default value return annotations.ForeignKeyAction.noAction; } - final fka = field.toForeignKeyAction(); - if (fka == null) { - // field was not defined correctly - throw _processorError.wrongForeignKeyAction(field, isUpdate); - } - return fka; + return field.toForeignKeyAction( + orElse: () => + throw _processorError.wrongForeignKeyAction(field, triggerName)); } } diff --git a/floor_generator/lib/processor/error/entity_processor_error.dart b/floor_generator/lib/processor/error/entity_processor_error.dart index f034af11..b2579d0b 100644 --- a/floor_generator/lib/processor/error/entity_processor_error.dart +++ b/floor_generator/lib/processor/error/entity_processor_error.dart @@ -72,9 +72,9 @@ class EntityProcessorError { } InvalidGenerationSourceError wrongForeignKeyAction( - DartObject field, bool isUpdate) { + DartObject field, String triggerName) { return InvalidGenerationSourceError( - 'No ForeignKeyAction with the value $field exists for the on${isUpdate ? 'Update' : 'Delete'} trigger.', + 'No ForeignKeyAction with the value $field exists for the $triggerName trigger.', todo: 'Make sure to add a correct ForeignKeyAction like `ForeignKeyAction.noAction` or leave it out entirely.', element: _classElement, diff --git a/floor_generator/lib/processor/insertion_method_processor.dart b/floor_generator/lib/processor/insertion_method_processor.dart index e485f955..873975ec 100644 --- a/floor_generator/lib/processor/insertion_method_processor.dart +++ b/floor_generator/lib/processor/insertion_method_processor.dart @@ -1,7 +1,7 @@ import 'package:analyzer/dart/element/element.dart'; import 'package:analyzer/dart/element/type.dart'; import 'package:floor_annotation/floor_annotation.dart' as annotations - show Insert; + show Insert, OnConflictStrategy; import 'package:floor_generator/misc/annotations.dart'; import 'package:floor_generator/misc/change_method_processor_helper.dart'; import 'package:floor_generator/misc/constants.dart'; @@ -87,7 +87,11 @@ class InsertionMethodProcessor implements Processor { return _methodElement .getAnnotation(annotations.Insert) .getField(AnnotationField.onConflict) - .toEnumValueString(); + .toEnumValueString( + orElse: () => throw InvalidGenerationSourceError( + 'Value of ${AnnotationField.onConflict} must be one of ${annotations.OnConflictStrategy.values.map((e) => e.toString()).join(',')}', + element: _methodElement, + )); } void _assertMethodReturnsFuture(final DartType returnType) { diff --git a/floor_generator/lib/processor/update_method_processor.dart b/floor_generator/lib/processor/update_method_processor.dart index 22e7ca7d..2dface6a 100644 --- a/floor_generator/lib/processor/update_method_processor.dart +++ b/floor_generator/lib/processor/update_method_processor.dart @@ -1,7 +1,7 @@ import 'package:analyzer/dart/element/element.dart'; import 'package:analyzer/dart/element/type.dart'; import 'package:floor_annotation/floor_annotation.dart' as annotations - show Update; + show Update, OnConflictStrategy; import 'package:floor_generator/misc/annotations.dart'; import 'package:floor_generator/misc/change_method_processor_helper.dart'; import 'package:floor_generator/misc/constants.dart'; @@ -69,7 +69,11 @@ class UpdateMethodProcessor implements Processor { return _methodElement .getAnnotation(annotations.Update) .getField(AnnotationField.onConflict) - .toEnumValueString(); + .toEnumValueString( + orElse: () => throw InvalidGenerationSourceError( + 'Value of ${AnnotationField.onConflict} must be one of ${annotations.OnConflictStrategy.values.map((e) => e.toString()).join(',')}', + element: _methodElement, + )); } @nonNull diff --git a/floor_generator/lib/value_object/foreign_key.dart b/floor_generator/lib/value_object/foreign_key.dart index a2b5c11d..d20c1bd3 100644 --- a/floor_generator/lib/value_object/foreign_key.dart +++ b/floor_generator/lib/value_object/foreign_key.dart @@ -29,8 +29,8 @@ class ForeignKey { return 'FOREIGN KEY ($escapedChildColumns)' ' REFERENCES `$parentName` ($escapedParentColumns)' - ' ON UPDATE ${onUpdate.toSQL}' - ' ON DELETE ${onDelete.toSQL}'; + ' ON UPDATE ${onUpdate.toSql()}' + ' ON DELETE ${onDelete.toSql()}'; } final _listEquality = const ListEquality(); diff --git a/floor_generator/test/misc/foreign_key_action_test.dart b/floor_generator/test/misc/foreign_key_action_test.dart index e55e5f1f..3ac0da9a 100644 --- a/floor_generator/test/misc/foreign_key_action_test.dart +++ b/floor_generator/test/misc/foreign_key_action_test.dart @@ -5,33 +5,32 @@ import 'package:test/test.dart'; void main() { group('foreign key action strings', () { test('NO ACTION', () { - final actual = annotations.ForeignKeyAction.noAction.toSQL; + final actual = annotations.ForeignKeyAction.noAction.toSql(); expect(actual, equals('NO ACTION')); }); test('RESTRICT', () { - final actual = annotations.ForeignKeyAction.restrict.toSQL; + final actual = annotations.ForeignKeyAction.restrict.toSql(); expect(actual, equals('RESTRICT')); }); test('SET NULL', () { - final actual = annotations.ForeignKeyAction.setNull.toSQL; + final actual = annotations.ForeignKeyAction.setNull.toSql(); expect(actual, equals('SET NULL')); }); test('SET DEFAULT', () { - final actual = annotations.ForeignKeyAction.setDefault.toSQL; + final actual = annotations.ForeignKeyAction.setDefault.toSql(); expect(actual, equals('SET DEFAULT')); }); test('CASCADE', () { - final actual = annotations.ForeignKeyAction.cascade.toSQL; + final actual = annotations.ForeignKeyAction.cascade.toSql(); expect(actual, equals('CASCADE')); }); - test('null annotation returns null', () { - final actual = null.toSQL; - expect(actual, isNull); + test('null throws ArgumentError', () { + expect(() => null.toSql(), throwsArgumentError); }); }); } diff --git a/floor_generator/test/processor/entity_processor_test.dart b/floor_generator/test/processor/entity_processor_test.dart index a6a9199e..405a49ee 100644 --- a/floor_generator/test/processor/entity_processor_test.dart +++ b/floor_generator/test/processor/entity_processor_test.dart @@ -1,5 +1,6 @@ import 'package:analyzer/dart/element/element.dart'; import 'package:build_test/build_test.dart'; +import 'package:floor_generator/misc/constants.dart'; import 'package:floor_generator/processor/entity_processor.dart'; import 'package:floor_generator/processor/error/entity_processor_error.dart'; import 'package:floor_generator/processor/field_processor.dart'; @@ -174,8 +175,8 @@ void main() { expect( processor.process, throwsInvalidGenerationSourceError( - EntityProcessorError(classElements[1]) - .wrongForeignKeyAction(MockDartObject(), true))); + EntityProcessorError(classElements[1]).wrongForeignKeyAction( + MockDartObject(), ForeignKeyField.onUpdate))); }); }); diff --git a/floor_generator/test/processor/insertion_method_processor_test.dart b/floor_generator/test/processor/insertion_method_processor_test.dart index 13068e06..5c62e525 100644 --- a/floor_generator/test/processor/insertion_method_processor_test.dart +++ b/floor_generator/test/processor/insertion_method_processor_test.dart @@ -1,4 +1,5 @@ import 'package:floor_generator/processor/insertion_method_processor.dart'; +import 'package:source_gen/source_gen.dart'; import 'package:test/test.dart'; import '../test_utils.dart'; @@ -18,4 +19,18 @@ void main() { expect(actual, equals('OnConflictStrategy.replace')); }); + + test('Error on wrong onConflict value', () async { + final insertionMethod = await ''' + @Insert(onConflict: OnConflictStrategy.doesnotexist) + Future insertPerson(Person person); + ''' + .asDaoMethodElement(); + final entities = await getPersonEntity(); + + final actual = + () => InsertionMethodProcessor(insertionMethod, [entities]).process(); + + expect(actual, throwsA(const TypeMatcher())); + }); } diff --git a/floor_generator/test/processor/update_method_processor_test.dart b/floor_generator/test/processor/update_method_processor_test.dart index 5eb5cc04..3e6abeb0 100644 --- a/floor_generator/test/processor/update_method_processor_test.dart +++ b/floor_generator/test/processor/update_method_processor_test.dart @@ -1,4 +1,5 @@ import 'package:floor_generator/processor/update_method_processor.dart'; +import 'package:source_gen/source_gen.dart'; import 'package:test/test.dart'; import '../test_utils.dart'; @@ -17,4 +18,18 @@ void main() { expect(actual, equals('OnConflictStrategy.replace')); }); + + test('Error on wrong onConflict value', () async { + final insertionMethod = await ''' + @Update(onConflict: OnConflictStrategy.doesnotexist) + Future updatePerson(Person person); + ''' + .asDaoMethodElement(); + final entities = await getPersonEntity(); + + final actual = + () => UpdateMethodProcessor(insertionMethod, [entities]).process(); + + expect(actual, throwsA(const TypeMatcher())); + }); } diff --git a/floor_generator/test/value_object/entity_test.dart b/floor_generator/test/value_object/entity_test.dart index 60d2a2f3..a0e30f95 100644 --- a/floor_generator/test/value_object/entity_test.dart +++ b/floor_generator/test/value_object/entity_test.dart @@ -137,8 +137,8 @@ void main() { 'FOREIGN KEY (`${foreignKey.childColumns[0]}`) ' 'REFERENCES `${foreignKey.parentName}` ' '(`${foreignKey.parentColumns[0]}`) ' - 'ON UPDATE ${foreignKey.onUpdate.toSQL} ' - 'ON DELETE ${foreignKey.onDelete.toSQL}' + 'ON UPDATE ${foreignKey.onUpdate.toSql()} ' + 'ON DELETE ${foreignKey.onDelete.toSql()}' ')'; expect(actual, equals(expected)); }); From c5ebdf96ba24929d0b95df4243e164cd70a6f377 Mon Sep 17 00:00:00 2001 From: Markus Richter <8398165+mqus@users.noreply.github.com> Date: Fri, 21 Aug 2020 23:53:21 +0200 Subject: [PATCH 5/6] Fix weird early return value and use early return on other function Also fix formatting from rebase --- .../misc/extension/dart_object_extension.dart | 23 +++++++++++++------ .../error/entity_processor_error.dart | 2 +- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/floor_generator/lib/misc/extension/dart_object_extension.dart b/floor_generator/lib/misc/extension/dart_object_extension.dart index 8bb7e6e6..cc4bc94b 100644 --- a/floor_generator/lib/misc/extension/dart_object_extension.dart +++ b/floor_generator/lib/misc/extension/dart_object_extension.dart @@ -5,22 +5,31 @@ import 'package:meta/meta.dart'; extension DartObjectExtension on DartObject { /// get the String representation of the enum value, or the result of - /// [orElse] if the enum was not valid. [orElse] + /// [orElse] if the enum was not valid. String toEnumValueString({@required String orElse()}) { final interfaceType = type as InterfaceType; final enumValue = interfaceType.element.fields .where((element) => element.isEnumConstant) .map((fieldElement) => fieldElement.name) .singleWhere((valueName) => getField(valueName) != null, - orElse: orElse); - - return '$interfaceType.$enumValue'; + orElse: () => null); + if (enumValue == null) { + return orElse(); + } else { + return '$interfaceType.$enumValue'; + } } + /// get the ForeignKeyAction this enum represents, or the result of + /// [orElse] if the enum did not contain a valid value. ForeignKeyAction toForeignKeyAction({@required ForeignKeyAction orElse()}) { final enumValueString = toEnumValueString(orElse: () => null); - return ForeignKeyAction.values.singleWhere( - (foreignKeyAction) => foreignKeyAction.toString() == enumValueString, - orElse: orElse); + if (enumValueString == null) { + return orElse(); + } else { + return ForeignKeyAction.values.singleWhere( + (foreignKeyAction) => foreignKeyAction.toString() == enumValueString, + orElse: orElse); + } } } diff --git a/floor_generator/lib/processor/error/entity_processor_error.dart b/floor_generator/lib/processor/error/entity_processor_error.dart index b2579d0b..58098520 100644 --- a/floor_generator/lib/processor/error/entity_processor_error.dart +++ b/floor_generator/lib/processor/error/entity_processor_error.dart @@ -85,7 +85,7 @@ class EntityProcessorError { return InvalidGenerationSourceError( 'autoGenerate is not allowed in WITHOUT ROWID tables', todo: - 'Remove autoGenerate in @PrimaryKey() or withoutRowid in @Entity().', + 'Remove autoGenerate in @PrimaryKey() or withoutRowid in @Entity().', element: _classElement, ); } From a25a0e348edf2fc6307f4c24c225f7ac428a20ee Mon Sep 17 00:00:00 2001 From: vitusortner Date: Sun, 22 Nov 2020 21:31:04 +0100 Subject: [PATCH 6/6] Make generator run --- ...key_action.dart => foreign_key_action_extension.dart} | 2 +- floor_generator/lib/processor/entity_processor.dart | 3 +-- floor_generator/lib/value_object/foreign_key.dart | 4 +--- .../foreign_key_action_extension_test.dart} | 2 +- .../test/processor/entity_processor_test.dart | 7 ++++--- floor_generator/test/value_object/entity_test.dart | 7 ++++--- floor_generator/test/value_object/foreign_key_test.dart | 9 +++++---- 7 files changed, 17 insertions(+), 17 deletions(-) rename floor_generator/lib/misc/extension/{foreign_key_action.dart => foreign_key_action_extension.dart} (91%) rename floor_generator/test/misc/{foreign_key_action_test.dart => extension/foreign_key_action_extension_test.dart} (98%) diff --git a/floor_generator/lib/misc/extension/foreign_key_action.dart b/floor_generator/lib/misc/extension/foreign_key_action_extension.dart similarity index 91% rename from floor_generator/lib/misc/extension/foreign_key_action.dart rename to floor_generator/lib/misc/extension/foreign_key_action_extension.dart index 0dd63dba..5351c8c0 100644 --- a/floor_generator/lib/misc/extension/foreign_key_action.dart +++ b/floor_generator/lib/misc/extension/foreign_key_action_extension.dart @@ -1,7 +1,7 @@ import 'package:floor_annotation/floor_annotation.dart'; import 'package:floor_generator/misc/annotations.dart'; -extension ToSQL on ForeignKeyAction { +extension ForeignKeyActionExtension on ForeignKeyAction { @nonNull String toSql() { switch (this) { diff --git a/floor_generator/lib/processor/entity_processor.dart b/floor_generator/lib/processor/entity_processor.dart index 0f825cd4..d2591db1 100644 --- a/floor_generator/lib/processor/entity_processor.dart +++ b/floor_generator/lib/processor/entity_processor.dart @@ -2,11 +2,10 @@ import 'package:analyzer/dart/constant/value.dart'; import 'package:analyzer/dart/element/element.dart'; import 'package:dartx/dartx.dart'; import 'package:floor_annotation/floor_annotation.dart' as annotations; -import 'package:floor_generator/misc/extension/dart_object_extension.dart'; import 'package:floor_generator/misc/annotations.dart'; import 'package:floor_generator/misc/constants.dart'; +import 'package:floor_generator/misc/extension/dart_object_extension.dart'; import 'package:floor_generator/misc/extension/type_converters_extension.dart'; -import 'package:floor_generator/misc/foreign_key_action.dart'; import 'package:floor_generator/misc/type_utils.dart'; import 'package:floor_generator/processor/error/entity_processor_error.dart'; import 'package:floor_generator/processor/queryable_processor.dart'; diff --git a/floor_generator/lib/value_object/foreign_key.dart b/floor_generator/lib/value_object/foreign_key.dart index d20c1bd3..fa8dd6f0 100644 --- a/floor_generator/lib/value_object/foreign_key.dart +++ b/floor_generator/lib/value_object/foreign_key.dart @@ -1,9 +1,7 @@ import 'package:collection/collection.dart'; import 'package:floor_annotation/floor_annotation.dart' show ForeignKeyAction; import 'package:floor_generator/misc/annotations.dart'; -import 'package:floor_generator/misc/extension/foreign_key_action.dart'; - -export 'package:floor_annotation/floor_annotation.dart' show ForeignKeyAction; +import 'package:floor_generator/misc/extension/foreign_key_action_extension.dart'; class ForeignKey { final String parentName; diff --git a/floor_generator/test/misc/foreign_key_action_test.dart b/floor_generator/test/misc/extension/foreign_key_action_extension_test.dart similarity index 98% rename from floor_generator/test/misc/foreign_key_action_test.dart rename to floor_generator/test/misc/extension/foreign_key_action_extension_test.dart index 3ac0da9a..44b79086 100644 --- a/floor_generator/test/misc/foreign_key_action_test.dart +++ b/floor_generator/test/misc/extension/foreign_key_action_extension_test.dart @@ -1,5 +1,5 @@ -import 'package:floor_generator/misc/extension/foreign_key_action.dart'; import 'package:floor_annotation/floor_annotation.dart' as annotations; +import 'package:floor_generator/misc/extension/foreign_key_action_extension.dart'; import 'package:test/test.dart'; void main() { diff --git a/floor_generator/test/processor/entity_processor_test.dart b/floor_generator/test/processor/entity_processor_test.dart index 237dfd6d..ba5f09b2 100644 --- a/floor_generator/test/processor/entity_processor_test.dart +++ b/floor_generator/test/processor/entity_processor_test.dart @@ -1,5 +1,6 @@ import 'package:analyzer/dart/element/element.dart'; import 'package:build_test/build_test.dart'; +import 'package:floor_annotation/floor_annotation.dart' as annotations; import 'package:floor_generator/misc/constants.dart'; import 'package:floor_generator/processor/entity_processor.dart'; import 'package:floor_generator/processor/error/entity_processor_error.dart'; @@ -134,8 +135,8 @@ void main() { 'Person', ['id'], ['owner_id'], - ForeignKeyAction.cascade, - ForeignKeyAction.setNull, + annotations.ForeignKeyAction.cascade, + annotations.ForeignKeyAction.setNull, ); expect(actual, equals(expected)); }); @@ -176,7 +177,7 @@ void main() { } '''); - final processor = EntityProcessor(classElements[1]); + final processor = EntityProcessor(classElements[1], {}); expect( processor.process, throwsInvalidGenerationSourceError( diff --git a/floor_generator/test/value_object/entity_test.dart b/floor_generator/test/value_object/entity_test.dart index 239866d3..59404bcb 100644 --- a/floor_generator/test/value_object/entity_test.dart +++ b/floor_generator/test/value_object/entity_test.dart @@ -1,5 +1,6 @@ +import 'package:floor_annotation/floor_annotation.dart' as annotations; import 'package:floor_generator/misc/constants.dart'; -import 'package:floor_generator/misc/extension/foreign_key_action.dart'; +import 'package:floor_generator/misc/extension/foreign_key_action_extension.dart'; import 'package:floor_generator/value_object/entity.dart'; import 'package:floor_generator/value_object/field.dart'; import 'package:floor_generator/value_object/foreign_key.dart'; @@ -120,8 +121,8 @@ void main() { 'parentName', ['parentColumn'], ['childColumn'], - ForeignKeyAction.cascade, - ForeignKeyAction.noAction, + annotations.ForeignKeyAction.cascade, + annotations.ForeignKeyAction.noAction, ); final primaryKey = PrimaryKey([nullableField], true); final entity = Entity( diff --git a/floor_generator/test/value_object/foreign_key_test.dart b/floor_generator/test/value_object/foreign_key_test.dart index 20d1cd2b..e07a1514 100644 --- a/floor_generator/test/value_object/foreign_key_test.dart +++ b/floor_generator/test/value_object/foreign_key_test.dart @@ -1,3 +1,4 @@ +import 'package:floor_annotation/floor_annotation.dart' as annotations; import 'package:floor_generator/value_object/foreign_key.dart'; import 'package:test/test.dart'; @@ -8,8 +9,8 @@ void main() { 'Person', ['id'], ['owner_id'], - ForeignKeyAction.cascade, - ForeignKeyAction.setNull, + annotations.ForeignKeyAction.cascade, + annotations.ForeignKeyAction.setNull, ); final actual = foreignKey.getDefinition(); @@ -26,8 +27,8 @@ void main() { 'Person', ['id', 'foo'], ['owner_id', 'bar'], - ForeignKeyAction.cascade, - ForeignKeyAction.setNull, + annotations.ForeignKeyAction.cascade, + annotations.ForeignKeyAction.setNull, ); final actual = foreignKey.getDefinition();