diff --git a/config/environment.default.js b/config/environment.default.js index ad7be69b9e..39628c5a68 100644 --- a/config/environment.default.js +++ b/config/environment.default.js @@ -8,13 +8,20 @@ module.exports = { nameSpace: '/' }, // The REST API server settings. - rest: { - ssl: true, - host: 'dspace7.4science.it', - port: 443, - // NOTE: Space is capitalized because 'namespace' is a reserved string in TypeScript - nameSpace: '/dspace-spring-rest/api' - }, + // rest: { + // ssl: true, + // host: 'dspace7.4science.it', + // port: 443, + // // NOTE: Space is capitalized because 'namespace' is a reserved string in TypeScript + // nameSpace: '/dspace-spring-rest/api' + // }, + rest: { + ssl: false, + host: 'dspace7-internal.atmire.com', + port: 80, + // NOTE: Space is capitalized because 'namespace' is a reserved string in TypeScript + nameSpace: '/rest/api' + }, // Caching settings cache: { // NOTE: how long should objects be cached for by default diff --git a/src/app/+search-page/search-page.component.ts b/src/app/+search-page/search-page.component.ts index e3426fc96b..389db140e3 100644 --- a/src/app/+search-page/search-page.component.ts +++ b/src/app/+search-page/search-page.component.ts @@ -36,7 +36,7 @@ export class SearchPageComponent implements OnInit, OnDestroy { query: string; scopeObjectRDObs: Observable>; - resultsRDObs: Observable>>>; + resultsRDObs: Observable> | PaginatedList>>>; currentParams = {}; searchOptions: SearchOptions; sortConfig: SortOptions; diff --git a/src/app/+search-page/search-service/search-result-element-decorator.ts b/src/app/+search-page/search-service/search-result-element-decorator.ts new file mode 100644 index 0000000000..545d1b20eb --- /dev/null +++ b/src/app/+search-page/search-service/search-result-element-decorator.ts @@ -0,0 +1,17 @@ +import { GenericConstructor } from '../../core/shared/generic-constructor'; +import { ListableObject } from '../../shared/object-collection/shared/listable-object.model'; + +const searchResultMap = new Map(); + +export function searchResultFor(domainConstructor: GenericConstructor) { + return function decorator(searchResult: any) { + if (!searchResult) { + return; + } + searchResultMap.set(domainConstructor, searchResult); + }; +} + +export function getSearchResultFor(domainConstructor: GenericConstructor) { + return searchResultMap.get(domainConstructor); +} diff --git a/src/app/+search-page/search-service/search.service.ts b/src/app/+search-page/search-service/search.service.ts index 94f317103a..e3a1ccc11b 100644 --- a/src/app/+search-page/search-service/search.service.ts +++ b/src/app/+search-page/search-service/search.service.ts @@ -1,35 +1,27 @@ import { Inject, Injectable, OnDestroy } from '@angular/core'; import { ActivatedRoute, NavigationExtras, Router } from '@angular/router'; import { Observable } from 'rxjs/Observable'; -import { map, flatMap, tap, filter } from 'rxjs/operators'; +import { flatMap, map, tap } from 'rxjs/operators'; 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 { NormalizedDSpaceObject } from '../../core/cache/models/normalized-dspace-object.model'; import { SortOptions } from '../../core/cache/models/sort-options.model'; -import { RestResponse, SearchSuccessResponse } from '../../core/cache/response-cache.models'; +import { SearchSuccessResponse } from '../../core/cache/response-cache.models'; import { ResponseCacheEntry } from '../../core/cache/response-cache.reducer'; import { ResponseCacheService } from '../../core/cache/response-cache.service'; -import { DebugResponseParsingService } from '../../core/data/debug-response-parsing.service'; -import { DSOResponseParsingService } from '../../core/data/dso-response-parsing.service'; import { ItemDataService } from '../../core/data/item-data.service'; import { PaginatedList } from '../../core/data/paginated-list'; import { ResponseParsingService } from '../../core/data/parsing.service'; import { RemoteData } from '../../core/data/remote-data'; -import { GetRequest, EndpointMapRequest, RestRequest } from '../../core/data/request.models'; -import { RequestEntry } from '../../core/data/request.reducer'; +import { GetRequest, RestRequest } from '../../core/data/request.models'; import { RequestService } from '../../core/data/request.service'; -import { DSpaceRESTV2Response } from '../../core/dspace-rest-v2/dspace-rest-v2-response.model'; import { DSpaceObject } from '../../core/shared/dspace-object.model'; import { GenericConstructor } from '../../core/shared/generic-constructor'; import { HALEndpointService } from '../../core/shared/hal-endpoint.service'; -import { Item } from '../../core/shared/item.model'; -import { Metadatum } from '../../core/shared/metadatum.model'; -import { PageInfo } from '../../core/shared/page-info.model'; import { URLCombiner } from '../../core/url-combiner/url-combiner'; import { hasValue, isNotEmpty } from '../../shared/empty.util'; -import { ItemSearchResult } from '../../shared/object-collection/shared/item-search-result.model'; import { PaginationComponentOptions } from '../../shared/pagination/pagination-component-options.model'; import { RouteService } from '../../shared/route.service'; import { NormalizedSearchResult } from '../normalized-search-result.model'; @@ -40,6 +32,10 @@ import { FilterType } from './filter-type.model'; import { SearchFilterConfig } from './search-filter-config.model'; import { SearchResponseParsingService } from '../../core/data/search-response-parsing.service'; import { SearchQueryResponse } from './search-query-response.model'; +import { PageInfo } from '../../core/shared/page-info.model'; +import { getSearchResultFor } from './search-result-element-decorator'; +import { ListableObject } from '../../shared/object-collection/shared/listable-object.model'; +import { NormalizedItem } from '../../core/cache/models/normalized-item.model'; function shuffle(array: any[]) { let i = 0; @@ -95,16 +91,14 @@ export class SearchService extends HALEndpointService implements OnDestroy { // searchOptions: BehaviorSubject; searchOptions: SearchOptions; - constructor( - protected responseCache: ResponseCacheService, - protected requestService: RequestService, - private itemDataService: ItemDataService, - @Inject(GLOBAL_CONFIG) protected EnvConfig: GlobalConfig, - private routeService: RouteService, - private route: ActivatedRoute, - private rdb: RemoteDataBuildService, - private router: Router - ) { + constructor(protected responseCache: ResponseCacheService, + protected requestService: RequestService, + private itemDataService: ItemDataService, + @Inject(GLOBAL_CONFIG) protected EnvConfig: GlobalConfig, + private routeService: RouteService, + private route: ActivatedRoute, + private rdb: RemoteDataBuildService, + private router: Router) { super(); const pagination: PaginationComponentOptions = new PaginationComponentOptions(); pagination.id = 'search-results-pagination'; @@ -115,7 +109,7 @@ export class SearchService extends HALEndpointService implements OnDestroy { // this.searchOptions = new BehaviorSubject(searchOptions); } - search(query: string, scopeId?: string, searchOptions?: SearchOptions): Observable>>> { + search(query: string, scopeId?: string, searchOptions?: SearchOptions): Observable> | PaginatedList>>> { const requestObs = this.getEndpoint().pipe( map((url: string) => { const args: string[] = []; @@ -150,25 +144,57 @@ export class SearchService extends HALEndpointService implements OnDestroy { flatMap((request: RestRequest) => this.responseCache.get(request.href)) ); - const sqrObs = responseCacheObs.pipe( + // get search results from response cache + const sqrObs: Observable = responseCacheObs.pipe( map((entry: ResponseCacheEntry) => entry.response), map((response: SearchSuccessResponse) => response.results) ); - const dsoObs = sqrObs.pipe( + // turn dspace href from search results to effective list of DSpaceObjects + // Turn list of observable remote data DSO's into observable remote data object with list of DSO + const dsoObs: Observable> = sqrObs.pipe( map((sqr: SearchQueryResponse) => { return sqr.objects.map((nsr: NormalizedSearchResult) => - this.rdb.buildSingle(nsr.dspaceObject, NormalizedDSpaceObject)); + this.rdb.buildSingle(nsr.dspaceObject)); }), flatMap((input: Array>>) => this.rdb.aggregate(input)) ); - const payloadObs = Observable.combineLatest(sqrObs, dsoObs, (sqr: SearchQueryResponse, dsos: RemoteData) => { + // Create search results again with the correct dso objects linked to each result + const tDomainListObs: Observable>> = Observable.combineLatest(sqrObs, dsoObs, (sqr: SearchQueryResponse, dsos: RemoteData) => { return sqr.objects.map((object: NormalizedSearchResult, index: number) => { - return Object.assign({}, object, { - dspaceObject: dsos.payload[index] - }); - }) + let co = DSpaceObject; + if (dsos.payload[index]) { + const constructor: GenericConstructor = dsos.payload[index].constructor as GenericConstructor; + co = getSearchResultFor(constructor); + return Object.assign(new co(), object, { + dspaceObject: dsos.payload[index] + }); + } else { + return undefined; + } + }); + }); + + const pageInfoObs: Observable = responseCacheObs + .filter((entry: ResponseCacheEntry) => entry.response.isSuccessful) + .map((entry: ResponseCacheEntry) => { + if (hasValue((entry.response as SearchSuccessResponse).pageInfo)) { + const resPageInfo = (entry.response as SearchSuccessResponse).pageInfo; + if (isNotEmpty(resPageInfo) && resPageInfo.currentPage >= 0) { + return Object.assign({}, resPageInfo, { currentPage: resPageInfo.currentPage + 1 }); + } else { + return resPageInfo; + } + } + }); + + const payloadObs = Observable.combineLatest(tDomainListObs, pageInfoObs, (tDomainList, pageInfo) => { + if (hasValue(pageInfo)) { + return new PaginatedList(pageInfo, tDomainList); + } else { + return tDomainList; + } }); return this.rdb.toRemoteDataObservable(requestEntryObs, responseCacheObs, payloadObs); diff --git a/src/app/core/cache/builders/remote-data-build.service.ts b/src/app/core/cache/builders/remote-data-build.service.ts index bb4877980a..45eb6cb46a 100644 --- a/src/app/core/cache/builders/remote-data-build.service.ts +++ b/src/app/core/cache/builders/remote-data-build.service.ts @@ -22,24 +22,19 @@ import { DSOSuccessResponse, ErrorResponse, SearchSuccessResponse } from '../res import { ResponseCacheEntry } from '../response-cache.reducer'; import { ResponseCacheService } from '../response-cache.service'; import { getMapsTo, getRelationMetadata, getRelationships } from './build-decorators'; +import { NormalizedObject } from '../models/normalized-object.model'; @Injectable() export class RemoteDataBuildService { - constructor( - protected objectCache: ObjectCacheService, - protected responseCache: ResponseCacheService, - protected requestService: RequestService - ) { + constructor(protected objectCache: ObjectCacheService, + protected responseCache: ResponseCacheService, + protected requestService: RequestService) { } - buildSingle( - hrefObs: string | Observable, - normalizedType: GenericConstructor - ): Observable> { + buildSingle(hrefObs: string | Observable): Observable> { if (typeof hrefObs === 'string') { hrefObs = Observable.of(hrefObs); } - const requestHrefObs = hrefObs.flatMap((href: string) => this.objectCache.getRequestHrefBySelfLink(href)); @@ -59,14 +54,14 @@ export class RemoteDataBuildService { // always use self link if that is cached, only if it isn't, get it via the response. const payloadObs = Observable.combineLatest( - hrefObs.flatMap((href: string) => this.objectCache.getBySelfLink(href, normalizedType)) + hrefObs.flatMap((href: string) => this.objectCache.getBySelfLink(href)) .startWith(undefined), responseCacheObs .filter((entry: ResponseCacheEntry) => entry.response.isSuccessful) .map((entry: ResponseCacheEntry) => (entry.response as DSOSuccessResponse).resourceSelfLinks) .flatMap((resourceSelfLinks: string[]) => { if (isNotEmpty(resourceSelfLinks)) { - return this.objectCache.getBySelfLink(resourceSelfLinks[0], normalizedType); + return this.objectCache.getBySelfLink(resourceSelfLinks[0]); } else { return Observable.of(undefined); } @@ -97,7 +92,7 @@ export class RemoteDataBuildService { let isSuccessful: boolean; let error: RemoteDataError; if (hasValue(resEntry) && hasValue(resEntry.response)) { - isSuccessful = !responsePending && resEntry.response.isSuccessful; + isSuccessful = resEntry.response.isSuccessful; const errorMessage = isSuccessful === false ? (resEntry.response as ErrorResponse).errorMessage : undefined; if (hasValue(errorMessage)) { error = new RemoteDataError(resEntry.response.statusCode, errorMessage); @@ -114,10 +109,8 @@ export class RemoteDataBuildService { }); } - buildList( - hrefObs: string | Observable, - normalizedType: GenericConstructor - ): Observable>> { + buildList(hrefObs: string | Observable, + normalizedType: GenericConstructor): Observable>> { if (typeof hrefObs === 'string') { hrefObs = Observable.of(hrefObs); } @@ -181,7 +174,7 @@ export class RemoteDataBuildService { const rdArr = []; normalized[relationship].forEach((href: string) => { - rdArr.push(this.buildSingle(href, resourceConstructor)); + rdArr.push(this.buildSingle(href)); }); if (isList) { @@ -198,7 +191,7 @@ export class RemoteDataBuildService { if (isList) { links[relationship] = this.buildList(normalized[relationship], resourceConstructor); } else { - links[relationship] = this.buildSingle(normalized[relationship], resourceConstructor); + links[relationship] = this.buildSingle(normalized[relationship]); } } } diff --git a/src/app/core/cache/models/normalized-bitstream-format.model.ts b/src/app/core/cache/models/normalized-bitstream-format.model.ts deleted file mode 100644 index bb8b049a1c..0000000000 --- a/src/app/core/cache/models/normalized-bitstream-format.model.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { inheritSerialization, autoserialize } from 'cerialize'; - -import { mapsTo } from '../builders/build-decorators'; - -import { BitstreamFormat } from '../../shared/bitstream-format.model'; -import { NormalizedObject } from './normalized-object.model'; - -@mapsTo(BitstreamFormat) -@inheritSerialization(NormalizedObject) -export class NormalizedBitstreamFormat extends NormalizedObject { - - @autoserialize - shortDescription: string; - - @autoserialize - description: string; - - @autoserialize - mimetype: string; - - @autoserialize - supportLevel: number; - - @autoserialize - internal: boolean; - - @autoserialize - extensions: string; - -} diff --git a/src/app/core/cache/models/normalized-object-factory.ts b/src/app/core/cache/models/normalized-object-factory.ts index 3c67b18b3e..5b13d55ac8 100644 --- a/src/app/core/cache/models/normalized-object-factory.ts +++ b/src/app/core/cache/models/normalized-object-factory.ts @@ -1,4 +1,3 @@ -import { NormalizedDSpaceObject } from './normalized-dspace-object.model'; import { NormalizedBitstream } from './normalized-bitstream.model'; import { NormalizedBundle } from './normalized-bundle.model'; import { NormalizedItem } from './normalized-item.model'; @@ -7,7 +6,6 @@ import { GenericConstructor } from '../../shared/generic-constructor'; import { NormalizedCommunity } from './normalized-community.model'; import { ResourceType } from '../../shared/resource-type'; import { NormalizedObject } from './normalized-object.model'; -import { NormalizedBitstreamFormat } from './normalized-bitstream-format.model'; export class NormalizedObjectFactory { public static getConstructor(type: ResourceType): GenericConstructor { @@ -15,9 +13,6 @@ export class NormalizedObjectFactory { case ResourceType.Bitstream: { return NormalizedBitstream } - case ResourceType.BitstreamFormat: { - return NormalizedBitstreamFormat - } case ResourceType.Bundle: { return NormalizedBundle } diff --git a/src/app/core/cache/models/normalized-object.model.ts b/src/app/core/cache/models/normalized-object.model.ts index b26bd90b2a..e98081d68a 100644 --- a/src/app/core/cache/models/normalized-object.model.ts +++ b/src/app/core/cache/models/normalized-object.model.ts @@ -1,5 +1,6 @@ import { CacheableObject } from '../object-cache.reducer'; import { autoserialize } from 'cerialize'; +import { ResourceType } from '../../shared/resource-type'; /** * An abstract model class for a NormalizedObject. */ @@ -17,6 +18,9 @@ export abstract class NormalizedObject implements CacheableObject { @autoserialize uuid: string; + @autoserialize + type: ResourceType; + @autoserialize _links: { [name: string]: string diff --git a/src/app/core/cache/object-cache.reducer.ts b/src/app/core/cache/object-cache.reducer.ts index 39c623deed..1ae3a190a4 100644 --- a/src/app/core/cache/object-cache.reducer.ts +++ b/src/app/core/cache/object-cache.reducer.ts @@ -4,6 +4,7 @@ import { } from './object-cache.actions'; import { hasValue } from '../../shared/empty.util'; import { CacheEntry } from './cache-entry'; +import { ResourceType } from '../shared/resource-type'; export enum DirtyType { Created = 'Created', @@ -19,6 +20,7 @@ export enum DirtyType { export interface CacheableObject { uuid?: string; self: string; + type: ResourceType; // isNew: boolean; // dirtyType: DirtyType; // hasDirtyAttributes: boolean; diff --git a/src/app/core/cache/object-cache.service.ts b/src/app/core/cache/object-cache.service.ts index ae41c38fbe..b747880dc3 100644 --- a/src/app/core/cache/object-cache.service.ts +++ b/src/app/core/cache/object-cache.service.ts @@ -10,6 +10,9 @@ import { hasNoValue } from '../../shared/empty.util'; import { GenericConstructor } from '../shared/generic-constructor'; import { coreSelector, CoreState } from '../core.reducers'; import { pathSelector } from '../shared/selectors'; +import { Item } from '../shared/item.model'; +import { NormalizedObjectFactory } from './models/normalized-object-factory'; +import { NormalizedObject } from './models/normalized-object.model'; function selfLinkFromUuidSelector(uuid: string): MemoizedSelector { return pathSelector(coreSelector, 'index', IndexName.OBJECT, uuid); @@ -24,9 +27,8 @@ function entryFromSelfLinkSelector(selfLink: string): MemoizedSelector - ) { } + constructor(private store: Store) { + } /** * Add an object to the cache @@ -70,14 +72,17 @@ export class ObjectCacheService { * @return Observable * An observable of the requested object */ - getByUUID(uuid: string, type: GenericConstructor): Observable { + getByUUID(uuid: string): Observable { return this.store.select(selfLinkFromUuidSelector(uuid)) - .flatMap((selfLink: string) => this.getBySelfLink(selfLink, type)) + .flatMap((selfLink: string) => this.getBySelfLink(selfLink)) } - getBySelfLink(selfLink: string, type: GenericConstructor): Observable { + getBySelfLink(selfLink: string): Observable { return this.getEntry(selfLink) - .map((entry: ObjectCacheEntry) => Object.assign(new type(), entry.data) as T); + .map((entry: ObjectCacheEntry) => { + const type: GenericConstructor= NormalizedObjectFactory.getConstructor(entry.data.type); + return Object.assign(new type(), entry.data) as T + }); } private getEntry(selfLink: string): Observable { @@ -116,9 +121,9 @@ export class ObjectCacheService { * The type of the objects to get * @return Observable> */ - getList(selfLinks: string[], type: GenericConstructor): Observable { + getList(selfLinks: string[], type: GenericConstructor): Observable { return Observable.combineLatest( - selfLinks.map((selfLink: string) => this.getBySelfLink(selfLink, type)) + selfLinks.map((selfLink: string) => this.getBySelfLink(selfLink)) ); } diff --git a/src/app/core/data/comcol-data.service.ts b/src/app/core/data/comcol-data.service.ts index cc9ef4ad60..24c019c611 100644 --- a/src/app/core/data/comcol-data.service.ts +++ b/src/app/core/data/comcol-data.service.ts @@ -9,8 +9,9 @@ import { CommunityDataService } from './community-data.service'; import { DataService } from './data.service'; import { FindByIDRequest } from './request.models'; +import { NormalizedObject } from '../cache/models/normalized-object.model'; -export abstract class ComColDataService extends DataService { +export abstract class ComColDataService extends DataService { protected abstract cds: CommunityDataService; protected abstract objectCache: ObjectCacheService; @@ -47,7 +48,7 @@ export abstract class ComColDataService Observable.throw(new Error(`The Community with scope ${scopeID} couldn't be retrieved`))), successResponse - .flatMap((response: DSOSuccessResponse) => this.objectCache.getByUUID(scopeID, NormalizedCommunity)) + .flatMap((response: DSOSuccessResponse) => this.objectCache.getByUUID(scopeID)) .map((nc: NormalizedCommunity) => nc._links[this.linkPath]) .filter((href) => isNotEmpty(href)) ).distinctUntilChanged(); diff --git a/src/app/core/data/data.service.ts b/src/app/core/data/data.service.ts index ccdbbea5b9..792c8acb94 100644 --- a/src/app/core/data/data.service.ts +++ b/src/app/core/data/data.service.ts @@ -13,8 +13,9 @@ import { PaginatedList } from './paginated-list'; import { RemoteData } from './remote-data'; import { FindAllOptions, FindAllRequest, FindByIDRequest, GetRequest } from './request.models'; import { RequestService } from './request.service'; +import { NormalizedObject } from '../cache/models/normalized-object.model'; -export abstract class DataService extends HALEndpointService { +export abstract class DataService extends HALEndpointService { protected abstract responseCache: ResponseCacheService; protected abstract requestService: RequestService; protected abstract rdbService: RemoteDataBuildService; @@ -22,9 +23,7 @@ export abstract class DataService protected abstract linkPath: string; protected abstract EnvConfig: GlobalConfig; - constructor( - protected normalizedResourceType: GenericConstructor, - ) { + constructor(protected normalizedResourceType: GenericConstructor,) { super(); } @@ -95,12 +94,12 @@ export abstract class DataService this.requestService.configure(request); }); - return this.rdbService.buildSingle(hrefObs, this.normalizedResourceType); + return this.rdbService.buildSingle(hrefObs); } findByHref(href: string): Observable> { this.requestService.configure(new GetRequest(this.requestService.generateRequestId(), href)); - return this.rdbService.buildSingle(href, this.normalizedResourceType); + return this.rdbService.buildSingle(href); } // TODO implement, after the structure of the REST server's POST response is finalized diff --git a/src/app/core/data/search-response-parsing.service.ts b/src/app/core/data/search-response-parsing.service.ts index bd64101397..886da34200 100644 --- a/src/app/core/data/search-response-parsing.service.ts +++ b/src/app/core/data/search-response-parsing.service.ts @@ -1,23 +1,35 @@ import { Injectable } from '@angular/core'; -import { - DSOSuccessResponse, RestResponse, - SearchSuccessResponse -} from '../cache/response-cache.models'; +import { RestResponse, SearchSuccessResponse } from '../cache/response-cache.models'; import { DSOResponseParsingService } from './dso-response-parsing.service'; 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 { hasValue, isNotEmpty } from '../../shared/empty.util'; +import { isNotEmpty } from '../../shared/empty.util'; import { SearchQueryResponse } from '../../+search-page/search-service/search-query-response.model'; +import { Metadatum } from '../shared/metadatum.model'; @Injectable() export class SearchResponseParsingService implements ResponseParsingService { - constructor(private dsoParser: DSOResponseParsingService) {} + constructor(private dsoParser: DSOResponseParsingService) { + } parse(request: RestRequest, data: DSpaceRESTV2Response): RestResponse { const payload = data.payload; + const hitHighlights = payload._embedded.objects + .map((object) => object.hitHighlights) + .map((hhObject) => { + if (hhObject) { + return Object.keys(hhObject).map((key) => Object.assign(new Metadatum(), { + key: key, + value: hhObject[key].join('...') + })) + } else { + return undefined; + } + }); + const dsoSelfLinks = payload._embedded.objects .map((object) => object._embedded.dspaceObject) // we don't need embedded collections, bitstreamformats, etc for search results. @@ -32,11 +44,24 @@ export class SearchResponseParsingService implements ResponseParsingService { .reduce((combined, thisElement) => [...combined, ...thisElement], []); const objects = payload._embedded.objects - .map((object, index) => Object.assign({}, object, { dspaceObject: dsoSelfLinks[index] })); - + .map((object, index) => Object.assign({}, object, { + dspaceObject: dsoSelfLinks[index], + hitHighlights: hitHighlights[index], + // we don't need embedded collections, bitstreamformats, etc for search results. + // And parsing them all takes up a lot of time. Throw them away to improve performance + // until objs until partial results are supported by the rest api + _embedded: undefined + })); payload.objects = objects; const deserialized = new DSpaceRESTv2Serializer(SearchQueryResponse).deserialize(payload); - return new SearchSuccessResponse(deserialized, data.statusCode, undefined); + return new SearchSuccessResponse(deserialized, data.statusCode, this.processPageInfo(data.payload.page)); } + protected processPageInfo(pageObj: any): PageInfo { + if (isNotEmpty(pageObj)) { + return new DSpaceRESTv2Serializer(PageInfo).deserialize(pageObj); + } else { + return undefined; + } + } } diff --git a/src/app/core/shared/bitstream-format.model.ts b/src/app/core/shared/bitstream-format.model.ts index c0f6be29c9..b85d9e2053 100644 --- a/src/app/core/shared/bitstream-format.model.ts +++ b/src/app/core/shared/bitstream-format.model.ts @@ -1,17 +1,24 @@ -import { DSpaceObject } from './dspace-object.model'; -export class BitstreamFormat extends DSpaceObject { +import { autoserialize } from 'cerialize'; +export class BitstreamFormat { + + @autoserialize shortDescription: string; + @autoserialize description: string; + @autoserialize mimetype: string; + @autoserialize supportLevel: number; + @autoserialize internal: boolean; + @autoserialize extensions: string; } diff --git a/src/app/core/shared/dspace-object.model.ts b/src/app/core/shared/dspace-object.model.ts index 63cedf84f4..5e62e3e321 100644 --- a/src/app/core/shared/dspace-object.model.ts +++ b/src/app/core/shared/dspace-object.model.ts @@ -9,7 +9,7 @@ import { Observable } from 'rxjs/Observable'; /** * An abstract model class for a DSpaceObject. */ -export class DSpaceObject implements CacheableObject, ListableObject { +export class DSpaceObject implements CacheableObject, ListableObject { self: string; diff --git a/src/app/shared/object-collection/shared/collection-search-result.model.ts b/src/app/shared/object-collection/shared/collection-search-result.model.ts index 63b6a0d37a..5e9afc59e5 100644 --- a/src/app/shared/object-collection/shared/collection-search-result.model.ts +++ b/src/app/shared/object-collection/shared/collection-search-result.model.ts @@ -1,5 +1,7 @@ -import { Collection } from '../../../core/shared/collection.model'; import { SearchResult } from '../../../+search-page/search-result.model'; +import { Collection } from '../../../core/shared/collection.model'; +import { searchResultFor } from '../../../+search-page/search-service/search-result-element-decorator'; +@searchResultFor(Collection) export class CollectionSearchResult extends SearchResult { } diff --git a/src/app/shared/object-collection/shared/community-search-result.model.ts b/src/app/shared/object-collection/shared/community-search-result.model.ts index 79ea34b6cd..8e371c182c 100644 --- a/src/app/shared/object-collection/shared/community-search-result.model.ts +++ b/src/app/shared/object-collection/shared/community-search-result.model.ts @@ -1,5 +1,7 @@ -import { SearchResult } from '../../../+search-page/search-result.model'; import { Community } from '../../../core/shared/community.model'; +import { SearchResult } from '../../../+search-page/search-result.model'; +import { searchResultFor } from '../../../+search-page/search-service/search-result-element-decorator'; +@searchResultFor(Community) export class CommunitySearchResult extends SearchResult { } diff --git a/src/app/shared/object-collection/shared/item-search-result.model.ts b/src/app/shared/object-collection/shared/item-search-result.model.ts index d9af3539a0..f20b3db1e3 100644 --- a/src/app/shared/object-collection/shared/item-search-result.model.ts +++ b/src/app/shared/object-collection/shared/item-search-result.model.ts @@ -1,5 +1,7 @@ import { SearchResult } from '../../../+search-page/search-result.model'; import { Item } from '../../../core/shared/item.model'; +import { searchResultFor } from '../../../+search-page/search-service/search-result-element-decorator'; +@searchResultFor(Item) export class ItemSearchResult extends SearchResult { } diff --git a/src/app/shared/object-grid/search-result-grid-element/collection-search-result/collection-search-result-grid-element.component.ts b/src/app/shared/object-grid/search-result-grid-element/collection-search-result/collection-search-result-grid-element.component.ts index e5747a1243..5d814ac7e5 100644 --- a/src/app/shared/object-grid/search-result-grid-element/collection-search-result/collection-search-result-grid-element.component.ts +++ b/src/app/shared/object-grid/search-result-grid-element/collection-search-result/collection-search-result-grid-element.component.ts @@ -2,10 +2,11 @@ import { Component } from '@angular/core'; import { renderElementsFor} from '../../../object-collection/shared/dso-element-decorator'; -import { CollectionSearchResult } from '../../../object-collection/shared/collection-search-result.model'; + import { SearchResultGridElementComponent } from '../search-result-grid-element.component'; import { Collection } from '../../../../core/shared/collection.model'; import { ViewMode } from '../../../../+search-page/search-options.model'; +import { CollectionSearchResult } from '../../../object-collection/shared/collection-search-result.model'; @Component({ selector: 'ds-collection-search-result-grid-element', diff --git a/src/app/shared/object-grid/search-result-grid-element/community-search-result/community-search-result-grid-element.component.ts b/src/app/shared/object-grid/search-result-grid-element/community-search-result/community-search-result-grid-element.component.ts index d08286ff2e..f011e49eda 100644 --- a/src/app/shared/object-grid/search-result-grid-element/community-search-result/community-search-result-grid-element.component.ts +++ b/src/app/shared/object-grid/search-result-grid-element/community-search-result/community-search-result-grid-element.component.ts @@ -1,5 +1,6 @@ import { Component } from '@angular/core'; + import { Community } from '../../../../core/shared/community.model'; import { renderElementsFor } from '../../../object-collection/shared/dso-element-decorator'; import { SearchResultGridElementComponent } from '../search-result-grid-element.component'; diff --git a/src/app/shared/object-list/search-result-list-element/collection-search-result/collection-search-result-list-element.component.ts b/src/app/shared/object-list/search-result-list-element/collection-search-result/collection-search-result-list-element.component.ts index 9a462c124e..746e700f05 100644 --- a/src/app/shared/object-list/search-result-list-element/collection-search-result/collection-search-result-list-element.component.ts +++ b/src/app/shared/object-list/search-result-list-element/collection-search-result/collection-search-result-list-element.component.ts @@ -1,6 +1,7 @@ import { Component } from '@angular/core'; import { renderElementsFor } from '../../../object-collection/shared/dso-element-decorator'; + import { SearchResultListElementComponent } from '../search-result-list-element.component'; import { Collection } from '../../../../core/shared/collection.model'; import { ViewMode } from '../../../../+search-page/search-options.model'; diff --git a/src/app/shared/object-list/search-result-list-element/community-search-result/community-search-result-list-element.component.ts b/src/app/shared/object-list/search-result-list-element/community-search-result/community-search-result-list-element.component.ts index 5664e840e3..2ca89fc9c5 100644 --- a/src/app/shared/object-list/search-result-list-element/community-search-result/community-search-result-list-element.component.ts +++ b/src/app/shared/object-list/search-result-list-element/community-search-result/community-search-result-list-element.component.ts @@ -1,10 +1,11 @@ import { Component } from '@angular/core'; import { renderElementsFor } from '../../../object-collection/shared/dso-element-decorator'; -import { CommunitySearchResult } from '../../../object-collection/shared/community-search-result.model'; + import { SearchResultListElementComponent } from '../search-result-list-element.component'; import { Community } from '../../../../core/shared/community.model'; import { ViewMode } from '../../../../+search-page/search-options.model'; +import { CommunitySearchResult } from '../../../object-collection/shared/community-search-result.model'; @Component({ selector: 'ds-community-search-result-list-element', diff --git a/src/app/shared/object-list/search-result-list-element/search-result-list-element.component.ts b/src/app/shared/object-list/search-result-list-element/search-result-list-element.component.ts index 9675a58a1e..31e31c72a8 100644 --- a/src/app/shared/object-list/search-result-list-element/search-result-list-element.component.ts +++ b/src/app/shared/object-list/search-result-list-element/search-result-list-element.component.ts @@ -3,7 +3,7 @@ import { Component, Inject } from '@angular/core'; import { SearchResult } from '../../../+search-page/search-result.model'; import { DSpaceObject } from '../../../core/shared/dspace-object.model'; import { Metadatum } from '../../../core/shared/metadatum.model'; -import { isEmpty, hasNoValue } from '../../empty.util'; +import { isEmpty, hasNoValue, isNotEmpty } from '../../empty.util'; import { ListableObject } from '../../object-collection/shared/listable-object.model'; import { AbstractListableElementComponent } from '../../object-collection/shared/object-collection-element/abstract-listable-element.component'; import { Observable } from 'rxjs/Observable'; @@ -24,13 +24,15 @@ export class SearchResultListElementComponent, K exten getValues(keys: string[]): string[] { const results: string[] = new Array(); - this.object.hitHighlights.forEach( - (md: Metadatum) => { - if (keys.indexOf(md.key) > -1) { - results.push(md.value); + if (isNotEmpty(this.object.hitHighlights)) { + this.object.hitHighlights.forEach( + (md: Metadatum) => { + if (keys.indexOf(md.key) > -1) { + results.push(md.value); + } } - } - ); + ); + } if (isEmpty(results)) { this.dso.filterMetadata(keys).forEach( (md: Metadatum) => { @@ -43,14 +45,16 @@ export class SearchResultListElementComponent, K exten getFirstValue(key: string): string { let result: string; - this.object.hitHighlights.some( - (md: Metadatum) => { - if (key === md.key) { - result = md.value; - return true; + if (isNotEmpty(this.object.hitHighlights)) { + this.object.hitHighlights.some( + (md: Metadatum) => { + if (key === md.key) { + result = md.value; + return true; + } } - } - ); + ); + } if (hasNoValue(result)) { result = this.dso.findMetadata(key); }