@knora/core
Version:
Knora ui module: core
790 lines • 109 kB
JavaScript
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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