@itwin/core-backend
Version:
iTwin.js backend components
250 lines • 10.8 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.
*--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.createUpdateContext = createUpdateContext;
exports.updateField = updateField;
exports.updateFields = updateFields;
exports.updateElementFields = updateElementFields;
exports.updateAllFields = updateAllFields;
const core_common_1 = require("@itwin/core-common");
const core_bentley_1 = require("@itwin/core-bentley");
const BackendLoggerCategory_1 = require("../../BackendLoggerCategory");
const ElementDrivesTextAnnotation_1 = require("../../annotations/ElementDrivesTextAnnotation");
const ecschema_metadata_1 = require("@itwin/ecschema-metadata");
// Resolve the raw primitive value of the property that a field points to.
function getFieldPropertyValue(field, iModel) {
const host = field.propertyHost;
const schemaItem = iModel.schemaContext.getSchemaItemSync(host.schemaName, host.className);
if (!ecschema_metadata_1.EntityClass.isEntityClass(schemaItem)) {
return undefined;
}
let ecClass = schemaItem;
const { propertyName, accessors } = field.propertyPath;
let ecProp = ecClass.getPropertySync(propertyName);
if (!ecProp) {
return undefined;
}
const isAspect = ecClass.isSync("ElementAspect", "BisCore");
const where = ` WHERE ${isAspect ? "Element.Id" : "ECInstanceId"}=${host.elementId}`;
// eslint-disable-next-line @typescript-eslint/no-deprecated
let curValue = iModel.withPreparedStatement(`SELECT ${propertyName} FROM ${host.schemaName}.${host.className} ${where}`, (stmt) => {
if (stmt.step() !== core_bentley_1.DbResult.BE_SQLITE_ROW) {
return undefined;
}
const rootValue = stmt.getValue(0);
if (undefined === rootValue || rootValue.isNull) {
return undefined;
}
switch (rootValue.columnInfo.getType()) {
case core_common_1.ECSqlValueType.Blob:
return { primitive: rootValue.getBlob() };
case core_common_1.ECSqlValueType.Boolean:
return { primitive: rootValue.getBoolean() };
case core_common_1.ECSqlValueType.DateTime:
return { primitive: new Date(rootValue.getDateTime()) };
case core_common_1.ECSqlValueType.Double:
return { primitive: rootValue.getDouble() };
case core_common_1.ECSqlValueType.Guid:
return { primitive: rootValue.getGuid() };
case core_common_1.ECSqlValueType.Int:
case core_common_1.ECSqlValueType.Int64:
return { primitive: rootValue.getInteger() };
case core_common_1.ECSqlValueType.Point2d:
return { primitive: rootValue.getXAndY() };
case core_common_1.ECSqlValueType.Point3d:
return { primitive: rootValue.getXYAndZ() };
case core_common_1.ECSqlValueType.String:
return { primitive: rootValue.getString() };
case core_common_1.ECSqlValueType.Struct: {
ecProp = (0, core_bentley_1.expectDefined)(ecProp);
(0, core_bentley_1.assert)(ecProp.isStruct());
ecClass = ecProp.structClass;
return { struct: rootValue.getStruct() };
}
case core_common_1.ECSqlValueType.PrimitiveArray: {
return { primitiveArray: rootValue.getArray() };
}
case core_common_1.ECSqlValueType.StructArray: {
return { structArray: rootValue.getArray() };
}
// Unsupported:
// case ECSqlValueType.Geometry:
// case ECSqlValueType.Navigation:
// case ECSqlValueType.Id:
}
return undefined;
});
if (undefined === curValue) {
return undefined;
}
if (accessors) {
for (const accessor of accessors) {
if (undefined !== curValue.primitive) {
// Can't index into a primitive.
return undefined;
}
if (typeof accessor === "number") {
const array = curValue.primitiveArray ?? curValue.structArray;
if (!array) {
return undefined;
}
const index = accessor < 0 ? (array.length + accessor) : accessor;
const item = array[index];
if (undefined === item) {
return undefined;
}
else if (curValue.primitiveArray) {
curValue = { primitive: curValue.primitiveArray[index] };
}
else {
(0, core_bentley_1.assert)(undefined !== curValue.structArray);
(0, core_bentley_1.assert)(ecProp instanceof ecschema_metadata_1.StructArrayProperty);
ecClass = ecProp.structClass;
curValue = { struct: curValue.structArray[index] };
}
}
else {
if (undefined === curValue.struct) {
return undefined;
}
const item = curValue.struct[accessor];
if (undefined === item) {
return undefined;
}
ecProp = ecClass.getPropertySync(accessor);
if (!ecProp) {
return undefined;
}
if (ecProp.isArray()) {
curValue = ecProp.isStruct() ? { structArray: item } : { primitiveArray: item };
}
else if (ecProp.isStruct()) {
ecClass = ecProp.structClass;
curValue = { struct: item };
}
else if (ecProp.isPrimitive()) {
curValue = { primitive: item };
}
else {
return undefined;
}
}
}
}
const propertyType = determineFieldPropertyType(ecProp);
if (!propertyType) {
return undefined;
}
// The ultimate result must be a primitive value.
if (undefined === curValue.primitive) {
return undefined;
}
return { value: curValue.primitive, type: propertyType };
}
function determineFieldPropertyType(prop) {
if (prop.isEnumeration()) {
switch (prop.propertyType) {
case ecschema_metadata_1.PropertyType.Integer_Enumeration:
return "int-enum";
case ecschema_metadata_1.PropertyType.String_Enumeration:
return "string-enum";
default:
return undefined;
}
}
if (prop.isPrimitive()) {
switch (prop.primitiveType) {
case ecschema_metadata_1.PrimitiveType.Boolean:
return "boolean";
case ecschema_metadata_1.PrimitiveType.String:
return prop.extendedTypeName === "DateTime" ? "datetime" : "string";
case ecschema_metadata_1.PrimitiveType.DateTime:
return "datetime";
case ecschema_metadata_1.PrimitiveType.Double:
case ecschema_metadata_1.PrimitiveType.Long:
return "quantity";
case ecschema_metadata_1.PrimitiveType.Point2d:
case ecschema_metadata_1.PrimitiveType.Point3d:
return "coordinate";
case ecschema_metadata_1.PrimitiveType.Binary:
return prop.extendedTypeName === "BeGuid" ? "string" : undefined;
case ecschema_metadata_1.PrimitiveType.Integer:
case ecschema_metadata_1.PrimitiveType.Long:
return "string";
default:
return undefined;
}
}
return undefined;
}
function createUpdateContext(hostElementId, iModel, deleted) {
return {
hostElementId,
getProperty: deleted ? () => undefined : (field) => getFieldPropertyValue(field, iModel),
};
}
// Recompute the display value of a single field, return false if it couldn't be evaluated.
function updateField(field, context) {
if (context.hostElementId && context.hostElementId !== field.propertyHost.elementId) {
return false;
}
let newContent;
try {
const propValue = context.getProperty(field);
if (undefined !== propValue) {
newContent = (0, core_common_1.formatFieldValue)(propValue, field.formatOptions);
}
}
catch (err) {
core_bentley_1.Logger.logException(BackendLoggerCategory_1.BackendLoggerCategory.IModelDb, err);
}
newContent = newContent ?? core_common_1.FieldRun.invalidContentIndicator;
if (newContent === field.cachedContent) {
return false;
}
field.setCachedContent(newContent);
return true;
}
// Re-evaluates the display strings for all fields that target the element specified by `context` and returns the number
// of fields whose display strings changed as a result.
function updateFields(textBlock, context) {
let numUpdated = 0;
for (const { child } of (0, core_common_1.traverseTextBlockComponent)(textBlock)) {
if (child.type === "field" && updateField(child, context)) {
++numUpdated;
}
}
return numUpdated;
}
function doUpdateFields(annotationId, sourceId, iModel, deleted) {
try {
const target = iModel.elements.getElement(annotationId);
if ((0, ElementDrivesTextAnnotation_1.isITextAnnotation)(target)) {
const context = createUpdateContext(sourceId, iModel, deleted);
const updatedBlocks = [];
for (const block of target.getTextBlocks()) {
if (updateFields(block.textBlock, context)) {
updatedBlocks.push(block);
}
}
if (updatedBlocks.length > 0) {
target.updateTextBlocks(updatedBlocks);
target.update();
}
}
}
catch (err) {
core_bentley_1.Logger.logException(BackendLoggerCategory_1.BackendLoggerCategory.IModelDb, err);
}
}
// Invoked by ElementDrivesTextAnnotation to update fields in target element when source element changes or is deleted.
function updateElementFields(props, iModel, deleted) {
doUpdateFields(props.targetId, props.sourceId, iModel, deleted);
}
function updateAllFields(annotationElementId, iModel) {
doUpdateFields(annotationElementId, undefined, iModel, false);
}
//# sourceMappingURL=fields.js.map