diff --git a/drift_dev/lib/src/analyzer/dart/table_parser.dart b/drift_dev/lib/src/analyzer/dart/table_parser.dart index 8bf25328..cc803bc4 100644 --- a/drift_dev/lib/src/analyzer/dart/table_parser.dart +++ b/drift_dev/lib/src/analyzer/dart/table_parser.dart @@ -76,7 +76,8 @@ class TableParser { if (dataClassName != null) { name = dataClassName.getField('name')!.toStringValue()!; - customParentClass = parseCustomParentClass(dataClassName, element, base); + customParentClass = + parseCustomParentClass(name, dataClassName, element, base); } else { name = dataClassNameForClassName(element.name); } diff --git a/drift_dev/lib/src/analyzer/dart/view_parser.dart b/drift_dev/lib/src/analyzer/dart/view_parser.dart index b3ce54d8..c10a5315 100644 --- a/drift_dev/lib/src/analyzer/dart/view_parser.dart +++ b/drift_dev/lib/src/analyzer/dart/view_parser.dart @@ -36,7 +36,7 @@ class ViewParser { _DataClassInformation _readDataClassInformation( List columns, ClassElement element) { DartObject? useRowClass; - String? dataClassName; + DartObject? driftView; String? customParentClass; for (final annotation in element.metadata) { @@ -44,14 +44,13 @@ class ViewParser { final annotationClass = computed!.type!.element!.name; if (annotationClass == 'DriftView') { - dataClassName = computed.getField('dataClassName')?.toStringValue(); - customParentClass = parseCustomParentClass(computed, element, base); + driftView = computed; } else if (annotationClass == 'UseRowClass') { useRowClass = computed; } } - if (dataClassName != null && useRowClass != null) { + if (driftView != null && useRowClass != null) { base.step.reportError(ErrorInDartCode( message: "A table can't be annotated with both @DataClassName and " '@UseRowClass', @@ -63,7 +62,15 @@ class ViewParser { String? constructorInExistingClass; bool? generateInsertable; - var name = dataClassName ?? dataClassNameForClassName(element.name); + var name = dataClassNameForClassName(element.name); + + if (driftView != null) { + final dataClassName = + driftView.getField('dataClassName')?.toStringValue(); + name = dataClassName ?? dataClassNameForClassName(element.name); + customParentClass = + parseCustomParentClass(name, driftView, element, base); + } if (useRowClass != null) { final type = useRowClass.getField('type')!.toTypeValue(); diff --git a/drift_dev/lib/src/analyzer/data_class.dart b/drift_dev/lib/src/analyzer/data_class.dart index 3506f283..18abaa8d 100644 --- a/drift_dev/lib/src/analyzer/data_class.dart +++ b/drift_dev/lib/src/analyzer/data_class.dart @@ -3,6 +3,7 @@ import 'package:analyzer/dart/element/element.dart'; import 'package:analyzer/dart/element/type.dart'; import 'package:drift_dev/src/analyzer/dart/parser.dart'; import 'package:drift_dev/src/analyzer/errors.dart'; +import 'package:drift_dev/src/utils/type_utils.dart'; String dataClassNameForClassName(String tableName) { // This implementation is very primitive at the moment. The basic idea is @@ -21,19 +22,53 @@ String dataClassNameForClassName(String tableName) { return '${tableName}Data'; } -String? parseCustomParentClass( - DartObject dataClassName, ClassElement element, MoorDartParser base) { +String? parseCustomParentClass(String dartTypeName, DartObject dataClassName, + ClassElement element, MoorDartParser base) { final extending = dataClassName.getField('extending'); if (extending != null && !extending.isNull) { final extendingType = extending.toTypeValue(); if (extendingType is InterfaceType) { + final superType = extendingType.allSupertypes + .any((type) => isFromMoor(type) && type.element.name == 'DataClass'); + if (!superType) { + base.step.reportError( + ErrorInDartCode( + message: 'Parameter `extending` in @DataClassName must be subtype ' + 'of DataClass', + affectedElement: element, + ), + ); + return null; + } + + if (extendingType.typeArguments.length > 1) { + base.step.reportError( + ErrorInDartCode( + message: 'Parameter `extending` in @DataClassName must have zero or' + ' one type parameter', + affectedElement: element, + ), + ); + return null; + } + final className = extendingType.element.name; if (extendingType.typeArguments.length == 1) { final genericType = extendingType.typeArguments[0].element?.name; - if (genericType == 'dynamic') { - return '$className'; + if (genericType == 'Object') { + return '$className<$dartTypeName>'; + } else { + base.step.reportError( + ErrorInDartCode( + message: 'Parameter `extending` in @DataClassName can only have ' + '`Object` as type parameter: `YourType`', + affectedElement: element, + ), + ); + return null; } } + return className; } else { base.step.reportError( diff --git a/drift_dev/lib/src/writer/tables/data_class_writer.dart b/drift_dev/lib/src/writer/tables/data_class_writer.dart index 92a5d4fc..ba830521 100644 --- a/drift_dev/lib/src/writer/tables/data_class_writer.dart +++ b/drift_dev/lib/src/writer/tables/data_class_writer.dart @@ -24,9 +24,7 @@ class DataClassWriter { : 'driftRuntimeOptions'; void write() { - final customParent = table.customParentClass - ?.replaceFirst('', '<${table.dartTypeName}>'); - final parentClass = customParent ?? 'DataClass'; + final parentClass = table.customParentClass ?? 'DataClass'; _buffer.write('class ${table.dartTypeName} extends $parentClass '); if (isInsertable) {