Skip to content

Commit 0eaf2df

Browse files
authored
Merge pull request #181 from IQSS/170-file-collection-results
GetCollectionItems use case, for returning dataset, collection and file item types
2 parents 42c1ce3 + 8aeefc4 commit 0eaf2df

30 files changed

+1189
-25
lines changed

docs/useCases.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ The different use cases currently available in the package are classified below,
1313
- [Get a Collection](#get-a-collection)
1414
- [Get Collection Facets](#get-collection-facets)
1515
- [Get User Permissions on a Collection](#get-user-permissions-on-a-collection)
16+
- [List All Collection Items](#list-all-collection-items)
1617
- [Collections write use cases](#collections-write-use-cases)
1718
- [Create a Collection](#create-a-collection)
1819
- [Publish a Collection](#publish-a-collection)
@@ -160,6 +161,40 @@ The `collectionIdOrAlias` is a generic collection identifier, which can be eithe
160161

161162
If no collection identifier is specified, the default collection identifier; `root` will be used. If you want to search for a different collection, you must add the collection identifier as a parameter in the use case call.
162163

164+
#### List All Collection Items
165+
166+
Returns an instance of [CollectionItemSubset](../src/collections/domain/models/CollectionItemSubset.ts) that contains reduced information for each collection item that the calling user can access in the installation.
167+
168+
##### Example call:
169+
170+
```typescript
171+
import { getCollectionItems } from '@iqss/dataverse-client-javascript'
172+
173+
/* ... */
174+
175+
const collectionId = 'subcollection1'
176+
const limit = 10
177+
const offset = 20
178+
179+
getCollectionItems.execute(collectionId, limit, offset).then((subset: CollectionItemSubset) => {
180+
/* ... */
181+
})
182+
183+
/* ... */
184+
```
185+
186+
_See [use case](../src/collections/domain/useCases/GetCollectionItems.ts) implementation_.
187+
188+
Note that `collectionId` is an optional parameter to filter the items by a specific collection. If not set, the use case will return items starting from the root collection.
189+
190+
The `CollectionItemSubset`returned instance contains a property called `totalItemCount` which is necessary for pagination.
191+
192+
This use case supports the following optional parameters depending on the search goals:
193+
194+
- **limit**: (number) Limit for pagination.
195+
- **offset**: (number) Offset for pagination.
196+
- **collectionSearchCriteria**: ([CollectionSearchCriteria](../src/collections/domain/models/CollectionSearchCriteria.ts)) Supports filtering the collection items by different properties.
197+
163198
### Collections Write Use Cases
164199

165200
#### Create a Collection

jest.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ const config: Config = {
1212
testTimeout: 25000,
1313
coverageThreshold: {
1414
global: {
15-
branches: 95,
15+
branches: 90,
1616
functions: 95,
1717
lines: 95,
1818
statements: 95
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { DatasetPreview } from '../../../datasets'
2+
import { FilePreview } from '../../../files'
3+
import { CollectionPreview } from './CollectionPreview'
4+
5+
export interface CollectionItemSubset {
6+
items: (CollectionPreview | DatasetPreview | FilePreview)[]
7+
totalItemCount: number
8+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export enum CollectionItemType {
2+
FILE = 'file',
3+
DATASET = 'dataset',
4+
COLLECTION = 'collection'
5+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { PublicationStatus } from '../../../core/domain/models/PublicationStatus'
2+
import { CollectionItemType } from './CollectionItemType'
3+
4+
export interface CollectionPreview {
5+
type: CollectionItemType.COLLECTION
6+
name: string
7+
parentName: string
8+
alias: string
9+
parentAlias: string
10+
description: string
11+
affiliation: string
12+
publicationStatuses: PublicationStatus[]
13+
releaseOrCreateDate: Date
14+
imageUrl?: string
15+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { CollectionItemType } from './CollectionItemType'
2+
3+
export class CollectionSearchCriteria {
4+
constructor(
5+
public readonly searchText?: string,
6+
public readonly itemTypes?: CollectionItemType[]
7+
) {}
8+
9+
withSearchText(searchText: string | undefined): CollectionSearchCriteria {
10+
return new CollectionSearchCriteria(searchText, this.itemTypes)
11+
}
12+
13+
withItemTypes(itemTypes: CollectionItemType[] | undefined): CollectionSearchCriteria {
14+
return new CollectionSearchCriteria(this.searchText, itemTypes)
15+
}
16+
}

src/collections/domain/repositories/ICollectionsRepository.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { CollectionDTO } from '../dtos/CollectionDTO'
22
import { Collection } from '../models/Collection'
33
import { CollectionFacet } from '../models/CollectionFacet'
4+
import { CollectionItemSubset } from '../models/CollectionItemSubset'
5+
import { CollectionSearchCriteria } from '../models/CollectionSearchCriteria'
46
import { CollectionUserPermissions } from '../models/CollectionUserPermissions'
57

68
export interface ICollectionsRepository {
@@ -14,4 +16,10 @@ export interface ICollectionsRepository {
1416
getCollectionUserPermissions(
1517
collectionIdOrAlias: number | string
1618
): Promise<CollectionUserPermissions>
19+
getCollectionItems(
20+
collectionId?: string,
21+
limit?: number,
22+
offset?: number,
23+
collectionSearchCriteria?: CollectionSearchCriteria
24+
): Promise<CollectionItemSubset>
1725
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { UseCase } from '../../../core/domain/useCases/UseCase'
2+
import { CollectionSearchCriteria } from '../../../collections'
3+
import { CollectionItemSubset } from '../models/CollectionItemSubset'
4+
import { ICollectionsRepository } from '../repositories/ICollectionsRepository'
5+
6+
export class GetCollectionItems implements UseCase<CollectionItemSubset> {
7+
private collectionsRepository: ICollectionsRepository
8+
9+
constructor(collectionsRepository: ICollectionsRepository) {
10+
this.collectionsRepository = collectionsRepository
11+
}
12+
13+
/**
14+
* Returns an instance of CollectionItemSubset that contains reduced information for each item that the calling user can access in the installation.
15+
* If the collectionId parameter is not set, the use case will return items starting from the root collection.
16+
*
17+
* @param {string} [collectionId] - Collection id (optional).
18+
* @param {number} [limit] - Limit for pagination (optional).
19+
* @param {number} [offset] - Offset for pagination (optional).
20+
* @param {CollectionSearchCriteria} [collectionSearchCriteria] - Supports filtering the collection items by different properties (optional).
21+
* @returns {Promise<CollectionItemSubset>}
22+
*/
23+
async execute(
24+
collectionId?: string,
25+
limit?: number,
26+
offset?: number,
27+
collectionSearchCriteria?: CollectionSearchCriteria
28+
): Promise<CollectionItemSubset> {
29+
return await this.collectionsRepository.getCollectionItems(
30+
collectionId,
31+
limit,
32+
offset,
33+
collectionSearchCriteria
34+
)
35+
}
36+
}

src/collections/index.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,32 @@ import { CreateCollection } from './domain/useCases/CreateCollection'
22
import { GetCollection } from './domain/useCases/GetCollection'
33
import { GetCollectionFacets } from './domain/useCases/GetCollectionFacets'
44
import { GetCollectionUserPermissions } from './domain/useCases/GetCollectionUserPermissions'
5+
import { GetCollectionItems } from './domain/useCases/GetCollectionItems'
6+
import { PublishCollection } from './domain/useCases/PublishCollection'
57

68
import { CollectionsRepository } from './infra/repositories/CollectionsRepository'
7-
import { PublishCollection } from './domain/useCases/PublishCollection'
89

910
const collectionsRepository = new CollectionsRepository()
1011

1112
const getCollection = new GetCollection(collectionsRepository)
1213
const createCollection = new CreateCollection(collectionsRepository)
1314
const getCollectionFacets = new GetCollectionFacets(collectionsRepository)
1415
const getCollectionUserPermissions = new GetCollectionUserPermissions(collectionsRepository)
16+
const getCollectionItems = new GetCollectionItems(collectionsRepository)
1517
const publishCollection = new PublishCollection(collectionsRepository)
1618

1719
export {
1820
getCollection,
1921
createCollection,
2022
getCollectionFacets,
2123
getCollectionUserPermissions,
24+
getCollectionItems,
2225
publishCollection
2326
}
2427
export { Collection, CollectionInputLevel } from './domain/models/Collection'
2528
export { CollectionFacet } from './domain/models/CollectionFacet'
2629
export { CollectionUserPermissions } from './domain/models/CollectionUserPermissions'
2730
export { CollectionDTO, CollectionInputLevelDTO } from './domain/dtos/CollectionDTO'
31+
export { CollectionPreview } from './domain/models/CollectionPreview'
32+
export { CollectionItemType } from './domain/models/CollectionItemType'
33+
export { CollectionSearchCriteria } from './domain/models/CollectionSearchCriteria'

src/collections/infra/repositories/CollectionsRepository.ts

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,17 @@ import { ApiRepository } from '../../../core/infra/repositories/ApiRepository'
22
import { ICollectionsRepository } from '../../domain/repositories/ICollectionsRepository'
33
import {
44
transformCollectionFacetsResponseToCollectionFacets,
5+
transformCollectionItemsResponseToCollectionItemSubset,
56
transformCollectionResponseToCollection
67
} from './transformers/collectionTransformers'
78
import { Collection, ROOT_COLLECTION_ALIAS } from '../../domain/models/Collection'
89
import { CollectionDTO } from '../../domain/dtos/CollectionDTO'
910
import { CollectionFacet } from '../../domain/models/CollectionFacet'
1011
import { CollectionUserPermissions } from '../../domain/models/CollectionUserPermissions'
1112
import { transformCollectionUserPermissionsResponseToCollectionUserPermissions } from './transformers/collectionUserPermissionsTransformers'
13+
import { CollectionItemSubset } from '../../domain/models/CollectionItemSubset'
14+
import { CollectionSearchCriteria } from '../../domain/models/CollectionSearchCriteria'
15+
import { CollectionItemType } from '../../domain/models/CollectionItemType'
1216

1317
export interface NewCollectionRequestPayload {
1418
alias: string
@@ -36,6 +40,14 @@ export interface NewCollectionInputLevelRequestPayload {
3640
required: boolean
3741
}
3842

43+
export interface GetCollectionItemsQueryParams {
44+
q: string
45+
subtree?: string
46+
per_page?: number
47+
start?: number
48+
type?: string
49+
}
50+
3951
export class CollectionsRepository extends ApiRepository implements ICollectionsRepository {
4052
private readonly collectionsResourceName: string = 'dataverses'
4153

@@ -129,4 +141,56 @@ export class CollectionsRepository extends ApiRepository implements ICollections
129141
throw error
130142
})
131143
}
144+
145+
public async getCollectionItems(
146+
collectionId?: string,
147+
limit?: number,
148+
offset?: number,
149+
collectionSearchCriteria?: CollectionSearchCriteria
150+
): Promise<CollectionItemSubset> {
151+
const queryParams: GetCollectionItemsQueryParams = {
152+
q: '*'
153+
}
154+
if (collectionId) {
155+
queryParams.subtree = collectionId
156+
}
157+
if (limit) {
158+
queryParams.per_page = limit
159+
}
160+
if (offset) {
161+
queryParams.start = offset
162+
}
163+
if (collectionSearchCriteria) {
164+
this.applyCollectionSearchCriteriaToQueryParams(queryParams, collectionSearchCriteria)
165+
}
166+
167+
let url = '/search?sort=date&order=desc'
168+
169+
if (collectionSearchCriteria?.itemTypes) {
170+
const itemTypesQueryString = collectionSearchCriteria.itemTypes
171+
.map((itemType: CollectionItemType) => {
172+
const mappedItemType =
173+
itemType === CollectionItemType.COLLECTION ? 'dataverse' : itemType.toString()
174+
return `type=${mappedItemType}`
175+
})
176+
.join('&')
177+
178+
url += `&${itemTypesQueryString}`
179+
}
180+
181+
return this.doGet(url, true, queryParams)
182+
.then((response) => transformCollectionItemsResponseToCollectionItemSubset(response))
183+
.catch((error) => {
184+
throw error
185+
})
186+
}
187+
188+
private applyCollectionSearchCriteriaToQueryParams(
189+
queryParams: GetCollectionItemsQueryParams,
190+
collectionSearchCriteria: CollectionSearchCriteria
191+
) {
192+
if (collectionSearchCriteria.searchText) {
193+
queryParams.q = encodeURIComponent(collectionSearchCriteria.searchText)
194+
}
195+
}
132196
}

0 commit comments

Comments
 (0)