diff --git a/drift_dev/lib/src/writer/tables/data_class_writer.dart b/drift_dev/lib/src/writer/tables/data_class_writer.dart index ce6732fc..cc7769bf 100644 --- a/drift_dev/lib/src/writer/tables/data_class_writer.dart +++ b/drift_dev/lib/src/writer/tables/data_class_writer.dart @@ -48,11 +48,15 @@ class DataClassWriter { _buffer.write('class ${table.nameOfRowClass} extends $parentClass '); if (isInsertable) { - // The data class is only an insertable if we can actually insert rows - // into the target entity. - final type = _emitter.dartCode(_emitter.writer.rowType(table)); + if (scope.options.writeToColumnsMixins) { + _buffer.writeln('with ${table.entityInfoName}ToColumns {'); + } else { + // The data class is only an insertable if we can actually insert rows + // into the target entity. + final type = _emitter.dartCode(_emitter.writer.rowType(table)); - _buffer.writeln('implements ${_emitter.drift('Insertable')}<$type> {'); + _buffer.writeln('implements ${_emitter.drift('Insertable')}<$type> {'); + } } else { _buffer.writeln('{'); } @@ -88,7 +92,9 @@ class DataClassWriter { ..write('});'); if (isInsertable) { - _writeToColumnsOverride(); + if (!scope.options.writeToColumnsMixins) { + _writeToColumnsOverride(); + } if (scope.options.dataClassToCompanions) { _writeToCompanion(); } diff --git a/drift_dev/lib/src/writer/tables/table_writer.dart b/drift_dev/lib/src/writer/tables/table_writer.dart index 5c5558ec..54d1910b 100644 --- a/drift_dev/lib/src/writer/tables/table_writer.dart +++ b/drift_dev/lib/src/writer/tables/table_writer.dart @@ -265,11 +265,17 @@ class TableWriter extends TableOrViewWriter { scope.generationOptions.isGeneratingForSchema; void writeInto() { + emitter = scope.leaf(); + writeDataClass(); writeTableInfoClass(); } void writeDataClass() { + if (scope.options.writeToColumnsMixins) { + writeToColumnsMixin(); + } + if (scope.generationOptions.writeDataClasses) { final existing = table.existingRowClass; if (existing != null) { @@ -277,7 +283,7 @@ class TableWriter extends TableOrViewWriter { // user. However, if the existing row type is a record, it is helpful // to generate a typedef for it. if (existing.isRecord) { - scope.leaf() + emitter ..write('typedef ${table.nameOfRowClass} = ') ..writeDart(AnnotatedDartCode.type(existing.targetType)) ..write(';'); @@ -293,8 +299,6 @@ class TableWriter extends TableOrViewWriter { } void writeTableInfoClass() { - emitter = scope.leaf(); - if (!scope.generationOptions.writeDataClasses) { // Write a small table header without data class buffer @@ -362,6 +366,81 @@ class TableWriter extends TableOrViewWriter { buffer.write('}'); } + void writeToColumnsMixin() { + buffer.write('mixin ${table.baseDartName}ToColumns '); + + final type = emitter.dartCode(emitter.writer.rowType(table)); + buffer.writeln('implements ${emitter.drift('Insertable')}<$type> {'); + + for (final column in table.columns) { + if (column.documentationComment != null) { + buffer.write('${column.documentationComment}\n'); + } + final typeName = emitter.dartCode(emitter.dartType(column)); + buffer.writeln('$typeName get ${column.nameInDart};'); + } + + _writeToColumnsOverride(); + buffer.write('}'); + } + + void _writeToColumnsOverride() { + final expression = emitter.drift('Expression'); + final variable = emitter.drift('Variable'); + + buffer + ..write('@override\nMap toColumns' + '(bool nullToAbsent) {\n') + ..write('final map = {};'); + + for (final column in table.columns) { + // Generated column - cannot be used for inserts or updates + if (column.isGenerated) continue; + + // We include all columns that are not null. If nullToAbsent is false, we + // also include null columns. When generating NNBD code, we can include + // non-nullable columns without an additional null check since we know + // the values aren't going to be null. + final needsNullCheck = column.nullableInDart; + final needsScope = needsNullCheck || column.typeConverter != null; + if (needsNullCheck) { + buffer.write('if (!nullToAbsent || ${column.nameInDart} != null)'); + } + if (needsScope) buffer.write('{'); + + final typeName = + emitter.dartCode(emitter.variableTypeCode(column, nullable: false)); + final mapSetter = 'map[${asDartLiteral(column.nameInSql)}] = ' + '$variable<$typeName>'; + + if (column.typeConverter != null) { + // apply type converter before writing the variable + final converter = column.typeConverter!; + + emitter + ..write('final converter = ') + ..writeDart(emitter.writer + .readConverter(converter, forNullable: column.nullable)) + ..writeln(';') + ..write(mapSetter) + ..write('(converter.toSql(${column.nameInDart})'); + buffer.write(');'); + } else { + // no type converter. Write variable directly + buffer + ..write(mapSetter) + ..write('(') + ..write(column.nameInDart) + ..write(');'); + } + + // This one closes the optional if from before. + if (needsScope) buffer.write('}'); + } + + buffer.write('return map; \n}\n'); + } + void _writeConvertersAsStaticFields() { for (final converter in table.appliedConverters) { final typeName = diff --git a/drift_dev/lib/src/writer/tables/update_companion_writer.dart b/drift_dev/lib/src/writer/tables/update_companion_writer.dart index 0c2f343c..4461d707 100644 --- a/drift_dev/lib/src/writer/tables/update_companion_writer.dart +++ b/drift_dev/lib/src/writer/tables/update_companion_writer.dart @@ -46,9 +46,6 @@ class UpdateCompanionWriter { if (table.existingRowClass?.generateInsertable ?? false) { _writeToCompanionExtension(); } - if (scope.options.writeToColumnsMixins) { - _writeToColumnsMixin(); - } } void _writeFields() { @@ -266,82 +263,4 @@ class UpdateCompanionWriter { ..write('return $insertableClass(this);\n') ..write('}\n}\n'); } - - void _writeToColumnsMixin() { - final info = table.existingRowClass; - if (info == null) return; - - _buffer.write('mixin ${table.baseDartName}ToColumns '); - - final type = _emitter.dartCode(_emitter.writer.rowType(table)); - _buffer.writeln('implements ${_emitter.drift('Insertable')}<$type> {'); - - for (final column in columns) { - if (column.documentationComment != null) { - _buffer.write('${column.documentationComment}\n'); - } - final typeName = _emitter.dartCode(_emitter.dartType(column)); - _buffer.writeln('$typeName get ${column.nameInDart};'); - } - - _writeTableToColumnsOverride(); - _buffer.write('}'); - } - - void _writeTableToColumnsOverride() { - final expression = _emitter.drift('Expression'); - final variable = _emitter.drift('Variable'); - - _buffer - ..write('@override\nMap toColumns' - '(bool nullToAbsent) {\n') - ..write('final map = {};'); - - for (final column in columns) { - // Generated column - cannot be used for inserts or updates - if (column.isGenerated) continue; - - // We include all columns that are not null. If nullToAbsent is false, we - // also include null columns. When generating NNBD code, we can include - // non-nullable columns without an additional null check since we know - // the values aren't going to be null. - final needsNullCheck = column.nullableInDart; - final needsScope = needsNullCheck || column.typeConverter != null; - if (needsNullCheck) { - _buffer.write('if (!nullToAbsent || ${column.nameInDart} != null)'); - } - if (needsScope) _buffer.write('{'); - - final typeName = - _emitter.dartCode(_emitter.variableTypeCode(column, nullable: false)); - final mapSetter = 'map[${asDartLiteral(column.nameInSql)}] = ' - '$variable<$typeName>'; - - if (column.typeConverter != null) { - // apply type converter before writing the variable - final converter = column.typeConverter!; - - _emitter - ..write('final converter = ') - ..writeDart(_emitter.writer - .readConverter(converter, forNullable: column.nullable)) - ..writeln(';') - ..write(mapSetter) - ..write('(converter.toSql(${column.nameInDart})'); - _buffer.write(');'); - } else { - // no type converter. Write variable directly - _buffer - ..write(mapSetter) - ..write('(') - ..write(column.nameInDart) - ..write(');'); - } - - // This one closes the optional if from before. - if (needsScope) _buffer.write('}'); - } - - _buffer.write('return map; \n}\n'); - } }