Make `forNullableType` even more lenient

This commit is contained in:
Simon Binder 2022-08-18 17:35:54 +02:00
parent d205ab9477
commit 2d75e1fd62
No known key found for this signature in database
GPG Key ID: 7891917E4147B8C0
4 changed files with 55 additions and 5 deletions

View File

@ -1,4 +1,4 @@
## 2.0.2
## 2.0.2+1
- Revert the breaking change around `QueryRow.read` only returning non-nullable
values now - it was causing issues with type inference in some cases.

View File

@ -2,6 +2,7 @@ import 'dart:core';
import 'dart:core' as core;
import 'dart:typed_data';
import 'package:collection/collection.dart';
import 'package:convert/convert.dart';
import 'package:meta/meta.dart';
@ -182,8 +183,19 @@ class SqlTypes {
}
}
/// In [DriftSqlType.forNullableType], we need to do an `is` check over
/// `DriftSqlType<T>` with a potentially nullable `T`. Since `DriftSqlType` is
/// defined with a non-nullable `T`, this is illegal.
/// The non-nullable upper bound in [DriftSqlType] is generally useful, for
/// instance because it works well with [SqlTypes.read] which can then have a
/// sound nullable return type.
///
/// As a hack, we define this base class that doesn't have this restriction and
/// use this one for type checks.
abstract class _InternalDriftSqlType<T> {}
/// An enumation of type mappings that are builtin to drift and `drift_dev`.
enum DriftSqlType<T extends Object> {
enum DriftSqlType<T extends Object> implements _InternalDriftSqlType<T> {
/// A boolean type, represented as `0` or `1` (int) in SQL.
bool<core.bool>(),
@ -282,12 +294,16 @@ enum DriftSqlType<T extends Object> {
/// Using [forType] should pretty much always be preferred over this method,
/// this one just exists for backwards compatibility.
static DriftSqlType forNullableType<Dart>() {
final type = _dartToDrift[Dart];
// Lookup the type in the map first for faster lookups. Go back to a full
// typecheck where that doesn't work (which can be the case for complex
// type like `forNullableType<FutureOr<int?>>`).
final type = _dartToDrift[Dart] ??
values.whereType<_InternalDriftSqlType<Dart>>().singleOrNull;
if (type == null) {
throw ArgumentError('Could not find a matching SQL type for $Dart');
}
return type;
return type as DriftSqlType;
}
}

View File

@ -1,6 +1,6 @@
name: drift
description: Drift is a reactive library to store relational data in Dart and Flutter applications.
version: 2.0.2
version: 2.0.2+1
repository: https://github.com/simolus3/drift
homepage: https://drift.simonbinder.eu/
issue_tracker: https://github.com/simolus3/drift/issues

View File

@ -0,0 +1,34 @@
import 'package:drift/drift.dart' hide isNotNull, isNull;
import 'package:test/test.dart';
import '../generated/todos.dart';
import '../test_utils/test_utils.dart';
// Regression test for https://github.com/simolus3/drift/issues/1991
Future<int?> _getCategoryIdByDescription(
TodoDb appDatabase, String description) async {
const q = "SELECT id FROM categories WHERE desc = ?";
final row = await appDatabase.customSelect(
q,
variables: [Variable<String>(description)],
).getSingleOrNull();
return row?.read("id");
}
void main() {
test('type inference for nullable call in async function', () async {
final db = TodoDb.connect(testInMemoryDatabase());
addTearDown(db.close);
final categoryDescription = 'category description';
expect(await _getCategoryIdByDescription(db, categoryDescription), isNull);
await db.categories.insertOne(
CategoriesCompanion.insert(description: categoryDescription));
// Search the category we just inserted
expect(
await _getCategoryIdByDescription(db, categoryDescription), isNotNull);
});
}