50463: use search/facet endpoint to retrieve facet values

This commit is contained in:
Lotte Hofstede
2018-03-20 11:39:51 +01:00
parent 3f36e0371e
commit cdf1dc402a
18 changed files with 236 additions and 97 deletions

View File

@@ -117,7 +117,7 @@
"placeholder": "Subject", "placeholder": "Subject",
"head": "Subject" "head": "Subject"
}, },
"date": { "dateIssued": {
"placeholder": "Date", "placeholder": "Date",
"head": "Date" "head": "Date"
} }

View File

@@ -6,6 +6,7 @@ import { FacetValue } from '../../search-service/facet-value.model';
import { SearchFilterService } from './search-filter.service'; import { SearchFilterService } from './search-filter.service';
import { Observable } from 'rxjs/Observable'; import { Observable } from 'rxjs/Observable';
import { slide } from '../../../shared/animations/slide'; import { slide } from '../../../shared/animations/slide';
import { PaginatedList } from '../../../core/data/paginated-list';
/** /**
* This component renders a simple item page. * This component renders a simple item page.
@@ -22,13 +23,13 @@ import { slide } from '../../../shared/animations/slide';
export class SearchFilterComponent implements OnInit { export class SearchFilterComponent implements OnInit {
@Input() filter: SearchFilterConfig; @Input() filter: SearchFilterConfig;
filterValues: Observable<RemoteData<FacetValue[]>>; filterValues: Observable<RemoteData<FacetValue[] | PaginatedList<FacetValue>>>;
constructor(private searchService: SearchService, private filterService: SearchFilterService) { constructor(private searchService: SearchService, private filterService: SearchFilterService) {
} }
ngOnInit() { ngOnInit() {
this.filterValues = this.searchService.getFacetValuesFor(this.filter.name); this.filterValues = this.searchService.getFacetValuesFor(this.filter.name, '', '');
const sub = this.filterService.isFilterActive(this.filter.paramName).first().subscribe((isActive) => { const sub = this.filterService.isFilterActive(this.filter.paramName).first().subscribe((isActive) => {
if (this.filter.isOpenByDefault || isActive) { if (this.filter.isOpenByDefault || isActive) {
this.initialExpand(); this.initialExpand();

View File

@@ -1,7 +1,13 @@
import { autoserialize, autoserializeAs } from 'cerialize';
export class FacetValue { export class FacetValue {
@autoserializeAs(String, 'label')
value: string; value: string;
@autoserialize
count: number; count: number;
@autoserialize
search: string; search: string;
} }

View File

@@ -1,13 +1,14 @@
import { Inject, Injectable, OnDestroy } from '@angular/core'; import { Injectable, OnDestroy } from '@angular/core';
import { ActivatedRoute, NavigationExtras, Router } from '@angular/router'; import { ActivatedRoute, NavigationExtras, Router } from '@angular/router';
import { Observable } from 'rxjs/Observable'; import { Observable } from 'rxjs/Observable';
import { flatMap, map, tap } from 'rxjs/operators'; import { flatMap, map, tap } from 'rxjs/operators';
import { ViewMode } from '../../+search-page/search-options.model'; import { ViewMode } from '../../+search-page/search-options.model';
import { GLOBAL_CONFIG } from '../../../config';
import { GlobalConfig } from '../../../config/global-config.interface';
import { RemoteDataBuildService } from '../../core/cache/builders/remote-data-build.service'; import { RemoteDataBuildService } from '../../core/cache/builders/remote-data-build.service';
import { SortOptions } from '../../core/cache/models/sort-options.model'; import { SortOptions } from '../../core/cache/models/sort-options.model';
import { SearchSuccessResponse } from '../../core/cache/response-cache.models'; import {
FacetValueMapSuccessResponse, FacetValueSuccessResponse,
SearchSuccessResponse
} from '../../core/cache/response-cache.models';
import { ResponseCacheEntry } from '../../core/cache/response-cache.reducer'; import { ResponseCacheEntry } from '../../core/cache/response-cache.reducer';
import { ResponseCacheService } from '../../core/cache/response-cache.service'; import { ResponseCacheService } from '../../core/cache/response-cache.service';
import { PaginatedList } from '../../core/data/paginated-list'; import { PaginatedList } from '../../core/data/paginated-list';
@@ -33,6 +34,7 @@ import { SearchQueryResponse } from './search-query-response.model';
import { PageInfo } from '../../core/shared/page-info.model'; import { PageInfo } from '../../core/shared/page-info.model';
import { getSearchResultFor } from './search-result-element-decorator'; import { getSearchResultFor } from './search-result-element-decorator';
import { ListableObject } from '../../shared/object-collection/shared/listable-object.model'; import { ListableObject } from '../../shared/object-collection/shared/listable-object.model';
import { FacetResponseParsingService } from '../../core/data/facet-response-parsing.service';
function shuffle(array: any[]) { function shuffle(array: any[]) {
let i = 0; let i = 0;
@@ -49,20 +51,21 @@ function shuffle(array: any[]) {
} }
@Injectable() @Injectable()
export class SearchService extends HALEndpointService implements OnDestroy { export class SearchService implements OnDestroy {
protected linkPath = 'discover/search/objects'; private searchLinkPath = 'discover/search/objects';
private facetLinkPath = 'discover/search/facets';
private sub; private sub;
uiSearchRoute = '/search'; uiSearchRoute = '/search';
config: SearchFilterConfig[] = [ config: SearchFilterConfig[] = [
Object.assign(new SearchFilterConfig(), // Object.assign(new SearchFilterConfig(),
{ // {
name: 'scope', // name: 'scope',
type: FilterType.hierarchy, // type: FilterType.hierarchy,
hasFacets: true, // hasFacets: true,
isOpenByDefault: true // isOpenByDefault: true
}), // }),
Object.assign(new SearchFilterConfig(), Object.assign(new SearchFilterConfig(),
{ {
name: 'author', name: 'author',
@@ -72,7 +75,7 @@ export class SearchService extends HALEndpointService implements OnDestroy {
}), }),
Object.assign(new SearchFilterConfig(), Object.assign(new SearchFilterConfig(),
{ {
name: 'date', name: 'dateIssued',
type: FilterType.range, type: FilterType.range,
hasFacets: true, hasFacets: true,
isOpenByDefault: false isOpenByDefault: false
@@ -92,10 +95,9 @@ export class SearchService extends HALEndpointService implements OnDestroy {
private route: ActivatedRoute, private route: ActivatedRoute,
protected responseCache: ResponseCacheService, protected responseCache: ResponseCacheService,
protected requestService: RequestService, protected requestService: RequestService,
@Inject(GLOBAL_CONFIG) protected EnvConfig: GlobalConfig,
private routeService: RouteService, private routeService: RouteService,
private rdb: RemoteDataBuildService,) { private rdb: RemoteDataBuildService,
super(); private halService: HALEndpointService) {
const pagination: PaginationComponentOptions = new PaginationComponentOptions(); const pagination: PaginationComponentOptions = new PaginationComponentOptions();
pagination.id = 'search-results-pagination'; pagination.id = 'search-results-pagination';
pagination.currentPage = 1; pagination.currentPage = 1;
@@ -106,7 +108,7 @@ export class SearchService extends HALEndpointService implements OnDestroy {
} }
search(query: string, scopeId?: string, searchOptions?: SearchOptions): Observable<RemoteData<Array<SearchResult<DSpaceObject>> | PaginatedList<SearchResult<DSpaceObject>>>> { search(query: string, scopeId?: string, searchOptions?: SearchOptions): Observable<RemoteData<Array<SearchResult<DSpaceObject>> | PaginatedList<SearchResult<DSpaceObject>>>> {
const requestObs = this.getEndpoint().pipe( const requestObs = this.halService.getEndpoint(this.searchLinkPath).pipe(
map((url: string) => { map((url: string) => {
const args: string[] = []; const args: string[] = [];
@@ -219,35 +221,92 @@ export class SearchService extends HALEndpointService implements OnDestroy {
)); ));
} }
getFacetValuesFor(searchFilterConfigName: string): Observable<RemoteData<FacetValue[]>> { getFacetValuesFor(searchFilterConfigName: string, query: string, scopeId: string): Observable<RemoteData<FacetValue[] | PaginatedList<FacetValue>>> {
const filterConfig = this.config.find((config: SearchFilterConfig) => config.name === searchFilterConfigName); const requestObs = this.halService.getEndpoint(this.facetLinkPath).pipe(
return this.routeService.getQueryParameterValues(filterConfig.paramName).map((selectedValues: string[]) => { map((url: string) => {
const payload: FacetValue[] = []; const args: string[] = [];
const totalFilters = 13;
for (let i = 0; i < totalFilters; i++) { if (isNotEmpty(query)) {
const value = searchFilterConfigName + ' ' + (i + 1); args.push(`query=${query}`);
if (!selectedValues.includes(value)) {
payload.push({
value: value,
count: Math.floor(Math.random() * 20) + 20 * (totalFilters - i), // make sure first results have the highest (random) count
search: (decodeURI(this.router.url) + (this.router.url.includes('?') ? '&' : '?') + filterConfig.paramName + '=' + value)
} }
if (isNotEmpty(scopeId)) {
args.push(`scope=${scopeId}`);
}
if (isNotEmpty(args)) {
url = new URLCombiner(url, `?${args.join('&')}`).toString();
}
const request = new GetRequest(this.requestService.generateRequestId(), url);
return Object.assign(request, {
getResponseParser(): GenericConstructor<ResponseParsingService> {
return FacetResponseParsingService;
}
});
}),
tap((request: RestRequest) => this.requestService.configure(request)),
); );
const requestEntryObs = requestObs.pipe(
flatMap((request: RestRequest) => this.requestService.getByHref(request.href))
);
const responseCacheObs = requestObs.pipe(
flatMap((request: RestRequest) => this.responseCache.get(request.href))
);
// get search results from response cache
const facetValueResponseObs: Observable<FacetValueSuccessResponse> = responseCacheObs.pipe(
map((entry: ResponseCacheEntry) => entry.response),
map((response: FacetValueMapSuccessResponse) => response.results[searchFilterConfigName])
);
// get search results from response cache
const facetValueObs: Observable<FacetValue[]> = facetValueResponseObs.pipe(
map((response: FacetValueSuccessResponse) => response.results)
);
const pageInfoObs: Observable<PageInfo> = facetValueResponseObs.pipe(
map((response: FacetValueSuccessResponse) => { console.log(response); return response.pageInfo})
);
const payloadObs = Observable.combineLatest(facetValueObs, pageInfoObs, (facetValue, pageInfo) => {
if (hasValue(pageInfo)) {
return new PaginatedList(pageInfo, facetValue);
} else {
return facetValue;
} }
} });
const requestPending = false; return this.rdb.toRemoteDataObservable(requestEntryObs, responseCacheObs, payloadObs);
const responsePending = false;
const isSuccessful = true; // const filterConfig = this.config.find((config: SearchFilterConfig) => config.name === searchFilterConfigName);
const error = undefined; // return this.routeService.getQueryParameterValues(filterConfig.paramName).map((selectedValues: string[]) => {
return new RemoteData( // const payload: FacetValue[] = [];
requestPending, // const totalFilters = 13;
responsePending, // for (let i = 0; i < totalFilters; i++) {
isSuccessful, // const value = searchFilterConfigName + ' ' + (i + 1);
error, // if (!selectedValues.includes(value)) {
payload // payload.push({
) // value: value,
} // count: Math.floor(Math.random() * 20) + 20 * (totalFilters - i), // make sure first results have the highest (random) count
) // search: (decodeURI(this.router.url) + (this.router.url.includes('?') ? '&' : '?') + filterConfig.paramName + '=' + value)
// }
// );
// }
// }
// const requestPending = false;
// const responsePending = false;
// const isSuccessful = true;
// const error = undefined;
// return new RemoteData(
// requestPending,
// responsePending,
// isSuccessful,
// error,
// payload
// )
// }
// )
} }
getViewMode(): Observable<ViewMode> { getViewMode(): Observable<ViewMode> {

View File

@@ -12,7 +12,7 @@ import { BrowseDefinition } from '../shared/browse-definition.model';
import { HALEndpointService } from '../shared/hal-endpoint.service'; import { HALEndpointService } from '../shared/hal-endpoint.service';
@Injectable() @Injectable()
export class BrowseService extends HALEndpointService { export class BrowseService {
protected linkPath = 'browses'; protected linkPath = 'browses';
private static toSearchKeyArray(metadatumKey: string): string[] { private static toSearchKeyArray(metadatumKey: string): string[] {
@@ -31,13 +31,12 @@ export class BrowseService extends HALEndpointService {
constructor( constructor(
protected responseCache: ResponseCacheService, protected responseCache: ResponseCacheService,
protected requestService: RequestService, protected requestService: RequestService,
@Inject(GLOBAL_CONFIG) protected EnvConfig: GlobalConfig) { protected halService: HALEndpointService) {
super();
} }
getBrowseURLFor(metadatumKey: string, linkPath: string): Observable<string> { getBrowseURLFor(metadatumKey: string, linkPath: string): Observable<string> {
const searchKeyArray = BrowseService.toSearchKeyArray(metadatumKey); const searchKeyArray = BrowseService.toSearchKeyArray(metadatumKey);
return this.getEndpoint() return this.halService.getEndpoint(linkPath)
.filter((href: string) => isNotEmpty(href)) .filter((href: string) => isNotEmpty(href))
.distinctUntilChanged() .distinctUntilChanged()
.map((endpointURL: string) => new BrowseEndpointRequest(this.requestService.generateRequestId(), endpointURL)) .map((endpointURL: string) => new BrowseEndpointRequest(this.requestService.generateRequestId(), endpointURL))

View File

@@ -3,6 +3,7 @@ import { RequestError } from '../data/request.models';
import { PageInfo } from '../shared/page-info.model'; import { PageInfo } from '../shared/page-info.model';
import { BrowseDefinition } from '../shared/browse-definition.model'; import { BrowseDefinition } from '../shared/browse-definition.model';
import { ConfigObject } from '../shared/config/config.model'; import { ConfigObject } from '../shared/config/config.model';
import { FacetValue } from '../../+search-page/search-service/facet-value.model';
/* tslint:disable:max-classes-per-file */ /* tslint:disable:max-classes-per-file */
export class RestResponse { export class RestResponse {
@@ -32,6 +33,28 @@ export class SearchSuccessResponse extends RestResponse {
} }
} }
export class FacetValueMap {
[name: string]: FacetValueSuccessResponse
}
export class FacetValueSuccessResponse extends RestResponse {
constructor(
public results: FacetValue[],
public statusCode: string,
public pageInfo?: PageInfo) {
super(true, statusCode);
}
}
export class FacetValueMapSuccessResponse extends RestResponse {
constructor(
public results: FacetValueMap,
public statusCode: string,
) {
super(true, statusCode);
}
}
export class EndpointMap { export class EndpointMap {
[linkPath: string]: string [linkPath: string]: string
} }

View File

@@ -1,10 +1,7 @@
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable'; import { Observable } from 'rxjs/Observable';
import { RequestService } from '../data/request.service'; import { RequestService } from '../data/request.service';
import { ResponseCacheService } from '../cache/response-cache.service'; import { ResponseCacheService } from '../cache/response-cache.service';
import { GlobalConfig } from '../../../config/global-config.interface';
import { ConfigSuccessResponse, ErrorResponse, RestResponse } from '../cache/response-cache.models'; import { ConfigSuccessResponse, ErrorResponse, RestResponse } from '../cache/response-cache.models';
import { ConfigRequest, FindAllOptions, RestRequest } from '../data/request.models'; import { ConfigRequest, FindAllOptions, RestRequest } from '../data/request.models';
import { ResponseCacheEntry } from '../cache/response-cache.reducer'; import { ResponseCacheEntry } from '../cache/response-cache.reducer';
@@ -12,13 +9,13 @@ import { hasValue, isNotEmpty } from '../../shared/empty.util';
import { HALEndpointService } from '../shared/hal-endpoint.service'; import { HALEndpointService } from '../shared/hal-endpoint.service';
import { ConfigData } from './config-data'; import { ConfigData } from './config-data';
export abstract class ConfigService extends HALEndpointService { export abstract class ConfigService {
protected request: ConfigRequest; protected request: ConfigRequest;
protected abstract responseCache: ResponseCacheService; protected abstract responseCache: ResponseCacheService;
protected abstract requestService: RequestService; protected abstract requestService: RequestService;
protected abstract linkPath: string; protected abstract linkPath: string;
protected abstract EnvConfig: GlobalConfig;
protected abstract browseEndpoint: string; protected abstract browseEndpoint: string;
protected abstract halService: HALEndpointService;
protected getConfig(request: RestRequest): Observable<ConfigData> { protected getConfig(request: RestRequest): Observable<ConfigData> {
const [successResponse, errorResponse] = this.responseCache.get(request.href) const [successResponse, errorResponse] = this.responseCache.get(request.href)
@@ -68,7 +65,7 @@ export abstract class ConfigService extends HALEndpointService {
} }
public getConfigAll(): Observable<ConfigData> { public getConfigAll(): Observable<ConfigData> {
return this.getEndpoint() return this.halService.getEndpoint(this.linkPath)
.filter((href: string) => isNotEmpty(href)) .filter((href: string) => isNotEmpty(href))
.distinctUntilChanged() .distinctUntilChanged()
.map((endpointURL: string) => new ConfigRequest(this.requestService.generateRequestId(), endpointURL)) .map((endpointURL: string) => new ConfigRequest(this.requestService.generateRequestId(), endpointURL))
@@ -85,7 +82,7 @@ export abstract class ConfigService extends HALEndpointService {
} }
public getConfigByName(name: string): Observable<ConfigData> { public getConfigByName(name: string): Observable<ConfigData> {
return this.getEndpoint() return this.halService.getEndpoint(this.linkPath)
.map((endpoint: string) => this.getConfigByNameHref(endpoint, name)) .map((endpoint: string) => this.getConfigByNameHref(endpoint, name))
.filter((href: string) => isNotEmpty(href)) .filter((href: string) => isNotEmpty(href))
.distinctUntilChanged() .distinctUntilChanged()
@@ -96,7 +93,7 @@ export abstract class ConfigService extends HALEndpointService {
} }
public getConfigBySearch(options: FindAllOptions = {}): Observable<ConfigData> { public getConfigBySearch(options: FindAllOptions = {}): Observable<ConfigData> {
return this.getEndpoint() return this.halService.getEndpoint(this.linkPath)
.map((endpoint: string) => this.getConfigSearchHref(endpoint, options)) .map((endpoint: string) => this.getConfigSearchHref(endpoint, options))
.filter((href: string) => isNotEmpty(href)) .filter((href: string) => isNotEmpty(href))
.distinctUntilChanged() .distinctUntilChanged()

View File

@@ -1,10 +1,9 @@
import { Inject, Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { ConfigService } from './config.service'; import { ConfigService } from './config.service';
import { ResponseCacheService } from '../cache/response-cache.service'; import { ResponseCacheService } from '../cache/response-cache.service';
import { RequestService } from '../data/request.service'; import { RequestService } from '../data/request.service';
import { GLOBAL_CONFIG } from '../../../config'; import { HALEndpointService } from '../shared/hal-endpoint.service';
import { GlobalConfig } from '../../../config/global-config.interface';
@Injectable() @Injectable()
export class SubmissionDefinitionsConfigService extends ConfigService { export class SubmissionDefinitionsConfigService extends ConfigService {
@@ -14,7 +13,7 @@ export class SubmissionDefinitionsConfigService extends ConfigService {
constructor( constructor(
protected responseCache: ResponseCacheService, protected responseCache: ResponseCacheService,
protected requestService: RequestService, protected requestService: RequestService,
@Inject(GLOBAL_CONFIG) protected EnvConfig: GlobalConfig) { protected halService: HALEndpointService) {
super(); super();
} }

View File

@@ -1,10 +1,9 @@
import { Inject, Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { ConfigService } from './config.service'; import { ConfigService } from './config.service';
import { ResponseCacheService } from '../cache/response-cache.service'; import { ResponseCacheService } from '../cache/response-cache.service';
import { RequestService } from '../data/request.service'; import { RequestService } from '../data/request.service';
import { GLOBAL_CONFIG } from '../../../config'; import { HALEndpointService } from '../shared/hal-endpoint.service';
import { GlobalConfig } from '../../../config/global-config.interface';
@Injectable() @Injectable()
export class SubmissionFormsConfigService extends ConfigService { export class SubmissionFormsConfigService extends ConfigService {
@@ -14,7 +13,7 @@ export class SubmissionFormsConfigService extends ConfigService {
constructor( constructor(
protected responseCache: ResponseCacheService, protected responseCache: ResponseCacheService,
protected requestService: RequestService, protected requestService: RequestService,
@Inject(GLOBAL_CONFIG) protected EnvConfig: GlobalConfig) { protected halService: HALEndpointService) {
super(); super();
} }

View File

@@ -1,10 +1,9 @@
import { Inject, Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { ConfigService } from './config.service'; import { ConfigService } from './config.service';
import { ResponseCacheService } from '../cache/response-cache.service'; import { ResponseCacheService } from '../cache/response-cache.service';
import { RequestService } from '../data/request.service'; import { RequestService } from '../data/request.service';
import { GLOBAL_CONFIG } from '../../../config'; import { HALEndpointService } from '../shared/hal-endpoint.service';
import { GlobalConfig } from '../../../config/global-config.interface';
@Injectable() @Injectable()
export class SubmissionSectionsConfigService extends ConfigService { export class SubmissionSectionsConfigService extends ConfigService {
@@ -14,7 +13,7 @@ export class SubmissionSectionsConfigService extends ConfigService {
constructor( constructor(
protected responseCache: ResponseCacheService, protected responseCache: ResponseCacheService,
protected requestService: RequestService, protected requestService: RequestService,
@Inject(GLOBAL_CONFIG) protected EnvConfig: GlobalConfig) { protected halService: HALEndpointService) {
super(); super();
} }

View File

@@ -40,6 +40,8 @@ import { SubmissionDefinitionsConfigService } from './config/submission-definiti
import { SubmissionFormsConfigService } from './config/submission-forms-config.service'; import { SubmissionFormsConfigService } from './config/submission-forms-config.service';
import { SubmissionSectionsConfigService } from './config/submission-sections-config.service'; import { SubmissionSectionsConfigService } from './config/submission-sections-config.service';
import { UUIDService } from './shared/uuid.service'; import { UUIDService } from './shared/uuid.service';
import { HALEndpointService } from './shared/hal-endpoint.service';
import { FacetResponseParsingService } from './data/facet-response-parsing.service';
const IMPORTS = [ const IMPORTS = [
CommonModule, CommonModule,
@@ -61,6 +63,7 @@ const PROVIDERS = [
CollectionDataService, CollectionDataService,
DSOResponseParsingService, DSOResponseParsingService,
DSpaceRESTv2Service, DSpaceRESTv2Service,
HALEndpointService,
HostWindowService, HostWindowService,
ItemDataService, ItemDataService,
MetadataService, MetadataService,
@@ -70,6 +73,7 @@ const PROVIDERS = [
RequestService, RequestService,
ResponseCacheService, ResponseCacheService,
EndpointMapResponseParsingService, EndpointMapResponseParsingService,
FacetResponseParsingService,
DebugResponseParsingService, DebugResponseParsingService,
SearchResponseParsingService, SearchResponseParsingService,
ServerResponseService, ServerResponseService,

View File

@@ -10,6 +10,7 @@ import { Collection } from '../shared/collection.model';
import { ComColDataService } from './comcol-data.service'; import { ComColDataService } from './comcol-data.service';
import { CommunityDataService } from './community-data.service'; import { CommunityDataService } from './community-data.service';
import { RequestService } from './request.service'; import { RequestService } from './request.service';
import { HALEndpointService } from '../shared/hal-endpoint.service';
@Injectable() @Injectable()
export class CollectionDataService extends ComColDataService<NormalizedCollection, Collection> { export class CollectionDataService extends ComColDataService<NormalizedCollection, Collection> {
@@ -20,9 +21,9 @@ export class CollectionDataService extends ComColDataService<NormalizedCollectio
protected requestService: RequestService, protected requestService: RequestService,
protected rdbService: RemoteDataBuildService, protected rdbService: RemoteDataBuildService,
protected store: Store<CoreState>, protected store: Store<CoreState>,
@Inject(GLOBAL_CONFIG) protected EnvConfig: GlobalConfig,
protected cds: CommunityDataService, protected cds: CommunityDataService,
protected objectCache: ObjectCacheService protected objectCache: ObjectCacheService,
protected halService: HALEndpointService
) { ) {
super(); super();
} }

View File

@@ -10,10 +10,12 @@ import { CommunityDataService } from './community-data.service';
import { DataService } from './data.service'; import { DataService } from './data.service';
import { FindByIDRequest } from './request.models'; import { FindByIDRequest } from './request.models';
import { NormalizedObject } from '../cache/models/normalized-object.model'; import { NormalizedObject } from '../cache/models/normalized-object.model';
import { HALEndpointService } from '../shared/hal-endpoint.service';
export abstract class ComColDataService<TNormalized extends NormalizedObject, TDomain> extends DataService<TNormalized, TDomain> { export abstract class ComColDataService<TNormalized extends NormalizedObject, TDomain> extends DataService<TNormalized, TDomain> {
protected abstract cds: CommunityDataService; protected abstract cds: CommunityDataService;
protected abstract objectCache: ObjectCacheService; protected abstract objectCache: ObjectCacheService;
protected abstract halService: HALEndpointService;
/** /**
* Get the scoped endpoint URL by fetching the object with * Get the scoped endpoint URL by fetching the object with
@@ -27,7 +29,7 @@ export abstract class ComColDataService<TNormalized extends NormalizedObject, TD
*/ */
public getScopedEndpoint(scopeID: string): Observable<string> { public getScopedEndpoint(scopeID: string): Observable<string> {
if (isEmpty(scopeID)) { if (isEmpty(scopeID)) {
return this.getEndpoint(); return this.halService.getEndpoint(this.linkPath);
} else { } else {
const scopeCommunityHrefObs = this.cds.getEndpoint() const scopeCommunityHrefObs = this.cds.getEndpoint()
.flatMap((endpoint: string) => this.cds.getFindByIDHref(endpoint, scopeID)) .flatMap((endpoint: string) => this.cds.getFindByIDHref(endpoint, scopeID))

View File

@@ -10,6 +10,7 @@ import { CoreState } from '../core.reducers';
import { Community } from '../shared/community.model'; import { Community } from '../shared/community.model';
import { ComColDataService } from './comcol-data.service'; import { ComColDataService } from './comcol-data.service';
import { RequestService } from './request.service'; import { RequestService } from './request.service';
import { HALEndpointService } from '../shared/hal-endpoint.service';
@Injectable() @Injectable()
export class CommunityDataService extends ComColDataService<NormalizedCommunity, Community> { export class CommunityDataService extends ComColDataService<NormalizedCommunity, Community> {
@@ -21,9 +22,13 @@ export class CommunityDataService extends ComColDataService<NormalizedCommunity,
protected requestService: RequestService, protected requestService: RequestService,
protected rdbService: RemoteDataBuildService, protected rdbService: RemoteDataBuildService,
protected store: Store<CoreState>, protected store: Store<CoreState>,
@Inject(GLOBAL_CONFIG) protected EnvConfig: GlobalConfig, protected objectCache: ObjectCacheService,
protected objectCache: ObjectCacheService protected halService: HALEndpointService
) { ) {
super(); super();
} }
getEndpoint() {
return this.halService.getEndpoint(this.linkPath);
}
} }

View File

@@ -1,11 +1,9 @@
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { Observable } from 'rxjs/Observable'; import { Observable } from 'rxjs/Observable';
import { GlobalConfig } from '../../../config';
import { hasValue, isNotEmpty } from '../../shared/empty.util'; import { hasValue, isNotEmpty } from '../../shared/empty.util';
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
import { ResponseCacheService } from '../cache/response-cache.service'; import { ResponseCacheService } from '../cache/response-cache.service';
import { CoreState } from '../core.reducers'; import { CoreState } from '../core.reducers';
import { GenericConstructor } from '../shared/generic-constructor';
import { HALEndpointService } from '../shared/hal-endpoint.service'; import { HALEndpointService } from '../shared/hal-endpoint.service';
import { URLCombiner } from '../url-combiner/url-combiner'; import { URLCombiner } from '../url-combiner/url-combiner';
import { PaginatedList } from './paginated-list'; import { PaginatedList } from './paginated-list';
@@ -14,13 +12,13 @@ import { FindAllOptions, FindAllRequest, FindByIDRequest, GetRequest } from './r
import { RequestService } from './request.service'; import { RequestService } from './request.service';
import { NormalizedObject } from '../cache/models/normalized-object.model'; import { NormalizedObject } from '../cache/models/normalized-object.model';
export abstract class DataService<TNormalized extends NormalizedObject, TDomain> extends HALEndpointService { export abstract class DataService<TNormalized extends NormalizedObject, TDomain> {
protected abstract responseCache: ResponseCacheService; protected abstract responseCache: ResponseCacheService;
protected abstract requestService: RequestService; protected abstract requestService: RequestService;
protected abstract rdbService: RemoteDataBuildService; protected abstract rdbService: RemoteDataBuildService;
protected abstract store: Store<CoreState>; protected abstract store: Store<CoreState>;
protected abstract linkPath: string; protected abstract linkPath: string;
protected abstract EnvConfig: GlobalConfig; protected abstract halService: HALEndpointService;
public abstract getScopedEndpoint(scope: string): Observable<string> public abstract getScopedEndpoint(scope: string): Observable<string>
@@ -55,7 +53,7 @@ export abstract class DataService<TNormalized extends NormalizedObject, TDomain>
} }
findAll(options: FindAllOptions = {}): Observable<RemoteData<PaginatedList<TDomain>>> { findAll(options: FindAllOptions = {}): Observable<RemoteData<PaginatedList<TDomain>>> {
const hrefObs = this.getEndpoint().filter((href: string) => isNotEmpty(href)) const hrefObs = this.halService.getEndpoint(this.linkPath).filter((href: string) => isNotEmpty(href))
.flatMap((endpoint: string) => this.getFindAllHref(endpoint, options)); .flatMap((endpoint: string) => this.getFindAllHref(endpoint, options));
hrefObs hrefObs
@@ -74,7 +72,7 @@ export abstract class DataService<TNormalized extends NormalizedObject, TDomain>
} }
findById(id: string): Observable<RemoteData<TDomain>> { findById(id: string): Observable<RemoteData<TDomain>> {
const hrefObs = this.getEndpoint() const hrefObs = this.halService.getEndpoint(this.linkPath)
.map((endpoint: string) => this.getFindByIDHref(endpoint, id)); .map((endpoint: string) => this.getFindByIDHref(endpoint, id));
hrefObs hrefObs

View File

@@ -0,0 +1,41 @@
import { Injectable } from '@angular/core';
import {
FacetValueMap,
FacetValueMapSuccessResponse,
FacetValueSuccessResponse,
RestResponse
} from '../cache/response-cache.models';
import { ResponseParsingService } from './parsing.service';
import { RestRequest } from './request.models';
import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer';
import { PageInfo } from '../shared/page-info.model';
import { isNotEmpty } from '../../shared/empty.util';
import { FacetValue } from '../../+search-page/search-service/facet-value.model';
@Injectable()
export class FacetResponseParsingService implements ResponseParsingService {
parse(request: RestRequest, data: DSpaceRESTV2Response): RestResponse {
const payload = data.payload;
const facetMap: FacetValueMap = new FacetValueMap();
const serializer = new DSpaceRESTv2Serializer(FacetValue);
payload._embedded.facets.map((facet) => {
const values = facet._embedded.values.map((value) => {value.search = value._links.search.href; return value;});
const facetValues = serializer.deserializeArray(values);
const valuesResponse = new FacetValueSuccessResponse(facetValues, data.statusCode, this.processPageInfo(data.payload.page));
facetMap[facet.name] = valuesResponse;
});
return new FacetValueMapSuccessResponse(facetMap, data.statusCode);
}
protected processPageInfo(pageObj: any): PageInfo {
if (isNotEmpty(pageObj)) {
return new DSpaceRESTv2Serializer(PageInfo).deserialize(pageObj);
} else {
return undefined;
}
}
}

View File

@@ -14,6 +14,7 @@ import { URLCombiner } from '../url-combiner/url-combiner';
import { DataService } from './data.service'; import { DataService } from './data.service';
import { RequestService } from './request.service'; import { RequestService } from './request.service';
import { HALEndpointService } from '../shared/hal-endpoint.service';
@Injectable() @Injectable()
export class ItemDataService extends DataService<NormalizedItem, Item> { export class ItemDataService extends DataService<NormalizedItem, Item> {
@@ -24,15 +25,14 @@ export class ItemDataService extends DataService<NormalizedItem, Item> {
protected requestService: RequestService, protected requestService: RequestService,
protected rdbService: RemoteDataBuildService, protected rdbService: RemoteDataBuildService,
protected store: Store<CoreState>, protected store: Store<CoreState>,
@Inject(GLOBAL_CONFIG) protected EnvConfig: GlobalConfig, private bs: BrowseService,
private bs: BrowseService protected halService: HALEndpointService) {
) {
super(); super();
} }
public getScopedEndpoint(scopeID: string): Observable<string> { public getScopedEndpoint(scopeID: string): Observable<string> {
if (isEmpty(scopeID)) { if (isEmpty(scopeID)) {
return this.getEndpoint(); return this.halService.getEndpoint(this.linkPath);
} else { } else {
return this.bs.getBrowseURLFor('dc.date.issued', this.linkPath) return this.bs.getBrowseURLFor('dc.date.issued', this.linkPath)
.filter((href: string) => isNotEmpty(href)) .filter((href: string) => isNotEmpty(href))

View File

@@ -8,13 +8,19 @@ import { EndpointMapRequest } from '../data/request.models';
import { ResponseCacheEntry } from '../cache/response-cache.reducer'; import { ResponseCacheEntry } from '../cache/response-cache.reducer';
import { isEmpty, isNotEmpty } from '../../shared/empty.util'; import { isEmpty, isNotEmpty } from '../../shared/empty.util';
import { RESTURLCombiner } from '../url-combiner/rest-url-combiner'; import { RESTURLCombiner } from '../url-combiner/rest-url-combiner';
import { Inject, Injectable } from '@angular/core';
import { GLOBAL_CONFIG } from '../../../config';
export abstract class HALEndpointService { @Injectable()
protected abstract responseCache: ResponseCacheService; export class HALEndpointService {
protected abstract requestService: RequestService;
protected abstract linkPath: string;
protected abstract EnvConfig: GlobalConfig;
protected linkPath: string;
constructor(private responseCache: ResponseCacheService,
private requestService: RequestService,
@Inject(GLOBAL_CONFIG) private EnvConfig: GlobalConfig) {
}
protected getRootHref(): string { protected getRootHref(): string {
return new RESTURLCombiner(this.EnvConfig, '/').toString(); return new RESTURLCombiner(this.EnvConfig, '/').toString();
} }
@@ -33,8 +39,8 @@ export abstract class HALEndpointService {
.distinctUntilChanged(); .distinctUntilChanged();
} }
public getEndpoint(): Observable<string> { public getEndpoint(linkPath: string): Observable<string> {
return this.getEndpointAt(...this.linkPath.split('/')); return this.getEndpointAt(...linkPath.split('/'));
} }
private getEndpointAt(...path: string[]): Observable<string> { private getEndpointAt(...path: string[]): Observable<string> {
@@ -50,10 +56,10 @@ export abstract class HALEndpointService {
return Observable.of(this.getRootHref()).pipe(...pipeArguments, distinctUntilChanged()); return Observable.of(this.getRootHref()).pipe(...pipeArguments, distinctUntilChanged());
} }
public isEnabledOnRestApi(): Observable<boolean> { public isEnabledOnRestApi(linkPath: string): Observable<boolean> {
return this.getRootEndpointMap().pipe( return this.getRootEndpointMap().pipe(
// TODO this only works when there's no / in linkPath // TODO this only works when there's no / in linkPath
map((endpointMap: EndpointMap) => isNotEmpty(endpointMap[this.linkPath])), map((endpointMap: EndpointMap) => isNotEmpty(endpointMap[linkPath])),
startWith(undefined), startWith(undefined),
distinctUntilChanged() distinctUntilChanged()
) )