mirror of https://github.com/AMT-Cheif/drift.git
Merge remote-tracking branch 'simolus3/develop' into fix-lint-warning
This commit is contained in:
commit
40554c8166
|
@ -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 %}
|
{% 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
|
##### Migrating from unix timestamps to text
|
||||||
|
|
||||||
To migrate from using timestamps (the default option) to storing datetimes as
|
To migrate from using timestamps (the default option) to storing datetimes as
|
||||||
|
|
|
@ -8,7 +8,7 @@ template: layouts/docs/list
|
||||||
## Welcome to drift
|
## Welcome to drift
|
||||||
|
|
||||||
Drift is a reactive persistence library for Dart and Flutter applications. It's built on top
|
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:
|
and provides additional features, like:
|
||||||
|
|
||||||
- __Type safety__: Instead of writing sql queries manually and parsing the `List<Map<String, dynamic>>` that they
|
- __Type safety__: Instead of writing sql queries manually and parsing the `List<Map<String, dynamic>>` that they
|
||||||
|
|
|
@ -7,47 +7,76 @@ data:
|
||||||
show_favorites: true
|
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" %}
|
||||||
<div class="mx-auto">
|
<div class="mx-auto">
|
||||||
|
<p class="h4">
|
||||||
|
Drift is <em>the</em> 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.
|
||||||
|
</p>
|
||||||
<a class="btn btn-lg btn-primary mr-3 mb-4" href="{{ 'docs/index' | pageUrl }}">
|
<a class="btn btn-lg btn-primary mr-3 mb-4" href="{{ 'docs/index' | pageUrl }}">
|
||||||
Learn more <i class="fas fa-arrow-alt-circle-right ml-2"></i>
|
Learn more <i class="fas fa-arrow-alt-circle-right ml-2"></i>
|
||||||
</a>
|
</a>
|
||||||
<a class="btn btn-lg btn-secondary mr-3 mb-4" href="https://pub.dev/packages/drift">
|
<a class="btn btn-lg btn-secondary mr-3 mb-4" href="https://pub.dev/packages/drift">
|
||||||
Get from pub <i class="fas fa-code ml-2 "></i>
|
Get started <i class="fas fa-code ml-2 "></i>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<p class="lead mt-5">
|
|
||||||
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
|
|
||||||
<a href="{{ 'docs/Getting started/index' | pageUrl }}">getting started guide</a> for a step-by-step guide on using drift.
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% 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/section.html" color="primary" %}
|
||||||
|
|
||||||
{% block "blocks/feature.html" icon="fas fa-lightbulb" title="Declarative tables, fluent queries" %}
|
{% block "blocks/feature.html" icon="fas fa-lightbulb" title="Declarative tables, fluent queries" %}
|
||||||
{% block "blocks/markdown.html" %}
|
{% block "blocks/markdown.html" %}
|
||||||
With drift, you can write your database tables in pure Dart without having to miss out on
|
With drift, you can declare your database tables and queries in pure Dart without having to miss out on
|
||||||
advanced sqlite features. Drift will take care of creating the tables and generate code
|
advanced SQL features. Drift will take care of creating the tables and generate code
|
||||||
that allows you run fluent queries on your data.
|
that allows you run fluent queries on your data.
|
||||||
|
|
||||||
[Get started now]({{ "docs/Getting started/index.md" | pageUrl }})
|
[Get started now]({{ "docs/Getting started/index.md" | pageUrl }})
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% 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" %}
|
{% 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
|
validated and analyzed during build-time, so drift can provide hints about potential errors quickly and generate efficient mapping
|
||||||
code.
|
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 %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
@ -60,25 +89,3 @@ When using drift, working with databases in Dart is fun!
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% 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 %}
|
|
||||||
|
|
|
@ -38,8 +38,6 @@ dev_dependencies:
|
||||||
drift_dev:
|
drift_dev:
|
||||||
|
|
||||||
dependency_overrides:
|
dependency_overrides:
|
||||||
# Waiting for dartdoc, https://github.com/dart-lang/dartdoc/pull/3033
|
|
||||||
analyzer: ^4.0.0
|
|
||||||
moor_generator:
|
moor_generator:
|
||||||
path: ../moor_generator
|
path: ../moor_generator
|
||||||
drift:
|
drift:
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
{% assign links = site.links %}
|
||||||
|
<footer class="bg-dark py-5 row d-print-none">
|
||||||
|
<div class="container-fluid mx-sm-5">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-6 col-sm-4 text-xs-center order-sm-2">
|
||||||
|
{% if links.user %}
|
||||||
|
{% assign links = links.user %}
|
||||||
|
{% include "partials/footer-links-block.html" %}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div class="col-6 col-sm-4 text-right text-xs-center order-sm-3">
|
||||||
|
{% if links.developer %}
|
||||||
|
{% assign links = links.developer %}
|
||||||
|
{% include "partials/footer-links-block.html" %}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div class="col-12 col-sm-4 text-center py-2 order-sm-2">
|
||||||
|
{% if site.copyright %}
|
||||||
|
<small class="text-white"><div>© {{ site.copyright }}</div>
|
||||||
|
Except where otherwise noted, content on this site is licensed under a <a href="https://creativecommons.org/licenses/by/4.0/" target="_blank" rel="license noopener noreferrer">CC BY 4.0</a> license.
|
||||||
|
Code snippets are marked with <a href="http://creativecommons.org/publicdomain/zero/1.0" target="_blank" rel="license noopener noreferrer">CC0 1.0</a>,
|
||||||
|
drift itself is <a href="https://github.com/simolus3/drift/blob/develop/LICENSE" rel="license" target="_blank">MIT-licensed</a>.
|
||||||
|
</small>
|
||||||
|
{% endif %}
|
||||||
|
{% if site.privacy_policy %}
|
||||||
|
<small class="ml-1"><a href="{{ site.privacy_policy }}" target="_blank">{{ "footer_privacy_policy" | i18n }}</a></small>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
|
@ -158,11 +158,19 @@ abstract class Table extends HasResultSet {
|
||||||
ColumnBuilder<bool> boolean() => _isGenerated();
|
ColumnBuilder<bool> boolean() => _isGenerated();
|
||||||
|
|
||||||
/// Use this as the body of a getter to declare a column that holds date and
|
/// 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):
|
/// Example (inside the body of a table class):
|
||||||
/// ```
|
/// ```
|
||||||
/// DateTimeColumn get accountCreatedAt => dateTime()();
|
/// DateTimeColumn get accountCreatedAt => dateTime()();
|
||||||
/// ```
|
/// ```
|
||||||
|
/// [the documentation]: https://drift.simonbinder.eu/docs/getting-started/advanced_dart_tables/#supported-column-types
|
||||||
@protected
|
@protected
|
||||||
ColumnBuilder<DateTime> dateTime() => _isGenerated();
|
ColumnBuilder<DateTime> dateTime() => _isGenerated();
|
||||||
|
|
||||||
|
|
|
@ -188,7 +188,14 @@ abstract class ValueSerializer {
|
||||||
///
|
///
|
||||||
/// To override the default serializer drift uses, you can change the
|
/// To override the default serializer drift uses, you can change the
|
||||||
/// [DriftRuntimeOptions.defaultSerializer] field.
|
/// [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
|
/// Converts the [value] to something that can be passed to
|
||||||
/// [JsonCodec.encode].
|
/// [JsonCodec.encode].
|
||||||
|
@ -200,7 +207,9 @@ abstract class ValueSerializer {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _DefaultValueSerializer extends ValueSerializer {
|
class _DefaultValueSerializer extends ValueSerializer {
|
||||||
const _DefaultValueSerializer();
|
final bool serializeDateTimeValuesAsString;
|
||||||
|
|
||||||
|
const _DefaultValueSerializer({this.serializeDateTimeValuesAsString = false});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
T fromJson<T>(dynamic json) {
|
T fromJson<T>(dynamic json) {
|
||||||
|
@ -211,7 +220,11 @@ class _DefaultValueSerializer extends ValueSerializer {
|
||||||
final _typeList = <T>[];
|
final _typeList = <T>[];
|
||||||
|
|
||||||
if (_typeList is List<DateTime?>) {
|
if (_typeList is List<DateTime?>) {
|
||||||
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<double?> && json is int) {
|
if (_typeList is List<double?> && json is int) {
|
||||||
|
@ -231,7 +244,9 @@ class _DefaultValueSerializer extends ValueSerializer {
|
||||||
@override
|
@override
|
||||||
dynamic toJson<T>(T value) {
|
dynamic toJson<T>(T value) {
|
||||||
if (value is DateTime) {
|
if (value is DateTime) {
|
||||||
return value.millisecondsSinceEpoch;
|
return serializeDateTimeValuesAsString
|
||||||
|
? value.toIso8601String()
|
||||||
|
: value.millisecondsSinceEpoch;
|
||||||
}
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
|
|
|
@ -48,6 +48,12 @@ void _testWith(TodoDb Function() openDb, {bool dateTimeAsText = false}) {
|
||||||
expect(await eval(Variable(local)), local);
|
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 {
|
test('plus and minus', () async {
|
||||||
|
|
|
@ -17,8 +17,8 @@ void main() {
|
||||||
|
|
||||||
await expectLater(
|
await expectLater(
|
||||||
db.validateDatabaseSchema(),
|
db.validateDatabaseSchema(),
|
||||||
throwsA(isA<SchemaMismatch>().having(
|
throwsA(isA<SchemaMismatch>().having((e) => e.toString(), 'toString()',
|
||||||
(e) => e.toString(), 'toString()', contains('TEXT and INTEGER'))),
|
contains('Expected TEXT, got INTEGER'))),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,29 +2,37 @@ import 'package:drift/drift.dart';
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
import 'generated/todos.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,
|
id: 3,
|
||||||
title: null,
|
title: null,
|
||||||
content: 'content',
|
content: 'content',
|
||||||
targetDate: someDate,
|
targetDate: _someDate,
|
||||||
category: 3,
|
category: 3,
|
||||||
);
|
);
|
||||||
|
|
||||||
final Map<String, dynamic> regularSerialized = {
|
final Map<String, dynamic> _regularSerialized = {
|
||||||
'id': 3,
|
'id': 3,
|
||||||
'title': null,
|
'title': null,
|
||||||
'content': 'content',
|
'content': 'content',
|
||||||
'target_date': someDate.millisecondsSinceEpoch,
|
'target_date': _someDate.millisecondsSinceEpoch,
|
||||||
'category': 3,
|
'category': 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
final Map<String, dynamic> customSerialized = {
|
final Map<String, dynamic> _asTextSerialized = {
|
||||||
|
'id': 3,
|
||||||
|
'title': null,
|
||||||
|
'content': 'content',
|
||||||
|
'target_date': _someDate.toIso8601String(),
|
||||||
|
'category': 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
final Map<String, dynamic> _customSerialized = {
|
||||||
'id': 3,
|
'id': 3,
|
||||||
'title': 'set to null',
|
'title': 'set to null',
|
||||||
'content': 'content',
|
'content': 'content',
|
||||||
'target_date': someDate.toIso8601String(),
|
'target_date': _someDate.toIso8601String(),
|
||||||
'category': 3,
|
'category': 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -61,7 +69,16 @@ void main() {
|
||||||
|
|
||||||
group('serialization', () {
|
group('serialization', () {
|
||||||
test('with defaults', () {
|
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', () {
|
test('applies json type converter', () {
|
||||||
|
@ -71,20 +88,31 @@ void main() {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('with custom serializer', () {
|
test('with custom serializer', () {
|
||||||
expect(someTodoEntry.toJson(serializer: CustomSerializer()),
|
expect(_someTodoEntry.toJson(serializer: CustomSerializer()),
|
||||||
equals(customSerialized));
|
equals(_customSerialized));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
group('deserialization', () {
|
group('deserialization', () {
|
||||||
test('with defaults', () {
|
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', () {
|
test('with custom serializer', () {
|
||||||
expect(
|
expect(
|
||||||
TodoEntry.fromJson(customSerialized, serializer: CustomSerializer()),
|
TodoEntry.fromJson(_customSerialized, serializer: CustomSerializer()),
|
||||||
equals(someTodoEntry));
|
equals(_someTodoEntry));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -337,7 +337,7 @@ class ColumnParser {
|
||||||
if (foundExplicitName != null) {
|
if (foundExplicitName != null) {
|
||||||
name = ColumnName.explicitly(foundExplicitName);
|
name = ColumnName.explicitly(foundExplicitName);
|
||||||
} else {
|
} else {
|
||||||
name = ColumnName.implicitly(ReCase(getter.name.name).snakeCase);
|
name = ColumnName.implicitly(ReCase(getter.name2.lexeme).snakeCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
final columnType = _startMethodToColumnType(foundStartMethod);
|
final columnType = _startMethodToColumnType(foundStartMethod);
|
||||||
|
@ -424,7 +424,7 @@ class ColumnParser {
|
||||||
getter.documentationComment?.tokens.map((t) => t.toString()).join('\n');
|
getter.documentationComment?.tokens.map((t) => t.toString()).join('\n');
|
||||||
return DriftColumn(
|
return DriftColumn(
|
||||||
type: columnType,
|
type: columnType,
|
||||||
dartGetterName: getter.name.name,
|
dartGetterName: getter.name2.lexeme,
|
||||||
name: name,
|
name: name,
|
||||||
overriddenJsonName: _readJsonKey(element),
|
overriddenJsonName: _readJsonKey(element),
|
||||||
customConstraints: foundCustomConstraint,
|
customConstraints: foundCustomConstraint,
|
||||||
|
@ -456,9 +456,11 @@ class ColumnParser {
|
||||||
final annotations = getter.metadata;
|
final annotations = getter.metadata;
|
||||||
final object = annotations.firstWhereOrNull((e) {
|
final object = annotations.firstWhereOrNull((e) {
|
||||||
final value = e.computeConstantValue();
|
final value = e.computeConstantValue();
|
||||||
return value != null &&
|
final valueType = value?.type;
|
||||||
isFromMoor(value.type!) &&
|
|
||||||
value.type!.element!.name == 'JsonKey';
|
return valueType is InterfaceType &&
|
||||||
|
isFromDrift(valueType) &&
|
||||||
|
valueType.element2.name == 'JsonKey';
|
||||||
});
|
});
|
||||||
|
|
||||||
if (object == null) return null;
|
if (object == null) return null;
|
||||||
|
|
|
@ -85,7 +85,7 @@ class TableParser {
|
||||||
|
|
||||||
for (final annotation in element.metadata) {
|
for (final annotation in element.metadata) {
|
||||||
final computed = annotation.computeConstantValue();
|
final computed = annotation.computeConstantValue();
|
||||||
final annotationClass = computed!.type!.element!.name;
|
final annotationClass = computed!.type!.nameIfInterfaceType;
|
||||||
|
|
||||||
if (annotationClass == 'DataClassName') {
|
if (annotationClass == 'DataClassName') {
|
||||||
dataClassName = computed;
|
dataClassName = computed;
|
||||||
|
@ -124,8 +124,8 @@ class TableParser {
|
||||||
useRowClass.getField('generateInsertable')!.toBoolValue()!;
|
useRowClass.getField('generateInsertable')!.toBoolValue()!;
|
||||||
|
|
||||||
if (type is InterfaceType) {
|
if (type is InterfaceType) {
|
||||||
existingClass = FoundDartClass(type.element, type.typeArguments);
|
existingClass = FoundDartClass(type.element2, type.typeArguments);
|
||||||
name = type.element.name;
|
name = type.element2.name;
|
||||||
} else {
|
} else {
|
||||||
base.step.reportError(ErrorInDartCode(
|
base.step.reportError(ErrorInDartCode(
|
||||||
message: 'The @UseRowClass annotation must be used with a class',
|
message: 'The @UseRowClass annotation must be used with a class',
|
||||||
|
@ -309,7 +309,7 @@ class TableParser {
|
||||||
|
|
||||||
Future<Iterable<DriftColumn>> _parseColumns(ClassElement element) async {
|
Future<Iterable<DriftColumn>> _parseColumns(ClassElement element) async {
|
||||||
final columnNames = element.allSupertypes
|
final columnNames = element.allSupertypes
|
||||||
.map((t) => t.element)
|
.map((t) => t.element2)
|
||||||
.followedBy([element])
|
.followedBy([element])
|
||||||
.expand((e) => e.fields)
|
.expand((e) => e.fields)
|
||||||
.where((field) =>
|
.where((field) =>
|
||||||
|
@ -350,10 +350,10 @@ class _DataClassInformation {
|
||||||
|
|
||||||
extension on Element {
|
extension on Element {
|
||||||
bool get isFromDefaultTable {
|
bool get isFromDefaultTable {
|
||||||
final parent = enclosingElement2;
|
final parent = enclosingElement3;
|
||||||
|
|
||||||
return parent is ClassElement &&
|
return parent is ClassElement &&
|
||||||
parent.name == 'Table' &&
|
parent.name == 'Table' &&
|
||||||
isFromMoor(parent.thisType);
|
isFromDrift(parent.thisType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ class UseDaoParser {
|
||||||
/// declared by that class and the referenced tables.
|
/// declared by that class and the referenced tables.
|
||||||
Future<Dao?> parseDao(ClassElement element, ConstantReader annotation) async {
|
Future<Dao?> parseDao(ClassElement element, ConstantReader annotation) async {
|
||||||
final dbType = element.allSupertypes
|
final dbType = element.allSupertypes
|
||||||
.firstWhereOrNull((i) => i.element.name == 'DatabaseAccessor');
|
.firstWhereOrNull((i) => i.element2.name == 'DatabaseAccessor');
|
||||||
|
|
||||||
if (dbType == null) {
|
if (dbType == null) {
|
||||||
step.reportError(ErrorInDartCode(
|
step.reportError(ErrorInDartCode(
|
||||||
|
|
|
@ -41,7 +41,7 @@ class ViewParser {
|
||||||
|
|
||||||
for (final annotation in element.metadata) {
|
for (final annotation in element.metadata) {
|
||||||
final computed = annotation.computeConstantValue();
|
final computed = annotation.computeConstantValue();
|
||||||
final annotationClass = computed!.type!.element!.name;
|
final annotationClass = computed!.type!.nameIfInterfaceType;
|
||||||
|
|
||||||
if (annotationClass == 'DriftView') {
|
if (annotationClass == 'DriftView') {
|
||||||
driftView = computed;
|
driftView = computed;
|
||||||
|
@ -80,8 +80,8 @@ class ViewParser {
|
||||||
useRowClass.getField('generateInsertable')!.toBoolValue()!;
|
useRowClass.getField('generateInsertable')!.toBoolValue()!;
|
||||||
|
|
||||||
if (type is InterfaceType) {
|
if (type is InterfaceType) {
|
||||||
existingClass = FoundDartClass(type.element, type.typeArguments);
|
existingClass = FoundDartClass(type.element2, type.typeArguments);
|
||||||
name = type.element.name;
|
name = type.element2.name;
|
||||||
} else {
|
} else {
|
||||||
base.step.reportError(ErrorInDartCode(
|
base.step.reportError(ErrorInDartCode(
|
||||||
message: 'The @UseRowClass annotation must be used with a class',
|
message: 'The @UseRowClass annotation must be used with a class',
|
||||||
|
@ -100,7 +100,7 @@ class ViewParser {
|
||||||
Future<String> _parseViewName(ClassElement element) async {
|
Future<String> _parseViewName(ClassElement element) async {
|
||||||
for (final annotation in element.metadata) {
|
for (final annotation in element.metadata) {
|
||||||
final computed = annotation.computeConstantValue();
|
final computed = annotation.computeConstantValue();
|
||||||
final annotationClass = computed!.type!.element!.name;
|
final annotationClass = computed!.type!.nameIfInterfaceType;
|
||||||
|
|
||||||
if (annotationClass == 'DriftView') {
|
if (annotationClass == 'DriftView') {
|
||||||
final name = computed.getField('name')?.toStringValue();
|
final name = computed.getField('name')?.toStringValue();
|
||||||
|
@ -116,7 +116,7 @@ class ViewParser {
|
||||||
|
|
||||||
Future<Iterable<DriftColumn>> _parseColumns(ClassElement element) async {
|
Future<Iterable<DriftColumn>> _parseColumns(ClassElement element) async {
|
||||||
final columnNames = element.allSupertypes
|
final columnNames = element.allSupertypes
|
||||||
.map((t) => t.element)
|
.map((t) => t.element2)
|
||||||
.followedBy([element])
|
.followedBy([element])
|
||||||
.expand((e) => e.fields)
|
.expand((e) => e.fields)
|
||||||
.where((field) =>
|
.where((field) =>
|
||||||
|
@ -134,7 +134,7 @@ class ViewParser {
|
||||||
|
|
||||||
final results = await Future.wait(fields.map((field) async {
|
final results = await Future.wait(fields.map((field) async {
|
||||||
final dartType = (field.type as InterfaceType).typeArguments[0];
|
final dartType = (field.type as InterfaceType).typeArguments[0];
|
||||||
final typeName = dartType.element!.name!;
|
final typeName = dartType.nameIfInterfaceType!;
|
||||||
final sqlType = _dartTypeToColumnType(typeName);
|
final sqlType = _dartTypeToColumnType(typeName);
|
||||||
|
|
||||||
if (sqlType == null) {
|
if (sqlType == null) {
|
||||||
|
@ -181,7 +181,7 @@ class ViewParser {
|
||||||
Future<List<TableReferenceInDartView>> _parseStaticReferences(
|
Future<List<TableReferenceInDartView>> _parseStaticReferences(
|
||||||
ClassElement element, List<DriftTable> tables) async {
|
ClassElement element, List<DriftTable> tables) async {
|
||||||
return await Stream.fromIterable(element.allSupertypes
|
return await Stream.fromIterable(element.allSupertypes
|
||||||
.map((t) => t.element)
|
.map((t) => t.element2)
|
||||||
.followedBy([element]).expand((e) => e.fields))
|
.followedBy([element]).expand((e) => e.fields))
|
||||||
.asyncMap((field) => _getStaticReference(field, tables))
|
.asyncMap((field) => _getStaticReference(field, tables))
|
||||||
.where((ref) => ref != null)
|
.where((ref) => ref != null)
|
||||||
|
@ -198,7 +198,7 @@ class ViewParser {
|
||||||
final type = tables.firstWhereOrNull(
|
final type = tables.firstWhereOrNull(
|
||||||
(tbl) => tbl.fromClass!.name == node.returnType.toString());
|
(tbl) => tbl.fromClass!.name == node.returnType.toString());
|
||||||
if (type != null) {
|
if (type != null) {
|
||||||
final name = node.name.toString();
|
final name = node.name2.lexeme;
|
||||||
return TableReferenceInDartView(type, name);
|
return TableReferenceInDartView(type, name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ import 'package:drift_dev/src/analyzer/runner/steps.dart';
|
||||||
import 'helper.dart';
|
import 'helper.dart';
|
||||||
|
|
||||||
class FoundDartClass {
|
class FoundDartClass {
|
||||||
final ClassElement classElement;
|
final InterfaceElement classElement;
|
||||||
|
|
||||||
/// The instantiation of the [classElement], if the found type was a generic
|
/// The instantiation of the [classElement], if the found type was a generic
|
||||||
/// typedef.
|
/// typedef.
|
||||||
|
@ -230,8 +230,8 @@ void _checkType(
|
||||||
final isAllowedUint8List = typeConverter == null &&
|
final isAllowedUint8List = typeConverter == null &&
|
||||||
columnType == DriftSqlType.blob &&
|
columnType == DriftSqlType.blob &&
|
||||||
typeToCheck is InterfaceType &&
|
typeToCheck is InterfaceType &&
|
||||||
typeToCheck.element.name == 'Uint8List' &&
|
typeToCheck.element2.name == 'Uint8List' &&
|
||||||
typeToCheck.element.library.name == 'dart.typed_data';
|
typeToCheck.element2.library.name == 'dart.typed_data';
|
||||||
|
|
||||||
if (!typeSystem.isAssignableTo(expectedDartType.type, typeToCheck) &&
|
if (!typeSystem.isAssignableTo(expectedDartType.type, typeToCheck) &&
|
||||||
!isAllowedUint8List) {
|
!isAllowedUint8List) {
|
||||||
|
@ -246,14 +246,14 @@ extension on TypeProvider {
|
||||||
case DriftSqlType.int:
|
case DriftSqlType.int:
|
||||||
return intType;
|
return intType;
|
||||||
case DriftSqlType.bigInt:
|
case DriftSqlType.bigInt:
|
||||||
return intElement.library.getType('BigInt')!.instantiate(
|
return intElement.library.getClass('BigInt')!.instantiate(
|
||||||
typeArguments: const [], nullabilitySuffix: NullabilitySuffix.none);
|
typeArguments: const [], nullabilitySuffix: NullabilitySuffix.none);
|
||||||
case DriftSqlType.string:
|
case DriftSqlType.string:
|
||||||
return stringType;
|
return stringType;
|
||||||
case DriftSqlType.bool:
|
case DriftSqlType.bool:
|
||||||
return boolType;
|
return boolType;
|
||||||
case DriftSqlType.dateTime:
|
case DriftSqlType.dateTime:
|
||||||
return intElement.library.getType('DateTime')!.instantiate(
|
return intElement.library.getClass('DateTime')!.instantiate(
|
||||||
typeArguments: const [], nullabilitySuffix: NullabilitySuffix.none);
|
typeArguments: const [], nullabilitySuffix: NullabilitySuffix.none);
|
||||||
case DriftSqlType.blob:
|
case DriftSqlType.blob:
|
||||||
return listType(intType);
|
return listType(intType);
|
||||||
|
|
|
@ -28,8 +28,8 @@ String? parseCustomParentClass(String dartTypeName, DartObject dataClassName,
|
||||||
if (extending != null && !extending.isNull) {
|
if (extending != null && !extending.isNull) {
|
||||||
final extendingType = extending.toTypeValue();
|
final extendingType = extending.toTypeValue();
|
||||||
if (extendingType is InterfaceType) {
|
if (extendingType is InterfaceType) {
|
||||||
final superType = extendingType.allSupertypes
|
final superType = extendingType.allSupertypes.any(
|
||||||
.any((type) => isFromMoor(type) && type.element.name == 'DataClass');
|
(type) => isFromDrift(type) && type.element2.name == 'DataClass');
|
||||||
if (!superType) {
|
if (!superType) {
|
||||||
base.step.reportError(
|
base.step.reportError(
|
||||||
ErrorInDartCode(
|
ErrorInDartCode(
|
||||||
|
@ -52,10 +52,10 @@ String? parseCustomParentClass(String dartTypeName, DartObject dataClassName,
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final className = extendingType.element.name;
|
final className = extendingType.nameIfInterfaceType;
|
||||||
if (extendingType.typeArguments.length == 1) {
|
if (extendingType.typeArguments.length == 1) {
|
||||||
final genericType = extendingType.typeArguments[0].element?.name;
|
final genericType = extendingType.typeArguments[0];
|
||||||
if (genericType == 'Object' || genericType == 'dynamic') {
|
if (genericType.isDartCoreObject || genericType.isDynamic) {
|
||||||
return '$className<$dartTypeName>';
|
return '$className<$dartTypeName>';
|
||||||
} else {
|
} else {
|
||||||
base.step.reportError(
|
base.step.reportError(
|
||||||
|
|
|
@ -28,7 +28,7 @@ Future<FoundDartClass?> findDartClass(
|
||||||
} else if (foundElement is TypeAliasElement) {
|
} else if (foundElement is TypeAliasElement) {
|
||||||
final innerType = foundElement.aliasedType;
|
final innerType = foundElement.aliasedType;
|
||||||
if (innerType is InterfaceType) {
|
if (innerType is InterfaceType) {
|
||||||
return FoundDartClass(innerType.element, innerType.typeArguments);
|
return FoundDartClass(innerType.element2, innerType.typeArguments);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -122,7 +122,7 @@ class ParseDartStep extends Step {
|
||||||
Future<List<DriftTable>> parseTables(
|
Future<List<DriftTable>> parseTables(
|
||||||
Iterable<DartType> types, Element initializedBy) {
|
Iterable<DartType> types, Element initializedBy) {
|
||||||
return Future.wait(types.map((type) {
|
return Future.wait(types.map((type) {
|
||||||
if (!_tableTypeChecker.isAssignableFrom(type.element!)) {
|
if (!_tableTypeChecker.isAssignableFromType(type)) {
|
||||||
reportError(ErrorInDartCode(
|
reportError(ErrorInDartCode(
|
||||||
severity: Severity.criticalError,
|
severity: Severity.criticalError,
|
||||||
message: 'The type $type is not a moor table',
|
message: 'The type $type is not a moor table',
|
||||||
|
@ -130,7 +130,7 @@ class ParseDartStep extends Step {
|
||||||
));
|
));
|
||||||
return Future.value(null);
|
return Future.value(null);
|
||||||
} else {
|
} else {
|
||||||
return _parseTable(type.element as ClassElement);
|
return _parseTable((type as InterfaceType).element2 as ClassElement);
|
||||||
}
|
}
|
||||||
})).then((list) {
|
})).then((list) {
|
||||||
// only keep tables that were resolved successfully
|
// only keep tables that were resolved successfully
|
||||||
|
@ -145,7 +145,7 @@ class ParseDartStep extends Step {
|
||||||
Future<List<MoorView>> parseViews(Iterable<DartType> types,
|
Future<List<MoorView>> parseViews(Iterable<DartType> types,
|
||||||
Element initializedBy, List<DriftTable> tables) {
|
Element initializedBy, List<DriftTable> tables) {
|
||||||
return Future.wait(types.map((type) {
|
return Future.wait(types.map((type) {
|
||||||
if (!_viewTypeChecker.isAssignableFrom(type.element!)) {
|
if (!_viewTypeChecker.isAssignableFromType(type)) {
|
||||||
reportError(ErrorInDartCode(
|
reportError(ErrorInDartCode(
|
||||||
severity: Severity.criticalError,
|
severity: Severity.criticalError,
|
||||||
message: 'The type $type is not a drift view',
|
message: 'The type $type is not a drift view',
|
||||||
|
@ -153,7 +153,8 @@ class ParseDartStep extends Step {
|
||||||
));
|
));
|
||||||
return Future.value(null);
|
return Future.value(null);
|
||||||
} else {
|
} else {
|
||||||
return _parseView(type.element as ClassElement, tables);
|
return _parseView(
|
||||||
|
(type as InterfaceType).element2 as ClassElement, tables);
|
||||||
}
|
}
|
||||||
})).then((list) {
|
})).then((list) {
|
||||||
// only keep tables that were resolved successfully
|
// only keep tables that were resolved successfully
|
||||||
|
|
|
@ -21,7 +21,7 @@ class DaoGenerator extends Generator implements BaseGenerator {
|
||||||
|
|
||||||
final daoName = element!.displayName;
|
final daoName = element!.displayName;
|
||||||
|
|
||||||
final dbTypeName = dao.dbClass.codeString(writer.generationOptions);
|
final dbTypeName = dao.dbClass.codeString();
|
||||||
classScope.leaf().write('mixin _\$${daoName}Mixin on '
|
classScope.leaf().write('mixin _\$${daoName}Mixin on '
|
||||||
'DatabaseAccessor<$dbTypeName> {\n');
|
'DatabaseAccessor<$dbTypeName> {\n');
|
||||||
|
|
||||||
|
|
|
@ -413,7 +413,8 @@ class _Moor2DriftDartRewriter extends GeneralizingAstVisitor<void> {
|
||||||
|
|
||||||
if (type is! InterfaceType) continue;
|
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()!;
|
final name = value.getField('name')!.toStringValue()!;
|
||||||
|
|
||||||
if (name == 'moor2drift') {
|
if (name == 'moor2drift') {
|
||||||
|
@ -452,8 +453,8 @@ class _Moor2DriftDartRewriter extends GeneralizingAstVisitor<void> {
|
||||||
if (type is! InterfaceType ||
|
if (type is! InterfaceType ||
|
||||||
// note that even old moor code uses these names since UseMoor/UseDao
|
// note that even old moor code uses these names since UseMoor/UseDao
|
||||||
// are type aliases to the new interfaces.
|
// are type aliases to the new interfaces.
|
||||||
(type.element.name != 'DriftDatabase' &&
|
(type.element2.name != 'DriftDatabase' &&
|
||||||
type.element.name != 'DriftAccessor')) {
|
type.element2.name != 'DriftAccessor')) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,7 +40,7 @@ abstract class DriftEntityWithResultSet extends DriftSchemaEntity {
|
||||||
/// The type name of the Dart row class for this result set.
|
/// The type name of the Dart row class for this result set.
|
||||||
///
|
///
|
||||||
/// This may contain generics.
|
/// This may contain generics.
|
||||||
String dartTypeCode([GenerationOptions options = const GenerationOptions()]);
|
String dartTypeCode();
|
||||||
|
|
||||||
/// The name of the Dart class storing additional properties like type
|
/// The name of the Dart class storing additional properties like type
|
||||||
/// converters.
|
/// converters.
|
||||||
|
@ -65,7 +65,7 @@ abstract class DriftEntityWithResultSet extends DriftSchemaEntity {
|
||||||
/// Information used by the generator to generate code for a custom data class
|
/// Information used by the generator to generate code for a custom data class
|
||||||
/// written by users.
|
/// written by users.
|
||||||
class ExistingRowClass {
|
class ExistingRowClass {
|
||||||
final ClassElement targetClass;
|
final InterfaceElement targetClass;
|
||||||
|
|
||||||
/// The Dart types that should be used to instantiate the [targetClass].
|
/// The Dart types that should be used to instantiate the [targetClass].
|
||||||
final List<DartType> typeInstantiation;
|
final List<DartType> typeInstantiation;
|
||||||
|
|
|
@ -142,11 +142,11 @@ abstract class SqlQuery {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resultSet.matchingTable != null) {
|
if (resultSet.matchingTable != null) {
|
||||||
return resultSet.matchingTable!.table.dartTypeCode(options);
|
return resultSet.matchingTable!.table.dartTypeCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resultSet.singleColumn) {
|
if (resultSet.singleColumn) {
|
||||||
return resultSet.columns.single.dartTypeCode(options);
|
return resultSet.columns.single.dartTypeCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
return resultClassName;
|
return resultClassName;
|
||||||
|
@ -593,7 +593,7 @@ abstract class FoundElement {
|
||||||
bool get hidden => false;
|
bool get hidden => false;
|
||||||
|
|
||||||
/// Dart code for a type representing tis element.
|
/// 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.
|
/// A semantic interpretation of a [Variable] in a sql statement.
|
||||||
|
@ -676,8 +676,8 @@ class FoundVariable extends FoundElement implements HasType {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String dartTypeCode([GenerationOptions options = const GenerationOptions()]) {
|
String dartTypeCode() {
|
||||||
return OperationOnTypes(this).dartTypeCode(options);
|
return OperationOnTypes(this).dartTypeCode();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@ import 'package:analyzer/dart/element/nullability_suffix.dart';
|
||||||
import 'package:analyzer/dart/element/type.dart';
|
import 'package:analyzer/dart/element/type.dart';
|
||||||
import 'package:drift_dev/src/model/model.dart';
|
import 'package:drift_dev/src/model/model.dart';
|
||||||
import 'package:drift_dev/src/utils/type_utils.dart';
|
import 'package:drift_dev/src/utils/type_utils.dart';
|
||||||
import 'package:drift_dev/writer.dart';
|
|
||||||
|
|
||||||
/// Something that has a type.
|
/// Something that has a type.
|
||||||
///
|
///
|
||||||
|
@ -60,14 +59,14 @@ class DriftDartType {
|
||||||
return type.getDisplayString(withNullability: withNullability);
|
return type.getDisplayString(withNullability: withNullability);
|
||||||
}
|
}
|
||||||
|
|
||||||
String codeString([GenerationOptions options = const GenerationOptions()]) {
|
String codeString() {
|
||||||
if (overiddenSource != null) {
|
if (overiddenSource != null) {
|
||||||
if (nullabilitySuffix == NullabilitySuffix.star) {
|
if (nullabilitySuffix == NullabilitySuffix.star) {
|
||||||
return getDisplayString(withNullability: false);
|
return getDisplayString(withNullability: false);
|
||||||
}
|
}
|
||||||
return getDisplayString(withNullability: true);
|
return getDisplayString(withNullability: true);
|
||||||
} else {
|
} 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
|
/// 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
|
/// table has declared an `IntColumn`, the matching dart type name would be
|
||||||
/// [int].
|
/// [int].
|
||||||
String dartTypeCode([GenerationOptions options = const GenerationOptions()]) {
|
String dartTypeCode() {
|
||||||
final converter = typeConverter;
|
final converter = typeConverter;
|
||||||
if (converter != null) {
|
if (converter != null) {
|
||||||
var inner = converter.dartType.codeString(options);
|
var inner = converter.dartType.codeString();
|
||||||
if (converter.canBeSkippedForNulls && nullable) inner += '?';
|
if (converter.canBeSkippedForNulls && nullable) inner += '?';
|
||||||
return isArray ? 'List<$inner>' : inner;
|
return isArray ? 'List<$inner>' : inner;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,6 @@ import 'package:analyzer/dart/element/type.dart';
|
||||||
import 'package:analyzer/dart/element/type_provider.dart';
|
import 'package:analyzer/dart/element/type_provider.dart';
|
||||||
import 'package:drift_dev/src/model/table.dart';
|
import 'package:drift_dev/src/model/table.dart';
|
||||||
import 'package:drift_dev/src/utils/type_utils.dart';
|
import 'package:drift_dev/src/utils/type_utils.dart';
|
||||||
import 'package:drift_dev/src/writer/writer.dart';
|
|
||||||
|
|
||||||
import 'types.dart';
|
import 'types.dart';
|
||||||
|
|
||||||
|
@ -92,12 +91,12 @@ class UsedTypeConverter {
|
||||||
bool nullable,
|
bool nullable,
|
||||||
TypeProvider typeProvider,
|
TypeProvider typeProvider,
|
||||||
) {
|
) {
|
||||||
if (enumType.element is! ClassElement) {
|
if (enumType is! InterfaceType) {
|
||||||
throw InvalidTypeForEnumConverterException('Not a class', enumType);
|
throw InvalidTypeForEnumConverterException('Not a class', enumType);
|
||||||
}
|
}
|
||||||
|
|
||||||
final creatingClass = enumType.element as ClassElement;
|
final creatingClass = enumType.element2;
|
||||||
if (!creatingClass.isEnum) {
|
if (creatingClass is! EnumElement) {
|
||||||
throw InvalidTypeForEnumConverterException('Not an enum', enumType);
|
throw InvalidTypeForEnumConverterException('Not an enum', enumType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,23 +131,22 @@ class UsedTypeConverter {
|
||||||
return dartTypeIsNullable || (canBeSkippedForNulls && nullableInSql);
|
return dartTypeIsNullable || (canBeSkippedForNulls && nullableInSql);
|
||||||
}
|
}
|
||||||
|
|
||||||
String dartTypeCode(GenerationOptions options, bool nullableInSql) {
|
String dartTypeCode(bool nullableInSql) {
|
||||||
var type = dartType.codeString(options);
|
var type = dartType.codeString();
|
||||||
if (canBeSkippedForNulls && nullableInSql) type += '?';
|
if (canBeSkippedForNulls && nullableInSql) type += '?';
|
||||||
|
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A suitable typename to store an instance of the type converter used here.
|
/// A suitable typename to store an instance of the type converter used here.
|
||||||
String converterNameInCode(GenerationOptions options,
|
String converterNameInCode({bool makeNullable = false}) {
|
||||||
{bool makeNullable = false}) {
|
|
||||||
var sqlDartType = sqlType.getDisplayString(withNullability: true);
|
var sqlDartType = sqlType.getDisplayString(withNullability: true);
|
||||||
if (makeNullable) sqlDartType += '?';
|
if (makeNullable) sqlDartType += '?';
|
||||||
|
|
||||||
final className =
|
final className =
|
||||||
alsoAppliesToJsonConversion ? 'JsonTypeConverter' : 'TypeConverter';
|
alsoAppliesToJsonConversion ? 'JsonTypeConverter' : 'TypeConverter';
|
||||||
|
|
||||||
return '$className<${dartTypeCode(options, makeNullable)}, $sqlDartType>';
|
return '$className<${dartTypeCode(makeNullable)}, $sqlDartType>';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -166,7 +166,7 @@ class FindSchemaDifferences {
|
||||||
|
|
||||||
if (refType != actType) {
|
if (refType != actType) {
|
||||||
return FoundDifference(
|
return FoundDifference(
|
||||||
'Different types: ${ref.typeName} and ${act.typeName}');
|
'Different types: Expected ${ref.typeName}, got ${act.typeName}');
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -174,19 +174,20 @@ class FindSchemaDifferences {
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
final firstSpan = ref.constraints.spanOrNull?.text ?? '';
|
final firstSpan = ref.constraints.spanOrNull?.text ?? '';
|
||||||
final secondSpan = act.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();
|
return const Success();
|
||||||
}
|
}
|
||||||
|
|
||||||
CompareResult _compareByAst(AstNode a, AstNode b) {
|
CompareResult _compareByAst(AstNode reference, AstNode actual) {
|
||||||
try {
|
try {
|
||||||
enforceEqual(a, b);
|
enforceEqual(reference, actual);
|
||||||
return const Success();
|
return const Success();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return FoundDifference(
|
return FoundDifference('Not equal: Expected `${reference.span?.text}`, '
|
||||||
'Not equal: `${a.span?.text}` and `${b.span?.text}`');
|
'got `${actual.span?.text}`');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,34 +1,40 @@
|
||||||
import 'package:analyzer/dart/element/nullability_suffix.dart';
|
import 'package:analyzer/dart/element/nullability_suffix.dart';
|
||||||
import 'package:analyzer/dart/element/type.dart';
|
import 'package:analyzer/dart/element/type.dart';
|
||||||
import 'package:drift_dev/src/writer/writer.dart';
|
|
||||||
|
|
||||||
bool isFromMoor(DartType type) {
|
bool isFromDrift(DartType type) {
|
||||||
final firstComponent = type.element?.library?.location?.components.first;
|
if (type is! InterfaceType) return false;
|
||||||
|
|
||||||
|
final firstComponent = type.element2.library.location?.components.first;
|
||||||
if (firstComponent == null) return false;
|
if (firstComponent == null) return false;
|
||||||
|
|
||||||
return firstComponent.contains('drift') || firstComponent.contains('moor');
|
return firstComponent.contains('drift') || firstComponent.contains('moor');
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isColumn(DartType type) {
|
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('Column') &&
|
||||||
!name.contains('Builder');
|
!name.contains('Builder');
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isExpression(DartType type) {
|
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 {
|
extension TypeUtils on DartType {
|
||||||
|
String? get nameIfInterfaceType {
|
||||||
|
final $this = this;
|
||||||
|
return $this is InterfaceType ? $this.element2.name : null;
|
||||||
|
}
|
||||||
|
|
||||||
String get userVisibleName => getDisplayString(withNullability: true);
|
String get userVisibleName => getDisplayString(withNullability: true);
|
||||||
|
|
||||||
/// How this type should look like in generated code.
|
/// How this type should look like in generated code.
|
||||||
String codeString([GenerationOptions options = const GenerationOptions()]) {
|
String codeString() {
|
||||||
if (nullabilitySuffix == NullabilitySuffix.star) {
|
if (nullabilitySuffix == NullabilitySuffix.star) {
|
||||||
// We can't actually use the legacy star in code, so don't show it.
|
// We can't actually use the legacy star in code, so don't show it.
|
||||||
return getDisplayString(withNullability: false);
|
return getDisplayString(withNullability: false);
|
||||||
|
|
|
@ -99,7 +99,7 @@ class DatabaseWriter {
|
||||||
|
|
||||||
// Write fields to access an dao. We use a lazy getter for that.
|
// Write fields to access an dao. We use a lazy getter for that.
|
||||||
for (final dao in db.daos) {
|
for (final dao in db.daos) {
|
||||||
final typeName = dao.codeString(scope.generationOptions);
|
final typeName = dao.codeString();
|
||||||
final getterName = ReCase(typeName).camelCase;
|
final getterName = ReCase(typeName).camelCase;
|
||||||
final databaseImplName = db.fromClass!.name;
|
final databaseImplName = db.fromClass!.name;
|
||||||
|
|
||||||
|
|
|
@ -293,7 +293,7 @@ class QueryWriter {
|
||||||
final namedElements = <FoundElement>[];
|
final namedElements = <FoundElement>[];
|
||||||
|
|
||||||
String typeFor(FoundElement element) {
|
String typeFor(FoundElement element) {
|
||||||
var type = element.dartTypeCode(scope.generationOptions);
|
var type = element.dartTypeCode();
|
||||||
|
|
||||||
if (element is FoundDartPlaceholder &&
|
if (element is FoundDartPlaceholder &&
|
||||||
element.writeAsScopedFunction(options)) {
|
element.writeAsScopedFunction(options)) {
|
||||||
|
|
|
@ -30,7 +30,7 @@ class ResultSetWriter {
|
||||||
// write fields
|
// write fields
|
||||||
for (final column in resultSet.columns) {
|
for (final column in resultSet.columns) {
|
||||||
final name = resultSet.dartNameFor(column);
|
final name = resultSet.dartNameFor(column);
|
||||||
final runtimeType = column.dartTypeCode(scope.generationOptions);
|
final runtimeType = column.dartTypeCode();
|
||||||
|
|
||||||
into.write('$modifier $runtimeType $name\n;');
|
into.write('$modifier $runtimeType $name\n;');
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ class ResultSetWriter {
|
||||||
|
|
||||||
for (final nested in resultSet.nestedResults) {
|
for (final nested in resultSet.nestedResults) {
|
||||||
if (nested is NestedResultTable) {
|
if (nested is NestedResultTable) {
|
||||||
var typeName = nested.table.dartTypeCode(scope.generationOptions);
|
var typeName = nested.table.dartTypeCode();
|
||||||
final fieldName = nested.dartFieldName;
|
final fieldName = nested.dartFieldName;
|
||||||
|
|
||||||
if (nested.isNullable) {
|
if (nested.isNullable) {
|
||||||
|
|
|
@ -48,7 +48,7 @@ class DataClassWriter {
|
||||||
_buffer.write('${column.documentationComment}\n');
|
_buffer.write('${column.documentationComment}\n');
|
||||||
}
|
}
|
||||||
final modifier = scope.options.fieldModifier;
|
final modifier = scope.options.fieldModifier;
|
||||||
_buffer.write('$modifier ${column.dartTypeCode(scope.generationOptions)} '
|
_buffer.write('$modifier ${column.dartTypeCode()} '
|
||||||
'${column.dartGetterName}; \n');
|
'${column.dartGetterName}; \n');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,7 +120,7 @@ class DataClassWriter {
|
||||||
typeConverter.tableAndField(forNullableColumn: column.nullable);
|
typeConverter.tableAndField(forNullableColumn: column.nullable);
|
||||||
deserialized = '$converterField.fromJson($fromConverter)';
|
deserialized = '$converterField.fromJson($fromConverter)';
|
||||||
} else {
|
} else {
|
||||||
final type = column.dartTypeCode(scope.generationOptions);
|
final type = column.dartTypeCode();
|
||||||
|
|
||||||
deserialized = "serializer.fromJson<$type>(json['$jsonKey'])";
|
deserialized = "serializer.fromJson<$type>(json['$jsonKey'])";
|
||||||
}
|
}
|
||||||
|
@ -151,7 +151,7 @@ class DataClassWriter {
|
||||||
final getter = column.dartGetterName;
|
final getter = column.dartGetterName;
|
||||||
final needsThis = getter == 'serializer';
|
final needsThis = getter == 'serializer';
|
||||||
var value = needsThis ? 'this.$getter' : getter;
|
var value = needsThis ? 'this.$getter' : getter;
|
||||||
var dartType = column.dartTypeCode(scope.generationOptions);
|
var dartType = column.dartTypeCode();
|
||||||
|
|
||||||
final typeConverter = column.typeConverter;
|
final typeConverter = column.typeConverter;
|
||||||
if (typeConverter != null && typeConverter.alsoAppliesToJsonConversion) {
|
if (typeConverter != null && typeConverter.alsoAppliesToJsonConversion) {
|
||||||
|
@ -177,7 +177,7 @@ class DataClassWriter {
|
||||||
final last = i == columns.length - 1;
|
final last = i == columns.length - 1;
|
||||||
final isNullable = column.nullableInDart;
|
final isNullable = column.nullableInDart;
|
||||||
|
|
||||||
final typeName = column.dartTypeCode(scope.generationOptions);
|
final typeName = column.dartTypeCode();
|
||||||
if (wrapNullableInValue && isNullable) {
|
if (wrapNullableInValue && isNullable) {
|
||||||
_buffer
|
_buffer
|
||||||
..write('Value<$typeName> ${column.dartGetterName} ')
|
..write('Value<$typeName> ${column.dartGetterName} ')
|
||||||
|
|
|
@ -100,7 +100,7 @@ abstract class TableOrViewWriter {
|
||||||
if (converter != null) {
|
if (converter != null) {
|
||||||
// Generate a GeneratedColumnWithTypeConverter instance, as it has
|
// Generate a GeneratedColumnWithTypeConverter instance, as it has
|
||||||
// additional methods to check for equality against a mapped value.
|
// 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 =
|
final converterCode =
|
||||||
converter.tableAndField(forNullableColumn: column.nullable);
|
converter.tableAndField(forNullableColumn: column.nullable);
|
||||||
|
@ -134,7 +134,7 @@ abstract class TableOrViewWriter {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final dataClassName = tableOrView.dartTypeCode(scope.generationOptions);
|
final dataClassName = tableOrView.dartTypeCode();
|
||||||
|
|
||||||
buffer
|
buffer
|
||||||
..write('@override\n$dataClassName map(Map<String, dynamic> data, '
|
..write('@override\n$dataClassName map(Map<String, dynamic> data, '
|
||||||
|
@ -321,7 +321,7 @@ class TableWriter extends TableOrViewWriter {
|
||||||
|
|
||||||
void _writeConvertersAsStaticFields() {
|
void _writeConvertersAsStaticFields() {
|
||||||
for (final converter in table.converters) {
|
for (final converter in table.converters) {
|
||||||
final typeName = converter.converterNameInCode(scope.generationOptions);
|
final typeName = converter.converterNameInCode();
|
||||||
final code = converter.expression;
|
final code = converter.expression;
|
||||||
|
|
||||||
buffer.write('static $typeName ${converter.fieldName} = $code;');
|
buffer.write('static $typeName ${converter.fieldName} = $code;');
|
||||||
|
@ -334,8 +334,8 @@ class TableWriter extends TableOrViewWriter {
|
||||||
if (converter != null &&
|
if (converter != null &&
|
||||||
converter.canBeSkippedForNulls &&
|
converter.canBeSkippedForNulls &&
|
||||||
column.nullable) {
|
column.nullable) {
|
||||||
final nullableTypeName = converter
|
final nullableTypeName =
|
||||||
.converterNameInCode(scope.generationOptions, makeNullable: true);
|
converter.converterNameInCode(makeNullable: true);
|
||||||
|
|
||||||
final wrap = converter.alsoAppliesToJsonConversion
|
final wrap = converter.alsoAppliesToJsonConversion
|
||||||
? 'JsonTypeConverter.asNullable'
|
? 'JsonTypeConverter.asNullable'
|
||||||
|
|
|
@ -43,7 +43,7 @@ class UpdateCompanionWriter {
|
||||||
void _writeFields() {
|
void _writeFields() {
|
||||||
for (final column in columns) {
|
for (final column in columns) {
|
||||||
final modifier = scope.options.fieldModifier;
|
final modifier = scope.options.fieldModifier;
|
||||||
final type = column.dartTypeCode(scope.generationOptions);
|
final type = column.dartTypeCode();
|
||||||
_buffer.write('$modifier Value<$type> ${column.dartGetterName};\n');
|
_buffer.write('$modifier Value<$type> ${column.dartGetterName};\n');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -83,7 +83,7 @@ class UpdateCompanionWriter {
|
||||||
|
|
||||||
if (table.isColumnRequiredForInsert(column)) {
|
if (table.isColumnRequiredForInsert(column)) {
|
||||||
requiredColumns.add(column);
|
requiredColumns.add(column);
|
||||||
final typeName = column.dartTypeCode(scope.generationOptions);
|
final typeName = column.dartTypeCode();
|
||||||
|
|
||||||
_buffer.write('required $typeName $param,');
|
_buffer.write('required $typeName $param,');
|
||||||
} else {
|
} else {
|
||||||
|
@ -151,7 +151,7 @@ class UpdateCompanionWriter {
|
||||||
}
|
}
|
||||||
first = false;
|
first = false;
|
||||||
|
|
||||||
final typeName = column.dartTypeCode(scope.generationOptions);
|
final typeName = column.dartTypeCode();
|
||||||
_buffer.write('Value<$typeName>? ${column.dartGetterName}');
|
_buffer.write('Value<$typeName>? ${column.dartGetterName}');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ dependencies:
|
||||||
sqlparser: ^0.22.0
|
sqlparser: ^0.22.0
|
||||||
|
|
||||||
# Dart analysis
|
# Dart analysis
|
||||||
analyzer: "^4.3.0"
|
analyzer: "^4.4.0"
|
||||||
analyzer_plugin: ^0.11.0
|
analyzer_plugin: ^0.11.0
|
||||||
source_span: ^1.5.5
|
source_span: ^1.5.5
|
||||||
package_config: ^2.0.0
|
package_config: ^2.0.0
|
||||||
|
|
|
@ -44,7 +44,7 @@ void main() {
|
||||||
expect(parser.returnExpressionOfMethod(node)!.toSource(), source);
|
expect(parser.returnExpressionOfMethod(node)!.toSource(), source);
|
||||||
}
|
}
|
||||||
|
|
||||||
final testClass = library.getType('Test');
|
final testClass = library.getClass('Test');
|
||||||
|
|
||||||
await _verifyReturnExpressionMatches(
|
await _verifyReturnExpressionMatches(
|
||||||
testClass!.getGetter('getter')!, "'foo'");
|
testClass!.getGetter('getter')!, "'foo'");
|
||||||
|
|
|
@ -146,7 +146,7 @@ void main() {
|
||||||
});
|
});
|
||||||
|
|
||||||
Future<DriftTable?> parse(String name) async {
|
Future<DriftTable?> parse(String name) async {
|
||||||
return parser.parseTable(dartStep.library.getType(name)!);
|
return parser.parseTable(dartStep.library.getClass(name)!);
|
||||||
}
|
}
|
||||||
|
|
||||||
group('table names', () {
|
group('table names', () {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
@Tags(['analyzer'])
|
@Tags(['analyzer'])
|
||||||
import 'package:drift_dev/src/analyzer/runner/results.dart';
|
import 'package:drift_dev/src/analyzer/runner/results.dart';
|
||||||
|
import 'package:drift_dev/src/utils/type_utils.dart';
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
import '../utils.dart';
|
import '../utils.dart';
|
||||||
|
@ -48,7 +49,7 @@ class ProductsDao extends BaseProductsDao with _$ProductDaoMixin {
|
||||||
expect(file.errors.errors, isEmpty);
|
expect(file.errors.errors, isEmpty);
|
||||||
|
|
||||||
final dao = (file.currentResult as ParsedDartFile).declaredDaos.single;
|
final dao = (file.currentResult as ParsedDartFile).declaredDaos.single;
|
||||||
expect(dao.dbClass.element!.name, 'MyDatabase');
|
expect(dao.dbClass.nameIfInterfaceType, 'MyDatabase');
|
||||||
|
|
||||||
state.close();
|
state.close();
|
||||||
});
|
});
|
||||||
|
|
|
@ -70,7 +70,7 @@ void main() {
|
||||||
expect(result, hasChanges);
|
expect(result, hasChanges);
|
||||||
expect(
|
expect(
|
||||||
result.describe(),
|
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, hasChanges);
|
||||||
expect(
|
expect(
|
||||||
result.describe(),
|
result.describe(),
|
||||||
contains('Not equal: `PRIMARY KEY NOT NULL` and ``'),
|
contains(
|
||||||
|
'Not equal: `PRIMARY KEY NOT NULL` (expected) and `` (actual)'),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -4,6 +4,7 @@ import 'package:analyzer/dart/ast/ast.dart';
|
||||||
import 'package:analyzer/file_system/memory_file_system.dart';
|
import 'package:analyzer/file_system/memory_file_system.dart';
|
||||||
import 'package:build/build.dart';
|
import 'package:build/build.dart';
|
||||||
import 'package:build_test/build_test.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:drift_dev/src/backends/build/drift_builder.dart';
|
||||||
import 'package:pub_semver/pub_semver.dart';
|
import 'package:pub_semver/pub_semver.dart';
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
|
@ -81,15 +82,18 @@ class _GeneratesConstDataClasses extends Matcher {
|
||||||
|
|
||||||
final definedClasses = parsed.declarations.whereType<ClassDeclaration>();
|
final definedClasses = parsed.declarations.whereType<ClassDeclaration>();
|
||||||
for (final definedClass in definedClasses) {
|
for (final definedClass in definedClasses) {
|
||||||
if (expectedWithConstConstructor.contains(definedClass.name.name)) {
|
if (expectedWithConstConstructor.contains(definedClass.name2.lexeme)) {
|
||||||
final constructor = definedClass.getConstructor(null);
|
final constructor = definedClass.members
|
||||||
|
.whereType<ConstructorDeclaration>()
|
||||||
|
.firstWhereOrNull((e) => e.name2 == null);
|
||||||
if (constructor?.constKeyword == null) {
|
if (constructor?.constKeyword == null) {
|
||||||
matchState['desc'] = 'Constructor ${definedClass.name.name} is not '
|
matchState['desc'] =
|
||||||
|
'Constructor ${definedClass.name2.lexeme} is not '
|
||||||
'const.';
|
'const.';
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
remaining.remove(definedClass.name.name);
|
remaining.remove(definedClass.name2.lexeme);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -80,25 +80,26 @@ class _GeneratesWithoutFinalFields extends Matcher {
|
||||||
|
|
||||||
final definedClasses = parsed.declarations.whereType<ClassDeclaration>();
|
final definedClasses = parsed.declarations.whereType<ClassDeclaration>();
|
||||||
for (final definedClass in definedClasses) {
|
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) {
|
for (final member in definedClass.members) {
|
||||||
if (member is FieldDeclaration) {
|
if (member is FieldDeclaration) {
|
||||||
if (member.fields.isFinal) {
|
if (member.fields.isFinal) {
|
||||||
matchState['desc'] =
|
matchState['desc'] =
|
||||||
'Field ${member.fields.variables.first.name.name} in '
|
'Field ${member.fields.variables.first.name2.lexeme} in '
|
||||||
'${definedClass.name.name} is final.';
|
'$definedClassName is final.';
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (member is ConstructorDeclaration) {
|
} else if (member is ConstructorDeclaration) {
|
||||||
if (member.constKeyword != null) {
|
if (member.constKeyword != null) {
|
||||||
matchState['desc'] = 'Constructor ${member.name?.name ?? ''} in '
|
matchState['desc'] = 'Constructor ${member.name2?.lexeme ?? ''} '
|
||||||
'${definedClass.name.name} is constant.';
|
'in $definedClassName is constant.';
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
remaining.remove(definedClass.name.name);
|
remaining.remove(definedClassName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue