Simplify generation of enum type converters

This commit is contained in:
Simon Binder 2020-05-13 20:16:20 +02:00
parent 25ee06ab36
commit 7b9fa3d9ed
No known key found for this signature in database
GPG Key ID: 7891917E4147B8C0
6 changed files with 28 additions and 104 deletions

View File

@ -69,9 +69,9 @@ Future<void> writeShoppingCart(CartWithItems entry) {
.go();
// And write the new ones
await into(shoppingCartEntries).insertAll([
for (var item in entry.items) ShoppingCartEntry(shoppingCart: cart.id, item: item.id)
]);
for (final item in entry.items) {
await into(shoppingCartEntries).insert(ShoppingCartEntry(shoppingCart: cart.id, item: item.id));
}
});
}
```

View File

@ -20,3 +20,23 @@ abstract class TypeConverter<D, S> {
/// nullable.
D mapToDart(S fromDb);
}
/// Implementation for an enum to int converter that uses the index of the enum
/// as the value stored in the database.
class EnumIndexConverter<T> extends TypeConverter<T, int> {
/// All values of the enum.
final List<T> values;
/// Constant default constructor.
const EnumIndexConverter(this.values);
@override
T mapToDart(int fromDb) {
return fromDb == null ? null : values[fromDb];
}
@override
int mapToSql(T value) {
return (value as dynamic)?.index as int;
}
}

View File

@ -7,19 +7,6 @@ part of 'todos.dart';
// **************************************************************************
// ignore_for_file: unnecessary_brace_in_string_interps, unnecessary_this
class _$GeneratedConverter$0 extends TypeConverter<CategoryPriority, int> {
const _$GeneratedConverter$0();
@override
CategoryPriority mapToDart(int fromDb) {
return fromDb == null ? null : CategoryPriority.values[fromDb];
}
@override
int mapToSql(CategoryPriority value) {
return value?.index;
}
}
class TodoEntry extends DataClass implements Insertable<TodoEntry> {
final int id;
final String title;
@ -573,7 +560,7 @@ class $CategoriesTable extends Categories
}
static TypeConverter<CategoryPriority, int> $converter0 =
const _$GeneratedConverter$0();
const EnumIndexConverter<CategoryPriority>(CategoryPriority.values);
}
class User extends DataClass implements Insertable<User> {

View File

@ -20,7 +20,7 @@ class UsedTypeConverter {
/// The expression that will construct the type converter at runtime. The
/// type converter constructed will map a [mappedType] to the [sqlType] and
/// vice-versa.
String expression;
final String expression;
/// The type that will be present at runtime.
final DartType mappedType;
@ -54,8 +54,10 @@ class UsedTypeConverter {
throw InvalidTypeForEnumConverterException('Not an enum', enumType);
}
final className = creatingClass.name;
return UsedTypeConverter(
expression: 'bogus expression for enum value',
expression: 'const EnumIndexConverter<$className>($className.values)',
mappedType: enumType,
sqlType: ColumnType.integer,
isForEnum: true,

View File

@ -1,4 +1,3 @@
import 'package:analyzer/dart/element/type.dart';
import 'package:moor/moor.dart';
// ignore: implementation_imports
import 'package:moor/src/runtime/executor/stream_queries.dart';
@ -17,44 +16,6 @@ class DatabaseWriter {
DatabaseWriter(this.db, this.scope);
void write() {
// Write generated convertesr
final enumConverters =
db.tables.expand((t) => t.converters).where((c) => c.isForEnum);
final generatedConvertersForType = <DartType, String>{};
var amountOfGeneratedConverters = 0;
for (final converter in enumConverters) {
String classForConverter;
if (generatedConvertersForType.containsKey(converter.mappedType)) {
classForConverter = generatedConvertersForType[converter.mappedType];
} else {
final id = amountOfGeneratedConverters++;
classForConverter = '_\$GeneratedConverter\$$id';
final buffer = scope.leaf();
final dartType = converter.mappedType.getDisplayString();
final superClass = converter.displayNameOfConverter;
buffer
..writeln('class $classForConverter extends $superClass {')
..writeln('const $classForConverter();')
..writeln('@override')
..writeln('$dartType mapToDart(int fromDb) {')
..writeln('return fromDb == null ? null : $dartType.values[fromDb];')
..writeln('}')
..writeln('@override')
..writeln('int mapToSql($dartType value) {')
..writeln('return value?.index;')
..writeln('}')
..writeln('}');
generatedConvertersForType[converter.mappedType] = classForConverter;
}
converter.expression = 'const $classForConverter()';
}
// Write referenced tables
for (final table in db.tables) {
TableWriter(table, scope.child()).writeInto();

View File

@ -1,46 +0,0 @@
import 'package:moor_generator/src/analyzer/options.dart';
import 'package:moor_generator/src/analyzer/runner/results.dart';
import 'package:moor_generator/src/writer/database_writer.dart';
import 'package:moor_generator/src/writer/writer.dart';
import 'package:test/test.dart';
import '../analyzer/utils.dart';
void main() {
test('does not generate multiple converters for the same enum', () async {
final state = TestState.withContent({
'foo|lib/a.dart': '''
import 'package:moor/moor.dart';
enum MyEnum { foo, bar, baz }
class TableA extends Table {
IntColumn get col => intEnum<MyEnum>()();
}
class TableB extends Table {
IntColumn get another => intEnum<MyEnum>()();
}
@UseMoor(tables: [TableA, TableB])
class Database {
}
''',
});
final file = await state.analyze('package:foo/a.dart');
final db = (file.currentResult as ParsedDartFile).declaredDatabases.single;
final writer = Writer(const MoorOptions());
DatabaseWriter(db, writer.child()).write();
expect(
writer.writeGenerated(),
allOf(
contains(r'_$GeneratedConverter$0'),
isNot(contains(r'_$GeneratedConverter$1')),
),
);
});
}