mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-18 07:23:03 +00:00
intermediate commit
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { getMockObjectCacheService } from '../../shared/mocks/mock-object-cache.service';
|
||||
import { ErrorResponse, GenericSuccessResponse } from '../cache/response-cache.models';
|
||||
import { ErrorResponse, GenericSuccessResponse } from '../cache/response.models';
|
||||
import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
|
||||
import { BrowseEntriesResponseParsingService } from './browse-entries-response-parsing.service';
|
||||
import { BrowseEntriesRequest } from './request.models';
|
||||
|
@@ -7,7 +7,7 @@ import {
|
||||
ErrorResponse,
|
||||
GenericSuccessResponse,
|
||||
RestResponse
|
||||
} from '../cache/response-cache.models';
|
||||
} from '../cache/response.models';
|
||||
import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
|
||||
import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer';
|
||||
import { BrowseEntry } from '../shared/browse-entry.model';
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import { getMockObjectCacheService } from '../../shared/mocks/mock-object-cache.service';
|
||||
import { ErrorResponse, GenericSuccessResponse } from '../cache/response-cache.models';
|
||||
import { ErrorResponse, GenericSuccessResponse } from '../cache/response.models';
|
||||
import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
|
||||
import { BrowseEntriesResponseParsingService } from './browse-entries-response-parsing.service';
|
||||
import { BrowseEntriesRequest, BrowseItemsRequest } from './request.models';
|
||||
|
@@ -7,7 +7,7 @@ import {
|
||||
ErrorResponse,
|
||||
GenericSuccessResponse,
|
||||
RestResponse
|
||||
} from '../cache/response-cache.models';
|
||||
} from '../cache/response.models';
|
||||
import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
|
||||
import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer';
|
||||
import { BaseResponseParsingService } from './base-response-parsing.service';
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import { BrowseResponseParsingService } from './browse-response-parsing.service';
|
||||
import { BrowseEndpointRequest } from './request.models';
|
||||
import { GenericSuccessResponse, ErrorResponse } from '../cache/response-cache.models';
|
||||
import { GenericSuccessResponse, ErrorResponse } from '../cache/response.models';
|
||||
import { BrowseDefinition } from '../shared/browse-definition.model';
|
||||
import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
|
||||
|
||||
|
@@ -2,7 +2,7 @@ import { Injectable } from '@angular/core';
|
||||
import { ResponseParsingService } from './parsing.service';
|
||||
import { RestRequest } from './request.models';
|
||||
import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
|
||||
import { GenericSuccessResponse, ErrorResponse, RestResponse } from '../cache/response-cache.models';
|
||||
import { GenericSuccessResponse, ErrorResponse, RestResponse } from '../cache/response.models';
|
||||
import { isNotEmpty } from '../../shared/empty.util';
|
||||
import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer';
|
||||
import { BrowseDefinition } from '../shared/browse-definition.model';
|
||||
|
@@ -1,10 +1,8 @@
|
||||
import { Inject, Injectable } from '@angular/core';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { GLOBAL_CONFIG, GlobalConfig } from '../../../config';
|
||||
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
|
||||
import { NormalizedCollection } from '../cache/models/normalized-collection.model';
|
||||
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||
import { ResponseCacheService } from '../cache/response-cache.service';
|
||||
import { CoreState } from '../core.reducers';
|
||||
import { Collection } from '../shared/collection.model';
|
||||
import { ComColDataService } from './comcol-data.service';
|
||||
@@ -17,7 +15,6 @@ export class CollectionDataService extends ComColDataService<NormalizedCollectio
|
||||
protected linkPath = 'collections';
|
||||
|
||||
constructor(
|
||||
protected responseCache: ResponseCacheService,
|
||||
protected requestService: RequestService,
|
||||
protected rdbService: RemoteDataBuildService,
|
||||
protected store: Store<CoreState>,
|
||||
|
@@ -5,7 +5,6 @@ import { GlobalConfig } from '../../../config';
|
||||
import { getMockRequestService } from '../../shared/mocks/mock-request.service';
|
||||
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
|
||||
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||
import { ResponseCacheService } from '../cache/response-cache.service';
|
||||
import { CoreState } from '../core.reducers';
|
||||
import { ComColDataService } from './comcol-data.service';
|
||||
import { CommunityDataService } from './community-data.service';
|
||||
@@ -23,7 +22,6 @@ class NormalizedTestObject extends NormalizedObject {
|
||||
class TestService extends ComColDataService<NormalizedTestObject, any> {
|
||||
|
||||
constructor(
|
||||
protected responseCache: ResponseCacheService,
|
||||
protected requestService: RequestService,
|
||||
protected rdbService: RemoteDataBuildService,
|
||||
protected store: Store<CoreState>,
|
||||
@@ -41,7 +39,6 @@ class TestService extends ComColDataService<NormalizedTestObject, any> {
|
||||
describe('ComColDataService', () => {
|
||||
let scheduler: TestScheduler;
|
||||
let service: TestService;
|
||||
let responseCache: ResponseCacheService;
|
||||
let requestService: RequestService;
|
||||
let cds: CommunityDataService;
|
||||
let objectCache: ObjectCacheService;
|
||||
@@ -68,14 +65,6 @@ describe('ComColDataService', () => {
|
||||
});
|
||||
}
|
||||
|
||||
function initMockResponseCacheService(isSuccessful: boolean): ResponseCacheService {
|
||||
return jasmine.createSpyObj('responseCache', {
|
||||
get: cold('c-', {
|
||||
c: { response: { isSuccessful } }
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
function initMockObjectCacheService(): ObjectCacheService {
|
||||
return jasmine.createSpyObj('objectCache', {
|
||||
getByUUID: cold('d-', {
|
||||
@@ -90,7 +79,6 @@ describe('ComColDataService', () => {
|
||||
|
||||
function initTestService(): TestService {
|
||||
return new TestService(
|
||||
responseCache,
|
||||
requestService,
|
||||
rdbService,
|
||||
store,
|
||||
@@ -111,7 +99,6 @@ describe('ComColDataService', () => {
|
||||
cds = initMockCommunityDataService();
|
||||
requestService = getMockRequestService();
|
||||
objectCache = initMockObjectCacheService();
|
||||
responseCache = initMockResponseCacheService(true);
|
||||
service = initTestService();
|
||||
|
||||
const expected = new FindByIDRequest(requestService.generateRequestId(), communityEndpoint, scopeID);
|
||||
@@ -127,7 +114,6 @@ describe('ComColDataService', () => {
|
||||
cds = initMockCommunityDataService();
|
||||
requestService = getMockRequestService();
|
||||
objectCache = initMockObjectCacheService();
|
||||
responseCache = initMockResponseCacheService(true);
|
||||
service = initTestService();
|
||||
});
|
||||
|
||||
@@ -150,7 +136,6 @@ describe('ComColDataService', () => {
|
||||
cds = initMockCommunityDataService();
|
||||
requestService = getMockRequestService();
|
||||
objectCache = initMockObjectCacheService();
|
||||
responseCache = initMockResponseCacheService(false);
|
||||
service = initTestService();
|
||||
});
|
||||
|
||||
|
@@ -1,15 +1,16 @@
|
||||
import { distinctUntilChanged, filter, map, mergeMap, take, tap } from 'rxjs/operators';
|
||||
import { distinctUntilChanged, filter, map, mergeMap, share, take, tap } from 'rxjs/operators';
|
||||
import { merge as observableMerge, Observable, throwError as observableThrowError } from 'rxjs';
|
||||
import { isEmpty, isNotEmpty } from '../../shared/empty.util';
|
||||
import { hasValue, isEmpty, isNotEmpty } from '../../shared/empty.util';
|
||||
import { NormalizedCommunity } from '../cache/models/normalized-community.model';
|
||||
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||
import { ResponseCacheEntry } from '../cache/response-cache.reducer';
|
||||
import { CommunityDataService } from './community-data.service';
|
||||
|
||||
import { DataService } from './data.service';
|
||||
import { FindAllOptions, FindByIDRequest } from './request.models';
|
||||
import { NormalizedObject } from '../cache/models/normalized-object.model';
|
||||
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
||||
import { RequestEntry } from './request.reducer';
|
||||
import { getResponseFromEntry } from '../shared/operators';
|
||||
|
||||
export abstract class ComColDataService<TNormalized extends NormalizedObject, TDomain> extends DataService<TNormalized, TDomain> {
|
||||
protected abstract cds: CommunityDataService;
|
||||
@@ -26,9 +27,9 @@ export abstract class ComColDataService<TNormalized extends NormalizedObject, TD
|
||||
* @return { Observable<string> }
|
||||
* an Observable<string> containing the scoped URL
|
||||
*/
|
||||
public getBrowseEndpoint(options: FindAllOptions = {}): Observable<string> {
|
||||
public getBrowseEndpoint(options: FindAllOptions = {}, linkPath: string = this.linkPath): Observable<string> {
|
||||
if (isEmpty(options.scopeID)) {
|
||||
return this.halService.getEndpoint(this.linkPath);
|
||||
return this.halService.getEndpoint(linkPath);
|
||||
} else {
|
||||
const scopeCommunityHrefObs = this.cds.getEndpoint().pipe(
|
||||
mergeMap((endpoint: string) => this.cds.getFindByIDHref(endpoint, options.scopeID)),
|
||||
@@ -37,7 +38,7 @@ export abstract class ComColDataService<TNormalized extends NormalizedObject, TD
|
||||
tap((href: string) => {
|
||||
const request = new FindByIDRequest(this.requestService.generateRequestId(), href, options.scopeID);
|
||||
this.requestService.configure(request);
|
||||
}),);
|
||||
}));
|
||||
|
||||
// return scopeCommunityHrefObs.pipe(
|
||||
// mergeMap((href: string) => this.responseCache.get(href)),
|
||||
@@ -46,7 +47,7 @@ export abstract class ComColDataService<TNormalized extends NormalizedObject, TD
|
||||
// if (response.isSuccessful) {
|
||||
// const community$: Observable<NormalizedCommunity> = this.objectCache.getByUUID(scopeID);
|
||||
// return community$.pipe(
|
||||
// map((community) => community._links[this.linkPath]),
|
||||
// map((community) => community._links[linkPath]),
|
||||
// filter((href) => isNotEmpty(href)),
|
||||
// distinctUntilChanged()
|
||||
// );
|
||||
@@ -57,8 +58,8 @@ export abstract class ComColDataService<TNormalized extends NormalizedObject, TD
|
||||
// distinctUntilChanged()
|
||||
// );
|
||||
const responses = scopeCommunityHrefObs.pipe(
|
||||
mergeMap((href: string) => this.responseCache.get(href)),
|
||||
map((entry: ResponseCacheEntry) => entry.response));
|
||||
mergeMap((href: string) => this.requestService.getByHref(href)),
|
||||
getResponseFromEntry());
|
||||
const errorResponses = responses.pipe(
|
||||
filter((response) => !response.isSuccessful),
|
||||
mergeMap(() => observableThrowError(new Error(`The Community with scope ${options.scopeID} couldn't be retrieved`)))
|
||||
@@ -66,11 +67,11 @@ export abstract class ComColDataService<TNormalized extends NormalizedObject, TD
|
||||
const successResponses = responses.pipe(
|
||||
filter((response) => response.isSuccessful),
|
||||
mergeMap(() => this.objectCache.getByUUID(options.scopeID)),
|
||||
map((nc: NormalizedCommunity) => nc._links[this.linkPath]),
|
||||
map((nc: NormalizedCommunity) => nc._links[linkPath]),
|
||||
filter((href) => isNotEmpty(href))
|
||||
);
|
||||
|
||||
return observableMerge(errorResponses, successResponses).pipe(distinctUntilChanged());
|
||||
return observableMerge(errorResponses, successResponses).pipe(distinctUntilChanged(), share());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,12 +1,10 @@
|
||||
|
||||
import {mergeMap, filter, take} from 'rxjs/operators';
|
||||
import { filter, mergeMap, take } from 'rxjs/operators';
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
import { Store } from '@ngrx/store';
|
||||
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
|
||||
import { NormalizedCommunity } from '../cache/models/normalized-community.model';
|
||||
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||
import { ResponseCacheService } from '../cache/response-cache.service';
|
||||
import { CoreState } from '../core.reducers';
|
||||
import { Community } from '../shared/community.model';
|
||||
import { ComColDataService } from './comcol-data.service';
|
||||
@@ -25,7 +23,6 @@ export class CommunityDataService extends ComColDataService<NormalizedCommunity,
|
||||
protected cds = this;
|
||||
|
||||
constructor(
|
||||
protected responseCache: ResponseCacheService,
|
||||
protected requestService: RequestService,
|
||||
protected rdbService: RemoteDataBuildService,
|
||||
protected store: Store<CoreState>,
|
||||
@@ -40,12 +37,10 @@ export class CommunityDataService extends ComColDataService<NormalizedCommunity,
|
||||
}
|
||||
|
||||
findTop(options: FindAllOptions = {}): Observable<RemoteData<PaginatedList<Community>>> {
|
||||
const hrefObs = this.halService.getEndpoint(this.topLinkPath).pipe(filter((href: string) => isNotEmpty(href)),
|
||||
mergeMap((endpoint: string) => this.getFindAllHref(options)),);
|
||||
|
||||
const hrefObs = this.getFindAllHref(options, this.topLinkPath);
|
||||
hrefObs.pipe(
|
||||
filter((href: string) => hasValue(href)),
|
||||
take(1),)
|
||||
take(1))
|
||||
.subscribe((href: string) => {
|
||||
const request = new FindAllRequest(this.requestService.generateRequestId(), href, options);
|
||||
this.requestService.configure(request);
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { ConfigSuccessResponse, ErrorResponse } from '../cache/response-cache.models';
|
||||
import { ConfigSuccessResponse, ErrorResponse } from '../cache/response.models';
|
||||
import { ConfigResponseParsingService } from './config-response-parsing.service';
|
||||
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||
import { GlobalConfig } from '../../../config/global-config.interface';
|
||||
|
@@ -3,7 +3,7 @@ import { Inject, Injectable } from '@angular/core';
|
||||
import { ResponseParsingService } from './parsing.service';
|
||||
import { RestRequest } from './request.models';
|
||||
import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
|
||||
import { ConfigSuccessResponse, ErrorResponse, RestResponse } from '../cache/response-cache.models';
|
||||
import { ConfigSuccessResponse, ErrorResponse, RestResponse } from '../cache/response.models';
|
||||
import { isNotEmpty } from '../../shared/empty.util';
|
||||
import { ConfigObjectFactory } from '../shared/config/config-object-factory';
|
||||
|
||||
|
@@ -1,6 +1,5 @@
|
||||
import { DataService } from './data.service';
|
||||
import { NormalizedObject } from '../cache/models/normalized-object.model';
|
||||
import { ResponseCacheService } from '../cache/response-cache.service';
|
||||
import { RequestService } from './request.service';
|
||||
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
|
||||
import { CoreState } from '../core.reducers';
|
||||
@@ -22,7 +21,6 @@ class NormalizedTestObject extends NormalizedObject {
|
||||
|
||||
class TestService extends DataService<NormalizedTestObject, any> {
|
||||
constructor(
|
||||
protected responseCache: ResponseCacheService,
|
||||
protected requestService: RequestService,
|
||||
protected rdbService: RemoteDataBuildService,
|
||||
protected store: Store<CoreState>,
|
||||
@@ -33,7 +31,7 @@ class TestService extends DataService<NormalizedTestObject, any> {
|
||||
super();
|
||||
}
|
||||
|
||||
public getBrowseEndpoint(options: FindAllOptions): Observable<string> {
|
||||
public getBrowseEndpoint(options: FindAllOptions = {}, linkPath: string = this.linkPath): Observable<string> {
|
||||
return observableOf(endpoint);
|
||||
}
|
||||
}
|
||||
@@ -41,7 +39,6 @@ class TestService extends DataService<NormalizedTestObject, any> {
|
||||
describe('DataService', () => {
|
||||
let service: TestService;
|
||||
let options: FindAllOptions;
|
||||
const responseCache = {} as ResponseCacheService;
|
||||
const requestService = {} as RequestService;
|
||||
const halService = {} as HALEndpointService;
|
||||
const rdbService = {} as RemoteDataBuildService;
|
||||
@@ -57,7 +54,6 @@ describe('DataService', () => {
|
||||
|
||||
function initTestService(): TestService {
|
||||
return new TestService(
|
||||
responseCache,
|
||||
requestService,
|
||||
rdbService,
|
||||
store,
|
||||
|
@@ -1,9 +1,8 @@
|
||||
import { distinctUntilChanged, filter, first, map, take } from 'rxjs/operators';
|
||||
import { delay, distinctUntilChanged, filter, first, map, take, tap } from 'rxjs/operators';
|
||||
import { Observable } from 'rxjs';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { hasValue, isNotEmpty } from '../../shared/empty.util';
|
||||
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
|
||||
import { ResponseCacheService } from '../cache/response-cache.service';
|
||||
import { CoreState } from '../core.reducers';
|
||||
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
||||
import { URLCombiner } from '../url-combiner/url-combiner';
|
||||
@@ -15,9 +14,9 @@ import { NormalizedObject } from '../cache/models/normalized-object.model';
|
||||
import { compare, Operation } from 'fast-json-patch';
|
||||
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||
import { DSpaceObject } from '../shared/dspace-object.model';
|
||||
import { of } from 'rxjs/internal/observable/of';
|
||||
|
||||
export abstract class DataService<TNormalized extends NormalizedObject, TDomain> {
|
||||
protected abstract responseCache: ResponseCacheService;
|
||||
protected abstract requestService: RequestService;
|
||||
protected abstract rdbService: RemoteDataBuildService;
|
||||
protected abstract store: Store<CoreState>;
|
||||
@@ -25,34 +24,31 @@ export abstract class DataService<TNormalized extends NormalizedObject, TDomain>
|
||||
protected abstract halService: HALEndpointService;
|
||||
protected abstract objectCache: ObjectCacheService;
|
||||
|
||||
public abstract getBrowseEndpoint(options: FindAllOptions): Observable<string>
|
||||
public abstract getBrowseEndpoint(options: FindAllOptions, linkPath?: string): Observable<string>
|
||||
|
||||
protected getFindAllHref(options: FindAllOptions = {}): Observable<string> {
|
||||
protected getFindAllHref(options: FindAllOptions = {}, linkPath?: string): Observable<string> {
|
||||
let result: Observable<string>;
|
||||
const args = [];
|
||||
|
||||
result = this.getBrowseEndpoint(options).pipe(distinctUntilChanged());
|
||||
|
||||
result = this.getBrowseEndpoint(options, linkPath);
|
||||
if (hasValue(options.currentPage) && typeof options.currentPage === 'number') {
|
||||
/* TODO: this is a temporary fix for the pagination start index (0 or 1) discrepancy between the rest and the frontend respectively */
|
||||
args.push(`page=${options.currentPage - 1}`);
|
||||
}
|
||||
|
||||
if (hasValue(options.elementsPerPage)) {
|
||||
args.push(`size=${options.elementsPerPage}`);
|
||||
}
|
||||
|
||||
if (hasValue(options.sort)) {
|
||||
args.push(`sort=${options.sort.field},${options.sort.direction}`);
|
||||
}
|
||||
|
||||
if (hasValue(options.startsWith)) {
|
||||
args.push(`startsWith=${options.startsWith}`);
|
||||
}
|
||||
|
||||
if (isNotEmpty(args)) {
|
||||
return result.pipe(map((href: string) => new URLCombiner(href, `?${args.join('&')}`).toString()));
|
||||
} else {
|
||||
result.subscribe((t) => console.log(t));
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -115,6 +111,7 @@ export abstract class DataService<TNormalized extends NormalizedObject, TDomain>
|
||||
this.objectCache.addPatch(object.self, operations);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO implement, after the structure of the REST server's POST response is finalized
|
||||
// create(dso: DSpaceObject): Observable<RemoteData<TDomain>> {
|
||||
// const postHrefObs = this.getEndpoint();
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { RestResponse } from '../cache/response-cache.models';
|
||||
import { RestResponse } from '../cache/response.models';
|
||||
import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
|
||||
import { ResponseParsingService } from './parsing.service';
|
||||
import { RestRequest } from './request.models';
|
||||
|
@@ -7,7 +7,7 @@ import { NormalizedObject } from '../cache/models/normalized-object.model';
|
||||
import { ResourceType } from '../shared/resource-type';
|
||||
import { NormalizedObjectFactory } from '../cache/models/normalized-object-factory';
|
||||
import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
|
||||
import { RestResponse, DSOSuccessResponse } from '../cache/response-cache.models';
|
||||
import { RestResponse, DSOSuccessResponse } from '../cache/response.models';
|
||||
import { RestRequest } from './request.models';
|
||||
|
||||
import { ResponseParsingService } from './parsing.service';
|
||||
@@ -23,12 +23,14 @@ export class DSOResponseParsingService extends BaseResponseParsingService implem
|
||||
constructor(
|
||||
@Inject(GLOBAL_CONFIG) protected EnvConfig: GlobalConfig,
|
||||
protected objectCache: ObjectCacheService,
|
||||
) { super();
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
parse(request: RestRequest, data: DSpaceRESTV2Response): RestResponse {
|
||||
const processRequestDTO = this.process<NormalizedObject,ResourceType>(data.payload, request.href);
|
||||
const processRequestDTO = this.process<NormalizedObject, ResourceType>(data.payload, request.href);
|
||||
let objectList = processRequestDTO;
|
||||
|
||||
if (hasNoValue(processRequestDTO)) {
|
||||
return new DSOSuccessResponse([], data.statusCode, undefined)
|
||||
}
|
||||
|
@@ -3,7 +3,6 @@ import { Store } from '@ngrx/store';
|
||||
import { Observable } from 'rxjs';
|
||||
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
|
||||
import { NormalizedDSpaceObject } from '../cache/models/normalized-dspace-object.model';
|
||||
import { ResponseCacheService } from '../cache/response-cache.service';
|
||||
import { CoreState } from '../core.reducers';
|
||||
import { DSpaceObject } from '../shared/dspace-object.model';
|
||||
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
||||
@@ -18,7 +17,6 @@ class DataServiceImpl extends DataService<NormalizedDSpaceObject, DSpaceObject>
|
||||
protected linkPath = 'dso';
|
||||
|
||||
constructor(
|
||||
protected responseCache: ResponseCacheService,
|
||||
protected requestService: RequestService,
|
||||
protected rdbService: RemoteDataBuildService,
|
||||
protected store: Store<CoreState>,
|
||||
@@ -27,8 +25,8 @@ class DataServiceImpl extends DataService<NormalizedDSpaceObject, DSpaceObject>
|
||||
super();
|
||||
}
|
||||
|
||||
getBrowseEndpoint(options: FindAllOptions): Observable<string> {
|
||||
return this.halService.getEndpoint(this.linkPath);
|
||||
getBrowseEndpoint(options: FindAllOptions = {}, linkPath: string = this.linkPath): Observable<string> {
|
||||
return this.halService.getEndpoint(linkPath);
|
||||
}
|
||||
|
||||
getFindByIDHref(endpoint, resourceID): string {
|
||||
@@ -46,7 +44,7 @@ export class DSpaceObjectDataService {
|
||||
protected rdbService: RemoteDataBuildService,
|
||||
protected halService: HALEndpointService,
|
||||
protected objectCache: ObjectCacheService) {
|
||||
this.dataService = new DataServiceImpl(null, requestService, rdbService, null, halService, objectCache);
|
||||
this.dataService = new DataServiceImpl(requestService, rdbService, null, halService, objectCache);
|
||||
}
|
||||
|
||||
findById(uuid: string): Observable<RemoteData<DSpaceObject>> {
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { Inject, Injectable } from '@angular/core';
|
||||
import { GLOBAL_CONFIG } from '../../../config';
|
||||
import { GlobalConfig } from '../../../config/global-config.interface';
|
||||
import { ErrorResponse, RestResponse, EndpointMapSuccessResponse } from '../cache/response-cache.models';
|
||||
import { ErrorResponse, RestResponse, EndpointMapSuccessResponse } from '../cache/response.models';
|
||||
import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
|
||||
import { ResponseParsingService } from './parsing.service';
|
||||
import { RestRequest } from './request.models';
|
||||
|
@@ -2,7 +2,7 @@ import { Inject, Injectable } from '@angular/core';
|
||||
import {
|
||||
FacetConfigSuccessResponse,
|
||||
RestResponse
|
||||
} from '../cache/response-cache.models';
|
||||
} from '../cache/response.models';
|
||||
import { ResponseParsingService } from './parsing.service';
|
||||
import { RestRequest } from './request.models';
|
||||
import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
|
||||
|
@@ -4,7 +4,7 @@ import {
|
||||
FacetValueMapSuccessResponse,
|
||||
FacetValueSuccessResponse,
|
||||
RestResponse
|
||||
} from '../cache/response-cache.models';
|
||||
} from '../cache/response.models';
|
||||
import { ResponseParsingService } from './parsing.service';
|
||||
import { RestRequest } from './request.models';
|
||||
import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
|
||||
|
@@ -4,7 +4,7 @@ import {
|
||||
FacetValueMapSuccessResponse,
|
||||
FacetValueSuccessResponse,
|
||||
RestResponse
|
||||
} from '../cache/response-cache.models';
|
||||
} from '../cache/response.models';
|
||||
import { ResponseParsingService } from './parsing.service';
|
||||
import { RestRequest } from './request.models';
|
||||
import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
|
||||
|
@@ -3,7 +3,6 @@ import { cold, getTestScheduler } from 'jasmine-marbles';
|
||||
import { TestScheduler } from 'rxjs/testing';
|
||||
import { BrowseService } from '../browse/browse.service';
|
||||
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
|
||||
import { ResponseCacheService } from '../cache/response-cache.service';
|
||||
import { CoreState } from '../core.reducers';
|
||||
import { ItemDataService } from './item-data.service';
|
||||
import { RequestService } from './request.service';
|
||||
@@ -16,7 +15,6 @@ describe('ItemDataService', () => {
|
||||
let service: ItemDataService;
|
||||
let bs: BrowseService;
|
||||
const requestService = {} as RequestService;
|
||||
const responseCache = {} as ResponseCacheService;
|
||||
const rdbService = {} as RemoteDataBuildService;
|
||||
const objectCache = {} as ObjectCacheService;
|
||||
const store = {} as Store<CoreState>;
|
||||
@@ -48,7 +46,6 @@ describe('ItemDataService', () => {
|
||||
|
||||
function initTestService() {
|
||||
return new ItemDataService(
|
||||
responseCache,
|
||||
requestService,
|
||||
rdbService,
|
||||
store,
|
||||
|
@@ -7,7 +7,6 @@ import { isNotEmpty } from '../../shared/empty.util';
|
||||
import { BrowseService } from '../browse/browse.service';
|
||||
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
|
||||
import { NormalizedItem } from '../cache/models/normalized-item.model';
|
||||
import { ResponseCacheService } from '../cache/response-cache.service';
|
||||
import { CoreState } from '../core.reducers';
|
||||
import { Item } from '../shared/item.model';
|
||||
import { URLCombiner } from '../url-combiner/url-combiner';
|
||||
@@ -23,7 +22,6 @@ export class ItemDataService extends DataService<NormalizedItem, Item> {
|
||||
protected linkPath = 'items';
|
||||
|
||||
constructor(
|
||||
protected responseCache: ResponseCacheService,
|
||||
protected requestService: RequestService,
|
||||
protected rdbService: RemoteDataBuildService,
|
||||
protected store: Store<CoreState>,
|
||||
@@ -39,12 +37,12 @@ export class ItemDataService extends DataService<NormalizedItem, Item> {
|
||||
* @param {FindAllOptions} options
|
||||
* @returns {Observable<string>}
|
||||
*/
|
||||
public getBrowseEndpoint(options: FindAllOptions = {}): Observable<string> {
|
||||
public getBrowseEndpoint(options: FindAllOptions = {}, linkPath: string = this.linkPath): Observable<string> {
|
||||
let field = 'dc.date.issued';
|
||||
if (options.sort && options.sort.field) {
|
||||
field = options.sort.field;
|
||||
}
|
||||
return this.bs.getBrowseURLFor(field, this.linkPath).pipe(
|
||||
return this.bs.getBrowseURLFor(field, linkPath).pipe(
|
||||
filter((href: string) => isNotEmpty(href)),
|
||||
map((href: string) => new URLCombiner(href, `?scope=${options.scopeID}`).toString()),
|
||||
distinctUntilChanged(),);
|
||||
|
@@ -4,7 +4,7 @@ import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.
|
||||
import { RestRequest } from './request.models';
|
||||
import { ResponseParsingService } from './parsing.service';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { MetadataschemaSuccessResponse, RestResponse } from '../cache/response-cache.models';
|
||||
import { MetadataschemaSuccessResponse, RestResponse } from '../cache/response.models';
|
||||
|
||||
@Injectable()
|
||||
export class MetadataschemaParsingService implements ResponseParsingService {
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
|
||||
import { RestRequest } from './request.models';
|
||||
import { RestResponse } from '../cache/response-cache.models';
|
||||
import { RestResponse } from '../cache/response.models';
|
||||
|
||||
export interface ResponseParsingService {
|
||||
parse(request: RestRequest, data: DSpaceRESTV2Response): RestResponse;
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { RegistryBitstreamformatsSuccessResponse, RestResponse } from '../cache/response-cache.models';
|
||||
import { RegistryBitstreamformatsSuccessResponse, RestResponse } from '../cache/response.models';
|
||||
import { RegistryBitstreamformatsResponse } from '../registry/registry-bitstreamformats-response.model';
|
||||
import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer';
|
||||
import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import {
|
||||
RegistryMetadatafieldsSuccessResponse,
|
||||
RestResponse
|
||||
} from '../cache/response-cache.models';
|
||||
} from '../cache/response.models';
|
||||
import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
|
||||
import { RestRequest } from './request.models';
|
||||
import { ResponseParsingService } from './parsing.service';
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { RegistryMetadataschemasSuccessResponse, RestResponse } from '../cache/response-cache.models';
|
||||
import { RegistryMetadataschemasSuccessResponse, RestResponse } from '../cache/response.models';
|
||||
import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
|
||||
import { RestRequest } from './request.models';
|
||||
import { ResponseParsingService } from './parsing.service';
|
||||
|
@@ -1,6 +1,7 @@
|
||||
import { Action } from '@ngrx/store';
|
||||
import { type } from '../../shared/ngrx/type';
|
||||
import { RestRequest } from './request.models';
|
||||
import { RestResponse } from '../cache/response.models';
|
||||
|
||||
/**
|
||||
* The list of RequestAction type definitions
|
||||
@@ -8,7 +9,8 @@ import { RestRequest } from './request.models';
|
||||
export const RequestActionTypes = {
|
||||
CONFIGURE: type('dspace/core/data/request/CONFIGURE'),
|
||||
EXECUTE: type('dspace/core/data/request/EXECUTE'),
|
||||
COMPLETE: type('dspace/core/data/request/COMPLETE')
|
||||
COMPLETE: type('dspace/core/data/request/COMPLETE'),
|
||||
RESET_TIMESTAMPS: type('dspace/core/data/request/RESET_TIMESTAMPS')
|
||||
};
|
||||
|
||||
/* tslint:disable:max-classes-per-file */
|
||||
@@ -43,7 +45,10 @@ export class RequestExecuteAction implements Action {
|
||||
*/
|
||||
export class RequestCompleteAction implements Action {
|
||||
type = RequestActionTypes.COMPLETE;
|
||||
payload: string;
|
||||
payload: {
|
||||
uuid: string,
|
||||
response: RestResponse
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new RequestCompleteAction
|
||||
@@ -51,10 +56,32 @@ export class RequestCompleteAction implements Action {
|
||||
* @param uuid
|
||||
* the request's uuid
|
||||
*/
|
||||
constructor(uuid: string) {
|
||||
this.payload = uuid;
|
||||
constructor(uuid: string, response: RestResponse) {
|
||||
this.payload = {
|
||||
uuid,
|
||||
response
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An ngrx action to reset the timeAdded property of all responses in the cached objects
|
||||
*/
|
||||
export class ResetResponseTimestampsAction implements Action {
|
||||
type = RequestActionTypes.RESET_TIMESTAMPS;
|
||||
payload: number;
|
||||
|
||||
/**
|
||||
* Create a new ResetResponseTimestampsAction
|
||||
*
|
||||
* @param newTimestamp
|
||||
* the new timeAdded all objects should get
|
||||
*/
|
||||
constructor(newTimestamp: number) {
|
||||
this.payload = newTimestamp;
|
||||
}
|
||||
}
|
||||
|
||||
/* tslint:enable:max-classes-per-file */
|
||||
|
||||
/**
|
||||
@@ -63,4 +90,5 @@ export class RequestCompleteAction implements Action {
|
||||
export type RequestAction
|
||||
= RequestConfigureAction
|
||||
| RequestExecuteAction
|
||||
| RequestCompleteAction;
|
||||
| RequestCompleteAction
|
||||
| ResetResponseTimestampsAction;
|
||||
|
@@ -1,30 +1,33 @@
|
||||
|
||||
import {of as observableOf, Observable } from 'rxjs';
|
||||
import { Observable, of as observableOf } from 'rxjs';
|
||||
import { Inject, Injectable, Injector } from '@angular/core';
|
||||
import { Request } from '@angular/http';
|
||||
import { RequestArgs } from '@angular/http/src/interfaces';
|
||||
import { Actions, Effect, ofType } from '@ngrx/effects';
|
||||
|
||||
import { GLOBAL_CONFIG, GlobalConfig } from '../../../config';
|
||||
import { isNotEmpty } from '../../shared/empty.util';
|
||||
import { ErrorResponse, RestResponse } from '../cache/response-cache.models';
|
||||
import { ResponseCacheService } from '../cache/response-cache.service';
|
||||
import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
|
||||
|
||||
import { DSpaceRESTv2Service } from '../dspace-rest-v2/dspace-rest-v2.service';
|
||||
import { RequestActionTypes, RequestCompleteAction, RequestExecuteAction } from './request.actions';
|
||||
import {
|
||||
RequestActionTypes,
|
||||
RequestCompleteAction,
|
||||
RequestExecuteAction,
|
||||
ResetResponseTimestampsAction
|
||||
} from './request.actions';
|
||||
import { RequestError, RestRequest } from './request.models';
|
||||
import { RequestEntry } from './request.reducer';
|
||||
import { RequestService } from './request.service';
|
||||
import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer';
|
||||
import { NormalizedObjectFactory } from '../cache/models/normalized-object-factory';
|
||||
import { catchError, flatMap, map, take, tap } from 'rxjs/operators';
|
||||
import { ErrorResponse, RestResponse } from '../cache/response.models';
|
||||
import { StoreActionTypes } from '../../store.actions';
|
||||
|
||||
export const addToResponseCacheAndCompleteAction = (request: RestRequest, responseCache: ResponseCacheService, envConfig: GlobalConfig) =>
|
||||
(source: Observable<ErrorResponse>): Observable<RequestCompleteAction> =>
|
||||
export const addToResponseCacheAndCompleteAction = (request: RestRequest, envConfig: GlobalConfig) =>
|
||||
(source: Observable<RestResponse>): Observable<RequestCompleteAction> =>
|
||||
source.pipe(
|
||||
tap((response: RestResponse) => responseCache.add(request.href, response, request.responseMsToLive ? request.responseMsToLive : envConfig.cache.msToLive.default)),
|
||||
map((response: RestResponse) => new RequestCompleteAction(request.uuid))
|
||||
map((response: RestResponse) => {
|
||||
return new RequestCompleteAction(request.uuid, response)
|
||||
})
|
||||
);
|
||||
|
||||
@Injectable()
|
||||
@@ -46,20 +49,32 @@ export class RequestEffects {
|
||||
}
|
||||
return this.restApi.request(request.method, request.href, body, request.options).pipe(
|
||||
map((data: DSpaceRESTV2Response) => this.injector.get(request.getResponseParser()).parse(request, data)),
|
||||
addToResponseCacheAndCompleteAction(request, this.responseCache, this.EnvConfig),
|
||||
addToResponseCacheAndCompleteAction(request, this.EnvConfig),
|
||||
catchError((error: RequestError) => observableOf(new ErrorResponse(error)).pipe(
|
||||
addToResponseCacheAndCompleteAction(request, this.responseCache, this.EnvConfig)
|
||||
addToResponseCacheAndCompleteAction(request, this.EnvConfig)
|
||||
))
|
||||
);
|
||||
})
|
||||
);
|
||||
|
||||
/**
|
||||
* When the store is rehydrated in the browser, set all cache
|
||||
* timestamps to 'now', because the time zone of the server can
|
||||
* differ from the client.
|
||||
*
|
||||
* This assumes that the server cached everything a negligible
|
||||
* time ago, and will likely need to be revisited later
|
||||
*/
|
||||
@Effect() fixTimestampsOnRehydrate = this.actions$
|
||||
.pipe(ofType(StoreActionTypes.REHYDRATE),
|
||||
map(() => new ResetResponseTimestampsAction(new Date().getTime()))
|
||||
);
|
||||
|
||||
constructor(
|
||||
@Inject(GLOBAL_CONFIG) private EnvConfig: GlobalConfig,
|
||||
private actions$: Actions,
|
||||
private restApi: DSpaceRESTv2Service,
|
||||
private injector: Injector,
|
||||
private responseCache: ResponseCacheService,
|
||||
protected requestService: RequestService
|
||||
) { }
|
||||
|
||||
|
@@ -14,32 +14,36 @@ import { BrowseItemsResponseParsingService } from './browse-items-response-parsi
|
||||
|
||||
/* tslint:disable:max-classes-per-file */
|
||||
|
||||
|
||||
export abstract class RestRequest {
|
||||
public responseMsToLive = 0;
|
||||
constructor(
|
||||
public uuid: string,
|
||||
public href: string,
|
||||
public method: RestRequestMethod = RestRequestMethod.GET,
|
||||
public body?: any,
|
||||
public options?: HttpOptions,
|
||||
public responseMsToLive?: number
|
||||
) {
|
||||
}
|
||||
|
||||
getResponseParser(): GenericConstructor<ResponseParsingService> {
|
||||
return DSOResponseParsingService;
|
||||
}
|
||||
|
||||
get toCache(): boolean {
|
||||
return this.responseMsToLive > 0;
|
||||
}
|
||||
}
|
||||
|
||||
export class GetRequest extends RestRequest {
|
||||
public responseMsToLive = 60 * 15 * 1000;
|
||||
|
||||
constructor(
|
||||
public uuid: string,
|
||||
public href: string,
|
||||
public body?: any,
|
||||
public options?: HttpOptions,
|
||||
public responseMsToLive?: number
|
||||
) {
|
||||
super(uuid, href, RestRequestMethod.GET, body, options, responseMsToLive)
|
||||
super(uuid, href, RestRequestMethod.GET, body, options)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,6 +216,7 @@ export class IntegrationRequest extends GetRequest {
|
||||
return IntegrationResponseParsingService;
|
||||
}
|
||||
}
|
||||
|
||||
export class RequestError extends Error {
|
||||
statusText: string;
|
||||
}
|
||||
|
@@ -1,14 +1,16 @@
|
||||
import {
|
||||
RequestActionTypes, RequestAction, RequestConfigureAction,
|
||||
RequestExecuteAction, RequestCompleteAction
|
||||
RequestExecuteAction, RequestCompleteAction, ResetResponseTimestampsAction
|
||||
} from './request.actions';
|
||||
import { RestRequest } from './request.models';
|
||||
import { RestResponse } from '../cache/response.models';
|
||||
|
||||
export class RequestEntry {
|
||||
request: RestRequest;
|
||||
requestPending: boolean;
|
||||
responsePending: boolean;
|
||||
completed: boolean;
|
||||
response: RestResponse
|
||||
}
|
||||
|
||||
export interface RequestState {
|
||||
@@ -32,6 +34,9 @@ export function requestReducer(state = initialState, action: RequestAction): Req
|
||||
case RequestActionTypes.COMPLETE: {
|
||||
return completeRequest(state, action as RequestCompleteAction);
|
||||
}
|
||||
case RequestActionTypes.RESET_TIMESTAMPS: {
|
||||
return resetResponseTimestamps(state, action as ResetResponseTimestampsAction);
|
||||
}
|
||||
|
||||
default: {
|
||||
return state;
|
||||
@@ -45,7 +50,7 @@ function configureRequest(state: RequestState, action: RequestConfigureAction):
|
||||
request: action.payload,
|
||||
requestPending: true,
|
||||
responsePending: false,
|
||||
completed: false
|
||||
completed: false,
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -70,10 +75,25 @@ function executeRequest(state: RequestState, action: RequestExecuteAction): Requ
|
||||
* the new state, with the response added to the request
|
||||
*/
|
||||
function completeRequest(state: RequestState, action: RequestCompleteAction): RequestState {
|
||||
return Object.assign({}, state, {
|
||||
[action.payload]: Object.assign({}, state[action.payload], {
|
||||
const time = new Date().getTime();
|
||||
|
||||
const ob = Object.assign({}, state, {
|
||||
[action.payload.uuid]: Object.assign({}, state[action.payload.uuid], {
|
||||
responsePending: false,
|
||||
completed: true
|
||||
completed: true,
|
||||
response: Object.assign({}, action.payload.response, { timeAdded: time })
|
||||
})
|
||||
});
|
||||
console.log(ob);
|
||||
return ob;
|
||||
}
|
||||
|
||||
function resetResponseTimestamps(state: RequestState, action: ResetResponseTimestampsAction) {
|
||||
const newState = Object.create(null);
|
||||
Object.keys(state).forEach((key) => {
|
||||
newState[key] = Object.assign({}, state[key],
|
||||
{ response: Object.assign({}, state[key].response, { timeAdded: action.payload }) }
|
||||
);
|
||||
});
|
||||
return newState;
|
||||
}
|
||||
|
@@ -1,10 +1,8 @@
|
||||
import { cold, getTestScheduler, hot } from 'jasmine-marbles';
|
||||
import { of as observableOf } from 'rxjs';
|
||||
import { getMockObjectCacheService } from '../../shared/mocks/mock-object-cache.service';
|
||||
import { getMockResponseCacheService } from '../../shared/mocks/mock-response-cache.service';
|
||||
import { defaultUUID, getMockUUIDService } from '../../shared/mocks/mock-uuid.service';
|
||||
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||
import { ResponseCacheService } from '../cache/response-cache.service';
|
||||
import { CoreState } from '../core.reducers';
|
||||
import { UUIDService } from '../shared/uuid.service';
|
||||
import { RequestConfigureAction, RequestExecuteAction } from './request.actions';
|
||||
@@ -29,7 +27,6 @@ describe('RequestService', () => {
|
||||
let service: RequestService;
|
||||
let serviceAsAny: any;
|
||||
let objectCache: ObjectCacheService;
|
||||
let responseCache: ResponseCacheService;
|
||||
let uuidService: UUIDService;
|
||||
let store: Store<CoreState>;
|
||||
|
||||
@@ -49,7 +46,6 @@ describe('RequestService', () => {
|
||||
objectCache = getMockObjectCacheService();
|
||||
(objectCache.hasBySelfLink as any).and.returnValue(false);
|
||||
|
||||
responseCache = getMockResponseCacheService();
|
||||
(responseCache.has as any).and.returnValue(false);
|
||||
(responseCache.get as any).and.returnValue(observableOf(undefined));
|
||||
|
||||
@@ -65,7 +61,6 @@ describe('RequestService', () => {
|
||||
|
||||
service = new RequestService(
|
||||
objectCache,
|
||||
responseCache,
|
||||
uuidService,
|
||||
store
|
||||
);
|
||||
|
@@ -1,14 +1,23 @@
|
||||
import { Observable, merge as observableMerge } from 'rxjs';
|
||||
import { filter, first, map, mergeMap, partition, take } from 'rxjs/operators';
|
||||
import { merge as observableMerge, Observable, of as observableOf } from 'rxjs';
|
||||
import {
|
||||
filter,
|
||||
find,
|
||||
first,
|
||||
map,
|
||||
mergeMap,
|
||||
reduce,
|
||||
startWith,
|
||||
switchMap,
|
||||
take,
|
||||
tap
|
||||
} from 'rxjs/operators';
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
import { MemoizedSelector, select, Store } from '@ngrx/store';
|
||||
import { hasValue } from '../../shared/empty.util';
|
||||
import { hasNoValue, hasValue } from '../../shared/empty.util';
|
||||
import { CacheableObject } from '../cache/object-cache.reducer';
|
||||
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||
import { DSOSuccessResponse, RestResponse } from '../cache/response-cache.models';
|
||||
import { ResponseCacheEntry } from '../cache/response-cache.reducer';
|
||||
import { ResponseCacheService } from '../cache/response-cache.service';
|
||||
import { DSOSuccessResponse, RestResponse } from '../cache/response.models';
|
||||
import { coreSelector, CoreState } from '../core.reducers';
|
||||
import { IndexName } from '../index/index.reducer';
|
||||
import { pathSelector } from '../shared/selectors';
|
||||
@@ -19,13 +28,13 @@ import { GetRequest, RestRequest } from './request.models';
|
||||
import { RequestEntry } from './request.reducer';
|
||||
import { CommitSSBAction } from '../cache/server-sync-buffer.actions';
|
||||
import { RestRequestMethod } from './rest-request-method';
|
||||
import { getResponseFromEntry } from '../shared/operators';
|
||||
|
||||
@Injectable()
|
||||
export class RequestService {
|
||||
private requestsOnTheirWayToTheStore: string[] = [];
|
||||
|
||||
constructor(private objectCache: ObjectCacheService,
|
||||
private responseCache: ResponseCacheService,
|
||||
private uuidService: UUIDService,
|
||||
private store: Store<CoreState>) {
|
||||
}
|
||||
@@ -83,23 +92,27 @@ export class RequestService {
|
||||
|
||||
private isCachedOrPending(request: GetRequest) {
|
||||
let isCached = this.objectCache.hasBySelfLink(request.href);
|
||||
if (!isCached && this.responseCache.has(request.href)) {
|
||||
const responses = this.responseCache.get(request.href).pipe(
|
||||
take(1),
|
||||
map((entry: ResponseCacheEntry) => entry.response)
|
||||
);
|
||||
const responses: Observable<RestResponse> = this.isReusable(request.uuid).pipe(
|
||||
filter((reusable: boolean) => !isCached && reusable),
|
||||
switchMap(() => {
|
||||
return this.getByHref(request.href).pipe(
|
||||
getResponseFromEntry(),
|
||||
take(1)
|
||||
);
|
||||
}
|
||||
));
|
||||
|
||||
const errorResponses = responses.pipe(filter((response) => !response.isSuccessful), map(() => true)); // TODO add a configurable number of retries in case of an error.
|
||||
const dsoSuccessResponses = responses.pipe(
|
||||
filter((response) => response.isSuccessful && hasValue((response as DSOSuccessResponse).resourceSelfLinks)),
|
||||
map((response: DSOSuccessResponse) => response.resourceSelfLinks),
|
||||
map((resourceSelfLinks: string[]) => resourceSelfLinks
|
||||
.every((selfLink) => this.objectCache.hasBySelfLink(selfLink))
|
||||
));
|
||||
const otherSuccessResponses = responses.pipe(filter((response) => response.isSuccessful && !hasValue((response as DSOSuccessResponse).resourceSelfLinks)), map(() => true));
|
||||
const errorResponses = responses.pipe(filter((response) => !response.isSuccessful), map(() => true)); // TODO add a configurable number of retries in case of an error.
|
||||
const dsoSuccessResponses = responses.pipe(
|
||||
filter((response) => response.isSuccessful && hasValue((response as DSOSuccessResponse).resourceSelfLinks)),
|
||||
map((response: DSOSuccessResponse) => response.resourceSelfLinks),
|
||||
map((resourceSelfLinks: string[]) => resourceSelfLinks
|
||||
.every((selfLink) => this.objectCache.hasBySelfLink(selfLink))
|
||||
));
|
||||
const otherSuccessResponses = responses.pipe(filter((response) => response.isSuccessful && !hasValue((response as DSOSuccessResponse).resourceSelfLinks)), map(() => true));
|
||||
|
||||
observableMerge(errorResponses, otherSuccessResponses, dsoSuccessResponses).subscribe((c) => isCached = c);
|
||||
|
||||
observableMerge(errorResponses, otherSuccessResponses, dsoSuccessResponses).subscribe((c) => isCached = c);
|
||||
}
|
||||
const isPending = this.isPending(request);
|
||||
return isCached || isPending;
|
||||
}
|
||||
@@ -129,4 +142,34 @@ export class RequestService {
|
||||
commit(method?: RestRequestMethod) {
|
||||
this.store.dispatch(new CommitSSBAction(method))
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether a ResponseCacheEntry should still be cached
|
||||
*
|
||||
* @param entry
|
||||
* the entry to check
|
||||
* @return boolean
|
||||
* false if the entry is null, undefined, or its time to
|
||||
* live has been exceeded, true otherwise
|
||||
*/
|
||||
private isReusable(uuid: string): Observable<boolean> {
|
||||
if (hasNoValue(uuid)) {
|
||||
return observableOf(false);
|
||||
} else {
|
||||
const requestEntry$ = this.getByUUID(uuid);
|
||||
return requestEntry$.pipe(
|
||||
filter((entry: RequestEntry) => hasValue(entry) && hasValue(entry.response)),
|
||||
map((entry: RequestEntry) => {
|
||||
if (hasValue(entry) && entry.response.isSuccessful) {
|
||||
const timeOutdated = entry.response.timeAdded + entry.request.responseMsToLive;
|
||||
const isOutDated = new Date().getTime() > timeOutdated;
|
||||
return !isOutDated;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
})
|
||||
);
|
||||
return observableOf(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { RestResponse, SearchSuccessResponse } from '../cache/response-cache.models';
|
||||
import { RestResponse, SearchSuccessResponse } from '../cache/response.models';
|
||||
import { DSOResponseParsingService } from './dso-response-parsing.service';
|
||||
import { ResponseParsingService } from './parsing.service';
|
||||
import { RestRequest } from './request.models';
|
||||
|
Reference in New Issue
Block a user