@itwin/core-backend
Version:
iTwin.js backend components
377 lines • 24.7 kB
JavaScript
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
import { Id64 } from "@itwin/core-bentley";
import { BisCodeSpec, CodeScopeSpec, CodeSpec, EditTxnError } from "@itwin/core-common";
import { EditTxn, withEditTxn } from "../../EditTxn";
import { SnapshotDb } from "../../IModelDb";
import { ExtensiveTestScenario, IModelTestUtils } from "../IModelTestUtils";
import { DocumentPartition, Sheet } from "../../Element";
import { expect } from "chai";
import { DocumentListModel, SheetIndexModel, SheetModel } from "../../Model";
import { ElementOwnsChildElements, SheetIndexFolderOwnsEntries, SheetIndexOwnsEntries, SheetIndexReferenceRefersToSheetIndex, SheetReferenceRefersToSheet } from "../../NavigationRelationship";
import { SheetIndex, SheetIndexFolder, SheetIndexReference, SheetReference } from "../../SheetIndex";
const getOrCreateDocumentList = (txn) => {
const documentListName = "SheetList";
const ids = txn.iModel.queryEntityIds({ from: DocumentPartition.classFullName, where: `CodeValue = '${documentListName}'` });
if (ids.size === 1)
return ids.values().next().value;
const subjectId = txn.iModel.elements.getRootSubject().id;
return DocumentListModel.insert(txn, subjectId, documentListName);
};
const insertSheet = (txn, sheetName) => {
const modelId = getOrCreateDocumentList(txn);
const sheetElementProps = {
height: 42,
width: 42,
scale: 42,
classFullName: Sheet.classFullName,
code: Sheet.createCode(txn.iModel, modelId, sheetName),
model: modelId,
};
const sheetElementId = txn.insertElement(sheetElementProps);
return txn.insertModel({
classFullName: SheetModel.classFullName,
modeledElement: { id: sheetElementId, relClassName: "BisCore:ModelModelsElement" },
});
};
const insertCodeSpec = (txn) => {
const indexSpec = CodeSpec.create(txn.iModel, BisCodeSpec.sheetIndex, CodeScopeSpec.Type.Model);
txn.iModel.codeSpecs.insert(txn, indexSpec);
const entrySpec = CodeSpec.create(txn.iModel, BisCodeSpec.sheetIndexEntry, CodeScopeSpec.Type.ParentElement);
txn.iModel.codeSpecs.insert(txn, entrySpec);
};
describe("SheetIndex", () => {
let iModel;
beforeEach(async () => {
const iModelFile = IModelTestUtils.prepareOutputFile("IModel", "TestSheetIndex.bim");
const iModelDb = SnapshotDb.createEmpty(iModelFile, { rootSubject: { name: "SheetIndex" } });
await ExtensiveTestScenario.prepareDb(iModelDb);
await ExtensiveTestScenario.populateDb(iModelDb);
iModel = iModelDb;
withEditTxn(iModel, (txn) => insertCodeSpec(txn));
});
afterEach(() => {
iModel.close();
});
it("SheetIndexModel Should insert", () => {
withEditTxn(iModel, (txn) => {
const subjectId = iModel.elements.getRootSubject().id;
const modelId = SheetIndexModel.insert(txn, subjectId, "testSheetIndex");
expect(Id64.isValidId64(modelId)).to.be.true;
});
});
it("SheetIndex Should insert", () => {
withEditTxn(iModel, (txn) => {
const subjectId = iModel.elements.getRootSubject().id;
const modelId = SheetIndexModel.insert(txn, subjectId, "TestSheetIndexModel");
expect(Id64.isValidId64(modelId)).to.be.true;
const sheetIndex = SheetIndex.insert(txn, modelId, "TestSheetIndex");
expect(Id64.isValidId64(sheetIndex)).to.be.true;
});
});
describe("Update", () => {
it("Priority", () => {
withEditTxn(iModel, (txn) => {
const subjectId = iModel.elements.getRootSubject().id;
const modelId = SheetIndexModel.insert(txn, subjectId, "TestSheetIndexModel");
expect(Id64.isValidId64(modelId)).to.be.true;
const sheetIndex1Id = SheetIndex.insert(txn, modelId, "TestSheetIndex");
expect(Id64.isValidId64(sheetIndex1Id)).to.be.true;
const folderId = SheetIndexFolder.insert(txn, { sheetIndexModelId: modelId, parentId: sheetIndex1Id, name: "TestFolder", priority: 1 });
expect(Id64.isValidId64(folderId)).to.be.true;
const folder = iModel.elements.tryGetElement(folderId);
expect(folder).to.not.be.undefined;
expect(folder?.entryPriority).equals(1);
folder.entryPriority = 0;
folder.update(txn);
const folderPostUpdate = iModel.elements.tryGetElement(folderId);
expect(folderPostUpdate?.entryPriority).equals(0);
});
});
it("Parent", () => {
withEditTxn(iModel, (txn) => {
const subjectId = iModel.elements.getRootSubject().id;
const modelId = SheetIndexModel.insert(txn, subjectId, "TestSheetIndexModel");
expect(Id64.isValidId64(modelId)).to.be.true;
const sheetIndex1Id = SheetIndex.insert(txn, modelId, "TestSheetIndex-1");
expect(Id64.isValidId64(sheetIndex1Id)).to.be.true;
const sheetIndex2Id = SheetIndex.insert(txn, modelId, "TestSheetIndex-2");
expect(Id64.isValidId64(sheetIndex2Id)).to.be.true;
const folderId = SheetIndexFolder.insert(txn, { sheetIndexModelId: modelId, parentId: sheetIndex1Id, name: "TestFolder", priority: 1 });
expect(Id64.isValidId64(folderId)).to.be.true;
const folder = iModel.elements.tryGetElement(folderId);
expect(folder).to.not.be.undefined;
const parentRel11 = iModel.relationships.tryGetInstanceProps(ElementOwnsChildElements.classFullName, { sourceId: sheetIndex1Id, targetId: folderId });
expect(parentRel11).to.not.be.undefined;
folder.parent = new SheetIndexOwnsEntries(sheetIndex2Id);
folder.update(txn);
const parentRel12 = iModel.relationships.tryGetInstanceProps(ElementOwnsChildElements.classFullName, { sourceId: sheetIndex1Id, targetId: folderId });
expect(parentRel12).to.be.undefined;
const parentRel22 = iModel.relationships.tryGetInstanceProps(ElementOwnsChildElements.classFullName, { sourceId: sheetIndex2Id, targetId: folderId });
expect(parentRel22).to.not.be.undefined;
});
});
it("Sheet Reference", () => {
withEditTxn(iModel, (txn) => {
const sheet1Id = insertSheet(txn, "sheet-1");
const sheet2Id = insertSheet(txn, "sheet-2");
const subjectId = iModel.elements.getRootSubject().id;
const modelId = SheetIndexModel.insert(txn, subjectId, "TestSheetIndexModel");
expect(Id64.isValidId64(modelId)).to.be.true;
const sheetIndexId = SheetIndex.insert(txn, modelId, "TestSheetIndex");
expect(Id64.isValidId64(sheetIndexId)).to.be.true;
const sheetRefId = SheetReference.insert(txn, { sheetIndexModelId: modelId, parentId: sheetIndexId, name: "TestSheetReference", priority: 1 });
expect(Id64.isValidId64(sheetRefId)).to.be.true;
const sheetRef = iModel.elements.tryGetElement(sheetRefId);
expect(sheetRef).to.not.be.undefined;
expect(sheetRef.sheet).to.be.undefined;
sheetRef.sheet = new SheetReferenceRefersToSheet(sheet1Id);
sheetRef.update(txn);
const refersRel11 = iModel.relationships.tryGetInstanceProps(SheetReferenceRefersToSheet.classFullName, { sourceId: sheetRefId, targetId: sheet1Id });
expect(refersRel11).to.not.be.undefined;
const parentRel12 = iModel.relationships.tryGetInstanceProps(SheetReferenceRefersToSheet.classFullName, { sourceId: sheetRefId, targetId: sheet2Id });
expect(parentRel12).to.be.undefined;
sheetRef.sheet = new SheetReferenceRefersToSheet(sheet2Id);
sheetRef.update(txn);
const refersRel21 = iModel.relationships.tryGetInstanceProps(SheetReferenceRefersToSheet.classFullName, { sourceId: sheetRefId, targetId: sheet1Id });
expect(refersRel21).to.be.undefined;
const parentRel22 = iModel.relationships.tryGetInstanceProps(SheetReferenceRefersToSheet.classFullName, { sourceId: sheetRefId, targetId: sheet2Id });
expect(parentRel22).to.not.be.undefined;
});
});
it("Sheet Index Reference", () => {
withEditTxn(iModel, (txn) => {
const subjectId = iModel.elements.getRootSubject().id;
const modelId = SheetIndexModel.insert(txn, subjectId, "TestSheetIndexModel");
expect(Id64.isValidId64(modelId)).to.be.true;
const sheetIndex1Id = SheetIndex.insert(txn, modelId, "TestSheetIndex-1");
expect(Id64.isValidId64(sheetIndex1Id)).to.be.true;
const sheetIndex2Id = SheetIndex.insert(txn, modelId, "TestSheetIndex-2");
expect(Id64.isValidId64(sheetIndex2Id)).to.be.true;
const sheetIndex3Id = SheetIndex.insert(txn, modelId, "TestSheetIndex-3");
expect(Id64.isValidId64(sheetIndex3Id)).to.be.true;
const sheetIndexRefId = SheetIndexReference.insert(txn, { sheetIndexModelId: modelId, parentId: sheetIndex1Id, name: "TestSheetReference", priority: 1 });
expect(Id64.isValidId64(sheetIndexRefId)).to.be.true;
const sheetIndexRef = iModel.elements.tryGetElement(sheetIndexRefId);
expect(sheetIndexRef).to.not.be.undefined;
expect(sheetIndexRef.sheetIndex).to.be.undefined;
sheetIndexRef.sheetIndex = new SheetIndexReferenceRefersToSheetIndex(sheetIndex2Id);
sheetIndexRef.update(txn);
const parentRel11 = iModel.relationships.tryGetInstanceProps(SheetIndexReferenceRefersToSheetIndex.classFullName, { sourceId: sheetIndexRefId, targetId: sheetIndex2Id });
expect(parentRel11).to.not.be.undefined;
sheetIndexRef.sheetIndex = new SheetIndexReferenceRefersToSheetIndex(sheetIndex3Id);
sheetIndexRef.update(txn);
const refersRel21 = iModel.relationships.tryGetInstanceProps(SheetIndexReferenceRefersToSheetIndex.classFullName, { sourceId: sheetIndexRefId, targetId: sheetIndex2Id });
expect(refersRel21).to.be.undefined;
const parentRel22 = iModel.relationships.tryGetInstanceProps(SheetIndexReferenceRefersToSheetIndex.classFullName, { sourceId: sheetIndexRefId, targetId: sheetIndex3Id });
expect(parentRel22).to.not.be.undefined;
});
});
});
describe("SheetIndexFolder", () => {
it("Should insert", () => {
withEditTxn(iModel, (txn) => {
const subjectId = iModel.elements.getRootSubject().id;
const modelId = SheetIndexModel.insert(txn, subjectId, "TestSheetIndexModel");
expect(Id64.isValidId64(modelId)).to.be.true;
const sheetIndexId = SheetIndex.insert(txn, modelId, "TestSheetIndex");
expect(Id64.isValidId64(sheetIndexId)).to.be.true;
const folderId = SheetIndexFolder.insert(txn, { sheetIndexModelId: modelId, parentId: sheetIndexId, name: "TestFolder-1", priority: 1 });
expect(Id64.isValidId64(folderId)).to.be.true;
const folder = iModel.elements.tryGetElement(folderId);
expect(folder).to.not.be.undefined;
const relationship = iModel.relationships.tryGetInstanceProps(ElementOwnsChildElements.classFullName, { sourceId: sheetIndexId, targetId: folderId });
expect(relationship).to.not.be.undefined;
expect(relationship?.classFullName).equals(SheetIndexOwnsEntries.classFullName);
expect(folder?.parent?.id).equals(sheetIndexId);
});
});
it("Should not insert SheetIndexFolder with the same name", () => {
withEditTxn(iModel, (txn) => {
const subjectId = iModel.elements.getRootSubject().id;
const modelId = SheetIndexModel.insert(txn, subjectId, "TestSheetIndexModel");
expect(Id64.isValidId64(modelId)).to.be.true;
const sheetIndex = SheetIndex.insert(txn, modelId, "TestSheetIndex");
expect(Id64.isValidId64(sheetIndex)).to.be.true;
const folder = SheetIndexFolder.insert(txn, { sheetIndexModelId: modelId, parentId: sheetIndex, name: "TestFolder", priority: 1 });
expect(Id64.isValidId64(folder)).to.be.true;
const failInsert = () => SheetIndexFolder.insert(txn, { sheetIndexModelId: modelId, parentId: sheetIndex, name: "TestFolder", priority: 0 });
expect(failInsert).throws();
});
});
it("Should have children", () => {
withEditTxn(iModel, (txn) => {
const subjectId = iModel.elements.getRootSubject().id;
const modelId = SheetIndexModel.insert(txn, subjectId, "TestSheetIndexModel");
expect(Id64.isValidId64(modelId)).to.be.true;
const sheetIndexId = SheetIndex.insert(txn, modelId, "TestSheetIndex");
expect(Id64.isValidId64(sheetIndexId)).to.be.true;
const folder1Id = SheetIndexFolder.insert(txn, { sheetIndexModelId: modelId, parentId: sheetIndexId, name: "TestFolder-1", priority: 1 });
expect(Id64.isValidId64(folder1Id)).to.be.true;
const folder2Id = SheetIndexFolder.insert(txn, { sheetIndexModelId: modelId, parentId: folder1Id, name: "TestFolder-2", priority: 1 });
expect(Id64.isValidId64(folder2Id)).to.be.true;
const folder2 = iModel.elements.tryGetElement(folder2Id);
expect(folder2).to.not.be.undefined;
const relationship = iModel.relationships.tryGetInstanceProps(ElementOwnsChildElements.classFullName, { sourceId: folder1Id, targetId: folder2Id });
expect(relationship).to.not.be.undefined;
expect(relationship?.classFullName).equals(SheetIndexFolderOwnsEntries.classFullName);
expect(folder2?.parent?.id).equals(folder1Id);
});
});
});
describe("SheetReferences", () => {
it("Should not insert SheetReferences with the same name", () => {
withEditTxn(iModel, (txn) => {
const subjectId = iModel.elements.getRootSubject().id;
const modelId = SheetIndexModel.insert(txn, subjectId, "TestSheetIndexModel");
expect(Id64.isValidId64(modelId)).to.be.true;
const sheetIndex = SheetIndex.insert(txn, modelId, "TestSheetIndex");
expect(Id64.isValidId64(sheetIndex)).to.be.true;
const sheetRef1 = SheetReference.insert(txn, { sheetIndexModelId: modelId, parentId: sheetIndex, name: "TestSheetRef", priority: 1 });
expect(Id64.isValidId64(sheetRef1)).to.be.true;
const failInsert = () => SheetReference.insert(txn, { sheetIndexModelId: modelId, parentId: sheetIndex, name: "TestSheetRef", priority: 0 });
expect(failInsert).throws();
});
});
it("Should insert SheetReferences without a Sheet", () => {
withEditTxn(iModel, (txn) => {
const subjectId = iModel.elements.getRootSubject().id;
const modelId = SheetIndexModel.insert(txn, subjectId, "TestSheetIndexModel");
expect(Id64.isValidId64(modelId)).to.be.true;
const sheetIndex = SheetIndex.insert(txn, modelId, "TestSheetIndex");
expect(Id64.isValidId64(sheetIndex)).to.be.true;
const sheetRef = SheetReference.insert(txn, { sheetIndexModelId: modelId, parentId: sheetIndex, name: "TestSheetRef", priority: 1 });
expect(Id64.isValidId64(sheetRef)).to.be.true;
});
});
it("Should insert and with a Sheet", () => {
withEditTxn(iModel, (txn) => {
const sheetId = insertSheet(txn, "sheet-1");
const subjectId = iModel.elements.getRootSubject().id;
const modelId = SheetIndexModel.insert(txn, subjectId, "TestSheetIndexModel");
expect(Id64.isValidId64(modelId)).to.be.true;
const sheetIndex = SheetIndex.insert(txn, modelId, "TestSheetIndex");
expect(Id64.isValidId64(sheetIndex)).to.be.true;
const sheetRefId = SheetReference.insert(txn, { sheetIndexModelId: modelId, parentId: sheetIndex, name: "TestSheetRef", priority: 1, sheetId });
expect(Id64.isValidId64(sheetRefId)).to.be.true;
const ref = iModel.elements.tryGetElement(sheetRefId);
expect(ref).to.not.be.undefined;
const relationship = iModel.relationships.tryGetInstanceProps(SheetReferenceRefersToSheet.classFullName, { sourceId: sheetRefId, targetId: sheetId });
expect(relationship).to.not.be.undefined;
expect(relationship?.classFullName).equals(SheetReferenceRefersToSheet.classFullName);
expect(ref?.sheet?.id).equals(sheetId);
});
});
it("supports deprecated SheetReference.insert overload when implicit writes are allowed", () => {
const previousEnforcement = EditTxn.implicitWriteEnforcement;
EditTxn.implicitWriteEnforcement = "allow";
try {
withEditTxn(iModel, (txn) => {
const sheetId = insertSheet(txn, "legacy-sheet");
const subjectId = iModel.elements.getRootSubject().id;
const modelId = SheetIndexModel.insert(txn, subjectId, "LegacySheetRefModel");
const sheetIndex = SheetIndex.insert(txn, modelId, "LegacySheetIndex");
// eslint-disable-next-line @typescript-eslint/no-deprecated
const sheetRefId = SheetReference.insert({
iModelDb: iModel,
sheetIndexModelId: modelId,
parentId: sheetIndex,
name: "LegacySheetRef",
priority: 1,
sheetId,
});
expect(Id64.isValidId64(sheetRefId)).to.be.true;
const ref = iModel.elements.tryGetElement(sheetRefId);
expect(ref?.sheet?.id).to.equal(sheetId);
});
}
finally {
EditTxn.implicitWriteEnforcement = previousEnforcement;
}
});
it("rejects deprecated SheetReference.insert overload when implicit writes are disallowed", () => {
const previousEnforcement = EditTxn.implicitWriteEnforcement;
EditTxn.implicitWriteEnforcement = "throw";
try {
withEditTxn(iModel, (txn) => {
const sheetId = insertSheet(txn, "legacy-throw-sheet");
const subjectId = iModel.elements.getRootSubject().id;
const modelId = SheetIndexModel.insert(txn, subjectId, "LegacyThrowSheetRefModel");
const sheetIndex = SheetIndex.insert(txn, modelId, "LegacyThrowSheetIndex");
// eslint-disable-next-line @typescript-eslint/no-deprecated
expect(() => SheetReference.insert({
iModelDb: iModel,
sheetIndexModelId: modelId,
parentId: sheetIndex,
name: "LegacyThrowSheetRef",
priority: 1,
sheetId,
})).to.throw().that.satisfies((error) => EditTxnError.isError(error, "implicit-txn-write-disallowed"));
});
}
finally {
EditTxn.implicitWriteEnforcement = previousEnforcement;
}
});
it.skip("Should not insert with the same Sheet twice", () => {
withEditTxn(iModel, (txn) => {
const sheetId = insertSheet(txn, "sheet-1");
const subjectId = iModel.elements.getRootSubject().id;
const modelId = SheetIndexModel.insert(txn, subjectId, "TestSheetIndexModel");
expect(Id64.isValidId64(modelId)).to.be.true;
const sheetIndex = SheetIndex.insert(txn, modelId, "TestSheetIndex");
SheetReference.insert(txn, { sheetIndexModelId: modelId, parentId: sheetIndex, name: "TestSheetRef-1", priority: 1, sheetId });
const sameIndex = () => SheetReference.insert(txn, { sheetIndexModelId: modelId, parentId: sheetIndex, name: "TestSheetRef-2", priority: 2, sheetId });
expect(sameIndex).throws();
});
});
});
describe("SheetIndexReferences", () => {
it("Should not insert SheetIndexReferences with the same name", () => {
withEditTxn(iModel, (txn) => {
const subjectId = iModel.elements.getRootSubject().id;
const modelId = SheetIndexModel.insert(txn, subjectId, "TestSheetIndexModel");
expect(Id64.isValidId64(modelId)).to.be.true;
const sheetIndex = SheetIndex.insert(txn, modelId, "TestSheetIndex");
expect(Id64.isValidId64(sheetIndex)).to.be.true;
const sheetIndexRef = SheetIndexReference.insert(txn, { sheetIndexModelId: modelId, parentId: sheetIndex, name: "TestSheetIndexRef", priority: 1 });
expect(Id64.isValidId64(sheetIndexRef)).to.be.true;
const failInsert = () => SheetIndexReference.insert(txn, { sheetIndexModelId: modelId, parentId: sheetIndex, name: "TestSheetIndexRef", priority: 0 });
expect(failInsert).throws();
});
});
it("Should insert SheetIndexReferences without a SheetIndexRef", () => {
withEditTxn(iModel, (txn) => {
const subjectId = iModel.elements.getRootSubject().id;
const modelId = SheetIndexModel.insert(txn, subjectId, "TestSheetIndexModel");
expect(Id64.isValidId64(modelId)).to.be.true;
const sheetIndex1Id = SheetIndex.insert(txn, modelId, "TestSheetIndex");
expect(Id64.isValidId64(sheetIndex1Id)).to.be.true;
const sheetRef = SheetIndexReference.insert(txn, { sheetIndexModelId: modelId, parentId: sheetIndex1Id, name: "TestSheetIndexRef", priority: 1 });
expect(Id64.isValidId64(sheetRef)).to.be.true;
});
});
it("Should insert and with a SheetIndexRef", () => {
withEditTxn(iModel, (txn) => {
const subjectId = iModel.elements.getRootSubject().id;
const modelId = SheetIndexModel.insert(txn, subjectId, "TestSheetIndexModel");
expect(Id64.isValidId64(modelId)).to.be.true;
const sheetIndex1Id = SheetIndex.insert(txn, modelId, "TestSheetIndex-1");
expect(Id64.isValidId64(sheetIndex1Id)).to.be.true;
const sheetIndex2Id = SheetIndex.insert(txn, modelId, "TestSheetIndex-2");
expect(Id64.isValidId64(sheetIndex1Id)).to.be.true;
const sheetIndexRefId = SheetIndexReference.insert(txn, { sheetIndexModelId: modelId, parentId: sheetIndex1Id, name: "TestSheetRef", priority: 1, sheetIndexId: sheetIndex2Id });
expect(Id64.isValidId64(sheetIndexRefId)).to.be.true;
const ref = iModel.elements.tryGetElement(sheetIndexRefId);
expect(ref).to.not.be.undefined;
const relationship = iModel.relationships.tryGetInstanceProps(SheetIndexReferenceRefersToSheetIndex.classFullName, { sourceId: sheetIndexRefId, targetId: sheetIndex2Id });
expect(relationship).to.not.be.undefined;
expect(relationship?.classFullName).equals(SheetIndexReferenceRefersToSheetIndex.classFullName);
expect(ref?.sheetIndex?.id).equals(sheetIndex2Id);
});
});
});
});
//# sourceMappingURL=SheetIndex.test.js.map