diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c7fa4ff9..fa88a238 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -83,7 +83,7 @@ jobs: - name: Install dependencies run: flutter packages get - working-directory: floor + working-directory: floor_common - name: Run generator run: flutter packages pub run build_runner build --delete-conflicting-outputs diff --git a/example/lib/database.dart b/example/lib/database.dart index 037973f8..5c7d6aa5 100644 --- a/example/lib/database.dart +++ b/example/lib/database.dart @@ -2,14 +2,15 @@ import 'dart:async'; import 'package:example/task.dart'; import 'package:example/task_dao.dart'; +import 'package:example/timestamp.dart'; import 'package:example/type_converter.dart'; import 'package:floor/floor.dart'; import 'package:sqflite/sqflite.dart' as sqflite; part 'database.g.dart'; -@Database(version: 1, entities: [Task]) @TypeConverters([DateTimeConverter, TaskTypeConverter]) +@Database(version: 1, entities: [Task], embeds: [Timestamp]) abstract class FlutterDatabase extends FloorDatabase { TaskDao get taskDao; } diff --git a/example/lib/database.g.dart b/example/lib/database.g.dart index 39dcf3a9..496effff 100644 --- a/example/lib/database.g.dart +++ b/example/lib/database.g.dart @@ -96,7 +96,7 @@ class _$FlutterDatabase extends FlutterDatabase { }, onCreate: (database, version) async { await database.execute( - 'CREATE TABLE IF NOT EXISTS `Task` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `message` TEXT NOT NULL, `isRead` INTEGER, `timestamp` INTEGER NOT NULL, `status` INTEGER, `type` TEXT)'); + 'CREATE TABLE IF NOT EXISTS `Task` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `message` TEXT NOT NULL, `isRead` INTEGER, `timestamp_created_at` INTEGER NOT NULL, `timestamp_updated_at` INTEGER NOT NULL, `status` INTEGER, `type` TEXT)'); await callback?.onCreate?.call(database, version); }, @@ -122,7 +122,10 @@ class _$TaskDao extends TaskDao { 'id': item.id, 'message': item.message, 'isRead': item.isRead == null ? null : (item.isRead! ? 1 : 0), - 'timestamp': _dateTimeConverter.encode(item.timestamp), + 'timestamp_created_at': + _dateTimeConverter.encode(item.timestamp.createdAt), + 'timestamp_updated_at': + _dateTimeConverter.encode(item.timestamp.updatedAt), 'status': item.status?.index, 'type': _taskTypeConverter.encode(item.type) }, @@ -135,7 +138,10 @@ class _$TaskDao extends TaskDao { 'id': item.id, 'message': item.message, 'isRead': item.isRead == null ? null : (item.isRead! ? 1 : 0), - 'timestamp': _dateTimeConverter.encode(item.timestamp), + 'timestamp_created_at': + _dateTimeConverter.encode(item.timestamp.createdAt), + 'timestamp_updated_at': + _dateTimeConverter.encode(item.timestamp.updatedAt), 'status': item.status?.index, 'type': _taskTypeConverter.encode(item.type) }, @@ -148,7 +154,10 @@ class _$TaskDao extends TaskDao { 'id': item.id, 'message': item.message, 'isRead': item.isRead == null ? null : (item.isRead! ? 1 : 0), - 'timestamp': _dateTimeConverter.encode(item.timestamp), + 'timestamp_created_at': + _dateTimeConverter.encode(item.timestamp.createdAt), + 'timestamp_updated_at': + _dateTimeConverter.encode(item.timestamp.updatedAt), 'status': item.status?.index, 'type': _taskTypeConverter.encode(item.type) }, @@ -173,7 +182,11 @@ class _$TaskDao extends TaskDao { row['id'] as int?, row['isRead'] == null ? null : (row['isRead'] as int) != 0, row['message'] as String, - _dateTimeConverter.decode(row['timestamp'] as int), + Timestamp( + createdAt: _dateTimeConverter + .decode(row['timestamp_created_at'] as int), + updatedAt: _dateTimeConverter + .decode(row['timestamp_updated_at'] as int)), row['status'] == null ? null : TaskStatus.values[row['status'] as int], @@ -188,7 +201,11 @@ class _$TaskDao extends TaskDao { row['id'] as int?, row['isRead'] == null ? null : (row['isRead'] as int) != 0, row['message'] as String, - _dateTimeConverter.decode(row['timestamp'] as int), + Timestamp( + createdAt: _dateTimeConverter + .decode(row['timestamp_created_at'] as int), + updatedAt: _dateTimeConverter + .decode(row['timestamp_updated_at'] as int)), row['status'] == null ? null : TaskStatus.values[row['status'] as int], @@ -202,7 +219,11 @@ class _$TaskDao extends TaskDao { row['id'] as int?, row['isRead'] == null ? null : (row['isRead'] as int) != 0, row['message'] as String, - _dateTimeConverter.decode(row['timestamp'] as int), + Timestamp( + createdAt: _dateTimeConverter + .decode(row['timestamp_created_at'] as int), + updatedAt: _dateTimeConverter + .decode(row['timestamp_updated_at'] as int)), row['status'] == null ? null : TaskStatus.values[row['status'] as int], @@ -226,7 +247,11 @@ class _$TaskDao extends TaskDao { row['id'] as int?, row['isRead'] == null ? null : (row['isRead'] as int) != 0, row['message'] as String, - _dateTimeConverter.decode(row['timestamp'] as int), + Timestamp( + createdAt: _dateTimeConverter + .decode(row['timestamp_created_at'] as int), + updatedAt: _dateTimeConverter + .decode(row['timestamp_updated_at'] as int)), row['status'] == null ? null : TaskStatus.values[row['status'] as int], diff --git a/example/lib/main.dart b/example/lib/main.dart index b0994452..43fa85c0 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,6 +1,7 @@ import 'package:example/database.dart'; import 'package:example/task.dart'; import 'package:example/task_dao.dart'; +import 'package:example/timestamp.dart'; import 'package:flutter/material.dart'; Future main() async { @@ -179,7 +180,7 @@ class TaskListCell extends StatelessWidget { child: ListTile( title: Text(task.message), subtitle: Text('Status: ${task.statusTitle}'), - trailing: Text(task.timestamp.toIso8601String()), + trailing: Text(task.timestamp.format()), ), confirmDismiss: (direction) async { String? statusMessage; @@ -263,7 +264,13 @@ class TasksTextField extends StatelessWidget { if (message.trim().isEmpty) { _textEditingController.clear(); } else { - final task = Task.optional(message: message, type: TaskType.task); + final task = Task.optional( + message: message, + type: TaskType.task, + timestamp: Timestamp( + createdAt: DateTime.now(), + updatedAt: DateTime.now(), + )); await dao.insertTask(task); _textEditingController.clear(); } diff --git a/example/lib/task.dart b/example/lib/task.dart index 3a7240e9..b6042a1c 100644 --- a/example/lib/task.dart +++ b/example/lib/task.dart @@ -1,3 +1,4 @@ +import 'package:example/timestamp.dart'; import 'package:floor/floor.dart'; enum TaskStatus { @@ -29,7 +30,7 @@ class Task { final bool? isRead; - final DateTime timestamp; + final Timestamp timestamp; final TaskStatus? status; @@ -46,7 +47,7 @@ class Task { factory Task.optional({ int? id, - DateTime? timestamp, + Timestamp? timestamp, String? message, bool? isRead, TaskStatus? status, @@ -56,7 +57,11 @@ class Task { id, isRead ?? false, message ?? 'empty', - timestamp ?? DateTime.now(), + timestamp ?? + Timestamp( + createdAt: DateTime.now(), + updatedAt: DateTime.now(), + ), status, type, ); @@ -70,7 +75,7 @@ class Task { int? id, String? message, bool? isRead, - DateTime? timestamp, + Timestamp? timestamp, TaskStatus? status, TaskType? type, }) { diff --git a/example/lib/timestamp.dart b/example/lib/timestamp.dart new file mode 100644 index 00000000..2714383f --- /dev/null +++ b/example/lib/timestamp.dart @@ -0,0 +1,37 @@ +import 'package:floor/floor.dart'; +import 'package:intl/intl.dart'; + +@Embed() +@Entity() +class Timestamp { + @ColumnInfo(name: 'created_at') + final DateTime createdAt; + + @ColumnInfo(name: 'updated_at') + final DateTime updatedAt; + + Timestamp({required this.createdAt, required this.updatedAt}); + + @override + bool operator ==(Object other) => + identical(this, other) || + other is Timestamp && + runtimeType == other.runtimeType && + createdAt == other.createdAt && + updatedAt == other.updatedAt; + + @override + int get hashCode => createdAt.hashCode ^ updatedAt.hashCode; + + String format() { + final DateFormat formatter = DateFormat('yyyy-MM-dd'); + final String formattedCreatedAt = formatter.format(createdAt); + final String formattedUpdatedAt = formatter.format(updatedAt); + return 'Created at: $formattedCreatedAt \nUpdated at: $formattedUpdatedAt'; + } + + @override + String toString() { + return 'Timestamp(createdAt: $createdAt, updatedAt: $updatedAt)'; + } +} diff --git a/example/pubspec.lock b/example/pubspec.lock index 841a53a7..c780dd34 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -223,7 +223,7 @@ packages: path: "../floor" relative: true source: path - version: "1.4.2" + version: "1.5.0" floor_annotation: dependency: transitive description: @@ -311,6 +311,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.2" + intl: + dependency: "direct main" + description: + name: intl + sha256: "910f85bce16fb5c6f614e117efa303e85a1731bb0081edf3604a2ae6e9a3cc91" + url: "https://pub.dev" + source: hosted + version: "0.17.0" io: dependency: transitive description: diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 0b074ef2..b25a1d64 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -15,6 +15,7 @@ dependencies: flutter: sdk: flutter sqflite: any # This dependency is needed to solve the problem with warning about transitive dependencies + intl: ^0.17.0 dev_dependencies: analyzer: ^6.4.1 diff --git a/example/test/main_test.dart b/example/test/main_test.dart index 836ea537..2236d773 100644 --- a/example/test/main_test.dart +++ b/example/test/main_test.dart @@ -14,6 +14,8 @@ void main() { }); tearDown(() async { + //Delay is necessary, otherwise test wil fail after completion + await Future.delayed(const Duration(milliseconds: 100)); await database.close(); }); diff --git a/floor_annotation/lib/floor_annotation.dart b/floor_annotation/lib/floor_annotation.dart index c97fef74..90e23134 100644 --- a/floor_annotation/lib/floor_annotation.dart +++ b/floor_annotation/lib/floor_annotation.dart @@ -5,6 +5,7 @@ export 'src/dao.dart'; export 'src/database.dart'; export 'src/database_view.dart'; export 'src/delete.dart'; +export 'src/embed.dart'; export 'src/entity.dart'; export 'src/foreign_key.dart'; export 'src/fts.dart'; diff --git a/floor_annotation/lib/src/database.dart b/floor_annotation/lib/src/database.dart index d3bf873e..ec07a22d 100644 --- a/floor_annotation/lib/src/database.dart +++ b/floor_annotation/lib/src/database.dart @@ -6,6 +6,9 @@ class Database { /// The entities the database manages. final List entities; + /// The embeds the database manages. + final List embeds; + /// The views the database manages. final List views; @@ -13,6 +16,7 @@ class Database { const Database({ required this.version, required this.entities, + this.embeds = const [], this.views = const [], }); } diff --git a/floor_annotation/lib/src/embed.dart b/floor_annotation/lib/src/embed.dart new file mode 100644 index 00000000..67258c69 --- /dev/null +++ b/floor_annotation/lib/src/embed.dart @@ -0,0 +1,5 @@ +class Embed { + const Embed(); +} + +const embed = Embed(); diff --git a/floor_generator/lib/misc/constants.dart b/floor_generator/lib/misc/constants.dart index 689c1f7e..71c50a7e 100644 --- a/floor_generator/lib/misc/constants.dart +++ b/floor_generator/lib/misc/constants.dart @@ -4,6 +4,7 @@ abstract class AnnotationField { static const onConflict = 'onConflict'; static const databaseVersion = 'version'; + static const databaseEmbeds = 'embeds'; static const databaseEntities = 'entities'; static const databaseViews = 'views'; diff --git a/floor_generator/lib/misc/extension/embeds_extension.dart b/floor_generator/lib/misc/extension/embeds_extension.dart new file mode 100644 index 00000000..a6a01f1d --- /dev/null +++ b/floor_generator/lib/misc/extension/embeds_extension.dart @@ -0,0 +1,13 @@ +import 'package:analyzer/dart/element/type.dart'; +import 'package:collection/collection.dart'; +import 'package:floor_generator/value_object/embed.dart'; +import 'package:floor_generator/value_object/type_converter.dart'; + +extension EmbedsExtension on Iterable { + /// Returns the [Embed] in the closest [TypeConverterScope] for + /// [dartType] or null + Embed? getClosestOrNull(DartType dartType) { + return toList().firstWhereOrNull( + (embed) => embed.classElement.name == dartType.toString()); + } +} diff --git a/floor_generator/lib/misc/extension/field_element_extension.dart b/floor_generator/lib/misc/extension/field_element_extension.dart new file mode 100644 index 00000000..037dc06e --- /dev/null +++ b/floor_generator/lib/misc/extension/field_element_extension.dart @@ -0,0 +1,15 @@ +import 'package:analyzer/dart/element/element.dart'; +import 'package:floor_annotation/floor_annotation.dart' as annotations; +import 'package:floor_generator/misc/type_utils.dart'; + +extension FieldElementExtension on FieldElement { + bool shouldBeIncluded() { + final isIgnored = hasAnnotation(annotations.ignore.runtimeType); + return !(isStatic || isSynthetic || isIgnored); + } + + bool get isEmbedded { + return (type.element?.hasAnnotation(annotations.Embed) ?? false) && + type.element is ClassElement; + } +} diff --git a/floor_generator/lib/processor/database_processor.dart b/floor_generator/lib/processor/database_processor.dart index f088d351..4d1f77ba 100644 --- a/floor_generator/lib/processor/database_processor.dart +++ b/floor_generator/lib/processor/database_processor.dart @@ -6,12 +6,14 @@ import 'package:floor_generator/misc/extension/set_extension.dart'; import 'package:floor_generator/misc/extension/type_converter_element_extension.dart'; import 'package:floor_generator/misc/type_utils.dart'; import 'package:floor_generator/processor/dao_processor.dart'; +import 'package:floor_generator/processor/embed_processor.dart'; import 'package:floor_generator/processor/entity_processor.dart'; import 'package:floor_generator/processor/error/database_processor_error.dart'; import 'package:floor_generator/processor/processor.dart'; import 'package:floor_generator/processor/view_processor.dart'; import 'package:floor_generator/value_object/dao_getter.dart'; import 'package:floor_generator/value_object/database.dart'; +import 'package:floor_generator/value_object/embed.dart'; import 'package:floor_generator/value_object/entity.dart'; import 'package:floor_generator/value_object/queryable.dart'; import 'package:floor_generator/value_object/type_converter.dart'; @@ -31,8 +33,10 @@ class DatabaseProcessor extends Processor { final databaseName = _classElement.displayName; final databaseTypeConverters = _classElement.getTypeConverters(TypeConverterScope.database); - final entities = _getEntities(_classElement, databaseTypeConverters); - final views = _getViews(_classElement, databaseTypeConverters); + final embeds = _getEmbeds(_classElement, databaseTypeConverters); + final entities = + _getEntities(_classElement, databaseTypeConverters, embeds); + final views = _getViews(_classElement, databaseTypeConverters, embeds); final daoGetters = _getDaoGetters( databaseName, entities, @@ -102,9 +106,29 @@ class DatabaseProcessor extends Processor { classElement.isAbstract; } + Set _getEmbeds( + final ClassElement databaseClassElement, + final Set typeConverters, + ) { + return _classElement + .getAnnotation(annotations.Database) + ?.getField(AnnotationField.databaseEmbeds) + ?.toListValue() + ?.mapNotNull((object) => object.toTypeValue()?.element) + .whereType() + .where(_isEmbed) + .map((classElement) => EmbedProcessor( + classElement, + typeConverters, + ).process()) + .toSet() ?? + {}; + } + List _getEntities( final ClassElement databaseClassElement, final Set typeConverters, + final Set embedConverters, ) { final entities = _classElement .getAnnotation(annotations.Database) @@ -116,6 +140,7 @@ class DatabaseProcessor extends Processor { .map((classElement) => EntityProcessor( classElement, typeConverters, + embedConverters, ).process()) .toList(); @@ -129,6 +154,7 @@ class DatabaseProcessor extends Processor { List _getViews( final ClassElement databaseClassElement, final Set typeConverters, + final Set embedConverters, ) { return _classElement .getAnnotation(annotations.Database) @@ -140,6 +166,7 @@ class DatabaseProcessor extends Processor { .map((classElement) => ViewProcessor( classElement, typeConverters, + embedConverters, ).process()) .toList() ?? []; @@ -169,6 +196,11 @@ class DatabaseProcessor extends Processor { fieldTypeConverters; } + bool _isEmbed(final ClassElement classElement) { + return classElement.hasAnnotation(annotations.Embed) && + !classElement.isAbstract; + } + bool _isEntity(final ClassElement classElement) { return classElement.hasAnnotation(annotations.Entity) && !classElement.isAbstract; diff --git a/floor_generator/lib/processor/embed_processor.dart b/floor_generator/lib/processor/embed_processor.dart new file mode 100644 index 00000000..5ab5a4f7 --- /dev/null +++ b/floor_generator/lib/processor/embed_processor.dart @@ -0,0 +1,34 @@ +import 'package:analyzer/dart/element/element.dart'; +import 'package:floor_generator/misc/extension/field_element_extension.dart'; +import 'package:floor_generator/misc/extension/type_converters_extension.dart'; +import 'package:floor_generator/processor/field_processor.dart'; +import 'package:floor_generator/processor/processor.dart'; +import 'package:floor_generator/value_object/embed.dart'; +import 'package:floor_generator/value_object/field.dart'; +import 'package:floor_generator/value_object/type_converter.dart'; + +class EmbedProcessor extends Processor { + final ClassElement _classElement; + Set typeConverters; + + EmbedProcessor(this._classElement, this.typeConverters); + + @override + Embed process() { + return Embed( + _classElement, + _getFields(), + ); + } + + List _getFields() { + final fields = _classElement.fields + .where((fieldElement) => fieldElement.shouldBeIncluded()) + .map((field) => FieldProcessor( + field, typeConverters.getClosestOrNull(field.type), null) + .process()) + .toList(); + + return fields; + } +} diff --git a/floor_generator/lib/processor/entity_processor.dart b/floor_generator/lib/processor/entity_processor.dart index 12e96142..23514ee4 100644 --- a/floor_generator/lib/processor/entity_processor.dart +++ b/floor_generator/lib/processor/entity_processor.dart @@ -18,14 +18,17 @@ import 'package:floor_generator/value_object/index.dart'; import 'package:floor_generator/value_object/primary_key.dart'; import 'package:floor_generator/value_object/type_converter.dart'; +import '../value_object/embed.dart'; + class EntityProcessor extends QueryableProcessor { final EntityProcessorError _processorError; EntityProcessor( final ClassElement classElement, final Set typeConverters, + final Set embedConverters, ) : _processorError = EntityProcessorError(classElement), - super(classElement, typeConverters); + super(classElement, typeConverters, embedConverters); @override Entity process() { @@ -262,28 +265,50 @@ class EntityProcessor extends QueryableProcessor { false; } + void _processFields( + final Map map, + final List fields, { + String columnNamePrefix = '', + String parameterPrefix = '', + }) { + for (final field in fields) { + if (field.embedConverter != null) { + final embedVar = field.columnName.isEmpty ? '' : '${field.columnName}_'; + _processFields( + map, + field.embedConverter?.fields ?? [], + columnNamePrefix: '$columnNamePrefix$embedVar', + parameterPrefix: '$parameterPrefix${field.fieldElement.name}.', + ); + } else { + map['$columnNamePrefix${field.columnName}'] = + _getAttributeValue(field, parameterPrefix); + } + } + } + String _getValueMapping(final List fields) { - final keyValueList = fields.map((field) { - final columnName = field.columnName; - final attributeValue = _getAttributeValue(field); - return "'$columnName': $attributeValue"; - }).toList(); + final Map map = {}; + _processFields(map, fields); + + final keyValueList = + map.entries.map((entry) => "'${entry.key}': ${entry.value}").toList(); return '{${keyValueList.join(', ')}}'; } - String _getAttributeValue(final Field field) { + String _getAttributeValue(final Field field, String parameterPrefix) { final fieldElement = field.fieldElement; final parameterName = fieldElement.displayName; final fieldType = fieldElement.type; final typeConverter = [...queryableTypeConverters, field.typeConverter] .whereNotNull() .getClosestOrNull(fieldType); - String attributeValue = 'item.$parameterName'; + String attributeValue = 'item.$parameterPrefix$parameterName'; if (typeConverter != null) { attributeValue = - '_${typeConverter.name.decapitalize()}.encode(item.$parameterName)'; + '_${typeConverter.name.decapitalize()}.encode(item.$parameterPrefix$parameterName)'; } else if (fieldType.isDartCoreBool) { attributeValue = _serializeBoolean(field, attributeValue); } else if (fieldType.isEnumType) { diff --git a/floor_generator/lib/processor/field_processor.dart b/floor_generator/lib/processor/field_processor.dart index 26015be5..db2db04c 100644 --- a/floor_generator/lib/processor/field_processor.dart +++ b/floor_generator/lib/processor/field_processor.dart @@ -12,15 +12,18 @@ import 'package:floor_generator/value_object/field.dart'; import 'package:floor_generator/value_object/type_converter.dart'; import 'package:source_gen/source_gen.dart'; +import '../value_object/embed.dart'; + class FieldProcessor extends Processor { final FieldElement _fieldElement; final TypeConverter? _typeConverter; + final Embed? _embedConverter; FieldProcessor( - final FieldElement fieldElement, - final TypeConverter? typeConverter, - ) : _fieldElement = fieldElement, - _typeConverter = typeConverter; + this._fieldElement, + this._typeConverter, + this._embedConverter, + ); @override Field process() { @@ -33,13 +36,13 @@ class FieldProcessor extends Processor { }.whereNotNull().closestOrNull; return Field( - _fieldElement, - name, - columnName, - isNullable, - _getSqlType(typeConverter), - typeConverter, - ); + _fieldElement, + name, + columnName, + isNullable, + _getSqlType(typeConverter, _embedConverter), + typeConverter, + _embedConverter); } String _getColumnName(final String name) { @@ -52,12 +55,15 @@ class FieldProcessor extends Processor { : name; } - String _getSqlType(final TypeConverter? typeConverter) { + String _getSqlType( + final TypeConverter? typeConverter, final Embed? embedConverter) { final type = _fieldElement.type; if (typeConverter != null) { return typeConverter.databaseType.asSqlType(); } else if (type.isDefaultSqlType || type.isEnumType) { return type.asSqlType(); + } else if (embedConverter != null) { + return ''; } else { throw InvalidGenerationSourceError( 'Column type is not supported for $type.', diff --git a/floor_generator/lib/processor/queryable_processor.dart b/floor_generator/lib/processor/queryable_processor.dart index f5291c62..b498bb30 100644 --- a/floor_generator/lib/processor/queryable_processor.dart +++ b/floor_generator/lib/processor/queryable_processor.dart @@ -1,6 +1,7 @@ import 'package:analyzer/dart/element/element.dart'; import 'package:collection/collection.dart'; -import 'package:floor_annotation/floor_annotation.dart' as annotations; +import 'package:floor_generator/misc/extension/embeds_extension.dart'; +import 'package:floor_generator/misc/extension/field_element_extension.dart'; import 'package:floor_generator/misc/extension/set_extension.dart'; import 'package:floor_generator/misc/extension/string_extension.dart'; import 'package:floor_generator/misc/extension/type_converter_element_extension.dart'; @@ -15,6 +16,8 @@ import 'package:floor_generator/value_object/type_converter.dart'; import 'package:meta/meta.dart'; import 'package:source_gen/source_gen.dart'; +import '../value_object/embed.dart'; + abstract class QueryableProcessor extends Processor { final QueryableProcessorError _queryableProcessorError; @@ -23,10 +26,13 @@ abstract class QueryableProcessor extends Processor { final Set queryableTypeConverters; + final Set embedConverters; + @protected QueryableProcessor( this.classElement, final Set typeConverters, + this.embedConverters, ) : _queryableProcessorError = QueryableProcessorError(classElement), queryableTypeConverters = typeConverters + classElement.getTypeConverters(TypeConverterScope.queryable); @@ -39,19 +45,28 @@ abstract class QueryableProcessor extends Processor { final fields = [ ...classElement.fields, ...classElement.allSupertypes.expand((type) => type.element.fields), - ]; - - return fields - .where((fieldElement) => fieldElement.shouldBeIncluded()) - .map((field) { - final typeConverter = - queryableTypeConverters.getClosestOrNull(field.type); - return FieldProcessor(field, typeConverter).process(); + ].where((fieldElement) => fieldElement.shouldBeIncluded()); + + return fields.map((field) { + if (field.isEmbedded) { + return FieldProcessor( + field, null, embedConverters.getClosestOrNull(field.type)) + .process(); + } else { + return FieldProcessor(field, + queryableTypeConverters.getClosestOrNull(field.type), null) + .process(); + } }).toList(); } @protected String getConstructor(final List fields) { + return _getConstructor(classElement, fields); + } + + String _getConstructor(ClassElement classElement, final List fields, + {String prefix = ''}) { final constructorParameters = classElement.constructors .firstWhereOrNull((element) => element.isPublic && !element.isFactory) ?.parameters; @@ -61,7 +76,7 @@ abstract class QueryableProcessor extends Processor { } else { final parameterValues = constructorParameters .map((parameterElement) => - _getParameterValue(parameterElement, fields)) + _getParameterValue(parameterElement, fields, prefix: prefix)) .where((parameterValue) => parameterValue != null) .join(', '); @@ -72,14 +87,14 @@ abstract class QueryableProcessor extends Processor { /// Returns `null` whenever field is @ignored String? _getParameterValue( final ParameterElement parameterElement, - final List fields, - ) { + final List fields, { + final String prefix = '', + }) { final parameterName = parameterElement.displayName; final field = - // null whenever field is @ignored fields.firstWhereOrNull((field) => field.name == parameterName); if (field != null) { - final databaseValue = "row['${field.columnName}']"; + final databaseValue = "row['$prefix${field.columnName}']"; String parameterValue; @@ -101,6 +116,11 @@ abstract class QueryableProcessor extends Processor { parameterElement.type, parameterElement, ); + } else if (field.embedConverter != null) { + final embedVar = field.columnName.isEmpty ? '' : '${field.columnName}_'; + parameterValue = _getConstructor( + field.embedConverter!.classElement, field.embedConverter!.fields, + prefix: '$prefix$embedVar'); } else { throw InvalidGenerationSourceError( 'Column type is not supported for ${parameterElement.type}', @@ -113,15 +133,7 @@ abstract class QueryableProcessor extends Processor { return '$parameterName: $parameterValue'; } return parameterValue; // also covers positional parameter - } else { - return null; } - } -} - -extension on FieldElement { - bool shouldBeIncluded() { - final isIgnored = hasAnnotation(annotations.ignore.runtimeType); - return !(isStatic || isSynthetic || isIgnored); + return null; } } diff --git a/floor_generator/lib/processor/view_processor.dart b/floor_generator/lib/processor/view_processor.dart index b30d9bd5..3b1995df 100644 --- a/floor_generator/lib/processor/view_processor.dart +++ b/floor_generator/lib/processor/view_processor.dart @@ -7,14 +7,17 @@ import 'package:floor_generator/processor/queryable_processor.dart'; import 'package:floor_generator/value_object/type_converter.dart'; import 'package:floor_generator/value_object/view.dart'; +import '../value_object/embed.dart'; + class ViewProcessor extends QueryableProcessor { final ViewProcessorError _processorError; ViewProcessor( final ClassElement classElement, final Set typeConverters, + final Set embedConverters, ) : _processorError = ViewProcessorError(classElement), - super(classElement, typeConverters); + super(classElement, typeConverters, embedConverters); @override View process() { diff --git a/floor_generator/lib/value_object/embed.dart b/floor_generator/lib/value_object/embed.dart new file mode 100644 index 00000000..1cda9b56 --- /dev/null +++ b/floor_generator/lib/value_object/embed.dart @@ -0,0 +1,25 @@ +import 'package:analyzer/dart/element/element.dart'; +import 'package:collection/collection.dart'; +import 'package:floor_generator/value_object/field.dart'; + +class Embed { + final ClassElement classElement; + final List fields; + + Embed(this.classElement, this.fields); + + @override + bool operator ==(Object other) => + identical(this, other) || + other is Embed && + runtimeType == other.runtimeType && + const ListEquality().equals(fields, other.fields); + + @override + int get hashCode => classElement.hashCode ^ fields.hashCode; + + @override + String toString() { + return 'Embed{classElement: $classElement, fields: $fields}'; + } +} diff --git a/floor_generator/lib/value_object/entity.dart b/floor_generator/lib/value_object/entity.dart index fda23624..58bc9d21 100644 --- a/floor_generator/lib/value_object/entity.dart +++ b/floor_generator/lib/value_object/entity.dart @@ -30,7 +30,7 @@ class Entity extends Queryable { ) : super(classElement, name, fields, constructor); String getCreateTableStatement() { - final databaseDefinition = fields.map((field) { + final databaseDefinition = _getFields(fields).map((field) { final autoIncrement = primaryKey.fields.contains(field) && primaryKey.autoGenerateId; return field.getDatabaseDefinition(autoIncrement); @@ -57,6 +57,18 @@ class Entity extends Queryable { } } + List _getFields(List fields, {String columnNamePrefix = ''}) { + return fields.map((field) { + final embedConverter = field.embedConverter; + if (embedConverter != null) { + final embedVar = field.columnName.isEmpty ? '' : '${field.columnName}_'; + return _getFields(embedConverter.fields, columnNamePrefix: embedVar); + } else { + return [field.copyWith(columnNamePrefix: columnNamePrefix)]; + } + }).reduce((value, element) => value + element); + } + String? _createPrimaryKeyDefinition() { if (primaryKey.autoGenerateId) { return null; diff --git a/floor_generator/lib/value_object/field.dart b/floor_generator/lib/value_object/field.dart index 0f265ed4..8fe3d564 100644 --- a/floor_generator/lib/value_object/field.dart +++ b/floor_generator/lib/value_object/field.dart @@ -1,5 +1,7 @@ import 'package:analyzer/dart/element/element.dart'; +import 'package:floor_generator/value_object/embed.dart'; import 'package:floor_generator/value_object/type_converter.dart'; +import 'package:source_gen/source_gen.dart'; /// Represents an Entity field and thus a table column. class Field { @@ -9,6 +11,7 @@ class Field { final bool isNullable; final String sqlType; final TypeConverter? typeConverter; + final Embed? embedConverter; Field( this.fieldElement, @@ -17,10 +20,19 @@ class Field { this.isNullable, this.sqlType, this.typeConverter, + this.embedConverter, ); /// The database column definition. String getDatabaseDefinition(final bool autoGenerate) { + if (embedConverter != null) { + throw InvalidGenerationSourceError( + 'You ', + todo: 'Either make to use a supported type or supply a type converter.', + element: fieldElement, + ); + } + final columnSpecification = StringBuffer(); if (autoGenerate) { @@ -33,6 +45,19 @@ class Field { return '`$columnName` $sqlType$columnSpecification'; } + Field copyWith({ + String columnNamePrefix = '', + }) => + Field( + fieldElement, + name, + '$columnNamePrefix$columnName', + isNullable, + sqlType, + typeConverter, + embedConverter, + ); + @override bool operator ==(Object other) => identical(this, other) || diff --git a/floor_generator/test/processor/dao_processor_test.dart b/floor_generator/test/processor/dao_processor_test.dart index a718498f..995e9a63 100644 --- a/floor_generator/test/processor/dao_processor_test.dart +++ b/floor_generator/test/processor/dao_processor_test.dart @@ -232,7 +232,7 @@ Future> _getEntities() async { return library.classes .where((classElement) => classElement.hasAnnotation(annotations.Entity)) - .map((classElement) => EntityProcessor(classElement, {}).process()) + .map((classElement) => EntityProcessor(classElement, {}, {}).process()) .toList(); } @@ -258,6 +258,6 @@ Future> _getViews() async { return library.classes .where((classElement) => classElement.hasAnnotation(annotations.DatabaseView)) - .map((classElement) => ViewProcessor(classElement, {}).process()) + .map((classElement) => ViewProcessor(classElement, {}, {}).process()) .toList(); } diff --git a/floor_generator/test/processor/entity_processor_test.dart b/floor_generator/test/processor/entity_processor_test.dart index 02332bbb..3ed3735c 100644 --- a/floor_generator/test/processor/entity_processor_test.dart +++ b/floor_generator/test/processor/entity_processor_test.dart @@ -29,11 +29,12 @@ void main() { } '''); - final actual = EntityProcessor(classElement, {}).process(); + final actual = EntityProcessor(classElement, {}, {}).process(); const name = 'Person'; final fields = classElement.fields - .map((fieldElement) => FieldProcessor(fieldElement, null).process()) + .map((fieldElement) => + FieldProcessor(fieldElement, null, null).process()) .toList(); final primaryKey = PrimaryKey([fields[0]], false); const foreignKeys = []; @@ -77,11 +78,12 @@ void main() { } '''); - final actual = EntityProcessor(classElement, {}).process(); + final actual = EntityProcessor(classElement, {}, {}).process(); const name = 'Person'; final fields = classElement.fields - .map((fieldElement) => FieldProcessor(fieldElement, null).process()) + .map((fieldElement) => + FieldProcessor(fieldElement, null, null).process()) .toList(); final primaryKey = PrimaryKey([fields[0]], false); const foreignKeys = []; @@ -115,11 +117,12 @@ void main() { } '''); - final actual = EntityProcessor(classElement, {}).process(); + final actual = EntityProcessor(classElement, {}, {}).process(); const name = 'Person'; final fields = classElement.fields - .map((fieldElement) => FieldProcessor(fieldElement, null).process()) + .map((fieldElement) => + FieldProcessor(fieldElement, null, null).process()) .toList(); final primaryKey = PrimaryKey(fields, false); const foreignKeys = []; @@ -154,11 +157,12 @@ void main() { } '''); - final actual = EntityProcessor(classElement, {}).process(); + final actual = EntityProcessor(classElement, {}, {}).process(); const name = 'Person'; final fields = classElement.fields - .map((fieldElement) => FieldProcessor(fieldElement, null).process()) + .map((fieldElement) => + FieldProcessor(fieldElement, null, null).process()) .toList(); final primaryKey = PrimaryKey(fields.sublist(0, 1), false); const foreignKeys = []; @@ -202,11 +206,12 @@ void main() { } '''); - final actual = EntityProcessor(classElement, {}).process(); + final actual = EntityProcessor(classElement, {}, {}).process(); const name = 'Person'; final fields = classElement.fields - .map((fieldElement) => FieldProcessor(fieldElement, null).process()) + .map((fieldElement) => + FieldProcessor(fieldElement, null, null).process()) .toList(); final primaryKey = PrimaryKey([fields[0]], false); const foreignKeys = []; @@ -266,7 +271,7 @@ void main() { '''); final actual = - EntityProcessor(classElements[1], {}).process().foreignKeys[0]; + EntityProcessor(classElements[1], {}, {}).process().foreignKeys[0]; final expected = ForeignKey( 'Person', @@ -296,7 +301,7 @@ void main() { } '''); - final actual = EntityProcessor(classElements[0], {}).process().fts; + final actual = EntityProcessor(classElements[0], {}, {}).process().fts; final Fts expected = Fts3('simple', []); @@ -321,7 +326,7 @@ void main() { } '''); - final actual = EntityProcessor(classElements[0], {}).process().fts; + final actual = EntityProcessor(classElements[0], {}, {}).process().fts; final Fts expected = Fts4('simple', []); @@ -342,11 +347,12 @@ void main() { } '''); - final actual = EntityProcessor(classElement, {}).process(); + final actual = EntityProcessor(classElement, {}, {}).process(); const name = 'Person'; final fields = classElement.fields - .map((fieldElement) => FieldProcessor(fieldElement, null).process()) + .map((fieldElement) => + FieldProcessor(fieldElement, null, null).process()) .toList(); final primaryKey = PrimaryKey([fields[0]], false); const foreignKeys = []; @@ -381,7 +387,8 @@ void main() { } '''); - final actual = EntityProcessor(classElement, {}).process().valueMapping; + final actual = + EntityProcessor(classElement, {}, {}).process().valueMapping; const expected = '{' "'id': item.id, " @@ -403,7 +410,8 @@ void main() { } '''); - final actual = EntityProcessor(classElement, {}).process().valueMapping; + final actual = + EntityProcessor(classElement, {}, {}).process().valueMapping; const expected = '{' "'id': item.id, " @@ -428,7 +436,8 @@ void main() { } '''); - final actual = EntityProcessor(classElement, {}).process().valueMapping; + final actual = + EntityProcessor(classElement, {}, {}).process().valueMapping; const expected = '{' "'id': item.id, " @@ -453,7 +462,8 @@ void main() { } '''); - final actual = EntityProcessor(classElement, {}).process().valueMapping; + final actual = + EntityProcessor(classElement, {}, {}).process().valueMapping; const expected = '{' "'id': item.id, " @@ -476,7 +486,7 @@ void main() { } '''); - final processor = EntityProcessor(classElements, {}); + final processor = EntityProcessor(classElements, {}, {}); expect( processor.process, throwsInvalidGenerationSourceError( @@ -496,7 +506,7 @@ void main() { } '''); - final processor = EntityProcessor(classElements, {}); + final processor = EntityProcessor(classElements, {}, {}); expect( processor.process, throwsInvalidGenerationSourceError( @@ -537,7 +547,7 @@ void main() { } '''); - final processor = EntityProcessor(classElements[1], {}); + final processor = EntityProcessor(classElements[1], {}, {}); expect( processor.process, throwsInvalidGenerationSourceError( @@ -578,7 +588,7 @@ void main() { } '''); - final processor = EntityProcessor(classElements[1], {}); + final processor = EntityProcessor(classElements[1], {}, {}); expect( processor.process, throwsInvalidGenerationSourceError( @@ -612,7 +622,7 @@ void main() { } '''); - final processor = EntityProcessor(classElements[0], {}); + final processor = EntityProcessor(classElements[0], {}, {}); expect( processor.process, throwsInvalidGenerationSourceError( @@ -644,7 +654,7 @@ void main() { } '''); - final processor = EntityProcessor(classElements, {}); + final processor = EntityProcessor(classElements, {}, {}); expect( processor.process, throwsInvalidGenerationSourceError( @@ -668,7 +678,7 @@ void main() { } '''); - final processor = EntityProcessor(classElement, {}); + final processor = EntityProcessor(classElement, {}, {}); expect( processor.process, throwsInvalidGenerationSourceError( @@ -692,7 +702,7 @@ void main() { } '''); - final processor = EntityProcessor(classElement, {}); + final processor = EntityProcessor(classElement, {}, {}); expect( processor.process, throwsInvalidGenerationSourceError(EntityProcessorError(classElement) @@ -716,7 +726,7 @@ void main() { } '''); - final processor = EntityProcessor(classElement, {}); + final processor = EntityProcessor(classElement, {}, {}); expect( processor.process, throwsInvalidGenerationSourceError( @@ -738,7 +748,7 @@ void main() { } '''); - final actual = EntityProcessor(classElement, {}); + final actual = EntityProcessor(classElement, {}, {}); expect( actual.process, diff --git a/floor_generator/test/processor/field_processor_test.dart b/floor_generator/test/processor/field_processor_test.dart index 7334bec0..83df54ce 100644 --- a/floor_generator/test/processor/field_processor_test.dart +++ b/floor_generator/test/processor/field_processor_test.dart @@ -16,7 +16,7 @@ void main() { final int id; '''); - final actual = FieldProcessor(fieldElement, null).process(); + final actual = FieldProcessor(fieldElement, null, null).process(); const name = 'id'; const columnName = 'id'; @@ -29,6 +29,7 @@ void main() { isNullable, sqlType, null, + null, ); expect(actual, equals(expected)); }); @@ -38,7 +39,7 @@ void main() { final int? id; '''); - final actual = FieldProcessor(fieldElement, null).process(); + final actual = FieldProcessor(fieldElement, null, null).process(); const name = 'id'; const columnName = 'id'; @@ -51,6 +52,7 @@ void main() { isNullable, sqlType, null, + null, ); expect(actual, equals(expected)); }); @@ -61,7 +63,7 @@ void main() { final Uint8List bytes; '''); - final actual = FieldProcessor(fieldElement, null).process(); + final actual = FieldProcessor(fieldElement, null, null).process(); const name = 'bytes'; const columnName = 'data'; @@ -74,6 +76,7 @@ void main() { isNullable, sqlType, null, + null, ); expect(actual, equals(expected)); }); @@ -89,7 +92,7 @@ void main() { final DateTime dateTime; '''); - final actual = FieldProcessor(fieldElement, typeConverter).process(); + final actual = FieldProcessor(fieldElement, typeConverter, null).process(); const name = 'dateTime'; const columnName = 'dateTime'; @@ -102,6 +105,7 @@ void main() { isNullable, sqlType, typeConverter, + null, ); expect(actual, equals(expected)); }); @@ -112,7 +116,7 @@ void main() { final DateTime dateTime; '''); - final actual = FieldProcessor(fieldElement, null).process(); + final actual = FieldProcessor(fieldElement, null, null).process(); const name = 'dateTime'; const columnName = 'dateTime'; @@ -131,6 +135,7 @@ void main() { isNullable, sqlType, typeConverter, + null, ); expect(actual, equals(expected)); }); @@ -148,7 +153,7 @@ void main() { '''); final actual = - FieldProcessor(fieldElement, externalTypeConverter).process(); + FieldProcessor(fieldElement, externalTypeConverter, null).process(); const name = 'dateTime'; const columnName = 'dateTime'; @@ -167,6 +172,7 @@ void main() { isNullable, sqlType, typeConverter, + null, ); expect(actual, equals(expected)); }); @@ -176,7 +182,7 @@ void main() { '''); expect( - FieldProcessor(fieldElement, null).process, + FieldProcessor(fieldElement, null, null).process, throwsInvalidGenerationSourceError(InvalidGenerationSourceError( 'Column type is not supported for List.', todo: diff --git a/floor_generator/test/processor/query_method_processor_test.dart b/floor_generator/test/processor/query_method_processor_test.dart index 5d1470b5..0ce6bce8 100644 --- a/floor_generator/test/processor/query_method_processor_test.dart +++ b/floor_generator/test/processor/query_method_processor_test.dart @@ -511,7 +511,7 @@ Future> _getEntities() async { return library.classes .where((classElement) => classElement.hasAnnotation(annotations.Entity)) - .map((classElement) => EntityProcessor(classElement, {}).process()) + .map((classElement) => EntityProcessor(classElement, {}, {}).process()) .toList(); } @@ -537,6 +537,6 @@ Future> _getViews() async { return library.classes .where((classElement) => classElement.hasAnnotation(annotations.DatabaseView)) - .map((classElement) => ViewProcessor(classElement, {}).process()) + .map((classElement) => ViewProcessor(classElement, {}, {}).process()) .toList(); } diff --git a/floor_generator/test/processor/queryable_processor_test.dart b/floor_generator/test/processor/queryable_processor_test.dart index 3c5176ed..5b67f2f0 100644 --- a/floor_generator/test/processor/queryable_processor_test.dart +++ b/floor_generator/test/processor/queryable_processor_test.dart @@ -26,7 +26,8 @@ void main() { final actual = TestProcessor(classElement).process(); final fields = classElement.fields - .map((fieldElement) => FieldProcessor(fieldElement, null).process()) + .map((fieldElement) => + FieldProcessor(fieldElement, null, null).process()) .toList(); const constructor = "Person(row['id'] as int, row['name'] as String)"; final expected = TestQueryable( @@ -57,9 +58,10 @@ void main() { final actual = TestProcessor(classElement, {typeConverter}).process(); - final idField = FieldProcessor(classElement.fields[0], null).process(); + final idField = + FieldProcessor(classElement.fields[0], null, null).process(); final dateTimeField = - FieldProcessor(classElement.fields[1], typeConverter).process(); + FieldProcessor(classElement.fields[1], typeConverter, null).process(); final fields = [idField, dateTimeField]; const constructor = "Order(row['id'] as int, _typeConverter.decode(row['dateTime'] as int))"; @@ -103,9 +105,10 @@ void main() { await intDartType, TypeConverterScope.queryable, ); - final idField = FieldProcessor(classElement.fields[0], null).process(); + final idField = + FieldProcessor(classElement.fields[0], null, null).process(); final dateTimeField = - FieldProcessor(classElement.fields[1], typeConverter).process(); + FieldProcessor(classElement.fields[1], typeConverter, null).process(); final fields = [idField, dateTimeField]; const constructor = "Order(row['id'] as int, _dateTimeConverter.decode(row['dateTime'] as int))"; @@ -157,9 +160,10 @@ void main() { await intDartType, TypeConverterScope.queryable, ); - final idField = FieldProcessor(classElement.fields[0], null).process(); + final idField = + FieldProcessor(classElement.fields[0], null, null).process(); final dateTimeField = - FieldProcessor(classElement.fields[1], typeConverter).process(); + FieldProcessor(classElement.fields[1], typeConverter, null).process(); final fields = [idField, dateTimeField]; const constructor = "Order(row['id'] as int, _dateTimeConverter.decode(row['dateTime'] as int))"; @@ -689,7 +693,7 @@ class TestProcessor extends QueryableProcessor { TestProcessor( ClassElement classElement, [ Set? typeConverters, - ]) : super(classElement, typeConverters ?? {}); + ]) : super(classElement, typeConverters ?? {}, {}); @override TestQueryable process() { diff --git a/floor_generator/test/processor/view_processor_test.dart b/floor_generator/test/processor/view_processor_test.dart index 44aa6de9..55fc776d 100644 --- a/floor_generator/test/processor/view_processor_test.dart +++ b/floor_generator/test/processor/view_processor_test.dart @@ -18,11 +18,12 @@ void main() { } '''); - final actual = ViewProcessor(classElement, {}).process(); + final actual = ViewProcessor(classElement, {}, {}).process(); const name = 'Person'; final fields = classElement.fields - .map((fieldElement) => FieldProcessor(fieldElement, null).process()) + .map((fieldElement) => + FieldProcessor(fieldElement, null, null).process()) .toList(); const query = 'SELECT * from otherentity'; const constructor = "Person(row['id'] as int, row['name'] as String)"; @@ -48,11 +49,12 @@ void main() { } '''); - final actual = ViewProcessor(classElement, {}).process(); + final actual = ViewProcessor(classElement, {}, {}).process(); const name = 'Person'; final fields = classElement.fields - .map((fieldElement) => FieldProcessor(fieldElement, null).process()) + .map((fieldElement) => + FieldProcessor(fieldElement, null, null).process()) .toList(); const query = 'WITH subquery as (SELECT * from otherentity) SELECT subquery.*'; @@ -78,7 +80,7 @@ void main() { } '''); - final actual = () => ViewProcessor(classElement, {}).process(); + final actual = () => ViewProcessor(classElement, {}, {}).process(); expect(actual, throwsInvalidGenerationSourceError()); }); @@ -97,7 +99,7 @@ void main() { } '''); - final actual = () => ViewProcessor(classElement, {}).process(); + final actual = () => ViewProcessor(classElement, {}, {}).process(); expect(actual, throwsInvalidGenerationSourceError()); }); @@ -116,7 +118,7 @@ void main() { } '''); - final actual = () => ViewProcessor(classElement, {}).process(); + final actual = () => ViewProcessor(classElement, {}, {}).process(); expect(actual, throwsInvalidGenerationSourceError()); }); @@ -135,7 +137,7 @@ void main() { } """); - final actual = ViewProcessor(classElement, {}).process().query; + final actual = ViewProcessor(classElement, {}, {}).process().query; const expected = ''' SELECT * @@ -157,7 +159,7 @@ void main() { } '''); - final actual = ViewProcessor(classElement, {}).process().query; + final actual = ViewProcessor(classElement, {}, {}).process().query; const expected = 'SELECT * from otherentity'; expect(actual, equals(expected)); @@ -175,11 +177,12 @@ void main() { } '''); - final actual = ViewProcessor(classElement, {}).process(); + final actual = ViewProcessor(classElement, {}, {}).process(); const name = 'personview'; final fields = classElement.fields - .map((fieldElement) => FieldProcessor(fieldElement, null).process()) + .map((fieldElement) => + FieldProcessor(fieldElement, null, null).process()) .toList(); const query = 'SELECT * from otherentity'; const constructor = "Person(row['id'] as int, row['name'] as String)"; diff --git a/floor_generator/test/test_utils.dart b/floor_generator/test/test_utils.dart index 0a5960ae..2363bf3a 100644 --- a/floor_generator/test/test_utils.dart +++ b/floor_generator/test/test_utils.dart @@ -190,12 +190,12 @@ Future createDao(final String methodSignature) async { final entities = library.classes .where((classElement) => classElement.hasAnnotation(annotations.Entity)) - .map((classElement) => EntityProcessor(classElement, {}).process()) + .map((classElement) => EntityProcessor(classElement, {}, {}).process()) .toList(); final views = library.classes .where((classElement) => classElement.hasAnnotation(annotations.DatabaseView)) - .map((classElement) => ViewProcessor(classElement, {}).process()) + .map((classElement) => ViewProcessor(classElement, {}, {}).process()) .toList(); return DaoProcessor( @@ -260,7 +260,7 @@ Future getPersonEntity() async { return library.classes .where((classElement) => classElement.hasAnnotation(annotations.Entity)) - .map((classElement) => EntityProcessor(classElement, {}).process()) + .map((classElement) => EntityProcessor(classElement, {}, {}).process()) .first; } diff --git a/floor_generator/test/value_object/entity_test.dart b/floor_generator/test/value_object/entity_test.dart index 013fa912..ce0952da 100644 --- a/floor_generator/test/value_object/entity_test.dart +++ b/floor_generator/test/value_object/entity_test.dart @@ -14,14 +14,8 @@ void main() { final fakeClassElement = FakeClassElement(); final fakeFieldElement = FakeFieldElement(); - final field = Field( - fakeFieldElement, - 'field1Name', - 'field1ColumnName', - false, - SqlType.integer, - null, - ); + final field = Field(fakeFieldElement, 'field1Name', 'field1ColumnName', false, + SqlType.integer, null, null); final nullableField = Field( fakeFieldElement, 'field2Name', @@ -29,6 +23,7 @@ void main() { true, SqlType.text, null, + null, ); final allFields = [field, nullableField]; diff --git a/floor_generator/test/value_object/field_test.dart b/floor_generator/test/value_object/field_test.dart index e01f8b26..20610013 100644 --- a/floor_generator/test/value_object/field_test.dart +++ b/floor_generator/test/value_object/field_test.dart @@ -16,6 +16,7 @@ void main() { false, SqlType.integer, null, + null, ); final actual = field.getDatabaseDefinition(autoGenerate); @@ -34,6 +35,7 @@ void main() { true, SqlType.text, null, + null, ); final actual = field.getDatabaseDefinition(autoGenerate); diff --git a/floor_generator/test/value_object/view_test.dart b/floor_generator/test/value_object/view_test.dart index 78a494b3..032d3c43 100644 --- a/floor_generator/test/value_object/view_test.dart +++ b/floor_generator/test/value_object/view_test.dart @@ -16,6 +16,7 @@ void main() { false, SqlType.integer, null, + null, ); final nullableField = Field( fakeFieldElement, @@ -24,6 +25,7 @@ void main() { true, SqlType.text, null, + null, ); final allFields = [field, nullableField]; diff --git a/floor_generator/test/writer/dao_writer_test.dart b/floor_generator/test/writer/dao_writer_test.dart index cbf940ce..2f2c4972 100644 --- a/floor_generator/test/writer/dao_writer_test.dart +++ b/floor_generator/test/writer/dao_writer_test.dart @@ -445,13 +445,13 @@ Future _createDao(final String dao) async { final entities = library.classes .where((classElement) => classElement.hasAnnotation(annotations.Entity)) - .map((classElement) => EntityProcessor(classElement, {}).process()) + .map((classElement) => EntityProcessor(classElement, {}, {}).process()) .toList(); final views = library.classes .where((classElement) => classElement.hasAnnotation(annotations.DatabaseView)) - .map((classElement) => ViewProcessor(classElement, {}).process()) + .map((classElement) => ViewProcessor(classElement, {}, {}).process()) .toList(); return DaoProcessor( diff --git a/floor_generator/test/writer/query_method_writer_test.dart b/floor_generator/test/writer/query_method_writer_test.dart index caac2306..bc285602 100644 --- a/floor_generator/test/writer/query_method_writer_test.dart +++ b/floor_generator/test/writer/query_method_writer_test.dart @@ -897,10 +897,8 @@ Future createOrderDao( final entities = library.classes .where((classElement) => classElement.hasAnnotation(annotations.Entity)) - .map((classElement) => EntityProcessor( - classElement, - typeConverters, - ).process()) + .map((classElement) => + EntityProcessor(classElement, typeConverters, {}).process()) .toList(); return DaoProcessor(