Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
16 changes: 16 additions & 0 deletions app/lib/search/mem_index.dart
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ class InMemoryPackageIndex {
BitArray packages,
IndexedScore<String> Function() scoreFn,
) {
_resetBitArray(packages, query.packages);
final predicateFilterCount = _filterOnPredicates(query, packages);
if (predicateFilterCount <= query.offset) {
return PackageSearchResult.empty();
Expand Down Expand Up @@ -333,6 +334,21 @@ class InMemoryPackageIndex {
);
}

/// The [BitArrayPool] does not resets the reused pool items, because initialization
/// depends on the presence of the [filterOnPackages] list.
void _resetBitArray(BitArray selected, List<String>? filterOnPackages) {
if (filterOnPackages != null && filterOnPackages.isNotEmpty) {
selected.clearAll();
for (final package in filterOnPackages) {
final index = _nameToIndex[package];
if (index == null) continue;
selected.setBit(index);
}
} else {
selected.setRange(0, _documents.length);
}
}

/// Returns the package name that is considered as the best name match
/// for the [query], or `null` if there is no such package name, or the
/// match is not enabled for the given context (e.g. non-default ordering).
Expand Down
1 change: 1 addition & 0 deletions app/lib/search/search_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ class ServiceSearchQuery {
int get offset => max(0, _data.offset ?? 0);
int get limit => max(_minSearchLimit, _data.limit ?? 10);
TextMatchExtent? get textMatchExtent => _data.textMatchExtent;
List<String>? get packages => _data.packages;

Map<String, dynamic> toUriQueryParameters() {
return _data.toUriQueryParameters();
Expand Down
6 changes: 2 additions & 4 deletions app/lib/search/token_index.dart
Original file line number Diff line number Diff line change
Expand Up @@ -249,10 +249,8 @@ class ScorePool<K> extends _AllocationPool<IndexedScore<K>> {
class BitArrayPool extends _AllocationPool<BitArray> {
BitArrayPool(int length)
: super(
// sets all bits to 1
() => BitArray(length)..setRange(0, length),
// sets all bits to 1
(array) => array.setRange(0, length),
() => BitArray(length),
(array) {}, // keeping the array as-is, reset happens at the beginning of the processing
);
}

Expand Down
22 changes: 22 additions & 0 deletions app/test/search/mem_index_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import 'dart:convert';

import 'package:_pub_shared/search/search_form.dart';
import 'package:_pub_shared/search/search_request_data.dart';
import 'package:clock/clock.dart';
import 'package:pub_dev/search/mem_index.dart';
import 'package:pub_dev/search/search_service.dart';
Expand Down Expand Up @@ -543,6 +544,27 @@ server.dart adds a small, prescriptive server (PicoServer) that can be configure
ServiceSearchQuery.parse(query: '=', order: SearchOrder.text));
expect(rs.isEmpty, isTrue);
});

test('only packages list filter', () {
final rs = index
.search(ServiceSearchQuery(SearchRequestData(packages: ['http'])));
expect(rs.packageHits.map((e) => e.package).toList(), ['http']);
});

test('query + packages list filter', () {
// library itself would return `http` too
final rs = index.search(ServiceSearchQuery(SearchRequestData(
query: 'library',
packages: ['async'],
)));
expect(rs.packageHits.map((e) => e.package).toList(), ['async']);
});

test('non-existent package name', () {
final rs = index.search(
ServiceSearchQuery(SearchRequestData(packages: ['not-a-package'])));
expect(rs.packageHits, isEmpty);
});
});

group('special cases', () {
Expand Down
8 changes: 7 additions & 1 deletion pkg/_pub_shared/lib/search/search_request_data.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class SearchRequestData {
final int? offset;
final int? limit;
final TextMatchExtent? textMatchExtent;
final List<String>? packages;

SearchRequestData({
String? query,
Expand All @@ -27,8 +28,10 @@ class SearchRequestData {
this.offset,
this.limit,
this.textMatchExtent,
List<String>? packages,
}) : query = _trimToNull(query),
publisherId = _trimToNull(publisherId);
publisherId = _trimToNull(publisherId),
packages = packages != null && packages.isNotEmpty ? packages : null;

factory SearchRequestData.fromJson(Map<String, dynamic> json) =>
_$SearchRequestDataFromJson(json);
Expand All @@ -54,6 +57,7 @@ class SearchRequestData {
break;
}
}
final packages = uri.queryParametersAll['packages'];

return SearchRequestData(
query: q,
Expand All @@ -64,6 +68,7 @@ class SearchRequestData {
offset: offset,
limit: limit,
textMatchExtent: textMatchExtent,
packages: packages,
);
}

Expand All @@ -78,6 +83,7 @@ class SearchRequestData {
'limit': (limit ?? 10).toString(),
'order': order?.name,
if (textMatchExtent != null) 'textMatchExtent': textMatchExtent!.name,
if (packages != null && packages!.isNotEmpty) 'packages': packages,
};
map.removeWhere((k, v) => v == null);
return map;
Expand Down
4 changes: 4 additions & 0 deletions pkg/_pub_shared/lib/search/search_request_data.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.