Skip to content
12 changes: 12 additions & 0 deletions src/collections/domain/models/CollectionItemSubset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,17 @@ import { CollectionPreview } from './CollectionPreview'

export interface CollectionItemSubset {
items: (CollectionPreview | DatasetPreview | FilePreview)[]
facets: CollectionItemsFacet[]
totalItemCount: number
}

export interface CollectionItemsFacet {
name: string
friendlyName: string
labels: CollectionItemsFacetLabel[]
}

interface CollectionItemsFacetLabel {
name: string
count: number
}
63 changes: 60 additions & 3 deletions src/collections/domain/models/CollectionSearchCriteria.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,73 @@
import { CollectionItemType } from './CollectionItemType'

export enum SortType {
NAME = 'name',
DATE = 'date'
}

export enum OrderType {
ASC = 'asc',
DESC = 'desc'
}

export type FilterQuery = `${string}:${string}`

export class CollectionSearchCriteria {
constructor(
public readonly searchText?: string,
public readonly itemTypes?: CollectionItemType[]
public readonly itemTypes?: CollectionItemType[],
public readonly sort?: SortType,
public readonly order?: OrderType,
public readonly filterQueries?: FilterQuery[]
) {}

withSearchText(searchText: string | undefined): CollectionSearchCriteria {
return new CollectionSearchCriteria(searchText, this.itemTypes)
return new CollectionSearchCriteria(
searchText,
this.itemTypes,
this.sort,
this.order,
this.filterQueries
)
}

withItemTypes(itemTypes: CollectionItemType[] | undefined): CollectionSearchCriteria {
return new CollectionSearchCriteria(this.searchText, itemTypes)
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,
this.filterQueries
)
}

withOrder(order: OrderType | undefined): CollectionSearchCriteria {
return new CollectionSearchCriteria(
this.searchText,
this.itemTypes,
this.sort,
order,
this.filterQueries
)
}

withFilterQueries(filterQueries: FilterQuery[] | undefined): CollectionSearchCriteria {
return new CollectionSearchCriteria(
this.searchText,
this.itemTypes,
this.sort,
this.order,
filterQueries
)
}
}
92 changes: 62 additions & 30 deletions src/collections/infra/repositories/CollectionsRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@ 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 {
CollectionSearchCriteria,
OrderType,
SortType
} from '../../domain/models/CollectionSearchCriteria'
import { CollectionItemType } from '../../domain/models/CollectionItemType'

export interface NewCollectionRequestPayload {
Expand Down Expand Up @@ -40,12 +44,16 @@ export interface NewCollectionInputLevelRequestPayload {
required: boolean
}

export interface GetCollectionItemsQueryParams {
q: string
subtree?: string
per_page?: number
start?: number
type?: string
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 {
Expand Down Expand Up @@ -119,37 +127,30 @@ export class CollectionsRepository extends ApiRepository implements ICollections
offset?: number,
collectionSearchCriteria?: CollectionSearchCriteria
): Promise<CollectionItemSubset> {
const queryParams: GetCollectionItemsQueryParams = {
q: '*'
}
const queryParams = new URLSearchParams({
[GetCollectionItemsQueryParams.QUERY]: '*',
[GetCollectionItemsQueryParams.SHOW_FACETS]: 'true',
[GetCollectionItemsQueryParams.SORT]: SortType.DATE,
[GetCollectionItemsQueryParams.ORDER]: OrderType.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
Expand Down Expand Up @@ -201,11 +202,42 @@ 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)
})
}

if (collectionSearchCriteria?.sort) {
queryParams.set(GetCollectionItemsQueryParams.SORT, collectionSearchCriteria.sort)
}

if (collectionSearchCriteria?.order) {
queryParams.set(GetCollectionItemsQueryParams.ORDER, collectionSearchCriteria.order)
}

if (collectionSearchCriteria?.filterQueries) {
collectionSearchCriteria.filterQueries.forEach((filterQuery) => {
const [filterQueryKey, filterQueryValue] = filterQuery.split(':')

const filterQueryValueWithQuotes = `"${filterQueryValue}"`

const filterQueryToSet = `${filterQueryKey}:${filterQueryValueWithQuotes}`

queryParams.append(GetCollectionItemsQueryParams.FILTERQUERY, filterQueryToSet)
})
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export type CollectionItemsFacetPayload = [Record<string, CollectionItemsFacetPayloadValue>]

export interface CollectionItemsFacetPayloadValue {
friendly: string
labels: Record<string, number>[]
}
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand All @@ -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
Expand Down Expand Up @@ -79,7 +83,10 @@ export const transformCollectionItemsResponseToCollectionItemSubset = (
): CollectionItemSubset => {
const responseDataPayload = response.data.data
const itemsPayload = responseDataPayload.items
const facetsPayload = responseDataPayload.facets as CollectionItemsFacetPayload

const items: (DatasetPreview | FilePreview | CollectionPreview)[] = []

itemsPayload.forEach(function (
itemPayload: CollectionPreviewPayload | DatasetPreviewPayload | FilePreviewPayload
) {
Expand All @@ -97,8 +104,21 @@ export const transformCollectionItemsResponseToCollectionItemSubset = (
)
}
})

const facets: CollectionItemsFacet[] = Object.entries(facetsPayload[0]).map(
([key, facetData]) => ({
name: key,
friendlyName: facetData.friendly,
labels: facetData.labels.map((label: Record<string, number>) => {
const [name, count] = Object.entries(label)[0]
return { name, count }
})
})
)

return {
items: items,
items,
facets,
totalItemCount: responseDataPayload.total_count
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/core/infra/repositories/ApiRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export abstract class ApiRepository {
public async doGet(
apiEndpoint: string,
authRequired = false,
queryParams: object = {}
queryParams: object | URLSearchParams = {}
): Promise<AxiosResponse> {
return await axios
.get(buildRequestUrl(apiEndpoint), buildRequestConfig(authRequired, queryParams))
Expand Down
2 changes: 1 addition & 1 deletion src/core/infra/repositories/apiConfigBuilders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 => {
Expand Down
Loading
Loading