mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 10:04:11 +00:00
switched to resource-types for annotations to get around circular dependency issues
This commit is contained in:
@@ -42,7 +42,7 @@ export class AuthStatus implements CacheableObject {
|
||||
/**
|
||||
* The eperson of this auth status
|
||||
*/
|
||||
@link(EPerson)
|
||||
@link(EPerson.type)
|
||||
eperson: Observable<RemoteData<EPerson>>;
|
||||
|
||||
/**
|
||||
|
24
src/app/core/cache/builders/build-decorators.ts
vendored
24
src/app/core/cache/builders/build-decorators.ts
vendored
@@ -88,23 +88,23 @@ export function getRelationships(target: any) {
|
||||
return relationshipMap.get(target);
|
||||
}
|
||||
|
||||
export function dataService<T extends CacheableObject>(domainModelConstructor: GenericConstructor<T>): any {
|
||||
export function dataService(resourceType: ResourceType): any {
|
||||
return (target: any) => {
|
||||
if (hasNoValue(domainModelConstructor)) {
|
||||
throw new Error(`Invalid @dataService annotation on ${target}, domainModelConstructor needs to be defined`);
|
||||
if (hasNoValue(resourceType)) {
|
||||
throw new Error(`Invalid @dataService annotation on ${target}, resourceType needs to be defined`);
|
||||
}
|
||||
const existingDataservice = dataServiceMap.get(domainModelConstructor);
|
||||
const existingDataservice = dataServiceMap.get(resourceType.value);
|
||||
|
||||
if (hasValue(existingDataservice)) {
|
||||
throw new Error(`Multiple dataservices for ${domainModelConstructor}: ${existingDataservice} and ${target}`);
|
||||
throw new Error(`Multiple dataservices for ${resourceType.value}: ${existingDataservice} and ${target}`);
|
||||
}
|
||||
|
||||
dataServiceMap.set(domainModelConstructor, target);
|
||||
dataServiceMap.set(resourceType.value, target);
|
||||
};
|
||||
}
|
||||
|
||||
export function getDataServiceFor<T extends CacheableObject>(domainModelConstructor: GenericConstructor<T>) {
|
||||
return dataServiceMap.get(domainModelConstructor);
|
||||
export function getDataServiceFor<T extends CacheableObject>(resourceType: ResourceType) {
|
||||
return dataServiceMap.get(resourceType.value);
|
||||
}
|
||||
|
||||
export function resolvedLink<T extends DataService<any>, K extends keyof T>(provider: GenericConstructor<T>, methodName?: K, ...params: any[]): any {
|
||||
@@ -135,20 +135,18 @@ export function getResolvedLinks(target: any) {
|
||||
}
|
||||
|
||||
export class LinkDefinition<T extends HALResource> {
|
||||
targetConstructor: GenericConstructor<CacheableObject>;
|
||||
resourceType: ResourceType;
|
||||
isList = false;
|
||||
linkName: keyof T['_links'];
|
||||
propertyName: keyof T;
|
||||
}
|
||||
|
||||
export const link = <T extends HALResource>(
|
||||
targetConstructor: GenericConstructor<HALResource>,
|
||||
resourceType: ResourceType,
|
||||
isList = false,
|
||||
linkName?: keyof T['_links'],
|
||||
) => {
|
||||
console.log('link call', targetConstructor, isList, linkName);
|
||||
return (target: T, propertyName: string) => {
|
||||
console.log('link return', targetConstructor, isList, linkName, target, propertyName);
|
||||
let targetMap = linkMap.get(target.constructor);
|
||||
|
||||
if (hasNoValue(targetMap)) {
|
||||
@@ -160,7 +158,7 @@ export const link = <T extends HALResource>(
|
||||
}
|
||||
|
||||
targetMap.set(propertyName, {
|
||||
targetConstructor,
|
||||
resourceType,
|
||||
isList,
|
||||
linkName,
|
||||
propertyName
|
||||
|
4
src/app/core/cache/builders/link.service.ts
vendored
4
src/app/core/cache/builders/link.service.ts
vendored
@@ -21,10 +21,10 @@ export class LinkService {
|
||||
if (hasNoValue(matchingLinkDef)) {
|
||||
throw new Error(`followLink('${linkToFollow.name}') was used for a ${model.constructor.name}, but there is no property on ${model.constructor.name} models with an @link() for ${linkToFollow.name}`);
|
||||
} else {
|
||||
const provider = getDataServiceFor(matchingLinkDef.targetConstructor);
|
||||
const provider = getDataServiceFor(matchingLinkDef.resourceType);
|
||||
|
||||
if (hasNoValue(provider)) {
|
||||
throw new Error(`The @link() for ${linkToFollow.name} on ${model.constructor.name} models refers to a ${matchingLinkDef.targetConstructor.name}, but there is no service with an @dataService(${matchingLinkDef.targetConstructor.name}) annotation in order to retrieve it`);
|
||||
throw new Error(`The @link() for ${linkToFollow.name} on ${model.constructor.name} models uses the resource type ${matchingLinkDef.resourceType.value.toUpperCase()}, but there is no service with an @dataService(${matchingLinkDef.resourceType.value.toUpperCase()}) annotation in order to retrieve it`);
|
||||
}
|
||||
|
||||
const service = Injector.create({
|
||||
|
@@ -28,7 +28,7 @@ import { RequestService } from './request.service';
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
@dataService(Bitstream)
|
||||
@dataService(Bitstream.type)
|
||||
export class BitstreamDataService extends DataService<Bitstream> {
|
||||
|
||||
protected linkPath = 'bitstreams';
|
||||
|
@@ -41,7 +41,7 @@ const selectedBitstreamFormatSelector = createSelector(bitstreamFormatsStateSele
|
||||
* A service responsible for fetching/sending data from/to the REST API on the bitstreamformats endpoint
|
||||
*/
|
||||
@Injectable()
|
||||
@dataService(BitstreamFormat)
|
||||
@dataService(BitstreamFormat.type)
|
||||
export class BitstreamFormatDataService extends DataService<BitstreamFormat> {
|
||||
|
||||
protected linkPath = 'bitstreamformats';
|
||||
|
@@ -27,7 +27,7 @@ import { RequestService } from './request.service';
|
||||
@Injectable(
|
||||
{providedIn: 'root'}
|
||||
)
|
||||
@dataService(Bundle)
|
||||
@dataService(Bundle.type)
|
||||
export class BundleDataService extends DataService<Bundle> {
|
||||
protected linkPath = 'bundles';
|
||||
protected forceBypassCache = false;
|
||||
|
@@ -49,7 +49,7 @@ import { INotification } from '../../shared/notifications/models/notification.mo
|
||||
import { PaginatedSearchOptions } from '../../shared/search/paginated-search-options.model';
|
||||
|
||||
@Injectable()
|
||||
@dataService(Collection)
|
||||
@dataService(Collection.type)
|
||||
export class CollectionDataService extends ComColDataService<Collection> {
|
||||
protected linkPath = 'collections';
|
||||
protected errorTitle = 'collection.source.update.notifications.error.title';
|
||||
|
@@ -21,7 +21,7 @@ import { NormalizedObjectBuildService } from '../cache/builders/normalized-objec
|
||||
import { DSOChangeAnalyzer } from './dso-change-analyzer.service';
|
||||
|
||||
@Injectable()
|
||||
@dataService(Community)
|
||||
@dataService(Community.type)
|
||||
export class CommunityDataService extends ComColDataService<Community> {
|
||||
protected linkPath = 'communities';
|
||||
protected topLinkPath = 'communities/search/top';
|
||||
|
@@ -39,7 +39,7 @@ class DataServiceImpl extends DataService<DSpaceObject> {
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
@dataService(DSpaceObject)
|
||||
@dataService(DSpaceObject.type)
|
||||
export class DSpaceObjectDataService {
|
||||
protected linkPath = 'dso';
|
||||
private dataService: DataServiceImpl;
|
||||
|
@@ -41,7 +41,7 @@ import { PaginatedList } from './paginated-list';
|
||||
import { ExternalSourceEntry } from '../shared/external-source-entry.model';
|
||||
|
||||
@Injectable()
|
||||
@dataService(Item)
|
||||
@dataService(Item.type)
|
||||
export class ItemDataService extends DataService<Item> {
|
||||
protected linkPath = 'items';
|
||||
|
||||
|
@@ -1,6 +1,5 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { Observable } from 'rxjs';
|
||||
import { dataService } from '../cache/builders/build-decorators';
|
||||
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
|
||||
import { CoreState } from '../core.reducers';
|
||||
@@ -8,7 +7,6 @@ import { CoreState } from '../core.reducers';
|
||||
import { DataService } from './data.service';
|
||||
import { RequestService } from './request.service';
|
||||
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
||||
import { FindListOptions } from './request.models';
|
||||
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||
import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
@@ -40,7 +38,7 @@ class DataServiceImpl extends DataService<MetadataSchema> {
|
||||
* A service responsible for fetching/sending data from/to the REST API on the metadataschemas endpoint
|
||||
*/
|
||||
@Injectable()
|
||||
@dataService(MetadataSchema)
|
||||
@dataService(MetadataSchema.type)
|
||||
export class MetadataSchemaDataService {
|
||||
private dataService: DataServiceImpl;
|
||||
|
||||
|
@@ -28,7 +28,7 @@ import { FindListOptions, FindListRequest } from './request.models';
|
||||
* The service handling all relationship type requests
|
||||
*/
|
||||
@Injectable()
|
||||
@dataService(RelationshipType)
|
||||
@dataService(RelationshipType.type)
|
||||
export class RelationshipTypeService extends DataService<RelationshipType> {
|
||||
protected linkPath = 'relationshiptypes';
|
||||
|
||||
|
@@ -47,7 +47,7 @@ const relationshipStateSelector = (listID: string, itemID: string): MemoizedSele
|
||||
* The service handling all relationship requests
|
||||
*/
|
||||
@Injectable()
|
||||
@dataService(Relationship)
|
||||
@dataService(Relationship.type)
|
||||
export class RelationshipService extends DataService<Relationship> {
|
||||
protected linkPath = 'relationships';
|
||||
|
||||
|
@@ -22,7 +22,7 @@ import { getSucceededRemoteData } from '../shared/operators';
|
||||
* Service responsible for handling requests related to the Site object
|
||||
*/
|
||||
@Injectable()
|
||||
@dataService(Site)
|
||||
@dataService(Site.type)
|
||||
export class SiteDataService extends DataService<Site> {
|
||||
protected linkPath = 'sites';
|
||||
|
||||
|
@@ -14,7 +14,7 @@ import { HALEndpointService } from '../shared/hal-endpoint.service';
|
||||
import { EPerson } from './models/eperson.model';
|
||||
|
||||
@Injectable()
|
||||
@dataService(EPerson)
|
||||
@dataService(EPerson.type)
|
||||
export class EPersonDataService extends DataService<EPerson> {
|
||||
|
||||
protected linkPath: 'eperson/epersons';
|
||||
|
@@ -41,7 +41,7 @@ export class MetadataField extends ListableObject implements HALResource {
|
||||
/**
|
||||
* The metadata schema object of this metadata field
|
||||
*/
|
||||
@link(MetadataSchema)
|
||||
@link(MetadataSchema.type)
|
||||
// TODO the responseparsingservice assumes schemas are always embedded. This should be remotedata instead.
|
||||
schema?: MetadataSchema;
|
||||
|
||||
|
@@ -34,17 +34,17 @@ export class Bitstream extends DSpaceObject implements HALResource {
|
||||
/**
|
||||
* The Bitstream Format for this Bitstream
|
||||
*/
|
||||
@link(BitstreamFormat)
|
||||
@link(BitstreamFormat.type)
|
||||
format?: Observable<RemoteData<BitstreamFormat>>;
|
||||
|
||||
_links: {
|
||||
// @link(Bitstream)
|
||||
// @link(Bitstream.type)
|
||||
self: HALLink;
|
||||
|
||||
// @link(Bundle)
|
||||
// @link(Bundle.type)
|
||||
bundle: HALLink;
|
||||
|
||||
// @link(BitstreamFormat)
|
||||
// @link(BitstreamFormat.type)
|
||||
format: HALLink;
|
||||
|
||||
content: HALLink;
|
||||
|
@@ -66,13 +66,13 @@ export class Collection extends DSpaceObject {
|
||||
/**
|
||||
* The Bitstream that represents the logo of this Collection
|
||||
*/
|
||||
@link(Bitstream)
|
||||
@link(Bitstream.type)
|
||||
logo?: Observable<RemoteData<Bitstream>>;
|
||||
|
||||
/**
|
||||
* The default access conditions of this Collection
|
||||
*/
|
||||
@link(ResourcePolicy, true)
|
||||
@link(ResourcePolicy.type, true)
|
||||
defaultAccessConditions?: Observable<RemoteData<PaginatedList<ResourcePolicy>>>;
|
||||
|
||||
_links: {
|
||||
|
@@ -51,13 +51,13 @@ export class Community extends DSpaceObject {
|
||||
/**
|
||||
* The Bitstream that represents the logo of this Community
|
||||
*/
|
||||
@link(Bitstream)
|
||||
@link(Bitstream.type)
|
||||
logo?: Observable<RemoteData<Bitstream>>;
|
||||
|
||||
@link(Collection, true)
|
||||
@link(Collection.type, true)
|
||||
collections?: Observable<RemoteData<PaginatedList<Collection>>>;
|
||||
|
||||
@link(Community, true)
|
||||
@link(Community.type, true)
|
||||
subcommunities?: Observable<RemoteData<PaginatedList<Community>>>;
|
||||
|
||||
_links: {
|
||||
|
@@ -65,13 +65,13 @@ export class RelationshipType implements CacheableObject {
|
||||
/**
|
||||
* The type of Item found to the left of this RelationshipType
|
||||
*/
|
||||
@link(ItemType)
|
||||
@link(ItemType.type)
|
||||
leftType?: Observable<RemoteData<ItemType>>;
|
||||
|
||||
/**
|
||||
* The type of Item found to the right of this RelationshipType
|
||||
*/
|
||||
@link(ItemType)
|
||||
@link(ItemType.type)
|
||||
rightType?: Observable<RemoteData<ItemType>>;
|
||||
|
||||
_links: {
|
||||
|
@@ -3,15 +3,16 @@ import { link } from '../../cache/builders/build-decorators';
|
||||
import { CacheableObject } from '../../cache/object-cache.reducer';
|
||||
import { RemoteData } from '../../data/remote-data';
|
||||
import { HALLink } from '../hal-link.model';
|
||||
import { ResourceType } from '../resource-type';
|
||||
import { RelationshipType } from './relationship-type.model';
|
||||
import { Item } from '../item.model';
|
||||
import { ITEM } from "../item-resource-type";
|
||||
import { RELATIONSHIP } from "../relationship.resource-type";
|
||||
|
||||
/**
|
||||
* Describes a Relationship between two Items
|
||||
*/
|
||||
export class Relationship implements CacheableObject {
|
||||
static type = new ResourceType('relationship');
|
||||
static type = RELATIONSHIP;
|
||||
|
||||
/**
|
||||
* The link to the rest endpoint where this object can be found
|
||||
@@ -32,14 +33,13 @@ export class Relationship implements CacheableObject {
|
||||
* The item to the left of this relationship
|
||||
*/
|
||||
|
||||
// TODO it's likely a circular dependency 😒 -> https://stackoverflow.com/questions/35240716/webpack-import-returns-undefined-depending-on-the-order-of-imports
|
||||
@link(Item)
|
||||
@link(ITEM)
|
||||
leftItem?: Observable<RemoteData<Item>>;
|
||||
|
||||
/**
|
||||
* The item to the right of this relationship
|
||||
*/
|
||||
@link(Item)
|
||||
@link(ITEM)
|
||||
rightItem?: Observable<RemoteData<Item>>;
|
||||
|
||||
/**
|
||||
@@ -65,7 +65,7 @@ export class Relationship implements CacheableObject {
|
||||
/**
|
||||
* The type of Relationship
|
||||
*/
|
||||
@link(RelationshipType)
|
||||
@link(RelationshipType.type)
|
||||
relationshipType?: Observable<RemoteData<RelationshipType>>;
|
||||
|
||||
_links: {
|
||||
|
9
src/app/core/shared/item-resource-type.ts
Normal file
9
src/app/core/shared/item-resource-type.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { ResourceType } from "./resource-type";
|
||||
|
||||
/**
|
||||
* The resource type for Item.
|
||||
*
|
||||
* Needs to be in a separate file to prevent circular
|
||||
* dependencies in webpack.
|
||||
*/
|
||||
export const ITEM = new ResourceType('item');
|
@@ -12,13 +12,14 @@ import { DSpaceObject } from './dspace-object.model';
|
||||
import { GenericConstructor } from './generic-constructor';
|
||||
import { HALLink } from './hal-link.model';
|
||||
import { Relationship } from './item-relationships/relationship.model';
|
||||
import { ResourceType } from './resource-type';
|
||||
import { ITEM } from "./item-resource-type";
|
||||
import { RELATIONSHIP } from "./relationship.resource-type";
|
||||
|
||||
/**
|
||||
* Class representing a DSpace Item
|
||||
*/
|
||||
export class Item extends DSpaceObject {
|
||||
static type = new ResourceType('item');
|
||||
static type = ITEM;
|
||||
|
||||
/**
|
||||
* A string representing the unique handle of this Item
|
||||
@@ -48,13 +49,13 @@ export class Item extends DSpaceObject {
|
||||
/**
|
||||
* The Collection that owns this Item
|
||||
*/
|
||||
@link(Collection)
|
||||
@link(Collection.type)
|
||||
owningCollection: Observable<RemoteData<Collection>>;
|
||||
|
||||
@link(Bundle, true)
|
||||
@link(Bundle.type, true)
|
||||
bundles: Observable<RemoteData<PaginatedList<Bundle>>>;
|
||||
|
||||
@link(Relationship, true)
|
||||
@link(RELATIONSHIP)
|
||||
relationships: Observable<RemoteData<PaginatedList<Relationship>>>;
|
||||
|
||||
_links: {
|
||||
|
10
src/app/core/shared/relationship.resource-type.ts
Normal file
10
src/app/core/shared/relationship.resource-type.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { ResourceType } from "./resource-type";
|
||||
|
||||
/**
|
||||
* The resource type for Relationship.
|
||||
*
|
||||
* Needs to be in a separate file to prevent circular
|
||||
* dependencies in webpack.
|
||||
*/
|
||||
export const RELATIONSHIP = new ResourceType('relationship');
|
||||
|
@@ -39,13 +39,13 @@ export abstract class SubmissionObject extends DSpaceObject implements Cacheable
|
||||
/**
|
||||
* The collection this submission applies to
|
||||
*/
|
||||
@link(Collection)
|
||||
@link(Collection.type)
|
||||
collection?: Observable<RemoteData<Collection>> | Collection;
|
||||
|
||||
/**
|
||||
* The submission item
|
||||
*/
|
||||
@link(Item)
|
||||
@link(Item.type)
|
||||
item?: Observable<RemoteData<Item>> | Item;
|
||||
|
||||
/**
|
||||
@@ -56,13 +56,13 @@ export abstract class SubmissionObject extends DSpaceObject implements Cacheable
|
||||
/**
|
||||
* The configuration object that define this submission
|
||||
*/
|
||||
@link(SubmissionDefinitionsModel)
|
||||
@link(SubmissionDefinitionsModel.type)
|
||||
submissionDefinition?: Observable<RemoteData<SubmissionDefinitionsModel>> | SubmissionDefinitionsModel;
|
||||
|
||||
/**
|
||||
* The workspaceitem submitter
|
||||
*/
|
||||
@link(EPerson)
|
||||
@link(EPerson.type)
|
||||
submitter?: Observable<RemoteData<EPerson>> | EPerson;
|
||||
|
||||
/**
|
||||
|
@@ -19,7 +19,7 @@ import { DSOChangeAnalyzer } from '../data/dso-change-analyzer.service';
|
||||
* A service that provides methods to make REST requests with workflowitems endpoint.
|
||||
*/
|
||||
@Injectable()
|
||||
@dataService(WorkflowItem)
|
||||
@dataService(WorkflowItem.type)
|
||||
export class WorkflowItemDataService extends DataService<WorkflowItem> {
|
||||
protected linkPath = 'workflowitems';
|
||||
protected responseMsToLive = 10 * 1000;
|
||||
|
@@ -19,7 +19,7 @@ import { WorkspaceItem } from './models/workspaceitem.model';
|
||||
* A service that provides methods to make REST requests with workspaceitems endpoint.
|
||||
*/
|
||||
@Injectable()
|
||||
@dataService(WorkspaceItem)
|
||||
@dataService(WorkspaceItem.type)
|
||||
export class WorkspaceitemDataService extends DataService<WorkspaceItem> {
|
||||
protected linkPath = 'workspaceitems';
|
||||
protected responseMsToLive = 10 * 1000;
|
||||
|
@@ -21,7 +21,7 @@ import { ProcessTaskResponse } from './models/process-task-response';
|
||||
* The service handling all REST requests for ClaimedTask
|
||||
*/
|
||||
@Injectable()
|
||||
@dataService(ClaimedTask)
|
||||
@dataService(ClaimedTask.type)
|
||||
export class ClaimedTaskDataService extends TasksService<ClaimedTask> {
|
||||
|
||||
protected responseMsToLive = 10 * 1000;
|
||||
|
@@ -34,19 +34,19 @@ export class TaskObject extends DSpaceObject implements CacheableObject {
|
||||
/**
|
||||
* The group of this task
|
||||
*/
|
||||
@link(EPerson)
|
||||
@link(EPerson.type)
|
||||
eperson?: Observable<RemoteData<EPerson>>;
|
||||
|
||||
/**
|
||||
* The group of this task
|
||||
*/
|
||||
@link(Group)
|
||||
@link(Group.type)
|
||||
group?: Observable<RemoteData<Group>>;
|
||||
|
||||
/**
|
||||
* The workflowitem object whom this task is related
|
||||
*/
|
||||
@link(WorkflowItem)
|
||||
@link(WorkflowItem.type)
|
||||
workflowitem?: Observable<RemoteData<WorkflowItem>> | WorkflowItem;
|
||||
|
||||
_links: {
|
||||
|
@@ -21,7 +21,7 @@ import { ProcessTaskResponse } from './models/process-task-response';
|
||||
* The service handling all REST requests for PoolTask
|
||||
*/
|
||||
@Injectable()
|
||||
@dataService(PoolTask)
|
||||
@dataService(PoolTask.type)
|
||||
export class PoolTaskDataService extends TasksService<PoolTask> {
|
||||
|
||||
/**
|
||||
|
Reference in New Issue
Block a user