mirror of https://github.com/AMT-Cheif/drift.git
Run tests with null assertions enabled
This commit is contained in:
parent
ca41c38272
commit
51e62d4e2f
|
@ -29,7 +29,7 @@ jobs:
|
|||
# build, test and upload coverage
|
||||
- run: dart run build_runner build --delete-conflicting-outputs
|
||||
working-directory: moor
|
||||
- run: dart --no-sound-null-safety test #-x background_isolate --coverage=coverage
|
||||
- run: dart --no-sound-null-safety --null-assertions test #-x background_isolate --coverage=coverage
|
||||
working-directory: moor
|
||||
# - uses: actions/upload-artifact@v2
|
||||
# with:
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
## unreleased
|
||||
## unreleased (breaking - 4.0)
|
||||
|
||||
- __Breaking__: Removed the second type parameter from `TypedResult.read`
|
||||
- Support null safety
|
||||
- Changed the sql representation of text types from `VARCHAR` to `TEXT`
|
||||
- Added extensions for `isNull` and `isNotNull`
|
||||
- Support creating a `VmDatabase` from a raw sqlite3 `Database` via `VmDatabase.opened`
|
||||
|
|
|
@ -143,7 +143,7 @@ class TypedResult {
|
|||
/// as a column, for instance via [JoinedSelectStatement.addColumns].
|
||||
///
|
||||
/// To access the underlying columns directly, use [rawData].
|
||||
D? read<D, T extends SqlType<D>>(Expression<D> expr) {
|
||||
D? read<D>(Expression<D> expr) {
|
||||
if (_parsedExpressions != null) {
|
||||
return _parsedExpressions![expr] as D;
|
||||
}
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
//@dart=2.9
|
||||
import 'package:moor/moor.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
void main() {
|
||||
final nullable = GeneratedDateTimeColumn('name', null, true);
|
||||
final nonNull = GeneratedDateTimeColumn('name', null, false);
|
||||
final nullable = GeneratedDateTimeColumn('name', 'table', true);
|
||||
final nonNull = GeneratedDateTimeColumn('name', 'table', false);
|
||||
|
||||
test('should write column definition', () {
|
||||
final nonNullQuery = GenerationContext(null, null);
|
||||
final nullableQuery = GenerationContext(null, null);
|
||||
final nonNullQuery = GenerationContext.fromDb(null);
|
||||
final nullableQuery = GenerationContext.fromDb(null);
|
||||
nonNull.writeColumnDefinition(nonNullQuery);
|
||||
nullable.writeColumnDefinition(nullableQuery);
|
||||
|
||||
|
@ -17,7 +16,7 @@ void main() {
|
|||
});
|
||||
|
||||
test('can compare', () {
|
||||
final ctx = GenerationContext(null, null);
|
||||
final ctx = GenerationContext.fromDb(null);
|
||||
nonNull.isSmallerThan(currentDateAndTime).writeInto(ctx);
|
||||
|
||||
expect(ctx.sql, "name < strftime('%s', CURRENT_TIMESTAMP)");
|
||||
|
|
|
@ -14,7 +14,7 @@ void main() {
|
|||
hasAutoIncrement: true,
|
||||
);
|
||||
|
||||
final context = GenerationContext.fromDb(TodoDb(null));
|
||||
final context = GenerationContext.fromDb(TodoDb());
|
||||
column.writeColumnDefinition(context);
|
||||
|
||||
expect(
|
||||
|
@ -30,7 +30,7 @@ void main() {
|
|||
hasAutoIncrement: false,
|
||||
);
|
||||
|
||||
final context = GenerationContext.fromDb(TodoDb(null));
|
||||
final context = GenerationContext.fromDb(TodoDb());
|
||||
column.writeColumnDefinition(context);
|
||||
|
||||
expect(context.sql, equals('foo INTEGER NOT NULL PRIMARY KEY'));
|
||||
|
|
|
@ -2,6 +2,8 @@ import 'package:moor/moor.dart';
|
|||
// ignore: import_of_legacy_library_into_null_safe
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
import '../utils/null_executor.dart';
|
||||
|
||||
part 'todos.g.dart';
|
||||
|
||||
mixin AutoIncrement on Table {
|
||||
|
@ -112,7 +114,7 @@ class CustomConverter extends TypeConverter<MyCustomObject, String> {
|
|||
},
|
||||
)
|
||||
class TodoDb extends _$TodoDb {
|
||||
TodoDb(QueryExecutor e) : super(e) {
|
||||
TodoDb([QueryExecutor? e]) : super(e ?? const NullExecutor()) {
|
||||
moorRuntimeOptions.dontWarnAboutMultipleDatabases = true;
|
||||
}
|
||||
TodoDb.connect(DatabaseConnection connection) : super.connect(connection) {
|
||||
|
|
|
@ -87,7 +87,7 @@ class MockTransactionExecutor extends MockTransactionsInternal {
|
|||
when(runInsert(any, any)).thenAnswer((_) => Future.value(0));
|
||||
when(runCustom(any, any)).thenAnswer((_) => Future.value());
|
||||
when(runBatched(any)).thenAnswer((_) => Future.value());
|
||||
when(ensureOpen(any)).thenAnswer((_) => Future.value());
|
||||
when(ensureOpen(any)).thenAnswer((_) => Future.value(true));
|
||||
|
||||
when(send()).thenAnswer((_) => Future.value(null));
|
||||
when(rollback()).thenAnswer((_) => Future.value(null));
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
import 'package:moor/backends.dart';
|
||||
|
||||
class NullExecutor implements QueryExecutor {
|
||||
const NullExecutor();
|
||||
|
||||
@override
|
||||
TransactionExecutor beginTransaction() {
|
||||
throw UnsupportedError('beginTransaction');
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> ensureOpen(QueryExecutorUser user) {
|
||||
throw UnsupportedError('ensureOpen');
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> runBatched(BatchedStatements statements) {
|
||||
throw UnsupportedError('runBatched');
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> runCustom(String statement, [List? args]) {
|
||||
throw UnsupportedError('runCustom');
|
||||
}
|
||||
|
||||
@override
|
||||
Future<int> runDelete(String statement, List args) {
|
||||
throw UnsupportedError('runDelete');
|
||||
}
|
||||
|
||||
@override
|
||||
Future<int> runInsert(String statement, List args) {
|
||||
throw UnsupportedError('runInsert');
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<Map<String, dynamic>>> runSelect(String statement, List args) {
|
||||
throw UnsupportedError('runSelect');
|
||||
}
|
||||
|
||||
@override
|
||||
Future<int> runUpdate(String statement, List args) {
|
||||
throw UnsupportedError('runUpdate');
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() => Future.value();
|
||||
|
||||
@override
|
||||
SqlDialect get dialect => SqlDialect.sqlite;
|
||||
}
|
|
@ -20,13 +20,9 @@ void main() {
|
|||
});
|
||||
|
||||
test('can deserialize ints as doubles', () {
|
||||
final entry = TableWithoutPKData.fromJson({
|
||||
'notReallyAnId': 3,
|
||||
'someFloat': 4,
|
||||
});
|
||||
const serializer = ValueSerializer.defaults();
|
||||
|
||||
expect(entry,
|
||||
TableWithoutPKData(notReallyAnId: 3, someFloat: 4, custom: null));
|
||||
expect(serializer.fromJson<double>(3), 3.0);
|
||||
});
|
||||
|
||||
test('default serializer can be overridden globally', () {
|
||||
|
|
|
@ -43,19 +43,20 @@ void main() {
|
|||
final db = DelegatedDatabase(delegate, isSequential: sequential);
|
||||
await db.ensureOpen(_FakeExecutorUser());
|
||||
|
||||
expect(await db.runSelect(null, null), isEmpty);
|
||||
expect(await db.runUpdate(null, null), 3);
|
||||
expect(await db.runInsert(null, null), 4);
|
||||
await db.runCustom(null);
|
||||
await db.runBatched(null);
|
||||
expect(await db.runSelect('select', const []), isEmpty);
|
||||
expect(await db.runUpdate('update', const []), 3);
|
||||
expect(await db.runInsert('insert', const []), 4);
|
||||
await db.runCustom('custom');
|
||||
final batched = BatchedStatements([], []);
|
||||
await db.runBatched(batched);
|
||||
|
||||
verifyInOrder([
|
||||
delegate.isOpen,
|
||||
delegate.runSelect(null, null),
|
||||
delegate.runUpdate(null, null),
|
||||
delegate.runInsert(null, null),
|
||||
delegate.runCustom(null, []),
|
||||
delegate.runBatched(null),
|
||||
delegate.runSelect('select', const []),
|
||||
delegate.runUpdate('update', const []),
|
||||
delegate.runInsert('insert', const []),
|
||||
delegate.runCustom('custom', const []),
|
||||
delegate.runBatched(batched),
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
@ -150,12 +151,12 @@ void main() {
|
|||
|
||||
final transaction = db.beginTransaction();
|
||||
await transaction.ensureOpen(_FakeExecutorUser());
|
||||
await transaction.runSelect(null, null);
|
||||
await transaction.runSelect('SELECT 1;', const []);
|
||||
await transaction.send();
|
||||
|
||||
verifyInOrder([
|
||||
delegate.runCustom('BEGIN TRANSACTION', []),
|
||||
delegate.runSelect(null, null),
|
||||
delegate.runSelect('SELECT 1;', const []),
|
||||
delegate.runCustom('COMMIT TRANSACTION', []),
|
||||
]);
|
||||
});
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
//@dart=2.9
|
||||
import 'package:moor/moor.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
|
@ -6,8 +5,8 @@ import '../data/tables/todos.dart';
|
|||
import '../data/utils/expect_equality.dart';
|
||||
|
||||
void main() {
|
||||
final expression = GeneratedIntColumn('col', null, false);
|
||||
final db = TodoDb(null);
|
||||
final expression = GeneratedIntColumn('col', 'table', false);
|
||||
final db = TodoDb();
|
||||
|
||||
final comparisons = {
|
||||
expression.isSmallerThan: '<',
|
||||
|
@ -24,7 +23,7 @@ void main() {
|
|||
};
|
||||
|
||||
group('can compare with other expressions', () {
|
||||
final compare = GeneratedIntColumn('compare', null, false);
|
||||
final compare = GeneratedIntColumn('compare', 'table', false);
|
||||
|
||||
comparisons.forEach((fn, value) {
|
||||
test('for operator $value', () {
|
||||
|
@ -54,8 +53,8 @@ void main() {
|
|||
|
||||
group('between', () {
|
||||
test('other expressions', () {
|
||||
final low = GeneratedIntColumn('low', null, false);
|
||||
final high = GeneratedIntColumn('high', null, false);
|
||||
final low = GeneratedIntColumn('low', 'table', false);
|
||||
final high = GeneratedIntColumn('high', 'table', false);
|
||||
|
||||
final ctx = GenerationContext.fromDb(db);
|
||||
expression.isBetween(low, high).writeInto(ctx);
|
||||
|
|
|
@ -32,7 +32,7 @@ void main() {
|
|||
}
|
||||
|
||||
void testStringMapping(String dart, String expectedLiteral) {
|
||||
final ctx = GenerationContext.fromDb(TodoDb(null));
|
||||
final ctx = GenerationContext.fromDb(TodoDb());
|
||||
final constant = Constant(dart);
|
||||
|
||||
constant.writeInto(ctx);
|
||||
|
|
|
@ -8,7 +8,7 @@ import '../data/utils/expect_generated.dart';
|
|||
typedef _Extractor = Expression<int> Function(Expression<DateTime> d);
|
||||
|
||||
void main() {
|
||||
final column = GeneratedDateTimeColumn('val', null, false);
|
||||
final column = GeneratedDateTimeColumn('val', 'table', false);
|
||||
|
||||
group('extracting information via top-level method', () {
|
||||
final expectedResults = <_Extractor, String>{
|
||||
|
|
|
@ -7,10 +7,10 @@ import '../data/utils/expect_generated.dart';
|
|||
|
||||
void main() {
|
||||
test('in expressions are generated', () {
|
||||
final innerExpression = GeneratedTextColumn('name', null, true);
|
||||
final innerExpression = GeneratedTextColumn('name', 'table', true);
|
||||
final isInExpression = innerExpression.isIn(['Max', 'Tobias']);
|
||||
|
||||
final context = GenerationContext.fromDb(TodoDb(null));
|
||||
final context = GenerationContext.fromDb(TodoDb());
|
||||
isInExpression.writeInto(context);
|
||||
|
||||
expect(context.sql, 'name IN (?, ?)');
|
||||
|
@ -18,7 +18,7 @@ void main() {
|
|||
});
|
||||
|
||||
test('not in expressions are generated', () {
|
||||
final innerExpression = GeneratedTextColumn('name', null, true);
|
||||
final innerExpression = GeneratedTextColumn('name', 'table', true);
|
||||
final isNotIn = innerExpression.isNotIn(['Max', 'Tobias']);
|
||||
|
||||
expect(isNotIn, generates('name NOT IN (?, ?)', ['Max', 'Tobias']));
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
//@dart=2.9
|
||||
import 'package:moor/moor.dart';
|
||||
import 'package:moor/moor.dart' as moor;
|
||||
import 'package:test/test.dart';
|
||||
|
@ -7,7 +6,7 @@ import '../data/utils/expect_equality.dart';
|
|||
import '../data/utils/expect_generated.dart';
|
||||
|
||||
void main() {
|
||||
final innerExpression = GeneratedTextColumn('name', null, true);
|
||||
final innerExpression = GeneratedTextColumn('name', 'table', true);
|
||||
|
||||
test('IS NULL expressions are generated', () {
|
||||
final oldFunction = moor.isNull(innerExpression);
|
||||
|
@ -30,7 +29,7 @@ void main() {
|
|||
});
|
||||
|
||||
test('generates COALESCE expressions', () {
|
||||
final expr = moor.coalesce([const Constant<int>(null), const Constant(3)]);
|
||||
final expr = moor.coalesce([const Constant<int?>(null), const Constant(3)]);
|
||||
|
||||
expect(expr, generates('COALESCE(NULL, 3)'));
|
||||
});
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
//@dart=2.9
|
||||
import 'package:moor/moor.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
|
@ -6,8 +5,8 @@ import '../data/tables/todos.dart';
|
|||
import '../data/utils/expect_generated.dart';
|
||||
|
||||
void main() {
|
||||
final expression = GeneratedTextColumn('col', null, false);
|
||||
final db = TodoDb(null);
|
||||
final expression = GeneratedTextColumn('col', 'table', false);
|
||||
final db = TodoDb();
|
||||
|
||||
test('generates like expressions', () {
|
||||
final ctx = GenerationContext.fromDb(db);
|
||||
|
|
|
@ -8,7 +8,7 @@ void main() {
|
|||
test('maps the variable to sql', () {
|
||||
final variable =
|
||||
Variable(DateTime.fromMillisecondsSinceEpoch(1551297563000));
|
||||
final ctx = GenerationContext.fromDb(TodoDb(null));
|
||||
final ctx = GenerationContext.fromDb(TodoDb());
|
||||
|
||||
variable.writeInto(ctx);
|
||||
|
||||
|
@ -17,8 +17,8 @@ void main() {
|
|||
});
|
||||
|
||||
test('writes null directly for null values', () {
|
||||
final variable = Variable.withString(null);
|
||||
final ctx = GenerationContext.fromDb(TodoDb(null));
|
||||
const variable = Variable<String>(null);
|
||||
final ctx = GenerationContext.fromDb(TodoDb());
|
||||
|
||||
variable.writeInto(ctx);
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
//@dart=2.9
|
||||
@TestOn('vm')
|
||||
import 'package:moor/moor.dart';
|
||||
import 'package:moor/extensions/moor_ffi.dart';
|
||||
|
@ -9,8 +8,8 @@ import '../data/tables/todos.dart';
|
|||
import '../data/utils/expect_generated.dart';
|
||||
|
||||
void main() {
|
||||
final a = GeneratedRealColumn('a', null, false);
|
||||
final b = GeneratedRealColumn('b', null, false);
|
||||
final a = GeneratedRealColumn('a', 'table', false);
|
||||
final b = GeneratedRealColumn('b', 'table', false);
|
||||
|
||||
test('pow', () {
|
||||
expect(sqlPow(a, b), generates('pow(a, b)'));
|
||||
|
@ -25,7 +24,7 @@ void main() {
|
|||
test('atan', () => expect(sqlAtan(a), generates('atan(a)')));
|
||||
|
||||
test('containsCase', () {
|
||||
final c = GeneratedTextColumn('a', null, false);
|
||||
final c = GeneratedTextColumn('a', 'table', false);
|
||||
|
||||
expect(c.containsCase('foo'), generates('moor_contains(a, ?, 0)', ['foo']));
|
||||
expect(
|
||||
|
@ -39,11 +38,11 @@ void main() {
|
|||
// insert exactly one row so that we can evaluate expressions from Dart
|
||||
await db.into(db.pureDefaults).insert(PureDefaultsCompanion.insert());
|
||||
|
||||
Future<bool> evaluate(Expression<bool> expr) async {
|
||||
Future<bool> evaluate(Expression<bool?> expr) async {
|
||||
final result = await (db.selectOnly(db.pureDefaults)..addColumns([expr]))
|
||||
.getSingle();
|
||||
|
||||
return result.read(expr);
|
||||
return result!.read<bool?>(expr)!;
|
||||
}
|
||||
|
||||
expect(
|
||||
|
@ -59,7 +58,7 @@ void main() {
|
|||
});
|
||||
|
||||
group('regexp flags', () {
|
||||
TodoDb db;
|
||||
late TodoDb db;
|
||||
|
||||
setUp(() async {
|
||||
db = TodoDb(VmDatabase.memory());
|
||||
|
@ -69,11 +68,11 @@ void main() {
|
|||
|
||||
tearDown(() => db.close());
|
||||
|
||||
Future<bool> evaluate(Expression<bool> expr) async {
|
||||
Future<bool> evaluate(Expression<bool?> expr) async {
|
||||
final result = await (db.selectOnly(db.pureDefaults)..addColumns([expr]))
|
||||
.getSingle();
|
||||
|
||||
return result.read(expr);
|
||||
return result!.read<bool?>(expr)!;
|
||||
}
|
||||
|
||||
test('multiLine', () {
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
// Tests that wouldn't compile with null safety enabled.
|
||||
//@dart=2.9
|
||||
|
||||
import 'package:moor/moor.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import 'data/tables/todos.dart';
|
||||
import 'data/utils/mocks.dart';
|
||||
|
||||
void main() {
|
||||
TodoDb db;
|
||||
MockExecutor executor;
|
||||
MockStreamQueries streamQueries;
|
||||
|
||||
setUp(() {
|
||||
executor = MockExecutor();
|
||||
streamQueries = MockStreamQueries();
|
||||
|
||||
final connection = createConnection(executor, streamQueries);
|
||||
db = TodoDb.connect(connection);
|
||||
});
|
||||
|
||||
test("doesn't allow writing null rows", () {
|
||||
expect(
|
||||
() {
|
||||
return db.into(db.todosTable).insert(null);
|
||||
},
|
||||
throwsA(const TypeMatcher<InvalidDataException>().having(
|
||||
(e) => e.message, 'message', contains('Cannot write null row'))),
|
||||
);
|
||||
});
|
||||
}
|
|
@ -27,7 +27,8 @@ void main() {
|
|||
clearInteractions(inner);
|
||||
|
||||
lazy.beginTransaction();
|
||||
await lazy.runBatched(null);
|
||||
final batched = BatchedStatements([], []);
|
||||
await lazy.runBatched(batched);
|
||||
await lazy.runCustom('custom_stmt');
|
||||
await lazy.runDelete('delete_stmt', [1]);
|
||||
await lazy.runInsert('insert_stmt', [2]);
|
||||
|
@ -35,7 +36,7 @@ void main() {
|
|||
await lazy.runUpdate('update_stmt', [4]);
|
||||
|
||||
verifyInOrder([
|
||||
inner.runBatched(null),
|
||||
inner.runBatched(batched),
|
||||
inner.runCustom('custom_stmt'),
|
||||
inner.runDelete('delete_stmt', [1]),
|
||||
inner.runInsert('insert_stmt', [2]),
|
||||
|
|
Loading…
Reference in New Issue