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
19 changes: 19 additions & 0 deletions lib/core/ui/querya_shell_status.dart
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,25 @@ class QueryaShellStatus extends ChangeNotifier {
notifyListeners();
}

/// Replaces the shown message and query metrics, for example with those of
/// the tab that has just been selected, or with a notice such as `Nothing to
/// run`. Nulls clear the field. While a query is running the busy message
/// owns the bar and this does nothing.
void setQueryMetrics({
String? message,
int? rowCount,
int? columnCount,
Duration? duration,
}) {
if (_isBusy) return;
_statusMessage = message;
_messageIsBusy = false;
_rowCount = rowCount;
_columnCount = columnCount;
_lastQueryDuration = duration;
notifyListeners();
}

/// Clears busy + metrics (e.g. connection switch).
void clear() {
_isBusy = false;
Expand Down
43 changes: 40 additions & 3 deletions lib/features/workspace/generic_sql_workspace.dart
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 +533,31 @@ class GenericSqlWorkspaceState extends material.State<GenericSqlWorkspace> {
});
}

/// The status bar already shows the row and column counts on its right and
/// the result bar the row count: a plain `N row(s).` is not repeated there.
static String? _shellMessage(String? statusLine) =>
statusLine != null && RegExp(r'^\d+ row\(s\)\.$').hasMatch(statusLine)
? null
: statusLine;

/// The tab whose numbers the status bar shows.
SqlQueryTabSession? _statusSession;

/// Shows the active tab's own numbers in the status bar (a tab that has not
/// run shows none).
void _publishActiveStatus() {
if (!mounted) return;
final session = _activeSession;
if (session.running) return;
final hasResult = session.columns.isNotEmpty || session.rows.isNotEmpty;
QueryaShellStatus.instance.setQueryMetrics(
message: _shellMessage(session.statusLine),
rowCount: hasResult ? session.rows.length : null,
columnCount: hasResult ? session.columns.length : null,
duration: session.elapsed,
);
}

/// Runs the statement at the caret ([statementAtCursor]: the selection, or
/// the one statement under the caret), or else the script: the selection, or
/// the whole text. A script runs one statement at a time and stops at the
Expand All @@ -554,7 +579,11 @@ class GenericSqlWorkspaceState extends material.State<GenericSqlWorkspace> {
selected: selected,
caret: selection.isValid ? selection.baseOffset : scope.length,
);
if (spans.isEmpty) return;
if (spans.isEmpty) {
// Say so: a silent Run on an empty editor reads as a broken button.
QueryaShellStatus.instance.setQueryMetrics(message: 'Nothing to run');
return;
}
if (!mounted) return;
final scopeStart = selected ? selection.start : 0;
final texts = [for (final s in spans) s.textIn(scope)];
Expand Down Expand Up @@ -731,7 +760,7 @@ class GenericSqlWorkspaceState extends material.State<GenericSqlWorkspace> {
duration: duration,
rowCount: outRows.length,
columnCount: cols.length,
message: session.statusLine,
message: _shellMessage(session.statusLine),
);

// One history entry per run, with the text that ran.
Expand Down Expand Up @@ -836,7 +865,10 @@ class GenericSqlWorkspaceState extends material.State<GenericSqlWorkspace> {
? selection.textInside(session.controller.text)
: session.controller.text)
.trim();
if (sql.isEmpty) return;
if (sql.isEmpty) {
QueryaShellStatus.instance.setQueryMetrics(message: 'Nothing to explain');
return;
}

invalidatePane(session);
setState(() {
Expand Down Expand Up @@ -1072,6 +1104,11 @@ class GenericSqlWorkspaceState extends material.State<GenericSqlWorkspace> {

@override
material.Widget build(material.BuildContext context) {
if (!identical(_statusSession, _activeSession)) {
_statusSession = _activeSession;
material.WidgetsBinding.instance
.addPostFrameCallback((_) => _publishActiveStatus());
}
return Actions(
actions: <Type, Action<Intent>>{
NewSqlIntent: CallbackAction<NewSqlIntent>(
Expand Down
34 changes: 34 additions & 0 deletions test/core/ui/querya_shell_status_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,38 @@ void main() {

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

test('setQueryMetrics replaces the numbers of the last run (#1479)', () {
status.reportQueryResult(
duration: const Duration(milliseconds: 48),
rowCount: 8,
columnCount: 6,
message: 'OK',
);

status.setQueryMetrics();

expect(status.statusMessage, isNull);
expect(status.rowCount, isNull);
expect(status.columnCount, isNull);
expect(status.lastQueryDuration, isNull);
});

test('setQueryMetrics shows a notice and drops the old counts (#1478)', () {
status.reportQueryResult(rowCount: 1, columnCount: 1, message: '1 row(s).');

status.setQueryMetrics(message: 'Nothing to run');

expect(status.statusMessage, 'Nothing to run');
expect(status.rowCount, isNull);
});

test('setQueryMetrics leaves a running query\'s busy message alone', () {
status.beginBusy(message: 'Running query…');

status.setQueryMetrics(message: 'Nothing to run');

expect(status.isBusy, isTrue);
expect(status.statusMessage, 'Running query…');
});
}
Loading