Skip to content

Commit 89d2f3d

Browse files
committed
Search refactor: moving all internal serialization method to SearchRequestData
1 parent 83fe245 commit 89d2f3d

File tree

3 files changed

+90
-114
lines changed

3 files changed

+90
-114
lines changed

app/lib/search/handlers.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ Future<shelf.Response> _searchHandler(shelf.Request request) async {
6161
}
6262
final Stopwatch sw = Stopwatch()..start();
6363
final query = request.method == 'POST'
64-
? ServiceSearchQuery.fromSearchRequestData(
64+
? ServiceSearchQuery(
6565
SearchRequestData.fromJson(
6666
json.decode(await request.readAsString()) as Map<String, dynamic>,
6767
),
@@ -72,7 +72,7 @@ Future<shelf.Response> _searchHandler(shelf.Request request) async {
7272
if (elapsed > _slowSearchThreshold) {
7373
_logger.info(
7474
'[pub-slow-search-query] Slow search: handler exceeded ${_slowSearchThreshold.inMilliseconds} ms: '
75-
'${query.toUriQueryParameters()}');
75+
'${query.toDebugString()}');
7676
}
7777

7878
if (request.requestedUri.queryParameters['debug-drift'] == '1') {

app/lib/search/search_service.dart

Lines changed: 30 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@
33
// BSD-style license that can be found in the LICENSE file.
44

55
import 'dart:async';
6+
import 'dart:convert';
67
import 'dart:math' show max;
78

89
import 'package:_pub_shared/search/search_form.dart';
910
import 'package:_pub_shared/search/search_request_data.dart';
1011
import 'package:_pub_shared/search/tags.dart';
1112
import 'package:clock/clock.dart';
12-
import 'package:collection/collection.dart';
1313
import 'package:json_annotation/json_annotation.dart';
1414
import 'package:pub_dev/shared/utils.dart';
1515

@@ -158,36 +158,9 @@ class ApiDocPage {
158158
}
159159

160160
class ServiceSearchQuery {
161-
final String? query;
162-
final ParsedQueryText parsedQuery;
163-
final TagsPredicate tagsPredicate;
161+
final SearchRequestData _data;
164162

165-
final String? publisherId;
166-
167-
final int? minPoints;
168-
169-
/// The value of the `sort` URL query parameter.
170-
final SearchOrder? order;
171-
final int offset;
172-
final int limit;
173-
174-
/// The scope/depth of text matching.
175-
final TextMatchExtent? textMatchExtent;
176-
177-
ServiceSearchQuery._({
178-
this.query,
179-
TagsPredicate? tagsPredicate,
180-
String? publisherId,
181-
required this.minPoints,
182-
this.order,
183-
int? offset,
184-
int? limit,
185-
this.textMatchExtent,
186-
}) : offset = max(0, offset ?? 0),
187-
limit = max(_minSearchLimit, limit ?? 10),
188-
parsedQuery = ParsedQueryText.parse(query),
189-
tagsPredicate = tagsPredicate ?? TagsPredicate(),
190-
publisherId = publisherId?.trimToNull();
163+
ServiceSearchQuery(this._data);
191164

192165
factory ServiceSearchQuery.parse({
193166
String? query,
@@ -200,96 +173,51 @@ class ServiceSearchQuery {
200173
TextMatchExtent? textMatchExtent,
201174
}) {
202175
final q = query?.trimToNull();
203-
return ServiceSearchQuery._(
176+
final tags = tagsPredicate?.toQueryParameters();
177+
return ServiceSearchQuery(SearchRequestData(
204178
query: q,
205-
tagsPredicate: tagsPredicate,
179+
tags: tags,
206180
publisherId: publisherId,
207181
minPoints: minPoints,
208182
order: order,
209183
offset: offset,
210184
limit: limit,
211185
textMatchExtent: textMatchExtent,
212-
);
186+
));
213187
}
214188

215189
factory ServiceSearchQuery.fromServiceUrl(Uri uri) {
216-
final q = uri.queryParameters['q'];
217-
final tagsPredicate =
218-
TagsPredicate.parseQueryValues(uri.queryParametersAll['tags']);
219-
final publisherId = uri.queryParameters['publisherId'];
220-
final String? orderValue = uri.queryParameters['order'];
221-
final SearchOrder? order = parseSearchOrder(orderValue);
222-
223-
final minPoints =
224-
int.tryParse(uri.queryParameters['minPoints'] ?? '0') ?? 0;
225-
final offset = int.tryParse(uri.queryParameters['offset'] ?? '0') ?? 0;
226-
final limit = int.tryParse(uri.queryParameters['limit'] ?? '0') ?? 0;
227-
final textMatchExtentValue =
228-
uri.queryParameters['textMatchExtent']?.trim() ?? '';
229-
final textMatchExtent = TextMatchExtent.values
230-
.firstWhereOrNull((e) => e.name == textMatchExtentValue);
190+
return ServiceSearchQuery(SearchRequestData.fromServiceUrl(uri));
191+
}
231192

232-
return ServiceSearchQuery.parse(
233-
query: q,
234-
tagsPredicate: tagsPredicate,
193+
ServiceSearchQuery change({
194+
TextMatchExtent? textMatchExtent,
195+
}) {
196+
return ServiceSearchQuery(SearchRequestData(
197+
query: query,
198+
tags: _data.tags,
235199
publisherId: publisherId,
236200
order: order,
237201
minPoints: minPoints,
238202
offset: offset,
239203
limit: limit,
240-
textMatchExtent: textMatchExtent,
241-
);
204+
textMatchExtent: textMatchExtent ?? this.textMatchExtent,
205+
));
242206
}
243207

244-
factory ServiceSearchQuery.fromSearchRequestData(SearchRequestData data) {
245-
final tagsPredicate = TagsPredicate.parseQueryValues(data.tags);
246-
return ServiceSearchQuery.parse(
247-
query: data.query,
248-
tagsPredicate: tagsPredicate,
249-
publisherId: data.publisherId,
250-
order: data.order,
251-
minPoints: data.minPoints,
252-
offset: data.offset ?? 0,
253-
limit: data.limit,
254-
textMatchExtent: data.textMatchExtent,
255-
);
256-
}
208+
late final parsedQuery = ParsedQueryText.parse(_data.query);
209+
late final tagsPredicate = TagsPredicate.parseQueryValues(_data.tags);
257210

258-
ServiceSearchQuery change({
259-
String? query,
260-
TagsPredicate? tagsPredicate,
261-
String? publisherId,
262-
SearchOrder? order,
263-
int? offset,
264-
int? limit,
265-
TextMatchExtent? textMatchExtent,
266-
}) {
267-
return ServiceSearchQuery._(
268-
query: query ?? this.query,
269-
tagsPredicate: tagsPredicate ?? this.tagsPredicate,
270-
publisherId: publisherId ?? this.publisherId,
271-
order: order ?? this.order,
272-
minPoints: minPoints,
273-
offset: offset ?? this.offset,
274-
limit: limit ?? this.limit,
275-
textMatchExtent: textMatchExtent ?? this.textMatchExtent,
276-
);
277-
}
211+
String? get query => _data.query;
212+
String? get publisherId => _data.publisherId?.trimToNull();
213+
int? get minPoints => _data.minPoints;
214+
SearchOrder? get order => _data.order;
215+
int get offset => max(0, _data.offset ?? 0);
216+
int get limit => max(_minSearchLimit, _data.limit ?? 10);
217+
TextMatchExtent? get textMatchExtent => _data.textMatchExtent;
278218

279219
Map<String, dynamic> toUriQueryParameters() {
280-
final map = <String, dynamic>{
281-
'q': query,
282-
'tags': tagsPredicate.toQueryParameters(),
283-
'publisherId': publisherId,
284-
'offset': offset.toString(),
285-
if (minPoints != null && minPoints! > 0)
286-
'minPoints': minPoints.toString(),
287-
'limit': limit.toString(),
288-
'order': order?.name,
289-
if (textMatchExtent != null) 'textMatchExtent': textMatchExtent!.name,
290-
};
291-
map.removeWhere((k, v) => v == null);
292-
return map;
220+
return _data.toUriQueryParameters();
293221
}
294222

295223
/// The effective sort order to use:
@@ -327,17 +255,10 @@ class ServiceSearchQuery {
327255
}
328256

329257
SearchRequestData toSearchRequestData() {
330-
return SearchRequestData(
331-
query: query,
332-
tags: tagsPredicate.toQueryParameters(),
333-
publisherId: publisherId,
334-
minPoints: minPoints,
335-
order: order,
336-
offset: offset,
337-
limit: limit,
338-
textMatchExtent: textMatchExtent,
339-
);
258+
return _data;
340259
}
260+
261+
String toDebugString() => json.encode(_data.toJson());
341262
}
342263

343264
class QueryValidity {

pkg/_pub_shared/lib/search/search_request_data.dart

Lines changed: 58 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,19 +19,69 @@ class SearchRequestData {
1919
final TextMatchExtent? textMatchExtent;
2020

2121
SearchRequestData({
22-
this.query,
22+
String? query,
2323
this.tags,
24-
this.publisherId,
24+
String? publisherId,
2525
this.minPoints,
2626
this.order,
2727
this.offset,
2828
this.limit,
2929
this.textMatchExtent,
30-
});
30+
}) : query = _trimToNull(query),
31+
publisherId = _trimToNull(publisherId);
3132

3233
factory SearchRequestData.fromJson(Map<String, dynamic> json) =>
3334
_$SearchRequestDataFromJson(json);
3435
Map<String, dynamic> toJson() => _$SearchRequestDataToJson(this);
36+
37+
factory SearchRequestData.fromServiceUrl(Uri uri) {
38+
final q = uri.queryParameters['q'];
39+
final tags = uri.queryParametersAll['tags'];
40+
final publisherId = uri.queryParameters['publisherId'];
41+
final String? orderValue = uri.queryParameters['order'];
42+
final SearchOrder? order = parseSearchOrder(orderValue);
43+
44+
final minPoints =
45+
int.tryParse(uri.queryParameters['minPoints'] ?? '0') ?? 0;
46+
final offset = int.tryParse(uri.queryParameters['offset'] ?? '0') ?? 0;
47+
final limit = int.tryParse(uri.queryParameters['limit'] ?? '0') ?? 0;
48+
final textMatchExtentValue =
49+
uri.queryParameters['textMatchExtent']?.trim() ?? '';
50+
TextMatchExtent? textMatchExtent;
51+
for (final extent in TextMatchExtent.values) {
52+
if (extent.name == textMatchExtentValue) {
53+
textMatchExtent = extent;
54+
break;
55+
}
56+
}
57+
58+
return SearchRequestData(
59+
query: q,
60+
tags: tags,
61+
publisherId: publisherId,
62+
order: order,
63+
minPoints: minPoints,
64+
offset: offset,
65+
limit: limit,
66+
textMatchExtent: textMatchExtent,
67+
);
68+
}
69+
70+
Map<String, dynamic> toUriQueryParameters() {
71+
final map = <String, dynamic>{
72+
'q': query,
73+
'tags': tags,
74+
'publisherId': publisherId,
75+
'offset': (offset ?? 0).toString(),
76+
if (minPoints != null && minPoints! > 0)
77+
'minPoints': minPoints.toString(),
78+
'limit': (limit ?? 10).toString(),
79+
'order': order?.name,
80+
if (textMatchExtent != null) 'textMatchExtent': textMatchExtent!.name,
81+
};
82+
map.removeWhere((k, v) => v == null);
83+
return map;
84+
}
3585
}
3686

3787
/// The scope (depth) of the text matching.
@@ -65,3 +115,8 @@ enum TextMatchExtent {
65115
/// Text search is on names, descriptions, topic tags, readme content and API symbols.
66116
bool shouldMatchApi() => index >= api.index;
67117
}
118+
119+
String? _trimToNull(String? value) {
120+
final trimmed = value?.trim();
121+
return trimmed == null || trimmed.isEmpty ? null : trimmed;
122+
}

0 commit comments

Comments
 (0)