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 /// corresponding to the enum's index. Note that this can invalidate your data
/// if you add another value to the enum class. /// if you add another value to the enum class.
@protected @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. /// Use this as the body of a getter to declare a column that holds strings.
/// Example (inside the body of a table class): /// Example (inside the body of a table class):
@ -149,6 +149,13 @@ abstract class Table extends HasResultSet {
@protected @protected
ColumnBuilder<String> text() => _isGenerated(); 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. /// Use this as the body of a getter to declare a column that holds bools.
/// Example (inside the body of a table class): /// Example (inside the body of a table class):
/// ``` /// ```

View File

@ -1,4 +1,5 @@
import 'dart:typed_data'; import 'dart:typed_data';
import '../../dsl/dsl.dart'; import '../../dsl/dsl.dart';
import '../data_class.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 /// A type converter automatically mapping `null` values to `null` in both
/// directions. /// directions.
/// ///

View File

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

View File

@ -54,6 +54,7 @@ class DriftTableResolver extends LocalElementResolver<DiscoveredDriftTable> {
AnnotatedDartCode? defaultArgument; AnnotatedDartCode? defaultArgument;
final typeName = column.definition?.typeName; final typeName = column.definition?.typeName;
final enumMatch = final enumMatch =
typeName != null ? _enumRegex.firstMatch(typeName) : null; typeName != null ? _enumRegex.firstMatch(typeName) : null;
if (enumMatch != null) { if (enumMatch != null) {
@ -72,6 +73,9 @@ class DriftTableResolver extends LocalElementResolver<DiscoveredDriftTable> {
(msg) => reportError( (msg) => reportError(
DriftAnalysisError.inDriftFile(column.definition ?? stmt, msg)), DriftAnalysisError.inDriftFile(column.definition ?? stmt, msg)),
dartClass.classElement.thisType, 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( AppliedTypeConverter? readTypeConverter(
LibraryElement library, LibraryElement library,
Expression dartExpression, Expression dartExpression,
@ -223,32 +228,39 @@ AppliedTypeConverter? readTypeConverter(
AppliedTypeConverter readEnumConverter( AppliedTypeConverter readEnumConverter(
void Function(String) reportError, void Function(String) reportError,
DartType enumType, DartType dartEnumType,
EnumType columnEnumType,
) { ) {
if (enumType is! InterfaceType) { if (dartEnumType is! InterfaceType) {
reportError('Not a class: `$enumType`'); reportError('Not a class: `$dartEnumType`');
} }
final creatingClass = enumType.element; final creatingClass = dartEnumType.element;
if (creatingClass is! EnumElement) { if (creatingClass is! EnumElement) {
reportError('Not an enum: `${creatingClass!.displayName}`'); reportError('Not an enum: `${creatingClass!.displayName}`');
} }
// `const EnumIndexConverter<EnumType>(EnumType.values)` // `const EnumIndexConverter<EnumType>(EnumType.values)`
// or
// `const EnumNameConverter<EnumType>(EnumType.values)`
final expression = AnnotatedDartCode.build((builder) { final expression = AnnotatedDartCode.build((builder) {
builder.addText('const ');
if (columnEnumType == EnumType.intEnum) {
builder.addSymbol('EnumIndexConverter', AnnotatedDartCode.drift);
} else {
builder.addSymbol('EnumNameConverter', AnnotatedDartCode.drift);
}
builder builder
..addText('const ')
..addSymbol('EnumIndexConverter', AnnotatedDartCode.drift)
..addText('<') ..addText('<')
..addDartType(enumType) ..addDartType(dartEnumType)
..addText('>(') ..addText('>(')
..addDartType(enumType) ..addDartType(dartEnumType)
..addText('.values)'); ..addText('.values)');
}); });
return AppliedTypeConverter( return AppliedTypeConverter(
expression: expression, expression: expression,
dartType: enumType, dartType: dartEnumType,
jsonType: null, jsonType: null,
sqlType: DriftSqlType.int, sqlType: DriftSqlType.int,
dartTypeIsNullable: false, dartTypeIsNullable: false,