UNPKG

@itwin/imodels-client-management

Version:

iModels API client wrapper for applications that manage iModels.

433 lines 21.9 kB
/*--------------------------------------------------------------------------------------------- * Copyright (c) Bentley Systems, Incorporated. All rights reserved. * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ import { EntityListIteratorImpl, IModelsErrorImpl, OperationsBase, UtilityFunctions, } from "../../base/internal"; import { IModelCreationState, IModelState, IModelsErrorCode, PreferReturn, } from "../../base/types"; import { Constants } from "../../Constants"; import { assertStringHeaderValue } from "../SharedFunctions"; export class IModelOperations extends OperationsBase { _iModelsClient; constructor(options, _iModelsClient) { super(options); this._iModelsClient = _iModelsClient; } /** * Gets iModels for a specific iTwin. This method returns iModels in their minimal representation. The returned iterator * internally queries entities in pages. Wraps the {@link https://developer.bentley.com/apis/imodels-v2/operations/get-itwin-imodels/ Get iTwin iModels} * operation from iModels API. * @param {GetIModelListParams} params parameters for this operation. See {@link GetIModelListParams}. * @returns {EntityListIterator<MinimalIModel>} iterator for iModel list. See {@link EntityListIterator}, {@link MinimalIModel}. */ getMinimalList(params) { return new EntityListIteratorImpl(async () => this.getEntityCollectionPage({ authorization: params.authorization, url: this._options.urlFormatter.getIModelListUrl({ urlParams: params.urlParams, }), preferReturn: PreferReturn.Minimal, entityCollectionAccessor: (response) => response.body.iModels, headers: params.headers, })); } /** * Gets iModels for a specific iTwin. This method returns iModels in their full representation. The returned iterator * internally queries entities in pages. Wraps the {@link https://developer.bentley.com/apis/imodels-v2/operations/get-itwin-imodels/ Get iTwin iModels} * operation from iModels API. * @param {GetIModelListParams} params parameters for this operation. See {@link GetIModelListParams}. * @returns {EntityListIterator<IModel>} iterator for iModel list. See {@link EntityListIterator}, {@link IModel}. */ getRepresentationList(params) { const entityCollectionAccessor = (response) => { const iModels = response.body.iModels; const mappedIModels = iModels.map((iModel) => this.appendRelatedEntityCallbacks(params.authorization, iModel, params.headers)); return mappedIModels; }; return new EntityListIteratorImpl(async () => this.getEntityCollectionPage({ authorization: params.authorization, url: this._options.urlFormatter.getIModelListUrl({ urlParams: params.urlParams, }), preferReturn: PreferReturn.Representation, entityCollectionAccessor, headers: params.headers, })); } /** * Gets a single iModel by its id. This method returns an iModel in its full representation. Wraps the * {@link https://developer.bentley.com/apis/imodels-v2/operations/get-imodel-details/ Get iModel} operation from iModels API. * @param {GetSingleIModelParams} params parameters for this operation. See {@link GetSingleIModelParams}. * @returns {Promise<iModel>} an iModel with specified id. See {@link IModel}. */ async getSingle(params) { const response = await this.sendGetRequest({ authorization: params.authorization, url: this._options.urlFormatter.getSingleIModelUrl({ iModelId: params.iModelId, }), headers: params.headers, }); const result = this.appendRelatedEntityCallbacks(params.authorization, response.body.iModel, params.headers); return result; } /** * Creates an empty iModel with specified properties. Wraps the * {@link https://developer.bentley.com/apis/imodels-v2/operations/create-imodel/ Create iModel} operation from iModels API. * @param {CreateEmptyIModelParams} params parameters for this operation. See {@link CreateEmptyIModelParams}. * @returns {Promise<iModel>} newly created iModel. See {@link IModel}. */ async createEmpty(params) { const createIModelBody = this.getCreateEmptyIModelRequestBody(params.iModelProperties); if (createIModelBody.geographicCoordinateSystem && createIModelBody.creationMode !== "empty") { throw new IModelsErrorImpl({ code: IModelsErrorCode.InvalidIModelGCSCreationMode, message: "For empty iModels, GeographicCoordinateSystem can only be set when creationMode is 'empty'.", originalError: undefined, statusCode: undefined, details: undefined, }); } let createdIModel = await this.sendIModelPostRequest(params.authorization, createIModelBody, params.headers); if (createdIModel.state === IModelState.NotInitialized) { await this.waitForEmptyIModelInitialization({ authorization: params.authorization, headers: params.headers, iModelId: createdIModel.id, timeOutInMs: params.timeOutInMs, }); createdIModel = await this.getSingle({ authorization: params.authorization, iModelId: createdIModel.id, }); } const result = this.appendRelatedEntityCallbacks(params.authorization, createdIModel, params.headers); return result; } /** * Creates an iModel from a template. Wraps the * {@link https://developer.bentley.com/apis/imodels-v2/operations/create-imodel/ Create iModel} operation from iModels API. * It uses the `template` request body property to specify the source iModel which will be used as a template. Internally * this method creates the iModel instance and then repeatedly queries the iModel state until the iModel is initialized. * The execution of this method can take up to several minutes due to waiting for initialization to complete. * @param {CreateIModelFromTemplateParams} params parameters for this operation. See {@link CreateIModelFromTemplateParams}. * @returns {Promise<iModel>} newly created iModel. See {@link IModel}. * @throws an error that implements `iModelsError` interface with code {@link IModelsErrorCode.IModelFromTemplateInitializationFailed} if * iModel initialization failed or did not complete in time. See {@link IModelsErrorCode}. */ async createFromTemplate(params) { const createIModelBody = this.getCreateIModelFromTemplateRequestBody(params.iModelProperties); const createdIModel = await this.sendIModelPostRequest(params.authorization, createIModelBody, params.headers); await this.waitForTemplatedIModelInitialization({ authorization: params.authorization, iModelId: createdIModel.id, headers: params.headers, timeOutInMs: params.timeOutInMs, }); return this.getSingle({ authorization: params.authorization, iModelId: createdIModel.id, headers: params.headers, }); } /** * Clones the specified iModel. Wraps the * {@link https://developer.bentley.com/apis/imodels-v2/operations/clone-imodel/ Clone iModel} operation from iModels API. * Internally this method clones the iModel and then repeatedly queries the new iModel's state until it is initialized. * The execution of this method can take up to several minutes due to waiting for initialization to complete. * @param {CloneIModelParams} params parameters for this operation. See {@link CloneIModelParams}. * @returns {Promise<IModel>} newly created iModel. See {@link IModel}. * @throws an error that implements `iModelsError` interface with code {@link IModelsErrorCode.ClonedIModelInitializationFailed} if * iModel initialization failed or {@link IModelsErrorCode.ClonedIModelInitializationTimedOut} if operation did not complete in time. * See {@link IModelsErrorCode}. */ async clone(params) { const cloneIModelBody = this.getCloneIModelRequestBody(params.iModelProperties); const cloneIModelResponse = await this.sendPostRequest({ authorization: params.authorization, url: this._options.urlFormatter.getCloneIModelUrl({ iModelId: params.iModelId, }), body: cloneIModelBody, headers: params.headers, }); const locationHeaderValue = cloneIModelResponse.headers.get(Constants.headers.location); assertStringHeaderValue(Constants.headers.location, locationHeaderValue); const { iModelId: clonedIModelId } = this._options.urlFormatter.parseIModelUrl(locationHeaderValue); await this.waitForClonedIModelInitialization({ authorization: params.authorization, iModelId: clonedIModelId, headers: params.headers, timeOutInMs: params.timeOutInMs, }); return this.getSingle({ authorization: params.authorization, iModelId: clonedIModelId, }); } /** * Forks the specified iModel. Wraps the * {@link https://developer.bentley.com/apis/imodels-v2/operations/fork-imodel/ Fork iModel} operation from iModels API. * Internally this method forks the iModel and then repeatedly queries the new iModel's creation state until it is succeeded. * The execution of this method can take up to several minutes due to waiting for initialization to complete. * @param {ForkIModelParams} params parameters for this operation. See {@link ForkIModelParams}. * @returns {Promise<IModel>} newly created iModel. See {@link IModel}. * @throws an error that implements `iModelsError` interface with code {@link IModelsErrorCode.IModelForkInitializationFailed} if * iModel initialization failed, {@link IModelsErrorCode.IModelForkInitializationTimedOut} if operation did not complete in time or * {@link IModelsErrorCode.MainIModelIsMissingFederationGuids} if the iModel from which user is attempting to create a fork does not * have {@link https://www.itwinjs.org/bis/guide/fundamentals/federationguids/ FederationGuid} property set on all its elements. * See {@link IModelsErrorCode}. */ async fork(params) { const forkIModelBody = this.getForkIModelRequestBody(params.iModelProperties); const forkIModelResponse = await this.sendPostRequest({ authorization: params.authorization, url: this._options.urlFormatter.getForkIModelUrl({ iModelId: params.iModelId, }), body: forkIModelBody, headers: params.headers, }); const locationHeaderValue = forkIModelResponse.headers.get(Constants.headers.location); assertStringHeaderValue(Constants.headers.location, locationHeaderValue); const { iModelId: forkIModelId } = this._options.urlFormatter.parseIModelUrl(locationHeaderValue); await this.waitForIModelForkInitialization({ authorization: params.authorization, iModelId: forkIModelId, headers: params.headers, timeOutInMs: params.timeOutInMs, }); return this.getSingle({ authorization: params.authorization, iModelId: forkIModelId, }); } /** * Updates iModel properties. Wraps the * {@link https://developer.bentley.com/apis/imodels-v2/operations/update-imodel/ Update iModel} operation from iModels API. * @param {UpdateIModelParams} params parameters for this operation. See {@link UpdateIModelParams}. * @returns {Promise<IModel>} updated iModel. See {@link IModel}. */ async update(params) { const updateIModelBody = this.getUpdateIModelRequestBody(params.iModelProperties); const updateIModelResponse = await this.sendPatchRequest({ authorization: params.authorization, url: this._options.urlFormatter.getSingleIModelUrl({ iModelId: params.iModelId, }), body: updateIModelBody, headers: params.headers, }); const result = this.appendRelatedEntityCallbacks(params.authorization, updateIModelResponse.body.iModel, params.headers); return result; } /** * Deletes an iModel with specified id. Wraps the {@link https://developer.bentley.com/apis/imodels-v2/operations/delete-imodel/ Delete iModel} * operation from iModels API. * @param {DeleteIModelParams} params parameters for this operation. See {@link DeleteIModelParams}. * @returns {Promise<void>} a promise that resolves after operation completes. */ async delete(params) { await this.sendDeleteRequest({ authorization: params.authorization, url: this._options.urlFormatter.getSingleIModelUrl({ iModelId: params.iModelId, }), headers: params.headers, }); } appendRelatedEntityCallbacks(authorization, iModel, headers) { const getCreator = async () => this.getCreator(authorization, iModel._links.creator?.href, headers); const result = { ...iModel, getCreator, }; return result; } getCreateEmptyIModelRequestBody(iModelProperties) { const result = { iTwinId: iModelProperties.iTwinId, name: iModelProperties.name, description: iModelProperties.description, extent: iModelProperties.extent, containersEnabled: iModelProperties.containersEnabled, creationMode: iModelProperties.creationMode, geographicCoordinateSystem: iModelProperties.geographicCoordinateSystem, }; return result; } async sendIModelPostRequest(authorization, createIModelBody, headers) { const createIModelResponse = await this.sendPostRequest({ authorization, url: this._options.urlFormatter.getCreateIModelUrl(), body: createIModelBody, headers, }); return createIModelResponse.body.iModel; } async getCreator(authorization, creatorLink, headers) { if (!creatorLink) return undefined; const { iModelId, userId } = this._options.urlFormatter.parseUserUrl(creatorLink); return this._iModelsClient.users.getSingle({ authorization, iModelId, userId, headers, }); } getCreateIModelFromTemplateRequestBody(iModelProperties) { const emptyIModelParams = this.getCreateEmptyIModelRequestBody(iModelProperties); return { ...emptyIModelParams, template: { iModelId: iModelProperties.template.iModelId, changesetId: iModelProperties.template.changesetId, }, }; } getCloneIModelRequestBody(iModelProperties) { return { iTwinId: iModelProperties.iTwinId, name: iModelProperties.name, description: iModelProperties.description, changesetId: iModelProperties.changesetId, changesetIndex: iModelProperties.changesetIndex, containersEnabled: iModelProperties.containersEnabled, }; } getForkIModelRequestBody(iModelProperties) { return { iTwinId: iModelProperties.iTwinId, name: iModelProperties.name, description: iModelProperties.description, changesetId: iModelProperties.changesetId, changesetIndex: iModelProperties.changesetIndex, preserveHistory: iModelProperties.preserveHistory, containersEnabled: iModelProperties.containersEnabled, }; } getUpdateIModelRequestBody(iModelProperties) { return { name: iModelProperties.name, description: iModelProperties.description, extent: iModelProperties.extent, }; } async isIModelInitialized(params) { const { state } = await this._iModelsClient.operations.getCreateIModelDetails({ authorization: params.authorization, iModelId: params.iModelId, headers: params.headers, }); if (state !== IModelCreationState.Scheduled && state !== IModelCreationState.WaitingForFile && state !== IModelCreationState.Successful) throw new IModelsErrorImpl({ code: params.errorCodeOnFailure, message: `iModel initialization failed with state '${state}'`, originalError: undefined, statusCode: undefined, details: undefined, }); return state === IModelCreationState.Successful; } async isIModelForkInitialized(params) { const { state } = await this._iModelsClient.operations.getCreateIModelDetails({ authorization: params.authorization, iModelId: params.iModelId, headers: params.headers, }); if (state === IModelCreationState.MainIModelIsMissingFederationGuids) throw new IModelsErrorImpl({ code: IModelsErrorCode.MainIModelIsMissingFederationGuids, message: "iModel fork initialization failed because some elements in the main iModel do not have FederationGuid property set.", originalError: undefined, statusCode: undefined, details: undefined, }); if (state !== IModelCreationState.Scheduled && state !== IModelCreationState.WaitingForFile && state !== IModelCreationState.Successful) throw new IModelsErrorImpl({ code: IModelsErrorCode.IModelForkInitializationFailed, message: `iModel fork initialization failed with state '${state}'`, originalError: undefined, statusCode: undefined, details: undefined, }); return state === IModelCreationState.Successful; } async waitForEmptyIModelInitialization(params) { return UtilityFunctions.waitForCondition({ conditionToSatisfy: async () => this.isIModelInitialized({ authorization: params.authorization, iModelId: params.iModelId, errorCodeOnFailure: IModelsErrorCode.EmptyIModelInitializationFailed, headers: params.headers, }), timeoutErrorFactory: () => new IModelsErrorImpl({ code: IModelsErrorCode.EmptyIModelInitializationFailed, message: "Timed out waiting for empty iModel initialization.", originalError: undefined, statusCode: undefined, details: undefined, }), timeOutInMs: params.timeOutInMs, }); } async waitForTemplatedIModelInitialization(params) { return UtilityFunctions.waitForCondition({ conditionToSatisfy: async () => this.isIModelInitialized({ authorization: params.authorization, iModelId: params.iModelId, errorCodeOnFailure: IModelsErrorCode.IModelFromTemplateInitializationFailed, headers: params.headers, }), timeoutErrorFactory: () => new IModelsErrorImpl({ code: IModelsErrorCode.IModelFromTemplateInitializationTimedOut, message: "Timed out waiting for Baseline File initialization.", originalError: undefined, statusCode: undefined, details: undefined, }), timeOutInMs: params.timeOutInMs, }); } async waitForClonedIModelInitialization(params) { return UtilityFunctions.waitForCondition({ conditionToSatisfy: async () => this.isIModelInitialized({ authorization: params.authorization, iModelId: params.iModelId, errorCodeOnFailure: IModelsErrorCode.ClonedIModelInitializationFailed, headers: params.headers, }), timeoutErrorFactory: () => new IModelsErrorImpl({ code: IModelsErrorCode.ClonedIModelInitializationTimedOut, message: "Timed out waiting for Cloned iModel initialization.", originalError: undefined, statusCode: undefined, details: undefined, }), timeOutInMs: params.timeOutInMs, }); } async waitForIModelForkInitialization(params) { return UtilityFunctions.waitForCondition({ conditionToSatisfy: async () => this.isIModelForkInitialized({ authorization: params.authorization, iModelId: params.iModelId, headers: params.headers, }), timeoutErrorFactory: () => new IModelsErrorImpl({ code: IModelsErrorCode.IModelForkInitializationTimedOut, message: "Timed out waiting for iModel fork initialization.", originalError: undefined, statusCode: undefined, details: undefined, }), timeOutInMs: params.timeOutInMs, }); } } //# sourceMappingURL=IModelOperations.js.map