Skip to content

Commit e6a2990

Browse files
committed
Merge remote-tracking branch 'upstream/main'
2 parents 8c75603 + ca4f705 commit e6a2990

File tree

22 files changed

+277
-437
lines changed

22 files changed

+277
-437
lines changed

.github/actions/setup-env/action.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ inputs:
2020
runs:
2121
using: "composite"
2222
steps:
23-
- uses: pnpm/action-setup@v2
23+
- uses: pnpm/action-setup@v3
2424
name: Setup pnpm
2525
with:
2626
version: ${{ inputs.pnpm-version }}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package run.halo.app.extension.index.query;
2+
3+
import static java.util.Objects.requireNonNull;
4+
5+
import java.util.Collections;
6+
import java.util.NavigableSet;
7+
import lombok.Getter;
8+
9+
@Getter
10+
public class Not extends LogicalQuery {
11+
12+
private final Query negatedQuery;
13+
14+
public Not(Query negatedQuery) {
15+
super(Collections.singleton(
16+
requireNonNull(negatedQuery, "The negated query must not be null.")));
17+
this.negatedQuery = negatedQuery;
18+
}
19+
20+
@Override
21+
public NavigableSet<String> matches(QueryIndexView indexView) {
22+
var negatedResult = negatedQuery.matches(indexView);
23+
var allIds = indexView.getAllIds();
24+
allIds.removeAll(negatedResult);
25+
return allIds;
26+
}
27+
}

api/src/main/java/run/halo/app/extension/index/query/QueryFactory.java

+4
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,10 @@ public static Query or(Query query1, Query query2, Collection<Query> additionalQ
173173
return new Or(queries);
174174
}
175175

176+
public static Query not(Query query) {
177+
return new Not(query);
178+
}
179+
176180
public static Query betweenLowerExclusive(String fieldName, String lowerValue,
177181
String upperValue) {
178182
return new Between(fieldName, lowerValue, false, upperValue, true);

api/src/test/java/run/halo/app/extension/index/query/QueryFactoryTest.java

+10
Original file line numberDiff line numberDiff line change
@@ -248,4 +248,14 @@ void containsTest() {
248248
"104", "105"
249249
);
250250
}
251+
252+
@Test
253+
void notTest() {
254+
var indexView = IndexViewDataSet.createEmployeeIndexView();
255+
var resultSet =
256+
QueryFactory.not(QueryFactory.contains("firstName", "i")).matches(indexView);
257+
assertThat(resultSet).containsExactlyInAnyOrder(
258+
"100", "101", "103", "104", "105"
259+
);
260+
}
251261
}

application/src/main/java/run/halo/app/core/extension/attachment/endpoint/AttachmentEndpoint.java

+48-119
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,27 @@
11
package run.halo.app.core.extension.attachment.endpoint;
22

33
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
4-
import static java.util.Comparator.comparing;
54
import static org.springdoc.core.fn.builders.apiresponse.Builder.responseBuilder;
65
import static org.springdoc.core.fn.builders.content.Builder.contentBuilder;
76
import static org.springdoc.core.fn.builders.schema.Builder.schemaBuilder;
87
import static org.springframework.boot.convert.ApplicationConversionService.getSharedInstance;
98
import static org.springframework.web.reactive.function.server.RequestPredicates.contentType;
109
import static run.halo.app.extension.ListResult.generateGenericClass;
10+
import static run.halo.app.extension.index.query.QueryFactory.all;
11+
import static run.halo.app.extension.index.query.QueryFactory.and;
12+
import static run.halo.app.extension.index.query.QueryFactory.contains;
13+
import static run.halo.app.extension.index.query.QueryFactory.in;
14+
import static run.halo.app.extension.index.query.QueryFactory.isNull;
15+
import static run.halo.app.extension.index.query.QueryFactory.not;
1116
import static run.halo.app.extension.router.QueryParamBuildUtil.buildParametersFromType;
12-
import static run.halo.app.extension.router.selector.SelectorUtil.labelAndFieldSelectorToPredicate;
17+
import static run.halo.app.extension.router.selector.SelectorUtil.labelAndFieldSelectorToListOptions;
1318

1419
import io.swagger.v3.oas.annotations.media.ArraySchema;
1520
import io.swagger.v3.oas.annotations.media.Schema;
16-
import java.util.ArrayList;
17-
import java.util.Comparator;
1821
import java.util.List;
19-
import java.util.Objects;
2022
import java.util.Optional;
21-
import java.util.function.Predicate;
2223
import lombok.extern.slf4j.Slf4j;
24+
import org.apache.commons.lang3.BooleanUtils;
2325
import org.springdoc.core.fn.builders.requestbody.Builder;
2426
import org.springdoc.webflux.core.fn.SpringdocRouteBuilder;
2527
import org.springframework.data.domain.Sort;
@@ -42,11 +44,12 @@
4244
import run.halo.app.core.extension.endpoint.CustomEndpoint;
4345
import run.halo.app.core.extension.endpoint.SortResolver;
4446
import run.halo.app.core.extension.service.AttachmentService;
45-
import run.halo.app.extension.Comparators;
46-
import run.halo.app.extension.MetadataUtil;
47+
import run.halo.app.extension.ListOptions;
48+
import run.halo.app.extension.PageRequestImpl;
4749
import run.halo.app.extension.ReactiveExtensionClient;
4850
import run.halo.app.extension.router.IListRequest;
4951
import run.halo.app.extension.router.IListRequest.QueryListRequest;
52+
import run.halo.app.extension.router.selector.LabelSelector;
5053

5154
@Slf4j
5255
@Component
@@ -107,50 +110,35 @@ public RouterFunction<ServerResponse> endpoint() {
107110

108111
Mono<ServerResponse> search(ServerRequest request) {
109112
var searchRequest = new SearchRequest(request);
110-
return client.list(Group.class, group -> MetadataUtil.nullSafeLabels(group)
111-
.containsKey(Group.HIDDEN_LABEL), null)
113+
var groupListOptions = new ListOptions();
114+
groupListOptions.setLabelSelector(LabelSelector.builder()
115+
.exists(Group.HIDDEN_LABEL)
116+
.build());
117+
return client.listAll(Group.class, groupListOptions, Sort.unsorted())
112118
.map(group -> group.getMetadata().getName())
113119
.collectList()
114120
.defaultIfEmpty(List.of())
115-
.flatMap(groups -> client.list(Attachment.class,
116-
searchRequest.toPredicate().and(visibleGroupPredicate(groups)),
117-
searchRequest.toComparator(),
118-
searchRequest.getPage(), searchRequest.getSize())
119-
.flatMap(listResult -> ServerResponse.ok()
120-
.contentType(MediaType.APPLICATION_JSON)
121-
.bodyValue(listResult)
122-
)
121+
.flatMap(hiddenGroups -> client.listBy(Attachment.class,
122+
searchRequest.toListOptions(hiddenGroups),
123+
PageRequestImpl.of(searchRequest.getPage(), searchRequest.getSize(),
124+
searchRequest.getSort())
125+
)
126+
.flatMap(listResult -> ServerResponse.ok()
127+
.contentType(MediaType.APPLICATION_JSON)
128+
.bodyValue(listResult)
129+
)
123130
);
124-
125-
}
126-
127-
static Predicate<Attachment> visibleGroupPredicate(List<String> hiddenGroups) {
128-
return attachment -> {
129-
if (!StringUtils.hasText(attachment.getSpec().getGroupName())) {
130-
return true;
131-
}
132-
return !hiddenGroups.contains(attachment.getSpec().getGroupName());
133-
};
134131
}
135132

136133
public interface ISearchRequest extends IListRequest {
137134

138-
@Schema(description = "Display name of attachment")
139-
Optional<String> getDisplayName();
140-
141-
@Schema(description = "Name of policy")
142-
Optional<String> getPolicy();
143-
144-
@Schema(description = "Name of group")
145-
Optional<String> getGroup();
135+
@Schema(description = "Keyword for searching.")
136+
Optional<String> getKeyword();
146137

147138
@Schema(description = "Filter attachments without group. This parameter will ignore group"
148139
+ " parameter.")
149140
Optional<Boolean> getUngrouped();
150141

151-
@Schema(description = "Name of user who uploaded the attachment")
152-
Optional<String> getUploadedBy();
153-
154142
@ArraySchema(uniqueItems = true,
155143
arraySchema = @Schema(name = "sort",
156144
description = "Sort property and direction of the list result. Supported fields: "
@@ -159,7 +147,6 @@ public interface ISearchRequest extends IListRequest {
159147
implementation = String.class,
160148
example = "creationTimestamp,desc"))
161149
Sort getSort();
162-
163150
}
164151

165152
public static class SearchRequest extends QueryListRequest implements ISearchRequest {
@@ -172,20 +159,8 @@ public SearchRequest(ServerRequest request) {
172159
}
173160

174161
@Override
175-
public Optional<String> getDisplayName() {
176-
return Optional.ofNullable(queryParams.getFirst("displayName"))
177-
.filter(StringUtils::hasText);
178-
}
179-
180-
@Override
181-
public Optional<String> getPolicy() {
182-
return Optional.ofNullable(queryParams.getFirst("policy"))
183-
.filter(StringUtils::hasText);
184-
}
185-
186-
@Override
187-
public Optional<String> getGroup() {
188-
return Optional.ofNullable(queryParams.getFirst("group"))
162+
public Optional<String> getKeyword() {
163+
return Optional.ofNullable(queryParams.getFirst("keyword"))
189164
.filter(StringUtils::hasText);
190165
}
191166

@@ -195,81 +170,35 @@ public Optional<Boolean> getUngrouped() {
195170
.map(ungroupedStr -> getSharedInstance().convert(ungroupedStr, Boolean.class));
196171
}
197172

198-
@Override
199-
public Optional<String> getUploadedBy() {
200-
return Optional.ofNullable(queryParams.getFirst("uploadedBy"))
201-
.filter(StringUtils::hasText);
202-
}
203-
204173
@Override
205174
public Sort getSort() {
206-
return SortResolver.defaultInstance.resolve(exchange);
175+
var sort = SortResolver.defaultInstance.resolve(exchange);
176+
sort = sort.and(Sort.by(
177+
Sort.Order.desc("metadata.creationTimestamp"),
178+
Sort.Order.asc("metadata.name")
179+
));
180+
return sort;
207181
}
208182

209-
public Predicate<Attachment> toPredicate() {
210-
Predicate<Attachment> displayNamePred = attachment -> getDisplayName()
211-
.map(displayNameInParam -> {
212-
String displayName = attachment.getSpec().getDisplayName();
213-
return displayName.contains(displayNameInParam);
214-
}).orElse(true);
215-
216-
Predicate<Attachment> policyPred = attachment -> getPolicy()
217-
.map(policy -> Objects.equals(policy, attachment.getSpec().getPolicyName()))
218-
.orElse(true);
219-
220-
Predicate<Attachment> groupPred = attachment -> getGroup()
221-
.map(group -> Objects.equals(group, attachment.getSpec().getGroupName()))
222-
.orElse(true);
223-
224-
Predicate<Attachment> ungroupedPred = attachment -> getUngrouped()
225-
.filter(Boolean::booleanValue)
226-
.map(ungrouped -> !StringUtils.hasText(attachment.getSpec().getGroupName()))
227-
.orElseGet(() -> groupPred.test(attachment));
183+
public ListOptions toListOptions(List<String> hiddenGroups) {
184+
final var listOptions =
185+
labelAndFieldSelectorToListOptions(getLabelSelector(), getFieldSelector());
228186

229-
Predicate<Attachment> uploadedByPred = attachment -> getUploadedBy()
230-
.map(uploadedBy -> Objects.equals(uploadedBy, attachment.getSpec().getOwnerName()))
231-
.orElse(true);
232-
233-
234-
var selectorPred =
235-
labelAndFieldSelectorToPredicate(getLabelSelector(), getFieldSelector());
236-
237-
return displayNamePred
238-
.and(policyPred)
239-
.and(ungroupedPred)
240-
.and(uploadedByPred)
241-
.and(selectorPred);
242-
}
187+
var fieldQuery = all();
188+
if (getKeyword().isPresent()) {
189+
fieldQuery = and(fieldQuery, contains("spec.displayName", getKeyword().get()));
190+
}
243191

244-
public Comparator<Attachment> toComparator() {
245-
var sort = getSort();
246-
List<Comparator<Attachment>> comparators = new ArrayList<>();
247-
var creationOrder = sort.getOrderFor("creationTimestamp");
248-
if (creationOrder != null) {
249-
Comparator<Attachment> comparator = comparing(
250-
attachment -> attachment.getMetadata().getCreationTimestamp());
251-
if (creationOrder.isDescending()) {
252-
comparator = comparator.reversed();
253-
}
254-
comparators.add(comparator);
192+
if (getUngrouped().isPresent() && BooleanUtils.isTrue(getUngrouped().get())) {
193+
fieldQuery = and(fieldQuery, isNull("spec.groupName"));
255194
}
256195

257-
var sizeOrder = sort.getOrderFor("size");
258-
if (sizeOrder != null) {
259-
Comparator<Attachment> comparator =
260-
comparing(attachment -> attachment.getSpec().getSize());
261-
if (sizeOrder.isDescending()) {
262-
comparator = comparator.reversed();
263-
}
264-
comparators.add(comparator);
196+
if (!hiddenGroups.isEmpty()) {
197+
fieldQuery = and(fieldQuery, not(in("spec.groupName", hiddenGroups)));
265198
}
266199

267-
// add default comparator
268-
comparators.add(Comparators.compareCreationTimestamp(false));
269-
comparators.add(Comparators.compareName(true));
270-
return comparators.stream()
271-
.reduce(Comparator::thenComparing)
272-
.orElse(null);
200+
listOptions.setFieldSelector(listOptions.getFieldSelector().andQuery(fieldQuery));
201+
return listOptions;
273202
}
274203
}
275204

application/src/main/java/run/halo/app/infra/SchemeInitializer.java

+33-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
import java.util.Set;
88
import org.apache.commons.lang3.BooleanUtils;
9+
import org.apache.commons.lang3.StringUtils;
910
import org.springframework.boot.context.event.ApplicationContextInitializedEvent;
1011
import org.springframework.context.ApplicationListener;
1112
import org.springframework.lang.NonNull;
@@ -191,7 +192,38 @@ public void onApplicationEvent(@NonNull ApplicationContextInitializedEvent event
191192
// storage.halo.run
192193
schemeManager.register(Group.class);
193194
schemeManager.register(Policy.class);
194-
schemeManager.register(Attachment.class);
195+
schemeManager.register(Attachment.class, indexSpecs -> {
196+
indexSpecs.add(new IndexSpec()
197+
.setName("spec.displayName")
198+
.setIndexFunc(simpleAttribute(Attachment.class,
199+
attachment -> attachment.getSpec().getDisplayName()))
200+
);
201+
indexSpecs.add(new IndexSpec()
202+
.setName("spec.policyName")
203+
.setIndexFunc(simpleAttribute(Attachment.class,
204+
attachment -> attachment.getSpec().getPolicyName()))
205+
);
206+
indexSpecs.add(new IndexSpec()
207+
.setName("spec.groupName")
208+
.setIndexFunc(simpleAttribute(Attachment.class, attachment -> {
209+
var group = attachment.getSpec().getGroupName();
210+
return StringUtils.isBlank(group) ? null : group;
211+
}))
212+
);
213+
indexSpecs.add(new IndexSpec()
214+
.setName("spec.ownerName")
215+
.setIndexFunc(simpleAttribute(Attachment.class,
216+
attachment -> attachment.getSpec().getOwnerName()))
217+
);
218+
indexSpecs.add(new IndexSpec()
219+
.setName("spec.size")
220+
.setIndexFunc(simpleAttribute(Attachment.class,
221+
attachment -> {
222+
var size = attachment.getSpec().getSize();
223+
return size != null ? size.toString() : null;
224+
}))
225+
);
226+
});
195227
schemeManager.register(PolicyTemplate.class);
196228
// metrics.halo.run
197229
schemeManager.register(Counter.class);

0 commit comments

Comments
 (0)