Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 32 additions & 1 deletion lib/core/ui/querya_shell_status.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ class QueryaShellStatus extends ChangeNotifier {
int? _columnCount;
Duration? _lastQueryDuration;

/// Whether [_statusMessage] only describes the running work ("Running
/// query…"): such a message goes away with the busy state.
bool _messageIsBusy = false;

bool get isBusy => _isBusy;
String? get statusMessage => _statusMessage;
int? get rowCount => _rowCount;
Expand All @@ -24,13 +28,22 @@ class QueryaShellStatus extends ChangeNotifier {
/// Marks the shell busy (spinner + optional message).
void beginBusy({String? message}) {
_isBusy = true;
if (message != null) _statusMessage = message;
if (message != null) {
_statusMessage = message;
_messageIsBusy = true;
}
notifyListeners();
}

/// Clears busy; keeps last query metrics unless [clearMetrics] is true.
///
/// A message set by [beginBusy] is dropped: it described work that is over.
void endBusy({bool clearMetrics = false}) {
_isBusy = false;
if (_messageIsBusy) {
_statusMessage = null;
_messageIsBusy = false;
}
if (clearMetrics) {
_statusMessage = null;
_rowCount = null;
Expand All @@ -52,13 +65,31 @@ class QueryaShellStatus extends ChangeNotifier {
if (rowCount != null) _rowCount = rowCount;
if (columnCount != null) _columnCount = columnCount;
if (message != null) _statusMessage = message;
_messageIsBusy = false;
notifyListeners();
}

/// Publishes a query (or command) that failed and clears busy. The row and
/// column counts of an earlier result are dropped so they are not read as
/// this run's.
void reportQueryFailure({
Duration? duration,
String message = 'Query failed',
}) {
_isBusy = false;
_statusMessage = message;
_messageIsBusy = false;
_rowCount = null;
_columnCount = null;
if (duration != null) _lastQueryDuration = duration;
notifyListeners();
}

/// Clears busy + metrics (e.g. connection switch).
void clear() {
_isBusy = false;
_statusMessage = null;
_messageIsBusy = false;
_rowCount = null;
_columnCount = null;
_lastQueryDuration = null;
Expand Down
13 changes: 10 additions & 3 deletions lib/features/workspace/generic_sql_workspace.dart
Original file line number Diff line number Diff line change
Expand Up @@ -663,7 +663,10 @@ class GenericSqlWorkspaceState extends material.State<GenericSqlWorkspace> {
'Statement ${failedAt + 1} of ${texts.length} failed (line $line): $failure';
session.running = false;
});
QueryaShellStatus.instance.endBusy();
QueryaShellStatus.instance.reportQueryFailure(
duration: sw.elapsed,
message: 'Statement ${failedAt + 1} of ${texts.length} failed',
);
return;
}

Expand Down Expand Up @@ -749,7 +752,10 @@ class GenericSqlWorkspaceState extends material.State<GenericSqlWorkspace> {
session.error = statementTimeoutText(e);
session.running = false;
});
QueryaShellStatus.instance.endBusy();
QueryaShellStatus.instance.reportQueryFailure(
duration: sw.elapsed,
message: 'Query timed out',
);
}
} catch (e) {
if (mounted) {
Expand All @@ -758,7 +764,7 @@ class GenericSqlWorkspaceState extends material.State<GenericSqlWorkspace> {
session.error = e.toString();
session.running = false;
});
QueryaShellStatus.instance.endBusy();
QueryaShellStatus.instance.reportQueryFailure(duration: sw.elapsed);
}
} finally {
// Autocommit: after a read that succeeded while no transaction is known
Expand Down Expand Up @@ -869,6 +875,7 @@ class GenericSqlWorkspaceState extends material.State<GenericSqlWorkspace> {
session.error = e.toString();
session.running = false;
});
QueryaShellStatus.instance.reportQueryFailure(message: 'Explain failed');
}
} finally {
QueryaShellStatus.instance.endBusy();
Expand Down
58 changes: 58 additions & 0 deletions test/core/ui/querya_shell_status_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:querya_desktop/core/ui/querya_shell_status.dart';

void main() {
final status = QueryaShellStatus.instance;

setUp(status.resetForTest);
tearDown(status.resetForTest);

test('the busy message goes away with the busy state', () {
status.beginBusy(message: 'Running query…');
expect(status.isBusy, isTrue);
expect(status.statusMessage, 'Running query…');

status.endBusy();

expect(status.isBusy, isFalse);
expect(status.statusMessage, isNull);
});

test('a failure replaces the busy message and drops old counts', () {
status.reportQueryResult(
duration: const Duration(milliseconds: 7),
rowCount: 12,
columnCount: 8,
message: '12 row(s).',
);
status.beginBusy(message: 'Running query…');

status.reportQueryFailure(
duration: const Duration(milliseconds: 3),
message: 'Query failed',
);

expect(status.isBusy, isFalse);
expect(status.statusMessage, 'Query failed');
expect(status.rowCount, isNull);
expect(status.columnCount, isNull);
expect(status.lastQueryDuration, const Duration(milliseconds: 3));
});

test('endBusy after a failure keeps the failure message', () {
status.beginBusy(message: 'Explaining query…');
status.reportQueryFailure(message: 'Explain failed');

status.endBusy();

expect(status.statusMessage, 'Explain failed');
});

test('a result message is not cleared by a later endBusy', () {
status.reportQueryResult(rowCount: 1, columnCount: 1, message: '1 row(s).');

status.endBusy();

expect(status.statusMessage, '1 row(s).');
});
}
Loading