UNPKG

@itwin/ecschema-metadata

Version:

ECObjects core concepts in typescript

664 lines • 27.3 kB
"use strict"; /*--------------------------------------------------------------------------------------------- * Copyright (c) Bentley Systems, Incorporated. All rights reserved. * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ /** @packageDocumentation * @module Metadata */ Object.defineProperty(exports, "__esModule", { value: true }); exports.MutableProperty = exports.StructArrayProperty = exports.EnumerationArrayProperty = exports.PrimitiveArrayProperty = exports.ArrayProperty = exports.NavigationProperty = exports.StructProperty = exports.EnumerationProperty = exports.PrimitiveProperty = exports.PrimitiveOrEnumPropertyBase = exports.Property = void 0; const DelayedPromise_1 = require("../DelayedPromise"); const XmlSerializationUtils_1 = require("../Deserialization/XmlSerializationUtils"); const ECObjects_1 = require("../ECObjects"); const Exception_1 = require("../Exception"); const PropertyTypes_1 = require("../PropertyTypes"); const ECName_1 = require("../ECName"); const CustomAttribute_1 = require("./CustomAttribute"); const Enumeration_1 = require("./Enumeration"); const KindOfQuantity_1 = require("./KindOfQuantity"); const PropertyCategory_1 = require("./PropertyCategory"); /** * A common abstract class for all ECProperty types. * @public @preview */ class Property { _name; _class; // TODO: class seems to be unused? _description; _label; _isReadOnly; _priority; _category; _kindOfQuantity; _customAttributes; /** @internal */ _type; /** @internal */ constructor(ecClass, name, type) { this._class = ecClass; this._name = new ECName_1.ECName(name); this._type = type; } isArray() { return PropertyTypes_1.PropertyTypeUtils.isArray(this._type); } isPrimitive() { return PropertyTypes_1.PropertyTypeUtils.isPrimitive(this._type); } isStruct() { return PropertyTypes_1.PropertyTypeUtils.isStruct(this._type); } isEnumeration() { return PropertyTypes_1.PropertyTypeUtils.isEnumeration(this._type); } isNavigation() { return PropertyTypes_1.PropertyTypeUtils.isNavigation(this._type); } get name() { return this._name.name; } get class() { return this._class; } get label() { return this._label; } get description() { return this._description; } get isReadOnly() { return this._isReadOnly || false; } get priority() { if (this._priority === undefined) { const baseProperty = this.class.getInheritedPropertySync(this.name); if (undefined !== baseProperty) { return baseProperty.priority; } } return this._priority || 0; } get category() { if (this._category === undefined) { const baseProperty = this.class.getInheritedPropertySync(this.name); if (undefined !== baseProperty) { return baseProperty.category; } } return this._category; } get kindOfQuantity() { if (this._kindOfQuantity === undefined) { const baseProperty = this.class.getInheritedPropertySync(this.name); if (undefined !== baseProperty) { return baseProperty.kindOfQuantity; } } return this._kindOfQuantity; } get propertyType() { return this._type; } get customAttributes() { return this._customAttributes; } /** Returns the name in the format 'ClassName.PropertyName'. */ get fullName() { return `${this._class.name}.${this.name}`; } /** Returns the schema of the class holding the property. */ get schema() { return this._class.schema; } getCategorySync() { if (!this._category) { const baseProperty = this.class.getInheritedPropertySync(this.name); if (undefined !== baseProperty) { return baseProperty.getCategorySync(); } return undefined; } return this.class.schema.lookupItemSync(this._category, PropertyCategory_1.PropertyCategory); } getKindOfQuantitySync() { if (!this._kindOfQuantity) { const baseProperty = this.class.getInheritedPropertySync(this.name); if (undefined !== baseProperty) { return baseProperty.getKindOfQuantitySync(); } return undefined; } return this.class.schema.lookupItemSync(this._kindOfQuantity, KindOfQuantity_1.KindOfQuantity); } /** * Save this Property's properties to an object for serializing to JSON. */ toJSON() { const schemaJson = {}; schemaJson.name = this.name; schemaJson.type = (0, PropertyTypes_1.propertyTypeToString)(this._type); if (this.description !== undefined) schemaJson.description = this.description; if (this.label !== undefined) schemaJson.label = this.label; if (this._isReadOnly !== undefined) schemaJson.isReadOnly = this._isReadOnly; if (this._category !== undefined) schemaJson.category = this._category.fullName; // needs to be fully qualified name if (this._priority !== undefined) schemaJson.priority = this._priority; if (this._kindOfQuantity !== undefined) schemaJson.kindOfQuantity = this._kindOfQuantity.fullName; const customAttributes = (0, CustomAttribute_1.serializeCustomAttributes)(this.customAttributes); if (customAttributes !== undefined) schemaJson.customAttributes = customAttributes; return schemaJson; } /** @internal */ async toXml(schemaXml) { const propType = `EC${(0, PropertyTypes_1.propertyTypeToString)(this._type)}`.replace("Primitive", ""); const itemElement = schemaXml.createElement(propType); itemElement.setAttribute("propertyName", this.name); if (undefined !== this.description) itemElement.setAttribute("description", this.description); if (undefined !== this.label) itemElement.setAttribute("displayLabel", this.label); if (undefined !== this.isReadOnly) itemElement.setAttribute("readOnly", String(this.isReadOnly)); if (undefined !== this._category) { const category = await this._category; const categoryName = XmlSerializationUtils_1.XmlSerializationUtils.createXmlTypedName(this.schema, category.schema, category.name); itemElement.setAttribute("category", categoryName); } if (undefined !== this._priority) itemElement.setAttribute("priority", this._priority.toString()); if (undefined !== this._kindOfQuantity) { const kindOfQuantity = await this._kindOfQuantity; const kindOfQuantityName = XmlSerializationUtils_1.XmlSerializationUtils.createXmlTypedName(this.schema, kindOfQuantity.schema, kindOfQuantity.name); itemElement.setAttribute("kindOfQuantity", kindOfQuantityName); } if (this._customAttributes) { const caContainerElement = schemaXml.createElement("ECCustomAttributes"); for (const [name, attribute] of this._customAttributes) { const caElement = await XmlSerializationUtils_1.XmlSerializationUtils.writeCustomAttribute(name, attribute, schemaXml, this.schema); caContainerElement.appendChild(caElement); } itemElement.appendChild(caContainerElement); } return itemElement; } fromJSONSync(propertyProps) { if (undefined !== propertyProps.label) { this._label = propertyProps.label; } if (undefined !== propertyProps.description) { this._description = propertyProps.description; } if (undefined !== propertyProps.priority) { this._priority = propertyProps.priority; } if (undefined !== propertyProps.isReadOnly) { this._isReadOnly = propertyProps.isReadOnly; } if (undefined !== propertyProps.category) { const propertyCategorySchemaItemKey = this.class.schema.getSchemaItemKey(propertyProps.category); if (!propertyCategorySchemaItemKey) throw new Exception_1.ECSchemaError(Exception_1.ECSchemaStatus.InvalidECJson, `The Property ${this.name} has a 'category' ("${propertyProps.category}") that cannot be found.`); this._category = new DelayedPromise_1.DelayedPromiseWithProps(propertyCategorySchemaItemKey, async () => { const category = await this.class.schema.lookupItem(propertyCategorySchemaItemKey, PropertyCategory_1.PropertyCategory); if (undefined === category) throw new Exception_1.ECSchemaError(Exception_1.ECSchemaStatus.InvalidECJson, `The Property ${this.name} has a 'category' ("${propertyProps.category}") that cannot be found.`); return category; }); } if (undefined !== propertyProps.kindOfQuantity) { const koqSchemaItemKey = this.class.schema.getSchemaItemKey(propertyProps.kindOfQuantity); if (!koqSchemaItemKey) throw new Exception_1.ECSchemaError(Exception_1.ECSchemaStatus.InvalidECJson, `The Property ${this.name} has a 'kindOfQuantity' ("${propertyProps.kindOfQuantity}") that cannot be found.`); this._kindOfQuantity = new DelayedPromise_1.DelayedPromiseWithProps(koqSchemaItemKey, async () => { const koq = await this.class.schema.lookupItem(koqSchemaItemKey, KindOfQuantity_1.KindOfQuantity); if (undefined === koq) throw new Exception_1.ECSchemaError(Exception_1.ECSchemaStatus.InvalidECJson, `The Property ${this.name} has a 'kindOfQuantity' ("${propertyProps.kindOfQuantity}") that cannot be found.`); return koq; }); } } async fromJSON(propertyProps) { this.fromJSONSync(propertyProps); } /** @internal */ addCustomAttribute(customAttribute) { if (!this._customAttributes) this._customAttributes = new Map(); this._customAttributes.set(customAttribute.className, customAttribute); } /** @internal */ setName(name) { this._name = name; } /** * @internal Used in schema editing. */ setDescription(description) { this._description = description; } /** * @internal Used in schema editing. */ setLabel(label) { this._label = label; } /** * @internal Used in schema editing. */ setIsReadOnly(isReadOnly) { this._isReadOnly = isReadOnly; } /** * @internal Used in schema editing. */ setPriority(priority) { this._priority = priority; } /** * @internal Used in schema editing. */ setCategory(category) { this._category = category; } /** * @internal Used in schema editing. */ setKindOfQuantity(kindOfQuantity) { this._kindOfQuantity = kindOfQuantity; } /** * Retrieve all custom attributes in the current property and its base * This is the async version of getCustomAttributesSync() */ async getCustomAttributes() { return this.getCustomAttributesSync(); } /** * Retrieve all custom attributes in the current property and its base. */ getCustomAttributesSync() { let customAttributes = this._customAttributes; if (undefined === customAttributes) { customAttributes = new Map(); } const baseProperty = this.class.getInheritedPropertySync(this.name); let baseCustomAttributes; if (undefined !== baseProperty) baseCustomAttributes = baseProperty.getCustomAttributesSync(); if (undefined !== baseCustomAttributes) { customAttributes = new Map([...baseCustomAttributes, ...customAttributes]); } return customAttributes; } /** * @internal */ static isProperty(object) { const property = object; return property !== undefined && property.class !== undefined && property.name !== undefined && property.propertyType !== undefined; } } exports.Property = Property; /** @public @preview */ class PrimitiveOrEnumPropertyBase extends Property { /** @internal */ _extendedTypeName; /** @internal */ _minLength; /** @internal */ _maxLength; /** @internal */ _minValue; /** @internal */ _maxValue; get extendedTypeName() { return this._extendedTypeName; } get minLength() { return this._minLength; } get maxLength() { return this._maxLength; } get minValue() { return this._minValue; } get maxValue() { return this._maxValue; } /** @internal */ constructor(ecClass, name, type) { super(ecClass, name, type); } /** * Save this PrimitiveOrEnumPropertyBase's properties to an object for serializing to JSON. */ toJSON() { const schemaJson = super.toJSON(); if (this.extendedTypeName !== undefined) schemaJson.extendedTypeName = this.extendedTypeName; if (this._minLength !== undefined) schemaJson.minLength = this.minLength; if (this._maxLength !== undefined) schemaJson.maxLength = this.maxLength; if (this._minValue !== undefined) schemaJson.minValue = this.minValue; if (this._maxValue !== undefined) schemaJson.maxValue = this.maxValue; return schemaJson; } /** @internal */ async toXml(schemaXml) { const itemElement = await super.toXml(schemaXml); if (undefined !== this.extendedTypeName) itemElement.setAttribute("extendedTypeName", this.extendedTypeName); if (undefined !== this.minValue) itemElement.setAttribute("minimumValue", this.minValue.toString()); if (undefined !== this.maxValue) itemElement.setAttribute("maximumValue", this.maxValue.toString()); if (undefined !== this.minLength) itemElement.setAttribute("minimumLength", this.minLength.toString()); if (undefined !== this.maxLength) itemElement.setAttribute("maximumLength", this.maxLength.toString()); return itemElement; } fromJSONSync(propertyBaseProps) { super.fromJSONSync(propertyBaseProps); if (undefined !== propertyBaseProps.minLength) { this._minLength = propertyBaseProps.minLength; } if (undefined !== propertyBaseProps.maxLength) { this._maxLength = propertyBaseProps.maxLength; } if (undefined !== propertyBaseProps.minValue) { this._minValue = propertyBaseProps.minValue; } if (undefined !== propertyBaseProps.maxValue) { this._maxValue = propertyBaseProps.maxValue; } if (undefined !== propertyBaseProps.extendedTypeName) { this._extendedTypeName = propertyBaseProps.extendedTypeName; } } /** * @internal Used in schema editing. */ setExtendedTypeName(extendedTypeName) { this._extendedTypeName = extendedTypeName; } /** * @internal Used in schema editing. */ setMinLength(minLength) { this._minLength = minLength; } /** * @internal Used in schema editing. */ setMaxLength(maxLength) { this._maxLength = maxLength; } /** * @internal Used in schema editing. */ setMinValue(minValue) { this._minValue = minValue; } /** * @internal Used in schema editing. */ setMaxValue(maxValue) { this._maxValue = maxValue; } async fromJSON(propertyBaseProps) { this.fromJSONSync(propertyBaseProps); } } exports.PrimitiveOrEnumPropertyBase = PrimitiveOrEnumPropertyBase; /** @public @preview */ class PrimitiveProperty extends PrimitiveOrEnumPropertyBase { get primitiveType() { return PropertyTypes_1.PropertyTypeUtils.getPrimitiveType(this.propertyType); } /** @internal */ constructor(ecClass, name, primitiveType = ECObjects_1.PrimitiveType.Integer) { super(ecClass, name, PropertyTypes_1.PropertyTypeUtils.fromPrimitiveType(primitiveType)); } fromJSONSync(primitivePropertyProps) { super.fromJSONSync(primitivePropertyProps); if (undefined !== primitivePropertyProps.typeName) { if (this.primitiveType !== (0, ECObjects_1.parsePrimitiveType)(primitivePropertyProps.typeName)) throw new Exception_1.ECSchemaError(Exception_1.ECSchemaStatus.InvalidECJson, ``); } } async fromJSON(primitivePropertyProps) { this.fromJSONSync(primitivePropertyProps); } /** * Save this PrimitiveProperty's properties to an object for serializing to JSON. */ toJSON() { const schemaJson = super.toJSON(); schemaJson.typeName = (0, ECObjects_1.primitiveTypeToString)(this.primitiveType); return schemaJson; } /** @internal */ async toXml(schemaXml) { const itemElement = await super.toXml(schemaXml); itemElement.setAttribute("typeName", (0, ECObjects_1.primitiveTypeToString)(this.primitiveType)); return itemElement; } } exports.PrimitiveProperty = PrimitiveProperty; /** @public @preview */ class EnumerationProperty extends PrimitiveOrEnumPropertyBase { /** @internal */ _enumeration; get enumeration() { return this._enumeration; } /** * Save this EnumerationProperty's properties to an object for serializing to JSON. */ toJSON() { const schemaJson = super.toJSON(); schemaJson.typeName = this.enumeration.fullName; return schemaJson; } /** @internal */ constructor(ecClass, name, type) { // TODO: Should we allow specifying the backing type? super(ecClass, name, PropertyTypes_1.PropertyType.Integer_Enumeration); this._enumeration = type; } fromJSONSync(enumerationPropertyProps) { super.fromJSONSync(enumerationPropertyProps); if (undefined !== enumerationPropertyProps.typeName) { if (!(this.enumeration.fullName).match(enumerationPropertyProps.typeName)) // need to match {schema}.{version}.{itemName} on typeName throw new Exception_1.ECSchemaError(Exception_1.ECSchemaStatus.InvalidECJson, ``); const enumSchemaItemKey = this.class.schema.getSchemaItemKey(this.enumeration.fullName); if (!enumSchemaItemKey) throw new Exception_1.ECSchemaError(Exception_1.ECSchemaStatus.InvalidECJson, `Unable to locate the enumeration ${enumerationPropertyProps.typeName}.`); this._enumeration = new DelayedPromise_1.DelayedPromiseWithProps(enumSchemaItemKey, async () => { const enumeration = await this.class.schema.lookupItem(enumSchemaItemKey, Enumeration_1.Enumeration); if (undefined === enumeration) throw new Exception_1.ECSchemaError(Exception_1.ECSchemaStatus.InvalidECJson, `Unable to locate the enumeration ${enumerationPropertyProps.typeName}.`); return enumeration; }); } } /** @internal */ async toXml(schemaXml) { const itemElement = await super.toXml(schemaXml); const enumeration = await this.enumeration; const enumerationName = XmlSerializationUtils_1.XmlSerializationUtils.createXmlTypedName(this.schema, enumeration.schema, enumeration.name); itemElement.setAttribute("typeName", enumerationName); return itemElement; } async fromJSON(enumerationPropertyProps) { this.fromJSONSync(enumerationPropertyProps); } } exports.EnumerationProperty = EnumerationProperty; /** @public @preview */ class StructProperty extends Property { /** @internal */ _structClass; get structClass() { return this._structClass; } /** @internal */ constructor(ecClass, name, type) { super(ecClass, name, PropertyTypes_1.PropertyType.Struct); this._structClass = type; } /** * Save this StructProperty's properties to an object for serializing to JSON. */ toJSON() { const schemaJson = super.toJSON(); schemaJson.typeName = this.structClass.fullName; return schemaJson; } /** @internal */ async toXml(schemaXml) { const itemElement = await super.toXml(schemaXml); const structClassName = XmlSerializationUtils_1.XmlSerializationUtils.createXmlTypedName(this.schema, this.structClass.schema, this.structClass.name); itemElement.setAttribute("typeName", structClassName); return itemElement; } fromJSONSync(structPropertyProps) { super.fromJSONSync(structPropertyProps); if (undefined !== structPropertyProps.typeName) { if (!this.structClass.key.matchesFullName(structPropertyProps.typeName)) throw new Exception_1.ECSchemaError(Exception_1.ECSchemaStatus.InvalidECJson, ``); } } async fromJSON(structPropertyProps) { this.fromJSONSync(structPropertyProps); } } exports.StructProperty = StructProperty; /** @public @preview */ class NavigationProperty extends Property { /** @internal */ _relationshipClass; /** @internal */ _direction; get relationshipClass() { return this._relationshipClass; } getRelationshipClassSync() { if (!this._relationshipClass) // eslint-disable-line @typescript-eslint/no-misused-promises return undefined; // We cannot use the type guard here to avoid a circular dependency const result = this.class.schema.lookupItemSync(this._relationshipClass); return result?.schemaItemType === ECObjects_1.SchemaItemType.RelationshipClass ? result : undefined; } get direction() { return this._direction; } /** * Save this NavigationProperty's properties to an object for serializing to JSON. */ toJSON() { const schemaJson = super.toJSON(); schemaJson.relationshipName = this.relationshipClass.fullName; schemaJson.direction = (0, ECObjects_1.strengthDirectionToString)(this.direction); return schemaJson; } /** @internal */ async toXml(schemaXml) { const itemElement = await super.toXml(schemaXml); const relationshipClass = await this.relationshipClass; const relationshipClassName = XmlSerializationUtils_1.XmlSerializationUtils.createXmlTypedName(this.schema, relationshipClass.schema, relationshipClass.name); itemElement.setAttribute("relationshipName", relationshipClassName); itemElement.setAttribute("direction", (0, ECObjects_1.strengthDirectionToString)(this.direction)); return itemElement; } /** @internal */ constructor(ecClass, name, relationship, direction) { super(ecClass, name, PropertyTypes_1.PropertyType.Navigation); this._relationshipClass = relationship; this._direction = (direction !== undefined) ? direction : ECObjects_1.StrengthDirection.Forward; } } exports.NavigationProperty = NavigationProperty; // TODO: Consolidate all of the INT32_MAX variables. const INT32_MAX = 2147483647; /** @public @preview */ class ArrayProperty extends Property { /** @internal */ _minOccurs = 0; /** @internal */ _maxOccurs = INT32_MAX; get minOccurs() { return this._minOccurs; } get maxOccurs() { return this._maxOccurs; } /** * @internal Used in schema editing. */ setMinOccurs(minOccurs) { this._minOccurs = minOccurs; } /** * @internal Used in schema editing. */ setMaxOccurs(maxOccurs) { this._maxOccurs = maxOccurs; } } exports.ArrayProperty = ArrayProperty; // eslint-disable-next-line @typescript-eslint/naming-convention const ArrayPropertyMixin = (Base) => { return class extends Base { /** @internal */ _minOccurs = 0; /** @internal */ _maxOccurs = INT32_MAX; get minOccurs() { return this._minOccurs; } get maxOccurs() { return this._maxOccurs; } constructor(...args) { super(...args); this._type = PropertyTypes_1.PropertyTypeUtils.asArray(this.propertyType); } fromJSONSync(arrayPropertyProps) { super.fromJSONSync(arrayPropertyProps); if (undefined !== arrayPropertyProps.minOccurs) { this._minOccurs = arrayPropertyProps.minOccurs; } if (undefined !== arrayPropertyProps.maxOccurs) { this._maxOccurs = arrayPropertyProps.maxOccurs; } } async fromJSON(arrayPropertyProps) { this.fromJSONSync(arrayPropertyProps); } /** * Save this ArrayProperty's properties to an object for serializing to JSON. */ toJSON() { const schemaJson = super.toJSON(); schemaJson.minOccurs = this.minOccurs; if (this.maxOccurs !== undefined) schemaJson.maxOccurs = this.maxOccurs; return schemaJson; } /** @internal */ async toXml(schemaXml) { const itemElement = await super.toXml(schemaXml); itemElement.setAttribute("minOccurs", this.minOccurs.toString()); if (this.maxOccurs) itemElement.setAttribute("maxOccurs", this.maxOccurs.toString()); return itemElement; } /** * @internal Used in schema editing. */ setMinOccurs(minOccurs) { this._minOccurs = minOccurs; } /** * @internal Used in schema editing. */ setMaxOccurs(maxOccurs) { this._maxOccurs = maxOccurs; } }; }; /** @public @preview */ class PrimitiveArrayProperty extends ArrayPropertyMixin(PrimitiveProperty) { /** @internal */ constructor(ecClass, name, primitiveType = ECObjects_1.PrimitiveType.Integer) { super(ecClass, name, primitiveType); } /** * Save this PrimitiveArrayProperty's properties to an object for serializing to JSON. */ toJSON() { return super.toJSON(); } } exports.PrimitiveArrayProperty = PrimitiveArrayProperty; /** @public @preview */ class EnumerationArrayProperty extends ArrayPropertyMixin(EnumerationProperty) { constructor(ecClass, name, type) { super(ecClass, name, type); } } exports.EnumerationArrayProperty = EnumerationArrayProperty; /** @public @preview */ class StructArrayProperty extends ArrayPropertyMixin(StructProperty) { /** @internal */ constructor(ecClass, name, type) { super(ecClass, name, type); } } exports.StructArrayProperty = StructArrayProperty; /** * Hackish approach that works like a "friend class" so we can access protected members without making them public. * @internal */ class MutableProperty extends Property { } exports.MutableProperty = MutableProperty; //# sourceMappingURL=Property.js.map