diff --git a/docs/pages/docs/Getting started/advanced_dart_tables.md b/docs/pages/docs/Getting started/advanced_dart_tables.md index ed991a14..deef704b 100644 --- a/docs/pages/docs/Getting started/advanced_dart_tables.md +++ b/docs/pages/docs/Getting started/advanced_dart_tables.md @@ -288,6 +288,12 @@ describes how to migrate stored columns between the format: {% assign snippets = "package:drift_docs/snippets/migrations/datetime_conversion.dart.excerpt.json" | readString | json_decode %} +Note that the JSON serialization generated by default is not affected by the +datetime mode chosen. By default, drift will serialize `DateTime` values to a +unix timestamp in milliseconds. You can change this by creating a +`ValueSerializer.defaults(serializeDateTimeValuesAsString: true)` and assigning +it to `driftRuntimeOptions.defaultSerializer`. + ##### Migrating from unix timestamps to text To migrate from using timestamps (the default option) to storing datetimes as diff --git a/docs/pages/docs/index.md b/docs/pages/docs/index.md index d976eda5..94621b48 100644 --- a/docs/pages/docs/index.md +++ b/docs/pages/docs/index.md @@ -1,5 +1,5 @@ --- -data: +data: title: "Documentation & Guides" description: Welcome to drift's documentation. This site shows you what drift can do and how to use it. template: layouts/docs/list @@ -8,7 +8,7 @@ template: layouts/docs/list ## Welcome to drift Drift is a reactive persistence library for Dart and Flutter applications. It's built on top -of database libraries like [sqflite](https://pub.dev/packages/sqflite) or [sql.js](https://github.com/sql-js/sql.js/) +of database libraries like [the sqlite3 package](https://pub.dev/packages/sqlite3), [sqflite](https://pub.dev/packages/sqflite) or [sql.js](https://github.com/sql-js/sql.js/) and provides additional features, like: - __Type safety__: Instead of writing sql queries manually and parsing the `List>` that they diff --git a/docs/pages/index.html b/docs/pages/index.html index 7965babe..c65cdac1 100644 --- a/docs/pages/index.html +++ b/docs/pages/index.html @@ -7,47 +7,76 @@ data: show_favorites: true --- -{% block "blocks/cover.html" title="Drift: Persistence library for Dart" image_anchor="top" height="med" color="indigo" %} +{% block "blocks/cover.html" title="Drift: Persistence library for Dart" image_anchor="top" height="med" %}
+

+ Drift is the relational persistence library for your Dart and Flutter apps. + Write type-safe queries in Dart or SQL, enjoy auto-updating streams, easily managed transactions + and so much more to make persistence fun. +

Learn more - Get from pub + Get started - -

- With a fluent query api, a powerful sql analyzer, auto-updating streams and much more, - drift makes persistence fun. Scroll down to learn about its key features, or visit the - getting started guide for a step-by-step guide on using drift. -

{% endblock %} -{% block "blocks/lead.html" color="dark" %} -Drift is an easy to use, reactive persistence library for Flutter apps. Define tables in Dart or -SQL and enjoy a fluent query API, auto-updating streams and more! -{% endblock %} - {% block "blocks/section.html" color="primary" %} {% block "blocks/feature.html" icon="fas fa-lightbulb" title="Declarative tables, fluent queries" %} {% block "blocks/markdown.html" %} -With drift, you can write your database tables in pure Dart without having to miss out on -advanced sqlite features. Drift will take care of creating the tables and generate code +With drift, you can declare your database tables and queries in pure Dart without having to miss out on +advanced SQL features. Drift will take care of creating the tables and generate code that allows you run fluent queries on your data. [Get started now]({{ "docs/Getting started/index.md" | pageUrl }}) {% endblock %} {% endblock %} -{% block "blocks/feature.html" icon="fas fa-database" title="Prefer SQL? Drift got you covered!" %} +{% block "blocks/feature.html" icon="fas fa-database" title="Definitely relational" %} {% block "blocks/markdown.html" %} -Drift contains a powerful sql parser and analyzer, allowing it to create typesafe APIs for all your sql queries. All sql queries are +Drift is not the kind of ORM that tries to hide SQL away and then breaks down at the first +aggregation or non-obvious join. + +Instead, drift embraces relational databases with an Dart API that's easy to learn +while still being close to SQL. Advanced expressions or subqueries are supported out of +the box. +{% endblock %} +{% endblock %} + +{% block "blocks/feature.html" icon="fas fa-lightbulb" title="Safe schemas" %} +{% block "blocks/markdown.html" %} +A well-chosen SQL schema enables type-safe queries and avoids hard-to-spot mistakes. +Thanks to drift's extensive support for schema migrations, changing schemas is a safe +and easy process. +Further, drift provides a complete test toolkit to help you test migrations +between all your revisions. + +[All about schema migrations]({{ "docs/Advanced Features/migrations.md" | pageUrl }}) +{% endblock %} +{% endblock %} + +{% block "blocks/feature.html" icon="fas fa-database" title="Prefer SQL? Drift's got you covered!" %} +{% block "blocks/markdown.html" %} +Drift ships a powerful sql parser and analyzer, allowing it to create typesafe methods for all your sql queries. All sql queries are validated and analyzed during build-time, so drift can provide hints about potential errors quickly and generate efficient mapping code. +Of course, you can mix SQL and Dart to your liking. -[Learn more]({{ 'docs/Using SQL/index.md' | pageUrl }}) +[Using SQL with Drift]({{ 'docs/Using SQL/index.md' | pageUrl }}) +{% endblock %} +{% endblock %} + +{% block "blocks/feature.html" icon="fas fa-lightbulb" title="Supported on your favorite platform" %} +{% block "blocks/markdown.html" %} +Drift's core APIs are written to support a range of database libraries as backends, it doesn't even require Flutter. +Drift has primary first-class support for Android, iOS, macOS, Linux Windows and the web. + +Other database libraries can easily be integrated into drift as well. + +[All platforms]({{ "docs/platforms.md" | pageUrl }}) {% endblock %} {% endblock %} @@ -60,25 +89,3 @@ When using drift, working with databases in Dart is fun! {% endblock %} {% endblock %} - -{% block "blocks/section.html" color="light" type="section" %} -{% block "blocks/markdown.html" %} -## Key features - -Here are some of the many ways drift helps you write awesome database code: - - * __Auto-updating streams__: With drift, any query - no matter how complex - can be turned into a stream that emits new data as the underlying data changes. - * __Polyglot__: Drift lets you write queries in a fluent Dart api or directly in SQL - you can even embed Dart expressions in SQL. - * __Boilerplate-free__: Stop writing mapping code yourself - drift can take of that. Drift generates Dart code around your data so you can focus - on building great apps. - * __Flexible__: Want to write queries in SQL? Drift verifies them at compile time and generates Dart apis for them. Prefer to write them in Dart? - Drift will generate efficient SQL for Dart queries too. - * __Easy to learn__: Instead of having to learn yet another ORM, drift lets you write queries in SQL and generates typesafe wrappers. Queries and tables - can also be written in Dart that looks similar to SQL without loosing type-safety. - * __Fast _and_ powerful__: With the new `ffi` backend, drift can outperform key-value stores without putting any compromises on the integrity - and flexibility that relational databases provide. Drift is the only major persistence library with builtin support for multiple isolates. - * __Well tested and production ready__: Each component of drift is verified by a wide range of unit and integration tests. Drift powers many Flutter apps - in production. - * __Cross-Platform__: Drift works on iOS, Android, Linux, macOS, Windows and on the web. It doesn't even require Flutter. See [supported platforms]({{ "docs/platforms.md" | pageUrl }}). -{% endblock %} -{% endblock %} diff --git a/docs/pubspec.yaml b/docs/pubspec.yaml index dd500ece..128756ef 100644 --- a/docs/pubspec.yaml +++ b/docs/pubspec.yaml @@ -38,8 +38,6 @@ dev_dependencies: drift_dev: dependency_overrides: - # Waiting for dartdoc, https://github.com/dart-lang/dartdoc/pull/3033 - analyzer: ^4.0.0 moor_generator: path: ../moor_generator drift: diff --git a/docs/templates/partials/footer.html b/docs/templates/partials/footer.html new file mode 100644 index 00000000..a8f984d1 --- /dev/null +++ b/docs/templates/partials/footer.html @@ -0,0 +1,31 @@ +{% assign links = site.links %} + diff --git a/drift/lib/src/dsl/table.dart b/drift/lib/src/dsl/table.dart index be47cba0..ba43f10d 100644 --- a/drift/lib/src/dsl/table.dart +++ b/drift/lib/src/dsl/table.dart @@ -158,11 +158,19 @@ abstract class Table extends HasResultSet { ColumnBuilder boolean() => _isGenerated(); /// Use this as the body of a getter to declare a column that holds date and - /// time. Note that [DateTime] values are stored on a second-accuracy. + /// time. + /// + /// Drift supports two modes for storing date times: As unix timestamp with + /// second accuracy (the default) and as ISO 8601 string with microsecond + /// accuracy. For more information between the modes, and information on how + /// to change them, see [the documentation]. + /// + /// Note that [DateTime] values are stored on a second-accuracy. /// Example (inside the body of a table class): /// ``` /// DateTimeColumn get accountCreatedAt => dateTime()(); /// ``` + /// [the documentation]: https://drift.simonbinder.eu/docs/getting-started/advanced_dart_tables/#supported-column-types @protected ColumnBuilder dateTime() => _isGenerated(); diff --git a/drift/lib/src/runtime/data_class.dart b/drift/lib/src/runtime/data_class.dart index 81eb66d2..c1d73213 100644 --- a/drift/lib/src/runtime/data_class.dart +++ b/drift/lib/src/runtime/data_class.dart @@ -188,7 +188,14 @@ abstract class ValueSerializer { /// /// To override the default serializer drift uses, you can change the /// [DriftRuntimeOptions.defaultSerializer] field. - const factory ValueSerializer.defaults() = _DefaultValueSerializer; + /// + /// The [serializeDateTimeValuesAsString] option (which defaults to `false`) + /// describes whether [DateTime] values should be serialized to a unix + /// timestamp ([DateTime.millisecondsSinceEpoch]) or a string + /// ([DateTime.toIso8601String]). + /// In either case, date time values can be _deserialized_ from both formats. + const factory ValueSerializer.defaults( + {bool serializeDateTimeValuesAsString}) = _DefaultValueSerializer; /// Converts the [value] to something that can be passed to /// [JsonCodec.encode]. @@ -200,7 +207,9 @@ abstract class ValueSerializer { } class _DefaultValueSerializer extends ValueSerializer { - const _DefaultValueSerializer(); + final bool serializeDateTimeValuesAsString; + + const _DefaultValueSerializer({this.serializeDateTimeValuesAsString = false}); @override T fromJson(dynamic json) { @@ -211,7 +220,11 @@ class _DefaultValueSerializer extends ValueSerializer { final _typeList = []; if (_typeList is List) { - return DateTime.fromMillisecondsSinceEpoch(json as int) as T; + if (json is int) { + return DateTime.fromMillisecondsSinceEpoch(json) as T; + } else { + return DateTime.parse(json.toString()) as T; + } } if (_typeList is List && json is int) { @@ -231,7 +244,9 @@ class _DefaultValueSerializer extends ValueSerializer { @override dynamic toJson(T value) { if (value is DateTime) { - return value.millisecondsSinceEpoch; + return serializeDateTimeValuesAsString + ? value.toIso8601String() + : value.millisecondsSinceEpoch; } return value; diff --git a/drift/test/database/expressions/expressions_integration_test.dart b/drift/test/database/expressions/expressions_integration_test.dart index d83aa132..7da7bc4d 100644 --- a/drift/test/database/expressions/expressions_integration_test.dart +++ b/drift/test/database/expressions/expressions_integration_test.dart @@ -48,6 +48,12 @@ void _testWith(TodoDb Function() openDb, {bool dateTimeAsText = false}) { expect(await eval(Variable(local)), local); }, ); + + test('preserves milliseconds', () async { + final local = DateTime(2020, 09, 03, 23, 55, 0, 123); + + expect(await eval(Variable(local)), local); + }); } test('plus and minus', () async { diff --git a/drift/test/database/validate_schema_test.dart b/drift/test/database/validate_schema_test.dart index fb38223b..167ac325 100644 --- a/drift/test/database/validate_schema_test.dart +++ b/drift/test/database/validate_schema_test.dart @@ -17,8 +17,8 @@ void main() { await expectLater( db.validateDatabaseSchema(), - throwsA(isA().having( - (e) => e.toString(), 'toString()', contains('TEXT and INTEGER'))), + throwsA(isA().having((e) => e.toString(), 'toString()', + contains('Expected TEXT, got INTEGER'))), ); }); } diff --git a/drift/test/serialization_test.dart b/drift/test/serialization_test.dart index 5461b0dd..c04b00b9 100644 --- a/drift/test/serialization_test.dart +++ b/drift/test/serialization_test.dart @@ -2,29 +2,37 @@ import 'package:drift/drift.dart'; import 'package:test/test.dart'; import 'generated/todos.dart'; -final DateTime someDate = DateTime(2019, 06, 08); +final DateTime _someDate = DateTime(2019, 06, 08); -final TodoEntry someTodoEntry = TodoEntry( +final TodoEntry _someTodoEntry = TodoEntry( id: 3, title: null, content: 'content', - targetDate: someDate, + targetDate: _someDate, category: 3, ); -final Map regularSerialized = { +final Map _regularSerialized = { 'id': 3, 'title': null, 'content': 'content', - 'target_date': someDate.millisecondsSinceEpoch, + 'target_date': _someDate.millisecondsSinceEpoch, 'category': 3, }; -final Map customSerialized = { +final Map _asTextSerialized = { + 'id': 3, + 'title': null, + 'content': 'content', + 'target_date': _someDate.toIso8601String(), + 'category': 3, +}; + +final Map _customSerialized = { 'id': 3, 'title': 'set to null', 'content': 'content', - 'target_date': someDate.toIso8601String(), + 'target_date': _someDate.toIso8601String(), 'category': 3, }; @@ -61,7 +69,16 @@ void main() { group('serialization', () { test('with defaults', () { - expect(someTodoEntry.toJson(), equals(regularSerialized)); + expect(_someTodoEntry.toJson(), equals(_regularSerialized)); + }); + + test('with default serializer, date as text', () { + expect( + _someTodoEntry.toJson( + serializer: const ValueSerializer.defaults( + serializeDateTimeValuesAsString: true)), + equals(_asTextSerialized), + ); }); test('applies json type converter', () { @@ -71,20 +88,31 @@ void main() { }); test('with custom serializer', () { - expect(someTodoEntry.toJson(serializer: CustomSerializer()), - equals(customSerialized)); + expect(_someTodoEntry.toJson(serializer: CustomSerializer()), + equals(_customSerialized)); }); }); group('deserialization', () { test('with defaults', () { - expect(TodoEntry.fromJson(regularSerialized), equals(someTodoEntry)); + expect(TodoEntry.fromJson(_regularSerialized), equals(_someTodoEntry)); + expect(TodoEntry.fromJson(_asTextSerialized), equals(_someTodoEntry)); + }); + + test('with date-as-text serializer', () { + const serializer = + ValueSerializer.defaults(serializeDateTimeValuesAsString: true); + + expect(TodoEntry.fromJson(_regularSerialized, serializer: serializer), + equals(_someTodoEntry)); + expect(TodoEntry.fromJson(_asTextSerialized, serializer: serializer), + equals(_someTodoEntry)); }); test('with custom serializer', () { expect( - TodoEntry.fromJson(customSerialized, serializer: CustomSerializer()), - equals(someTodoEntry)); + TodoEntry.fromJson(_customSerialized, serializer: CustomSerializer()), + equals(_someTodoEntry)); }); }); } diff --git a/drift_dev/lib/src/analyzer/dart/column_parser.dart b/drift_dev/lib/src/analyzer/dart/column_parser.dart index 63997b9e..1db392fb 100644 --- a/drift_dev/lib/src/analyzer/dart/column_parser.dart +++ b/drift_dev/lib/src/analyzer/dart/column_parser.dart @@ -337,7 +337,7 @@ class ColumnParser { if (foundExplicitName != null) { name = ColumnName.explicitly(foundExplicitName); } else { - name = ColumnName.implicitly(ReCase(getter.name.name).snakeCase); + name = ColumnName.implicitly(ReCase(getter.name2.lexeme).snakeCase); } final columnType = _startMethodToColumnType(foundStartMethod); @@ -424,7 +424,7 @@ class ColumnParser { getter.documentationComment?.tokens.map((t) => t.toString()).join('\n'); return DriftColumn( type: columnType, - dartGetterName: getter.name.name, + dartGetterName: getter.name2.lexeme, name: name, overriddenJsonName: _readJsonKey(element), customConstraints: foundCustomConstraint, @@ -456,9 +456,11 @@ class ColumnParser { final annotations = getter.metadata; final object = annotations.firstWhereOrNull((e) { final value = e.computeConstantValue(); - return value != null && - isFromMoor(value.type!) && - value.type!.element!.name == 'JsonKey'; + final valueType = value?.type; + + return valueType is InterfaceType && + isFromDrift(valueType) && + valueType.element2.name == 'JsonKey'; }); if (object == null) return null; diff --git a/drift_dev/lib/src/analyzer/dart/table_parser.dart b/drift_dev/lib/src/analyzer/dart/table_parser.dart index fd4b592d..794e4bc4 100644 --- a/drift_dev/lib/src/analyzer/dart/table_parser.dart +++ b/drift_dev/lib/src/analyzer/dart/table_parser.dart @@ -85,7 +85,7 @@ class TableParser { for (final annotation in element.metadata) { final computed = annotation.computeConstantValue(); - final annotationClass = computed!.type!.element!.name; + final annotationClass = computed!.type!.nameIfInterfaceType; if (annotationClass == 'DataClassName') { dataClassName = computed; @@ -124,8 +124,8 @@ class TableParser { useRowClass.getField('generateInsertable')!.toBoolValue()!; if (type is InterfaceType) { - existingClass = FoundDartClass(type.element, type.typeArguments); - name = type.element.name; + existingClass = FoundDartClass(type.element2, type.typeArguments); + name = type.element2.name; } else { base.step.reportError(ErrorInDartCode( message: 'The @UseRowClass annotation must be used with a class', @@ -309,7 +309,7 @@ class TableParser { Future> _parseColumns(ClassElement element) async { final columnNames = element.allSupertypes - .map((t) => t.element) + .map((t) => t.element2) .followedBy([element]) .expand((e) => e.fields) .where((field) => @@ -350,10 +350,10 @@ class _DataClassInformation { extension on Element { bool get isFromDefaultTable { - final parent = enclosingElement2; + final parent = enclosingElement3; return parent is ClassElement && parent.name == 'Table' && - isFromMoor(parent.thisType); + isFromDrift(parent.thisType); } } diff --git a/drift_dev/lib/src/analyzer/dart/use_dao_parser.dart b/drift_dev/lib/src/analyzer/dart/use_dao_parser.dart index 483fee15..36457837 100644 --- a/drift_dev/lib/src/analyzer/dart/use_dao_parser.dart +++ b/drift_dev/lib/src/analyzer/dart/use_dao_parser.dart @@ -9,7 +9,7 @@ class UseDaoParser { /// declared by that class and the referenced tables. Future parseDao(ClassElement element, ConstantReader annotation) async { final dbType = element.allSupertypes - .firstWhereOrNull((i) => i.element.name == 'DatabaseAccessor'); + .firstWhereOrNull((i) => i.element2.name == 'DatabaseAccessor'); if (dbType == null) { step.reportError(ErrorInDartCode( diff --git a/drift_dev/lib/src/analyzer/dart/view_parser.dart b/drift_dev/lib/src/analyzer/dart/view_parser.dart index a21ecd9a..2aefe733 100644 --- a/drift_dev/lib/src/analyzer/dart/view_parser.dart +++ b/drift_dev/lib/src/analyzer/dart/view_parser.dart @@ -41,7 +41,7 @@ class ViewParser { for (final annotation in element.metadata) { final computed = annotation.computeConstantValue(); - final annotationClass = computed!.type!.element!.name; + final annotationClass = computed!.type!.nameIfInterfaceType; if (annotationClass == 'DriftView') { driftView = computed; @@ -80,8 +80,8 @@ class ViewParser { useRowClass.getField('generateInsertable')!.toBoolValue()!; if (type is InterfaceType) { - existingClass = FoundDartClass(type.element, type.typeArguments); - name = type.element.name; + existingClass = FoundDartClass(type.element2, type.typeArguments); + name = type.element2.name; } else { base.step.reportError(ErrorInDartCode( message: 'The @UseRowClass annotation must be used with a class', @@ -100,7 +100,7 @@ class ViewParser { Future _parseViewName(ClassElement element) async { for (final annotation in element.metadata) { final computed = annotation.computeConstantValue(); - final annotationClass = computed!.type!.element!.name; + final annotationClass = computed!.type!.nameIfInterfaceType; if (annotationClass == 'DriftView') { final name = computed.getField('name')?.toStringValue(); @@ -116,7 +116,7 @@ class ViewParser { Future> _parseColumns(ClassElement element) async { final columnNames = element.allSupertypes - .map((t) => t.element) + .map((t) => t.element2) .followedBy([element]) .expand((e) => e.fields) .where((field) => @@ -134,7 +134,7 @@ class ViewParser { final results = await Future.wait(fields.map((field) async { final dartType = (field.type as InterfaceType).typeArguments[0]; - final typeName = dartType.element!.name!; + final typeName = dartType.nameIfInterfaceType!; final sqlType = _dartTypeToColumnType(typeName); if (sqlType == null) { @@ -181,7 +181,7 @@ class ViewParser { Future> _parseStaticReferences( ClassElement element, List tables) async { return await Stream.fromIterable(element.allSupertypes - .map((t) => t.element) + .map((t) => t.element2) .followedBy([element]).expand((e) => e.fields)) .asyncMap((field) => _getStaticReference(field, tables)) .where((ref) => ref != null) @@ -198,7 +198,7 @@ class ViewParser { final type = tables.firstWhereOrNull( (tbl) => tbl.fromClass!.name == node.returnType.toString()); if (type != null) { - final name = node.name.toString(); + final name = node.name2.lexeme; return TableReferenceInDartView(type, name); } } diff --git a/drift_dev/lib/src/analyzer/dart_types.dart b/drift_dev/lib/src/analyzer/dart_types.dart index bccbf235..ea5f97d6 100644 --- a/drift_dev/lib/src/analyzer/dart_types.dart +++ b/drift_dev/lib/src/analyzer/dart_types.dart @@ -11,7 +11,7 @@ import 'package:drift_dev/src/analyzer/runner/steps.dart'; import 'helper.dart'; class FoundDartClass { - final ClassElement classElement; + final InterfaceElement classElement; /// The instantiation of the [classElement], if the found type was a generic /// typedef. @@ -230,8 +230,8 @@ void _checkType( final isAllowedUint8List = typeConverter == null && columnType == DriftSqlType.blob && typeToCheck is InterfaceType && - typeToCheck.element.name == 'Uint8List' && - typeToCheck.element.library.name == 'dart.typed_data'; + typeToCheck.element2.name == 'Uint8List' && + typeToCheck.element2.library.name == 'dart.typed_data'; if (!typeSystem.isAssignableTo(expectedDartType.type, typeToCheck) && !isAllowedUint8List) { @@ -246,14 +246,14 @@ extension on TypeProvider { case DriftSqlType.int: return intType; case DriftSqlType.bigInt: - return intElement.library.getType('BigInt')!.instantiate( + return intElement.library.getClass('BigInt')!.instantiate( typeArguments: const [], nullabilitySuffix: NullabilitySuffix.none); case DriftSqlType.string: return stringType; case DriftSqlType.bool: return boolType; case DriftSqlType.dateTime: - return intElement.library.getType('DateTime')!.instantiate( + return intElement.library.getClass('DateTime')!.instantiate( typeArguments: const [], nullabilitySuffix: NullabilitySuffix.none); case DriftSqlType.blob: return listType(intType); diff --git a/drift_dev/lib/src/analyzer/data_class.dart b/drift_dev/lib/src/analyzer/data_class.dart index 28174939..305744a6 100644 --- a/drift_dev/lib/src/analyzer/data_class.dart +++ b/drift_dev/lib/src/analyzer/data_class.dart @@ -28,8 +28,8 @@ String? parseCustomParentClass(String dartTypeName, DartObject dataClassName, if (extending != null && !extending.isNull) { final extendingType = extending.toTypeValue(); if (extendingType is InterfaceType) { - final superType = extendingType.allSupertypes - .any((type) => isFromMoor(type) && type.element.name == 'DataClass'); + final superType = extendingType.allSupertypes.any( + (type) => isFromDrift(type) && type.element2.name == 'DataClass'); if (!superType) { base.step.reportError( ErrorInDartCode( @@ -52,10 +52,10 @@ String? parseCustomParentClass(String dartTypeName, DartObject dataClassName, return null; } - final className = extendingType.element.name; + final className = extendingType.nameIfInterfaceType; if (extendingType.typeArguments.length == 1) { - final genericType = extendingType.typeArguments[0].element?.name; - if (genericType == 'Object' || genericType == 'dynamic') { + final genericType = extendingType.typeArguments[0]; + if (genericType.isDartCoreObject || genericType.isDynamic) { return '$className<$dartTypeName>'; } else { base.step.reportError( diff --git a/drift_dev/lib/src/analyzer/drift/find_dart_class.dart b/drift_dev/lib/src/analyzer/drift/find_dart_class.dart index ee2cf2c7..ffed6d37 100644 --- a/drift_dev/lib/src/analyzer/drift/find_dart_class.dart +++ b/drift_dev/lib/src/analyzer/drift/find_dart_class.dart @@ -28,7 +28,7 @@ Future findDartClass( } else if (foundElement is TypeAliasElement) { final innerType = foundElement.aliasedType; if (innerType is InterfaceType) { - return FoundDartClass(innerType.element, innerType.typeArguments); + return FoundDartClass(innerType.element2, innerType.typeArguments); } } } diff --git a/drift_dev/lib/src/analyzer/runner/steps/parse_dart.dart b/drift_dev/lib/src/analyzer/runner/steps/parse_dart.dart index 1d9f38de..1a9c3b8e 100644 --- a/drift_dev/lib/src/analyzer/runner/steps/parse_dart.dart +++ b/drift_dev/lib/src/analyzer/runner/steps/parse_dart.dart @@ -122,7 +122,7 @@ class ParseDartStep extends Step { Future> parseTables( Iterable types, Element initializedBy) { return Future.wait(types.map((type) { - if (!_tableTypeChecker.isAssignableFrom(type.element!)) { + if (!_tableTypeChecker.isAssignableFromType(type)) { reportError(ErrorInDartCode( severity: Severity.criticalError, message: 'The type $type is not a moor table', @@ -130,7 +130,7 @@ class ParseDartStep extends Step { )); return Future.value(null); } else { - return _parseTable(type.element as ClassElement); + return _parseTable((type as InterfaceType).element2 as ClassElement); } })).then((list) { // only keep tables that were resolved successfully @@ -145,7 +145,7 @@ class ParseDartStep extends Step { Future> parseViews(Iterable types, Element initializedBy, List tables) { return Future.wait(types.map((type) { - if (!_viewTypeChecker.isAssignableFrom(type.element!)) { + if (!_viewTypeChecker.isAssignableFromType(type)) { reportError(ErrorInDartCode( severity: Severity.criticalError, message: 'The type $type is not a drift view', @@ -153,7 +153,8 @@ class ParseDartStep extends Step { )); return Future.value(null); } else { - return _parseView(type.element as ClassElement, tables); + return _parseView( + (type as InterfaceType).element2 as ClassElement, tables); } })).then((list) { // only keep tables that were resolved successfully diff --git a/drift_dev/lib/src/backends/build/generators/dao_generator.dart b/drift_dev/lib/src/backends/build/generators/dao_generator.dart index c719a10c..6c01d742 100644 --- a/drift_dev/lib/src/backends/build/generators/dao_generator.dart +++ b/drift_dev/lib/src/backends/build/generators/dao_generator.dart @@ -21,7 +21,7 @@ class DaoGenerator extends Generator implements BaseGenerator { final daoName = element!.displayName; - final dbTypeName = dao.dbClass.codeString(writer.generationOptions); + final dbTypeName = dao.dbClass.codeString(); classScope.leaf().write('mixin _\$${daoName}Mixin on ' 'DatabaseAccessor<$dbTypeName> {\n'); diff --git a/drift_dev/lib/src/cli/commands/migrate.dart b/drift_dev/lib/src/cli/commands/migrate.dart index 4152fa7f..4e94c739 100644 --- a/drift_dev/lib/src/cli/commands/migrate.dart +++ b/drift_dev/lib/src/cli/commands/migrate.dart @@ -413,7 +413,8 @@ class _Moor2DriftDartRewriter extends GeneralizingAstVisitor { if (type is! InterfaceType) continue; - if (type.element.library.isDartCore && type.element.name == 'pragma') { + if (type.element2.library.isDartCore && + type.element2.name == 'pragma') { final name = value.getField('name')!.toStringValue()!; if (name == 'moor2drift') { @@ -452,8 +453,8 @@ class _Moor2DriftDartRewriter extends GeneralizingAstVisitor { if (type is! InterfaceType || // note that even old moor code uses these names since UseMoor/UseDao // are type aliases to the new interfaces. - (type.element.name != 'DriftDatabase' && - type.element.name != 'DriftAccessor')) { + (type.element2.name != 'DriftDatabase' && + type.element2.name != 'DriftAccessor')) { return; } diff --git a/drift_dev/lib/src/model/base_entity.dart b/drift_dev/lib/src/model/base_entity.dart index 8ef33210..1e73cc4d 100644 --- a/drift_dev/lib/src/model/base_entity.dart +++ b/drift_dev/lib/src/model/base_entity.dart @@ -40,7 +40,7 @@ abstract class DriftEntityWithResultSet extends DriftSchemaEntity { /// The type name of the Dart row class for this result set. /// /// This may contain generics. - String dartTypeCode([GenerationOptions options = const GenerationOptions()]); + String dartTypeCode(); /// The name of the Dart class storing additional properties like type /// converters. @@ -65,7 +65,7 @@ abstract class DriftEntityWithResultSet extends DriftSchemaEntity { /// Information used by the generator to generate code for a custom data class /// written by users. class ExistingRowClass { - final ClassElement targetClass; + final InterfaceElement targetClass; /// The Dart types that should be used to instantiate the [targetClass]. final List typeInstantiation; diff --git a/drift_dev/lib/src/model/sql_query.dart b/drift_dev/lib/src/model/sql_query.dart index f8cefd26..16cf7783 100644 --- a/drift_dev/lib/src/model/sql_query.dart +++ b/drift_dev/lib/src/model/sql_query.dart @@ -142,11 +142,11 @@ abstract class SqlQuery { } if (resultSet.matchingTable != null) { - return resultSet.matchingTable!.table.dartTypeCode(options); + return resultSet.matchingTable!.table.dartTypeCode(); } if (resultSet.singleColumn) { - return resultSet.columns.single.dartTypeCode(options); + return resultSet.columns.single.dartTypeCode(); } return resultClassName; @@ -593,7 +593,7 @@ abstract class FoundElement { bool get hidden => false; /// Dart code for a type representing tis element. - String dartTypeCode([GenerationOptions options = const GenerationOptions()]); + String dartTypeCode(); } /// A semantic interpretation of a [Variable] in a sql statement. @@ -676,8 +676,8 @@ class FoundVariable extends FoundElement implements HasType { } @override - String dartTypeCode([GenerationOptions options = const GenerationOptions()]) { - return OperationOnTypes(this).dartTypeCode(options); + String dartTypeCode() { + return OperationOnTypes(this).dartTypeCode(); } } diff --git a/drift_dev/lib/src/model/types.dart b/drift_dev/lib/src/model/types.dart index 33c55454..a7b19847 100644 --- a/drift_dev/lib/src/model/types.dart +++ b/drift_dev/lib/src/model/types.dart @@ -2,7 +2,6 @@ import 'package:analyzer/dart/element/nullability_suffix.dart'; import 'package:analyzer/dart/element/type.dart'; import 'package:drift_dev/src/model/model.dart'; import 'package:drift_dev/src/utils/type_utils.dart'; -import 'package:drift_dev/writer.dart'; /// Something that has a type. /// @@ -60,14 +59,14 @@ class DriftDartType { return type.getDisplayString(withNullability: withNullability); } - String codeString([GenerationOptions options = const GenerationOptions()]) { + String codeString() { if (overiddenSource != null) { if (nullabilitySuffix == NullabilitySuffix.star) { return getDisplayString(withNullability: false); } return getDisplayString(withNullability: true); } else { - return type.codeString(options); + return type.codeString(); } } } @@ -127,10 +126,10 @@ extension OperationOnTypes on HasType { /// The dart type that matches the values of this column. For instance, if a /// table has declared an `IntColumn`, the matching dart type name would be /// [int]. - String dartTypeCode([GenerationOptions options = const GenerationOptions()]) { + String dartTypeCode() { final converter = typeConverter; if (converter != null) { - var inner = converter.dartType.codeString(options); + var inner = converter.dartType.codeString(); if (converter.canBeSkippedForNulls && nullable) inner += '?'; return isArray ? 'List<$inner>' : inner; } diff --git a/drift_dev/lib/src/model/used_type_converter.dart b/drift_dev/lib/src/model/used_type_converter.dart index 97a58005..e9310d0d 100644 --- a/drift_dev/lib/src/model/used_type_converter.dart +++ b/drift_dev/lib/src/model/used_type_converter.dart @@ -4,7 +4,6 @@ import 'package:analyzer/dart/element/type.dart'; import 'package:analyzer/dart/element/type_provider.dart'; import 'package:drift_dev/src/model/table.dart'; import 'package:drift_dev/src/utils/type_utils.dart'; -import 'package:drift_dev/src/writer/writer.dart'; import 'types.dart'; @@ -92,12 +91,12 @@ class UsedTypeConverter { bool nullable, TypeProvider typeProvider, ) { - if (enumType.element is! ClassElement) { + if (enumType is! InterfaceType) { throw InvalidTypeForEnumConverterException('Not a class', enumType); } - final creatingClass = enumType.element as ClassElement; - if (!creatingClass.isEnum) { + final creatingClass = enumType.element2; + if (creatingClass is! EnumElement) { throw InvalidTypeForEnumConverterException('Not an enum', enumType); } @@ -132,23 +131,22 @@ class UsedTypeConverter { return dartTypeIsNullable || (canBeSkippedForNulls && nullableInSql); } - String dartTypeCode(GenerationOptions options, bool nullableInSql) { - var type = dartType.codeString(options); + String dartTypeCode(bool nullableInSql) { + var type = dartType.codeString(); if (canBeSkippedForNulls && nullableInSql) type += '?'; return type; } /// A suitable typename to store an instance of the type converter used here. - String converterNameInCode(GenerationOptions options, - {bool makeNullable = false}) { + String converterNameInCode({bool makeNullable = false}) { var sqlDartType = sqlType.getDisplayString(withNullability: true); if (makeNullable) sqlDartType += '?'; final className = alsoAppliesToJsonConversion ? 'JsonTypeConverter' : 'TypeConverter'; - return '$className<${dartTypeCode(options, makeNullable)}, $sqlDartType>'; + return '$className<${dartTypeCode(makeNullable)}, $sqlDartType>'; } } diff --git a/drift_dev/lib/src/services/schema/find_differences.dart b/drift_dev/lib/src/services/schema/find_differences.dart index 92cd3c8e..60895b8d 100644 --- a/drift_dev/lib/src/services/schema/find_differences.dart +++ b/drift_dev/lib/src/services/schema/find_differences.dart @@ -166,7 +166,7 @@ class FindSchemaDifferences { if (refType != actType) { return FoundDifference( - 'Different types: ${ref.typeName} and ${act.typeName}'); + 'Different types: Expected ${ref.typeName}, got ${act.typeName}'); } try { @@ -174,19 +174,20 @@ class FindSchemaDifferences { } catch (e) { final firstSpan = ref.constraints.spanOrNull?.text ?? ''; final secondSpan = act.constraints.spanOrNull?.text ?? ''; - return FoundDifference('Not equal: `$firstSpan` and `$secondSpan`'); + return FoundDifference( + 'Not equal: `$firstSpan` (expected) and `$secondSpan` (actual)'); } return const Success(); } - CompareResult _compareByAst(AstNode a, AstNode b) { + CompareResult _compareByAst(AstNode reference, AstNode actual) { try { - enforceEqual(a, b); + enforceEqual(reference, actual); return const Success(); } catch (e) { - return FoundDifference( - 'Not equal: `${a.span?.text}` and `${b.span?.text}`'); + return FoundDifference('Not equal: Expected `${reference.span?.text}`, ' + 'got `${actual.span?.text}`'); } } diff --git a/drift_dev/lib/src/utils/type_utils.dart b/drift_dev/lib/src/utils/type_utils.dart index 93611258..7a19c457 100644 --- a/drift_dev/lib/src/utils/type_utils.dart +++ b/drift_dev/lib/src/utils/type_utils.dart @@ -1,34 +1,40 @@ import 'package:analyzer/dart/element/nullability_suffix.dart'; import 'package:analyzer/dart/element/type.dart'; -import 'package:drift_dev/src/writer/writer.dart'; -bool isFromMoor(DartType type) { - final firstComponent = type.element?.library?.location?.components.first; +bool isFromDrift(DartType type) { + if (type is! InterfaceType) return false; + final firstComponent = type.element2.library.location?.components.first; if (firstComponent == null) return false; return firstComponent.contains('drift') || firstComponent.contains('moor'); } bool isColumn(DartType type) { - final name = type.element?.name ?? ''; + final name = type.nameIfInterfaceType; - return isFromMoor(type) && + return isFromDrift(type) && + name != null && name.contains('Column') && !name.contains('Builder'); } bool isExpression(DartType type) { - final name = type.element?.name ?? ''; + final name = type.nameIfInterfaceType; - return isFromMoor(type) && name.startsWith('Expression'); + return name != null && isFromDrift(type) && name.startsWith('Expression'); } extension TypeUtils on DartType { + String? get nameIfInterfaceType { + final $this = this; + return $this is InterfaceType ? $this.element2.name : null; + } + String get userVisibleName => getDisplayString(withNullability: true); /// How this type should look like in generated code. - String codeString([GenerationOptions options = const GenerationOptions()]) { + String codeString() { if (nullabilitySuffix == NullabilitySuffix.star) { // We can't actually use the legacy star in code, so don't show it. return getDisplayString(withNullability: false); diff --git a/drift_dev/lib/src/writer/database_writer.dart b/drift_dev/lib/src/writer/database_writer.dart index c1a745ec..c09aaef2 100644 --- a/drift_dev/lib/src/writer/database_writer.dart +++ b/drift_dev/lib/src/writer/database_writer.dart @@ -99,7 +99,7 @@ class DatabaseWriter { // Write fields to access an dao. We use a lazy getter for that. for (final dao in db.daos) { - final typeName = dao.codeString(scope.generationOptions); + final typeName = dao.codeString(); final getterName = ReCase(typeName).camelCase; final databaseImplName = db.fromClass!.name; diff --git a/drift_dev/lib/src/writer/queries/query_writer.dart b/drift_dev/lib/src/writer/queries/query_writer.dart index a7189f83..eb5edbd1 100644 --- a/drift_dev/lib/src/writer/queries/query_writer.dart +++ b/drift_dev/lib/src/writer/queries/query_writer.dart @@ -293,7 +293,7 @@ class QueryWriter { final namedElements = []; String typeFor(FoundElement element) { - var type = element.dartTypeCode(scope.generationOptions); + var type = element.dartTypeCode(); if (element is FoundDartPlaceholder && element.writeAsScopedFunction(options)) { diff --git a/drift_dev/lib/src/writer/queries/result_set_writer.dart b/drift_dev/lib/src/writer/queries/result_set_writer.dart index 7e3f62a1..800e7c26 100644 --- a/drift_dev/lib/src/writer/queries/result_set_writer.dart +++ b/drift_dev/lib/src/writer/queries/result_set_writer.dart @@ -30,7 +30,7 @@ class ResultSetWriter { // write fields for (final column in resultSet.columns) { final name = resultSet.dartNameFor(column); - final runtimeType = column.dartTypeCode(scope.generationOptions); + final runtimeType = column.dartTypeCode(); into.write('$modifier $runtimeType $name\n;'); @@ -40,7 +40,7 @@ class ResultSetWriter { for (final nested in resultSet.nestedResults) { if (nested is NestedResultTable) { - var typeName = nested.table.dartTypeCode(scope.generationOptions); + var typeName = nested.table.dartTypeCode(); final fieldName = nested.dartFieldName; if (nested.isNullable) { 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 06108fa1..3db5c010 100644 --- a/drift_dev/lib/src/writer/tables/data_class_writer.dart +++ b/drift_dev/lib/src/writer/tables/data_class_writer.dart @@ -48,7 +48,7 @@ class DataClassWriter { _buffer.write('${column.documentationComment}\n'); } final modifier = scope.options.fieldModifier; - _buffer.write('$modifier ${column.dartTypeCode(scope.generationOptions)} ' + _buffer.write('$modifier ${column.dartTypeCode()} ' '${column.dartGetterName}; \n'); } @@ -120,7 +120,7 @@ class DataClassWriter { typeConverter.tableAndField(forNullableColumn: column.nullable); deserialized = '$converterField.fromJson($fromConverter)'; } else { - final type = column.dartTypeCode(scope.generationOptions); + final type = column.dartTypeCode(); deserialized = "serializer.fromJson<$type>(json['$jsonKey'])"; } @@ -151,7 +151,7 @@ class DataClassWriter { final getter = column.dartGetterName; final needsThis = getter == 'serializer'; var value = needsThis ? 'this.$getter' : getter; - var dartType = column.dartTypeCode(scope.generationOptions); + var dartType = column.dartTypeCode(); final typeConverter = column.typeConverter; if (typeConverter != null && typeConverter.alsoAppliesToJsonConversion) { @@ -177,7 +177,7 @@ class DataClassWriter { final last = i == columns.length - 1; final isNullable = column.nullableInDart; - final typeName = column.dartTypeCode(scope.generationOptions); + final typeName = column.dartTypeCode(); if (wrapNullableInValue && isNullable) { _buffer ..write('Value<$typeName> ${column.dartGetterName} ') diff --git a/drift_dev/lib/src/writer/tables/table_writer.dart b/drift_dev/lib/src/writer/tables/table_writer.dart index 57ca69d1..f789e47a 100644 --- a/drift_dev/lib/src/writer/tables/table_writer.dart +++ b/drift_dev/lib/src/writer/tables/table_writer.dart @@ -100,7 +100,7 @@ abstract class TableOrViewWriter { if (converter != null) { // Generate a GeneratedColumnWithTypeConverter instance, as it has // additional methods to check for equality against a mapped value. - final mappedType = converter.dartTypeCode(options, column.nullable); + final mappedType = converter.dartTypeCode(column.nullable); final converterCode = converter.tableAndField(forNullableColumn: column.nullable); @@ -134,7 +134,7 @@ abstract class TableOrViewWriter { return; } - final dataClassName = tableOrView.dartTypeCode(scope.generationOptions); + final dataClassName = tableOrView.dartTypeCode(); buffer ..write('@override\n$dataClassName map(Map data, ' @@ -321,7 +321,7 @@ class TableWriter extends TableOrViewWriter { void _writeConvertersAsStaticFields() { for (final converter in table.converters) { - final typeName = converter.converterNameInCode(scope.generationOptions); + final typeName = converter.converterNameInCode(); final code = converter.expression; buffer.write('static $typeName ${converter.fieldName} = $code;'); @@ -334,8 +334,8 @@ class TableWriter extends TableOrViewWriter { if (converter != null && converter.canBeSkippedForNulls && column.nullable) { - final nullableTypeName = converter - .converterNameInCode(scope.generationOptions, makeNullable: true); + final nullableTypeName = + converter.converterNameInCode(makeNullable: true); final wrap = converter.alsoAppliesToJsonConversion ? 'JsonTypeConverter.asNullable' 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 d9695677..b733e932 100644 --- a/drift_dev/lib/src/writer/tables/update_companion_writer.dart +++ b/drift_dev/lib/src/writer/tables/update_companion_writer.dart @@ -43,7 +43,7 @@ class UpdateCompanionWriter { void _writeFields() { for (final column in columns) { final modifier = scope.options.fieldModifier; - final type = column.dartTypeCode(scope.generationOptions); + final type = column.dartTypeCode(); _buffer.write('$modifier Value<$type> ${column.dartGetterName};\n'); } } @@ -83,7 +83,7 @@ class UpdateCompanionWriter { if (table.isColumnRequiredForInsert(column)) { requiredColumns.add(column); - final typeName = column.dartTypeCode(scope.generationOptions); + final typeName = column.dartTypeCode(); _buffer.write('required $typeName $param,'); } else { @@ -151,7 +151,7 @@ class UpdateCompanionWriter { } first = false; - final typeName = column.dartTypeCode(scope.generationOptions); + final typeName = column.dartTypeCode(); _buffer.write('Value<$typeName>? ${column.dartGetterName}'); } diff --git a/drift_dev/pubspec.yaml b/drift_dev/pubspec.yaml index f2273deb..b985c16f 100644 --- a/drift_dev/pubspec.yaml +++ b/drift_dev/pubspec.yaml @@ -30,7 +30,7 @@ dependencies: sqlparser: ^0.22.0 # Dart analysis - analyzer: "^4.3.0" + analyzer: "^4.4.0" analyzer_plugin: ^0.11.0 source_span: ^1.5.5 package_config: ^2.0.0 diff --git a/drift_dev/test/analyzer/dart/dart_test.dart b/drift_dev/test/analyzer/dart/dart_test.dart index baf5faf7..c7df3056 100644 --- a/drift_dev/test/analyzer/dart/dart_test.dart +++ b/drift_dev/test/analyzer/dart/dart_test.dart @@ -44,7 +44,7 @@ void main() { expect(parser.returnExpressionOfMethod(node)!.toSource(), source); } - final testClass = library.getType('Test'); + final testClass = library.getClass('Test'); await _verifyReturnExpressionMatches( testClass!.getGetter('getter')!, "'foo'"); diff --git a/drift_dev/test/analyzer/dart/table_parser_test.dart b/drift_dev/test/analyzer/dart/table_parser_test.dart index af912166..2341859e 100644 --- a/drift_dev/test/analyzer/dart/table_parser_test.dart +++ b/drift_dev/test/analyzer/dart/table_parser_test.dart @@ -146,7 +146,7 @@ void main() { }); Future parse(String name) async { - return parser.parseTable(dartStep.library.getType(name)!); + return parser.parseTable(dartStep.library.getClass(name)!); } group('table names', () { diff --git a/drift_dev/test/analyzer/integration/dao_inheritance_test.dart b/drift_dev/test/analyzer/integration/dao_inheritance_test.dart index 80c21801..429d38c6 100644 --- a/drift_dev/test/analyzer/integration/dao_inheritance_test.dart +++ b/drift_dev/test/analyzer/integration/dao_inheritance_test.dart @@ -1,5 +1,6 @@ @Tags(['analyzer']) import 'package:drift_dev/src/analyzer/runner/results.dart'; +import 'package:drift_dev/src/utils/type_utils.dart'; import 'package:test/test.dart'; import '../utils.dart'; @@ -48,7 +49,7 @@ class ProductsDao extends BaseProductsDao with _$ProductDaoMixin { expect(file.errors.errors, isEmpty); final dao = (file.currentResult as ParsedDartFile).declaredDaos.single; - expect(dao.dbClass.element!.name, 'MyDatabase'); + expect(dao.dbClass.nameIfInterfaceType, 'MyDatabase'); state.close(); }); diff --git a/drift_dev/test/services/schema/find_differences_test.dart b/drift_dev/test/services/schema/find_differences_test.dart index bac1455e..c180bc7b 100644 --- a/drift_dev/test/services/schema/find_differences_test.dart +++ b/drift_dev/test/services/schema/find_differences_test.dart @@ -70,7 +70,7 @@ void main() { expect(result, hasChanges); expect( result.describe(), - contains('Different types: TEXT and INTEGER'), + contains('Different types: Expected TEXT, got INTEGER'), ); }); @@ -83,7 +83,8 @@ void main() { expect(result, hasChanges); expect( result.describe(), - contains('Not equal: `PRIMARY KEY NOT NULL` and ``'), + contains( + 'Not equal: `PRIMARY KEY NOT NULL` (expected) and `` (actual)'), ); }); }); diff --git a/drift_dev/test/writer/data_class_writer_test.dart b/drift_dev/test/writer/data_class_writer_test.dart index 4d790aef..6d670ad9 100644 --- a/drift_dev/test/writer/data_class_writer_test.dart +++ b/drift_dev/test/writer/data_class_writer_test.dart @@ -4,6 +4,7 @@ import 'package:analyzer/dart/ast/ast.dart'; import 'package:analyzer/file_system/memory_file_system.dart'; import 'package:build/build.dart'; import 'package:build_test/build_test.dart'; +import 'package:collection/collection.dart'; import 'package:drift_dev/src/backends/build/drift_builder.dart'; import 'package:pub_semver/pub_semver.dart'; import 'package:test/test.dart'; @@ -81,15 +82,18 @@ class _GeneratesConstDataClasses extends Matcher { final definedClasses = parsed.declarations.whereType(); for (final definedClass in definedClasses) { - if (expectedWithConstConstructor.contains(definedClass.name.name)) { - final constructor = definedClass.getConstructor(null); + if (expectedWithConstConstructor.contains(definedClass.name2.lexeme)) { + final constructor = definedClass.members + .whereType() + .firstWhereOrNull((e) => e.name2 == null); if (constructor?.constKeyword == null) { - matchState['desc'] = 'Constructor ${definedClass.name.name} is not ' + matchState['desc'] = + 'Constructor ${definedClass.name2.lexeme} is not ' 'const.'; return false; } - remaining.remove(definedClass.name.name); + remaining.remove(definedClass.name2.lexeme); } } diff --git a/drift_dev/test/writer/mutable_classes_integration_test.dart b/drift_dev/test/writer/mutable_classes_integration_test.dart index 26ef90e7..79ce91ad 100644 --- a/drift_dev/test/writer/mutable_classes_integration_test.dart +++ b/drift_dev/test/writer/mutable_classes_integration_test.dart @@ -80,25 +80,26 @@ class _GeneratesWithoutFinalFields extends Matcher { final definedClasses = parsed.declarations.whereType(); for (final definedClass in definedClasses) { - if (expectedWithoutFinals.contains(definedClass.name.name)) { + final definedClassName = definedClass.name2.lexeme; + if (expectedWithoutFinals.contains(definedClassName)) { for (final member in definedClass.members) { if (member is FieldDeclaration) { if (member.fields.isFinal) { matchState['desc'] = - 'Field ${member.fields.variables.first.name.name} in ' - '${definedClass.name.name} is final.'; + 'Field ${member.fields.variables.first.name2.lexeme} in ' + '$definedClassName is final.'; return false; } } else if (member is ConstructorDeclaration) { if (member.constKeyword != null) { - matchState['desc'] = 'Constructor ${member.name?.name ?? ''} in ' - '${definedClass.name.name} is constant.'; + matchState['desc'] = 'Constructor ${member.name2?.lexeme ?? ''} ' + 'in $definedClassName is constant.'; return false; } } } - remaining.remove(definedClass.name.name); + remaining.remove(definedClassName); } }