From 5c22df8e77f70ed4a29a75fdbec75c2b94df9422 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Saracca?= Date: Thu, 5 Dec 2024 17:39:15 -0300 Subject: [PATCH 1/9] feat: add show_facets as default param and use search params object --- .../models/GetCollectionItemsQueryParams.ts | 10 ++++ .../repositories/CollectionsRepository.ts | 59 +++++++++---------- src/core/infra/repositories/ApiRepository.ts | 2 +- .../infra/repositories/apiConfigBuilders.ts | 2 +- .../collections/CollectionsRepository.test.ts | 56 +++++++++++++----- 5 files changed, 80 insertions(+), 49 deletions(-) create mode 100644 src/collections/domain/models/GetCollectionItemsQueryParams.ts diff --git a/src/collections/domain/models/GetCollectionItemsQueryParams.ts b/src/collections/domain/models/GetCollectionItemsQueryParams.ts new file mode 100644 index 00000000..607d18f5 --- /dev/null +++ b/src/collections/domain/models/GetCollectionItemsQueryParams.ts @@ -0,0 +1,10 @@ +export enum GetCollectionItemsQueryParams { + QUERY = 'q', + SHOW_FACETS = 'show_facets', + SORT = 'sort', + ORDER = 'order', + SUBTREE = 'subtree', + PER_PAGE = 'per_page', + START = 'start', + TYPE = 'type' +} diff --git a/src/collections/infra/repositories/CollectionsRepository.ts b/src/collections/infra/repositories/CollectionsRepository.ts index 8e3754a7..a3c588e4 100644 --- a/src/collections/infra/repositories/CollectionsRepository.ts +++ b/src/collections/infra/repositories/CollectionsRepository.ts @@ -13,6 +13,7 @@ import { transformCollectionUserPermissionsResponseToCollectionUserPermissions } import { CollectionItemSubset } from '../../domain/models/CollectionItemSubset' import { CollectionSearchCriteria } from '../../domain/models/CollectionSearchCriteria' import { CollectionItemType } from '../../domain/models/CollectionItemType' +import { GetCollectionItemsQueryParams } from '../../domain/models/GetCollectionItemsQueryParams' export interface NewCollectionRequestPayload { alias: string @@ -40,14 +41,6 @@ export interface NewCollectionInputLevelRequestPayload { required: boolean } -export interface GetCollectionItemsQueryParams { - q: string - subtree?: string - per_page?: number - start?: number - type?: string -} - export class CollectionsRepository extends ApiRepository implements ICollectionsRepository { private readonly collectionsResourceName: string = 'dataverses' @@ -119,37 +112,30 @@ export class CollectionsRepository extends ApiRepository implements ICollections offset?: number, collectionSearchCriteria?: CollectionSearchCriteria ): Promise { - const queryParams: GetCollectionItemsQueryParams = { - q: '*' - } + const queryParams = new URLSearchParams({ + [GetCollectionItemsQueryParams.QUERY]: '*', + [GetCollectionItemsQueryParams.SHOW_FACETS]: 'true', + [GetCollectionItemsQueryParams.SORT]: 'date', + [GetCollectionItemsQueryParams.ORDER]: 'desc' + }) + if (collectionId) { - queryParams.subtree = collectionId + queryParams.set(GetCollectionItemsQueryParams.SUBTREE, collectionId) } + if (limit) { - queryParams.per_page = limit + queryParams.set(GetCollectionItemsQueryParams.PER_PAGE, limit.toString()) } + if (offset) { - queryParams.start = offset + queryParams.set(GetCollectionItemsQueryParams.START, offset.toString()) } + if (collectionSearchCriteria) { this.applyCollectionSearchCriteriaToQueryParams(queryParams, collectionSearchCriteria) } - let url = '/search?sort=date&order=desc' - - if (collectionSearchCriteria?.itemTypes) { - const itemTypesQueryString = collectionSearchCriteria.itemTypes - .map((itemType: CollectionItemType) => { - const mappedItemType = - itemType === CollectionItemType.COLLECTION ? 'dataverse' : itemType.toString() - return `type=${mappedItemType}` - }) - .join('&') - - url += `&${itemTypesQueryString}` - } - - return this.doGet(url, true, queryParams) + return this.doGet('/search', true, queryParams) .then((response) => transformCollectionItemsResponseToCollectionItemSubset(response)) .catch((error) => { throw error @@ -201,11 +187,22 @@ export class CollectionsRepository extends ApiRepository implements ICollections } private applyCollectionSearchCriteriaToQueryParams( - queryParams: GetCollectionItemsQueryParams, + queryParams: URLSearchParams, collectionSearchCriteria: CollectionSearchCriteria ) { if (collectionSearchCriteria.searchText) { - queryParams.q = encodeURIComponent(collectionSearchCriteria.searchText) + queryParams.set( + GetCollectionItemsQueryParams.QUERY, + encodeURIComponent(collectionSearchCriteria.searchText) + ) + } + + if (collectionSearchCriteria?.itemTypes) { + collectionSearchCriteria.itemTypes.forEach((itemType) => { + const mappedItemType = itemType === CollectionItemType.COLLECTION ? 'dataverse' : itemType + + queryParams.append(GetCollectionItemsQueryParams.TYPE, mappedItemType) + }) } } } diff --git a/src/core/infra/repositories/ApiRepository.ts b/src/core/infra/repositories/ApiRepository.ts index 980df121..fb0726ac 100644 --- a/src/core/infra/repositories/ApiRepository.ts +++ b/src/core/infra/repositories/ApiRepository.ts @@ -8,7 +8,7 @@ export abstract class ApiRepository { public async doGet( apiEndpoint: string, authRequired = false, - queryParams: object = {} + queryParams: object | URLSearchParams = {} ): Promise { return await axios .get(buildRequestUrl(apiEndpoint), buildRequestConfig(authRequired, queryParams)) diff --git a/src/core/infra/repositories/apiConfigBuilders.ts b/src/core/infra/repositories/apiConfigBuilders.ts index 5886d188..56a3eb54 100644 --- a/src/core/infra/repositories/apiConfigBuilders.ts +++ b/src/core/infra/repositories/apiConfigBuilders.ts @@ -4,7 +4,7 @@ import { ApiConstants } from './ApiConstants' export const buildRequestConfig = ( authRequired: boolean, - queryParams: object, + queryParams: object | URLSearchParams, contentType: string = ApiConstants.CONTENT_TYPE_APPLICATION_JSON, abortSignal?: AbortSignal ): AxiosRequestConfig => { diff --git a/test/unit/collections/CollectionsRepository.test.ts b/test/unit/collections/CollectionsRepository.test.ts index d9c97dd2..cf7693ba 100644 --- a/test/unit/collections/CollectionsRepository.test.ts +++ b/test/unit/collections/CollectionsRepository.test.ts @@ -31,6 +31,7 @@ import { createCollectionPreviewModel, createCollectionPreviewPayload } from '../../testHelpers/collections/collectionPreviewHelper' +import { GetCollectionItemsQueryParams } from '../../../src/collections/domain/models/GetCollectionItemsQueryParams' describe('CollectionsRepository', () => { const sut: CollectionsRepository = new CollectionsRepository() @@ -381,7 +382,7 @@ describe('CollectionsRepository', () => { } } - const expectedApiEndpoint = `${TestConstants.TEST_API_URL}/search?sort=date&order=desc` + const expectedApiEndpoint = `${TestConstants.TEST_API_URL}/search` test('should return item previews when response is successful', async () => { jest.spyOn(axios, 'get').mockResolvedValue(testItemPreviewsResponse) @@ -389,9 +390,12 @@ describe('CollectionsRepository', () => { // API Key auth let actual = await sut.getCollectionItems() - const expectedRequestParams = { - q: '*' - } + const expectedRequestParams = new URLSearchParams({ + [GetCollectionItemsQueryParams.QUERY]: '*', + [GetCollectionItemsQueryParams.SHOW_FACETS]: 'true', + [GetCollectionItemsQueryParams.SORT]: 'date', + [GetCollectionItemsQueryParams.ORDER]: 'desc' + }) const expectedRequestConfigApiKey = { params: expectedRequestParams, @@ -430,11 +434,21 @@ describe('CollectionsRepository', () => { // API Key auth let actual = await sut.getCollectionItems(undefined, testLimit, testOffset) - const expectedRequestParamsWithPagination = { - q: '*', - per_page: testLimit, - start: testOffset - } + const expectedRequestParamsWithPagination = new URLSearchParams({ + [GetCollectionItemsQueryParams.QUERY]: '*', + [GetCollectionItemsQueryParams.SHOW_FACETS]: 'true', + [GetCollectionItemsQueryParams.SORT]: 'date', + [GetCollectionItemsQueryParams.ORDER]: 'desc' + }) + + expectedRequestParamsWithPagination.set( + GetCollectionItemsQueryParams.PER_PAGE, + testLimit.toString() + ) + expectedRequestParamsWithPagination.set( + GetCollectionItemsQueryParams.START, + testOffset.toString() + ) const expectedRequestConfigApiKeyWithPagination = { params: expectedRequestParamsWithPagination, @@ -474,10 +488,17 @@ describe('CollectionsRepository', () => { // API Key auth let actual = await sut.getCollectionItems(testCollectionId, undefined, undefined) - const expectedRequestParamsWithCollectionId = { - q: '*', - subtree: testCollectionId - } + const expectedRequestParamsWithCollectionId = new URLSearchParams({ + [GetCollectionItemsQueryParams.QUERY]: '*', + [GetCollectionItemsQueryParams.SHOW_FACETS]: 'true', + [GetCollectionItemsQueryParams.SORT]: 'date', + [GetCollectionItemsQueryParams.ORDER]: 'desc' + }) + + expectedRequestParamsWithCollectionId.set( + GetCollectionItemsQueryParams.SUBTREE, + testCollectionId + ) const expectedRequestConfigApiKeyWithCollectionId = { params: expectedRequestParamsWithCollectionId, @@ -515,9 +536,12 @@ describe('CollectionsRepository', () => { let error = undefined as unknown as ReadError await sut.getCollectionItems().catch((e) => (error = e)) - const expectedRequestParams = { - q: '*' - } + const expectedRequestParams = new URLSearchParams({ + [GetCollectionItemsQueryParams.QUERY]: '*', + [GetCollectionItemsQueryParams.SHOW_FACETS]: 'true', + [GetCollectionItemsQueryParams.SORT]: 'date', + [GetCollectionItemsQueryParams.ORDER]: 'desc' + }) const expectedRequestConfigApiKey = { params: expectedRequestParams, From a67b55ba6734462fbe5c6dcd9dc795f8360eb9cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Saracca?= Date: Fri, 6 Dec 2024 09:35:36 -0300 Subject: [PATCH 2/9] feat: finish return formatted facets and tests --- .../domain/models/CollectionItemSubset.ts | 15 ++++ .../CollectionItemsFacetsPayload.ts | 6 ++ .../transformers/collectionTransformers.ts | 23 ++++++- .../collections/CollectionsRepository.test.ts | 68 +++++++++++++++++++ .../collectionItemsFacetsHelper.ts | 40 +++++++++++ .../collections/CollectionsRepository.test.ts | 9 ++- .../collections/GetCollectionItems.test.ts | 3 + 7 files changed, 162 insertions(+), 2 deletions(-) create mode 100644 src/collections/infra/repositories/transformers/CollectionItemsFacetsPayload.ts create mode 100644 test/testHelpers/collections/collectionItemsFacetsHelper.ts diff --git a/src/collections/domain/models/CollectionItemSubset.ts b/src/collections/domain/models/CollectionItemSubset.ts index 81631bb8..681b7db5 100644 --- a/src/collections/domain/models/CollectionItemSubset.ts +++ b/src/collections/domain/models/CollectionItemSubset.ts @@ -4,5 +4,20 @@ import { CollectionPreview } from './CollectionPreview' export interface CollectionItemSubset { items: (CollectionPreview | DatasetPreview | FilePreview)[] + facets: CollectionItemsFacet[] totalItemCount: number } + +export interface CollectionItemsFacet { + [key: string]: CollectionItemsFacetValue +} + +interface CollectionItemsFacetValue { + friendly: string + labels: CollectionItemsFacetLabel[] +} + +interface CollectionItemsFacetLabel { + name: string + count: number +} diff --git a/src/collections/infra/repositories/transformers/CollectionItemsFacetsPayload.ts b/src/collections/infra/repositories/transformers/CollectionItemsFacetsPayload.ts new file mode 100644 index 00000000..adb5e74f --- /dev/null +++ b/src/collections/infra/repositories/transformers/CollectionItemsFacetsPayload.ts @@ -0,0 +1,6 @@ +export type CollectionItemsFacetPayload = [Record] + +export interface CollectionItemsFacetPayloadValue { + friendly: string + labels: Record[] +} diff --git a/src/collections/infra/repositories/transformers/collectionTransformers.ts b/src/collections/infra/repositories/transformers/collectionTransformers.ts index 34ffe390..5139e960 100644 --- a/src/collections/infra/repositories/transformers/collectionTransformers.ts +++ b/src/collections/infra/repositories/transformers/collectionTransformers.ts @@ -9,7 +9,10 @@ import { transformPayloadToOwnerNode } from '../../../../core/infra/repositories import { transformHtmlToMarkdown } from '../../../../datasets/infra/repositories/transformers/datasetTransformers' import { CollectionFacet } from '../../../domain/models/CollectionFacet' import { CollectionFacetPayload } from './CollectionFacetPayload' -import { CollectionItemSubset } from '../../../domain/models/CollectionItemSubset' +import { + CollectionItemsFacet, + CollectionItemSubset +} from '../../../domain/models/CollectionItemSubset' import { DatasetPreview } from '../../../../datasets' import { FilePreview } from '../../../../files' import { DatasetPreviewPayload } from '../../../../datasets/infra/repositories/transformers/DatasetPreviewPayload' @@ -21,6 +24,7 @@ import { CollectionPreviewPayload } from './CollectionPreviewPayload' import { CollectionPreview } from '../../../domain/models/CollectionPreview' import { CollectionContact } from '../../../domain/models/CollectionContact' import { CollectionType } from '../../../domain/models/CollectionType' +import { CollectionItemsFacetPayload } from './CollectionItemsFacetsPayload' export const transformCollectionResponseToCollection = (response: AxiosResponse): Collection => { const collectionPayload = response.data.data @@ -79,7 +83,10 @@ export const transformCollectionItemsResponseToCollectionItemSubset = ( ): CollectionItemSubset => { const responseDataPayload = response.data.data const itemsPayload = responseDataPayload.items + const facets = responseDataPayload.facets as CollectionItemsFacetPayload + const items: (DatasetPreview | FilePreview | CollectionPreview)[] = [] + itemsPayload.forEach(function ( itemPayload: CollectionPreviewPayload | DatasetPreviewPayload | FilePreviewPayload ) { @@ -97,8 +104,22 @@ export const transformCollectionItemsResponseToCollectionItemSubset = ( ) } }) + + const transformedFacets: CollectionItemsFacet[] = Object.entries(facets[0]).map( + ([key, facetData]) => ({ + [key]: { + friendly: facetData.friendly, + labels: facetData.labels.map((label: Record) => { + const [name, count] = Object.entries(label)[0] + return { name, count } + }) + } + }) + ) + return { items: items, + facets: transformedFacets, totalItemCount: responseDataPayload.total_count } } diff --git a/test/integration/collections/CollectionsRepository.test.ts b/test/integration/collections/CollectionsRepository.test.ts index e4094730..d77cf0b6 100644 --- a/test/integration/collections/CollectionsRepository.test.ts +++ b/test/integration/collections/CollectionsRepository.test.ts @@ -294,6 +294,68 @@ describe('CollectionsRepository', () => { const expectedFileName = 'test-file-1.txt' const expectedCollectionsName = 'Scientific Research' + //prettier-ignore + const expectedFacetsAll = [ + { + dvCategory: { friendly: 'Dataverse Category', labels: [{ name: 'Laboratory', count: 1 }] } + }, + { + publicationStatus: { friendly: 'Publication Status', labels: [{ name: 'Unpublished', count: 3 },{ name: 'Draft', count: 2 }] } + }, + { + authorName_ss: { friendly: 'Author Name', labels: [{ name: 'Admin, Dataverse', count: 1 },{ name: 'Owner, Dataverse', count: 1 }]} + }, + { + subject_ss: { friendly: 'Subject', labels: [{ name: 'Medicine, Health and Life Sciences', count: 1 }]} + }, + { + fileTypeGroupFacet: { friendly: 'File Type', labels: [{ name: 'Text', count: 1 }] } + }, + { + fileAccess: { friendly: 'Access', labels: [{ name: 'Public', count: 1 }] } + } + ] + //prettier-ignore + const expectedFacetsFromCollectionOnly = [ + { + dvCategory: { friendly: 'Dataverse Category', labels: [{ name: 'Laboratory', count: 1 }] } + }, + { + publicationStatus: { friendly: 'Publication Status', labels: [{ name: 'Unpublished', count: 1 }]} + } + ] + //prettier-ignore + const expectedFacetsFromDatasetOnly = [ + { + publicationStatus: { friendly: 'Publication Status', labels: [{ name: 'Draft', count: 1 },{ name: 'Unpublished', count: 1 }] } + }, + { + authorName_ss: { friendly: 'Author Name', labels: [{ name: 'Admin, Dataverse', count: 1 },{ name: 'Owner, Dataverse', count: 1 }] } + }, + { + subject_ss: { friendly: 'Subject', labels: [{ name: 'Medicine, Health and Life Sciences', count: 1 }] } + } + ] + //prettier-ignore + const expectedFacetsFromFileOnly = [ + { + publicationStatus: { friendly: 'Publication Status', labels: [{ name: 'Draft', count: 1 },{ name: 'Unpublished', count: 1 }] } + }, + { fileTypeGroupFacet: { friendly: 'File Type', labels: [{ name: 'Text', count: 1 }] } }, + { fileAccess: { friendly: 'Access', labels: [{ name: 'Public', count: 1 }] } } + ] + //prettier-ignore + const expectedFacetsFromCollectionAndFile = [ + { + dvCategory: { friendly: 'Dataverse Category', labels: [{ name: 'Laboratory', count: 1 }] } + }, + { + publicationStatus: { friendly: 'Publication Status', labels: [{ name: 'Unpublished', count: 2 },{ name: 'Draft', count: 1 }] } + }, + { fileTypeGroupFacet: { friendly: 'File Type', labels: [{ name: 'Text', count: 1 }] } }, + { fileAccess: { friendly: 'Access', labels: [{ name: 'Public', count: 1 }] } } + ] + expect(actualFilePreview.checksum?.type).toBe('MD5') expect(actualFilePreview.checksum?.value).toBe(expectedFileMd5) expect(actualFilePreview.datasetCitation).toContain(expectedDatasetCitationFragment) @@ -347,6 +409,8 @@ describe('CollectionsRepository', () => { expect(actual.totalItemCount).toBe(3) + expect(actual.facets).toEqual(expectedFacetsAll) + // Test limit and offset actual = await sut.getCollectionItems(testCollectionAlias, 1, 1) expect((actual.items[0] as DatasetPreview).persistentId).toBe(testDatasetIds.persistentId) @@ -413,6 +477,7 @@ describe('CollectionsRepository', () => { expect(actual.items.length).toBe(1) expect(actual.totalItemCount).toBe(1) expect((actual.items[0] as CollectionPreview).name).toBe(expectedCollectionsName) + expect(actual.facets).toEqual(expectedFacetsFromCollectionOnly) // Test type dataset const collectionSearchCriteriaForDatasetType = new CollectionSearchCriteria().withItemTypes([ @@ -427,6 +492,7 @@ describe('CollectionsRepository', () => { expect(actual.items.length).toBe(1) expect(actual.totalItemCount).toBe(1) expect((actual.items[0] as DatasetPreview).title).toBe(expectedDatasetDescription) + expect(actual.facets).toEqual(expectedFacetsFromDatasetOnly) // Test type file const collectionSearchCriteriaForFileType = new CollectionSearchCriteria().withItemTypes([ @@ -441,6 +507,7 @@ describe('CollectionsRepository', () => { expect(actual.items.length).toBe(1) expect(actual.totalItemCount).toBe(1) expect((actual.items[0] as FilePreview).name).toBe(expectedFileName) + expect(actual.facets).toEqual(expectedFacetsFromFileOnly) // Test multiple types const collectionSearchCriteriaForMultiTypes = new CollectionSearchCriteria().withItemTypes([ @@ -457,6 +524,7 @@ describe('CollectionsRepository', () => { expect(actual.totalItemCount).toBe(2) expect((actual.items[0] as FilePreview).name).toBe(expectedFileName) expect((actual.items[1] as CollectionPreview).name).toBe(expectedCollectionsName) + expect(actual.facets).toEqual(expectedFacetsFromCollectionAndFile) }) test('should return error when collection does not exist', async () => { diff --git a/test/testHelpers/collections/collectionItemsFacetsHelper.ts b/test/testHelpers/collections/collectionItemsFacetsHelper.ts new file mode 100644 index 00000000..cb5650b1 --- /dev/null +++ b/test/testHelpers/collections/collectionItemsFacetsHelper.ts @@ -0,0 +1,40 @@ +import { CollectionItemsFacet } from '../../../src/collections/domain/models/CollectionItemSubset' +import { CollectionItemsFacetPayload } from '../../../src/collections/infra/repositories/transformers/CollectionItemsFacetsPayload' + +export const createCollectionItemsFacetsModel = (): CollectionItemsFacet[] => { + return [ + { + facet1: { + friendly: 'Facet 1', + labels: [ + { name: 'Label 1', count: 5 }, + { name: 'Label 2', count: 4 } + ] + } + }, + { + facet2: { + friendly: 'Facet 2', + labels: [ + { name: 'Label 3', count: 8 }, + { name: 'Label 4', count: 9 } + ] + } + } + ] +} + +export const createCollectionItemsFacetsPayload = (): CollectionItemsFacetPayload => { + return [ + { + facet1: { + friendly: 'Facet 1', + labels: [{ 'Label 1': 5 }, { 'Label 2': 4 }] + }, + facet2: { + friendly: 'Facet 2', + labels: [{ 'Label 3': 8 }, { 'Label 4': 9 }] + } + } + ] +} diff --git a/test/unit/collections/CollectionsRepository.test.ts b/test/unit/collections/CollectionsRepository.test.ts index cf7693ba..55489fd2 100644 --- a/test/unit/collections/CollectionsRepository.test.ts +++ b/test/unit/collections/CollectionsRepository.test.ts @@ -32,6 +32,10 @@ import { createCollectionPreviewPayload } from '../../testHelpers/collections/collectionPreviewHelper' import { GetCollectionItemsQueryParams } from '../../../src/collections/domain/models/GetCollectionItemsQueryParams' +import { + createCollectionItemsFacetsModel, + createCollectionItemsFacetsPayload +} from '../../testHelpers/collections/collectionItemsFacetsHelper' describe('CollectionsRepository', () => { const sut: CollectionsRepository = new CollectionsRepository() @@ -362,9 +366,11 @@ describe('CollectionsRepository', () => { createCollectionPreviewModel() ] const testTotalCount = 2 + const testFacets = createCollectionItemsFacetsModel() const testItemSubset: CollectionItemSubset = { items: testItems, + facets: testFacets, totalItemCount: testTotalCount } @@ -377,7 +383,8 @@ describe('CollectionsRepository', () => { createDatasetPreviewPayload(), createFilePreviewPayload(), createCollectionPreviewPayload() - ] + ], + facets: createCollectionItemsFacetsPayload() } } } diff --git a/test/unit/collections/GetCollectionItems.test.ts b/test/unit/collections/GetCollectionItems.test.ts index 28622f51..8c83ae95 100644 --- a/test/unit/collections/GetCollectionItems.test.ts +++ b/test/unit/collections/GetCollectionItems.test.ts @@ -5,6 +5,7 @@ import { createDatasetPreviewModel } from '../../testHelpers/datasets/datasetPre import { createFilePreviewModel } from '../../testHelpers/files/filePreviewHelper' import { CollectionItemSubset } from '../../../src/collections/domain/models/CollectionItemSubset' import { createCollectionPreviewModel } from '../../testHelpers/collections/collectionPreviewHelper' +import { createCollectionItemsFacetsModel } from '../../testHelpers/collections/collectionItemsFacetsHelper' describe('execute', () => { let collectionRepositoryStub: ICollectionsRepository @@ -16,9 +17,11 @@ describe('execute', () => { createCollectionPreviewModel() ] const testTotalCount = 3 + const testFacets = createCollectionItemsFacetsModel() const testItemSubset: CollectionItemSubset = { items: testItems, + facets: testFacets, totalItemCount: testTotalCount } From b0de9eaa38fd7d1bd3e656d84eaafdb1ef504894 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Saracca?= Date: Fri, 6 Dec 2024 11:48:26 -0300 Subject: [PATCH 3/9] feat: sort by name,date - asc,desc --- .../domain/models/CollectionSearchCriteria.ts | 17 ++++- .../models/GetCollectionItemsQueryParams.ts | 10 +++ .../repositories/CollectionsRepository.ts | 18 ++++- .../collections/CollectionsRepository.test.ts | 74 +++++++++++++++++++ .../collections/CollectionsRepository.test.ts | 22 +++--- 5 files changed, 126 insertions(+), 15 deletions(-) diff --git a/src/collections/domain/models/CollectionSearchCriteria.ts b/src/collections/domain/models/CollectionSearchCriteria.ts index 998ab9a8..cd4990c6 100644 --- a/src/collections/domain/models/CollectionSearchCriteria.ts +++ b/src/collections/domain/models/CollectionSearchCriteria.ts @@ -1,16 +1,27 @@ import { CollectionItemType } from './CollectionItemType' +import { OrderType, SortType } from './GetCollectionItemsQueryParams' export class CollectionSearchCriteria { constructor( public readonly searchText?: string, - public readonly itemTypes?: CollectionItemType[] + public readonly itemTypes?: CollectionItemType[], + public readonly sort?: SortType, + public readonly order?: OrderType ) {} withSearchText(searchText: string | undefined): CollectionSearchCriteria { - return new CollectionSearchCriteria(searchText, this.itemTypes) + return new CollectionSearchCriteria(searchText, this.itemTypes, this.sort, this.order) } withItemTypes(itemTypes: CollectionItemType[] | undefined): CollectionSearchCriteria { - return new CollectionSearchCriteria(this.searchText, itemTypes) + return new CollectionSearchCriteria(this.searchText, itemTypes, this.sort, this.order) + } + + withSort(sort: SortType | undefined): CollectionSearchCriteria { + return new CollectionSearchCriteria(this.searchText, this.itemTypes, sort, this.order) + } + + withOrder(order: OrderType | undefined): CollectionSearchCriteria { + return new CollectionSearchCriteria(this.searchText, this.itemTypes, this.sort, order) } } diff --git a/src/collections/domain/models/GetCollectionItemsQueryParams.ts b/src/collections/domain/models/GetCollectionItemsQueryParams.ts index 607d18f5..420893e9 100644 --- a/src/collections/domain/models/GetCollectionItemsQueryParams.ts +++ b/src/collections/domain/models/GetCollectionItemsQueryParams.ts @@ -8,3 +8,13 @@ export enum GetCollectionItemsQueryParams { START = 'start', TYPE = 'type' } + +export enum SortType { + NAME = 'name', + DATE = 'date' +} + +export enum OrderType { + ASC = 'asc', + DESC = 'desc' +} diff --git a/src/collections/infra/repositories/CollectionsRepository.ts b/src/collections/infra/repositories/CollectionsRepository.ts index a3c588e4..ea9bcb2e 100644 --- a/src/collections/infra/repositories/CollectionsRepository.ts +++ b/src/collections/infra/repositories/CollectionsRepository.ts @@ -13,7 +13,11 @@ import { transformCollectionUserPermissionsResponseToCollectionUserPermissions } import { CollectionItemSubset } from '../../domain/models/CollectionItemSubset' import { CollectionSearchCriteria } from '../../domain/models/CollectionSearchCriteria' import { CollectionItemType } from '../../domain/models/CollectionItemType' -import { GetCollectionItemsQueryParams } from '../../domain/models/GetCollectionItemsQueryParams' +import { + GetCollectionItemsQueryParams, + OrderType, + SortType +} from '../../domain/models/GetCollectionItemsQueryParams' export interface NewCollectionRequestPayload { alias: string @@ -115,8 +119,8 @@ export class CollectionsRepository extends ApiRepository implements ICollections const queryParams = new URLSearchParams({ [GetCollectionItemsQueryParams.QUERY]: '*', [GetCollectionItemsQueryParams.SHOW_FACETS]: 'true', - [GetCollectionItemsQueryParams.SORT]: 'date', - [GetCollectionItemsQueryParams.ORDER]: 'desc' + [GetCollectionItemsQueryParams.SORT]: SortType.DATE, + [GetCollectionItemsQueryParams.ORDER]: OrderType.DESC }) if (collectionId) { @@ -204,5 +208,13 @@ export class CollectionsRepository extends ApiRepository implements ICollections queryParams.append(GetCollectionItemsQueryParams.TYPE, mappedItemType) }) } + + if (collectionSearchCriteria?.sort) { + queryParams.set(GetCollectionItemsQueryParams.SORT, collectionSearchCriteria.sort) + } + + if (collectionSearchCriteria?.order) { + queryParams.set(GetCollectionItemsQueryParams.ORDER, collectionSearchCriteria.order) + } } } diff --git a/test/integration/collections/CollectionsRepository.test.ts b/test/integration/collections/CollectionsRepository.test.ts index d77cf0b6..07ca7208 100644 --- a/test/integration/collections/CollectionsRepository.test.ts +++ b/test/integration/collections/CollectionsRepository.test.ts @@ -24,6 +24,10 @@ import { uploadFileViaApi } from '../../testHelpers/files/filesHelper' import { deleteUnpublishedDatasetViaApi } from '../../testHelpers/datasets/datasetHelper' import { PublicationStatus } from '../../../src/core/domain/models/PublicationStatus' import { CollectionType } from '../../../src/collections/domain/models/CollectionType' +import { + OrderType, + SortType +} from '../../../src/collections/domain/models/GetCollectionItemsQueryParams' describe('CollectionsRepository', () => { const testCollectionAlias = 'collectionsRepositoryTestCollection' @@ -525,6 +529,76 @@ describe('CollectionsRepository', () => { expect((actual.items[0] as FilePreview).name).toBe(expectedFileName) expect((actual.items[1] as CollectionPreview).name).toBe(expectedCollectionsName) expect(actual.facets).toEqual(expectedFacetsFromCollectionAndFile) + + // Test sort and order + + // Sort by name ascending + const collectionSearchCriteriaNameAscending = new CollectionSearchCriteria() + .withSort(SortType.NAME) + .withOrder(OrderType.ASC) + + actual = await sut.getCollectionItems( + testCollectionAlias, + undefined, + undefined, + collectionSearchCriteriaNameAscending + ) + expect(actual.items.length).toBe(3) + expect(actual.totalItemCount).toBe(3) + expect((actual.items[0] as DatasetPreview).type).toBe(CollectionItemType.DATASET) + expect((actual.items[1] as CollectionPreview).type).toBe(CollectionItemType.COLLECTION) + expect((actual.items[2] as FilePreview).type).toBe(CollectionItemType.FILE) + + // Sort by name descending + const collectionSearchCriteriaNameDescending = new CollectionSearchCriteria() + .withSort(SortType.NAME) + .withOrder(OrderType.DESC) + + actual = await sut.getCollectionItems( + testCollectionAlias, + undefined, + undefined, + collectionSearchCriteriaNameDescending + ) + expect(actual.items.length).toBe(3) + expect(actual.totalItemCount).toBe(3) + expect((actual.items[0] as FilePreview).type).toBe(CollectionItemType.FILE) + expect((actual.items[1] as CollectionPreview).type).toBe(CollectionItemType.COLLECTION) + expect((actual.items[2] as DatasetPreview).type).toBe(CollectionItemType.DATASET) + + // Sort by date ascending + const collectionSearchCriteriaDateAscending = new CollectionSearchCriteria() + .withSort(SortType.DATE) + .withOrder(OrderType.ASC) + + actual = await sut.getCollectionItems( + testCollectionAlias, + undefined, + undefined, + collectionSearchCriteriaDateAscending + ) + expect(actual.items.length).toBe(3) + expect(actual.totalItemCount).toBe(3) + expect((actual.items[0] as CollectionPreview).type).toBe(CollectionItemType.COLLECTION) + expect((actual.items[1] as DatasetPreview).type).toBe(CollectionItemType.DATASET) + expect((actual.items[2] as FilePreview).type).toBe(CollectionItemType.FILE) + + // Sort by date descending + const collectionSearchCriteriaDateDescending = new CollectionSearchCriteria() + .withSort(SortType.DATE) + .withOrder(OrderType.DESC) + + actual = await sut.getCollectionItems( + testCollectionAlias, + undefined, + undefined, + collectionSearchCriteriaDateDescending + ) + expect(actual.items.length).toBe(3) + expect(actual.totalItemCount).toBe(3) + expect((actual.items[0] as FilePreview).type).toBe(CollectionItemType.FILE) + expect((actual.items[1] as DatasetPreview).type).toBe(CollectionItemType.DATASET) + expect((actual.items[2] as CollectionPreview).type).toBe(CollectionItemType.COLLECTION) }) test('should return error when collection does not exist', async () => { diff --git a/test/unit/collections/CollectionsRepository.test.ts b/test/unit/collections/CollectionsRepository.test.ts index 55489fd2..151cfcd3 100644 --- a/test/unit/collections/CollectionsRepository.test.ts +++ b/test/unit/collections/CollectionsRepository.test.ts @@ -31,7 +31,11 @@ import { createCollectionPreviewModel, createCollectionPreviewPayload } from '../../testHelpers/collections/collectionPreviewHelper' -import { GetCollectionItemsQueryParams } from '../../../src/collections/domain/models/GetCollectionItemsQueryParams' +import { + GetCollectionItemsQueryParams, + OrderType, + SortType +} from '../../../src/collections/domain/models/GetCollectionItemsQueryParams' import { createCollectionItemsFacetsModel, createCollectionItemsFacetsPayload @@ -400,8 +404,8 @@ describe('CollectionsRepository', () => { const expectedRequestParams = new URLSearchParams({ [GetCollectionItemsQueryParams.QUERY]: '*', [GetCollectionItemsQueryParams.SHOW_FACETS]: 'true', - [GetCollectionItemsQueryParams.SORT]: 'date', - [GetCollectionItemsQueryParams.ORDER]: 'desc' + [GetCollectionItemsQueryParams.SORT]: SortType.DATE, + [GetCollectionItemsQueryParams.ORDER]: OrderType.DESC }) const expectedRequestConfigApiKey = { @@ -444,8 +448,8 @@ describe('CollectionsRepository', () => { const expectedRequestParamsWithPagination = new URLSearchParams({ [GetCollectionItemsQueryParams.QUERY]: '*', [GetCollectionItemsQueryParams.SHOW_FACETS]: 'true', - [GetCollectionItemsQueryParams.SORT]: 'date', - [GetCollectionItemsQueryParams.ORDER]: 'desc' + [GetCollectionItemsQueryParams.SORT]: SortType.DATE, + [GetCollectionItemsQueryParams.ORDER]: OrderType.DESC }) expectedRequestParamsWithPagination.set( @@ -498,8 +502,8 @@ describe('CollectionsRepository', () => { const expectedRequestParamsWithCollectionId = new URLSearchParams({ [GetCollectionItemsQueryParams.QUERY]: '*', [GetCollectionItemsQueryParams.SHOW_FACETS]: 'true', - [GetCollectionItemsQueryParams.SORT]: 'date', - [GetCollectionItemsQueryParams.ORDER]: 'desc' + [GetCollectionItemsQueryParams.SORT]: SortType.DATE, + [GetCollectionItemsQueryParams.ORDER]: OrderType.DESC }) expectedRequestParamsWithCollectionId.set( @@ -546,8 +550,8 @@ describe('CollectionsRepository', () => { const expectedRequestParams = new URLSearchParams({ [GetCollectionItemsQueryParams.QUERY]: '*', [GetCollectionItemsQueryParams.SHOW_FACETS]: 'true', - [GetCollectionItemsQueryParams.SORT]: 'date', - [GetCollectionItemsQueryParams.ORDER]: 'desc' + [GetCollectionItemsQueryParams.SORT]: SortType.DATE, + [GetCollectionItemsQueryParams.ORDER]: OrderType.DESC }) const expectedRequestConfigApiKey = { From 1c017627d9fe218b627ed07ee2b244843fe3f8a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Saracca?= Date: Fri, 6 Dec 2024 15:43:16 -0300 Subject: [PATCH 4/9] feat: add filter queries in collection search criteria --- .../domain/models/CollectionSearchCriteria.ts | 15 ++++- .../models/GetCollectionItemsQueryParams.ts | 5 +- .../repositories/CollectionsRepository.ts | 6 ++ .../collections/CollectionsRepository.test.ts | 58 +++++++++++++++++-- 4 files changed, 75 insertions(+), 9 deletions(-) diff --git a/src/collections/domain/models/CollectionSearchCriteria.ts b/src/collections/domain/models/CollectionSearchCriteria.ts index cd4990c6..5d000c72 100644 --- a/src/collections/domain/models/CollectionSearchCriteria.ts +++ b/src/collections/domain/models/CollectionSearchCriteria.ts @@ -1,12 +1,13 @@ import { CollectionItemType } from './CollectionItemType' -import { OrderType, SortType } from './GetCollectionItemsQueryParams' +import { FilterQuery, OrderType, SortType } from './GetCollectionItemsQueryParams' export class CollectionSearchCriteria { constructor( public readonly searchText?: string, public readonly itemTypes?: CollectionItemType[], public readonly sort?: SortType, - public readonly order?: OrderType + public readonly order?: OrderType, + public readonly filterQueries?: FilterQuery[] ) {} withSearchText(searchText: string | undefined): CollectionSearchCriteria { @@ -24,4 +25,14 @@ export class CollectionSearchCriteria { withOrder(order: OrderType | undefined): CollectionSearchCriteria { return new CollectionSearchCriteria(this.searchText, this.itemTypes, this.sort, order) } + + withFilterQueries(filterQueries: FilterQuery[] | undefined): CollectionSearchCriteria { + return new CollectionSearchCriteria( + this.searchText, + this.itemTypes, + this.sort, + this.order, + filterQueries + ) + } } diff --git a/src/collections/domain/models/GetCollectionItemsQueryParams.ts b/src/collections/domain/models/GetCollectionItemsQueryParams.ts index 420893e9..3c9dd1b3 100644 --- a/src/collections/domain/models/GetCollectionItemsQueryParams.ts +++ b/src/collections/domain/models/GetCollectionItemsQueryParams.ts @@ -6,7 +6,8 @@ export enum GetCollectionItemsQueryParams { SUBTREE = 'subtree', PER_PAGE = 'per_page', START = 'start', - TYPE = 'type' + TYPE = 'type', + FILTERQUERY = 'fq' } export enum SortType { @@ -18,3 +19,5 @@ export enum OrderType { ASC = 'asc', DESC = 'desc' } + +export type FilterQuery = `${string}:${string}` diff --git a/src/collections/infra/repositories/CollectionsRepository.ts b/src/collections/infra/repositories/CollectionsRepository.ts index ea9bcb2e..f7f7d9ea 100644 --- a/src/collections/infra/repositories/CollectionsRepository.ts +++ b/src/collections/infra/repositories/CollectionsRepository.ts @@ -216,5 +216,11 @@ export class CollectionsRepository extends ApiRepository implements ICollections if (collectionSearchCriteria?.order) { queryParams.set(GetCollectionItemsQueryParams.ORDER, collectionSearchCriteria.order) } + + if (collectionSearchCriteria?.filterQueries) { + collectionSearchCriteria.filterQueries.forEach((filterQuery) => { + queryParams.append(GetCollectionItemsQueryParams.FILTERQUERY, filterQuery) + }) + } } } diff --git a/test/integration/collections/CollectionsRepository.test.ts b/test/integration/collections/CollectionsRepository.test.ts index 07ca7208..3f68e3ca 100644 --- a/test/integration/collections/CollectionsRepository.test.ts +++ b/test/integration/collections/CollectionsRepository.test.ts @@ -530,9 +530,7 @@ describe('CollectionsRepository', () => { expect((actual.items[1] as CollectionPreview).name).toBe(expectedCollectionsName) expect(actual.facets).toEqual(expectedFacetsFromCollectionAndFile) - // Test sort and order - - // Sort by name ascending + // Test Sort by name ascending const collectionSearchCriteriaNameAscending = new CollectionSearchCriteria() .withSort(SortType.NAME) .withOrder(OrderType.ASC) @@ -549,7 +547,7 @@ describe('CollectionsRepository', () => { expect((actual.items[1] as CollectionPreview).type).toBe(CollectionItemType.COLLECTION) expect((actual.items[2] as FilePreview).type).toBe(CollectionItemType.FILE) - // Sort by name descending + // Test Sort by name descending const collectionSearchCriteriaNameDescending = new CollectionSearchCriteria() .withSort(SortType.NAME) .withOrder(OrderType.DESC) @@ -566,7 +564,7 @@ describe('CollectionsRepository', () => { expect((actual.items[1] as CollectionPreview).type).toBe(CollectionItemType.COLLECTION) expect((actual.items[2] as DatasetPreview).type).toBe(CollectionItemType.DATASET) - // Sort by date ascending + // Test Sort by date ascending const collectionSearchCriteriaDateAscending = new CollectionSearchCriteria() .withSort(SortType.DATE) .withOrder(OrderType.ASC) @@ -583,7 +581,7 @@ describe('CollectionsRepository', () => { expect((actual.items[1] as DatasetPreview).type).toBe(CollectionItemType.DATASET) expect((actual.items[2] as FilePreview).type).toBe(CollectionItemType.FILE) - // Sort by date descending + // Test Sort by date descending const collectionSearchCriteriaDateDescending = new CollectionSearchCriteria() .withSort(SortType.DATE) .withOrder(OrderType.DESC) @@ -599,6 +597,54 @@ describe('CollectionsRepository', () => { expect((actual.items[0] as FilePreview).type).toBe(CollectionItemType.FILE) expect((actual.items[1] as DatasetPreview).type).toBe(CollectionItemType.DATASET) expect((actual.items[2] as CollectionPreview).type).toBe(CollectionItemType.COLLECTION) + + // Test with Filter query related to the collection + const collectionSearchCriteriaFilterQueryCollection = + new CollectionSearchCriteria().withFilterQueries(['dvCategory:Laboratory']) + + actual = await sut.getCollectionItems( + testCollectionAlias, + undefined, + undefined, + collectionSearchCriteriaFilterQueryCollection + ) + expect(actual.items.length).toBe(1) + expect(actual.totalItemCount).toBe(1) + expect((actual.items[0] as CollectionPreview).name).toBe(expectedCollectionsName) + expect(actual.facets).toEqual(expectedFacetsFromCollectionOnly) + + // Test with Filter query related to the dataset + const collectionSearchCriteriaFilterQueryDataset = + new CollectionSearchCriteria().withFilterQueries([ + 'subject_ss:Medicine, Health and Life Sciences' + ]) + + actual = await sut.getCollectionItems( + testCollectionAlias, + undefined, + undefined, + collectionSearchCriteriaFilterQueryDataset + ) + expect(actual.items.length).toBe(1) + expect(actual.totalItemCount).toBe(1) + expect((actual.items[0] as DatasetPreview).title).toBe(expectedDatasetDescription) + expect(actual.facets).toEqual(expectedFacetsFromDatasetOnly) + + // Test with Filter query related to the file + const collectionSearchCriteriaFilterQuerieCollAndFile = + new CollectionSearchCriteria().withFilterQueries(['fileAccess:Public']) + + actual = await sut.getCollectionItems( + testCollectionAlias, + undefined, + undefined, + collectionSearchCriteriaFilterQuerieCollAndFile + ) + + expect(actual.items.length).toBe(1) + expect(actual.totalItemCount).toBe(1) + expect((actual.items[0] as FilePreview).name).toBe(expectedFileName) + expect(actual.facets).toEqual(expectedFacetsFromFileOnly) }) test('should return error when collection does not exist', async () => { From f6c393af4494be18819afbf2a4480c40dadfca78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Saracca?= Date: Mon, 9 Dec 2024 09:17:33 -0300 Subject: [PATCH 5/9] test: simplify set expected params --- .../collections/CollectionsRepository.test.ts | 21 +++++-------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/test/unit/collections/CollectionsRepository.test.ts b/test/unit/collections/CollectionsRepository.test.ts index 151cfcd3..5c407e58 100644 --- a/test/unit/collections/CollectionsRepository.test.ts +++ b/test/unit/collections/CollectionsRepository.test.ts @@ -449,18 +449,11 @@ describe('CollectionsRepository', () => { [GetCollectionItemsQueryParams.QUERY]: '*', [GetCollectionItemsQueryParams.SHOW_FACETS]: 'true', [GetCollectionItemsQueryParams.SORT]: SortType.DATE, - [GetCollectionItemsQueryParams.ORDER]: OrderType.DESC + [GetCollectionItemsQueryParams.ORDER]: OrderType.DESC, + [GetCollectionItemsQueryParams.PER_PAGE]: testLimit.toString(), + [GetCollectionItemsQueryParams.START]: testOffset.toString() }) - expectedRequestParamsWithPagination.set( - GetCollectionItemsQueryParams.PER_PAGE, - testLimit.toString() - ) - expectedRequestParamsWithPagination.set( - GetCollectionItemsQueryParams.START, - testOffset.toString() - ) - const expectedRequestConfigApiKeyWithPagination = { params: expectedRequestParamsWithPagination, headers: TestConstants.TEST_EXPECTED_AUTHENTICATED_REQUEST_CONFIG_API_KEY.headers @@ -503,14 +496,10 @@ describe('CollectionsRepository', () => { [GetCollectionItemsQueryParams.QUERY]: '*', [GetCollectionItemsQueryParams.SHOW_FACETS]: 'true', [GetCollectionItemsQueryParams.SORT]: SortType.DATE, - [GetCollectionItemsQueryParams.ORDER]: OrderType.DESC + [GetCollectionItemsQueryParams.ORDER]: OrderType.DESC, + [GetCollectionItemsQueryParams.SUBTREE]: testCollectionId }) - expectedRequestParamsWithCollectionId.set( - GetCollectionItemsQueryParams.SUBTREE, - testCollectionId - ) - const expectedRequestConfigApiKeyWithCollectionId = { params: expectedRequestParamsWithCollectionId, headers: TestConstants.TEST_EXPECTED_AUTHENTICATED_REQUEST_CONFIG_API_KEY.headers From 1408cddd2d057db4ced3f370ac50c2cbe652346a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Saracca?= Date: Mon, 9 Dec 2024 12:58:01 -0300 Subject: [PATCH 6/9] feat: improve formatting of returned facets --- .../domain/models/CollectionItemSubset.ts | 7 ++-- .../transformers/collectionTransformers.ts | 13 ++++--- .../collections/CollectionsRepository.test.ts | 36 +++++++++---------- .../collectionItemsFacetsHelper.ts | 26 +++++++------- 4 files changed, 38 insertions(+), 44 deletions(-) diff --git a/src/collections/domain/models/CollectionItemSubset.ts b/src/collections/domain/models/CollectionItemSubset.ts index 681b7db5..aecd038f 100644 --- a/src/collections/domain/models/CollectionItemSubset.ts +++ b/src/collections/domain/models/CollectionItemSubset.ts @@ -9,11 +9,8 @@ export interface CollectionItemSubset { } export interface CollectionItemsFacet { - [key: string]: CollectionItemsFacetValue -} - -interface CollectionItemsFacetValue { - friendly: string + name: string + friendlyName: string labels: CollectionItemsFacetLabel[] } diff --git a/src/collections/infra/repositories/transformers/collectionTransformers.ts b/src/collections/infra/repositories/transformers/collectionTransformers.ts index 5139e960..68f730c6 100644 --- a/src/collections/infra/repositories/transformers/collectionTransformers.ts +++ b/src/collections/infra/repositories/transformers/collectionTransformers.ts @@ -107,13 +107,12 @@ export const transformCollectionItemsResponseToCollectionItemSubset = ( const transformedFacets: CollectionItemsFacet[] = Object.entries(facets[0]).map( ([key, facetData]) => ({ - [key]: { - friendly: facetData.friendly, - labels: facetData.labels.map((label: Record) => { - const [name, count] = Object.entries(label)[0] - return { name, count } - }) - } + name: key, + friendlyName: facetData.friendly, + labels: facetData.labels.map((label: Record) => { + const [name, count] = Object.entries(label)[0] + return { name, count } + }) }) ) diff --git a/test/integration/collections/CollectionsRepository.test.ts b/test/integration/collections/CollectionsRepository.test.ts index 3f68e3ca..bff0f6a5 100644 --- a/test/integration/collections/CollectionsRepository.test.ts +++ b/test/integration/collections/CollectionsRepository.test.ts @@ -301,63 +301,63 @@ describe('CollectionsRepository', () => { //prettier-ignore const expectedFacetsAll = [ { - dvCategory: { friendly: 'Dataverse Category', labels: [{ name: 'Laboratory', count: 1 }] } + name: 'dvCategory', friendlyName: 'Dataverse Category', labels: [{ name: 'Laboratory', count: 1 }] }, { - publicationStatus: { friendly: 'Publication Status', labels: [{ name: 'Unpublished', count: 3 },{ name: 'Draft', count: 2 }] } + name: 'publicationStatus', friendlyName: 'Publication Status', labels: [{ name: 'Unpublished', count: 3 },{ name: 'Draft', count: 2 }] }, { - authorName_ss: { friendly: 'Author Name', labels: [{ name: 'Admin, Dataverse', count: 1 },{ name: 'Owner, Dataverse', count: 1 }]} + name: 'authorName_ss', friendlyName: 'Author Name', labels: [{ name: 'Admin, Dataverse', count: 1 },{ name: 'Owner, Dataverse', count: 1 }] }, { - subject_ss: { friendly: 'Subject', labels: [{ name: 'Medicine, Health and Life Sciences', count: 1 }]} + name: 'subject_ss', friendlyName: 'Subject', labels: [{ name: 'Medicine, Health and Life Sciences', count: 1 }] }, { - fileTypeGroupFacet: { friendly: 'File Type', labels: [{ name: 'Text', count: 1 }] } + name: 'fileTypeGroupFacet', friendlyName: 'File Type', labels: [{ name: 'Text', count: 1 }] }, { - fileAccess: { friendly: 'Access', labels: [{ name: 'Public', count: 1 }] } + name: 'fileAccess', friendlyName: 'Access', labels: [{ name: 'Public', count: 1 }] } ] //prettier-ignore const expectedFacetsFromCollectionOnly = [ { - dvCategory: { friendly: 'Dataverse Category', labels: [{ name: 'Laboratory', count: 1 }] } + name: 'dvCategory', friendlyName: 'Dataverse Category', labels: [{ name: 'Laboratory', count: 1 }] }, { - publicationStatus: { friendly: 'Publication Status', labels: [{ name: 'Unpublished', count: 1 }]} + name: 'publicationStatus', friendlyName: 'Publication Status', labels: [{ name: 'Unpublished', count: 1 }] } ] //prettier-ignore const expectedFacetsFromDatasetOnly = [ { - publicationStatus: { friendly: 'Publication Status', labels: [{ name: 'Draft', count: 1 },{ name: 'Unpublished', count: 1 }] } + name: 'publicationStatus', friendlyName: 'Publication Status', labels: [{ name: 'Draft', count: 1 },{ name: 'Unpublished', count: 1 }] }, { - authorName_ss: { friendly: 'Author Name', labels: [{ name: 'Admin, Dataverse', count: 1 },{ name: 'Owner, Dataverse', count: 1 }] } + name: 'authorName_ss', friendlyName: 'Author Name', labels: [{ name: 'Admin, Dataverse', count: 1 },{ name: 'Owner, Dataverse', count: 1 }] }, { - subject_ss: { friendly: 'Subject', labels: [{ name: 'Medicine, Health and Life Sciences', count: 1 }] } + name: 'subject_ss', friendlyName: 'Subject', labels: [{ name: 'Medicine, Health and Life Sciences', count: 1 }] } ] //prettier-ignore const expectedFacetsFromFileOnly = [ { - publicationStatus: { friendly: 'Publication Status', labels: [{ name: 'Draft', count: 1 },{ name: 'Unpublished', count: 1 }] } + name: 'publicationStatus', friendlyName: 'Publication Status', labels: [{ name: 'Draft', count: 1 },{ name: 'Unpublished', count: 1 }] }, - { fileTypeGroupFacet: { friendly: 'File Type', labels: [{ name: 'Text', count: 1 }] } }, - { fileAccess: { friendly: 'Access', labels: [{ name: 'Public', count: 1 }] } } + { name: 'fileTypeGroupFacet', friendlyName: 'File Type', labels: [{ name: 'Text', count: 1 }] }, + { name: 'fileAccess', friendlyName: 'Access', labels: [{ name: 'Public', count: 1 }] } ] //prettier-ignore const expectedFacetsFromCollectionAndFile = [ { - dvCategory: { friendly: 'Dataverse Category', labels: [{ name: 'Laboratory', count: 1 }] } + name: 'dvCategory', friendlyName: 'Dataverse Category', labels: [{ name: 'Laboratory', count: 1 }] }, { - publicationStatus: { friendly: 'Publication Status', labels: [{ name: 'Unpublished', count: 2 },{ name: 'Draft', count: 1 }] } + name: 'publicationStatus', friendlyName: 'Publication Status', labels: [{ name: 'Unpublished', count: 2 },{ name: 'Draft', count: 1 }] }, - { fileTypeGroupFacet: { friendly: 'File Type', labels: [{ name: 'Text', count: 1 }] } }, - { fileAccess: { friendly: 'Access', labels: [{ name: 'Public', count: 1 }] } } + { name: 'fileTypeGroupFacet', friendlyName: 'File Type', labels: [{ name: 'Text', count: 1 }] }, + { name: 'fileAccess', friendlyName: 'Access', labels: [{ name: 'Public', count: 1 }] } ] expect(actualFilePreview.checksum?.type).toBe('MD5') diff --git a/test/testHelpers/collections/collectionItemsFacetsHelper.ts b/test/testHelpers/collections/collectionItemsFacetsHelper.ts index cb5650b1..c1754dee 100644 --- a/test/testHelpers/collections/collectionItemsFacetsHelper.ts +++ b/test/testHelpers/collections/collectionItemsFacetsHelper.ts @@ -4,22 +4,20 @@ import { CollectionItemsFacetPayload } from '../../../src/collections/infra/repo export const createCollectionItemsFacetsModel = (): CollectionItemsFacet[] => { return [ { - facet1: { - friendly: 'Facet 1', - labels: [ - { name: 'Label 1', count: 5 }, - { name: 'Label 2', count: 4 } - ] - } + name: 'facet1', + friendlyName: 'Facet 1', + labels: [ + { name: 'Label 1', count: 5 }, + { name: 'Label 2', count: 4 } + ] }, { - facet2: { - friendly: 'Facet 2', - labels: [ - { name: 'Label 3', count: 8 }, - { name: 'Label 4', count: 9 } - ] - } + name: 'facet2', + friendlyName: 'Facet 2', + labels: [ + { name: 'Label 3', count: 8 }, + { name: 'Label 4', count: 9 } + ] } ] } From 13612a8511f00e5afe0d255d7b3fe5c1f05b7ba3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Saracca?= Date: Tue, 10 Dec 2024 10:37:15 -0300 Subject: [PATCH 7/9] feat: wrapp filter query value around double quoutes --- .../infra/repositories/CollectionsRepository.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/collections/infra/repositories/CollectionsRepository.ts b/src/collections/infra/repositories/CollectionsRepository.ts index f7f7d9ea..242df28e 100644 --- a/src/collections/infra/repositories/CollectionsRepository.ts +++ b/src/collections/infra/repositories/CollectionsRepository.ts @@ -219,7 +219,13 @@ export class CollectionsRepository extends ApiRepository implements ICollections if (collectionSearchCriteria?.filterQueries) { collectionSearchCriteria.filterQueries.forEach((filterQuery) => { - queryParams.append(GetCollectionItemsQueryParams.FILTERQUERY, filterQuery) + const [filterQueryKey, filterQueryValue] = filterQuery.split(':') + + const filterQueryValueWithQuotes = `"${filterQueryValue}"` + + const filterQueryToSet = `${filterQueryKey}:${filterQueryValueWithQuotes}` + + queryParams.append(GetCollectionItemsQueryParams.FILTERQUERY, filterQueryToSet) }) } } From 14560a0083c10ffa26ddfec66d32175e2a6f2259 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Saracca?= Date: Wed, 11 Dec 2024 21:31:32 -0300 Subject: [PATCH 8/9] change variable namings --- .../repositories/transformers/collectionTransformers.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/collections/infra/repositories/transformers/collectionTransformers.ts b/src/collections/infra/repositories/transformers/collectionTransformers.ts index 68f730c6..d4b4ca82 100644 --- a/src/collections/infra/repositories/transformers/collectionTransformers.ts +++ b/src/collections/infra/repositories/transformers/collectionTransformers.ts @@ -83,7 +83,7 @@ export const transformCollectionItemsResponseToCollectionItemSubset = ( ): CollectionItemSubset => { const responseDataPayload = response.data.data const itemsPayload = responseDataPayload.items - const facets = responseDataPayload.facets as CollectionItemsFacetPayload + const facetsPayload = responseDataPayload.facets as CollectionItemsFacetPayload const items: (DatasetPreview | FilePreview | CollectionPreview)[] = [] @@ -105,7 +105,7 @@ export const transformCollectionItemsResponseToCollectionItemSubset = ( } }) - const transformedFacets: CollectionItemsFacet[] = Object.entries(facets[0]).map( + const facets: CollectionItemsFacet[] = Object.entries(facetsPayload[0]).map( ([key, facetData]) => ({ name: key, friendlyName: facetData.friendly, @@ -117,8 +117,8 @@ export const transformCollectionItemsResponseToCollectionItemSubset = ( ) return { - items: items, - facets: transformedFacets, + items, + facets, totalItemCount: responseDataPayload.total_count } } From 3a26dc9e36a14855f99dbb4a95c497094018e0b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Saracca?= Date: Wed, 11 Dec 2024 21:32:29 -0300 Subject: [PATCH 9/9] types alocations --- .../domain/models/CollectionSearchCriteria.ts | 45 ++++++++++++++++--- .../models/GetCollectionItemsQueryParams.ts | 23 ---------- .../repositories/CollectionsRepository.ts | 19 ++++++-- .../collections/CollectionsRepository.test.ts | 2 +- .../collections/CollectionsRepository.test.ts | 14 +++--- 5 files changed, 64 insertions(+), 39 deletions(-) delete mode 100644 src/collections/domain/models/GetCollectionItemsQueryParams.ts diff --git a/src/collections/domain/models/CollectionSearchCriteria.ts b/src/collections/domain/models/CollectionSearchCriteria.ts index 5d000c72..3f36735b 100644 --- a/src/collections/domain/models/CollectionSearchCriteria.ts +++ b/src/collections/domain/models/CollectionSearchCriteria.ts @@ -1,5 +1,16 @@ import { CollectionItemType } from './CollectionItemType' -import { FilterQuery, OrderType, SortType } from './GetCollectionItemsQueryParams' + +export enum SortType { + NAME = 'name', + DATE = 'date' +} + +export enum OrderType { + ASC = 'asc', + DESC = 'desc' +} + +export type FilterQuery = `${string}:${string}` export class CollectionSearchCriteria { constructor( @@ -11,19 +22,43 @@ export class CollectionSearchCriteria { ) {} withSearchText(searchText: string | undefined): CollectionSearchCriteria { - return new CollectionSearchCriteria(searchText, this.itemTypes, this.sort, this.order) + return new CollectionSearchCriteria( + searchText, + this.itemTypes, + this.sort, + this.order, + this.filterQueries + ) } withItemTypes(itemTypes: CollectionItemType[] | undefined): CollectionSearchCriteria { - return new CollectionSearchCriteria(this.searchText, itemTypes, this.sort, this.order) + return new CollectionSearchCriteria( + this.searchText, + itemTypes, + this.sort, + this.order, + this.filterQueries + ) } withSort(sort: SortType | undefined): CollectionSearchCriteria { - return new CollectionSearchCriteria(this.searchText, this.itemTypes, sort, this.order) + return new CollectionSearchCriteria( + this.searchText, + this.itemTypes, + sort, + this.order, + this.filterQueries + ) } withOrder(order: OrderType | undefined): CollectionSearchCriteria { - return new CollectionSearchCriteria(this.searchText, this.itemTypes, this.sort, order) + return new CollectionSearchCriteria( + this.searchText, + this.itemTypes, + this.sort, + order, + this.filterQueries + ) } withFilterQueries(filterQueries: FilterQuery[] | undefined): CollectionSearchCriteria { diff --git a/src/collections/domain/models/GetCollectionItemsQueryParams.ts b/src/collections/domain/models/GetCollectionItemsQueryParams.ts deleted file mode 100644 index 3c9dd1b3..00000000 --- a/src/collections/domain/models/GetCollectionItemsQueryParams.ts +++ /dev/null @@ -1,23 +0,0 @@ -export enum GetCollectionItemsQueryParams { - QUERY = 'q', - SHOW_FACETS = 'show_facets', - SORT = 'sort', - ORDER = 'order', - SUBTREE = 'subtree', - PER_PAGE = 'per_page', - START = 'start', - TYPE = 'type', - FILTERQUERY = 'fq' -} - -export enum SortType { - NAME = 'name', - DATE = 'date' -} - -export enum OrderType { - ASC = 'asc', - DESC = 'desc' -} - -export type FilterQuery = `${string}:${string}` diff --git a/src/collections/infra/repositories/CollectionsRepository.ts b/src/collections/infra/repositories/CollectionsRepository.ts index 242df28e..bee82863 100644 --- a/src/collections/infra/repositories/CollectionsRepository.ts +++ b/src/collections/infra/repositories/CollectionsRepository.ts @@ -11,13 +11,12 @@ import { CollectionFacet } from '../../domain/models/CollectionFacet' import { CollectionUserPermissions } from '../../domain/models/CollectionUserPermissions' import { transformCollectionUserPermissionsResponseToCollectionUserPermissions } from './transformers/collectionUserPermissionsTransformers' import { CollectionItemSubset } from '../../domain/models/CollectionItemSubset' -import { CollectionSearchCriteria } from '../../domain/models/CollectionSearchCriteria' -import { CollectionItemType } from '../../domain/models/CollectionItemType' import { - GetCollectionItemsQueryParams, + CollectionSearchCriteria, OrderType, SortType -} from '../../domain/models/GetCollectionItemsQueryParams' +} from '../../domain/models/CollectionSearchCriteria' +import { CollectionItemType } from '../../domain/models/CollectionItemType' export interface NewCollectionRequestPayload { alias: string @@ -45,6 +44,18 @@ export interface NewCollectionInputLevelRequestPayload { required: boolean } +export enum GetCollectionItemsQueryParams { + QUERY = 'q', + SHOW_FACETS = 'show_facets', + SORT = 'sort', + ORDER = 'order', + SUBTREE = 'subtree', + PER_PAGE = 'per_page', + START = 'start', + TYPE = 'type', + FILTERQUERY = 'fq' +} + export class CollectionsRepository extends ApiRepository implements ICollectionsRepository { private readonly collectionsResourceName: string = 'dataverses' diff --git a/test/integration/collections/CollectionsRepository.test.ts b/test/integration/collections/CollectionsRepository.test.ts index bff0f6a5..e763e105 100644 --- a/test/integration/collections/CollectionsRepository.test.ts +++ b/test/integration/collections/CollectionsRepository.test.ts @@ -27,7 +27,7 @@ import { CollectionType } from '../../../src/collections/domain/models/Collectio import { OrderType, SortType -} from '../../../src/collections/domain/models/GetCollectionItemsQueryParams' +} from '../../../src/collections/domain/models/CollectionSearchCriteria' describe('CollectionsRepository', () => { const testCollectionAlias = 'collectionsRepositoryTestCollection' diff --git a/test/unit/collections/CollectionsRepository.test.ts b/test/unit/collections/CollectionsRepository.test.ts index 5c407e58..d7a0af31 100644 --- a/test/unit/collections/CollectionsRepository.test.ts +++ b/test/unit/collections/CollectionsRepository.test.ts @@ -1,4 +1,7 @@ -import { CollectionsRepository } from '../../../src/collections/infra/repositories/CollectionsRepository' +import { + CollectionsRepository, + GetCollectionItemsQueryParams +} from '../../../src/collections/infra/repositories/CollectionsRepository' import axios from 'axios' import { ApiConfig, @@ -31,15 +34,14 @@ import { createCollectionPreviewModel, createCollectionPreviewPayload } from '../../testHelpers/collections/collectionPreviewHelper' -import { - GetCollectionItemsQueryParams, - OrderType, - SortType -} from '../../../src/collections/domain/models/GetCollectionItemsQueryParams' import { createCollectionItemsFacetsModel, createCollectionItemsFacetsPayload } from '../../testHelpers/collections/collectionItemsFacetsHelper' +import { + OrderType, + SortType +} from '../../../src/collections/domain/models/CollectionSearchCriteria' describe('CollectionsRepository', () => { const sut: CollectionsRepository = new CollectionsRepository()