Skip to content

Commit

Permalink
MODLISTS-90: Temporarily retrieve contents for all fields in entity t…
Browse files Browse the repository at this point in the history
…ype definition
  • Loading branch information
bvsharp committed Mar 13, 2024
1 parent ba30618 commit 43a1573
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 117 deletions.
4 changes: 2 additions & 2 deletions src/main/java/org/folio/list/controller/ListController.java
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,8 @@ public ResponseEntity<ListRefreshDTO> performRefresh(UUID id) {
}

@Override
public ResponseEntity<ResultsetPage> getListContents(UUID id, Integer offset, Integer size) {
return listService.getListContents(id, offset, size)
public ResponseEntity<ResultsetPage> getListContents(UUID id, List<String> fields, Integer offset, Integer size) {
return listService.getListContents(id, fields, offset, size)
.map(ResponseEntity::ok)
.orElseThrow(() -> new ListNotFoundException(id, ListActions.READ));
}
Expand Down
24 changes: 8 additions & 16 deletions src/main/java/org/folio/list/services/ListService.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import lombok.extern.log4j.Log4j2;

import org.apache.commons.collections4.CollectionUtils;
import org.folio.fql.model.field.FqlField;
import org.folio.fql.service.FqlService;
import org.folio.fql.model.Fql;
import org.folio.list.domain.ListContent;
Expand Down Expand Up @@ -48,7 +47,6 @@

import java.time.OffsetDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.toMap;
import static java.util.Objects.nonNull;
Expand Down Expand Up @@ -209,13 +207,13 @@ public Optional<ListRefreshDTO> performRefresh(UUID listId) {
});
}

public Optional<ResultsetPage> getListContents(UUID listId, Integer offset, Integer size) {
public Optional<ResultsetPage> getListContents(UUID listId, List<String> fields, Integer offset, Integer size) {
log.info("Attempting to get contents for list with listId {}, tenantId {}, offset {}, size {}",
listId, executionContext.getTenantId(), offset, size);
return listRepository.findByIdAndIsDeletedFalse(listId)
.map(list -> {
validationService.assertSharedOrOwnedByUser(list, ListActions.READ);
return getListContents(list, offset, size);
return getListContents(list, fields, offset, size);
});
}

Expand Down Expand Up @@ -272,19 +270,13 @@ private void deleteListAndContents(ListEntity list) {
listRepository.save(list.withIsDeleted(true));
}

private ResultsetPage getListContents(ListEntity list, Integer offset, Integer limit) {
List<Map<String, Object>> sortedContents = List.of();
List<String> fields = list.getFields();
if (CollectionUtils.isEmpty(fields)) {
Fql fql = fqlService.getFql(list.getFqlQuery());
fields = fqlService.getFqlFields(fql)
.stream()
.map(FqlField::getColumnName)
.collect(Collectors.toList());
}
if (!fields.contains("id")) {
fields.add("id");
private ResultsetPage getListContents(ListEntity list, List<String> fields, Integer offset, Integer limit) {
// If fields are not provided, retrieve all fields from the entity type definition
if (isEmpty(fields)) {
EntityType entityType = getEntityType(list.getEntityTypeId());
fields = getFieldsFromEntityType(entityType);
}
List<Map<String, Object>> sortedContents = List.of();
if (list.isRefreshed()) {
List<List<String>> contentIds = listContentsRepository.getContents(list.getId(), list.getSuccessRefresh().getId(), new OffsetRequest(offset, limit))
.stream()
Expand Down
9 changes: 9 additions & 0 deletions src/main/resources/swagger.api/list.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,15 @@ paths:
description: gets the list contents (if exists).
parameters:
- $ref: '#/components/parameters/id'
- name: fields
in: query
description: List of fields to retrieve content for
required: false
schema:
type: array
items:
type:
string
- name: offset
in: query
description: Offset to start retrieving items from
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,15 @@ void shouldGetListContents() throws Exception {
UUID listId = UUID.randomUUID();
Integer offset = 0;
Integer size = 2;
var requestBuilder = get("/lists/" + listId + "/contents?size=2&offset=0")
List<String> fields = List.of("key1", "key2", "key3", "key4");
var requestBuilder = get("/lists/" + listId + "/contents?size=2&offset=0&fields=key1,key2,key3,key4")
.contentType(APPLICATION_JSON)
.header(XOkapiHeaders.TENANT, listId);
List<Map<String, Object>> expectedList = List.of(
Map.of("key1", "value1", "key2", "value2"),
Map.of("key3", "value3", "key4", "value4"));
Optional<ResultsetPage> expectedContent = Optional.of(new ResultsetPage().content(expectedList).totalRecords(expectedList.size()));
when(listService.getListContents(listId, offset, size)).thenReturn(expectedContent);
when(listService.getListContents(listId, fields, offset, size)).thenReturn(expectedContent);
mockMvc.perform(requestBuilder)
.andExpect(status().isOk())
.andExpect(jsonPath("$.content[0]", is(expectedList.get(0))))
Expand All @@ -56,11 +57,12 @@ void getListContentsShouldReturnHttp404WhenListNotFound() throws Exception {
UUID listId = UUID.randomUUID();
Integer offset = 0;
Integer size = 0;
var requestBuilder = get("/lists/" + listId + "/contents?size=0&offset=0")
List<String> fields = List.of("key1");
var requestBuilder = get("/lists/" + listId + "/contents?size=0&offset=0&fields=key1")
.contentType(APPLICATION_JSON)
.header(XOkapiHeaders.TENANT, listId);
Optional<ResultsetPage> expectedContent = Optional.empty();
when(listService.getListContents(listId, offset, size)).thenReturn(expectedContent);
when(listService.getListContents(listId, fields, offset, size)).thenReturn(expectedContent);
mockMvc.perform(requestBuilder)
.andExpect(status().isNotFound())
.andExpect(jsonPath("$.code", is("read-list.not.found")));
Expand All @@ -73,12 +75,13 @@ void shouldReturnHttp401ForAccessingPrivateListContents() throws Exception {
listEntity.setId(listId);
Integer offset = 0;
Integer size = 0;
List<String> fields = List.of("key1");

var requestBuilder = get("/lists/" + listId + "/contents?size=0&offset=0")
var requestBuilder = get("/lists/" + listId + "/contents?size=0&offset=0&fields=key1")
.contentType(APPLICATION_JSON)
.header(XOkapiHeaders.TENANT, listId);

when(listService.getListContents(listId, offset, size))
when(listService.getListContents(listId, fields, offset, size))
.thenThrow(new PrivateListOfAnotherUserException(listEntity, ListActions.READ));

mockMvc.perform(requestBuilder)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,20 @@
import org.folio.list.exception.PrivateListOfAnotherUserException;
import org.folio.list.repository.ListContentsRepository;
import org.folio.list.repository.ListRepository;
import org.folio.list.rest.EntityTypeClient;
import org.folio.list.rest.QueryClient;
import org.folio.list.services.ListActions;
import org.folio.list.services.ListService;
import org.folio.list.services.ListValidationService;
import org.folio.list.utils.TestDataFixture;
import org.folio.querytool.domain.dto.ContentsRequest;
import org.folio.querytool.domain.dto.EntityType;
import org.folio.querytool.domain.dto.EntityTypeColumn;
import org.folio.querytool.domain.dto.ResultsetPage;
import org.folio.spring.FolioExecutionContext;
import org.folio.spring.data.OffsetRequest;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
Expand Down Expand Up @@ -46,6 +50,8 @@ class ListServiceGetListContentsTest {
private FqlService fqlService;
@Mock
private QueryClient queryClient;
@Mock
private EntityTypeClient entityTypeClient;
@InjectMocks
private ListService listService;

Expand Down Expand Up @@ -90,64 +96,23 @@ void shouldReturnValidContentPage() {
when(listRepository.findByIdAndIsDeletedFalse(listId)).thenReturn(Optional.of(expectedEntity));
when(listContentsRepository.getContents(listId, successRefresh.getId(), new OffsetRequest(offset, size))).thenReturn(listContents);
when(queryClient.getContents(contentsRequest)).thenReturn(expectedList);
Optional<ResultsetPage> actualContent = listService.getListContents(listId, offset, size);
Optional<ResultsetPage> actualContent = listService.getListContents(listId, fields, offset, size);
assertThat(actualContent).isEqualTo(expectedContent);
}

@Test
void shouldReturnRequestedFieldsPlusIdsIfIdsNotIncludedInFields() {
void shouldGetFieldsFromEntityTypeIfNotProvided() {
String tenantId = "tenant_01";
UUID entityTypeId = UUID.randomUUID();
UUID listId = UUID.randomUUID();
List<List<String>> contentIds = List.of(
List.of(UUID.randomUUID().toString()),
List.of(UUID.randomUUID().toString())
);
int offset = 0;
int size = 2;
int contentVersion = 2;
List<String> fields = new ArrayList<>(List.of("key1", "key2"));
ContentsRequest contentsRequest = new ContentsRequest().entityTypeId(entityTypeId)
.fields(fields)
.ids(contentIds);
List<Map<String, Object>> expectedList = List.of(
Map.of("id", contentIds.get(0), "key1", "value1", "key2", "value2"),
Map.of("id", contentIds.get(1), "key1", "value3", "key2", "value4")
);
Optional<ResultsetPage> expectedContent = Optional.of(new ResultsetPage().content(expectedList).totalRecords(expectedList.size()));

List<ListContent> listContents = contentIds.stream().map(id -> {
ListContent content = new ListContent();
content.setContentId(id);
return content;
}).toList();

ListEntity expectedEntity = new ListEntity();
ListRefreshDetails successRefresh = new ListRefreshDetails();
successRefresh.setContentVersion(contentVersion);
expectedEntity.setSuccessRefresh(successRefresh);
expectedEntity.setEntityTypeId(entityTypeId);
expectedEntity.setId(listId);
expectedEntity.setFields(fields);
expectedEntity.getSuccessRefresh().setRecordsCount(2);

when(executionContext.getTenantId()).thenReturn(tenantId);
when(listRepository.findByIdAndIsDeletedFalse(listId)).thenReturn(Optional.of(expectedEntity));
when(listContentsRepository.getContents(listId, successRefresh.getId(), new OffsetRequest(offset, size))).thenReturn(listContents);
when(queryClient.getContents(contentsRequest)).thenReturn(expectedList);
Optional<ResultsetPage> actualContent = listService.getListContents(listId, offset, size);
assertThat(actualContent).isEqualTo(expectedContent);
}

@Test
void shouldReturnContentPageWithIdsForEmptyFields() {
String tenantId = "tenant_01";
UUID entityTypeId = UUID.randomUUID();
UUID listId = UUID.randomUUID();
List<List<String>> contentIds = List.of(
List.of(UUID.randomUUID().toString()),
List.of(UUID.randomUUID().toString())
List<EntityTypeColumn> columns = List.of(
new EntityTypeColumn().name("id")
);
EntityType entityType = new EntityType().name("entity-type").columns(columns);
int offset = 0;
int size = 2;
int contentVersion = 2;
Expand Down Expand Up @@ -177,74 +142,33 @@ void shouldReturnContentPageWithIdsForEmptyFields() {
expectedEntity.getSuccessRefresh().setRecordsCount(2);

when(executionContext.getTenantId()).thenReturn(tenantId);
when(entityTypeClient.getEntityType(entityTypeId)).thenReturn(entityType);
when(listRepository.findByIdAndIsDeletedFalse(listId)).thenReturn(Optional.of(expectedEntity));
when(listContentsRepository.getContents(listId, successRefresh.getId(), new OffsetRequest(offset, size))).thenReturn(listContents);
when(queryClient.getContents(contentsRequest)).thenReturn(expectedList);
Optional<ResultsetPage> actualContent = listService.getListContents(listId, offset, size);
assertThat(actualContent).isEqualTo(expectedContent);
}

@Test
void shouldReturnContentPageWithIdsForNullFields() {
String tenantId = "tenant_01";
UUID entityTypeId = UUID.randomUUID();
UUID listId = UUID.randomUUID();
List<List<String>> contentIds = List.of(
List.of(UUID.randomUUID().toString()),
List.of(UUID.randomUUID().toString())
);
int offset = 0;
int size = 2;
int contentVersion = 2;
List<String> fields = List.of("id");
ContentsRequest contentsRequest = new ContentsRequest().entityTypeId(entityTypeId)
.fields(fields)
.ids(contentIds);
List<Map<String, Object>> expectedList = List.of(
Map.of("id", contentIds.get(0)),
Map.of("id", contentIds.get(1))
);
Optional<ResultsetPage> expectedContent = Optional.of(new ResultsetPage().content(expectedList).totalRecords(expectedList.size()));

List<ListContent> listContents = contentIds.stream().map(id -> {
ListContent content = new ListContent();
content.setContentId(id);
return content;
}).toList();

ListEntity expectedEntity = new ListEntity();
ListRefreshDetails successRefresh = new ListRefreshDetails();
successRefresh.setContentVersion(contentVersion);
expectedEntity.setSuccessRefresh(successRefresh);
expectedEntity.setEntityTypeId(entityTypeId);
expectedEntity.setId(listId);
expectedEntity.getSuccessRefresh().setRecordsCount(2);

when(executionContext.getTenantId()).thenReturn(tenantId);
when(listRepository.findByIdAndIsDeletedFalse(listId)).thenReturn(Optional.of(expectedEntity));
when(listContentsRepository.getContents(listId, successRefresh.getId(), new OffsetRequest(offset, size))).thenReturn(listContents);
when(queryClient.getContents(contentsRequest)).thenReturn(expectedList);
Optional<ResultsetPage> actualContent = listService.getListContents(listId, offset, size);
Optional<ResultsetPage> actualContent = listService.getListContents(listId, fields, offset, size);
assertThat(actualContent).isEqualTo(expectedContent);
}

@Test
void shouldReturnEmptyContentPageIfNotRefreshed() {
UUID listId = UUID.randomUUID();
List<String> fields = List.of("id", "key1", "key2");
Optional<ResultsetPage> emptyContent = Optional.of(new ResultsetPage().content(List.of()).totalRecords(0));
ListEntity neverRefreshedList = TestDataFixture.getNeverRefreshedListEntity();
when(listRepository.findByIdAndIsDeletedFalse(listId)).thenReturn(Optional.of(neverRefreshedList));
Optional<ResultsetPage> actualContent = listService.getListContents(listId, 0, 100);
Optional<ResultsetPage> actualContent = listService.getListContents(listId, fields, 0, 100);
assertThat(actualContent).isEqualTo(emptyContent);
}

@Test
void shouldThrowExceptionWhenValidationFailed() {
UUID listId = UUID.randomUUID();
ListEntity listEntity = TestDataFixture.getNeverRefreshedListEntity();
List<String> fields = List.of("id", "key1", "key2");
when(listRepository.findByIdAndIsDeletedFalse(listId)).thenReturn(Optional.of(listEntity));
doThrow(new PrivateListOfAnotherUserException(listEntity, ListActions.READ))
.when(listValidationService).assertSharedOrOwnedByUser(listEntity, ListActions.READ);
Assertions.assertThrows(PrivateListOfAnotherUserException.class, () -> listService.getListContents(listId, 0, 100));
Assertions.assertThrows(PrivateListOfAnotherUserException.class, () -> listService.getListContents(listId, fields, 0, 100));
}
}

0 comments on commit 43a1573

Please sign in to comment.