UNPKG

@knora/core

Version:
790 lines 109 kB
import * as tslib_1 from "tslib"; import { Injectable } from '@angular/core'; import { Constants } from '@knora/api'; import { forkJoin, from, of } from 'rxjs'; import { map, mergeMap } from 'rxjs/operators'; import { Utils } from '../../declarations/utils'; import { OntologyService } from './ontology.service'; import * as i0 from "@angular/core"; import * as i1 from "./ontology.service"; const jsonld = require('jsonld'); /** * @deprecated since v10.0.0 * * Will be replaced by `@knora/api` (github:knora-api-js-lib) * * Represents an error occurred in OntologyCacheService. */ class OntologyCacheError extends Error { constructor(message) { super(message); this.message = message; } } /** * * Represents an ontology's metadata. */ export class OntologyMetadata { /** * @hideconstructor * * @param {string} id Iri identifying the ontology. * @param {string} label a label describing the ontology. */ constructor(id, label) { this.id = id; this.label = label; } } /** * Occurrence of a property for a resource class (its cardinality). */ export var CardinalityOccurrence; (function (CardinalityOccurrence) { CardinalityOccurrence[CardinalityOccurrence["minCard"] = 0] = "minCard"; CardinalityOccurrence[CardinalityOccurrence["card"] = 1] = "card"; CardinalityOccurrence[CardinalityOccurrence["maxCard"] = 2] = "maxCard"; })(CardinalityOccurrence || (CardinalityOccurrence = {})); /** * Cardinality of a property for the given resource class. */ export class Cardinality { /** * @param {CardinalityOccurrence} occurrence type of given occurrence. * @param {number} value numerical value of given occurrence. * @param {string} property the property the given occurrence applies to. */ constructor(occurrence, value, property) { this.occurrence = occurrence; this.value = value; this.property = property; } } /** * Property gui order */ export class GuiOrder { /** * @param {number} value * @param {string} property */ constructor(value, property) { this.value = value; this.property = property; } } /** * A resource class definition. */ export class ResourceClass { /** * @param {string} id Iri identifying the resource class. * @param {string} icon path to an icon representing the resource class. * @param {string} comment comment on the resource class. * @param {string} label label describing the resource class. * @param {Cardinality[]} cardinalities the resource class's properties. * @param {GuiOrder[]} guiOrder the resource class's gui-order properties. */ constructor(id, icon, comment, label, cardinalities, guiOrder) { this.id = id; this.icon = icon; this.comment = comment; this.label = label; this.cardinalities = cardinalities; this.guiOrder = guiOrder; } } /** * A map of resource class Iris to resource class definitions. */ export class ResourceClasses { } /** * A property definition. */ export class Property { /** * @param {string} id Iri identifying the property definition. * @param {string} objectType the property's object constraint. * @param {string} comment comment on the property definition. * @param {string} label label describing the property definition. * @param {string[]} subPropertyOf Iris of properties the given property is a subproperty of. * @param {boolean} isEditable indicates whether the given property can be edited by the client. * @param {boolean} isLinkProperty indicates whether the given property is a linking property. * @param {boolean} isLinkValueProperty indicates whether the given property refers to a link value. * @param {string} guiAttribute the gui attribute assigned to this property, if any. */ constructor(id, objectType, comment, label, subPropertyOf, isEditable, isLinkProperty, isLinkValueProperty, guiAttribute) { this.id = id; this.objectType = objectType; this.comment = comment; this.label = label; this.subPropertyOf = subPropertyOf; this.isEditable = isEditable; this.isLinkProperty = isLinkProperty; this.isLinkValueProperty = isLinkValueProperty; this.guiAttribute = guiAttribute; } } /** * A map of property Iris to property definitions. */ export class Properties { } /** * Groups resource classes by the ontology they are defined in. * * A map of ontology Iris to an array of resource class Iris. */ export class ResourceClassIrisForOntology { } /** * Represents cached ontology information (only used by this service internally). * This cache is updated whenever new definitions are requested from Knora. * * Requested ontology information by a service is represented by [[OntologyInformation]]. */ class OntologyCache { constructor() { this.ontologies = []; this.resourceClassIrisForOntology = new ResourceClassIrisForOntology(); this.resourceClasses = new ResourceClasses(); this.properties = new Properties(); } } /** * Represents ontology information requested from this service. * * For every request, an instance of this class is returned containing the requested information. */ export class OntologyInformation { /** * @param {ResourceClassIrisForOntology} resourceClassesForOntology all resource class Iris for a given ontology. * @param {ResourceClasses} resourceClasses resource class definitions. * @param {Properties} properties property definitions. */ constructor(resourceClassesForOntology, resourceClasses, properties) { this.resourceClassesForOntology = resourceClassesForOntology; this.resourceClasses = resourceClasses; this.properties = properties; } /** * Sorts an array of `ResourceClass` or `Property` by label. * * @param a first element * @param b second element * @return negative -1 if the first element is considered lower than the second, 1 if the second element is considered bigger, 0 if they are equal */ static sortFunc(a, b) { // dealing with 'undefined' labels if (a.label === undefined) { return 1; } else if (b.label === undefined) { return -1; } const labelA = a.label.toLowerCase(); const labelB = b.label.toLowerCase(); if (labelA < labelB) { return -1; } else if (labelA > labelB) { return 1; } else { return 0; } } /** * Merge the given [[OntologyInformation]] into the current instance, * updating the existing information. * This is necessary when a service like the search fetches new results * that have to be added to an existing collection. * The existing ontology information must not be lost. * * @param {OntologyInformation} ontologyInfo the given definitions that have to be integrated. * @returns void */ updateOntologyInformation(ontologyInfo) { // get new resourceClassIrisForOntology const newResourceClassesForOntology = ontologyInfo.getResourceClassForOntology(); // update new resourceClassIrisForOntology // tslint:disable-next-line:forin for (const newResClassForOntology in newResourceClassesForOntology) { this.resourceClassesForOntology[newResClassForOntology] = newResourceClassesForOntology[newResClassForOntology]; } // get new resource class definitions const newResourceClasses = ontologyInfo.getResourceClasses(); // update resourceClasses // tslint:disable-next-line:forin for (const newResClass in newResourceClasses) { this.resourceClasses[newResClass] = newResourceClasses[newResClass]; } // get new property definitions const newProperties = ontologyInfo.getProperties(); // update properties // tslint:disable-next-line:forin for (const newProp in newProperties) { this.properties[newProp] = newProperties[newProp]; } } /** * Returns resource class definitions for ontologies. * * @returns ResourceClassIrisForOntology - all resource class definitions grouped by ontologies. */ getResourceClassForOntology() { return this.resourceClassesForOntology; } /** * Returns all resource classes as an object. * * @returns ResourceClasses - all resource class definitions as an object. */ getResourceClasses() { return this.resourceClasses; } /** * Returns all resource classes as an array. * * @param {boolean} sortAsc sort resource classes by label in ascending order by default * @returns ResourceClass[] */ getResourceClassesAsArray(sortAsc = true) { const resClasses = []; // tslint:disable-next-line:forin for (const resClassIri in this.resourceClasses) { const resClass = this.resourceClasses[resClassIri]; resClasses.push(resClass); } // resourceClasses order by label in ascending order resClasses.sort(OntologyInformation.sortFunc); // resourceClasses order by label in descending order if (!sortAsc) { resClasses.reverse(); } return resClasses; } /** * Returns a resource class's label. * * @param {string} resClass resource class to query for. * @returns string - the resource class's label. */ getLabelForResourceClass(resClass) { if (resClass !== undefined) { const resClassDef = this.resourceClasses[resClass]; if (resClassDef !== undefined && resClassDef.label !== undefined) { return resClassDef.label; } else { console.log(`cannot get label for ${resClass}`); } } else { console.log('call of OntologyInformation.getLabelForResourceClass without argument resClass'); } } /** * Returns all properties as an object. * * @returns Properties - all properties as an object. */ getProperties() { return this.properties; } /** * Returns all properties as an array. * * @param {boolean} sortAsc sort properties by label in ascending order by default * @returns Property[] - all properties as an array. */ getPropertiesAsArray(sortAsc = true) { const properties = []; // tslint:disable-next-line:forin for (const propIri in this.properties) { const prop = this.properties[propIri]; properties.push(prop); } // properties order by label in ascending order properties.sort(OntologyInformation.sortFunc); // properties order by label in descending order if (!sortAsc) { properties.reverse(); } return properties; } /** * Returns a property's label. * * @param {string} property to query for. * @returns string - the property's label. */ getLabelForProperty(property) { if (property !== undefined) { const propDef = this.properties[property]; if (propDef !== undefined && propDef.label !== undefined) { return propDef.label; } else { console.log(`cannot get label for ${property}`); } } else { console.log('call of OntologyInformation.getLabelForProperty without argument property'); } } } /** * Requests ontology information from Knora and caches it. * Other components or services obtain ontology information through this service. */ let OntologyCacheService = class OntologyCacheService { constructor(_ontologyService) { this._ontologyService = _ontologyService; /** * Ontologies ingored by this service. * @param {string[]} excludedOntologies */ this.excludedOntologies = [Constants.SalsahGui, Constants.StandoffOntology]; /** * @param {string[]} excludedProperties properties that Knora is not responsible for and that have to be ignored because they cannot be resolved at the moment. */ this.excludedProperties = [Constants.Label]; /** * @param {string[]} nonResourceClasses class definitions that are not be treated as Knora resource classes */ this.nonResourceClasses = [Constants.ForbiddenResource, Constants.XMLToStandoffMapping, Constants.ListNode]; /** * @param {OntologyCache} cacheOntology central instance that caches all definitions */ this.cacheOntology = new OntologyCache(); } /** * Requests the metadata of all ontologies from Knora. * * @returns Observable<object> - metadata for all ontologies as JSON-LD (no prefixes, all Iris fully expanded). */ getOntologiesMetadataFromKnora() { return this._ontologyService.getOntologiesMetadata().pipe(mergeMap( // this would return an Observable of a PromiseObservable -> combine them into one Observable // http://reactivex.io/documentation/operators/flatmap.html // http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#instance-method-mergeMap (ontRes) => { const ontPromises = jsonld.promises; // compact JSON-LD using an empty context: expands all Iris const ontPromise = ontPromises.compact(ontRes.body, {}); // convert promise to Observable and return it // https://www.learnrxjs.io/operators/creation/frompromise.html return from(ontPromise); })); } /** * Requests all entity definitions (resource classes and properties) for the given ontology from Knora. * * @param {string} ontologyIri the Iri of the requested ontology. * @returns Observable<object> - metadata for all entity definitions for ontology from Knora. */ getAllEntityDefinitionsForOntologyFromKnora(ontologyIri) { return this._ontologyService.getAllEntityDefinitionsForOntologies(ontologyIri).pipe(mergeMap( // this would return an Observable of a PromiseObservable -> combine them into one Observable // http://reactivex.io/documentation/operators/flatmap.html // http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#instance-method-mergeMap (ontRes) => { const ontPromises = jsonld.promises; // compact JSON-LD using an empty context: expands all Iris const ontPromise = ontPromises.compact(ontRes.body, {}); // convert promise to Observable and return it // https://www.learnrxjs.io/operators/creation/frompromise.html return from(ontPromise); })); } /** * Writes all the ontologies' metadata returned by Knora to the cache. * * @param {object[]} ontologies metadata of all existing ontologies as JSON-LD. * @returns a new OntologyMetadata object */ convertAndWriteOntologiesMetadataToCache(ontologies) { this.cacheOntology.ontologies = ontologies.map(ontology => { return new OntologyMetadata(ontology['@id'], ontology[Constants.Label]); }); } /** * Returns all ontologies' metadata from the cache and returns them. * * @returns Array<OntologyMetadata> - metadata of all existing ontologies. */ getAllOntologiesMetadataFromCache() { return this.cacheOntology.ontologies; } /** * Returns resource class Iris from the ontology response. * `knora-api:Resource` will be excluded. * * @param {Array<object>} classDefinitions the class definitions in an ontology response. * @returns string[] - resource class Iris from the given class definitions. */ getResourceClassIrisFromOntologyResponse(classDefinitions) { const resourceClassIris = []; for (const classDef of classDefinitions) { const classIri = classDef['@id']; // check that class name is not listed as a non resource class and that the isResourceClass flag is present and set to true if (classIri !== Constants.Resource && this.nonResourceClasses.indexOf(classIri) === -1 && (classDef[Constants.IsResourceClass] !== undefined && classDef[Constants.IsResourceClass] === true)) { // it is not a value class, but a resource class definition resourceClassIris.push(classIri); } } return resourceClassIris; } /** * Converts a Knora response for all entity definitions for the requested ontology * into an internal representation and caches it. * * Knora automatically includes the property definitions referred to in the cardinalities of resource classes. * If they are defined in another ontology, that ontology is requested from Knora too. * * @param {Object} ontology the ontology to be cached. * @returns void */ convertAndWriteAllEntityDefinitionsForOntologyToCache(ontology) { const graph = ontology['@graph']; // get all class definitions const classDefs = graph.filter((entity) => { const entityType = entity['@type']; return entityType === Constants.Class; }); // get all property definitions const propertyDefs = graph.filter((entity) => { const entityType = entity['@type']; return entityType === Constants.ObjectProperty || entityType === Constants.DataTypeProperty || entityType === Constants.Owl + Constants.Delimiter + 'AnnotationProperty' || entityType === Constants.RdfProperty; }); // cache all resource class Iris belonging to the current ontology this.cacheOntology.resourceClassIrisForOntology[ontology['@id']] = this.getResourceClassIrisFromOntologyResponse(classDefs); // write class and property defintions to cache this.convertAndWriteEntityDefinitionsToCache(classDefs, propertyDefs); } /** * Returns definitions for the requested ontologies from the cache. * * @param {string[]} ontologyIris the ontologies for which definitions should be returned. * @returns Observable<OntologyInformation> - the definitions for the requested ontologies. */ getOntologyInformationFromCache(ontologyIris) { const resourceClassesForOntology = new ResourceClassIrisForOntology(); // collect resource class Iris for all requested named graphs let allResourceClassIris = []; for (const ontologyIri of ontologyIris) { if (this.cacheOntology.resourceClassIrisForOntology[ontologyIri] === undefined) { throw new OntologyCacheError(`getResourceClassesForOntologiesFromCache: ontology not found in cache: ${ontologyIri}`); } // add information for the given ontology resourceClassesForOntology[ontologyIri] = this.cacheOntology.resourceClassIrisForOntology[ontologyIri]; // add all resource class Iris of this ontology allResourceClassIris = allResourceClassIris.concat(this.cacheOntology.resourceClassIrisForOntology[ontologyIri]); } // get resource class definitions for all requested ontologies return this.getResourceClassDefinitions(allResourceClassIris).pipe(map(resClassDefs => { return new OntologyInformation(resourceClassesForOntology, resClassDefs.getResourceClasses(), resClassDefs.getProperties()); })); } /** * Converts a Knora ontology response into an internal representation and caches it. * * @param {object[]} resourceClassDefinitions the resource class definitions returned by Knora. * @param {object[]} propertyClassDefinitions the property definitions returned by Knora. * @returns void */ convertAndWriteEntityDefinitionsToCache(resourceClassDefinitions, propertyClassDefinitions) { // convert and cache each given resource class definition for (const resClass of resourceClassDefinitions) { const resClassIri = resClass['@id']; // represents all cardinalities of this resource class const cardinalities = []; const guiOrder = []; if (resClass[Constants.SubClassOf] !== undefined) { let subclassOfCollection; // check if it is a single object or a collection if (!Array.isArray(resClass[Constants.SubClassOf])) { subclassOfCollection = [resClass[Constants.SubClassOf]]; } else { subclassOfCollection = resClass[Constants.SubClassOf]; } // get cardinalities for the properties of a resource class for (const curCard of subclassOfCollection) { // make sure it is a cardinality (it could also be an Iri of a superclass) if (curCard instanceof Object && curCard['@type'] !== undefined && curCard['@type'] === Constants.Restriction) { let newCard; // get occurrence if (curCard[Constants.MinCardinality] !== undefined) { newCard = new Cardinality(CardinalityOccurrence.minCard, curCard[Constants.MinCardinality], curCard[Constants.OnProperty]['@id']); } else if (curCard[Constants.Cardinality] !== undefined) { newCard = new Cardinality(CardinalityOccurrence.card, curCard[Constants.Cardinality], curCard[Constants.OnProperty]['@id']); } else if (curCard[Constants.MaxCardinality] !== undefined) { newCard = new Cardinality(CardinalityOccurrence.maxCard, curCard[Constants.MaxCardinality], curCard[Constants.OnProperty]['@id']); } else { // no known occurrence found throw new TypeError(`cardinality type invalid for ${resClass['@id']} ${curCard[Constants.OnProperty]}`); } // add cardinality cardinalities.push(newCard); // get gui order let newGuiOrder; if (curCard[Constants.GuiOrder] !== undefined) { newGuiOrder = new GuiOrder(curCard[Constants.GuiOrder], curCard[Constants.OnProperty]['@id']); // add gui order guiOrder.push(newGuiOrder); } } } } const resClassObj = new ResourceClass(resClassIri, resClass[Constants.ResourceIcon], resClass[Constants.Comment], resClass[Constants.Label], cardinalities, guiOrder); // write this resource class definition to the cache object this.cacheOntology.resourceClasses[resClassIri] = resClassObj; } // cache the property definitions this.convertAndWriteKnoraPropertyDefinitionsToOntologyCache(propertyClassDefinitions); } /** * Gets information about resource classes from the cache. * The answer includes the property definitions referred to by the cardinalities of the given resource classes. * * @param {string[]} resClassIris the given resource class Iris * @returns Observable<OntologyInformation> - an [[OntologyCache]] representing the requested resource classes. */ getResourceClassDefinitionsFromCache(resClassIris) { // collect the definitions for each resource class from the cache const resClassDefs = new ResourceClasses(); // collect the properties from the cardinalities of the given resource classes const propertyIris = []; resClassIris.forEach(resClassIri => { resClassDefs[resClassIri] = this.cacheOntology.resourceClasses[resClassIri]; this.cacheOntology.resourceClasses[resClassIri].cardinalities.forEach(card => { // get property definition for each cardinality propertyIris.push(card.property); }); }); return this.getPropertyDefinitions(propertyIris).pipe(map(propDefs => { return new OntologyInformation(new ResourceClassIrisForOntology(), resClassDefs, propDefs.getProperties()); })); } /** * Converts a Knora response for ontology information about properties * into an internal representation and cache it. * * @param {object[]} propertyDefinitionsFromKnora the property definitions returned by Knora * @returns void */ convertAndWriteKnoraPropertyDefinitionsToOntologyCache(propertyDefinitionsFromKnora) { // convert and cache each given property definition for (const propDef of propertyDefinitionsFromKnora) { const propIri = propDef['@id']; let isEditable = false; if (propDef[Constants.IsEditable] !== undefined && propDef[Constants.IsEditable] === true) { isEditable = true; } let isLinkProperty = false; if (propDef[Constants.IsLinkProperty] !== undefined && propDef[Constants.IsLinkProperty] === true) { isLinkProperty = true; } let isLinkValueProperty = false; if (propDef[Constants.IsLinkValueProperty] !== undefined && propDef[Constants.IsLinkValueProperty] === true) { isLinkValueProperty = true; } let subPropertyOf = []; if (propDef[Constants.SubPropertyOf] !== undefined && Array.isArray(propDef[Constants.SubPropertyOf])) { subPropertyOf = propDef[Constants.SubPropertyOf].map((superProp) => superProp['@id']); } else if (propDef[Constants.SubPropertyOf] !== undefined) { subPropertyOf.push(propDef[Constants.SubPropertyOf]['@id']); } let objectType; if (propDef[Constants.ObjectType] !== undefined) { objectType = propDef[Constants.ObjectType]['@id']; } const guiAttribute = []; if (propDef[Constants.GuiAttribute] !== undefined) { if (Array.isArray(propDef[Constants.GuiAttribute])) { for (const attr of propDef[Constants.GuiAttribute]) { guiAttribute.push(attr); } } else { guiAttribute.push(propDef[Constants.GuiAttribute]); } } // cache property definition this.cacheOntology.properties[propIri] = new Property(propIri, objectType, propDef[Constants.Comment], propDef[Constants.Label], subPropertyOf, isEditable, isLinkProperty, isLinkValueProperty, guiAttribute); } } /** * Returns property definitions from the cache. * * @param {string[]} propertyIris the property definitions to be returned. * @returns OntologyInformation - requested property defintions. */ getPropertyDefinitionsFromCache(propertyIris) { const propertyDefs = new Properties(); propertyIris.forEach(propIri => { // ignore non Knora props: if propIri is contained in excludedProperties, skip this propIri if (this.excludedProperties.indexOf(propIri) > -1) { return; } if (this.cacheOntology.properties[propIri] === undefined) { throw new OntologyCacheError(`getPropertyDefinitionsFromCache: property not found in cache: ${propIri}`); } propertyDefs[propIri] = this.cacheOntology.properties[propIri]; }); return new OntologyInformation(new ResourceClassIrisForOntology(), new ResourceClasses(), propertyDefs); } /** * Returns metadata about all ontologies. * * @returns Observable<Array<OntologyMetadata>> - metadata about all ontologies. */ getOntologiesMetadata() { if (this.cacheOntology.ontologies.length === 0) { // nothing in cache yet, get metadata from Knora return this.getOntologiesMetadataFromKnora().pipe(map(metadata => { this.convertAndWriteOntologiesMetadataToCache(metadata['@graph'].filter((onto) => { // ignore excluded ontologies return this.excludedOntologies.indexOf(onto['@id']) === -1; })); return this.getAllOntologiesMetadataFromCache(); })); } else { // return metadata from cache return of(this.getAllOntologiesMetadataFromCache()); } } /** * Requests the requested ontologies from Knora, adding them to the cache. * * @param {string[]} ontologyIris Iris of the ontologies to be requested. * @returns Observable<any[]> */ getAndCacheOntologies(ontologyIris) { // array to be populated with Observables const observables = []; // do a request for each ontology ontologyIris.forEach(ontologyIri => { // push an Observable onto `observables` observables.push(this.getAllEntityDefinitionsForOntologyFromKnora(ontologyIri).pipe(map((ontology) => { // write response to cache this.convertAndWriteAllEntityDefinitionsForOntologyToCache(ontology); }))); }); // forkJoin returns an Observable of an array of results // returned by each Observable contained in `observables` // a subscription to the Observable returned by forkJoin is executed // once all Observables have been completed return forkJoin(observables); } /** * Returns the entity definitions for the requested ontologies. * * @param {string[]} ontologyIris Iris of the ontologies to be queried. * @returns Observable<OntologyInformation> - all ontology metadata from the cache */ getEntityDefinitionsForOntologies(ontologyIris) { const ontologyIrisToQuery = ontologyIris.filter(ontologyIri => { // return the ontology Iris that are not cached yet return this.cacheOntology.resourceClassIrisForOntology[ontologyIri] === undefined; }); // get ontologies that are mot cached yet if (ontologyIrisToQuery.length > 0) { return this.getAndCacheOntologies(ontologyIrisToQuery).pipe(mergeMap(() => { // executed once all ontologies have been cached return this.getOntologyInformationFromCache(ontologyIris); })); } else { return this.getOntologyInformationFromCache(ontologyIris); } } /** * Returns the definitions for the given resource class Iris. * If the definitions are not already in the cache, the will be retrieved from Knora and cached. * * Properties contained in the cardinalities will be returned too. * * @param {string[]} resourceClassIris the given resource class Iris * @returns Observable<OntologyInformation> - the requested resource classes (including properties). */ getResourceClassDefinitions(resourceClassIris) { const resClassIrisToQueryFor = resourceClassIris.filter(resClassIri => { // return the resource class Iris that are not cached yet return this.cacheOntology.resourceClasses[resClassIri] === undefined; }); if (resClassIrisToQueryFor.length > 0) { // get a set of ontology Iris that have to be queried to obtain the missing resource classes const ontologyIris = resClassIrisToQueryFor.map(resClassIri => { return Utils.getOntologyIriFromEntityIri(resClassIri); }).filter(Utils.filterOutDuplicates); // obtain missing resource class information return this.getAndCacheOntologies(ontologyIris).pipe(mergeMap(() => { return this.getResourceClassDefinitionsFromCache(resourceClassIris); })); } else { return this.getResourceClassDefinitionsFromCache(resourceClassIris); } } /** * Get definitions for the given property Iris. * If the definitions are not already in the cache, the will be retrieved from Knora and cached. * * @param {string[]} propertyIris the Iris of the properties to be returned . * @returns Observable<OntologyInformation> - the requested property definitions. */ getPropertyDefinitions(propertyIris) { const propertiesToQuery = propertyIris.filter(propIri => { // ignore non Knora props: if propIri is contained in excludedProperties, skip this propIri if (this.excludedProperties.indexOf(propIri) > -1) { return false; } // return the property Iris that are not cached yet return this.cacheOntology.properties[propIri] === undefined; }); if (propertiesToQuery.length > 0) { // get a set of ontology Iris that have to be queried to obtain the missing properties const ontologyIris = propertiesToQuery.map(propIri => { return Utils.getOntologyIriFromEntityIri(propIri); }).filter(Utils.filterOutDuplicates); // obtain missing resource class information return this.getAndCacheOntologies(ontologyIris).pipe(map(results => { if (results) { return this.getPropertyDefinitionsFromCache(propertyIris); } else { throw new Error('Problem with: return this.getPropertyDefinitionsFromCache(propertyIris);'); } })); } else { return of(this.getPropertyDefinitionsFromCache(propertyIris)); } } }; OntologyCacheService.ctorParameters = () => [ { type: OntologyService } ]; OntologyCacheService.ngInjectableDef = i0.ɵɵdefineInjectable({ factory: function OntologyCacheService_Factory() { return new OntologyCacheService(i0.ɵɵinject(i1.OntologyService)); }, token: OntologyCacheService, providedIn: "root" }); OntologyCacheService = tslib_1.__decorate([ Injectable({ providedIn: 'root' }), tslib_1.__metadata("design:paramtypes", [OntologyService]) ], OntologyCacheService); export { OntologyCacheService }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib250b2xvZ3ktY2FjaGUuc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiJuZzovL0Brbm9yYS9jb3JlLyIsInNvdXJjZXMiOlsibGliL3NlcnZpY2VzL3YyL29udG9sb2d5LWNhY2hlLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDM0MsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLFlBQVksQ0FBQztBQUN2QyxPQUFPLEVBQUUsUUFBUSxFQUFFLElBQUksRUFBYyxFQUFFLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDdEQsT0FBTyxFQUFFLEdBQUcsRUFBRSxRQUFRLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUcvQyxPQUFPLEVBQUUsS0FBSyxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFFakQsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLG9CQUFvQixDQUFDOzs7QUFHckQsTUFBTSxNQUFNLEdBQUcsT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFDO0FBRWpDOzs7Ozs7R0FNRztBQUNILE1BQU0sa0JBQW1CLFNBQVEsS0FBSztJQUVsQyxZQUFxQixPQUFlO1FBQ2hDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQztRQURFLFlBQU8sR0FBUCxPQUFPLENBQVE7SUFFcEMsQ0FBQztDQUNKO0FBR0Q7OztHQUdHO0FBQ0gsTUFBTSxPQUFPLGdCQUFnQjtJQUV6Qjs7Ozs7T0FLRztJQUNILFlBQXFCLEVBQVUsRUFDbEIsS0FBYTtRQURMLE9BQUUsR0FBRixFQUFFLENBQVE7UUFDbEIsVUFBSyxHQUFMLEtBQUssQ0FBUTtJQUUxQixDQUFDO0NBRUo7QUFHRDs7R0FFRztBQUNILE1BQU0sQ0FBTixJQUFZLHFCQUlYO0FBSkQsV0FBWSxxQkFBcUI7SUFDN0IsdUVBQVcsQ0FBQTtJQUNYLGlFQUFRLENBQUE7SUFDUix1RUFBVyxDQUFBO0FBQ2YsQ0FBQyxFQUpXLHFCQUFxQixLQUFyQixxQkFB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