[CST-3088] Refactored VocabularyService to use VocabularyOptions and added more methods

This commit is contained in:
Giuseppe Digilio
2020-06-29 22:18:10 +02:00
parent df26b85c50
commit 4cc1a3eecd
5 changed files with 255 additions and 47 deletions

View File

@@ -1,4 +1,4 @@
import { Inject, Injectable } from '@angular/core';
import { Injectable } from '@angular/core';
import { deepClone } from 'fast-json-patch';
import { DSOResponseParsingService } from '../data/dso-response-parsing.service';
@@ -113,7 +113,7 @@ export class SubmissionResponseParsingService extends BaseResponseParsingService
return new ErrorResponse(
Object.assign(
new Error('Unexpected response from server'),
{statusCode: data.statusCode, statusText: data.statusText}
{ statusCode: data.statusCode, statusText: data.statusText }
)
);
}
@@ -133,7 +133,7 @@ export class SubmissionResponseParsingService extends BaseResponseParsingService
processedList.forEach((item) => {
item = Object.assign({}, item);
// item = Object.assign({}, item);
// In case data is an Instance of WorkspaceItem normalize field value of all the section of type form
if (item instanceof WorkspaceItem
|| item instanceof WorkflowItem) {

View File

@@ -8,16 +8,15 @@ import { isNotEmpty } from '../../../../shared/empty.util';
*/
export class VocabularyFindOptions extends FindListOptions {
constructor(public collection: string = '',
public name: string = '',
public metadata: string = '',
constructor(public collection,
public metadata,
public query: string = '',
public filter?: string,
public exact?: boolean,
public entryID?: string,
public elementsPerPage?: number,
public currentPage?: number,
public sort?: SortOptions,
public filter?: string,
public exact?: string,
public entryID?: string,
public sort?: SortOptions
) {
super();
@@ -35,7 +34,7 @@ export class VocabularyFindOptions extends FindListOptions {
searchParams.push(new RequestParam('filter', filter))
}
if (isNotEmpty(exact)) {
searchParams.push(new RequestParam('exact', exact))
searchParams.push(new RequestParam('exact', exact.toString()))
}
if (isNotEmpty(entryID)) {
searchParams.push(new RequestParam('entryID', entryID))

View File

@@ -9,7 +9,7 @@ import { RemoteDataBuildService } from '../../cache/builders/remote-data-build.s
import { ObjectCacheService } from '../../cache/object-cache.service';
import { HALEndpointService } from '../../shared/hal-endpoint.service';
import { RequestService } from '../../data/request.service';
import { VocabularyEntriesRequest } from '../../data/request.models';
import { FindListOptions, VocabularyEntriesRequest } from '../../data/request.models';
import { RequestParam } from '../../cache/models/request-param.model';
import { PageInfo } from '../../shared/page-info.model';
import { PaginatedList } from '../../data/paginated-list';
@@ -19,7 +19,7 @@ import { RestResponse } from '../../cache/response.models';
import { VocabularyService } from './vocabulary.service';
import { getMockRequestService } from '../../../shared/mocks/request.service.mock';
import { getMockRemoteDataBuildService } from '../../../shared/mocks/remote-data-build.service.mock';
import { VocabularyFindOptions } from './models/vocabulary-find-options.model';
import { VocabularyOptions } from './models/vocabulary-options.model';
describe('VocabularyService', () => {
let scheduler: TestScheduler;
@@ -143,10 +143,18 @@ describe('VocabularyService', () => {
const vocabularyId = 'types';
const metadata = 'dc.type';
const collectionUUID = '8b39g7ya-5a4b-438b-851f-be1d5b4a1c5a';
const vocabularyOptions = new VocabularyFindOptions(collectionUUID, vocabularyId, metadata);
const entryID = 'dsfsfsdf-5a4b-438b-851f-be1d5b4a1c5a';
const searchRequestURL = `https://rest.api/rest/api/submission/vocabularies/search/byMetadataAndCollection?metadata=${metadata}&collection=${collectionUUID}`;
const entriesRequestURL = `https://rest.api/rest/api/submission/vocabularies/${vocabulary.id}/entries?metadata=${metadata}&collection=${collectionUUID}`;
const entriesByValueRequestURL = `https://rest.api/rest/api/submission/vocabularies/${vocabulary.id}/entries?metadata=${metadata}&collection=${collectionUUID}&filter=test&exact=false`;
const entryByValueRequestURL = `https://rest.api/rest/api/submission/vocabularies/${vocabulary.id}/entries?metadata=${metadata}&collection=${collectionUUID}&filter=test&exact=true`;
const entryByIDRequestURL = `https://rest.api/rest/api/submission/vocabularies/${vocabulary.id}/entries?metadata=${metadata}&collection=${collectionUUID}&entryID=${entryID}`;
const vocabularyOptions: VocabularyOptions = {
name: vocabularyId,
metadata: metadata,
scope: collectionUUID,
closed: false
}
const pageInfo = new PageInfo();
const array = [vocabulary, hierarchicalVocabulary];
const arrayEntries = [vocabularyEntryDetail, anotherVocabularyEntryDetail];
@@ -274,11 +282,6 @@ describe('VocabularyService', () => {
describe('searchVocabularyByMetadataAndCollection', () => {
it('should proxy the call to vocabularyDataService.findVocabularyByHref', () => {
const options = new VocabularyFindOptions();
options.searchParams = [
new RequestParam('metadata', metadata),
new RequestParam('collection', collectionUUID)
];
scheduler.schedule(() => service.searchVocabularyByMetadataAndCollection(vocabularyOptions).subscribe());
scheduler.flush();
@@ -307,20 +310,103 @@ describe('VocabularyService', () => {
it('should configure a new VocabularyEntriesRequest', () => {
const expected = new VocabularyEntriesRequest(requestService.generateRequestId(), entriesRequestURL);
scheduler.schedule(() => service.getVocabularyEntries(vocabularyOptions).subscribe());
scheduler.schedule(() => service.getVocabularyEntries(vocabularyOptions, pageInfo).subscribe());
scheduler.flush();
expect(requestService.configure).toHaveBeenCalledWith(expected);
});
it('should call RemoteDataBuildService to create the RemoteData Observable', () => {
service.getVocabularyEntries(vocabularyOptions);
service.getVocabularyEntries(vocabularyOptions, pageInfo);
expect(rdbService.toRemoteDataObservable).toHaveBeenCalled();
});
});
describe('', () => {
beforeEach(() => {
requestService = getMockRequestService(getRequestEntry$(true));
rdbService = getMockRemoteDataBuildService();
spyOn(rdbService, 'toRemoteDataObservable').and.callThrough();
service = initTestService();
});
describe('getVocabularyEntries', () => {
it('should configure a new VocabularyEntriesRequest', () => {
const expected = new VocabularyEntriesRequest(requestService.generateRequestId(), entriesRequestURL);
scheduler.schedule(() => service.getVocabularyEntries(vocabularyOptions, pageInfo).subscribe());
scheduler.flush();
expect(requestService.configure).toHaveBeenCalledWith(expected);
});
it('should call RemoteDataBuildService to create the RemoteData Observable', () => {
service.getVocabularyEntries(vocabularyOptions, pageInfo);
expect(rdbService.toRemoteDataObservable).toHaveBeenCalled();
});
});
describe('getVocabularyEntriesByValue', () => {
it('should configure a new VocabularyEntriesRequest', () => {
const expected = new VocabularyEntriesRequest(requestService.generateRequestId(), entriesByValueRequestURL);
scheduler.schedule(() => service.getVocabularyEntriesByValue('test', false, vocabularyOptions, pageInfo).subscribe());
scheduler.flush();
expect(requestService.configure).toHaveBeenCalledWith(expected);
});
it('should call RemoteDataBuildService to create the RemoteData Observable', () => {
service.getVocabularyEntriesByValue('test', false, vocabularyOptions, pageInfo);
expect(rdbService.toRemoteDataObservable).toHaveBeenCalled();
});
});
describe('getVocabularyEntryByValue', () => {
it('should configure a new VocabularyEntriesRequest', () => {
const expected = new VocabularyEntriesRequest(requestService.generateRequestId(), entryByValueRequestURL);
scheduler.schedule(() => service.getVocabularyEntryByValue('test', vocabularyOptions).subscribe());
scheduler.flush();
expect(requestService.configure).toHaveBeenCalledWith(expected);
});
it('should call RemoteDataBuildService to create the RemoteData Observable', () => {
service.getVocabularyEntryByValue('test', vocabularyOptions);
expect(rdbService.toRemoteDataObservable).toHaveBeenCalled();
});
});
describe('getVocabularyEntryByID', () => {
it('should configure a new VocabularyEntriesRequest', () => {
const expected = new VocabularyEntriesRequest(requestService.generateRequestId(), entryByIDRequestURL);
scheduler.schedule(() => service.getVocabularyEntryByID(entryID, vocabularyOptions).subscribe());
scheduler.flush();
expect(requestService.configure).toHaveBeenCalledWith(expected);
});
it('should call RemoteDataBuildService to create the RemoteData Observable', () => {
service.getVocabularyEntryByID('test', vocabularyOptions);
expect(rdbService.toRemoteDataObservable).toHaveBeenCalled();
});
});
});
});
describe('vocabularyEntryDetails endpoint', () => {
@@ -400,16 +486,16 @@ describe('VocabularyService', () => {
describe('searchByGroup', () => {
it('should proxy the call to vocabularyEntryDetailDataService.searchBy', () => {
const options = new VocabularyFindOptions();
options.searchParams.push(new RequestParam('vocabulary', 'srsc'));
scheduler.schedule(() => service.searchTopEntries('srsc', new VocabularyFindOptions()));
const options = new FindListOptions();
options.searchParams = [new RequestParam('vocabulary', 'srsc')];
scheduler.schedule(() => service.searchTopEntries('srsc', pageInfo));
scheduler.flush();
expect((service as any).vocabularyEntryDetailDataService.searchBy).toHaveBeenCalledWith((service as any).searchTopMethod, options);
});
it('should return a RemoteData<PaginatedList<ResourcePolicy>) for the search', () => {
const result = service.searchTopEntries('srsc', new VocabularyFindOptions());
const result = service.searchTopEntries('srsc', pageInfo);
const expected = cold('a|', {
a: entriesPaginatedListRD
});

View File

@@ -22,12 +22,19 @@ import { PaginatedList } from '../../data/paginated-list';
import { Vocabulary } from './models/vocabulary.model';
import { VOCABULARY } from './models/vocabularies.resource-type';
import { VocabularyEntry } from './models/vocabulary-entry.model';
import { hasValue, isNotEmptyOperator } from '../../../shared/empty.util';
import { configureRequest, filterSuccessfulResponses, getRequestFromRequestHref } from '../../shared/operators';
import { hasValue, isNotEmpty, isNotEmptyOperator } from '../../../shared/empty.util';
import {
configureRequest,
filterSuccessfulResponses,
getFirstSucceededRemoteListPayload,
getRequestFromRequestHref
} from '../../shared/operators';
import { GenericSuccessResponse } from '../../cache/response.models';
import { VocabularyFindOptions } from './models/vocabulary-find-options.model';
import { VocabularyEntryDetail } from './models/vocabulary-entry-detail.model';
import { RequestParam } from '../../cache/models/request-param.model';
import { VocabularyOptions } from './models/vocabulary-options.model';
import { PageInfo } from '../../shared/page-info.model';
/* tslint:disable:max-classes-per-file */
@@ -110,20 +117,20 @@ export class VocabularyService {
/**
* Returns an observable of {@link RemoteData} of a {@link Vocabulary}, based on its ID, with a list of {@link FollowLinkConfig},
* to automatically resolve {@link HALLink}s of the object
* @param id ID of {@link Vocabulary} we want to retrieve
* @param name The name of {@link Vocabulary} we want to retrieve
* @param linksToFollow List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved
* @return {Observable<RemoteData<Vocabulary>>}
* Return an observable that emits vocabulary object
*/
findVocabularyById(id: string, ...linksToFollow: Array<FollowLinkConfig<Vocabulary>>): Observable<RemoteData<Vocabulary>> {
return this.vocabularyDataService.findById(id, ...linksToFollow);
findVocabularyById(name: string, ...linksToFollow: Array<FollowLinkConfig<Vocabulary>>): Observable<RemoteData<Vocabulary>> {
return this.vocabularyDataService.findById(name, ...linksToFollow);
}
/**
* Returns {@link RemoteData} of all object with a list of {@link FollowLinkConfig}, to indicate which embedded
* info should be added to the objects
*
* @param options Find list options object
* @param options Find list options object
* @param linksToFollow List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved
* @return {Observable<RemoteData<PaginatedList<Vocabulary>>>}
* Return an observable that emits object list
@@ -135,28 +142,131 @@ export class VocabularyService {
/**
* Return the {@link VocabularyEntry} list for a given {@link Vocabulary}
*
* @param options The {@link VocabularyFindOptions} for the request
* @param vocabularyOptions The {@link VocabularyOptions} for the request to which the entries belong
* @param pageInfo The {@link PageInfo} for the request
* @return {Observable<RemoteData<PaginatedList<VocabularyEntry>>>}
* Return an observable that emits object list
*/
getVocabularyEntries(options: VocabularyFindOptions): Observable<RemoteData<PaginatedList<VocabularyEntry>>> {
getVocabularyEntries(vocabularyOptions: VocabularyOptions, pageInfo: PageInfo): Observable<RemoteData<PaginatedList<VocabularyEntry>>> {
return this.vocabularyDataService.getFindAllHref(options, `${options.name}/entries`).pipe(
const options: VocabularyFindOptions = new VocabularyFindOptions(
vocabularyOptions.scope,
vocabularyOptions.metadata,
null,
null,
null,
null,
pageInfo.elementsPerPage,
pageInfo.currentPage
);
return this.vocabularyDataService.getFindAllHref(options, `${vocabularyOptions.name}/entries`).pipe(
isNotEmptyOperator(),
distinctUntilChanged(),
getVocabularyEntriesFor(this.requestService, this.rdbService)
);
}
/**
* Return the {@link VocabularyEntry} list for a given {@link Vocabulary}
*
* @param value The entry value to retrieve
* @param exact If true force the vocabulary to provide only entries that match exactly with the value
* @param vocabularyOptions The {@link VocabularyOptions} for the request to which the entries belong
* @param pageInfo The {@link PageInfo} for the request
* @return {Observable<RemoteData<PaginatedList<VocabularyEntry>>>}
* Return an observable that emits object list
*/
getVocabularyEntriesByValue(value: string, exact: boolean, vocabularyOptions: VocabularyOptions, pageInfo: PageInfo): Observable<RemoteData<PaginatedList<VocabularyEntry>>> {
const options: VocabularyFindOptions = new VocabularyFindOptions(
vocabularyOptions.scope,
vocabularyOptions.metadata,
null,
value,
exact,
null,
pageInfo.elementsPerPage,
pageInfo.currentPage
);
return this.vocabularyDataService.getFindAllHref(options, `${vocabularyOptions.name}/entries`).pipe(
isNotEmptyOperator(),
distinctUntilChanged(),
getVocabularyEntriesFor(this.requestService, this.rdbService)
);
}
/**
* Return the {@link VocabularyEntry} list for a given value
*
* @param value The entry value to retrieve
* @param vocabularyOptions The {@link VocabularyOptions} for the request to which the entry belongs
* @return {Observable<RemoteData<PaginatedList<VocabularyEntry>>>}
* Return an observable that emits {@link VocabularyEntry} object
*/
getVocabularyEntryByValue(value: string, vocabularyOptions: VocabularyOptions): Observable<VocabularyEntry> {
return this.getVocabularyEntriesByValue(value, true, vocabularyOptions, new PageInfo()).pipe(
getFirstSucceededRemoteListPayload(),
map((list: VocabularyEntry[]) => {
if (isNotEmpty(list)) {
return list[0]
} else {
return null;
}
})
);
}
/**
* Return the {@link VocabularyEntry} list for a given ID
*
* @param ID The entry ID to retrieve
* @param vocabularyOptions The {@link VocabularyOptions} for the request to which the entry belongs
* @return {Observable<RemoteData<PaginatedList<VocabularyEntry>>>}
* Return an observable that emits {@link VocabularyEntry} object
*/
getVocabularyEntryByID(ID: string, vocabularyOptions: VocabularyOptions): Observable<VocabularyEntry> {
const pageInfo = new PageInfo()
const options: VocabularyFindOptions = new VocabularyFindOptions(
vocabularyOptions.scope,
vocabularyOptions.metadata,
null,
null,
null,
ID,
pageInfo.elementsPerPage,
pageInfo.currentPage
);
return this.vocabularyDataService.getFindAllHref(options, `${vocabularyOptions.name}/entries`).pipe(
isNotEmptyOperator(),
distinctUntilChanged(),
getVocabularyEntriesFor(this.requestService, this.rdbService),
getFirstSucceededRemoteListPayload(),
map((list: VocabularyEntry[]) => {
if (isNotEmpty(list)) {
return list[0]
} else {
return null;
}
})
);
}
/**
* Return the controlled {@link Vocabulary} configured for the specified metadata and collection if any.
*
* @param options The {@link VocabularyFindOptions} for the request
* @param linksToFollow List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved
* @param vocabularyOptions The {@link VocabularyOptions} for the request
* @param linksToFollow List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved
* @return {Observable<RemoteData<PaginatedList<Vocabulary>>>}
* Return an observable that emits object list
*/
searchVocabularyByMetadataAndCollection(options: VocabularyFindOptions, ...linksToFollow: Array<FollowLinkConfig<Vocabulary>>): Observable<RemoteData<Vocabulary>> {
searchVocabularyByMetadataAndCollection(vocabularyOptions: VocabularyOptions, ...linksToFollow: Array<FollowLinkConfig<Vocabulary>>): Observable<RemoteData<Vocabulary>> {
const options: VocabularyFindOptions = new VocabularyFindOptions(
vocabularyOptions.scope,
vocabularyOptions.metadata
);
return this.vocabularyDataService.getSearchByHref(this.searchByMetadataAndCollectionMethod, options).pipe(
first((href: string) => hasValue(href)),
@@ -193,12 +303,13 @@ export class VocabularyService {
/**
* Return the top level {@link VocabularyEntryDetail} list for a given hierarchical vocabulary
*
* @param name The name of hierarchical {@link Vocabulary} to which the entries belongs
* @param options The {@link VocabularyFindOptions} for the request
* @param name The name of hierarchical {@link Vocabulary} to which the entries belongs
* @param pageInfo The {@link PageInfo} for the request
* @param linksToFollow List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved
*/
searchTopEntries(name: string, options: VocabularyFindOptions, ...linksToFollow: Array<FollowLinkConfig<VocabularyEntryDetail>>): Observable<RemoteData<PaginatedList<VocabularyEntryDetail>>> {
options.searchParams.push(new RequestParam('vocabulary', name));
searchTopEntries(name: string, pageInfo: PageInfo, ...linksToFollow: Array<FollowLinkConfig<VocabularyEntryDetail>>): Observable<RemoteData<PaginatedList<VocabularyEntryDetail>>> {
const options = new FindListOptions();
options.searchParams = [new RequestParam('vocabulary', name)];
return this.vocabularyEntryDetailDataService.searchBy(this.searchTopMethod, options, ...linksToFollow)
}
}

View File

@@ -1,18 +1,18 @@
import { Observable } from 'rxjs';
import { Observable, of as observableOf } from 'rxjs';
import { VocabularyFindOptions } from '../../core/submission/vocabularies/models/vocabulary-find-options.model';
import { PageInfo } from '../../core/shared/page-info.model';
import { VocabularyEntry } from '../../core/submission/vocabularies/models/vocabulary-entry.model';
import { PaginatedList } from '../../core/data/paginated-list';
import { createSuccessfulRemoteDataObject$ } from '../remote-data.utils';
import { RemoteData } from '../../core/data/remote-data';
import { VocabularyOptions } from '../../core/submission/vocabularies/models/vocabulary-options.model';
export class VocabularyServiceStub {
private _payload = [
Object.assign(new VocabularyEntry(),{authority: 1, display: 'one', value: 1}),
Object.assign(new VocabularyEntry(),{authority: 2, display: 'two', value: 2}),
Object.assign(new VocabularyEntry(), { authority: 1, display: 'one', value: 1 }),
Object.assign(new VocabularyEntry(), { authority: 2, display: 'two', value: 2 }),
];
setNewPayload(payload) {
@@ -23,7 +23,19 @@ export class VocabularyServiceStub {
return this._payload
}
getVocabularyEntries(options: VocabularyFindOptions): Observable<RemoteData<PaginatedList<VocabularyEntry>>> {
getVocabularyEntries(vocabularyOptions: VocabularyOptions, pageInfo: PageInfo): Observable<RemoteData<PaginatedList<VocabularyEntry>>> {
return createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), this._payload));
}
getVocabularyEntriesByValue(value: string, exact: boolean, vocabularyOptions: VocabularyOptions, pageInfo: PageInfo): Observable<RemoteData<PaginatedList<VocabularyEntry>>> {
return createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), this._payload));
}
getVocabularyEntryByValue(value: string, vocabularyOptions: VocabularyOptions): Observable<VocabularyEntry> {
return observableOf(Object.assign(new VocabularyEntry(), { authority: 1, display: 'one', value: 1 }));
}
getVocabularyEntryByID(id: string, vocabularyOptions: VocabularyOptions): Observable<VocabularyEntry> {
return observableOf(Object.assign(new VocabularyEntry(), { authority: 1, display: 'one', value: 1 }));
}
}