Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions docs/useCases.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ The different use cases currently available in the package are classified below,
- [Get Application Terms of Use](#get-application-terms-of-use)
- [Contact](#Contact)
- [Send Feedback to Object Contacts](#send-feedback-to-object-contacts)
- [Search](#Search)
- [Get Search Services](#get-search-services)

## Collections

Expand Down Expand Up @@ -222,6 +224,8 @@ This use case supports the following optional parameters depending on the search
- **limit**: (number) Limit for pagination.
- **offset**: (number) Offset for pagination.
- **collectionSearchCriteria**: ([CollectionSearchCriteria](../src/collections/domain/models/CollectionSearchCriteria.ts)) Supports filtering the collection items by different properties.
- **searchServiceName**: The search service name on which to execute the search (Optional).
- **showTypeCounts**: If true, the response will include the count per object type (Optional).

#### List My Data Collection Items

Expand Down Expand Up @@ -1991,3 +1995,25 @@ In ContactDTO, it takes the following information:
- **subject**: the email subject line.
- **body**: the email body to send.
- **fromEmail**: the email to list in the reply-to field.

## Search

#### Get Search Services

Returns all [Search Services](../src/search/domain/models/SearchService.ts) available in the installation.

##### Example call:

```typescript
import { getSearchServices } from '@iqss/dataverse-client-javascript'

/* ... */

getSearchServices.execute().then((searchServices: SearchService[]) => {
/* ... */
})

/* ... */
```

_See [use case](../src/search/domain/useCases/GetSearchServices.ts) implementation_.
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export interface ICollectionsRepository {
limit?: number,
offset?: number,
collectionSearchCriteria?: CollectionSearchCriteria,
searchServiceName?: string,
showTypeCounts?: boolean
): Promise<CollectionItemSubset>
getMyDataCollectionItems(
Expand Down
3 changes: 3 additions & 0 deletions src/collections/domain/useCases/GetCollectionItems.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export class GetCollectionItems implements UseCase<CollectionItemSubset> {
* @param {number} [limit] - Limit for pagination (optional).
* @param {number} [offset] - Offset for pagination (optional).
* @param {CollectionSearchCriteria} [collectionSearchCriteria] - Supports filtering the collection items by different properties (optional).
* @param {string} [searchServiceName] - The search service name on which to execute the search (optional).
* @param {boolean} [showTypeCounts] - If true, the response will include the count per object type (optional).
* @returns {Promise<CollectionItemSubset>}
*/
Expand All @@ -26,13 +27,15 @@ export class GetCollectionItems implements UseCase<CollectionItemSubset> {
limit?: number,
offset?: number,
collectionSearchCriteria?: CollectionSearchCriteria,
searchServiceName?: string,
showTypeCounts = false
): Promise<CollectionItemSubset> {
return await this.collectionsRepository.getCollectionItems(
collectionId,
limit,
offset,
collectionSearchCriteria,
searchServiceName,
showTypeCounts
)
}
Expand Down
8 changes: 7 additions & 1 deletion src/collections/infra/repositories/CollectionsRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ export enum GetCollectionItemsQueryParams {
START = 'start',
TYPE = 'type',
FILTERQUERY = 'fq',
SHOW_TYPE_COUNTS = 'show_type_counts'
SHOW_TYPE_COUNTS = 'show_type_counts',
SEARCH_SERVICE_NAME = 'search_service'
}

export enum GetMyDataCollectionItemsQueryParams {
Expand Down Expand Up @@ -168,6 +169,7 @@ export class CollectionsRepository extends ApiRepository implements ICollections
limit?: number,
offset?: number,
collectionSearchCriteria?: CollectionSearchCriteria,
searchServiceName?: string,
showTypeCounts?: boolean
): Promise<CollectionItemSubset> {
const queryParams = new URLSearchParams({
Expand All @@ -193,6 +195,10 @@ export class CollectionsRepository extends ApiRepository implements ICollections
queryParams.set(GetCollectionItemsQueryParams.SHOW_TYPE_COUNTS, 'true')
}

if (searchServiceName) {
queryParams.set(GetCollectionItemsQueryParams.SEARCH_SERVICE_NAME, searchServiceName)
}

if (collectionSearchCriteria) {
this.applyCollectionSearchCriteriaToQueryParams(queryParams, collectionSearchCriteria)
}
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ export * from './collections'
export * from './metadataBlocks'
export * from './files'
export * from './contactInfo'
export * from './search'
4 changes: 4 additions & 0 deletions src/search/domain/models/SearchService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export interface SearchService {
name: string
displayName: string
}
5 changes: 5 additions & 0 deletions src/search/domain/repositories/ISearchServicesRepository.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { SearchService } from '../models/SearchService'

export interface ISearchServicesRepository {
getSearchServices(): Promise<SearchService[]>
}
20 changes: 20 additions & 0 deletions src/search/domain/useCases/GetSearchServices.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { UseCase } from '../../../core/domain/useCases/UseCase'
import { SearchService } from '../models/SearchService'
import { ISearchServicesRepository } from '../repositories/ISearchServicesRepository'

export class GetSearchServices implements UseCase<SearchService[]> {
private searchServicesRepository: ISearchServicesRepository

constructor(searchServicesRepository: ISearchServicesRepository) {
this.searchServicesRepository = searchServicesRepository
}

/**
* Returns all search services available in the installation.
*
* @returns {Promise<SearchService[]>}
*/
async execute(): Promise<SearchService[]> {
return await this.searchServicesRepository.getSearchServices()
}
}
10 changes: 10 additions & 0 deletions src/search/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { GetSearchServices } from './domain/useCases/GetSearchServices'
import { SearchServicesRepository } from './infra/repositories/SearchServicesRepository'

const searchServicesRepository = new SearchServicesRepository()

const getSearchServices = new GetSearchServices(searchServicesRepository)

export { getSearchServices }

export { SearchService } from './domain/models/SearchService'
14 changes: 14 additions & 0 deletions src/search/infra/repositories/SearchServicesRepository.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { ApiRepository } from '../../../core/infra/repositories/ApiRepository'
import { SearchService } from '../../domain/models/SearchService'
import { ISearchServicesRepository } from '../../domain/repositories/ISearchServicesRepository'
import { transformSearchServicesResponseToSearchServices } from './transformers/searchServiceTransformers'

export class SearchServicesRepository extends ApiRepository implements ISearchServicesRepository {
public async getSearchServices(): Promise<SearchService[]> {
return this.doGet(`/search/services`)
.then((response) => transformSearchServicesResponseToSearchServices(response))
.catch((error) => {
throw error
})
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export interface SearchServicePayload {
name: string
displayName: string
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { AxiosResponse } from 'axios'
import { SearchService } from '../../../domain/models/SearchService'
import { SearchServicePayload } from './SearchServicePayload'

export const transformSearchServicesResponseToSearchServices = (
response: AxiosResponse
): SearchService[] => {
const searchServicesPayload = response.data.data.services
const searchServices: SearchService[] = []
searchServicesPayload.forEach(function (searchServicePayload: SearchServicePayload) {
searchServices.push(transformSearchServicePayloadToSearchService(searchServicePayload))
})

return searchServices
}

const transformSearchServicePayloadToSearchService = (
searchServicePayload: SearchServicePayload
): SearchService => {
return {
name: searchServicePayload.name,
displayName: searchServicePayload.displayName
}
}
23 changes: 23 additions & 0 deletions test/functional/search/GetSearchServices.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { ApiConfig, getSearchServices } from '../../../src'
import { TestConstants } from '../../testHelpers/TestConstants'
import { DataverseApiAuthMechanism } from '../../../src/core/infra/repositories/ApiConfig'
import { SearchService } from '../../../src/search/domain/models/SearchService'

describe('execute', () => {
beforeEach(async () => {
ApiConfig.init(
TestConstants.TEST_API_URL,
DataverseApiAuthMechanism.API_KEY,
process.env.TEST_API_KEY
)
})

test('should successfully return search services', async () => {
const searchServices: SearchService[] = await getSearchServices.execute()

expect(searchServices).toBeDefined()
expect(searchServices.length).toBe(1)
expect(searchServices[0].name).toBe('solr')
expect(searchServices[0].displayName).toBe('Dataverse Standard Search')
})
})
1 change: 1 addition & 0 deletions test/integration/collections/CollectionsRepository.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -784,6 +784,7 @@ describe('CollectionsRepository', () => {
undefined,
undefined,
undefined,
undefined,
true
)
expect(actual.countPerObjectType?.collections).toBe(1)
Expand Down
25 changes: 25 additions & 0 deletions test/integration/search/SearchServicesRepository.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { ApiConfig } from '../../../src'
import { DataverseApiAuthMechanism } from '../../../src/core/infra/repositories/ApiConfig'
import { SearchServicesRepository } from '../../../src/search/infra/repositories/SearchServicesRepository'
import { TestConstants } from '../../testHelpers/TestConstants'

describe('SearchServicesRepository', () => {
const sut: SearchServicesRepository = new SearchServicesRepository()

beforeAll(async () => {
ApiConfig.init(
TestConstants.TEST_API_URL,
DataverseApiAuthMechanism.API_KEY,
process.env.TEST_API_KEY
)
})

describe('getSearchServices', () => {
test('should return search services', async () => {
const actual = await sut.getSearchServices()
expect(actual.length).toEqual(1)
expect(actual[0].name).toEqual('solr')
expect(actual[0].displayName).toEqual('Dataverse Standard Search')
})
})
})
8 changes: 8 additions & 0 deletions test/testHelpers/search/searchServiceHelper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { SearchService } from '../../../src/search/domain/models/SearchService'

export const createSearchServiceModelArray = (count: number): SearchService[] => {
return Array.from({ length: count }, (_, index) => ({
name: `role${index + 1}`,
displayName: `Role ${index + 1}`
}))
}
10 changes: 9 additions & 1 deletion test/unit/collections/GetCollectionItems.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ describe('execute', () => {
undefined,
undefined,
undefined,
undefined,
false
)
expect(actual).toEqual(testItemSubset)
Expand All @@ -71,6 +72,7 @@ describe('execute', () => {
limit,
undefined,
undefined,
undefined,
false
)
expect(actual).toEqual(testItemSubset)
Expand All @@ -87,6 +89,7 @@ describe('execute', () => {
undefined,
offset,
undefined,
undefined,
false
)
expect(actual).toEqual(testItemSubset)
Expand All @@ -103,14 +106,15 @@ describe('execute', () => {
undefined,
undefined,
searchCriteria,
false
undefined
)

expect(collectionRepositoryStub.getCollectionItems).toHaveBeenCalledWith(
undefined,
undefined,
undefined,
searchCriteria,
undefined,
false
)
expect(actual).toEqual(testItemSubset)
Expand All @@ -136,6 +140,7 @@ describe('execute', () => {
undefined,
undefined,
undefined,
undefined,
showTypeCounts
)

Expand All @@ -144,6 +149,7 @@ describe('execute', () => {
undefined,
undefined,
undefined,
undefined,
showTypeCounts
)
expect(actual).toEqual(testItemSubsetWithCount)
Expand All @@ -164,6 +170,7 @@ describe('execute', () => {
limit,
offset,
searchCriteria,
undefined,
false
)

Expand All @@ -172,6 +179,7 @@ describe('execute', () => {
limit,
offset,
searchCriteria,
undefined,
false
)
expect(actual).toEqual(testItemSubset)
Expand Down
25 changes: 25 additions & 0 deletions test/unit/search/GetSearchServices.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { ReadError } from '../../../src'
import { ISearchServicesRepository } from '../../../src/search/domain/repositories/ISearchServicesRepository'
import { GetSearchServices } from '../../../src/search/domain/useCases/GetSearchServices'
import { createSearchServiceModelArray } from '../../testHelpers/search/searchServiceHelper'

describe('execute', () => {
test('should return search services array on repository success', async () => {
const searchServicesRepositoryStub: ISearchServicesRepository = {} as ISearchServicesRepository
const testServices = createSearchServiceModelArray(5)
searchServicesRepositoryStub.getSearchServices = jest.fn().mockResolvedValue(testServices)
const sut = new GetSearchServices(searchServicesRepositoryStub)

const actual = await sut.execute()

expect(actual).toEqual(testServices)
})

test('should return error result on repository error', async () => {
const searchServicesRepositoryStub: ISearchServicesRepository = {} as ISearchServicesRepository
searchServicesRepositoryStub.getSearchServices = jest.fn().mockRejectedValue(new ReadError())
const sut = new GetSearchServices(searchServicesRepositoryStub)

await expect(sut.execute()).rejects.toThrow(ReadError)
})
})