textEnum

This commit is contained in:
ValentinVignal 2022-11-26 21:51:13 +08:00
parent 0a5014a7b4
commit e8ee29bb18
No known key found for this signature in database
GPG Key ID: 040FFDADFB7EF05A
5 changed files with 80 additions and 16 deletions

View File

@ -139,7 +139,7 @@ abstract class Table extends HasResultSet {
/// corresponding to the enum's index. Note that this can invalidate your data
/// if you add another value to the enum class.
@protected
ColumnBuilder<int> intEnum<T>() => _isGenerated();
ColumnBuilder<int> intEnum<T extends Enum>() => _isGenerated();
/// Use this as the body of a getter to declare a column that holds strings.
/// Example (inside the body of a table class):
@ -149,6 +149,13 @@ abstract class Table extends HasResultSet {
@protected
ColumnBuilder<String> text() => _isGenerated();
/// Creates a column to store an `enum` class [T].
///
/// In the database, the column will be represented as text corresponding to
/// the name of the enum entries. Note that this can invalidate your data if
/// you rename the entries of the enum class.
ColumnBuilder<String> textEnum<T extends Enum>() => _isGenerated();
/// Use this as the body of a getter to declare a column that holds bools.
/// Example (inside the body of a table class):
/// ```

View File

@ -1,4 +1,5 @@
import 'dart:typed_data';
import '../../dsl/dsl.dart';
import '../data_class.dart';
@ -100,6 +101,26 @@ class EnumIndexConverter<T extends Enum> extends TypeConverter<T, int> {
}
}
/// Implementation for an enum to string converter that uses the name of the
/// enum as the value stored in the database.
class EnumNameConverter<T extends Enum> extends TypeConverter<T, String> {
/// All values of the enum.
final List<T> values;
/// Constant default constructor.
const EnumNameConverter(this.values);
@override
T fromSql(String fromDb) {
return values.byName(fromDb);
}
@override
String toSql(T value) {
return value.name;
}
}
/// A type converter automatically mapping `null` values to `null` in both
/// directions.
///

View File

@ -15,7 +15,8 @@ import 'table.dart';
const String _startInt = 'integer';
const String _startInt64 = 'int64';
const String _startEnum = 'intEnum';
const String _startIntEnum = 'intEnum';
const String _startTextEnum = 'textEnum';
const String _startString = 'text';
const String _startBool = 'boolean';
const String _startDateTime = 'dateTime';
@ -25,7 +26,8 @@ const String _startReal = 'real';
const Set<String> _starters = {
_startInt,
_startInt64,
_startEnum,
_startIntEnum,
_startTextEnum,
_startString,
_startBool,
_startDateTime,
@ -349,20 +351,37 @@ class ColumnParser {
);
}
if (foundStartMethod == _startEnum) {
if (foundStartMethod == _startIntEnum) {
if (converter != null) {
_resolver.reportError(DriftAnalysisError.forDartElement(
element,
'Using $_startEnum will apply a custom converter by default, '
'Using $_startIntEnum will apply a custom converter by default, '
"so you can't add an additional converter",
));
}
final enumType = remainingExpr.typeArgumentTypes![0];
final enumType = remainingExpr.typeArgumentTypes!.first;
converter = readEnumConverter(
(msg) => _resolver.reportError(DriftAnalysisError.inDartAst(element,
remainingExpr.typeArguments ?? remainingExpr.methodName, msg)),
enumType,
EnumType.intEnum,
);
} else if (foundStartMethod == _startTextEnum) {
if (converter != null) {
_resolver.reportError(DriftAnalysisError.forDartElement(
element,
'Using $_startTextEnum will apply a custom converter by default, '
"so you can't add an additional converter",
));
}
final enumType = remainingExpr.typeArgumentTypes!.first;
converter = readEnumConverter(
(msg) => _resolver.reportError(DriftAnalysisError.inDartAst(element,
remainingExpr.typeArguments ?? remainingExpr.methodName, msg)),
enumType,
EnumType.textEnum,
);
}
@ -427,7 +446,8 @@ class ColumnParser {
_startString: DriftSqlType.string,
_startInt: DriftSqlType.int,
_startInt64: DriftSqlType.bigInt,
_startEnum: DriftSqlType.int,
_startIntEnum: DriftSqlType.int,
_startTextEnum: DriftSqlType.string,
_startDateTime: DriftSqlType.dateTime,
_startBlob: DriftSqlType.blob,
_startReal: DriftSqlType.double,

View File

@ -54,6 +54,7 @@ class DriftTableResolver extends LocalElementResolver<DiscoveredDriftTable> {
AnnotatedDartCode? defaultArgument;
final typeName = column.definition?.typeName;
final enumMatch =
typeName != null ? _enumRegex.firstMatch(typeName) : null;
if (enumMatch != null) {
@ -72,6 +73,9 @@ class DriftTableResolver extends LocalElementResolver<DiscoveredDriftTable> {
(msg) => reportError(
DriftAnalysisError.inDriftFile(column.definition ?? stmt, msg)),
dartClass.classElement.thisType,
column.type.type == BasicType.int
? EnumType.intEnum
: EnumType.textEnum,
);
}
}

View File

@ -160,6 +160,11 @@ ExistingRowClass? validateExistingClass(
);
}
enum EnumType {
intEnum,
textEnum,
}
AppliedTypeConverter? readTypeConverter(
LibraryElement library,
Expression dartExpression,
@ -223,32 +228,39 @@ AppliedTypeConverter? readTypeConverter(
AppliedTypeConverter readEnumConverter(
void Function(String) reportError,
DartType enumType,
DartType dartEnumType,
EnumType columnEnumType,
) {
if (enumType is! InterfaceType) {
reportError('Not a class: `$enumType`');
if (dartEnumType is! InterfaceType) {
reportError('Not a class: `$dartEnumType`');
}
final creatingClass = enumType.element;
final creatingClass = dartEnumType.element;
if (creatingClass is! EnumElement) {
reportError('Not an enum: `${creatingClass!.displayName}`');
}
// `const EnumIndexConverter<EnumType>(EnumType.values)`
// or
// `const EnumNameConverter<EnumType>(EnumType.values)`
final expression = AnnotatedDartCode.build((builder) {
builder.addText('const ');
if (columnEnumType == EnumType.intEnum) {
builder.addSymbol('EnumIndexConverter', AnnotatedDartCode.drift);
} else {
builder.addSymbol('EnumNameConverter', AnnotatedDartCode.drift);
}
builder
..addText('const ')
..addSymbol('EnumIndexConverter', AnnotatedDartCode.drift)
..addText('<')
..addDartType(enumType)
..addDartType(dartEnumType)
..addText('>(')
..addDartType(enumType)
..addDartType(dartEnumType)
..addText('.values)');
});
return AppliedTypeConverter(
expression: expression,
dartType: enumType,
dartType: dartEnumType,
jsonType: null,
sqlType: DriftSqlType.int,
dartTypeIsNullable: false,