refactor: optimize old attachment query parameters using index (#5363)

#### What type of PR is this?
/kind improvement
/area core
/milestone 2.13.x

#### What this PR does / why we need it:
使用索引功能优化附件列表查询

#### Does this PR introduce a user-facing change?
```release-note
使用索引功能优化附件列表查询
```
pull/5302/head^2
guqing 2024-02-20 10:58:09 +08:00 committed by GitHub
parent 333422a0d4
commit 80e14e97d7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 170 additions and 264 deletions

View File

@ -0,0 +1,27 @@
package run.halo.app.extension.index.query;
import static java.util.Objects.requireNonNull;
import java.util.Collections;
import java.util.NavigableSet;
import lombok.Getter;
@Getter
public class Not extends LogicalQuery {
private final Query negatedQuery;
public Not(Query negatedQuery) {
super(Collections.singleton(
requireNonNull(negatedQuery, "The negated query must not be null.")));
this.negatedQuery = negatedQuery;
}
@Override
public NavigableSet<String> matches(QueryIndexView indexView) {
var negatedResult = negatedQuery.matches(indexView);
var allIds = indexView.getAllIds();
allIds.removeAll(negatedResult);
return allIds;
}
}

View File

@ -173,6 +173,10 @@ public class QueryFactory {
return new Or(queries); return new Or(queries);
} }
public static Query not(Query query) {
return new Not(query);
}
public static Query betweenLowerExclusive(String fieldName, String lowerValue, public static Query betweenLowerExclusive(String fieldName, String lowerValue,
String upperValue) { String upperValue) {
return new Between(fieldName, lowerValue, false, upperValue, true); return new Between(fieldName, lowerValue, false, upperValue, true);

View File

@ -248,4 +248,14 @@ class QueryFactoryTest {
"104", "105" "104", "105"
); );
} }
@Test
void notTest() {
var indexView = IndexViewDataSet.createEmployeeIndexView();
var resultSet =
QueryFactory.not(QueryFactory.contains("firstName", "i")).matches(indexView);
assertThat(resultSet).containsExactlyInAnyOrder(
"100", "101", "103", "104", "105"
);
}
} }

View File

@ -1,25 +1,27 @@
package run.halo.app.core.extension.attachment.endpoint; package run.halo.app.core.extension.attachment.endpoint;
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
import static java.util.Comparator.comparing;
import static org.springdoc.core.fn.builders.apiresponse.Builder.responseBuilder; import static org.springdoc.core.fn.builders.apiresponse.Builder.responseBuilder;
import static org.springdoc.core.fn.builders.content.Builder.contentBuilder; import static org.springdoc.core.fn.builders.content.Builder.contentBuilder;
import static org.springdoc.core.fn.builders.schema.Builder.schemaBuilder; import static org.springdoc.core.fn.builders.schema.Builder.schemaBuilder;
import static org.springframework.boot.convert.ApplicationConversionService.getSharedInstance; import static org.springframework.boot.convert.ApplicationConversionService.getSharedInstance;
import static org.springframework.web.reactive.function.server.RequestPredicates.contentType; import static org.springframework.web.reactive.function.server.RequestPredicates.contentType;
import static run.halo.app.extension.ListResult.generateGenericClass; import static run.halo.app.extension.ListResult.generateGenericClass;
import static run.halo.app.extension.index.query.QueryFactory.all;
import static run.halo.app.extension.index.query.QueryFactory.and;
import static run.halo.app.extension.index.query.QueryFactory.contains;
import static run.halo.app.extension.index.query.QueryFactory.in;
import static run.halo.app.extension.index.query.QueryFactory.isNull;
import static run.halo.app.extension.index.query.QueryFactory.not;
import static run.halo.app.extension.router.QueryParamBuildUtil.buildParametersFromType; import static run.halo.app.extension.router.QueryParamBuildUtil.buildParametersFromType;
import static run.halo.app.extension.router.selector.SelectorUtil.labelAndFieldSelectorToPredicate; import static run.halo.app.extension.router.selector.SelectorUtil.labelAndFieldSelectorToListOptions;
import io.swagger.v3.oas.annotations.media.ArraySchema; import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.function.Predicate;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.BooleanUtils;
import org.springdoc.core.fn.builders.requestbody.Builder; import org.springdoc.core.fn.builders.requestbody.Builder;
import org.springdoc.webflux.core.fn.SpringdocRouteBuilder; import org.springdoc.webflux.core.fn.SpringdocRouteBuilder;
import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort;
@ -42,11 +44,12 @@ import run.halo.app.core.extension.attachment.Group;
import run.halo.app.core.extension.endpoint.CustomEndpoint; import run.halo.app.core.extension.endpoint.CustomEndpoint;
import run.halo.app.core.extension.endpoint.SortResolver; import run.halo.app.core.extension.endpoint.SortResolver;
import run.halo.app.core.extension.service.AttachmentService; import run.halo.app.core.extension.service.AttachmentService;
import run.halo.app.extension.Comparators; import run.halo.app.extension.ListOptions;
import run.halo.app.extension.MetadataUtil; import run.halo.app.extension.PageRequestImpl;
import run.halo.app.extension.ReactiveExtensionClient; import run.halo.app.extension.ReactiveExtensionClient;
import run.halo.app.extension.router.IListRequest; import run.halo.app.extension.router.IListRequest;
import run.halo.app.extension.router.IListRequest.QueryListRequest; import run.halo.app.extension.router.IListRequest.QueryListRequest;
import run.halo.app.extension.router.selector.LabelSelector;
@Slf4j @Slf4j
@Component @Component
@ -107,50 +110,35 @@ public class AttachmentEndpoint implements CustomEndpoint {
Mono<ServerResponse> search(ServerRequest request) { Mono<ServerResponse> search(ServerRequest request) {
var searchRequest = new SearchRequest(request); var searchRequest = new SearchRequest(request);
return client.list(Group.class, group -> MetadataUtil.nullSafeLabels(group) var groupListOptions = new ListOptions();
.containsKey(Group.HIDDEN_LABEL), null) groupListOptions.setLabelSelector(LabelSelector.builder()
.exists(Group.HIDDEN_LABEL)
.build());
return client.listAll(Group.class, groupListOptions, Sort.unsorted())
.map(group -> group.getMetadata().getName()) .map(group -> group.getMetadata().getName())
.collectList() .collectList()
.defaultIfEmpty(List.of()) .defaultIfEmpty(List.of())
.flatMap(groups -> client.list(Attachment.class, .flatMap(hiddenGroups -> client.listBy(Attachment.class,
searchRequest.toPredicate().and(visibleGroupPredicate(groups)), searchRequest.toListOptions(hiddenGroups),
searchRequest.toComparator(), PageRequestImpl.of(searchRequest.getPage(), searchRequest.getSize(),
searchRequest.getPage(), searchRequest.getSize()) searchRequest.getSort())
)
.flatMap(listResult -> ServerResponse.ok() .flatMap(listResult -> ServerResponse.ok()
.contentType(MediaType.APPLICATION_JSON) .contentType(MediaType.APPLICATION_JSON)
.bodyValue(listResult) .bodyValue(listResult)
) )
); );
}
static Predicate<Attachment> visibleGroupPredicate(List<String> hiddenGroups) {
return attachment -> {
if (!StringUtils.hasText(attachment.getSpec().getGroupName())) {
return true;
}
return !hiddenGroups.contains(attachment.getSpec().getGroupName());
};
} }
public interface ISearchRequest extends IListRequest { public interface ISearchRequest extends IListRequest {
@Schema(description = "Display name of attachment") @Schema(description = "Keyword for searching.")
Optional<String> getDisplayName(); Optional<String> getKeyword();
@Schema(description = "Name of policy")
Optional<String> getPolicy();
@Schema(description = "Name of group")
Optional<String> getGroup();
@Schema(description = "Filter attachments without group. This parameter will ignore group" @Schema(description = "Filter attachments without group. This parameter will ignore group"
+ " parameter.") + " parameter.")
Optional<Boolean> getUngrouped(); Optional<Boolean> getUngrouped();
@Schema(description = "Name of user who uploaded the attachment")
Optional<String> getUploadedBy();
@ArraySchema(uniqueItems = true, @ArraySchema(uniqueItems = true,
arraySchema = @Schema(name = "sort", arraySchema = @Schema(name = "sort",
description = "Sort property and direction of the list result. Supported fields: " description = "Sort property and direction of the list result. Supported fields: "
@ -159,7 +147,6 @@ public class AttachmentEndpoint implements CustomEndpoint {
implementation = String.class, implementation = String.class,
example = "creationTimestamp,desc")) example = "creationTimestamp,desc"))
Sort getSort(); Sort getSort();
} }
public static class SearchRequest extends QueryListRequest implements ISearchRequest { public static class SearchRequest extends QueryListRequest implements ISearchRequest {
@ -172,20 +159,8 @@ public class AttachmentEndpoint implements CustomEndpoint {
} }
@Override @Override
public Optional<String> getDisplayName() { public Optional<String> getKeyword() {
return Optional.ofNullable(queryParams.getFirst("displayName")) return Optional.ofNullable(queryParams.getFirst("keyword"))
.filter(StringUtils::hasText);
}
@Override
public Optional<String> getPolicy() {
return Optional.ofNullable(queryParams.getFirst("policy"))
.filter(StringUtils::hasText);
}
@Override
public Optional<String> getGroup() {
return Optional.ofNullable(queryParams.getFirst("group"))
.filter(StringUtils::hasText); .filter(StringUtils::hasText);
} }
@ -195,81 +170,35 @@ public class AttachmentEndpoint implements CustomEndpoint {
.map(ungroupedStr -> getSharedInstance().convert(ungroupedStr, Boolean.class)); .map(ungroupedStr -> getSharedInstance().convert(ungroupedStr, Boolean.class));
} }
@Override
public Optional<String> getUploadedBy() {
return Optional.ofNullable(queryParams.getFirst("uploadedBy"))
.filter(StringUtils::hasText);
}
@Override @Override
public Sort getSort() { public Sort getSort() {
return SortResolver.defaultInstance.resolve(exchange); var sort = SortResolver.defaultInstance.resolve(exchange);
sort = sort.and(Sort.by(
Sort.Order.desc("metadata.creationTimestamp"),
Sort.Order.asc("metadata.name")
));
return sort;
} }
public Predicate<Attachment> toPredicate() { public ListOptions toListOptions(List<String> hiddenGroups) {
Predicate<Attachment> displayNamePred = attachment -> getDisplayName() final var listOptions =
.map(displayNameInParam -> { labelAndFieldSelectorToListOptions(getLabelSelector(), getFieldSelector());
String displayName = attachment.getSpec().getDisplayName();
return displayName.contains(displayNameInParam);
}).orElse(true);
Predicate<Attachment> policyPred = attachment -> getPolicy() var fieldQuery = all();
.map(policy -> Objects.equals(policy, attachment.getSpec().getPolicyName())) if (getKeyword().isPresent()) {
.orElse(true); fieldQuery = and(fieldQuery, contains("spec.displayName", getKeyword().get()));
Predicate<Attachment> groupPred = attachment -> getGroup()
.map(group -> Objects.equals(group, attachment.getSpec().getGroupName()))
.orElse(true);
Predicate<Attachment> ungroupedPred = attachment -> getUngrouped()
.filter(Boolean::booleanValue)
.map(ungrouped -> !StringUtils.hasText(attachment.getSpec().getGroupName()))
.orElseGet(() -> groupPred.test(attachment));
Predicate<Attachment> uploadedByPred = attachment -> getUploadedBy()
.map(uploadedBy -> Objects.equals(uploadedBy, attachment.getSpec().getOwnerName()))
.orElse(true);
var selectorPred =
labelAndFieldSelectorToPredicate(getLabelSelector(), getFieldSelector());
return displayNamePred
.and(policyPred)
.and(ungroupedPred)
.and(uploadedByPred)
.and(selectorPred);
} }
public Comparator<Attachment> toComparator() { if (getUngrouped().isPresent() && BooleanUtils.isTrue(getUngrouped().get())) {
var sort = getSort(); fieldQuery = and(fieldQuery, isNull("spec.groupName"));
List<Comparator<Attachment>> comparators = new ArrayList<>();
var creationOrder = sort.getOrderFor("creationTimestamp");
if (creationOrder != null) {
Comparator<Attachment> comparator = comparing(
attachment -> attachment.getMetadata().getCreationTimestamp());
if (creationOrder.isDescending()) {
comparator = comparator.reversed();
}
comparators.add(comparator);
} }
var sizeOrder = sort.getOrderFor("size"); if (!hiddenGroups.isEmpty()) {
if (sizeOrder != null) { fieldQuery = and(fieldQuery, not(in("spec.groupName", hiddenGroups)));
Comparator<Attachment> comparator =
comparing(attachment -> attachment.getSpec().getSize());
if (sizeOrder.isDescending()) {
comparator = comparator.reversed();
}
comparators.add(comparator);
} }
// add default comparator listOptions.setFieldSelector(listOptions.getFieldSelector().andQuery(fieldQuery));
comparators.add(Comparators.compareCreationTimestamp(false)); return listOptions;
comparators.add(Comparators.compareName(true));
return comparators.stream()
.reduce(Comparator::thenComparing)
.orElse(null);
} }
} }

View File

@ -6,6 +6,7 @@ import static run.halo.app.extension.index.IndexAttributeFactory.simpleAttribute
import java.util.Set; import java.util.Set;
import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.context.event.ApplicationContextInitializedEvent; import org.springframework.boot.context.event.ApplicationContextInitializedEvent;
import org.springframework.context.ApplicationListener; import org.springframework.context.ApplicationListener;
import org.springframework.lang.NonNull; import org.springframework.lang.NonNull;
@ -191,7 +192,38 @@ public class SchemeInitializer implements ApplicationListener<ApplicationContext
// storage.halo.run // storage.halo.run
schemeManager.register(Group.class); schemeManager.register(Group.class);
schemeManager.register(Policy.class); schemeManager.register(Policy.class);
schemeManager.register(Attachment.class); schemeManager.register(Attachment.class, indexSpecs -> {
indexSpecs.add(new IndexSpec()
.setName("spec.displayName")
.setIndexFunc(simpleAttribute(Attachment.class,
attachment -> attachment.getSpec().getDisplayName()))
);
indexSpecs.add(new IndexSpec()
.setName("spec.policyName")
.setIndexFunc(simpleAttribute(Attachment.class,
attachment -> attachment.getSpec().getPolicyName()))
);
indexSpecs.add(new IndexSpec()
.setName("spec.groupName")
.setIndexFunc(simpleAttribute(Attachment.class, attachment -> {
var group = attachment.getSpec().getGroupName();
return StringUtils.isBlank(group) ? null : group;
}))
);
indexSpecs.add(new IndexSpec()
.setName("spec.ownerName")
.setIndexFunc(simpleAttribute(Attachment.class,
attachment -> attachment.getSpec().getOwnerName()))
);
indexSpecs.add(new IndexSpec()
.setName("spec.size")
.setIndexFunc(simpleAttribute(Attachment.class,
attachment -> {
var size = attachment.getSpec().getSize();
return size != null ? size.toString() : null;
}))
);
});
schemeManager.register(PolicyTemplate.class); schemeManager.register(PolicyTemplate.class);
// metrics.halo.run // metrics.halo.run
schemeManager.register(Counter.class); schemeManager.register(Counter.class);

View File

@ -1,10 +1,6 @@
package run.halo.app.core.extension.attachment.endpoint; package run.halo.app.core.extension.attachment.endpoint;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.same; import static org.mockito.ArgumentMatchers.same;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
@ -17,32 +13,28 @@ import static org.springframework.security.test.web.reactive.server.SecurityMock
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Predicate;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.data.domain.Sort;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.client.MultipartBodyBuilder; import org.springframework.http.client.MultipartBodyBuilder;
import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
import org.springframework.mock.web.reactive.function.server.MockServerRequest;
import org.springframework.mock.web.server.MockServerWebExchange;
import org.springframework.test.web.reactive.server.WebTestClient; import org.springframework.test.web.reactive.server.WebTestClient;
import org.springframework.web.reactive.function.BodyInserters; import org.springframework.web.reactive.function.BodyInserters;
import reactor.core.publisher.Flux; import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import run.halo.app.core.extension.attachment.Attachment; import run.halo.app.core.extension.attachment.Attachment;
import run.halo.app.core.extension.attachment.Attachment.AttachmentSpec;
import run.halo.app.core.extension.attachment.Group; import run.halo.app.core.extension.attachment.Group;
import run.halo.app.core.extension.attachment.Policy; import run.halo.app.core.extension.attachment.Policy;
import run.halo.app.core.extension.attachment.Policy.PolicySpec; import run.halo.app.core.extension.attachment.Policy.PolicySpec;
import run.halo.app.core.extension.attachment.endpoint.AttachmentEndpoint.SearchRequest;
import run.halo.app.core.extension.service.impl.DefaultAttachmentService; import run.halo.app.core.extension.service.impl.DefaultAttachmentService;
import run.halo.app.extension.ConfigMap; import run.halo.app.extension.ConfigMap;
import run.halo.app.extension.ListResult; import run.halo.app.extension.ListResult;
import run.halo.app.extension.Metadata; import run.halo.app.extension.Metadata;
import run.halo.app.extension.PageRequest;
import run.halo.app.extension.ReactiveExtensionClient; import run.halo.app.extension.ReactiveExtensionClient;
import run.halo.app.plugin.ExtensionComponentsFinder; import run.halo.app.plugin.ExtensionComponentsFinder;
@ -241,10 +233,10 @@ class AttachmentEndpointTest {
@Test @Test
void shouldListUngroupedAttachments() { void shouldListUngroupedAttachments() {
when(client.list(eq(Group.class), any(), any())) when(client.listAll(eq(Group.class), any(), any(Sort.class)))
.thenReturn(Flux.empty()); .thenReturn(Flux.empty());
when(client.list(same(Attachment.class), any(), any(), anyInt(), anyInt())) when(client.listBy(same(Attachment.class), any(), any(PageRequest.class)))
.thenReturn(Mono.just(ListResult.emptyResult())); .thenReturn(Mono.just(ListResult.emptyResult()));
webClient webClient
@ -256,35 +248,12 @@ class AttachmentEndpointTest {
.jsonPath("items.length()").isEqualTo(0); .jsonPath("items.length()").isEqualTo(0);
} }
@Test
void shouldFilterWithUngrouped() {
var httpRequest = MockServerHttpRequest.get("/attachments")
.build();
var exchange = new MockServerWebExchange.Builder(httpRequest)
.build();
MockServerRequest request = MockServerRequest.builder()
.queryParam("ungrouped", "true")
.queryParam("group", "halo")
.exchange(exchange)
.build();
var searchRequest = new SearchRequest(request);
var pred = searchRequest.toPredicate();
var attachment = new Attachment();
var spec = new AttachmentSpec();
attachment.setSpec(spec);
assertTrue(pred.test(attachment));
spec.setGroupName("halo");
assertFalse(pred.test(attachment));
}
@Test @Test
void searchAttachmentWhenGroupIsEmpty() { void searchAttachmentWhenGroupIsEmpty() {
when(client.list(eq(Group.class), any(), any())) when(client.listAll(eq(Group.class), any(), any(Sort.class)))
.thenReturn(Flux.empty()); .thenReturn(Flux.empty());
when(client.list(eq(Attachment.class), any(), any(), anyInt(), anyInt())) when(client.listBy(eq(Attachment.class), any(), any(PageRequest.class)))
.thenReturn(Mono.empty()); .thenReturn(Mono.empty());
webClient webClient
@ -293,32 +262,7 @@ class AttachmentEndpointTest {
.exchange() .exchange()
.expectStatus().isOk(); .expectStatus().isOk();
verify(client).list(eq(Attachment.class), any(), any(), anyInt(), anyInt()); verify(client).listBy(eq(Attachment.class), any(), any(PageRequest.class));
} }
} }
@Test
void visibleGroupPredicate() {
Predicate<Attachment> noHiddenGroupPredicate =
AttachmentEndpoint.visibleGroupPredicate(List.of());
Attachment attachment = mock(Attachment.class);
AttachmentSpec spec = mock(AttachmentSpec.class);
when(attachment.getSpec()).thenReturn(spec);
when(spec.getGroupName()).thenReturn("");
assertThat(noHiddenGroupPredicate.test(attachment)).isTrue();
when(spec.getGroupName()).thenReturn("test");
assertThat(noHiddenGroupPredicate.test(attachment)).isTrue();
Predicate<Attachment> hasHiddenGroupPredicate =
AttachmentEndpoint.visibleGroupPredicate(List.of("hidden-group"));
when(spec.getGroupName()).thenReturn("fake");
assertThat(hasHiddenGroupPredicate.test(attachment)).isTrue();
when(spec.getGroupName()).thenReturn("hidden-group");
assertThat(hasHiddenGroupPredicate.test(attachment)).isFalse();
}
} }

View File

@ -364,23 +364,23 @@ onMounted(() => {
label: t( label: t(
'core.attachment.filters.sort.items.create_time_desc' 'core.attachment.filters.sort.items.create_time_desc'
), ),
value: 'creationTimestamp,desc', value: 'metadata.creationTimestamp,desc',
}, },
{ {
label: t( label: t(
'core.attachment.filters.sort.items.create_time_asc' 'core.attachment.filters.sort.items.create_time_asc'
), ),
value: 'creationTimestamp,asc', value: 'metadata.creationTimestamp,asc',
}, },
{ {
label: t( label: t(
'core.attachment.filters.sort.items.size_desc' 'core.attachment.filters.sort.items.size_desc'
), ),
value: 'size,desc', value: 'spec.size,desc',
}, },
{ {
label: t('core.attachment.filters.sort.items.size_asc'), label: t('core.attachment.filters.sort.items.size_asc'),
value: 'size,asc', value: 'spec.size,asc',
}, },
]" ]"
/> />

View File

@ -102,7 +102,7 @@ const handleDelete = (group: Group) => {
onConfirm: async () => { onConfirm: async () => {
// TODO: // TODO:
const { data } = await apiClient.attachment.searchAttachments({ const { data } = await apiClient.attachment.searchAttachments({
group: group.metadata.name, fieldSelector: [`spec.groupName=${group.metadata.name}`],
page: 0, page: 0,
size: 0, size: 0,
}); });
@ -151,7 +151,7 @@ const handleDeleteWithAttachments = (group: Group) => {
onConfirm: async () => { onConfirm: async () => {
// TODO: // TODO:
const { data } = await apiClient.attachment.searchAttachments({ const { data } = await apiClient.attachment.searchAttachments({
group: group.metadata.name, fieldSelector: [`spec.groupName=${group.metadata.name}`],
page: 0, page: 0,
size: 0, size: 0,
}); });

View File

@ -78,7 +78,7 @@ const handleOpenCreateNewPolicyModal = (policyTemplate: PolicyTemplate) => {
const handleDelete = async (policy: Policy) => { const handleDelete = async (policy: Policy) => {
const { data } = await apiClient.attachment.searchAttachments({ const { data } = await apiClient.attachment.searchAttachments({
policy: policy.metadata.name, fieldSelector: [`spec.policyName=${policy.metadata.name}`],
}); });
if (data.total > 0) { if (data.total > 0) {

View File

@ -50,14 +50,28 @@ export function useAttachmentControl(filterOptions: {
const { data, isLoading, isFetching, refetch } = useQuery<Attachment[]>({ const { data, isLoading, isFetching, refetch } = useQuery<Attachment[]>({
queryKey: ["attachments", policy, keyword, group, user, page, size, sort], queryKey: ["attachments", policy, keyword, group, user, page, size, sort],
queryFn: async () => { queryFn: async () => {
const isUnGrouped = group?.value?.metadata.name === "ungrouped";
const fieldSelectorMap: Record<string, string | undefined> = {
"spec.policyName": policy?.value?.metadata.name,
"spec.ownerName": user?.value,
"spec.groupName": isUnGrouped ? undefined : group?.value?.metadata.name,
};
const fieldSelector = Object.entries(fieldSelectorMap)
.map(([key, value]) => {
if (value) {
return `${key}=${value}`;
}
})
.filter(Boolean) as string[];
const { data } = await apiClient.attachment.searchAttachments({ const { data } = await apiClient.attachment.searchAttachments({
policy: policy?.value?.metadata.name, fieldSelector,
displayName: keyword?.value, page: page.value,
group: group?.value?.metadata.name, size: size.value,
ungrouped: group?.value?.metadata.name === "ungrouped", ungrouped: isUnGrouped,
uploadedBy: user?.value, keyword: keyword?.value,
page: page?.value,
size: size?.value,
sort: [sort?.value as string].filter(Boolean), sort: [sort?.value as string].filter(Boolean),
}); });

View File

@ -50,30 +50,24 @@ export const ApiConsoleHaloRunV1alpha1AttachmentApiAxiosParamCreator =
return { return {
/** /**
* *
* @param {string} [displayName] Display name of attachment
* @param {Array<string>} [fieldSelector] Field selector for filtering. * @param {Array<string>} [fieldSelector] Field selector for filtering.
* @param {string} [group] Name of group * @param {string} [keyword] Keyword for searching.
* @param {Array<string>} [labelSelector] Label selector for filtering. * @param {Array<string>} [labelSelector] Label selector for filtering.
* @param {number} [page] The page number. Zero indicates no page. * @param {number} [page] The page number. Zero indicates no page.
* @param {string} [policy] Name of policy
* @param {number} [size] Size of one page. Zero indicates no limit. * @param {number} [size] Size of one page. Zero indicates no limit.
* @param {Array<string>} [sort] Sort property and direction of the list result. Supported fields: creationTimestamp, size * @param {Array<string>} [sort] Sort property and direction of the list result. Supported fields: creationTimestamp, size
* @param {boolean} [ungrouped] Filter attachments without group. This parameter will ignore group parameter. * @param {boolean} [ungrouped] Filter attachments without group. This parameter will ignore group parameter.
* @param {string} [uploadedBy] Name of user who uploaded the attachment
* @param {*} [options] Override http request option. * @param {*} [options] Override http request option.
* @throws {RequiredError} * @throws {RequiredError}
*/ */
searchAttachments: async ( searchAttachments: async (
displayName?: string,
fieldSelector?: Array<string>, fieldSelector?: Array<string>,
group?: string, keyword?: string,
labelSelector?: Array<string>, labelSelector?: Array<string>,
page?: number, page?: number,
policy?: string,
size?: number, size?: number,
sort?: Array<string>, sort?: Array<string>,
ungrouped?: boolean, ungrouped?: boolean,
uploadedBy?: string,
options: AxiosRequestConfig = {} options: AxiosRequestConfig = {}
): Promise<RequestArgs> => { ): Promise<RequestArgs> => {
const localVarPath = `/apis/api.console.halo.run/v1alpha1/attachments`; const localVarPath = `/apis/api.console.halo.run/v1alpha1/attachments`;
@ -100,16 +94,12 @@ export const ApiConsoleHaloRunV1alpha1AttachmentApiAxiosParamCreator =
// http bearer authentication required // http bearer authentication required
await setBearerAuthToObject(localVarHeaderParameter, configuration); await setBearerAuthToObject(localVarHeaderParameter, configuration);
if (displayName !== undefined) {
localVarQueryParameter["displayName"] = displayName;
}
if (fieldSelector) { if (fieldSelector) {
localVarQueryParameter["fieldSelector"] = fieldSelector; localVarQueryParameter["fieldSelector"] = fieldSelector;
} }
if (group !== undefined) { if (keyword !== undefined) {
localVarQueryParameter["group"] = group; localVarQueryParameter["keyword"] = keyword;
} }
if (labelSelector) { if (labelSelector) {
@ -120,10 +110,6 @@ export const ApiConsoleHaloRunV1alpha1AttachmentApiAxiosParamCreator =
localVarQueryParameter["page"] = page; localVarQueryParameter["page"] = page;
} }
if (policy !== undefined) {
localVarQueryParameter["policy"] = policy;
}
if (size !== undefined) { if (size !== undefined) {
localVarQueryParameter["size"] = size; localVarQueryParameter["size"] = size;
} }
@ -136,10 +122,6 @@ export const ApiConsoleHaloRunV1alpha1AttachmentApiAxiosParamCreator =
localVarQueryParameter["ungrouped"] = ungrouped; localVarQueryParameter["ungrouped"] = ungrouped;
} }
if (uploadedBy !== undefined) {
localVarQueryParameter["uploadedBy"] = uploadedBy;
}
setSearchParams(localVarUrlObj, localVarQueryParameter); setSearchParams(localVarUrlObj, localVarQueryParameter);
let headersFromBaseOptions = let headersFromBaseOptions =
baseOptions && baseOptions.headers ? baseOptions.headers : {}; baseOptions && baseOptions.headers ? baseOptions.headers : {};
@ -243,46 +225,37 @@ export const ApiConsoleHaloRunV1alpha1AttachmentApiFp = function (
return { return {
/** /**
* *
* @param {string} [displayName] Display name of attachment
* @param {Array<string>} [fieldSelector] Field selector for filtering. * @param {Array<string>} [fieldSelector] Field selector for filtering.
* @param {string} [group] Name of group * @param {string} [keyword] Keyword for searching.
* @param {Array<string>} [labelSelector] Label selector for filtering. * @param {Array<string>} [labelSelector] Label selector for filtering.
* @param {number} [page] The page number. Zero indicates no page. * @param {number} [page] The page number. Zero indicates no page.
* @param {string} [policy] Name of policy
* @param {number} [size] Size of one page. Zero indicates no limit. * @param {number} [size] Size of one page. Zero indicates no limit.
* @param {Array<string>} [sort] Sort property and direction of the list result. Supported fields: creationTimestamp, size * @param {Array<string>} [sort] Sort property and direction of the list result. Supported fields: creationTimestamp, size
* @param {boolean} [ungrouped] Filter attachments without group. This parameter will ignore group parameter. * @param {boolean} [ungrouped] Filter attachments without group. This parameter will ignore group parameter.
* @param {string} [uploadedBy] Name of user who uploaded the attachment
* @param {*} [options] Override http request option. * @param {*} [options] Override http request option.
* @throws {RequiredError} * @throws {RequiredError}
*/ */
async searchAttachments( async searchAttachments(
displayName?: string,
fieldSelector?: Array<string>, fieldSelector?: Array<string>,
group?: string, keyword?: string,
labelSelector?: Array<string>, labelSelector?: Array<string>,
page?: number, page?: number,
policy?: string,
size?: number, size?: number,
sort?: Array<string>, sort?: Array<string>,
ungrouped?: boolean, ungrouped?: boolean,
uploadedBy?: string,
options?: AxiosRequestConfig options?: AxiosRequestConfig
): Promise< ): Promise<
(axios?: AxiosInstance, basePath?: string) => AxiosPromise<AttachmentList> (axios?: AxiosInstance, basePath?: string) => AxiosPromise<AttachmentList>
> { > {
const localVarAxiosArgs = const localVarAxiosArgs =
await localVarAxiosParamCreator.searchAttachments( await localVarAxiosParamCreator.searchAttachments(
displayName,
fieldSelector, fieldSelector,
group, keyword,
labelSelector, labelSelector,
page, page,
policy,
size, size,
sort, sort,
ungrouped, ungrouped,
uploadedBy,
options options
); );
return createRequestFunction( return createRequestFunction(
@ -348,16 +321,13 @@ export const ApiConsoleHaloRunV1alpha1AttachmentApiFactory = function (
): AxiosPromise<AttachmentList> { ): AxiosPromise<AttachmentList> {
return localVarFp return localVarFp
.searchAttachments( .searchAttachments(
requestParameters.displayName,
requestParameters.fieldSelector, requestParameters.fieldSelector,
requestParameters.group, requestParameters.keyword,
requestParameters.labelSelector, requestParameters.labelSelector,
requestParameters.page, requestParameters.page,
requestParameters.policy,
requestParameters.size, requestParameters.size,
requestParameters.sort, requestParameters.sort,
requestParameters.ungrouped, requestParameters.ungrouped,
requestParameters.uploadedBy,
options options
) )
.then((request) => request(axios, basePath)); .then((request) => request(axios, basePath));
@ -390,13 +360,6 @@ export const ApiConsoleHaloRunV1alpha1AttachmentApiFactory = function (
* @interface ApiConsoleHaloRunV1alpha1AttachmentApiSearchAttachmentsRequest * @interface ApiConsoleHaloRunV1alpha1AttachmentApiSearchAttachmentsRequest
*/ */
export interface ApiConsoleHaloRunV1alpha1AttachmentApiSearchAttachmentsRequest { export interface ApiConsoleHaloRunV1alpha1AttachmentApiSearchAttachmentsRequest {
/**
* Display name of attachment
* @type {string}
* @memberof ApiConsoleHaloRunV1alpha1AttachmentApiSearchAttachments
*/
readonly displayName?: string;
/** /**
* Field selector for filtering. * Field selector for filtering.
* @type {Array<string>} * @type {Array<string>}
@ -405,11 +368,11 @@ export interface ApiConsoleHaloRunV1alpha1AttachmentApiSearchAttachmentsRequest
readonly fieldSelector?: Array<string>; readonly fieldSelector?: Array<string>;
/** /**
* Name of group * Keyword for searching.
* @type {string} * @type {string}
* @memberof ApiConsoleHaloRunV1alpha1AttachmentApiSearchAttachments * @memberof ApiConsoleHaloRunV1alpha1AttachmentApiSearchAttachments
*/ */
readonly group?: string; readonly keyword?: string;
/** /**
* Label selector for filtering. * Label selector for filtering.
@ -425,13 +388,6 @@ export interface ApiConsoleHaloRunV1alpha1AttachmentApiSearchAttachmentsRequest
*/ */
readonly page?: number; readonly page?: number;
/**
* Name of policy
* @type {string}
* @memberof ApiConsoleHaloRunV1alpha1AttachmentApiSearchAttachments
*/
readonly policy?: string;
/** /**
* Size of one page. Zero indicates no limit. * Size of one page. Zero indicates no limit.
* @type {number} * @type {number}
@ -452,13 +408,6 @@ export interface ApiConsoleHaloRunV1alpha1AttachmentApiSearchAttachmentsRequest
* @memberof ApiConsoleHaloRunV1alpha1AttachmentApiSearchAttachments * @memberof ApiConsoleHaloRunV1alpha1AttachmentApiSearchAttachments
*/ */
readonly ungrouped?: boolean; readonly ungrouped?: boolean;
/**
* Name of user who uploaded the attachment
* @type {string}
* @memberof ApiConsoleHaloRunV1alpha1AttachmentApiSearchAttachments
*/
readonly uploadedBy?: string;
} }
/** /**
@ -509,16 +458,13 @@ export class ApiConsoleHaloRunV1alpha1AttachmentApi extends BaseAPI {
) { ) {
return ApiConsoleHaloRunV1alpha1AttachmentApiFp(this.configuration) return ApiConsoleHaloRunV1alpha1AttachmentApiFp(this.configuration)
.searchAttachments( .searchAttachments(
requestParameters.displayName,
requestParameters.fieldSelector, requestParameters.fieldSelector,
requestParameters.group, requestParameters.keyword,
requestParameters.labelSelector, requestParameters.labelSelector,
requestParameters.page, requestParameters.page,
requestParameters.policy,
requestParameters.size, requestParameters.size,
requestParameters.sort, requestParameters.sort,
requestParameters.ungrouped, requestParameters.ungrouped,
requestParameters.uploadedBy,
options options
) )
.then((request) => request(this.axios, this.basePath)); .then((request) => request(this.axios, this.basePath));