@itwin/core-backend
Version:
iTwin.js backend components
213 lines • 10.9 kB
JavaScript
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
/** @packageDocumentation
* @module ElementAspects
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.ExternalSourceAspect = exports.ChannelRootAspect = exports.ElementMultiAspect = exports.ElementUniqueAspect = exports.ElementAspect = void 0;
const core_common_1 = require("@itwin/core-common");
const Entity_1 = require("./Entity");
const core_bentley_1 = require("@itwin/core-bentley");
const Symbols_1 = require("./internal/Symbols");
/** An Element Aspect is a class that defines a set of properties that are related to (and owned by) a single element.
* Semantically, an ElementAspect can be considered part of the Element. Thus, an ElementAspect is deleted if its owning Element is deleted.
* BIS Guideline: Subclass ElementUniqueAspect or ElementMultiAspect rather than subclassing ElementAspect directly.
* @public @preview
*/
class ElementAspect extends Entity_1.Entity {
static get className() { return "ElementAspect"; }
element;
/** Construct an aspect from its JSON representation and its containing iModel. */
constructor(props, iModel) {
super(props, iModel);
this.element = core_common_1.RelatedElement.fromJSON(props.element); // eslint-disable-line @typescript-eslint/no-non-null-assertion
}
toJSON() {
const val = super.toJSON();
val.element = this.element;
return val;
}
/** Called before a new ElementAspect is inserted.
* @note throw an exception to disallow the insert
* @note If you override this method, you must call super.
* @beta
*/
static onInsert(arg) {
const { props, iModel } = arg;
iModel.channels[Symbols_1._verifyChannel](arg.model);
iModel.locks.checkExclusiveLock(props.element.id, "element", "insert aspect");
}
/** Called after a new ElementAspect was inserted.
* @note If you override this method, you must call super.
* @beta
*/
static onInserted(_arg) { }
/** Called before an ElementAspect is updated.
* @note throw an exception to disallow the update
* @note If you override this method, you must call super.
* @beta
*/
static onUpdate(arg) {
const { props, iModel } = arg;
iModel.channels[Symbols_1._verifyChannel](arg.model);
iModel.locks.checkExclusiveLock(props.element.id, "element", "update aspect");
}
/** Called after an ElementAspect was updated.
* @note If you override this method, you must call super.
* @beta
*/
static onUpdated(_arg) { }
/** Called before an ElementAspect is deleted.
* @note throw an exception to disallow the delete
* @note If you override this method, you must call super.
* @beta
*/
static onDelete(arg) {
const { aspectId, iModel } = arg;
iModel.channels[Symbols_1._verifyChannel](arg.model);
const { element } = iModel.elements.getAspect(aspectId);
iModel.locks.checkExclusiveLock(element.id, "element", "delete aspect");
}
/** Called after an ElementAspect was deleted.
* @note If you override this method, you must call super.
* @beta
*/
static onDeleted(_arg) { }
}
exports.ElementAspect = ElementAspect;
/** An Element Unique Aspect is an ElementAspect where there can be only zero or one instance of the Element Aspect class per Element.
* @public @preview
*/
class ElementUniqueAspect extends ElementAspect {
static get className() { return "ElementUniqueAspect"; }
}
exports.ElementUniqueAspect = ElementUniqueAspect;
/** An Element Multi-Aspect is an ElementAspect where there can be **n** instances of the Element Aspect class per Element.
* @public @preview
*/
class ElementMultiAspect extends ElementAspect {
static get className() { return "ElementMultiAspect"; }
}
exports.ElementMultiAspect = ElementMultiAspect;
/**
* @public @preview
*/
class ChannelRootAspect extends ElementUniqueAspect {
static get className() { return "ChannelRootAspect"; }
/** Insert a ChannelRootAspect on the specified element.
* @deprecated in 4.0 - will not be removed until after 2026-06-13. Use [[ChannelControl.makeChannelRoot]]. This method does not enforce the rule that channels may not nest and is therefore dangerous.
*/
static insert(iModel, ownerId, channelName) {
const props = { classFullName: this.classFullName, element: { id: ownerId }, owner: channelName };
iModel.elements.insertAspect(props);
}
}
exports.ChannelRootAspect = ChannelRootAspect;
/** An ElementMultiAspect that stores synchronization information for an Element originating from an external source.
* @note The associated ECClass was added to the BisCore schema in version 1.0.2
* @public @preview
*/
class ExternalSourceAspect extends ElementMultiAspect {
static get className() { return "ExternalSourceAspect"; }
/** An element that scopes the combination of `kind` and `identifier` to uniquely identify the object from the external source.
* @note Warning: in a future major release the `scope` property will be optional, since the scope is intended to be potentially invalid.
* all references should treat it as potentially undefined, but we cannot change the type yet since that is a breaking change.
*/
scope;
/** The identifier of the object in the source repository. */
identifier;
/** The kind of object within the source repository. */
kind;
/** The cryptographic hash (any algorithm) of the source object's content. If defined, it must be guaranteed to change when the source object's content changes. */
checksum;
/** An optional value that is typically a version number or a pseudo version number like last modified time.
* It will be used by the synchronization process to detect that a source object is unchanged so that computing a cryptographic hash can be avoided.
* If present, this value must be guaranteed to change when any of the source object's content changes.
*/
version;
/** A place where additional JSON properties can be stored. For example, provenance information or properties relating to the synchronization process.
* @note Warning: in a future major release, the type of `jsonProperties` will be changed to object, and itwin.js will automatically stringify it when writing to the iModel.
* This will be a breaking change, since application code will have to change from supplying a string to supplying an object.
*/
jsonProperties;
/** The source of the imported/synchronized object. Should point to an instance of [ExternalSource]($backend). */
source;
/** Construct an aspect from its JSON representation and its containing iModel. */
constructor(props, iModel) {
super(props, iModel);
this.scope = core_common_1.RelatedElement.fromJSON(props.scope); // eslint-disable-line @typescript-eslint/no-non-null-assertion
this.source = core_common_1.RelatedElement.fromJSON(props.source);
this.identifier = props.identifier;
this.kind = props.kind;
this.checksum = props.checksum;
this.version = props.version;
this.jsonProperties = props.jsonProperties;
}
/** Look up the elements that contain one or more ExternalSourceAspect with the specified Scope, Kind, and Identifier.
* The result of this function is an array of all of the ExternalSourceAspects that were found, each associated with the owning element.
* A given element could have more than one ExternalSourceAspect with the given scope, kind, and identifier.
* Also, many elements could have ExternalSourceAspect with the same scope, kind, and identifier.
* Therefore, the result array could have more than one entry with the same elementId.
* Aspects are never shared. Each aspect has its own unique ECInstanceId.
* @param iModelDb The iModel to query
* @param scope The scope of the ExternalSourceAspects to find
* @param kind The kind of the ExternalSourceAspects to find
* @param identifier The identifier of the ExternalSourceAspects to find
* @returns the query results
*/
static findAllBySource(iModelDb, scope, kind, identifier) {
const sql = `SELECT Element.Id, ECInstanceId FROM ${ExternalSourceAspect.classFullName} WHERE (Scope.Id=:scope AND Kind=:kind AND Identifier=:identifier)`;
const found = [];
// eslint-disable-next-line @typescript-eslint/no-deprecated
iModelDb.withPreparedStatement(sql, (statement) => {
statement.bindId("scope", scope);
statement.bindString("kind", kind);
statement.bindString("identifier", identifier);
while (core_bentley_1.DbResult.BE_SQLITE_ROW === statement.step()) {
found.push({ elementId: statement.getValue(0).getId(), aspectId: statement.getValue(1).getId() });
}
});
return found;
}
toJSON() {
const val = super.toJSON();
val.scope = this.scope;
val.source = this.source;
val.identifier = this.identifier;
val.kind = this.kind;
val.checksum = this.checksum;
val.version = this.version;
val.jsonProperties = this.jsonProperties;
return val;
}
collectReferenceIds(referenceIds) {
super.collectReferenceIds(referenceIds);
if (this.scope)
referenceIds.addElement(this.scope.id);
referenceIds.addElement(this.element.id);
if (this.source)
referenceIds.addElement(this.source.id);
}
}
exports.ExternalSourceAspect = ExternalSourceAspect;
/** @public @preview */
(function (ExternalSourceAspect) {
/** Standard values for the `Kind` property of `ExternalSourceAspect`.
* @public @preview
*/
let Kind;
(function (Kind) {
/** Indicates that the [[ExternalSourceAspect]] is storing [[Element]] provenance */
Kind["Element"] = "Element";
/** Indicates that the [[ExternalSourceAspect]] is storing [[Relationship]] provenance */
Kind["Relationship"] = "Relationship";
/** Indicates that the [[ExternalSourceAspect]] is storing *scope* provenance
* @see [[ExternalSourceAspect.scope]]
*/
Kind["Scope"] = "Scope";
})(Kind = ExternalSourceAspect.Kind || (ExternalSourceAspect.Kind = {}));
})(ExternalSourceAspect || (exports.ExternalSourceAspect = ExternalSourceAspect = {}));
//# sourceMappingURL=ElementAspect.js.map
;