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
15 changes: 12 additions & 3 deletions lib/core/database/mongodb_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,16 @@ void _throwIfMongoWriteFailed(
}

/// Service for managing MongoDB connections.
/// How many documents `find` returns when the caller gives no limit (or `0`,
/// which MongoDB reads as "no limit"). Decoding is about 64 us per document on
/// the UI isolate: 50,000 documents are a three-second wait and a 40-60 ms
/// stall (#1357).
const int kMongoDefaultFindLimit = 1000;

/// The limit `find` really applies for a requested [limit].
int effectiveMongoFindLimit(int? limit) =>
limit == null || limit <= 0 ? kMongoDefaultFindLimit : limit;

class MongoService {
MongoService._();

Expand Down Expand Up @@ -170,9 +180,8 @@ class MongoService {
if (skip != null && skip > 0) {
selector.skip(skip);
}
if (limit != null && limit > 0) {
selector.limit(limit);
}
// Never unbounded: `stream.toList()` below holds every document.
selector.limit(effectiveMongoFindLimit(limit));

final stream = coll.find(selector);
return await stream.toList();
Expand Down
14 changes: 13 additions & 1 deletion lib/features/mongodb/mongo_query_executor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,18 @@ class MongoQueryResult {
int get count => documents.length;
}

/// "Fetched N documents", and a note when `.limit(0)` (no limit in MongoDB)
/// was cut at [kMongoDefaultFindLimit] so the user knows there may be more.
String mongoFindSummary(int fetched, int? requestedLimit) {
final capped = requestedLimit != null &&
requestedLimit <= 0 &&
fetched >= kMongoDefaultFindLimit;
return capped
? 'Fetched $fetched documents (capped at $kMongoDefaultFindLimit; '
'give .limit(n) for more)'
: 'Fetched $fetched documents';
}

/// Abstract contract for executing parsed [MqlCommand]s against MongoDB.
abstract class MongoQueryExecutor {
Future<MongoQueryResult> execute({
Expand Down Expand Up @@ -66,7 +78,7 @@ class DefaultMongoQueryExecutor implements MongoQueryExecutor {
return MongoQueryResult(
documents: docs,
elapsed: stopwatch.elapsed,
summary: 'Fetched ${docs.length} documents',
summary: mongoFindSummary(docs.length, command.limit),
);

case MqlMethod.findOne:
Expand Down
14 changes: 14 additions & 0 deletions test/core/database/mongo_service_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -176,4 +176,18 @@ void main() {
expect(MongoService.instance.getConnection(302), isNull);
});
});

group('effectiveMongoFindLimit (#1357)', () {
test('no limit, or 0 (MongoDB: unlimited), becomes the default cap', () {
expect(effectiveMongoFindLimit(null), kMongoDefaultFindLimit);
expect(effectiveMongoFindLimit(0), kMongoDefaultFindLimit);
expect(effectiveMongoFindLimit(-5), kMongoDefaultFindLimit);
});

test('an explicit positive limit is kept', () {
expect(effectiveMongoFindLimit(1), 1);
expect(effectiveMongoFindLimit(100), 100);
expect(effectiveMongoFindLimit(50000), 50000);
});
});
}
24 changes: 24 additions & 0 deletions test/features/mongodb/mongo_find_summary_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:querya_desktop/core/database/mongodb_service.dart';
import 'package:querya_desktop/features/mongodb/mongo_query_executor.dart';

void main() {
group('mongoFindSummary (#1357)', () {
test('an ordinary find just says how many documents came back', () {
expect(mongoFindSummary(25, null), 'Fetched 25 documents');
expect(mongoFindSummary(100, 100), 'Fetched 100 documents');
expect(mongoFindSummary(kMongoDefaultFindLimit, 5000), 'Fetched 1000 documents');
});

test('.limit(0) that hit the cap says so', () {
expect(
mongoFindSummary(kMongoDefaultFindLimit, 0),
contains('capped at $kMongoDefaultFindLimit'),
);
});

test('.limit(0) that did not reach the cap is not marked', () {
expect(mongoFindSummary(12, 0), 'Fetched 12 documents');
});
});
}
Loading