@itwin/core-backend
Version:
iTwin.js backend components
598 lines • 27.1 kB
JavaScript
"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 Models
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.WebMercatorModel = exports.DictionaryModel = exports.LinkModel = exports.DocumentListModel = exports.RepositoryModel = exports.DefinitionModel = exports.InformationRecordModel = exports.SheetIndexModel = exports.GroupInformationModel = exports.InformationModel = exports.RoleModel = exports.SheetModel = exports.SectionDrawingModel = exports.DrawingModel = exports.SpatialLocationModel = exports.PhysicalModel = exports.SpatialModel = exports.GraphicalModel3d = exports.GraphicalModel2d = exports.GeometricModel2d = exports.GeometricModel3d = exports.GeometricModel = exports.Model = void 0;
// cspell:ignore elid
const core_bentley_1 = require("@itwin/core-bentley");
const core_geometry_1 = require("@itwin/core-geometry");
const core_common_1 = require("@itwin/core-common");
const Element_1 = require("./Element");
const Entity_1 = require("./Entity");
const NavigationRelationship_1 = require("./NavigationRelationship");
const Symbols_1 = require("./internal/Symbols");
/** A Model is a container for persisting a collection of related elements within an iModel.
* See [[IModelDb.Models]] for how to query and manage the Models in an IModelDb.
* See [Creating models]($docs/learning/backend/CreateModels.md)
* @public @preview
*/
class Model extends Entity_1.Entity {
static get className() { return "Model"; }
/** @internal */
static get protectedOperations() { return ["onInsert", "onUpdate", "onDelete"]; }
modeledElement;
name;
parentModel;
jsonProperties;
isPrivate;
isTemplate;
constructor(props, iModel) {
super(props, iModel);
this.modeledElement = new core_common_1.RelatedElement(props.modeledElement);
this.name = props.name ? props.name : ""; // NB this isn't really a property of Model (it's the code.value of the modeled element), but it comes in ModelProps because it's often needed
this.parentModel = props.parentModel;
this.isPrivate = core_bentley_1.JsonUtils.asBool(props.isPrivate);
this.isTemplate = core_bentley_1.JsonUtils.asBool(props.isTemplate);
this.jsonProperties = { ...props.jsonProperties }; // make sure we have our own copy
}
/**
* Model custom HandledProps includes 'isPrivate', 'isTemplate', and 'lastMod'.
* @inheritdoc
* @beta
*/
static _customHandledProps = [
{ propertyName: "isPrivate", source: "Class" },
{ propertyName: "isTemplate", source: "Class" },
{ propertyName: "lastMod", source: "Class" },
];
/**
* Model deserializes 'isPrivate', and 'isTemplate', and sets the proper parentModel.
* @inheritdoc
* @beta
*/
static deserialize(props) {
const instance = props.row;
const modelProps = super.deserialize(props);
const modeledElementProps = props.iModel.elements.tryGetElementProps(instance.modeledElement.id);
if (modeledElementProps) {
// ModeledElement may be undefined in the case of root Element
modelProps.name = core_bentley_1.JsonUtils.asString(modeledElementProps.code.value);
if (instance.parentModel !== undefined)
modelProps.parentModel = instance.parentModel.id;
else
modelProps.parentModel = modeledElementProps.model;
}
if (instance.isPrivate === true)
modelProps.isPrivate = true;
if (instance.isTemplate === true)
modelProps.isTemplate = true;
return modelProps;
}
/**
* Model serializes 'isPrivate', and 'isTemplate'.
* @inheritdoc
* @beta
*/
static serialize(props, _iModel) {
const inst = super.serialize(props, _iModel);
inst.isPrivate = props.isPrivate ?? false;
inst.isTemplate = props.isTemplate ?? false;
return inst;
}
toJSON() {
const val = super.toJSON();
val.name = this.name; // for cloning
return val;
}
/** Called before a new Model is inserted.
* @note throw an exception to disallow the insert
* @note If you override this method, you must call super.
* @note `this` is the class of the Model to be inserted
* @beta
*/
static onInsert(arg) {
const { props, iModel } = arg;
iModel.channels[Symbols_1._verifyChannel](props.modeledElement.id);
if (props.parentModel) // inserting requires shared lock on parent, if present
iModel.locks.checkSharedLock(props.parentModel, "parent model", "insert");
}
/** Called after a new Model is inserted.
* @note If you override this method, you must call super.
* @note `this` is the class of the Model that was inserted
* @beta
*/
static onInserted(_arg) {
// we don't need to tell LockControl about models being created - their ModeledElement does that
}
/** Called before a Model is updated.
* @note throw an exception to disallow the update
* @note If you override this method, you must call super.
* @note `this` is the class of the Model to be updated
* @beta
*/
static onUpdate(arg) {
const id = arg.props.id; // eslint-disable-line @typescript-eslint/no-non-null-assertion
arg.iModel.channels[Symbols_1._verifyChannel](id);
arg.iModel.locks.checkExclusiveLock(id, "model", "update");
}
/** Called after a Model is updated.
* @note If you override this method, you must call super.
* @note `this` is the class of the Model that was updated.
* @beta
*/
static onUpdated(arg) {
arg.iModel.models[Symbols_1._cache].delete(arg.id);
}
/** Called before a Model is deleted.
* @note throw an exception to disallow the delete
* @note If you override this method, you must call super.
* @note `this` is the class of the Model to be deleted
* @beta
*/
static onDelete(arg) {
arg.iModel.channels[Symbols_1._verifyChannel](arg.id);
arg.iModel.locks.checkExclusiveLock(arg.id, "model", "delete");
}
/** Called after a Model was deleted.
* @note If you override this method, you must call super.
* @note `this` is the class of the Model that was deleted
* @beta
*/
static onDeleted(arg) {
arg.iModel.models[Symbols_1._cache].delete(arg.id);
arg.iModel.elements[Symbols_1._cache].deleteWithModel(arg.id);
}
/** Called before a prospective Element is to be inserted into an instance of a Model of this class.
* @note throw an exception to disallow the insert
* @note If you override this method, you must call super.
* @note `this` is the class of the Model to hold the element
* @beta
*/
static onInsertElement(_arg) { }
/** Called after an Element has been inserted into an instance of a Model of this class.
* @note If you override this method, you must call super.
* @note `this` is the class of the Model holding the element
* @beta
*/
static onInsertedElement(arg) {
arg.iModel.models[Symbols_1._cache].delete(arg.id);
}
/** Called when an Element in an instance of a Model of this class is about to be updated.
* @note throw an exception to disallow the update
* @note If you override this method, you must call super.
* @note `this` is the class of the Model holding the element
* @beta
*/
static onUpdateElement(_arg) { }
/** Called after an Element in an instance of a Model of this class has been updated.
* @note If you override this method, you must call super.
* @note `this` is the class of the Model holding the element
* @beta
*/
static onUpdatedElement(arg) {
arg.iModel.models[Symbols_1._cache].delete(arg.id);
}
/** Called when an Element in an instance of a Model of this class is about to be deleted.
* @note throw an exception to disallow the delete
* @note If you override this method, you must call super.
* @note `this` is the class of the Model holding the element
* @beta
*/
static onDeleteElement(_arg) { }
/** Called after an Element in an instance of a Model of this class has been deleted.
* @note If you override this method, you must call super.
* @note `this` is the class of the Model that held the element
* @beta
*/
static onDeletedElement(arg) {
arg.iModel.models[Symbols_1._cache].delete(arg.id);
}
getAllUserProperties() {
if (!this.jsonProperties.UserProps)
this.jsonProperties.UserProps = new Object();
return this.jsonProperties.UserProps;
}
/** Get a set of JSON user properties by namespace */
getUserProperties(namespace) { return this.getAllUserProperties()[namespace]; }
/** Change a set of user JSON properties of this Element by namespace. */
setUserProperties(nameSpace, value) { this.getAllUserProperties()[nameSpace] = value; }
/** Remove a set of JSON user properties, specified by namespace, from this Element */
removeUserProperties(nameSpace) { delete this.getAllUserProperties()[nameSpace]; }
getJsonProperty(name) { return this.jsonProperties[name]; }
setJsonProperty(name, value) { this.jsonProperties[name] = value; }
/** Insert this Model in the iModel */
insert() { return this.id = this.iModel.models.insertModel(this.toJSON()); }
/** Update this Model in the iModel. */
update() { this.iModel.models.updateModel(this.toJSON()); }
/** Delete this Model from the iModel. */
delete() { this.iModel.models.deleteModel(this.id); }
collectReferenceIds(referenceIds) {
super.collectReferenceIds(referenceIds);
if (this.parentModel)
referenceIds.addModel(this.parentModel);
referenceIds.addElement(this.modeledElement.id);
}
}
exports.Model = Model;
/** A container for persisting geometric elements.
* @public @preview
*/
class GeometricModel extends Model {
geometryGuid;
static get className() { return "GeometricModel"; }
constructor(props, iModel) {
super(props, iModel);
this.geometryGuid = props.geometryGuid;
}
/** Query for the union of the extents of the elements contained by this model.
* @note This function blocks the JavaScript event loop. Consider using [[queryRange]] instead.
*/
queryExtents() {
const extents = this.iModel[Symbols_1._nativeDb].queryModelExtents({ id: this.id }).modelExtents;
return core_geometry_1.Range3d.fromJSON(extents);
}
/** Query for the union of the extents of all elements contained within this model. */
async queryRange() {
return this.iModel.models.queryRange(this.id);
}
}
exports.GeometricModel = GeometricModel;
/** A container for persisting 3d geometric elements.
* @public @preview
*/
class GeometricModel3d extends GeometricModel {
/** If true, then the elements in this GeometricModel3d are expected to be in an XY plane.
* @note The associated ECProperty was added to the BisCore schema in version 1.0.8
*/
isPlanProjection;
/** If true, then the elements in this GeometricModel3d are not in real-world coordinates and will not be in the spatial index.
* @note The associated ECProperty was added to the BisCore schema in version 1.0.8
*/
isNotSpatiallyLocated;
/** If true, then the elements in this GeometricModel3d are in real-world coordinates and will be in the spatial index. */
get isSpatiallyLocated() { return !this.isNotSpatiallyLocated; }
static get className() { return "GeometricModel3d"; }
constructor(props, iModel) {
super(props, iModel);
this.isNotSpatiallyLocated = core_bentley_1.JsonUtils.asBool(props.isNotSpatiallyLocated);
this.isPlanProjection = core_bentley_1.JsonUtils.asBool(props.isPlanProjection);
}
/**
* GeometricModel3d custom HandledProps includes 'isPlanProjection', and 'isNotSpatiallyLocated'.
* @inheritdoc
* @beta
*/
static _customHandledProps = [
{ propertyName: "isPlanProjection", source: "Class" },
{ propertyName: "isNotSpatiallyLocated", source: "Class" },
];
/**
* GeometricModel3d deserializes 'isPlanProjection', and 'isNotSpatiallyLocated'.
* @inheritdoc
* @beta
*/
static deserialize(props) {
const modelProps = super.deserialize(props);
const instance = props.row;
if (instance.isNotSpatiallyLocated === true || instance.isTemplate === true)
modelProps.isNotSpatiallyLocated = true;
if (instance.isPlanProjection === true)
modelProps.isPlanProjection = true;
return modelProps;
}
/**
* GeometricModel3d serializes 'isPlanProjection', and 'isNotSpatiallyLocated'.
* @inheritdoc
* @beta
*/
static serialize(props, _iModel) {
const inst = super.serialize(props, _iModel);
inst.isNotSpatiallyLocated = props.isNotSpatiallyLocated ?? false;
inst.isPlanProjection = props.isPlanProjection ?? false;
return inst;
}
toJSON() {
const val = super.toJSON();
if (this.isNotSpatiallyLocated)
val.isNotSpatiallyLocated = true;
if (this.isPlanProjection)
val.isPlanProjection = true;
return val;
}
}
exports.GeometricModel3d = GeometricModel3d;
/** A container for persisting 2d geometric elements.
* @public @preview
*/
class GeometricModel2d extends GeometricModel {
/** The actual coordinates of (0,0) in modeling coordinates. An offset applied to all modeling coordinates. */
globalOrigin;
static get className() { return "GeometricModel2d"; }
constructor(props, iModel) {
super(props, iModel);
this.globalOrigin = props.globalOrigin ? core_geometry_1.Point2d.fromJSON(props.globalOrigin) : undefined;
}
toJSON() {
const val = super.toJSON();
if (undefined !== this.globalOrigin)
val.globalOrigin = core_geometry_1.Point2d.fromJSON(this.globalOrigin);
return val;
}
}
exports.GeometricModel2d = GeometricModel2d;
/** A container for persisting 2d graphical elements.
* @public @preview
*/
class GraphicalModel2d extends GeometricModel2d {
static get className() { return "GraphicalModel2d"; }
}
exports.GraphicalModel2d = GraphicalModel2d;
/** A container for persisting GraphicalElement3d instances.
* @note The associated ECClass was added to the BisCore schema in version 1.0.8
* @see [[GraphicalPartition3d]]
* @public @preview
*/
class GraphicalModel3d extends GeometricModel3d {
static get className() { return "GraphicalModel3d"; }
}
exports.GraphicalModel3d = GraphicalModel3d;
/** A container for persisting 3d geometric elements that are spatially located.
* @public @preview
*/
class SpatialModel extends GeometricModel3d {
static get className() { return "SpatialModel"; }
}
exports.SpatialModel = SpatialModel;
/** A container for persisting physical elements that model physical space.
* @see [[PhysicalPartition]]
* @public @preview
*/
class PhysicalModel extends SpatialModel {
static get className() { return "PhysicalModel"; }
/** Insert a PhysicalPartition and a PhysicalModel that sub-models it.
* @param iModelDb Insert into this iModel
* @param parentSubjectId The PhysicalPartition will be inserted as a child of this Subject element.
* @param name The name of the PhysicalPartition that the new PhysicalModel will sub-model.
* @param isPlanProjection Optional value (default is false) that indicates if the contents of this model are expected to be in an XY plane.
* @returns The Id of the newly inserted PhysicalPartition and PhysicalModel (same value).
* @throws [[IModelError]] if there is an insert problem.
*/
static insert(iModelDb, parentSubjectId, name, isPlanProjection) {
const partitionProps = {
classFullName: Element_1.PhysicalPartition.classFullName,
model: core_common_1.IModel.repositoryModelId,
parent: new NavigationRelationship_1.SubjectOwnsPartitionElements(parentSubjectId),
code: Element_1.PhysicalPartition.createCode(iModelDb, parentSubjectId, name),
};
const partitionId = iModelDb.elements.insertElement(partitionProps);
const modelProps = {
classFullName: this.classFullName,
modeledElement: { id: partitionId },
isPlanProjection,
};
return iModelDb.models.insertModel(modelProps);
}
}
exports.PhysicalModel = PhysicalModel;
/** A container for persisting spatial location elements.
* @see [[SpatialLocationPartition]]
* @public @preview
*/
class SpatialLocationModel extends SpatialModel {
static get className() { return "SpatialLocationModel"; }
/** Insert a SpatialLocationPartition and a SpatialLocationModel that sub-models it.
* @param iModelDb Insert into this iModel
* @param parentSubjectId The SpatialLocationPartition will be inserted as a child of this Subject element.
* @param name The name of the SpatialLocationPartition that the new SpatialLocationModel will sub-model.
* @param isPlanProjection Optional value (default is false) that indicates if the contents of this model are expected to be in an XY plane.
* @returns The Id of the newly inserted SpatialLocationPartition and SpatialLocationModel (same value).
* @throws [[IModelError]] if there is an insert problem.
*/
static insert(iModelDb, parentSubjectId, name, isPlanProjection) {
const partitionProps = {
classFullName: Element_1.SpatialLocationPartition.classFullName,
model: core_common_1.IModel.repositoryModelId,
parent: new NavigationRelationship_1.SubjectOwnsPartitionElements(parentSubjectId),
code: Element_1.SpatialLocationPartition.createCode(iModelDb, parentSubjectId, name),
};
const partitionId = iModelDb.elements.insertElement(partitionProps);
const modelProps = {
classFullName: this.classFullName,
modeledElement: { id: partitionId },
isPlanProjection,
};
return iModelDb.models.insertModel(modelProps);
}
}
exports.SpatialLocationModel = SpatialLocationModel;
/** A 2d model that holds [[DrawingGraphic]]s. DrawingModels may be dimensional or non-dimensional.
* @public @preview
*/
class DrawingModel extends GraphicalModel2d {
static get className() { return "DrawingModel"; }
}
exports.DrawingModel = DrawingModel;
/** A container for persisting section [[DrawingGraphic]]s.
* @public @preview
*/
class SectionDrawingModel extends DrawingModel {
static get className() { return "SectionDrawingModel"; }
}
exports.SectionDrawingModel = SectionDrawingModel;
/** A container for persisting [[ViewAttachment]]s and [[DrawingGraphic]]s.
* A SheetModel is a digital representation of a *sheet of paper*. SheetModels are 2d models in bounded paper coordinates.
* SheetModels may contain annotation Elements as well as references to 2d or 3d Views.
* @public @preview
*/
class SheetModel extends GraphicalModel2d {
static get className() { return "SheetModel"; }
}
exports.SheetModel = SheetModel;
/** A container for persisting role elements.
* @public @preview
*/
class RoleModel extends Model {
static get className() { return "RoleModel"; }
}
exports.RoleModel = RoleModel;
/** A container for persisting information elements.
* @public @preview
*/
class InformationModel extends Model {
static get className() { return "InformationModel"; }
}
exports.InformationModel = InformationModel;
/** A container for persisting group information elements.
* @see [[GroupInformationPartition]]
* @public @preview
*/
class GroupInformationModel extends InformationModel {
static get className() { return "GroupInformationModel"; }
}
exports.GroupInformationModel = GroupInformationModel;
/** A sub-model of a [[SheetIndexPartition]] serving as a container for persisting [[SheetIndexEntry]] and [[SheetIndex]] elements.
* @beta
*/
class SheetIndexModel extends InformationModel {
static get className() { return "SheetIndexModel"; }
/** Insert a SheetIndex and a SheetIndexModel that sub-models it.
* @param iModelDb Insert into this iModel
* @param parentSubjectId The SheetIndex will be inserted as a child of this Subject element.
* @param name The name of the SheetIndex that the new SheetIndexModel will sub-model.
* @returns The Id of the newly inserted SheetIndexModel.
* @throws [[IModelError]] if there is an insert problem.
*/
static insert(iModelDb, parentSubjectId, name) {
const sheetIndex = {
classFullName: Element_1.SheetIndexPartition.classFullName,
model: core_common_1.IModel.repositoryModelId,
parent: new NavigationRelationship_1.SubjectOwnsPartitionElements(parentSubjectId),
code: Element_1.SheetIndexPartition.createCode(iModelDb, parentSubjectId, name),
};
const partitionId = iModelDb.elements.insertElement(sheetIndex);
return iModelDb.models.insertModel({
classFullName: this.classFullName,
modeledElement: { id: partitionId },
});
}
}
exports.SheetIndexModel = SheetIndexModel;
/** A container for persisting Information Record Elements
* @see [[InformationRecordPartition]]
* @public @preview
*/
class InformationRecordModel extends InformationModel {
static get className() { return "InformationRecordModel"; }
/** Insert a InformationRecordPartition and a InformationRecordModel that sub-models it.
* @param iModelDb Insert into this iModel
* @param parentSubjectId The InformationRecordPartition will be inserted as a child of this Subject element.
* @param name The name of the InformationRecordPartition that the new InformationRecordModel will sub-model.
* @returns The Id of the newly inserted InformationRecordModel.
* @throws [[IModelError]] if there is an insert problem.
*/
static insert(iModelDb, parentSubjectId, name) {
const partitionProps = {
classFullName: Element_1.InformationRecordPartition.classFullName,
model: core_common_1.IModel.repositoryModelId,
parent: new NavigationRelationship_1.SubjectOwnsPartitionElements(parentSubjectId),
code: Element_1.InformationRecordPartition.createCode(iModelDb, parentSubjectId, name),
};
const partitionId = iModelDb.elements.insertElement(partitionProps);
return iModelDb.models.insertModel({
classFullName: this.classFullName,
modeledElement: { id: partitionId },
});
}
}
exports.InformationRecordModel = InformationRecordModel;
/** A container for persisting definition elements.
* @see [[DefinitionPartition]]
* @public @preview
*/
class DefinitionModel extends InformationModel {
static get className() { return "DefinitionModel"; }
/** Insert a DefinitionPartition and a DefinitionModel that sub-models it.
* @param iModelDb Insert into this iModel
* @param parentSubjectId The DefinitionPartition will be inserted as a child of this Subject element.
* @param name The name of the DefinitionPartition that the new DefinitionModel will sub-model.
* @returns The Id of the newly inserted DefinitionModel.
* @throws [[IModelError]] if there is an insert problem.
*/
static insert(iModelDb, parentSubjectId, name) {
const partitionProps = {
classFullName: Element_1.DefinitionPartition.classFullName,
model: core_common_1.IModel.repositoryModelId,
parent: new NavigationRelationship_1.SubjectOwnsPartitionElements(parentSubjectId),
code: Element_1.DefinitionPartition.createCode(iModelDb, parentSubjectId, name),
};
const partitionId = iModelDb.elements.insertElement(partitionProps);
return iModelDb.models.insertModel({
classFullName: this.classFullName,
modeledElement: { id: partitionId },
});
}
}
exports.DefinitionModel = DefinitionModel;
/** The singleton container of repository-related information elements.
* @public @preview
*/
class RepositoryModel extends DefinitionModel {
static get className() { return "RepositoryModel"; }
}
exports.RepositoryModel = RepositoryModel;
/** Contains a list of document elements.
* @see [[DocumentPartition]]
* @public @preview
*/
class DocumentListModel extends InformationModel {
static get className() { return "DocumentListModel"; }
/** Insert a DocumentPartition and a DocumentListModel that sub-models it.
* @param iModelDb Insert into this iModel
* @param parentSubjectId The DocumentPartition will be inserted as a child of this Subject element.
* @param name The name of the DocumentPartition that the new DocumentListModel will sub-model.
* @returns The Id of the newly inserted DocumentPartition and DocumentListModel (same value)
* @throws [[IModelError]] if there is an insert problem.
*/
static insert(iModelDb, parentSubjectId, name) {
const partitionProps = {
classFullName: Element_1.DocumentPartition.classFullName,
model: core_common_1.IModel.repositoryModelId,
parent: new NavigationRelationship_1.SubjectOwnsPartitionElements(parentSubjectId),
code: Element_1.DocumentPartition.createCode(iModelDb, parentSubjectId, name),
};
const partitionId = iModelDb.elements.insertElement(partitionProps);
return iModelDb.models.insertModel({
classFullName: this.classFullName,
modeledElement: { id: partitionId },
});
}
}
exports.DocumentListModel = DocumentListModel;
/** A container for persisting link elements.
* @see [[LinkPartition]]
* @public @preview
*/
class LinkModel extends InformationModel {
static get className() { return "LinkModel"; }
}
exports.LinkModel = LinkModel;
/** The singleton container for repository-specific definition elements.
* @public @preview
*/
class DictionaryModel extends DefinitionModel {
static get className() { return "DictionaryModel"; }
}
exports.DictionaryModel = DictionaryModel;
/** Obtains and displays multi-resolution tiled raster organized according to the WebMercator tiling system.
* @public @preview
*/
class WebMercatorModel extends SpatialModel {
static get className() { return "WebMercatorModel"; }
}
exports.WebMercatorModel = WebMercatorModel;
//# sourceMappingURL=Model.js.map