Fix nnbd generation around type converters (#968)

This commit is contained in:
Simon Binder 2020-12-14 15:13:59 +01:00
parent a749f38e2b
commit 5db10342b0
No known key found for this signature in database
GPG Key ID: 7891917E4147B8C0
6 changed files with 32 additions and 15 deletions

View File

@ -289,8 +289,8 @@ class ConfigTable extends Table with TableInfo<ConfigTable, Config> {
return ConfigTable(_db, alias); return ConfigTable(_db, alias);
} }
static TypeConverter<SyncType?, int?> $converter0 = const SyncTypeConverter(); static TypeConverter<SyncType, int> $converter0 = const SyncTypeConverter();
static TypeConverter<SyncType?, int?> $converter1 = static TypeConverter<SyncType?, int> $converter1 =
const EnumIndexConverter<SyncType>(SyncType.values); const EnumIndexConverter<SyncType>(SyncType.values);
@override @override
bool get dontWriteConstraints => true; bool get dontWriteConstraints => true;
@ -1614,7 +1614,7 @@ abstract class _$CustomTablesDb extends GeneratedDatabase {
readsFrom: {config}).map(config.mapFromRow); readsFrom: {config}).map(config.mapFromRow);
} }
Selectable<String> typeConverterVar(SyncType? var1, List<SyncType?> var2) { Selectable<String> typeConverterVar(SyncType var1, List<SyncType?> var2) {
var $arrayStartIndex = 2; var $arrayStartIndex = 2;
final expandedvar2 = $expandVar($arrayStartIndex, var2.length); final expandedvar2 = $expandVar($arrayStartIndex, var2.length);
$arrayStartIndex += var2.length; $arrayStartIndex += var2.length;
@ -1623,7 +1623,7 @@ abstract class _$CustomTablesDb extends GeneratedDatabase {
variables: [ variables: [
Variable<int>(ConfigTable.$converter0.mapToSql(var1)!), Variable<int>(ConfigTable.$converter0.mapToSql(var1)!),
for (var $ in var2) for (var $ in var2)
Variable<int>(ConfigTable.$converter1.mapToSql($)!) Variable<int?>(ConfigTable.$converter1.mapToSql($)!)
], ],
readsFrom: { readsFrom: {
config config

View File

@ -558,7 +558,7 @@ class $CategoriesTable extends Categories
return $CategoriesTable(_db, alias); return $CategoriesTable(_db, alias);
} }
static TypeConverter<CategoryPriority, int?> $converter0 = static TypeConverter<CategoryPriority, int> $converter0 =
const EnumIndexConverter<CategoryPriority>(CategoryPriority.values); const EnumIndexConverter<CategoryPriority>(CategoryPriority.values);
} }
@ -1316,7 +1316,7 @@ class $TableWithoutPKTable extends TableWithoutPK
return $TableWithoutPKTable(_db, alias); return $TableWithoutPKTable(_db, alias);
} }
static TypeConverter<MyCustomObject, String?> $converter0 = static TypeConverter<MyCustomObject, String> $converter0 =
const CustomConverter(); const CustomConverter();
} }

View File

@ -11,6 +11,7 @@ import 'package:moor_generator/src/model/used_type_converter.dart';
import 'package:moor_generator/src/utils/names.dart'; import 'package:moor_generator/src/utils/names.dart';
import 'package:moor_generator/src/utils/string_escaper.dart'; import 'package:moor_generator/src/utils/string_escaper.dart';
import 'package:moor_generator/src/utils/type_converter_hint.dart'; import 'package:moor_generator/src/utils/type_converter_hint.dart';
import 'package:moor_generator/src/utils/type_utils.dart';
import 'package:recase/recase.dart'; import 'package:recase/recase.dart';
import 'package:sqlparser/sqlparser.dart'; import 'package:sqlparser/sqlparser.dart';
@ -217,8 +218,11 @@ class CreateTableReader {
} }
final interfaceType = type as InterfaceType; final interfaceType = type as InterfaceType;
// TypeConverter declares a "D mapToDart(S fromDb);". We need to know D final asTypeConverter = interfaceType.allSupertypes.firstWhere(
final typeInDart = interfaceType.getMethod('mapToDart').returnType; (type) => isFromMoor(type) && type.element.name == 'TypeConverter');
// TypeConverter<D, S>, where D is the type in Dart
final typeInDart = asTypeConverter.typeArguments.first;
return UsedTypeConverter( return UsedTypeConverter(
expression: code, mappedType: typeInDart, sqlType: sqlType); expression: code, mappedType: typeInDart, sqlType: sqlType);

View File

@ -17,6 +17,11 @@ abstract class HasType {
} }
extension OperationOnTypes on HasType { extension OperationOnTypes on HasType {
/// Whether this type is nullable in Dart
bool get nullableInDart {
return nullable || typeConverter?.hasNullableDartType == true;
}
/// the Dart type of this column that can be handled by moors type mapping. /// the Dart type of this column that can be handled by moors type mapping.
/// Basically the same as [dartTypeCode], minus custom types and nullability. /// Basically the same as [dartTypeCode], minus custom types and nullability.
String get variableTypeName => dartTypeNames[type]; String get variableTypeName => dartTypeNames[type];
@ -30,7 +35,7 @@ extension OperationOnTypes on HasType {
/// This is the same as [dartTypeCode] but without custom types. /// This is the same as [dartTypeCode] but without custom types.
String variableTypeCode( String variableTypeCode(
[GenerationOptions options = const GenerationOptions()]) { [GenerationOptions options = const GenerationOptions()]) {
final hasSuffix = nullable && options.nnbd; final hasSuffix = nullableInDart && options.nnbd;
return hasSuffix ? '$variableTypeName?' : variableTypeName; return hasSuffix ? '$variableTypeName?' : variableTypeName;
} }
@ -39,7 +44,10 @@ extension OperationOnTypes on HasType {
/// [int]. /// [int].
String dartTypeCode([GenerationOptions options = const GenerationOptions()]) { String dartTypeCode([GenerationOptions options = const GenerationOptions()]) {
if (typeConverter != null) { if (typeConverter != null) {
return typeConverter.mappedType?.codeString(options); final needsSuffix = nullable && !typeConverter.hasNullableDartType;
final baseType = typeConverter.mappedType.codeString(options);
return needsSuffix ? '$baseType?' : baseType;
} }
return variableTypeCode(options); return variableTypeCode(options);

View File

@ -37,6 +37,9 @@ class UsedTypeConverter {
@required this.sqlType, @required this.sqlType,
}); });
bool get hasNullableDartType =>
mappedType.nullabilitySuffix == NullabilitySuffix.question;
factory UsedTypeConverter.forEnumColumn(DartType enumType, bool nullable) { factory UsedTypeConverter.forEnumColumn(DartType enumType, bool nullable) {
if (enumType.element is! ClassElement) { if (enumType.element is! ClassElement) {
throw InvalidTypeForEnumConverterException('Not a class', enumType); throw InvalidTypeForEnumConverterException('Not a class', enumType);
@ -61,7 +64,7 @@ class UsedTypeConverter {
/// A suitable typename to store an instance of the type converter used here. /// A suitable typename to store an instance of the type converter used here.
String converterNameInCode(GenerationOptions options) { String converterNameInCode(GenerationOptions options) {
final sqlDartType = options.nullableType(dartTypeNames[sqlType]); final sqlDartType = dartTypeNames[sqlType];
return 'TypeConverter<${mappedType.codeString(options)}, $sqlDartType>'; return 'TypeConverter<${mappedType.codeString(options)}, $sqlDartType>';
} }
} }

View File

@ -176,15 +176,17 @@ class DataClassWriter {
for (var i = 0; i < table.columns.length; i++) { for (var i = 0; i < table.columns.length; i++) {
final column = table.columns[i]; final column = table.columns[i];
final last = i == table.columns.length - 1; final last = i == table.columns.length - 1;
final isNullable = column.nullableInDart;
final typeName = column.dartTypeCode(scope.generationOptions); final typeName = column.dartTypeCode(scope.generationOptions);
if (wrapNullableInValue && column.nullable) { if (wrapNullableInValue && isNullable) {
_buffer _buffer
..write('Value<$typeName> ${column.dartGetterName} ') ..write('Value<$typeName> ${column.dartGetterName} ')
..write('= const Value.absent()'); ..write('= const Value.absent()');
} else if (!column.nullable && scope.generationOptions.nnbd) { } else if (!isNullable && scope.generationOptions.nnbd) {
// We always write nullable types in the copyWith constructor, since all // We always use nullable parameters in copyWith, since all parameters
// parameters are optional. // are optional. The !isNullable check is there to avoid a duplicate
// question mark in the type name.
_buffer.write('$typeName? ${column.dartGetterName}'); _buffer.write('$typeName? ${column.dartGetterName}');
} else { } else {
_buffer.write('$typeName ${column.dartGetterName}'); _buffer.write('$typeName ${column.dartGetterName}');