UNPKG

@knora/core

Version:
892 lines 117 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"; var 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. */ var OntologyCacheError = /** @class */ (function (_super) { tslib_1.__extends(OntologyCacheError, _super); function OntologyCacheError(message) { var _this = _super.call(this, message) || this; _this.message = message; return _this; } return OntologyCacheError; }(Error)); /** * * Represents an ontology's metadata. */ var OntologyMetadata = /** @class */ (function () { /** * @hideconstructor * * @param {string} id Iri identifying the ontology. * @param {string} label a label describing the ontology. */ function OntologyMetadata(id, label) { this.id = id; this.label = label; } return OntologyMetadata; }()); export { OntologyMetadata }; /** * 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. */ var Cardinality = /** @class */ (function () { /** * @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. */ function Cardinality(occurrence, value, property) { this.occurrence = occurrence; this.value = value; this.property = property; } return Cardinality; }()); export { Cardinality }; /** * Property gui order */ var GuiOrder = /** @class */ (function () { /** * @param {number} value * @param {string} property */ function GuiOrder(value, property) { this.value = value; this.property = property; } return GuiOrder; }()); export { GuiOrder }; /** * A resource class definition. */ var ResourceClass = /** @class */ (function () { /** * @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. */ function ResourceClass(id, icon, comment, label, cardinalities, guiOrder) { this.id = id; this.icon = icon; this.comment = comment; this.label = label; this.cardinalities = cardinalities; this.guiOrder = guiOrder; } return ResourceClass; }()); export { ResourceClass }; /** * A map of resource class Iris to resource class definitions. */ var ResourceClasses = /** @class */ (function () { function ResourceClasses() { } return ResourceClasses; }()); export { ResourceClasses }; /** * A property definition. */ var Property = /** @class */ (function () { /** * @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. */ function Property(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; } return Property; }()); export { Property }; /** * A map of property Iris to property definitions. */ var Properties = /** @class */ (function () { function Properties() { } return Properties; }()); export { Properties }; /** * Groups resource classes by the ontology they are defined in. * * A map of ontology Iris to an array of resource class Iris. */ var ResourceClassIrisForOntology = /** @class */ (function () { function ResourceClassIrisForOntology() { } return ResourceClassIrisForOntology; }()); export { 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]]. */ var OntologyCache = /** @class */ (function () { function OntologyCache() { this.ontologies = []; this.resourceClassIrisForOntology = new ResourceClassIrisForOntology(); this.resourceClasses = new ResourceClasses(); this.properties = new Properties(); } return OntologyCache; }()); /** * Represents ontology information requested from this service. * * For every request, an instance of this class is returned containing the requested information. */ var OntologyInformation = /** @class */ (function () { /** * @param {ResourceClassIrisForOntology} resourceClassesForOntology all resource class Iris for a given ontology. * @param {ResourceClasses} resourceClasses resource class definitions. * @param {Properties} properties property definitions. */ function OntologyInformation(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 */ OntologyInformation.sortFunc = function (a, b) { // dealing with 'undefined' labels if (a.label === undefined) { return 1; } else if (b.label === undefined) { return -1; } var labelA = a.label.toLowerCase(); var 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 */ OntologyInformation.prototype.updateOntologyInformation = function (ontologyInfo) { // get new resourceClassIrisForOntology var newResourceClassesForOntology = ontologyInfo.getResourceClassForOntology(); // update new resourceClassIrisForOntology // tslint:disable-next-line:forin for (var newResClassForOntology in newResourceClassesForOntology) { this.resourceClassesForOntology[newResClassForOntology] = newResourceClassesForOntology[newResClassForOntology]; } // get new resource class definitions var newResourceClasses = ontologyInfo.getResourceClasses(); // update resourceClasses // tslint:disable-next-line:forin for (var newResClass in newResourceClasses) { this.resourceClasses[newResClass] = newResourceClasses[newResClass]; } // get new property definitions var newProperties = ontologyInfo.getProperties(); // update properties // tslint:disable-next-line:forin for (var newProp in newProperties) { this.properties[newProp] = newProperties[newProp]; } }; /** * Returns resource class definitions for ontologies. * * @returns ResourceClassIrisForOntology - all resource class definitions grouped by ontologies. */ OntologyInformation.prototype.getResourceClassForOntology = function () { return this.resourceClassesForOntology; }; /** * Returns all resource classes as an object. * * @returns ResourceClasses - all resource class definitions as an object. */ OntologyInformation.prototype.getResourceClasses = function () { 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[] */ OntologyInformation.prototype.getResourceClassesAsArray = function (sortAsc) { if (sortAsc === void 0) { sortAsc = true; } var resClasses = []; // tslint:disable-next-line:forin for (var resClassIri in this.resourceClasses) { var 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. */ OntologyInformation.prototype.getLabelForResourceClass = function (resClass) { if (resClass !== undefined) { var 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. */ OntologyInformation.prototype.getProperties = function () { 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. */ OntologyInformation.prototype.getPropertiesAsArray = function (sortAsc) { if (sortAsc === void 0) { sortAsc = true; } var properties = []; // tslint:disable-next-line:forin for (var propIri in this.properties) { var 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. */ OntologyInformation.prototype.getLabelForProperty = function (property) { if (property !== undefined) { var 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'); } }; return OntologyInformation; }()); export { OntologyInformation }; /** * Requests ontology information from Knora and caches it. * Other components or services obtain ontology information through this service. */ var OntologyCacheService = /** @class */ (function () { function OntologyCacheService(_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). */ OntologyCacheService.prototype.getOntologiesMetadataFromKnora = function () { 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 function (ontRes) { var ontPromises = jsonld.promises; // compact JSON-LD using an empty context: expands all Iris var 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. */ OntologyCacheService.prototype.getAllEntityDefinitionsForOntologyFromKnora = function (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 function (ontRes) { var ontPromises = jsonld.promises; // compact JSON-LD using an empty context: expands all Iris var 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 */ OntologyCacheService.prototype.convertAndWriteOntologiesMetadataToCache = function (ontologies) { this.cacheOntology.ontologies = ontologies.map(function (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. */ OntologyCacheService.prototype.getAllOntologiesMetadataFromCache = function () { 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. */ OntologyCacheService.prototype.getResourceClassIrisFromOntologyResponse = function (classDefinitions) { var e_1, _a; var resourceClassIris = []; try { for (var classDefinitions_1 = tslib_1.__values(classDefinitions), classDefinitions_1_1 = classDefinitions_1.next(); !classDefinitions_1_1.done; classDefinitions_1_1 = classDefinitions_1.next()) { var classDef = classDefinitions_1_1.value; var 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); } } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (classDefinitions_1_1 && !classDefinitions_1_1.done && (_a = classDefinitions_1.return)) _a.call(classDefinitions_1); } finally { if (e_1) throw e_1.error; } } 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 */ OntologyCacheService.prototype.convertAndWriteAllEntityDefinitionsForOntologyToCache = function (ontology) { var graph = ontology['@graph']; // get all class definitions var classDefs = graph.filter(function (entity) { var entityType = entity['@type']; return entityType === Constants.Class; }); // get all property definitions var propertyDefs = graph.filter(function (entity) { var 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. */ OntologyCacheService.prototype.getOntologyInformationFromCache = function (ontologyIris) { var e_2, _a; var resourceClassesForOntology = new ResourceClassIrisForOntology(); // collect resource class Iris for all requested named graphs var allResourceClassIris = []; try { for (var ontologyIris_1 = tslib_1.__values(ontologyIris), ontologyIris_1_1 = ontologyIris_1.next(); !ontologyIris_1_1.done; ontologyIris_1_1 = ontologyIris_1.next()) { var ontologyIri = ontologyIris_1_1.value; 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]); } } catch (e_2_1) { e_2 = { error: e_2_1 }; } finally { try { if (ontologyIris_1_1 && !ontologyIris_1_1.done && (_a = ontologyIris_1.return)) _a.call(ontologyIris_1); } finally { if (e_2) throw e_2.error; } } // get resource class definitions for all requested ontologies return this.getResourceClassDefinitions(allResourceClassIris).pipe(map(function (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 */ OntologyCacheService.prototype.convertAndWriteEntityDefinitionsToCache = function (resourceClassDefinitions, propertyClassDefinitions) { var e_3, _a, e_4, _b; try { // convert and cache each given resource class definition for (var resourceClassDefinitions_1 = tslib_1.__values(resourceClassDefinitions), resourceClassDefinitions_1_1 = resourceClassDefinitions_1.next(); !resourceClassDefinitions_1_1.done; resourceClassDefinitions_1_1 = resourceClassDefinitions_1.next()) { var resClass = resourceClassDefinitions_1_1.value; var resClassIri = resClass['@id']; // represents all cardinalities of this resource class var cardinalities = []; var guiOrder = []; if (resClass[Constants.SubClassOf] !== undefined) { var subclassOfCollection = void 0; // 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]; } try { // get cardinalities for the properties of a resource class for (var subclassOfCollection_1 = tslib_1.__values(subclassOfCollection), subclassOfCollection_1_1 = subclassOfCollection_1.next(); !subclassOfCollection_1_1.done; subclassOfCollection_1_1 = subclassOfCollection_1.next()) { var curCard = subclassOfCollection_1_1.value; // 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) { var newCard = void 0; // 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 var newGuiOrder = void 0; if (curCard[Constants.GuiOrder] !== undefined) { newGuiOrder = new GuiOrder(curCard[Constants.GuiOrder], curCard[Constants.OnProperty]['@id']); // add gui order guiOrder.push(newGuiOrder); } } } } catch (e_4_1) { e_4 = { error: e_4_1 }; } finally { try { if (subclassOfCollection_1_1 && !subclassOfCollection_1_1.done && (_b = subclassOfCollection_1.return)) _b.call(subclassOfCollection_1); } finally { if (e_4) throw e_4.error; } } } var 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; } } catch (e_3_1) { e_3 = { error: e_3_1 }; } finally { try { if (resourceClassDefinitions_1_1 && !resourceClassDefinitions_1_1.done && (_a = resourceClassDefinitions_1.return)) _a.call(resourceClassDefinitions_1); } finally { if (e_3) throw e_3.error; } } // 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. */ OntologyCacheService.prototype.getResourceClassDefinitionsFromCache = function (resClassIris) { // collect the definitions for each resource class from the cache var _this = this; var resClassDefs = new ResourceClasses(); // collect the properties from the cardinalities of the given resource classes var propertyIris = []; resClassIris.forEach(function (resClassIri) { resClassDefs[resClassIri] = _this.cacheOntology.resourceClasses[resClassIri]; _this.cacheOntology.resourceClasses[resClassIri].cardinalities.forEach(function (card) { // get property definition for each cardinality propertyIris.push(card.property); }); }); return this.getPropertyDefinitions(propertyIris).pipe(map(function (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 */ OntologyCacheService.prototype.convertAndWriteKnoraPropertyDefinitionsToOntologyCache = function (propertyDefinitionsFromKnora) { var e_5, _a, e_6, _b; try { // convert and cache each given property definition for (var propertyDefinitionsFromKnora_1 = tslib_1.__values(propertyDefinitionsFromKnora), propertyDefinitionsFromKnora_1_1 = propertyDefinitionsFromKnora_1.next(); !propertyDefinitionsFromKnora_1_1.done; propertyDefinitionsFromKnora_1_1 = propertyDefinitionsFromKnora_1.next()) { var propDef = propertyDefinitionsFromKnora_1_1.value; var propIri = propDef['@id']; var isEditable = false; if (propDef[Constants.IsEditable] !== undefined && propDef[Constants.IsEditable] === true) { isEditable = true; } var isLinkProperty = false; if (propDef[Constants.IsLinkProperty] !== undefined && propDef[Constants.IsLinkProperty] === true) { isLinkProperty = true; } var isLinkValueProperty = false; if (propDef[Constants.IsLinkValueProperty] !== undefined && propDef[Constants.IsLinkValueProperty] === true) { isLinkValueProperty = true; } var subPropertyOf = []; if (propDef[Constants.SubPropertyOf] !== undefined && Array.isArray(propDef[Constants.SubPropertyOf])) { subPropertyOf = propDef[Constants.SubPropertyOf].map(function (superProp) { return superProp['@id']; }); } else if (propDef[Constants.SubPropertyOf] !== undefined) { subPropertyOf.push(propDef[Constants.SubPropertyOf]['@id']); } var objectType = void 0; if (propDef[Constants.ObjectType] !== undefined) { objectType = propDef[Constants.ObjectType]['@id']; } var guiAttribute = []; if (propDef[Constants.GuiAttribute] !== undefined) { if (Array.isArray(propDef[Constants.GuiAttribute])) { try { for (var _c = tslib_1.__values(propDef[Constants.GuiAttribute]), _d = _c.next(); !_d.done; _d = _c.next()) { var attr = _d.value; guiAttribute.push(attr); } } catch (e_6_1) { e_6 = { error: e_6_1 }; } finally { try { if (_d && !_d.done && (_b = _c.return)) _b.call(_c); } finally { if (e_6) throw e_6.error; } } } 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); } } catch (e_5_1) { e_5 = { error: e_5_1 }; } finally { try { if (propertyDefinitionsFromKnora_1_1 && !propertyDefinitionsFromKnora_1_1.done && (_a = propertyDefinitionsFromKnora_1.return)) _a.call(propertyDefinitionsFromKnora_1); } finally { if (e_5) throw e_5.error; } } }; /** * Returns property definitions from the cache. * * @param {string[]} propertyIris the property definitions to be returned. * @returns OntologyInformation - requested property defintions. */ OntologyCacheService.prototype.getPropertyDefinitionsFromCache = function (propertyIris) { var _this = this; var propertyDefs = new Properties(); propertyIris.forEach(function (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. */ OntologyCacheService.prototype.getOntologiesMetadata = function () { var _this = this; if (this.cacheOntology.ontologies.length === 0) { // nothing in cache yet, get metadata from Knora return this.getOntologiesMetadataFromKnora().pipe(map(function (metadata) { _this.convertAndWriteOntologiesMetadataToCache(metadata['@graph'].filter(function (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[]> */ OntologyCacheService.prototype.getAndCacheOntologies = function (ontologyIris) { var _this = this; // array to be populated with Observables var observables = []; // do a request for each ontology ontologyIris.forEach(function (ontologyIri) { // push an Observable onto `observables` observables.push(_this.getAllEntityDefinitionsForOntologyFromKnora(ontologyIri).pipe(map(function (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 */ OntologyCacheService.prototype.getEntityDefinitionsForOntologies = function (ontologyIris) { var _this = this; var ontologyIrisToQuery = ontologyIris.filter(function (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(function () { // 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). */ OntologyCacheService.prototype.getResourceClassDefinitions = function (resourceClassIris) { var _this = this; var resClassIrisToQueryFor = resourceClassIris.filter(function (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 var ontologyIris = resClassIrisToQueryFor.map(function (resClassIri) { return Utils.getOntologyIriFromEntityIri(resClassIri); }).filter(Utils.filterOutDuplicates); // obtain missing resource class information return this.getAndCacheOntologies(ontologyIris).pipe(mergeMap(function () { 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. */ OntologyCacheService.prototype.getPropertyDefinitions = function (propertyIris) { var _this = this; var propertiesToQuery = propertyIris.filter(function (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 var ontologyIris = propertiesToQuery.map(function (propIri) { return Utils.getOntologyIriFromEntityIri(propIri); }).filter(Utils.filterOutDuplicates); // obtain missing resource class information return this.getAndCacheOntologies(ontologyIris).pipe(map(function (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 = function () { return [ { 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); return OntologyCacheService; }()); export { OntologyCacheService }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib250b2xvZ3ktY2FjaGUuc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiJuZzovL0Brbm9yYS9jb3JlLyIsInNvdXJjZXMiOlsibGliL3NlcnZpY2VzL3YyL29udG9sb2d5LWNhY2hlLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDM0MsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLFlBQVksQ0FBQztBQUN2QyxPQUFPLEVBQUUsUUFBUSxFQUFFLElBQUksRUFBYyxFQUFFLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDdEQsT0FBTyxFQUFFLEdBQUcsRUFBRSxRQUFRLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUcvQyxPQUFPLEVBQUUsS0FBSyxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFFakQsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLG9CQUFvQixDQUFDOzs7QUFHckQsSUFBTSxNQUFNLEdBQUcsT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFDO0FBRWpDOzs7Ozs7R0FNRztBQUNIO0lBQWlDLDhDQUFLO0lBRWxDLDRCQUFxQixPQUFlO1FBQXBDLFlBQ0ksa0JBQU0sT0FBTyxDQUFDLFNBQ2pCO1FBRm9CLGFBQU8sR0FBUCxPQUFPLENBQVE7O0lBRXBDLENBQUM7SUFDTCx5QkFBQztBQUFELENBQUMsQUFMRCxDQUFpQyxLQUFLLEdBS3JDO0FBR0Q7OztHQUdHO0FBQ0g7SUFFSTs7Ozs7T0FLRztJQUNILDBCQUFxQixFQUFVLEVBQ2xCLEtBQWE7UUFETCxPQUFFLEdBQUYsRUFBRSxDQUFRO1FBQ2xCLFVBQUssR0FBTCxLQUFLLENBQVE7SUFFMUIsQ0FBQztJQUVMLHVCQUFDO0FBQUQsQ0FBQyxBQWJELElBYUM7O0FBR0Q7O0dBRUc7QUFDSCxNQUFNLENBQU4sSUFBWSxxQkFJWDtBQUpELFdBQVkscUJBQXFCO0lBQzdCLHVFQUFXLENBQUE7SUFDWCxpRUFBUSxDQUFBO0lBQ1Is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