Fix lints and warnings added in Dart 3.0

This commit is contained in:
Simon Binder 2023-05-12 22:42:21 +02:00
parent a0b35ec6e0
commit 28417c52af
No known key found for this signature in database
GPG Key ID: 7891917E4147B8C0
48 changed files with 119 additions and 293 deletions

View File

@ -1,7 +1,7 @@
include: package:lints/recommended.yaml include: package:lints/recommended.yaml
analyzer: analyzer:
strong-mode: language:
implicit-casts: false strict-casts: true
exclude: exclude:
- "**/*.g.dart" - "**/*.g.dart"

View File

@ -3,6 +3,7 @@ data:
title: "Experimental IDE" title: "Experimental IDE"
weight: 5 weight: 5
description: Get real-time feedback as you type sql description: Get real-time feedback as you type sql
hidden: true
template: layouts/docs/single template: layouts/docs/single
--- ---

View File

@ -3,12 +3,12 @@ description: Documentation website for the drift project.
publish_to: none publish_to: none
environment: environment:
sdk: '>=2.15.0 <3.0.0' sdk: '>=2.19.0 <4.0.0'
dependencies: dependencies:
drift: drift:
path: ^1.8.2 path: ^1.8.2
json_annotation: ^4.7.0 json_annotation: ^4.8.1
docsy: docsy:
hosted: https://simonbinder.eu hosted: https://simonbinder.eu
version: ^0.2.2 version: ^0.2.2
@ -31,11 +31,11 @@ dev_dependencies:
build: ^2.1.0 build: ^2.1.0
build_runner: ^2.0.5 build_runner: ^2.0.5
build_runner_core: ^7.2.7 build_runner_core: ^7.2.7
build_web_compilers: ^3.2.0 build_web_compilers: ^4.0.0
built_site: built_site:
hosted: https://simonbinder.eu hosted: https://simonbinder.eu
version: ^0.2.10 version: ^0.2.15
linkcheck: ^2.0.19 linkcheck: ^3.0.0
json_serializable: ^6.1.6 json_serializable: ^6.1.6
shelf: ^1.2.0 shelf: ^1.2.0
shelf_static: ^1.1.0 shelf_static: ^1.1.0
@ -50,3 +50,10 @@ dependency_overrides:
git: git:
url: https://github.com/simolus3/mime.git url: https://github.com/simolus3/mime.git
ref: woff2 ref: woff2
# The bootstrap_sass on pub.dev doesn't support null safety, so I'm hosting
# https://github.com/dart-league/bootstrap_sass/pull/13.
# Hopefully this can change soon once docsy migrates to bootstrap 5
bootstrap_sass:
hosted:
url: https://simonbinder.eu
version: "4.6.0"

View File

@ -1,62 +0,0 @@
// Waiting for linkcheck to migrate...
// @dart=2.9
import 'dart:async';
import 'dart:io';
import 'package:linkcheck/linkcheck.dart' as check;
import 'package:linkcheck/src/parsers/url_skipper.dart';
import 'package:shelf/shelf_io.dart' as io;
import 'package:shelf_static/shelf_static.dart';
/// Checks that the content in `deploy/` only contains valid links.
Future<void> main() async {
final done = Completer<void>();
await _startServer(done.future);
check.CrawlResult results;
try {
results = await check.crawl(
[
Uri.parse('http://localhost:8080/'),
Uri.parse('http://localhost:8080/api/')
],
{'http://localhost:8080/**'},
// todo: Re-enable. Current problem is that we link new pages to their
// final url (under drift.simonbinder.eu) before they're deployed.
false,
UrlSkipper(
'', ['github.com', 'pub.dev', 'api.dart.dev', 'fonts.gstatic.com']),
false,
false,
const Stream<void /*Never*/ >.empty(),
stdout,
);
} finally {
done.complete();
}
var hasBrokenLinks = false;
for (final result in results.destinations) {
// todo: Remove !result.isExternal after external links work again
if (result.isBroken && !result.isExternal) {
print('Broken: $result (${result.toMap()})');
hasBrokenLinks = true;
}
}
if (!hasBrokenLinks) {
print('No broken links found!');
} else {
exit(1);
}
}
Future<void> _startServer(Future<void> completeSignal) async {
final handler = createStaticHandler('deploy/', defaultDocument: 'index.html');
final server = await io.serve(handler, 'localhost', 8080);
print('Started server - listening on :8080');
completeSignal.then((_) => server.close()).ignore();
}

View File

@ -1,8 +1,9 @@
include: package:lints/recommended.yaml include: package:lints/recommended.yaml
analyzer: analyzer:
strong-mode: language:
implicit-casts: false strict-casts: true
strict-inference: true
exclude: exclude:
- "**/*.g.dart" - "**/*.g.dart"

View File

@ -18,7 +18,7 @@ StreamChannel connectToServer(SendPort serverConnectPort, bool serialize) {
serverConnectPort.send([receive.sendPort, serialize]); serverConnectPort.send([receive.sendPort, serialize]);
final controller = final controller =
StreamChannelController(allowForeignErrors: false, sync: true); StreamChannelController<Object?>(allowForeignErrors: false, sync: true);
receive.listen((message) { receive.listen((message) {
if (message is SendPort) { if (message is SendPort) {
controller.local.stream.listen(message.send, onDone: () { controller.local.stream.listen(message.send, onDone: () {
@ -72,8 +72,8 @@ class RunningDriftServer {
ReceivePort('drift channel #${_counter++}'); ReceivePort('drift channel #${_counter++}');
sendPort.send(receiveForConnection.sendPort); sendPort.send(receiveForConnection.sendPort);
final controller = final controller = StreamChannelController<Object?>(
StreamChannelController(allowForeignErrors: false, sync: true); allowForeignErrors: false, sync: true);
receiveForConnection.listen((message) { receiveForConnection.listen((message) {
if (message == disconnectMessage) { if (message == disconnectMessage) {
// Client closed the connection // Client closed the connection

View File

@ -165,7 +165,7 @@ class _RemoteQueryExecutor extends _BaseExecutor {
if (!channel.isClosed) { if (!channel.isClosed) {
if (client._singleClientMode) { if (client._singleClientMode) {
return channel return channel
.request(NoArgsRequest.terminateAll) .request<void>(NoArgsRequest.terminateAll)
.onError<ConnectionClosedException>((error, stackTrace) => null) .onError<ConnectionClosedException>((error, stackTrace) => null)
.whenComplete(channel.close); .whenComplete(channel.close);
} else { } else {

View File

@ -143,7 +143,7 @@ class ServerImplementation implements DriftServer {
final executor = await _loadExecutor(transactionId); final executor = await _loadExecutor(transactionId);
// Give cancellations more time to come in // Give cancellations more time to come in
await Future.delayed(Duration.zero); await Future<void>.delayed(Duration.zero);
checkIfCancelled(); checkIfCancelled();
switch (method) { switch (method) {
@ -277,7 +277,7 @@ class _ServerDbUser implements QueryExecutorUser {
QueryExecutor executor, OpeningDetails details) async { QueryExecutor executor, OpeningDetails details) async {
final id = _server._putExecutor(executor, beforeCurrent: true); final id = _server._putExecutor(executor, beforeCurrent: true);
try { try {
await connection.request(RunBeforeOpen(details, id)); await connection.request<void>(RunBeforeOpen(details, id));
} finally { } finally {
_server._releaseExecutor(id); _server._releaseExecutor(id);
} }

View File

@ -27,7 +27,7 @@ class DelayedStreamQueryStore implements StreamQueryStore {
} }
@override @override
void markAsClosed(QueryStream stream, Function() whenRemoved) { void markAsClosed(QueryStream stream, void Function() whenRemoved) {
throw UnimplementedError('The stream will call this on the delegate'); throw UnimplementedError('The stream will call this on the delegate');
} }

View File

@ -76,7 +76,7 @@ abstract class QueryExecutorUser {
Future<void> beforeOpen(QueryExecutor executor, OpeningDetails details); Future<void> beforeOpen(QueryExecutor executor, OpeningDetails details);
} }
const _equality = ListEquality(); const _equality = ListEquality<Object?>();
/// Stores information needed to run batched statements in the order they were /// Stores information needed to run batched statements in the order they were
/// issued without preparing statements multiple times. /// issued without preparing statements multiple times.

View File

@ -119,7 +119,7 @@ class StreamQueryStore {
_tableUpdates.add(updates); _tableUpdates.add(updates);
} }
void markAsClosed(QueryStream stream, Function() whenRemoved) { void markAsClosed(QueryStream stream, void Function() whenRemoved) {
if (_isShuttingDown) return; if (_isShuttingDown) return;
final key = stream._fetcher.key; final key = stream._fetcher.key;

View File

@ -68,7 +68,7 @@ class _TransactionStreamStore extends StreamQueryStore {
} }
@override @override
void markAsClosed(QueryStream stream, Function() whenRemoved) { void markAsClosed(QueryStream stream, void Function() whenRemoved) {
super.markAsClosed(stream, whenRemoved); super.markAsClosed(stream, whenRemoved);
_queriesWithoutKey.add(stream); _queriesWithoutKey.add(stream);

View File

@ -218,8 +218,8 @@ class _AggregateExpression<D extends Object> extends Expression<D> {
@override @override
int get hashCode { int get hashCode {
return Object.hash( return Object.hash(functionName, distinct,
functionName, distinct, const ListEquality().hash(parameter), filter); const ListEquality<Object?>().hash(parameter), filter);
} }
@override @override
@ -232,7 +232,7 @@ class _AggregateExpression<D extends Object> extends Expression<D> {
final typedOther = other as _AggregateExpression; final typedOther = other as _AggregateExpression;
return typedOther.functionName == functionName && return typedOther.functionName == functionName &&
typedOther.distinct == distinct && typedOther.distinct == distinct &&
const ListEquality().equals(typedOther.parameter, parameter) && const ListEquality<Object?>().equals(typedOther.parameter, parameter) &&
typedOther.filter == filter; typedOther.filter == filter;
} }
} }

View File

@ -11,7 +11,7 @@ Expression<bool> notExistsQuery(BaseSelectStatement select) {
return _ExistsExpression(select, true); return _ExistsExpression(select, true);
} }
class _ExistsExpression<T> extends Expression<bool> { class _ExistsExpression extends Expression<bool> {
final BaseSelectStatement _select; final BaseSelectStatement _select;
final bool _not; final bool _not;

View File

@ -1,6 +1,6 @@
part of '../query_builder.dart'; part of '../query_builder.dart';
const _equality = ListEquality(); const _equality = ListEquality<Object?>();
/// Base class for everything that can be used as a function parameter in sql. /// Base class for everything that can be used as a function parameter in sql.
/// ///

View File

@ -251,7 +251,8 @@ class GeneratedColumn<T extends Object> extends Column<T> {
/// the constraint does not depend on the dialect. /// the constraint does not depend on the dialect.
/// ///
/// Used by generated code. /// Used by generated code.
static Function(GenerationContext) constraintIsAlways(String constraint) => static void Function(GenerationContext) constraintIsAlways(
String constraint) =>
(context) => context.buffer (context) => context.buffer
..write(' ') ..write(' ')
..write(constraint); ..write(constraint);
@ -260,7 +261,7 @@ class GeneratedColumn<T extends Object> extends Column<T> {
/// the constraint depends on the dialect. /// the constraint depends on the dialect.
/// ///
/// Used by generated code. /// Used by generated code.
static Function(GenerationContext) constraintsDependsOnDialect( static void Function(GenerationContext) constraintsDependsOnDialect(
Map<SqlDialect, String> constraints, Map<SqlDialect, String> constraints,
) => ) =>
(context) { (context) {

View File

@ -11,7 +11,7 @@ extension PortToChannel on MessagePort {
/// This can be used to implement a remote database connection over service /// This can be used to implement a remote database connection over service
/// workers. /// workers.
StreamChannel<Object?> channel() { StreamChannel<Object?> channel() {
final controller = StreamChannelController(); final controller = StreamChannelController<Object?>();
onMessage.map((event) => event.data).pipe(controller.local.sink); onMessage.map((event) => event.data).pipe(controller.local.sink);
controller.local.stream.listen(postMessage, onDone: close); controller.local.stream.listen(postMessage, onDone: close);

View File

@ -186,7 +186,7 @@ void main() {
batch.insert( batch.insert(
db.categories, CategoriesCompanion.insert(description: 'first')); db.categories, CategoriesCompanion.insert(description: 'first'));
await Future.delayed(Duration.zero); await Future<void>.delayed(Duration.zero);
batch.insert( batch.insert(
db.categories, CategoriesCompanion.insert(description: 'second')); db.categories, CategoriesCompanion.insert(description: 'second'));

View File

@ -158,7 +158,7 @@ void main() {
}); });
test("don't equal when one value is absent and the other one is null", () { test("don't equal when one value is absent and the other one is null", () {
const first = Value.absent(); const first = Value<Object?>.absent();
const different = Value(null); const different = Value(null);
expect(first.hashCode, isNot(equals(different.hashCode))); expect(first.hashCode, isNot(equals(different.hashCode)));

View File

@ -167,11 +167,11 @@ void main() {
.join([innerJoin(categories, todos.category.equalsExp(categories.id))]); .join([innerJoin(categories, todos.category.equalsExp(categories.id))]);
final queue = StreamQueue(query.watch()); final queue = StreamQueue(query.watch());
expect(await queue.next, []); expect(await queue.next, isEmpty);
db.markTablesUpdated({todos}); db.markTablesUpdated({todos});
db.markTablesUpdated({categories}); db.markTablesUpdated({categories});
expect(await queue.next, []); expect(await queue.next, isEmpty);
}); });
test('updates when any queried table changes in transaction', () { test('updates when any queried table changes in transaction', () {
@ -188,7 +188,7 @@ void main() {
..groupBy([b.description]); ..groupBy([b.description]);
final stream = query.watch(); final stream = query.watch();
expectLater(stream, emitsInOrder([[], []])); expectLater(stream, emitsInOrder([<Object?>[], <Object?>[]]));
return db.transaction(() async { return db.transaction(() async {
db.markTablesUpdated({b}); db.markTablesUpdated({b});

View File

@ -82,7 +82,7 @@ void main() {
test('does not emit cached data when resuming and data did not change', test('does not emit cached data when resuming and data did not change',
() async { () async {
final stream = db.select(db.users).watch(); final stream = db.select(db.users).watch();
final completer = Completer(); final completer = Completer<void>();
final subscription = stream.listen(expectAsync1((data) { final subscription = stream.listen(expectAsync1((data) {
completer.complete(); completer.complete();
@ -102,7 +102,7 @@ void main() {
test('emits new data if it changed during a paused subscription', () async { test('emits new data if it changed during a paused subscription', () async {
final stream = db.select(db.users).watch(); final stream = db.select(db.users).watch();
final completer = Completer(); final completer = Completer<void>();
final subscription = stream.listen(expectAsync1((data) { final subscription = stream.listen(expectAsync1((data) {
if (!completer.isCompleted) completer.complete(); if (!completer.isCompleted) completer.complete();
@ -177,7 +177,8 @@ void main() {
await first.first; // will listen to stream, then cancel await first.first; // will listen to stream, then cancel
await pumpEventQueue(times: 1); // give cancel event time to propagate await pumpEventQueue(times: 1); // give cancel event time to propagate
final checkEmits = expectLater(second, emitsInOrder([[], []])); final checkEmits =
expectLater(second, emitsInOrder([<Object?>[], <Object?>[]]));
db.markTablesUpdated({db.users}); db.markTablesUpdated({db.users});
await pumpEventQueue(times: 1); await pumpEventQueue(times: 1);
@ -271,7 +272,7 @@ void main() {
clearInteractions(executor); clearInteractions(executor);
// The stream is kept open for the rest of this event iteration // The stream is kept open for the rest of this event iteration
final completer = Completer.sync(); final completer = Completer<void>.sync();
Timer.run(completer.complete); Timer.run(completer.complete);
await completer.future; await completer.future;
@ -282,7 +283,7 @@ void main() {
test('when all listeners are paused', () async { test('when all listeners are paused', () async {
when(executor.runSelect(any, any)).thenAnswer((i) => Future.value([])); when(executor.runSelect(any, any)).thenAnswer((i) => Future.value([]));
final isPaused = Completer(); final isPaused = Completer<void>();
final subscription = db.select(db.categories).watch().listen(null); final subscription = db.select(db.categories).watch().listen(null);
subscription.onData((rows) { subscription.onData((rows) {
@ -307,7 +308,7 @@ void main() {
])); ]));
db.markTablesUpdated([db.categories]); db.markTablesUpdated([db.categories]);
await pumpEventQueue(); await pumpEventQueue();
final hadData = Completer(); final hadData = Completer<void>();
subscription.onData((rows) { subscription.onData((rows) {
expect(rows, hasLength(1)); expect(rows, hasLength(1));

View File

@ -231,7 +231,7 @@ void main() {
.thenAnswer((_) => Future.error(rollbackException)); .thenAnswer((_) => Future.error(rollbackException));
return expectLater( return expectLater(
db.transaction(() => Future.error(cause)), db.transaction(() => Future<void>.error(cause)),
throwsA(isA<CouldNotRollBackException>() throwsA(isA<CouldNotRollBackException>()
.having((e) => e.cause, 'cause', cause) .having((e) => e.cause, 'cause', cause)
.having((e) => e.exception, 'exception', rollbackException)), .having((e) => e.exception, 'exception', rollbackException)),

View File

@ -191,7 +191,8 @@ void main() {
test('when the database supports transactions', () async { test('when the database supports transactions', () async {
final transactionDelegate = MockSupportedTransactionDelegate(); final transactionDelegate = MockSupportedTransactionDelegate();
when(transactionDelegate.startTransaction(any)).thenAnswer((i) { when(transactionDelegate.startTransaction(any)).thenAnswer((i) {
(i.positionalArguments.single as Function(QueryDelegate))(delegate); (i.positionalArguments.single as void Function(
QueryDelegate))(delegate);
}); });
when(transactionDelegate.managesLockInternally).thenReturn(true); when(transactionDelegate.managesLockInternally).thenReturn(true);
@ -232,7 +233,7 @@ void main() {
final exception = Exception('expected'); final exception = Exception('expected');
when(transactionDelegate.startTransaction(any)).thenAnswer((i) async { when(transactionDelegate.startTransaction(any)).thenAnswer((i) async {
await (i.positionalArguments.single as Function( await (i.positionalArguments.single as Future<Object?> Function(
QueryDelegate))(delegate); QueryDelegate))(delegate);
throw exception; throw exception;
}); });

View File

@ -365,7 +365,7 @@ void main() {
await db.customStatement('pragma user_version = 3'); await db.customStatement('pragma user_version = 3');
await db.transaction( await db.transaction(
() => Future.error('Error after partial migration')); () => Future<void>.error('Error after partial migration'));
}), }),
), ),
); );

View File

@ -19,7 +19,7 @@ void main() {
.watchSingle(); .watchSingle();
expect(await watchValue().first, 1); expect(await watchValue().first, 1);
await Future.delayed(Duration.zero); await Future<void>.delayed(Duration.zero);
watchValue().listen(null); watchValue().listen(null);

View File

@ -357,7 +357,7 @@ void _runTests(FutureOr<DriftIsolate> Function() spawner, bool terminateIsolate,
rowInserted.complete(); rowInserted.complete();
// Hold transaction open for expectRowCount() outside the transaction to // Hold transaction open for expectRowCount() outside the transaction to
// finish // finish
await Future.delayed(const Duration(seconds: 1)); await Future<void>.delayed(const Duration(seconds: 1));
await database.customStatement('delete from tbl'); await database.customStatement('delete from tbl');
await expectRowCount(database, 0); await expectRowCount(database, 0);
}); });

View File

@ -17,7 +17,7 @@ void main() {
preferLocalSqlite3(); preferLocalSqlite3();
test('closes channel in shutdown', () async { test('closes channel in shutdown', () async {
final controller = StreamChannelController(); final controller = StreamChannelController<Object?>();
final server = final server =
DriftServer(testInMemoryDatabase(), allowRemoteShutdown: true); DriftServer(testInMemoryDatabase(), allowRemoteShutdown: true);
server.serve(controller.foreign); server.serve(controller.foreign);
@ -26,7 +26,7 @@ void main() {
}); });
test('can shutdown server on close', () async { test('can shutdown server on close', () async {
final controller = StreamChannelController(); final controller = StreamChannelController<Object?>();
final server = final server =
DriftServer(testInMemoryDatabase(), allowRemoteShutdown: true); DriftServer(testInMemoryDatabase(), allowRemoteShutdown: true);
server.serve(controller.foreign); server.serve(controller.foreign);
@ -47,7 +47,7 @@ void main() {
() async { () async {
final server = final server =
DriftServer(testInMemoryDatabase(), allowRemoteShutdown: true); DriftServer(testInMemoryDatabase(), allowRemoteShutdown: true);
final controller = StreamChannelController(); final controller = StreamChannelController<Object?>();
server.serve(controller.foreign, serialize: false); server.serve(controller.foreign, serialize: false);
final client = await connectToRemoteAndInitialize( final client = await connectToRemoteAndInitialize(
@ -116,7 +116,7 @@ void main() {
final server = DriftServer(DatabaseConnection(executor)); final server = DriftServer(DatabaseConnection(executor));
addTearDown(server.shutdown); addTearDown(server.shutdown);
final channelController = StreamChannelController(); final channelController = StreamChannelController<Object?>();
server.serve(channelController.foreign.changeStream(_checkStreamOfSimple), server.serve(channelController.foreign.changeStream(_checkStreamOfSimple),
serialize: true); serialize: true);
@ -153,7 +153,7 @@ void main() {
}); });
test('nested transactions', () async { test('nested transactions', () async {
final controller = StreamChannelController(); final controller = StreamChannelController<Object?>();
final executor = MockExecutor(); final executor = MockExecutor();
final outerTransaction = executor.transactions; final outerTransaction = executor.transactions;
// avoid this object being created implicitly in the beginTransaction() when // avoid this object being created implicitly in the beginTransaction() when
@ -207,7 +207,7 @@ void main() {
final executor = MockExecutor(); final executor = MockExecutor();
when(executor.dialect).thenReturn(SqlDialect.postgres); when(executor.dialect).thenReturn(SqlDialect.postgres);
final controller = StreamChannelController(); final controller = StreamChannelController<Object?>();
final server = DriftServer(DatabaseConnection(executor)) final server = DriftServer(DatabaseConnection(executor))
..serve(controller.foreign); ..serve(controller.foreign);

View File

@ -83,14 +83,14 @@ class _GeneratesSqlMatcher extends Matcher {
var matches = true; var matches = true;
final sqlMatchState = {}; final sqlMatchState = <String, Object?>{};
if (!_matchSql.matches(ctx.sql, sqlMatchState)) { if (!_matchSql.matches(ctx.sql, sqlMatchState)) {
matchState['sql'] = ctx.sql; matchState['sql'] = ctx.sql;
matchState['sql_match'] = sqlMatchState; matchState['sql_match'] = sqlMatchState;
matches = false; matches = false;
} }
final argsMatchState = {}; final argsMatchState = <String, Object?>{};
if (_matchVariables != null && if (_matchVariables != null &&
!_matchVariables!.matches(ctx.boundVariables, argsMatchState)) { !_matchVariables!.matches(ctx.boundVariables, argsMatchState)) {
matchState['vars'] = ctx.boundVariables; matchState['vars'] = ctx.boundVariables;

View File

@ -42,7 +42,7 @@ void main() {
}); });
test('singleElementsOrNull() emits null for empty data', () { test('singleElementsOrNull() emits null for empty data', () {
final stream = Stream.value([]); final stream = Stream.value(<Object?>[]);
expect(stream.transform(singleElementsOrNull()), emits(isNull)); expect(stream.transform(singleElementsOrNull()), emits(isNull));
}); });

View File

@ -1,7 +1,7 @@
include: package:lints/recommended.yaml include: package:lints/recommended.yaml
analyzer: analyzer:
strong-mode: language:
implicit-casts: false strict-casts: true
exclude: exclude:
- "**/*.g.dart" - "**/*.g.dart"

View File

@ -438,7 +438,7 @@ class ElementDeserializer {
final id = DriftElementId.fromJson(json['id'] as Map); final id = DriftElementId.fromJson(json['id'] as Map);
final declaration = DriftDeclaration.fromJson(json['declaration'] as Map); final declaration = DriftDeclaration.fromJson(json['declaration'] as Map);
final references = <DriftElement>[ final references = <DriftElement>[
for (final reference in json['references']) for (final reference in json.list('references'))
await _readElementReference(reference as Map), await _readElementReference(reference as Map),
]; ];
@ -489,7 +489,7 @@ class ElementDeserializer {
id.libraryUri, json['existing_data_class'] as Map) id.libraryUri, json['existing_data_class'] as Map)
: null, : null,
tableConstraints: [ tableConstraints: [
for (final constraint in json['table_constraints']) for (final constraint in json.list('table_constraints'))
await _readTableConstraint(constraint as Map, columnByName), await _readTableConstraint(constraint as Map, columnByName),
], ],
customParentClass: json['custom_parent_class'] != null customParentClass: json['custom_parent_class'] != null
@ -575,7 +575,7 @@ class ElementDeserializer {
on: on, on: on,
onWrite: UpdateKind.values.byName(json['onWrite'] as String), onWrite: UpdateKind.values.byName(json['onWrite'] as String),
writes: [ writes: [
for (final write in json['writes']) for (final write in json.list('writes').cast<Map>())
WrittenDriftTable( WrittenDriftTable(
await _readElementReference(write['table'] as Map) await _readElementReference(write['table'] as Map)
as DriftTable, as DriftTable,
@ -609,7 +609,7 @@ class ElementDeserializer {
? readReference(serializedSource['primaryFrom'] as Map) ? readReference(serializedSource['primaryFrom'] as Map)
: null, : null,
[ [
for (final element in serializedSource['staticReferences']) for (final element in serializedSource.list('staticReferences'))
readReference(element as Map) readReference(element as Map)
], ],
); );
@ -640,11 +640,11 @@ class ElementDeserializer {
}; };
final tables = [ final tables = [
for (final tableId in json['tables']) for (final tableId in json.list('tables'))
referenceById[DriftElementId.fromJson(tableId as Map)] as DriftTable referenceById[DriftElementId.fromJson(tableId as Map)] as DriftTable
]; ];
final views = [ final views = [
for (final tableId in json['views']) for (final tableId in json.list('views'))
referenceById[DriftElementId.fromJson(tableId as Map)] as DriftView referenceById[DriftElementId.fromJson(tableId as Map)] as DriftView
]; ];
final includes = final includes =
@ -664,7 +664,7 @@ class ElementDeserializer {
declaredQueries: queries, declaredQueries: queries,
schemaVersion: json['schema_version'] as int?, schemaVersion: json['schema_version'] as int?,
accessors: [ accessors: [
for (final dao in json['daos']) for (final dao in json.list('daos'))
await readDriftElement(DriftElementId.fromJson(dao as Map)) await readDriftElement(DriftElementId.fromJson(dao as Map))
as DatabaseAccessor, as DatabaseAccessor,
], ],
@ -803,21 +803,21 @@ class ElementDeserializer {
switch (type) { switch (type) {
case 'unique': case 'unique':
return UniqueColumns({ return UniqueColumns({
for (final ref in json['columns']) localColumns[ref]!, for (final ref in json.list('columns')) localColumns[ref]!,
}); });
case 'primary_key': case 'primary_key':
return PrimaryKeyColumns( return PrimaryKeyColumns(
{for (final ref in json['columns']) localColumns[ref]!}, {for (final ref in json.list('columns')) localColumns[ref]!},
); );
case 'foreign': case 'foreign':
return ForeignKeyTable( return ForeignKeyTable(
localColumns: [ localColumns: [
for (final ref in json['local']) localColumns[ref]!, for (final ref in json.list('local')) localColumns[ref]!,
], ],
otherTable: otherTable:
await _readElementReference(json['table'] as Map) as DriftTable, await _readElementReference(json['table'] as Map) as DriftTable,
otherColumns: [ otherColumns: [
for (final ref in json['foreign']) for (final ref in json.list('foreign'))
await _readDriftColumnReference(ref as Map) await _readDriftColumnReference(ref as Map)
], ],
onUpdate: _readAction(json['onUpdate'] as String?), onUpdate: _readAction(json['onUpdate'] as String?),
@ -829,6 +829,10 @@ class ElementDeserializer {
} }
} }
extension on Map {
Iterable<Object?> list(String key) => this[key] as Iterable;
}
class CouldNotDeserializeException implements Exception { class CouldNotDeserializeException implements Exception {
final String message; final String message;

View File

@ -346,9 +346,9 @@ class SchemaReader {
List<Set<DriftColumn>> uniqueKeys = []; List<Set<DriftColumn>> uniqueKeys = [];
if (content.containsKey('unique_keys')) { if (content.containsKey('unique_keys')) {
for (final key in content['unique_keys']) { for (final key in content['unique_keys'] as Iterable) {
uniqueKeys.add({ uniqueKeys.add({
for (final columnName in key) for (final columnName in key as Iterable)
columns.singleWhere((c) => c.nameInSql == columnName) columns.singleWhere((c) => c.nameInSql == columnName)
}); });
} }
@ -380,7 +380,7 @@ class SchemaReader {
_id(name), _id(name),
_declaration, _declaration,
columns: [ columns: [
for (final column in content['columns']) for (final column in content['columns'] as Iterable)
_readColumn(column as Map<String, dynamic>) _readColumn(column as Map<String, dynamic>)
], ],
source: SqlViewSource(content['sql'] as String), source: SqlViewSource(content['sql'] as String),

View File

@ -1,4 +1,3 @@
// @dart=2.9
import 'dart:async'; import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; import 'dart:io';
@ -7,6 +6,7 @@ import 'package:analyzer_plugin/channel/channel.dart';
import 'package:analyzer_plugin/protocol/protocol.dart'; import 'package:analyzer_plugin/protocol/protocol.dart';
import 'package:args/args.dart'; import 'package:args/args.dart';
import 'package:drift_dev/src/backends/plugin/plugin.dart'; import 'package:drift_dev/src/backends/plugin/plugin.dart';
import 'package:stream_transform/stream_transform.dart';
void main(List<String> args) { void main(List<String> args) {
final parser = ArgParser() final parser = ArgParser()
@ -32,10 +32,10 @@ class _WebSocketPluginServer implements PluginCommunicationChannel {
final dynamic address; final dynamic address;
final int port; final int port;
HttpServer server; late HttpServer server;
WebSocket _currentClient; WebSocket? _currentClient;
final StreamController<WebSocket> _clientStream = final StreamController<WebSocket?> _clientStream =
StreamController.broadcast(); StreamController.broadcast();
_WebSocketPluginServer({dynamic address, this.port = 9999}) _WebSocketPluginServer({dynamic address, this.port = 9999})
@ -50,15 +50,17 @@ class _WebSocketPluginServer implements PluginCommunicationChannel {
} }
void _handleClientAdded(WebSocket socket) { void _handleClientAdded(WebSocket socket) {
if (_currentClient != null) { var client = _currentClient;
if (client != null) {
print('ignoring connection attempt because an active client already ' print('ignoring connection attempt because an active client already '
'exists'); 'exists');
socket.close(); socket.close();
} else { } else {
print('client connected'); print('client connected');
_currentClient = socket; client = _currentClient = socket;
_clientStream.add(_currentClient); _clientStream.add(client);
_currentClient.done.then((_) { client.done.then((_) {
print('client disconnected'); print('client disconnected');
_currentClient = null; _currentClient = null;
_clientStream.add(null); _clientStream.add(null);
@ -68,23 +70,23 @@ class _WebSocketPluginServer implements PluginCommunicationChannel {
@override @override
void close() { void close() {
server?.close(force: true); server.close(force: true);
} }
@override @override
void listen(void Function(Request request) onRequest, void listen(void Function(Request request) onRequest,
{Function onError, void Function() onDone}) { {Function? onError, void Function()? onDone}) {
final stream = _clientStream.stream; final stream = _clientStream.stream;
// wait until we're connected // wait until we're connected
stream.firstWhere((socket) => socket != null).then((_) { stream.whereType<WebSocket>().first.then((socket) {
_currentClient.listen((data) { socket.listen((data) {
print('I: $data'); print('I: $data');
onRequest(Request.fromJson( onRequest(Request.fromJson(
json.decode(data as String) as Map<String, dynamic>)); json.decode(data as String) as Map<String, dynamic>));
}); });
}); });
stream.firstWhere((socket) => socket == null).then((_) => onDone()); stream.firstWhere((socket) => socket == null).then((_) => onDone?.call());
} }
@override @override

View File

@ -4,7 +4,7 @@ description: An absolute bare-bones web app.
#homepage: https://www.example.com #homepage: https://www.example.com
environment: environment:
sdk: '>=2.12.0 <3.0.0' sdk: '>=2.14.0 <3.0.0'
dependencies: dependencies:
js: ^0.6.4 js: ^0.6.4

View File

@ -2,7 +2,7 @@ name: benchmarks
description: Runs simple and complex benchmarks to measure performance of moor and moor_ffi description: Runs simple and complex benchmarks to measure performance of moor and moor_ffi
environment: environment:
sdk: '>=2.12.0 <3.0.0' sdk: '>=2.14.0 <3.0.0'
dependencies: dependencies:
drift: ^1.0.0 drift: ^1.0.0

View File

@ -1,5 +1,5 @@
include: package:lints/recommended.yaml include: package:lints/recommended.yaml
analyzer: analyzer:
strong-mode: language:
implicit-casts: false strict-casts: true

View File

@ -6,7 +6,6 @@ import 'package:drift_testcases/tests.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:integration_test/integration_test.dart'; import 'package:integration_test/integration_test.dart';
import 'package:path/path.dart'; import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart' show getDatabasesPath;
import 'package:sqlite3/sqlite3.dart' as raw; import 'package:sqlite3/sqlite3.dart' as raw;
import 'package:test/test.dart'; import 'package:test/test.dart';
@ -35,11 +34,16 @@ class FfiExecutor extends TestExecutor {
} }
} }
Future<String> get _testDbDirectory async {
final dbDirectory =
await Directory.systemTemp.createTemp('drift-ffi-flutter');
return dbDirectory.path;
}
Future<void> main() async { Future<void> main() async {
IntegrationTestWidgetsFlutterBinding.ensureInitialized(); IntegrationTestWidgetsFlutterBinding.ensureInitialized();
final dbPath = await getDatabasesPath(); final dbPath = await _testDbDirectory;
Directory(dbPath).createSync(recursive: true);
runAllTests(FfiExecutor(dbPath)); runAllTests(FfiExecutor(dbPath));
test('supports the rtree module', () { test('supports the rtree module', () {
@ -97,12 +101,12 @@ Future<void> main() async {
}); });
test('can use database path in background isolate', () async { test('can use database path in background isolate', () async {
final token = RootIsolateToken.instance; final token = RootIsolateToken.instance!;
final isolate = await DriftIsolate.spawn(() { final isolate = await DriftIsolate.spawn(() {
BackgroundIsolateBinaryMessenger.ensureInitialized(token); BackgroundIsolateBinaryMessenger.ensureInitialized(token);
return LazyDatabase(() async { return LazyDatabase(() async {
final path = await getDatabasesPath(); final path = await _testDbDirectory;
final file = File(join(path, 'background.db')); final file = File(join(path, 'background.db'));
return NativeDatabase(file); return NativeDatabase(file);

View File

@ -5,8 +5,8 @@ version: 1.0.0+1
publish_to: none publish_to: none
environment: environment:
sdk: ">=2.1.0 <3.0.0" sdk: ">=2.12.0 <3.0.0"
flutter: ">=1.12.0" flutter: ">=3.10.0"
dependencies: dependencies:
drift: ^2.0.0-0 drift: ^2.0.0-0
@ -17,7 +17,6 @@ dependencies:
drift_testcases: drift_testcases:
path: ../drift_testcases path: ../drift_testcases
sqlite3_flutter_libs: ^0.5.7 sqlite3_flutter_libs: ^0.5.7
sqflite: ^2.0.2+1
dev_dependencies: dev_dependencies:
test: ^1.18.0 test: ^1.18.0

View File

@ -1,35 +0,0 @@
# Created by https://www.gitignore.io/api/dart,intellij
# Edit at https://www.gitignore.io/?templates=dart,intellij
.vscode
### Dart ###
# See https://www.dartlang.org/guides/libraries/private-files
# Files and directories created by pub
.dart_tool/
.packages
build/
# If you're building an application, you may want to check-in your pubspec.lock
pubspec.lock
# Directory created by dartdoc
# If you don't generate documentation locally you can remove this line.
doc/api/
# Avoid committing generated Javascript files:
*.dart.js
*.info.json # Produced by the --dump-info flag.
*.js # When generated by dart2js. Don't specify *.js if your
# project includes source files written in JavaScript.
*.js_
*.js.deps
*.js.map
android/
ios/
### Intellij ###
.idea/**/*
# End of https://www.gitignore.io/api/dart,intellij

View File

@ -1,50 +0,0 @@
Playground to test the analyzer plugin for `.moor` files.
Currently, we support
- showing errors in moor files
- outline
- folding
- (very, very limited) autocomplete
- some quickfixes to make columns nullable or non-null
- navigation for references in sql queries
## Setup
To use this plugin, you'll need to perform these steps once. It is assumed that you
have already cloned the `moor` repository.
1. Make sure you run version `3.5.0` or later of the Dart extension in VS Code.
2. In the editor settings, change `dart.additionalAnalyzerFileExtensions`
to include `moor` files:
```json
{
"dart.additionalAnalyzerFileExtensions": ["moor"]
}
```
3. Uncomment the plugin lines in `analysis_options.yaml`
## Debugging
Note: If you only want to _use_ the plugin and don't care about debugging it, follow the step
from the [user documentation](https://drift.simonbinder.eu/docs/using-sql/sql_ide/).
After you completed the setup, these steps will open an editor instance that runs the plugin.
1. chdir into `moor_generator` and run `dart bin/moor_generator.dart debug-plugin`.
You can run that script from an IDE if you need debugging capabilities, but starting
it from the command line is fine. Keep that script running.
3. Uncomment the `plugin` lines in `analysis_options.yaml`
3. Open this folder in the code instance
4. Wait ~15s, you should start to see some log entries in the output of step 1.
As soon as they appear, the plugin is ready to go.
_Note_: `bin/moor_generator.dart` doesn't support multiple clients. Whenever you close or reload the
editor, that script needs to be restarted as well. That script should also be running before
starting the analysis server.
## Troubleshooting
If the plugin doesn't start properly, you can
1. make sure it was picked up by the analysis server: Set the `dart.analyzerDiagnosticsPort`
to any port and see some basic information under the "plugins" tab of the website started.
2. When setting `dart.analyzerInstrumentationLogFile`, the analysis server will write the
exception that caused the plugin to stop

View File

@ -1,8 +0,0 @@
include: package:pedantic/analysis_options.yaml
# The source-controlled version of this file should always have the plugin commented out. Our development version with
# the websocket proxy causes analysis errors when to plugin doesn't run
#analyzer:
# plugins:
# - drift

View File

@ -1,8 +0,0 @@
targets:
$default:
builders:
moor_generator:
options:
sqlite_modules:
- json1
- fts5

View File

@ -1 +0,0 @@
class Test {}

View File

@ -1,16 +0,0 @@
import 'first.dart';
import 'second.dart';
import 'last.dart';
CREATE TABLE playground (
id INT NOT NULL PRIMARY KEY AUTOINCREMENT,
name VARCHAR NOT NULL
);
CREATE VIRTUAL TABLE email USING fts5(name);
unknownColumn: SELECT * FROM playground WHERE bar = 'foo';
syntaxError: SELECT 3 + FROM playground;
lints: INSERT INTO playground DEFAULT VALUES;
variables: SELECT * FROM playground WHERE id BETWEEN :foo AND :bar;
dartTemplate: SELECT * FROM playground WHERE $predicate ORDER BY $ordering;

View File

@ -1,3 +0,0 @@
CREATE TABLE playground (
id INT NOT NULL PRIMARY KEY AUTOINCREMENT
)

View File

@ -1,13 +0,0 @@
name: plugin_example
description: Playground to test the analyzer plugin
environment:
sdk: '>=2.4.0 <3.0.0'
dependencies:
drift:
path: ../../drift
dev_dependencies:
pedantic: ^1.7.0
test: ^1.5.0

View File

@ -290,4 +290,4 @@ packages:
source: hosted source: hosted
version: "2.1.0" version: "2.1.0"
sdks: sdks:
dart: ">=2.19.0 <3.0.0" dart: ">=2.19.0 <4.0.0"

View File

@ -1,5 +1,6 @@
include: package:lints/recommended.yaml include: package:lints/recommended.yaml
analyzer: analyzer:
strong-mode: language:
implicit-casts: false strict-casts: true