mirror of https://github.com/AMT-Cheif/drift.git
Merge pull request #1492 from westito/generate_tocompanion
Add 'toCompanion' generator for custom row classes
This commit is contained in:
commit
38a8ad136f
|
@ -155,9 +155,17 @@ class UseRowClass {
|
|||
/// used to map database rows to the desired row class.
|
||||
final String constructor;
|
||||
|
||||
/// Generate a `toInsertable()` extension function for [type] mapping all
|
||||
/// fields to an insertable object.
|
||||
///
|
||||
/// This can be useful when a custom data class should be used for inserts or
|
||||
/// updates.
|
||||
final bool generateInsertable;
|
||||
|
||||
/// Customize the class used by drift to hold an instance of an annotated
|
||||
/// table.
|
||||
///
|
||||
/// For details, see the overall documentation on [UseRowClass].
|
||||
const UseRowClass(this.type, {this.constructor = ''});
|
||||
const UseRowClass(this.type,
|
||||
{this.constructor = '', this.generateInsertable = false});
|
||||
}
|
||||
|
|
|
@ -58,7 +58,7 @@ class SharedTodos extends Table {
|
|||
|
||||
const _uuid = Uuid();
|
||||
|
||||
@UseRowClass(CustomRowClass, constructor: 'map')
|
||||
@UseRowClass(CustomRowClass, constructor: 'map', generateInsertable: true)
|
||||
class TableWithoutPK extends Table {
|
||||
IntColumn get notReallyAnId => integer()();
|
||||
RealColumn get someFloat => real()();
|
||||
|
@ -67,13 +67,15 @@ class TableWithoutPK extends Table {
|
|||
text().map(const CustomConverter()).clientDefault(_uuid.v4)();
|
||||
}
|
||||
|
||||
class CustomRowClass implements Insertable<CustomRowClass> {
|
||||
class CustomRowClass {
|
||||
final int notReallyAnId;
|
||||
final double anotherName;
|
||||
final MyCustomObject custom;
|
||||
|
||||
final String? notFromDb;
|
||||
|
||||
double get someFloat => anotherName;
|
||||
|
||||
CustomRowClass._(
|
||||
this.notReallyAnId, this.anotherName, this.custom, this.notFromDb);
|
||||
|
||||
|
@ -81,15 +83,6 @@ class CustomRowClass implements Insertable<CustomRowClass> {
|
|||
{required MyCustomObject custom, String? notFromDb}) {
|
||||
return CustomRowClass._(notReallyAnId, someFloat, custom, notFromDb);
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, Expression> toColumns(bool nullToAbsent) {
|
||||
return TableWithoutPKCompanion(
|
||||
notReallyAnId: Value(notReallyAnId),
|
||||
someFloat: Value(anotherName),
|
||||
custom: Value(custom),
|
||||
).toColumns(nullToAbsent);
|
||||
}
|
||||
}
|
||||
|
||||
class PureDefaults extends Table {
|
||||
|
|
|
@ -1054,6 +1054,27 @@ class TableWithoutPKCompanion extends UpdateCompanion<CustomRowClass> {
|
|||
}
|
||||
}
|
||||
|
||||
class _$CustomRowClassInsertable implements Insertable<CustomRowClass> {
|
||||
CustomRowClass _object;
|
||||
|
||||
_$CustomRowClassInsertable(this._object);
|
||||
|
||||
@override
|
||||
Map<String, Expression> toColumns(bool nullToAbsent) {
|
||||
return TableWithoutPKCompanion(
|
||||
notReallyAnId: Value(_object.notReallyAnId),
|
||||
someFloat: Value(_object.someFloat),
|
||||
custom: Value(_object.custom),
|
||||
).toColumns(false);
|
||||
}
|
||||
}
|
||||
|
||||
extension CustomRowClassToInsertable on CustomRowClass {
|
||||
_$CustomRowClassInsertable toInsertable() {
|
||||
return _$CustomRowClassInsertable(this);
|
||||
}
|
||||
}
|
||||
|
||||
class $TableWithoutPKTable extends TableWithoutPK
|
||||
with TableInfo<$TableWithoutPKTable, CustomRowClass> {
|
||||
final GeneratedDatabase _db;
|
||||
|
|
|
@ -31,7 +31,8 @@ void main() {
|
|||
test('can insert floating point values', () async {
|
||||
// regression test for https://github.com/simolus3/moor/issues/30
|
||||
await db.into(db.tableWithoutPK).insert(
|
||||
CustomRowClass.map(42, 3.1415, custom: MyCustomObject('custom')));
|
||||
CustomRowClass.map(42, 3.1415, custom: MyCustomObject('custom'))
|
||||
.toInsertable());
|
||||
|
||||
verify(executor.runInsert(
|
||||
'INSERT INTO table_without_p_k '
|
||||
|
|
|
@ -15,8 +15,12 @@ class FoundDartClass {
|
|||
FoundDartClass(this.classElement, this.instantiation);
|
||||
}
|
||||
|
||||
ExistingRowClass? validateExistingClass(Iterable<MoorColumn> columns,
|
||||
FoundDartClass dartClass, String constructor, ErrorSink errors) {
|
||||
ExistingRowClass? validateExistingClass(
|
||||
Iterable<MoorColumn> columns,
|
||||
FoundDartClass dartClass,
|
||||
String constructor,
|
||||
bool generateInsertable,
|
||||
ErrorSink errors) {
|
||||
final desiredClass = dartClass.classElement;
|
||||
ConstructorElement? ctor;
|
||||
|
||||
|
@ -52,8 +56,22 @@ ExistingRowClass? validateExistingClass(Iterable<MoorColumn> columns,
|
|||
for (final parameter in ctor.parameters) {
|
||||
final column = unmatchedColumnsByName.remove(parameter.name);
|
||||
if (column != null) {
|
||||
columnsToParameter[column] = parameter;
|
||||
_checkType(parameter, column, errors);
|
||||
final matchField = !generateInsertable ||
|
||||
dartClass.classElement.fields
|
||||
.any((field) => field.name == parameter.name);
|
||||
if (matchField) {
|
||||
columnsToParameter[column] = parameter;
|
||||
_checkType(parameter, column, errors);
|
||||
} else {
|
||||
final error = ErrorInDartCode(
|
||||
affectedElement: parameter,
|
||||
severity: Severity.criticalError,
|
||||
message: 'Constructor parameter ${parameter.name} has no matching '
|
||||
'field. When "generateInsertable" enabled, all constructor '
|
||||
'parameter must have a matching field. Alternatively, you can '
|
||||
'declare a getter field.');
|
||||
throw Exception(error);
|
||||
}
|
||||
} else if (!parameter.isOptional) {
|
||||
errors.report(ErrorInDartCode(
|
||||
affectedElement: parameter,
|
||||
|
@ -63,7 +81,8 @@ ExistingRowClass? validateExistingClass(Iterable<MoorColumn> columns,
|
|||
}
|
||||
}
|
||||
|
||||
return ExistingRowClass(desiredClass, ctor, columnsToParameter,
|
||||
return ExistingRowClass(
|
||||
desiredClass, ctor, columnsToParameter, generateInsertable,
|
||||
typeInstantiation: dartClass.instantiation ?? const []);
|
||||
}
|
||||
|
||||
|
|
|
@ -70,6 +70,7 @@ class TableParser {
|
|||
String name;
|
||||
FoundDartClass? existingClass;
|
||||
String? constructorInExistingClass;
|
||||
bool? generateInsertable;
|
||||
|
||||
if (dataClassName != null) {
|
||||
name = dataClassName.getField('name')!.toStringValue()!;
|
||||
|
@ -81,6 +82,8 @@ class TableParser {
|
|||
final type = useRowClass.getField('type')!.toTypeValue();
|
||||
constructorInExistingClass =
|
||||
useRowClass.getField('constructor')!.toStringValue()!;
|
||||
generateInsertable =
|
||||
useRowClass.getField('generateInsertable')!.toBoolValue()!;
|
||||
|
||||
if (type is InterfaceType) {
|
||||
existingClass = FoundDartClass(type.element, type.typeArguments);
|
||||
|
@ -96,7 +99,7 @@ class TableParser {
|
|||
final verified = existingClass == null
|
||||
? null
|
||||
: validateExistingClass(columns, existingClass,
|
||||
constructorInExistingClass!, base.step.errors);
|
||||
constructorInExistingClass!, generateInsertable!, base.step.errors);
|
||||
return _DataClassInformation(name, verified);
|
||||
}
|
||||
|
||||
|
|
|
@ -181,7 +181,7 @@ class CreateTableReader {
|
|||
));
|
||||
} else {
|
||||
existingRowClass = validateExistingClass(
|
||||
foundColumns.values, clazz, '', step.errors);
|
||||
foundColumns.values, clazz, '', false, step.errors);
|
||||
dataClassName = existingRowClass?.targetClass.name;
|
||||
}
|
||||
} else if (overriddenNames.contains('/')) {
|
||||
|
|
|
@ -64,7 +64,7 @@ class ViewAnalyzer extends BaseAnalyzer {
|
|||
));
|
||||
} else {
|
||||
final rowClass = view.existingRowClass =
|
||||
validateExistingClass(columns, clazz, '', step.errors);
|
||||
validateExistingClass(columns, clazz, '', false, step.errors);
|
||||
final newName = rowClass?.targetClass.name;
|
||||
if (newName != null) {
|
||||
view.dartTypeName = rowClass!.targetClass.name;
|
||||
|
|
|
@ -69,7 +69,11 @@ class ExistingRowClass {
|
|||
final ConstructorElement constructor;
|
||||
final Map<MoorColumn, ParameterElement> mapping;
|
||||
|
||||
ExistingRowClass(this.targetClass, this.constructor, this.mapping,
|
||||
/// Generate toCompanion for data class
|
||||
final bool generateInsertable;
|
||||
|
||||
ExistingRowClass(
|
||||
this.targetClass, this.constructor, this.mapping, this.generateInsertable,
|
||||
{this.typeInstantiation = const []});
|
||||
|
||||
String dartType([GenerationOptions options = const GenerationOptions()]) {
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import 'package:collection/collection.dart';
|
||||
import 'package:drift_dev/moor_generator.dart';
|
||||
import 'package:drift_dev/src/utils/string_escaper.dart';
|
||||
import 'package:drift_dev/src/writer/utils/override_toString.dart';
|
||||
|
@ -28,6 +29,10 @@ class UpdateCompanionWriter {
|
|||
_writeToString();
|
||||
|
||||
_buffer.write('}\n');
|
||||
|
||||
if (table.existingRowClass?.generateInsertable ?? false) {
|
||||
_writeToCompanionExtension();
|
||||
}
|
||||
}
|
||||
|
||||
void _writeFields() {
|
||||
|
@ -211,4 +216,39 @@ class UpdateCompanionWriter {
|
|||
_buffer,
|
||||
);
|
||||
}
|
||||
|
||||
void _writeToCompanionExtension() {
|
||||
final info = table.existingRowClass;
|
||||
if (info == null) return;
|
||||
|
||||
final companionName = table.getNameForCompanionClass(scope.options);
|
||||
final className = table.dartTypeName;
|
||||
final insertableClass = '_\$${className}Insertable';
|
||||
|
||||
_buffer.write('class $insertableClass implements '
|
||||
'Insertable<$className> {\n'
|
||||
'$className _object;\n\n'
|
||||
'$insertableClass(this._object);\n\n'
|
||||
'@override\n'
|
||||
'Map<String, Expression> toColumns(bool nullToAbsent) {\n'
|
||||
'return $companionName(\n');
|
||||
|
||||
for (final field in info.mapping.values) {
|
||||
final column =
|
||||
table.columns.firstWhereOrNull((e) => e.dartGetterName == field.name);
|
||||
|
||||
if (column != null) {
|
||||
final dartName = column.dartGetterName;
|
||||
_buffer.write('$dartName: Value (_object.$dartName),\n');
|
||||
}
|
||||
}
|
||||
|
||||
_buffer
|
||||
..write(').toColumns(false);\n}\n}\n\n')
|
||||
..write('extension ${table.dartTypeName}ToInsertable '
|
||||
'on ${table.dartTypeName} {')
|
||||
..write('$insertableClass toInsertable() {\n')
|
||||
..write('return _\$${className}Insertable(this);\n')
|
||||
..write('}\n}\n');
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue