diff --git a/common/api/core-backend.api.md b/common/api/core-backend.api.md index ce088614fa47..4a9178472974 100644 --- a/common/api/core-backend.api.md +++ b/common/api/core-backend.api.md @@ -110,7 +110,6 @@ import { Id64Arg } from '@itwin/core-bentley'; import { Id64Array } from '@itwin/core-bentley'; import { Id64Set } from '@itwin/core-bentley'; import { Id64String } from '@itwin/core-bentley'; -import { IDisposable } from '@itwin/core-bentley'; import { ImageSourceFormat } from '@itwin/core-common'; import { IModel } from '@itwin/core-common'; import { IModelCoordinatesRequestProps } from '@itwin/core-common'; @@ -635,14 +634,14 @@ export interface ChangedECInstance { } // @internal -export class ChangedElementsDb implements IDisposable { +export class ChangedElementsDb implements Disposable { + // (undocumented) + [Symbol.dispose](): void; constructor(); // (undocumented) cleanCaches(): void; closeDb(): void; static createDb(briefcase: IModelDb, pathName: string): ChangedElementsDb; - // (undocumented) - dispose(): void; getChangeData(startChangesetId: string, endChangesetId: string): ChangeData | undefined; getChangedElements(startChangesetId: string, endChangesetId: string): ChangedElements | undefined; getChangedModels(startChangesetId: string, endChangesetId: string): ChangedModels | undefined; @@ -688,7 +687,8 @@ export interface ChangesetArg extends IModelIdArg { } // @beta -export class ChangesetECAdaptor implements IDisposable { +export class ChangesetECAdaptor implements Disposable { + [Symbol.dispose](): void; constructor(reader: SqliteChangesetReader, disableMetaData?: boolean); acceptClass(classFullName: string): ChangesetECAdaptor; acceptOp(op: SqliteChangeOp): ChangesetECAdaptor; @@ -702,7 +702,6 @@ export class ChangesetECAdaptor implements IDisposable { deleted?: ChangedECInstance; // (undocumented) readonly disableMetaData: boolean; - dispose(): void; inserted?: ChangedECInstance; get isDeleted(): boolean; isECTable(tableName: string): boolean; @@ -1740,9 +1739,10 @@ export abstract class DriverBundleElement extends InformationContentElement { } // @public -export class ECDb implements IDisposable { +export class ECDb implements Disposable { // @internal (undocumented) get [_nativeDb](): IModelJsNative.ECDb; + [Symbol.dispose](): void; constructor(); abandonChanges(): void; // @internal @@ -1750,6 +1750,7 @@ export class ECDb implements IDisposable { closeDb(): void; createDb(pathName: string): void; createQueryReader(ecsql: string, params?: QueryBinder, config?: QueryOptions): ECSqlReader; + // @deprecated (undocumented) dispose(): void; // @internal getCachedStatementCount(): number; @@ -1866,7 +1867,8 @@ export interface ECSqlRowArg { } // @public -export class ECSqlStatement implements IterableIterator, IDisposable { +export class ECSqlStatement implements IterableIterator, Disposable { + [Symbol.dispose](): void; [Symbol.iterator](): IterableIterator; bindArray(parameter: number | string, val: any[]): void; bindBlob(parameter: number | string, blob: string | Uint8Array | ArrayBuffer | SharedArrayBuffer): void; @@ -1888,6 +1890,7 @@ export class ECSqlStatement implements IterableIterator, IDisposable { bindValue(parameter: number | string, val: any): void; bindValues(values: any[] | object): void; clearBindings(): void; + // @deprecated (undocumented) dispose(): void; getBinder(parameter: string | number): ECSqlBinder; getColumnCount(): number; @@ -3332,10 +3335,12 @@ export namespace IModelDb { // @beta export class IModelElementCloneContext { + [Symbol.dispose](): void; constructor(sourceDb: IModelDb, targetDb?: IModelDb); // @internal cloneElement(sourceElement: Element_2, cloneOptions?: IModelJsNative.CloneElementOptions): ElementProps; static create(...args: ConstructorParameters): Promise; + // @deprecated (undocumented) dispose(): void; // @internal dump(outputFileName: string): void; @@ -5282,7 +5287,8 @@ export interface SqliteChange { export type SqliteChangeOp = "Inserted" | "Updated" | "Deleted"; // @beta -export class SqliteChangesetReader implements IDisposable { +export class SqliteChangesetReader implements Disposable { + [Symbol.dispose](): void; protected constructor( db: AnyDb); get changeIndex(): number; @@ -5290,7 +5296,6 @@ export class SqliteChangesetReader implements IDisposable { get columnCount(): number; readonly db: AnyDb; get disableSchemaCheck(): boolean; - dispose(): void; getChangeValue(columnIndex: number, stage: SqliteValueStage): SqliteValue_2; getChangeValueBinary(columnIndex: number, stage: SqliteValueStage): Uint8Array | null | undefined; getChangeValueDouble(columnIndex: number, stage: SqliteValueStage): number | null | undefined; @@ -5438,7 +5443,8 @@ export namespace SQLiteDb { } // @public -export class SqliteStatement implements IterableIterator, IDisposable { +export class SqliteStatement implements IterableIterator, Disposable { + [Symbol.dispose](): void; [Symbol.iterator](): IterableIterator; constructor(_sql: string); bindBlob(parameter: BindParameter, blob: Uint8Array): void; @@ -5454,6 +5460,7 @@ export class SqliteStatement implements IterableIterator, IDisposable { bindValue(parameter: BindParameter, value: any): void; bindValues(values: any[] | object): void; clearBindings(): void; + // @deprecated (undocumented) dispose(): void; getColumnBytes(colIndex: number): number; getColumnCount(): number; diff --git a/common/api/core-bentley.api.md b/common/api/core-bentley.api.md index 8ddb60e808ae..5bf7043e24e2 100644 --- a/common/api/core-bentley.api.md +++ b/common/api/core-bentley.api.md @@ -522,9 +522,15 @@ export class DisposableList implements IDisposable { } // @public +export function dispose(disposable?: Disposable): undefined; + +// @public @deprecated (undocumented) export function dispose(disposable?: IDisposable): undefined; // @public +export function disposeArray(list?: Disposable[]): undefined; + +// @public @deprecated (undocumented) export function disposeArray(list?: IDisposable[]): undefined; // @public @@ -695,7 +701,7 @@ export type Id64Set = Set; // @public export type Id64String = string; -// @public +// @public @deprecated export interface IDisposable { dispose(): void; } @@ -1009,6 +1015,9 @@ export class IndexMap { } // @public +export function isDisposable(obj: unknown): obj is Disposable; + +// @public @deprecated export function isIDisposable(obj: unknown): obj is IDisposable; // @public @@ -1404,9 +1413,11 @@ export class OrderedSet extends ReadonlyOrderedSet { export function partitionArray(array: T[], criterion: (element: T) => boolean): number; // @public -export class PerfLogger implements IDisposable { - constructor(operation: string, metaData?: LoggingMetaData); +export class PerfLogger implements Disposable { // (undocumented) + [Symbol.dispose](): void; + constructor(operation: string, metaData?: LoggingMetaData); + // @deprecated (undocumented) dispose(): void; } @@ -1744,7 +1755,7 @@ export class UnexpectedErrors { static setHandler(handler: OnUnexpectedError): OnUnexpectedError; } -// @public +// @public @deprecated export function using(resources: T | T[], func: (...r: T[]) => TResult): TResult; // @public diff --git a/common/api/core-common.api.md b/common/api/core-common.api.md index 379ad6300c36..974035500e9b 100644 --- a/common/api/core-common.api.md +++ b/common/api/core-common.api.md @@ -31,7 +31,6 @@ import { GuidString } from '@itwin/core-bentley'; import { Id64 } from '@itwin/core-bentley'; import { Id64Array } from '@itwin/core-bentley'; import { Id64String } from '@itwin/core-bentley'; -import { IDisposable } from '@itwin/core-bentley'; import { IModelJson } from '@itwin/core-geometry'; import { IModelStatus } from '@itwin/core-bentley'; import { IndexedPolyface } from '@itwin/core-geometry'; @@ -8140,11 +8139,13 @@ export namespace RenderSchedule { } // @public -export abstract class RenderTexture implements IDisposable { +export abstract class RenderTexture implements Disposable { + [Symbol.dispose](): void; protected constructor(type: RenderTexture.Type); // (undocumented) abstract get bytesUsed(): number; compare(other: RenderTexture): number; + // @deprecated (undocumented) abstract dispose(): void; // (undocumented) get isGlyph(): boolean; @@ -8780,6 +8781,8 @@ export class RpcRegistry { // @internal export abstract class RpcRequest { + // (undocumented) + [Symbol.dispose](): void; constructor(client: RpcInterface, operation: string, parameters: any[]); static get activeRequests(): ReadonlyMap; static get aggregateLoad(): RpcOperationsProfile; @@ -8790,8 +8793,6 @@ export abstract class RpcRequest { protected computeRetryAfter(attempts: number): number; get connecting(): boolean; static current(context: RpcInterface): RpcRequest; - // (undocumented) - dispose(): void; get elapsed(): number; static readonly events: BeEvent; get extendedStatus(): string; diff --git a/common/api/core-frontend.api.md b/common/api/core-frontend.api.md index 3e174218df8e..5e81b590663f 100644 --- a/common/api/core-frontend.api.md +++ b/common/api/core-frontend.api.md @@ -142,7 +142,6 @@ import { Id64Arg } from '@itwin/core-bentley'; import { Id64Array } from '@itwin/core-bentley'; import { Id64Set } from '@itwin/core-bentley'; import { Id64String } from '@itwin/core-bentley'; -import { IDisposable } from '@itwin/core-bentley'; import { ImageBuffer } from '@itwin/core-common'; import { ImageBufferFormat } from '@itwin/core-common'; import { ImageMapLayerSettings } from '@itwin/core-common'; @@ -1885,12 +1884,12 @@ export abstract class BriefcaseNotificationHandler extends NotificationHandler { // @public export class BriefcaseTxns extends BriefcaseNotificationHandler implements TxnNotifications { + // @internal (undocumented) + [Symbol.dispose](): void; // @internal constructor(iModel: BriefcaseConnection); // @internal (undocumented) get briefcaseChannelName(): "itwinjs-core/txns"; - // @internal (undocumented) - dispose(): void; getRedoString(): Promise; getUndoString(): Promise; hasPendingTxns(): Promise; @@ -2589,10 +2588,12 @@ export interface DecorateContextCreateArgs { } // @public -export class Decorations implements IDisposable { +export class Decorations implements Disposable { // (undocumented) - canvasDecorations?: CanvasDecorationList; + [Symbol.dispose](): void; // (undocumented) + canvasDecorations?: CanvasDecorationList; + // @deprecated (undocumented) dispose(): void; get normal(): GraphicList | undefined; set normal(normal: GraphicList | undefined); @@ -3341,12 +3342,12 @@ export class EntityState implements EntityProps { // @internal (undocumented) export class EnvironmentDecorations { + // (undocumented) + [Symbol.dispose](): void; constructor(view: ViewState3d, onLoaded: () => void, onDispose: () => void); // (undocumented) decorate(context: DecorateContext): void; // (undocumented) - dispose(): void; - // (undocumented) protected _environment: Environment; // (undocumented) protected _ground?: GroundPlaneDecorations; @@ -4424,6 +4425,8 @@ export interface GpuMemoryLimits { export class GraphicalEditingScope extends BriefcaseNotificationHandler implements EditingScopeNotifications { // (undocumented) get briefcaseChannelName(): "itwinjs-core/editing-scope"; + // @deprecated (undocumented) + dispose(): void; // @internal static enter(imodel: BriefcaseConnection): Promise; exit(): Promise; @@ -4537,7 +4540,8 @@ export interface GraphicAssemblerOptions { } // @public -export class GraphicBranch implements IDisposable { +export class GraphicBranch implements Disposable { + [Symbol.dispose](): void; constructor(ownsEntries?: boolean); add(graphic: RenderGraphic): void; // @internal @@ -4547,6 +4551,7 @@ export class GraphicBranch implements IDisposable { clear(): void; // @internal (undocumented) collectStatistics(stats: RenderMemory.Statistics): void; + // @deprecated (undocumented) dispose(): void; readonly entries: RenderGraphic[]; getViewFlags(flags: ViewFlags): ViewFlags; @@ -5163,12 +5168,12 @@ export class ImageryMapLayerTreeReference extends MapLayerTileTreeReference { // @internal (undocumented) export class ImageryMapTile extends RealityTile { + // (undocumented) + [Symbol.dispose](): void; constructor(params: TileParams, imageryTree: ImageryMapTileTree, quadId: QuadId, rectangle: MapCartoRectangle); // (undocumented) protected _collectStatistics(stats: RenderMemory.Statistics): void; // (undocumented) - dispose(): void; - // (undocumented) disposeContents(): void; // (undocumented) freeMemory(): void; @@ -5748,6 +5753,8 @@ export class IModelTileRequestChannels { // @internal export class IModelTileTree extends TileTree { + // (undocumented) + [Symbol.dispose](): void; constructor(params: IModelTileTreeParams, treeId: IModelTileTreeId); // (undocumented) get batchType(): BatchType; @@ -5761,8 +5768,6 @@ export class IModelTileTree extends TileTree { // (undocumented) readonly decoder: ImdlDecoder; // (undocumented) - dispose(): void; - // (undocumented) draw(args: TileDrawArgs): void; // (undocumented) get edgeOptions(): EdgeOptions | false; @@ -6242,6 +6247,8 @@ export class LookViewTool extends ViewManip { // @internal export class LRUTileList { + // (undocumented) + [Symbol.dispose](): void; constructor(); add(tile: Tile): void; // (undocumented) @@ -6251,8 +6258,6 @@ export class LRUTileList { clearUsed(userId: number): void; // (undocumented) protected computeBytesUsed(tile: Tile): number; - // (undocumented) - dispose(): void; drop(tile: Tile): void; freeMemory(maxBytes: number): void; // (undocumented) @@ -7698,9 +7703,9 @@ export namespace MockRender { // (undocumented) readonly [_implementationProhibited] = "renderAreaPattern"; // (undocumented) - collectStatistics(): void; + [Symbol.dispose](): void; // (undocumented) - dispose(): void; + collectStatistics(): void; } // (undocumented) export class Batch extends Graphic { @@ -7732,14 +7737,14 @@ export namespace MockRender { } // (undocumented) export class Geometry implements RenderGeometry { + // (undocumented) + [Symbol.dispose](): void; constructor(renderGeometryType: "mesh" | "polyline" | "point-string"); // (undocumented) collectStatistics(): void; // (undocumented) computeRange(): Range3d; // (undocumented) - dispose(): void; - // (undocumented) isDisposed: boolean; // (undocumented) readonly isInstanceable = true; @@ -8123,6 +8128,8 @@ export class NullTarget extends RenderTarget { // (undocumented) protected readonly [_implementationProhibited]: undefined; // (undocumented) + [Symbol.dispose](): void; + // (undocumented) get analysisFraction(): number; set analysisFraction(_fraction: number); // (undocumented) @@ -8137,8 +8144,6 @@ export class NullTarget extends RenderTarget { // (undocumented) changeScene(): void; // (undocumented) - dispose(): void; - // (undocumented) drawFrame(_sceneMilSecElapsed?: number): void; // (undocumented) onDestroy(): void; @@ -8239,6 +8244,8 @@ export type OnFrameStatsReadyEvent = BeEvent<(frameStats: Readonly) // @internal export class OnScreenTarget extends Target { + // (undocumented) + [Symbol.dispose](): void; constructor(canvas: HTMLCanvasElement); // (undocumented) protected _assignDC(): boolean; @@ -8253,8 +8260,6 @@ export class OnScreenTarget extends Target { get devicePixelRatioOverride(): number | undefined; set devicePixelRatioOverride(ovr: number | undefined); // (undocumented) - dispose(): void; - // (undocumented) protected drawOverlayDecorations(): void; // (undocumented) protected _endPaint(): void; @@ -8290,12 +8295,12 @@ export function openImageDataUrlInNewWindow(url: string, title?: string): void; // @internal (undocumented) export class OrbitGtTileTree extends TileTree { + // (undocumented) + [Symbol.dispose](): void; constructor(treeParams: TileTreeParams, _dataManager: OrbitGtDataManager, cloudRange: Range3d, _centerOffset: Vector3d, _ecefTransform: Transform); // (undocumented) collectStatistics(stats: RenderMemory.Statistics): void; // (undocumented) - dispose(): void; - // (undocumented) draw(args: TileDrawArgs): void; // (undocumented) getEcefTransform(): Promise; @@ -9647,7 +9652,7 @@ export interface RemoteExtensionProviderProps { } // @internal -export interface RenderAreaPattern extends IDisposable, RenderMemory.Consumer { +export interface RenderAreaPattern extends Disposable, RenderMemory.Consumer { // (undocumented) readonly [_implementationProhibited]: "renderAreaPattern"; } @@ -9687,10 +9692,12 @@ export enum RenderDiagnostics { } // @public -export abstract class RenderGraphic implements IDisposable { +export abstract class RenderGraphic implements Disposable { + // (undocumented) + [Symbol.dispose](): void; // @internal (undocumented) abstract collectStatistics(stats: RenderMemory.Statistics): void; - // (undocumented) + // @deprecated (undocumented) abstract dispose(): void; // @internal abstract unionRange(range: Range3d): void; @@ -10006,11 +10013,11 @@ export interface RenderPlan { } // @internal -export abstract class RenderPlanarClassifier implements IDisposable { +export abstract class RenderPlanarClassifier implements Disposable { // (undocumented) - abstract collectGraphics(context: SceneContext, target: PlanarClassifierTarget): void; + abstract [Symbol.dispose](): void; // (undocumented) - abstract dispose(): void; + abstract collectGraphics(context: SceneContext, target: PlanarClassifierTarget): void; // (undocumented) abstract setSource(classifierTreeRef?: SpatialClassifierTileTreeReference, planarClipMask?: PlanarClipMaskState): void; } @@ -10062,7 +10069,9 @@ export interface RenderSkySphereParams { } // @public -export abstract class RenderSystem implements IDisposable { +export abstract class RenderSystem implements Disposable { + // (undocumented) + [Symbol.dispose](): void; // @internal protected constructor(options?: RenderSystem.Options); // @beta @@ -10162,7 +10171,7 @@ export abstract class RenderSystem implements IDisposable { createWorkerGraphicDescriptionContextProps(iModel: IModelConnection): WorkerGraphicDescriptionContextProps; // @beta get debugControl(): RenderSystemDebugControl | undefined; - // @internal (undocumented) + // @deprecated (undocumented) abstract dispose(): void; // @internal abstract doIdleWork(): boolean; @@ -10239,10 +10248,12 @@ export interface RenderSystemDebugControl { } // @public -export abstract class RenderTarget implements IDisposable, RenderMemory.Consumer { +export abstract class RenderTarget implements Disposable, RenderMemory.Consumer { // @internal (undocumented) protected abstract readonly [_implementationProhibited]: unknown; // @internal (undocumented) + [Symbol.dispose](): void; + // @internal (undocumented) adjustPixelSizeForLOD(cssPixelSize: number): number; // @internal (undocumented) abstract get analysisFraction(): number; @@ -10276,8 +10287,6 @@ export abstract class RenderTarget implements IDisposable, RenderMemory.Consumer // @internal (undocumented) get devicePixelRatio(): number; // @internal (undocumented) - dispose(): void; - // @internal (undocumented) abstract drawFrame(sceneMilSecElapsed?: number): void; // @internal (undocumented) getPlanarClassifier(_id: string): RenderPlanarClassifier | undefined; @@ -10357,23 +10366,23 @@ export interface RenderTargetDebugControl { } // @internal (undocumented) -export abstract class RenderTerrainGeometry implements IDisposable, RenderMemory.Consumer { +export abstract class RenderTerrainGeometry implements Disposable, RenderMemory.Consumer { // (undocumented) - abstract collectStatistics(stats: RenderMemory.Statistics): void; + abstract [Symbol.dispose](): void; // (undocumented) - abstract dispose(): void; + abstract collectStatistics(stats: RenderMemory.Statistics): void; // (undocumented) abstract get transform(): Transform | undefined; } // @internal -export abstract class RenderTextureDrape implements IDisposable { +export abstract class RenderTextureDrape implements Disposable { + // (undocumented) + abstract [Symbol.dispose](): void; // (undocumented) abstract collectGraphics(context: SceneContext): void; // (undocumented) abstract collectStatistics(stats: RenderMemory.Statistics): void; - // (undocumented) - abstract dispose(): void; } // @public @@ -10541,6 +10550,8 @@ export interface ScreenSpaceEffectSource { // @public export class ScreenViewport extends Viewport { + // @internal (undocumented) + [Symbol.dispose](): void; protected constructor(canvas: HTMLCanvasElement, parentDiv: HTMLDivElement, target: RenderTarget); protected addDecorations(decorations: Decorations): void; // @internal (undocumented) @@ -10573,8 +10584,6 @@ export class ScreenViewport extends Viewport { static create(parentDiv: HTMLDivElement, view: ViewState): ScreenViewport; // @internal readonly decorationDiv: HTMLDivElement; - // @internal (undocumented) - dispose(): void; doRedo(animationTime?: BeDuration): void; doUndo(animationTime?: BeDuration): void; // @internal (undocumented) @@ -11421,9 +11430,9 @@ export class SubCategoriesCache { // @internal export namespace SubCategoriesCache { export class Queue { + [Symbol.dispose](): void; // (undocumented) protected _current?: QueueEntry; - dispose(): void; // (undocumented) protected _disposed: boolean; // (undocumented) @@ -11496,6 +11505,8 @@ export function synchronizeViewportViews(source: Viewport): SynchronizeViewports export abstract class Target extends RenderTarget implements RenderTargetDebugControl, WebGLDisposable { // (undocumented) protected readonly [_implementationProhibited]: undefined; + // (undocumented) + [Symbol.dispose](): void; protected constructor(rect?: ViewRect); // (undocumented) activeVolumeClassifierModelId?: Id64String; @@ -11602,8 +11613,6 @@ export abstract class Target extends RenderTarget implements RenderTargetDebugCo // (undocumented) displayRealityTileRanges: boolean; // (undocumented) - dispose(): void; - // (undocumented) protected disposeFbo(): void; // (undocumented) drawForReadPixels: boolean; @@ -11974,6 +11983,7 @@ export class ThreeDTileFormatInterpreter { // @public export abstract class Tile { + [Symbol.dispose](): void; protected constructor(params: TileParams, tree: TileTree); // @internal (undocumented) protected addRangeGraphic(builder: GraphicBuilder, type: TileBoundingBoxes): void; @@ -11996,6 +12006,7 @@ export abstract class Tile { protected _contentRange?: ElementAlignedBox3d; countDescendants(): number; readonly depth: number; + // @deprecated (undocumented) dispose(): void; protected disposeChildren(): void; disposeContents(): void; @@ -12661,6 +12672,8 @@ export class Tiles implements Iterable<{ id: any; owner: TileTreeOwner; }> { + // @internal (undocumented) + [Symbol.dispose](): void; [Symbol.iterator](): Iterator<{ supplier: TileTreeSupplier; id: any; @@ -12668,8 +12681,6 @@ export class Tiles implements Iterable<{ }>; // @internal constructor(iModel: IModelConnection); - // @internal (undocumented) - dispose(): void; dropSupplier(supplier: TileTreeSupplier): void; forEachTreeOwner(func: (owner: TileTreeOwner) => void): void; getTileTreeOwner(id: any, supplier: TileTreeSupplier): TileTreeOwner; @@ -12701,6 +12712,7 @@ export class TileStorage { // @public export abstract class TileTree { + [Symbol.dispose](): void; protected constructor(params: TileTreeParams); // @internal (undocumented) accumulateTransformedRange(range: Range3d, matrix: Matrix4d, location: Transform, frustumPlanes?: FrustumPlanes): void; @@ -12714,6 +12726,7 @@ export abstract class TileTree { collectTileGeometry(_collector: TileGeometryCollector): void; readonly contentRange?: ElementAlignedBox3d; countTiles(): number; + // @deprecated (undocumented) dispose(): void; abstract draw(args: TileDrawArgs): void; readonly expirationTime: BeDuration; @@ -12761,7 +12774,7 @@ export enum TileTreeLoadStatus { // @public export interface TileTreeOwner { // @internal - dispose(): void; + [Symbol.dispose](): void; readonly iModel: IModelConnection; load(): TileTree | undefined; readonly loadStatus: TileTreeLoadStatus; @@ -14477,7 +14490,9 @@ export abstract class ViewManip extends ViewTool { } // @public -export abstract class Viewport implements IDisposable, TileUser { +export abstract class Viewport implements Disposable, TileUser { + // (undocumented) + [Symbol.dispose](): void; // @internal protected constructor(target: RenderTarget); protected addDecorations(_decorations: Decorations): void; @@ -14549,7 +14564,7 @@ export abstract class Viewport implements IDisposable, TileUser { discloseTileTrees(trees: DisclosedTileTreeSet): void; get displayStyle(): DisplayStyleState; set displayStyle(style: DisplayStyleState); - // (undocumented) + // @deprecated (undocumented) dispose(): void; // @internal get drawingToSheetTransform(): Transform | undefined; diff --git a/common/api/ecschema-metadata.api.md b/common/api/ecschema-metadata.api.md index 934a716f0f6a..3f1814916732 100644 --- a/common/api/ecschema-metadata.api.md +++ b/common/api/ecschema-metadata.api.md @@ -34,7 +34,7 @@ export type AnyECType = Schema | SchemaItem | AnyProperty | RelationshipConstrai export type AnyEnumerationProperty = EnumerationProperty | EnumerationArrayProperty; // @beta (undocumented) -export type AnyEnumerator = Enumerator_2; +export type AnyEnumerator = Enumerator; // @beta (undocumented) export type AnyPrimitiveProperty = PrimitiveProperty | PrimitiveArrayProperty; @@ -549,9 +549,9 @@ export class Enumeration extends SchemaItem { fromJSON(enumerationProps: EnumerationProps): Promise; // (undocumented) fromJSONSync(enumerationProps: EnumerationProps): void; - getEnumerator(value: string): Enumerator_2 | undefined; + getEnumerator(value: string): Enumerator | undefined; // (undocumented) - getEnumerator(value: number): Enumerator_2 | undefined; + getEnumerator(value: number): Enumerator | undefined; getEnumeratorByName(name: string): AnyEnumerator | undefined; // (undocumented) get isInt(): boolean; @@ -612,7 +612,7 @@ export interface EnumerationProps extends SchemaItemProps { } // @beta (undocumented) -interface Enumerator_2 { +export interface Enumerator { // (undocumented) readonly description?: string; // (undocumented) @@ -622,7 +622,6 @@ interface Enumerator_2 { // (undocumented) readonly value: T; } -export { Enumerator_2 as Enumerator } // @beta (undocumented) export interface EnumeratorProps { diff --git a/common/api/frontend-devtools.api.md b/common/api/frontend-devtools.api.md index 06195128bc8b..940c6d7ad170 100644 --- a/common/api/frontend-devtools.api.md +++ b/common/api/frontend-devtools.api.md @@ -719,9 +719,9 @@ export class DetachRealityModelTool extends Tool { // @beta export class DiagnosticsPanel { - constructor(vp: Viewport, props?: DiagnosticsPanelProps); // (undocumented) - dispose(): void; + [Symbol.dispose](): void; + constructor(vp: Viewport, props?: DiagnosticsPanelProps); // (undocumented) get element(): HTMLElement; // (undocumented) @@ -908,9 +908,9 @@ export function formatMemory(numBytes: number): string; // @beta export class FpsTracker { - constructor(parent: HTMLElement, viewport: Viewport); // (undocumented) - dispose(): void; + [Symbol.dispose](): void; + constructor(parent: HTMLElement, viewport: Viewport); } // @beta @@ -949,9 +949,9 @@ export class GaussianBlurEffect extends ConvolutionEffect { // @alpha (undocumented) export class GpuProfiler { - constructor(parent: HTMLElement); // (undocumented) - dispose(): void; + [Symbol.dispose](): void; + constructor(parent: HTMLElement); } // @beta @@ -1332,9 +1332,9 @@ export class MeasureTileLoadTimeTool extends Tool { // @beta export class MemoryTracker { - constructor(parent: HTMLElement, vp: Viewport); // (undocumented) - dispose(): void; + [Symbol.dispose](): void; + constructor(parent: HTMLElement, vp: Viewport); } // @alpha (undocumented) @@ -2105,10 +2105,10 @@ export interface SliderProps { // @beta export class SnowDecorator implements Decorator { + readonly [Symbol.dispose]: VoidFunction; configure(params: Partial): void; // (undocumented) decorate(context: DecorateContext): void; - readonly dispose: VoidFunction; static toggle(viewport: Viewport, enable?: boolean): Promise; readonly viewport: Viewport; } @@ -2218,16 +2218,16 @@ export interface TextBoxProps { // @beta export class TileMemoryBreakdown { - constructor(parent: HTMLElement); // (undocumented) - dispose(): void; + [Symbol.dispose](): void; + constructor(parent: HTMLElement); } // @beta export class TileStatisticsTracker { - constructor(parent: HTMLElement, vp: Viewport); // (undocumented) - dispose(): void; + [Symbol.dispose](): void; + constructor(parent: HTMLElement, vp: Viewport); } // @beta @@ -2567,9 +2567,9 @@ export interface ToolArgs { // @alpha export class ToolSettingsTracker { - constructor(parent: HTMLElement, _vp: Viewport); // (undocumented) - dispose(): void; + [Symbol.dispose](): void; + constructor(parent: HTMLElement, _vp: Viewport); } // @beta diff --git a/common/api/hypermodeling-frontend.api.md b/common/api/hypermodeling-frontend.api.md index b1396ed7578e..94a4ead60ea8 100644 --- a/common/api/hypermodeling-frontend.api.md +++ b/common/api/hypermodeling-frontend.api.md @@ -62,6 +62,8 @@ export interface HyperModelingConfig { // @public export class HyperModelingDecorator implements Decorator { + // @internal (undocumented) + [Symbol.dispose](): void; get activeMarker(): SectionMarker | undefined; alignToSpatialView(marker: SectionMarker): Promise; alignView(marker: SectionMarker): void; @@ -71,8 +73,6 @@ export class HyperModelingDecorator implements Decorator { static create(vp: ScreenViewport, config: SectionMarkerConfig): Promise; // @internal (undocumented) decorate(context: DecorateContext): void; - // @internal (undocumented) - dispose(): void; static getForViewport(vp: ScreenViewport): HyperModelingDecorator | undefined; readonly markers: SectionMarkerSet; openSection(marker: SectionMarker): Promise; diff --git a/common/api/presentation-backend.api.md b/common/api/presentation-backend.api.md index 011ef7a40517..cd2b49c1a533 100644 --- a/common/api/presentation-backend.api.md +++ b/common/api/presentation-backend.api.md @@ -29,7 +29,6 @@ import { HierarchyCompareOptions } from '@itwin/presentation-common'; import { HierarchyLevelDescriptorRequestOptions } from '@itwin/presentation-common'; import { HierarchyRequestOptions } from '@itwin/presentation-common'; import { Id64String } from '@itwin/core-bentley'; -import { IDisposable } from '@itwin/core-bentley'; import { IModelDb } from '@itwin/core-backend'; import { InstanceKey } from '@itwin/presentation-common'; import { Item } from '@itwin/presentation-common'; @@ -218,6 +217,7 @@ export enum PresentationBackendNativeLoggerCategory { // @public export class PresentationManager { + [Symbol.dispose](): void; constructor(props?: PresentationManagerProps); // @deprecated activeLocale: string | undefined; @@ -230,6 +230,7 @@ export class PresentationManager { scopeId: string; } & BackendDiagnosticsAttribute): Promise; computeSelection(requestOptions: ComputeSelectionRequestOptions & BackendDiagnosticsAttribute): Promise; + // @deprecated (undocumented) dispose(): void; getContent(requestOptions: WithCancelEvent>>> & BackendDiagnosticsAttribute): Promise; getContentDescriptor(requestOptions: WithCancelEvent>> & BackendDiagnosticsAttribute): Promise; diff --git a/common/api/presentation-common.api.md b/common/api/presentation-common.api.md index 542890bec483..a03d93ffe971 100644 --- a/common/api/presentation-common.api.md +++ b/common/api/presentation-common.api.md @@ -13,7 +13,6 @@ import { FormatterSpec } from '@itwin/core-quantity'; import { GetMetaDataFunction } from '@itwin/core-bentley'; import { GuidString } from '@itwin/core-bentley'; import { Id64String } from '@itwin/core-bentley'; -import { IDisposable } from '@itwin/core-bentley'; import { IModelRpcProps } from '@itwin/core-common'; import { ParserSpec } from '@itwin/core-quantity'; import { RpcInterface } from '@itwin/core-common'; @@ -59,7 +58,7 @@ export class AsyncTasksTracker { // (undocumented) get pendingAsyncs(): Set; // (undocumented) - trackAsyncTask(): IDisposable; + trackAsyncTask(): Disposable; } // @public @@ -2563,8 +2562,10 @@ export enum QuerySpecificationTypes { } // @public -export class RegisteredRuleset implements IDisposable, Ruleset { +export class RegisteredRuleset implements Disposable, Ruleset { + [Symbol.dispose](): void; constructor(ruleset: Ruleset, uniqueIdentifier: string, disposeFunc: (ruleset: RegisteredRuleset) => void); + // @deprecated (undocumented) dispose(): void; // (undocumented) get id(): string; diff --git a/common/api/presentation-frontend.api.md b/common/api/presentation-frontend.api.md index ed9e0456c0a8..60edbeb28286 100644 --- a/common/api/presentation-frontend.api.md +++ b/common/api/presentation-frontend.api.md @@ -30,7 +30,6 @@ import { HierarchyRequestOptions } from '@itwin/presentation-common'; import { HierarchyUpdateInfo } from '@itwin/presentation-common'; import { Id64Arg } from '@itwin/core-bentley'; import { Id64String } from '@itwin/core-bentley'; -import { IDisposable } from '@itwin/core-bentley'; import { IModelConnection } from '@itwin/core-frontend'; import { InstanceKey } from '@itwin/presentation-common'; import { InternetConnectivityStatus } from '@itwin/core-common'; @@ -111,12 +110,14 @@ export const FAVORITE_PROPERTIES_ORDER_INFO_SETTING_NAME = "FavoritePropertiesOr export const FAVORITE_PROPERTIES_SETTING_NAME = "FavoriteProperties"; // @public -export class FavoritePropertiesManager implements IDisposable { +export class FavoritePropertiesManager implements Disposable { + // (undocumented) + [Symbol.dispose](): void; constructor(props: FavoritePropertiesManagerProps); add(field: Field, imodel: IModelConnection, scope: FavoritePropertiesScope): Promise; changeFieldPriority(imodel: IModelConnection, field: Field, afterField: Field | undefined, visibleFields: Field[]): Promise; clear(imodel: IModelConnection, scope: FavoritePropertiesScope): Promise; - // (undocumented) + // @deprecated (undocumented) dispose(): void; // @internal ensureInitialized(imodel: IModelConnection): Promise; @@ -263,10 +264,10 @@ export class NoopFavoritePropertiesStorage implements IFavoritePropertiesStorage } // @internal (undocumented) -export class OfflineCachingFavoritePropertiesStorage implements IFavoritePropertiesStorage, IDisposable { - constructor(props: OfflineCachingFavoritePropertiesStorageProps); +export class OfflineCachingFavoritePropertiesStorage implements IFavoritePropertiesStorage, Disposable { // (undocumented) - dispose(): void; + [Symbol.dispose](): void; + constructor(props: OfflineCachingFavoritePropertiesStorageProps); // (undocumented) get impl(): IFavoritePropertiesStorage; // (undocumented) @@ -313,14 +314,16 @@ export enum PresentationFrontendLoggerCategory { } // @public -export class PresentationManager implements IDisposable { +export class PresentationManager implements Disposable { + // (undocumented) + [Symbol.dispose](): void; get activeLocale(): string | undefined; set activeLocale(locale: string | undefined); // @deprecated get activeUnitSystem(): UnitSystemKey; set activeUnitSystem(value: UnitSystemKey | undefined); static create(props?: PresentationManagerProps): PresentationManager; - // (undocumented) + // @deprecated (undocumented) dispose(): void; // @internal ensureIModelInitialized(_: IModelConnection): Promise; @@ -502,10 +505,12 @@ export enum SelectionChangeType { } // @public -export class SelectionHandler implements IDisposable { +export class SelectionHandler implements Disposable { + [Symbol.dispose](): void; constructor(props: SelectionHandlerProps); addToSelection(keys: Keys, level?: number): void; clearSelection(level?: number): void; + // @deprecated (undocumented) dispose(): void; getSelection(level?: number): Readonly; getSelectionLevels(): number[]; @@ -535,12 +540,14 @@ export class SelectionHelper { } // @public -export class SelectionManager implements ISelectionProvider { +export class SelectionManager implements ISelectionProvider, Disposable { + // (undocumented) + [Symbol.dispose](): void; constructor(props: SelectionManagerProps); addToSelection(source: string, imodel: IModelConnection, keys: Keys, level?: number, rulesetId?: string): void; addToSelectionWithScope(source: string, imodel: IModelConnection, ids: Id64Arg, scope: SelectionScopeProps | SelectionScope | string, level?: number, rulesetId?: string): Promise; clearSelection(source: string, imodel: IModelConnection, level?: number, rulesetId?: string): void; - // (undocumented) + // @deprecated (undocumented) dispose(): void; getHiliteSet(imodel: IModelConnection): Promise; getHiliteSetIterator(imodel: IModelConnection): AsyncIterableIterator; @@ -555,7 +562,10 @@ export class SelectionManager implements ISelectionProvider { readonly scopes: SelectionScopesManager; readonly selectionChange: SelectionChangeEvent; setSyncWithIModelToolSelection(imodel: IModelConnection, sync?: boolean): void; - suspendIModelToolSelectionSync(imodel: IModelConnection): IDisposable; + suspendIModelToolSelectionSync(imodel: IModelConnection): { + [Symbol.dispose]: () => void; + dispose: () => void; + }; } // @public @@ -581,10 +591,10 @@ export interface SelectionScopesManagerProps { } // @internal (undocumented) -export class ToolSelectionSyncHandler implements IDisposable { - constructor(imodel: IModelConnection, logicalSelection: SelectionManager); +export class ToolSelectionSyncHandler implements Disposable { // (undocumented) - dispose(): void; + [Symbol.dispose](): void; + constructor(imodel: IModelConnection, logicalSelection: SelectionManager); // (undocumented) isSuspended?: boolean; get pendingAsyncs(): Set; diff --git a/common/api/summary/core-bentley.exports.csv b/common/api/summary/core-bentley.exports.csv index 47e70ddffec7..1a07f92a3b72 100644 --- a/common/api/summary/core-bentley.exports.csv +++ b/common/api/summary/core-bentley.exports.csv @@ -42,7 +42,11 @@ public;class;Dictionary public;interface;DictionaryEntry public;class;DisposableList public;function;dispose +public;function;dispose +deprecated;function;dispose +public;function;disposeArray public;function;disposeArray +deprecated;function;disposeArray public;type;DisposeFunc public;enum;DuplicatePolicy public;class;Entry @@ -59,11 +63,14 @@ public;type;Id64Array public;type;Id64Set public;type;Id64String public;interface;IDisposable +deprecated;interface;IDisposable public;enum;IModelHubStatus public;enum;IModelStatus public;class;IndexedValue public;class;IndexMap +public;function;isDisposable public;function;isIDisposable +deprecated;function;isIDisposable public;function;isInstanceOf public;function;isProperSubclassOf public;function;isSubclassOf @@ -141,6 +148,7 @@ public;class;UintArrayBuilder public;interface;UintArrayBuilderOptions public;class;UnexpectedErrors public;function;using +deprecated;function;using public;function;utf8ToString public;class;YieldManager public;interface;YieldManagerOptions \ No newline at end of file diff --git a/common/api/summary/ecschema-metadata.exports.csv b/common/api/summary/ecschema-metadata.exports.csv index d05f8917126e..2a7015f2f64a 100644 --- a/common/api/summary/ecschema-metadata.exports.csv +++ b/common/api/summary/ecschema-metadata.exports.csv @@ -43,6 +43,7 @@ beta;class;EnumerationArrayProperty beta;class;EnumerationProperty beta;interface;EnumerationPropertyProps beta;interface;EnumerationProps +beta;interface;Enumerator beta;interface;EnumeratorProps beta;class;Format internal;function;getFormatProps diff --git a/common/changes/@itwin/analytical-backend/wbg-using_2024-12-11-15-19.json b/common/changes/@itwin/analytical-backend/wbg-using_2024-12-11-15-19.json new file mode 100644 index 000000000000..119f283c15f5 --- /dev/null +++ b/common/changes/@itwin/analytical-backend/wbg-using_2024-12-11-15-19.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@itwin/analytical-backend", + "comment": "", + "type": "none" + } + ], + "packageName": "@itwin/analytical-backend" +} \ No newline at end of file diff --git a/common/changes/@itwin/build-tools/wbg-using_2024-12-11-15-19.json b/common/changes/@itwin/build-tools/wbg-using_2024-12-11-15-19.json new file mode 100644 index 000000000000..cbd318579d57 --- /dev/null +++ b/common/changes/@itwin/build-tools/wbg-using_2024-12-11-15-19.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@itwin/build-tools", + "comment": "", + "type": "none" + } + ], + "packageName": "@itwin/build-tools" +} \ No newline at end of file diff --git a/common/changes/@itwin/certa/wbg-using_2024-12-11-15-19.json b/common/changes/@itwin/certa/wbg-using_2024-12-11-15-19.json new file mode 100644 index 000000000000..e594204cd8fe --- /dev/null +++ b/common/changes/@itwin/certa/wbg-using_2024-12-11-15-19.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@itwin/certa", + "comment": "", + "type": "none" + } + ], + "packageName": "@itwin/certa" +} \ No newline at end of file diff --git a/common/changes/@itwin/core-backend/wbg-using_2024-12-11-15-19.json b/common/changes/@itwin/core-backend/wbg-using_2024-12-11-15-19.json new file mode 100644 index 000000000000..99b35bb89b62 --- /dev/null +++ b/common/changes/@itwin/core-backend/wbg-using_2024-12-11-15-19.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@itwin/core-backend", + "comment": "", + "type": "none" + } + ], + "packageName": "@itwin/core-backend" +} \ No newline at end of file diff --git a/common/changes/@itwin/core-bentley/wbg-using_2024-12-11-15-19.json b/common/changes/@itwin/core-bentley/wbg-using_2024-12-11-15-19.json new file mode 100644 index 000000000000..19108af49826 --- /dev/null +++ b/common/changes/@itwin/core-bentley/wbg-using_2024-12-11-15-19.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@itwin/core-bentley", + "comment": "Deprecated IDisposable interface (along with related isIDisposable and using utilities) in favor of TypeScript's built-in `Disposable` type and `using` declarations. ", + "type": "none" + } + ], + "packageName": "@itwin/core-bentley" +} \ No newline at end of file diff --git a/common/changes/@itwin/core-common/wbg-using_2024-12-11-15-19.json b/common/changes/@itwin/core-common/wbg-using_2024-12-11-15-19.json new file mode 100644 index 000000000000..d1ac065f5d72 --- /dev/null +++ b/common/changes/@itwin/core-common/wbg-using_2024-12-11-15-19.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@itwin/core-common", + "comment": "", + "type": "none" + } + ], + "packageName": "@itwin/core-common" +} \ No newline at end of file diff --git a/common/changes/@itwin/core-electron/wbg-using_2024-12-11-15-19.json b/common/changes/@itwin/core-electron/wbg-using_2024-12-11-15-19.json new file mode 100644 index 000000000000..f06beccf2b7b --- /dev/null +++ b/common/changes/@itwin/core-electron/wbg-using_2024-12-11-15-19.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@itwin/core-electron", + "comment": "", + "type": "none" + } + ], + "packageName": "@itwin/core-electron" +} \ No newline at end of file diff --git a/common/changes/@itwin/core-frontend/wbg-using_2024-12-11-15-19.json b/common/changes/@itwin/core-frontend/wbg-using_2024-12-11-15-19.json new file mode 100644 index 000000000000..ac11a63efe7e --- /dev/null +++ b/common/changes/@itwin/core-frontend/wbg-using_2024-12-11-15-19.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@itwin/core-frontend", + "comment": "", + "type": "none" + } + ], + "packageName": "@itwin/core-frontend" +} \ No newline at end of file diff --git a/common/changes/@itwin/core-geometry/wbg-using_2024-12-11-15-19.json b/common/changes/@itwin/core-geometry/wbg-using_2024-12-11-15-19.json new file mode 100644 index 000000000000..9d7216f28509 --- /dev/null +++ b/common/changes/@itwin/core-geometry/wbg-using_2024-12-11-15-19.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@itwin/core-geometry", + "comment": "", + "type": "none" + } + ], + "packageName": "@itwin/core-geometry" +} \ No newline at end of file diff --git a/common/changes/@itwin/core-i18n/wbg-using_2024-12-11-15-19.json b/common/changes/@itwin/core-i18n/wbg-using_2024-12-11-15-19.json new file mode 100644 index 000000000000..6e3adc7db470 --- /dev/null +++ b/common/changes/@itwin/core-i18n/wbg-using_2024-12-11-15-19.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@itwin/core-i18n", + "comment": "", + "type": "none" + } + ], + "packageName": "@itwin/core-i18n" +} \ No newline at end of file diff --git a/common/changes/@itwin/core-mobile/wbg-using_2024-12-11-15-19.json b/common/changes/@itwin/core-mobile/wbg-using_2024-12-11-15-19.json new file mode 100644 index 000000000000..55fa0784386a --- /dev/null +++ b/common/changes/@itwin/core-mobile/wbg-using_2024-12-11-15-19.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@itwin/core-mobile", + "comment": "", + "type": "none" + } + ], + "packageName": "@itwin/core-mobile" +} \ No newline at end of file diff --git a/common/changes/@itwin/core-orbitgt/wbg-using_2024-12-11-15-19.json b/common/changes/@itwin/core-orbitgt/wbg-using_2024-12-11-15-19.json new file mode 100644 index 000000000000..11f81174ebb1 --- /dev/null +++ b/common/changes/@itwin/core-orbitgt/wbg-using_2024-12-11-15-19.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@itwin/core-orbitgt", + "comment": "", + "type": "none" + } + ], + "packageName": "@itwin/core-orbitgt" +} \ No newline at end of file diff --git a/common/changes/@itwin/ecschema-editing/wbg-using_2024-12-11-15-19.json b/common/changes/@itwin/ecschema-editing/wbg-using_2024-12-11-15-19.json new file mode 100644 index 000000000000..b0e7d3b96542 --- /dev/null +++ b/common/changes/@itwin/ecschema-editing/wbg-using_2024-12-11-15-19.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@itwin/ecschema-editing", + "comment": "", + "type": "none" + } + ], + "packageName": "@itwin/ecschema-editing" +} \ No newline at end of file diff --git a/common/changes/@itwin/ecschema-locaters/wbg-using_2024-12-11-15-19.json b/common/changes/@itwin/ecschema-locaters/wbg-using_2024-12-11-15-19.json new file mode 100644 index 000000000000..be9107090da4 --- /dev/null +++ b/common/changes/@itwin/ecschema-locaters/wbg-using_2024-12-11-15-19.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@itwin/ecschema-locaters", + "comment": "", + "type": "none" + } + ], + "packageName": "@itwin/ecschema-locaters" +} \ No newline at end of file diff --git a/common/changes/@itwin/ecschema-metadata/wbg-using_2024-12-11-15-19.json b/common/changes/@itwin/ecschema-metadata/wbg-using_2024-12-11-15-19.json new file mode 100644 index 000000000000..5dd8c0e532c0 --- /dev/null +++ b/common/changes/@itwin/ecschema-metadata/wbg-using_2024-12-11-15-19.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@itwin/ecschema-metadata", + "comment": "", + "type": "none" + } + ], + "packageName": "@itwin/ecschema-metadata" +} \ No newline at end of file diff --git a/common/changes/@itwin/ecschema-rpcinterface-tests/wbg-using_2024-12-11-15-19.json b/common/changes/@itwin/ecschema-rpcinterface-tests/wbg-using_2024-12-11-15-19.json new file mode 100644 index 000000000000..097a0a761e80 --- /dev/null +++ b/common/changes/@itwin/ecschema-rpcinterface-tests/wbg-using_2024-12-11-15-19.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@itwin/ecschema-rpcinterface-tests", + "comment": "", + "type": "none" + } + ], + "packageName": "@itwin/ecschema-rpcinterface-tests" +} \ No newline at end of file diff --git a/common/changes/@itwin/ecschema2ts/wbg-using_2024-12-11-15-19.json b/common/changes/@itwin/ecschema2ts/wbg-using_2024-12-11-15-19.json new file mode 100644 index 000000000000..a63f999cea79 --- /dev/null +++ b/common/changes/@itwin/ecschema2ts/wbg-using_2024-12-11-15-19.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@itwin/ecschema2ts", + "comment": "", + "type": "none" + } + ], + "packageName": "@itwin/ecschema2ts" +} \ No newline at end of file diff --git a/common/changes/@itwin/express-server/wbg-using_2024-12-11-15-19.json b/common/changes/@itwin/express-server/wbg-using_2024-12-11-15-19.json new file mode 100644 index 000000000000..e622b1b8741e --- /dev/null +++ b/common/changes/@itwin/express-server/wbg-using_2024-12-11-15-19.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@itwin/express-server", + "comment": "", + "type": "none" + } + ], + "packageName": "@itwin/express-server" +} \ No newline at end of file diff --git a/common/changes/@itwin/frontend-devtools/wbg-using_2024-12-11-15-19.json b/common/changes/@itwin/frontend-devtools/wbg-using_2024-12-11-15-19.json new file mode 100644 index 000000000000..3704c5ffd7e2 --- /dev/null +++ b/common/changes/@itwin/frontend-devtools/wbg-using_2024-12-11-15-19.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@itwin/frontend-devtools", + "comment": "", + "type": "none" + } + ], + "packageName": "@itwin/frontend-devtools" +} \ No newline at end of file diff --git a/common/changes/@itwin/frontend-tiles/wbg-using_2024-12-11-15-19.json b/common/changes/@itwin/frontend-tiles/wbg-using_2024-12-11-15-19.json new file mode 100644 index 000000000000..9c049751a866 --- /dev/null +++ b/common/changes/@itwin/frontend-tiles/wbg-using_2024-12-11-15-19.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@itwin/frontend-tiles", + "comment": "", + "type": "none" + } + ], + "packageName": "@itwin/frontend-tiles" +} \ No newline at end of file diff --git a/common/changes/@itwin/hypermodeling-frontend/wbg-using_2024-12-11-15-19.json b/common/changes/@itwin/hypermodeling-frontend/wbg-using_2024-12-11-15-19.json new file mode 100644 index 000000000000..43c6ffed45ca --- /dev/null +++ b/common/changes/@itwin/hypermodeling-frontend/wbg-using_2024-12-11-15-19.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@itwin/hypermodeling-frontend", + "comment": "", + "type": "none" + } + ], + "packageName": "@itwin/hypermodeling-frontend" +} \ No newline at end of file diff --git a/common/changes/@itwin/linear-referencing-backend/wbg-using_2024-12-11-15-19.json b/common/changes/@itwin/linear-referencing-backend/wbg-using_2024-12-11-15-19.json new file mode 100644 index 000000000000..d853bb2d2d6d --- /dev/null +++ b/common/changes/@itwin/linear-referencing-backend/wbg-using_2024-12-11-15-19.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@itwin/linear-referencing-backend", + "comment": "", + "type": "none" + } + ], + "packageName": "@itwin/linear-referencing-backend" +} \ No newline at end of file diff --git a/common/changes/@itwin/map-layers-formats/wbg-using_2024-12-11-15-19.json b/common/changes/@itwin/map-layers-formats/wbg-using_2024-12-11-15-19.json new file mode 100644 index 000000000000..a6bcc7b85e0a --- /dev/null +++ b/common/changes/@itwin/map-layers-formats/wbg-using_2024-12-11-15-19.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@itwin/map-layers-formats", + "comment": "", + "type": "none" + } + ], + "packageName": "@itwin/map-layers-formats" +} \ No newline at end of file diff --git a/common/changes/@itwin/physical-material-backend/wbg-using_2024-12-11-15-19.json b/common/changes/@itwin/physical-material-backend/wbg-using_2024-12-11-15-19.json new file mode 100644 index 000000000000..f1494e27b9b7 --- /dev/null +++ b/common/changes/@itwin/physical-material-backend/wbg-using_2024-12-11-15-19.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@itwin/physical-material-backend", + "comment": "", + "type": "none" + } + ], + "packageName": "@itwin/physical-material-backend" +} \ No newline at end of file diff --git a/common/changes/@itwin/presentation-backend/wbg-using_2024-12-11-15-19.json b/common/changes/@itwin/presentation-backend/wbg-using_2024-12-11-15-19.json new file mode 100644 index 000000000000..8cf278a0fc94 --- /dev/null +++ b/common/changes/@itwin/presentation-backend/wbg-using_2024-12-11-15-19.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@itwin/presentation-backend", + "comment": "", + "type": "none" + } + ], + "packageName": "@itwin/presentation-backend" +} \ No newline at end of file diff --git a/common/changes/@itwin/presentation-common/wbg-using_2024-12-11-15-19.json b/common/changes/@itwin/presentation-common/wbg-using_2024-12-11-15-19.json new file mode 100644 index 000000000000..832da0bf5908 --- /dev/null +++ b/common/changes/@itwin/presentation-common/wbg-using_2024-12-11-15-19.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@itwin/presentation-common", + "comment": "", + "type": "none" + } + ], + "packageName": "@itwin/presentation-common" +} \ No newline at end of file diff --git a/common/changes/@itwin/presentation-frontend/wbg-using_2024-12-11-15-19.json b/common/changes/@itwin/presentation-frontend/wbg-using_2024-12-11-15-19.json new file mode 100644 index 000000000000..fee45652689b --- /dev/null +++ b/common/changes/@itwin/presentation-frontend/wbg-using_2024-12-11-15-19.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@itwin/presentation-frontend", + "comment": "", + "type": "none" + } + ], + "packageName": "@itwin/presentation-frontend" +} \ No newline at end of file diff --git a/common/changes/@itwin/rpcinterface-full-stack-tests/wbg-using_2024-12-11-15-19.json b/common/changes/@itwin/rpcinterface-full-stack-tests/wbg-using_2024-12-11-15-19.json new file mode 100644 index 000000000000..f4ac0f33aed4 --- /dev/null +++ b/common/changes/@itwin/rpcinterface-full-stack-tests/wbg-using_2024-12-11-15-19.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@itwin/rpcinterface-full-stack-tests", + "comment": "", + "type": "none" + } + ], + "packageName": "@itwin/rpcinterface-full-stack-tests" +} \ No newline at end of file diff --git a/common/config/rush/pnpm-lock.yaml b/common/config/rush/pnpm-lock.yaml index 3c2766c35203..204c1e8595a3 100644 --- a/common/config/rush/pnpm-lock.yaml +++ b/common/config/rush/pnpm-lock.yaml @@ -27,7 +27,7 @@ importers: '@types/fs-extra': ^4.0.7 '@types/mocha': ^10.0.6 '@types/multiparty': ^0.0.31 - '@types/node': ~20.9.5 + '@types/node': ~20.17.0 '@types/semver': 7.3.10 '@types/sinon': ^17.0.2 '@types/touch': ^3.1.2 @@ -87,7 +87,7 @@ importers: '@types/fs-extra': 4.0.7 '@types/mocha': 10.0.6 '@types/multiparty': 0.0.31 - '@types/node': 20.9.5 + '@types/node': 20.17.0 '@types/semver': 7.3.10 '@types/sinon': 17.0.2 '@types/touch': 3.1.2 @@ -114,7 +114,7 @@ importers: '@itwin/build-tools': workspace:* '@itwin/eslint-plugin': 5.0.0-dev.1 '@opentelemetry/api': 1.0.4 - '@types/node': ~20.9.5 + '@types/node': ~20.17.0 '@vitest/coverage-v8': ^2.1.0 eslint: ^9.13.0 rimraf: ^3.0.2 @@ -124,12 +124,12 @@ importers: '@itwin/build-tools': link:../../tools/build '@itwin/eslint-plugin': 5.0.0-dev.1_aji6oyyaiulsuzmkdveqwiygte '@opentelemetry/api': 1.0.4 - '@types/node': 20.9.5 - '@vitest/coverage-v8': 2.1.1_vitest@2.1.0 + '@types/node': 20.17.0 + '@vitest/coverage-v8': 2.1.0_vitest@2.1.0 eslint: 9.13.0 rimraf: 3.0.2 typescript: 5.6.2 - vitest: 2.1.0_@types+node@20.9.5 + vitest: 2.1.0_@types+node@20.17.0 ../../core/common: specifiers: @@ -140,7 +140,7 @@ importers: '@itwin/object-storage-core': ^2.2.5 '@types/chai': 4.3.1 '@types/flatbuffers': ~1.10.0 - '@types/node': ~20.9.5 + '@types/node': ~20.17.0 '@vitest/coverage-v8': ^2.1.0 eslint: ^9.13.0 flatbuffers: ~1.12.0 @@ -160,13 +160,13 @@ importers: '@itwin/object-storage-core': 2.2.5 '@types/chai': 4.3.1 '@types/flatbuffers': 1.10.0 - '@types/node': 20.9.5 - '@vitest/coverage-v8': 2.1.1_vitest@2.1.0 + '@types/node': 20.17.0 + '@vitest/coverage-v8': 2.1.0_vitest@2.1.0 eslint: 9.13.0 nyc: 15.1.0 rimraf: 3.0.2 typescript: 5.6.2 - vitest: 2.1.0_@types+node@20.9.5 + vitest: 2.1.0_@types+node@20.17.0 ../../core/ecschema-editing: specifiers: @@ -181,7 +181,7 @@ importers: '@types/chai': 4.3.1 '@types/chai-as-promised': ^7 '@types/mocha': ^10.0.6 - '@types/node': ~20.9.5 + '@types/node': ~20.17.0 '@types/sinon': ^17.0.2 '@xmldom/xmldom': ~0.8.5 benchmark: ^2.1.4 @@ -206,7 +206,7 @@ importers: '@types/chai': 4.3.1 '@types/chai-as-promised': 7.1.0 '@types/mocha': 10.0.6 - '@types/node': 20.9.5 + '@types/node': 20.17.0 '@types/sinon': 17.0.2 '@xmldom/xmldom': 0.8.5 benchmark: 2.1.4 @@ -246,7 +246,7 @@ importers: '@types/fs-extra': ^4.0.7 '@types/glob': ^5.0.35 '@types/mocha': ^10.0.6 - '@types/node': ~20.9.5 + '@types/node': ~20.17.0 '@types/sinon': ^17.0.2 '@xmldom/xmldom': ~0.8.5 chai: ^4.3.10 @@ -289,7 +289,7 @@ importers: '@types/fs-extra': 4.0.7 '@types/glob': 5.0.35 '@types/mocha': 10.0.6 - '@types/node': 20.9.5 + '@types/node': 20.17.0 '@types/sinon': 17.0.2 chai: 4.3.10 chai-as-promised: 7.1.1_chai@4.3.10 @@ -312,7 +312,7 @@ importers: '@types/chai': 4.3.1 '@types/chai-as-promised': ^7 '@types/mocha': ^10.0.6 - '@types/node': ~20.9.5 + '@types/node': ~20.17.0 '@types/sinon': ^17.0.2 '@xmldom/xmldom': ~0.8.5 benchmark: ^2.1.4 @@ -335,7 +335,7 @@ importers: '@types/chai': 4.3.1 '@types/chai-as-promised': 7.1.0 '@types/mocha': 10.0.6 - '@types/node': 20.9.5 + '@types/node': 20.17.0 '@types/sinon': 17.0.2 '@xmldom/xmldom': 0.8.5 benchmark: 2.1.4 @@ -436,7 +436,7 @@ importers: '@openid/appauth': ^1.2.6 '@types/chai': 4.3.1 '@types/mocha': ^10.0.6 - '@types/node': ~20.9.5 + '@types/node': ~20.17.0 chai: ^4.3.10 cpx2: ^3.0.0 electron: ^33.0.0 @@ -464,7 +464,7 @@ importers: '@itwin/eslint-plugin': 5.0.0-dev.1_aji6oyyaiulsuzmkdveqwiygte '@types/chai': 4.3.1 '@types/mocha': 10.0.6 - '@types/node': 20.9.5 + '@types/node': 20.17.0 chai: 4.3.10 cpx2: 3.0.0 electron: 33.0.0 @@ -488,7 +488,7 @@ importers: '@types/express': ^4.17.20 '@types/express-ws': ^3.0.3 '@types/mocha': ^10.0.6 - '@types/node': ~20.9.5 + '@types/node': ~20.17.0 '@types/sinon': ^17.0.2 '@types/supertest': ^6.0.2 chai: ^4.3.10 @@ -514,7 +514,7 @@ importers: '@types/express': 4.17.20 '@types/express-ws': 3.0.3 '@types/mocha': 10.0.6 - '@types/node': 20.9.5 + '@types/node': 20.17.0 '@types/sinon': 17.0.2 '@types/supertest': 6.0.2 chai: 4.3.10 @@ -601,8 +601,8 @@ importers: '@itwin/core-quantity': link:../quantity '@itwin/eslint-plugin': 5.0.0-dev.1_aji6oyyaiulsuzmkdveqwiygte '@types/chai-as-promised': 7.1.0 - '@vitest/browser': 2.1.1_bbcqthgmodi4rrojsqljgj3bpm - '@vitest/coverage-v8': 2.1.1_vvzb4akewk7qhprv5gsu3bguym + '@vitest/browser': 2.1.0_bbcqthgmodi4rrojsqljgj3bpm + '@vitest/coverage-v8': 2.1.0_qvp2nat4f5x6c53yn4p7pzv3mu babel-loader: 8.2.5_webpack@5.97.1 babel-plugin-istanbul: 6.1.1 cpx2: 3.0.0 @@ -615,7 +615,7 @@ importers: typescript: 5.6.2 vite-multiple-assets: 1.3.1 vite-plugin-static-copy: 1.0.6 - vitest: 2.1.0_@vitest+browser@2.1.1 + vitest: 2.1.0_@vitest+browser@2.1.0 webpack: 5.97.1 ../../core/frontend-devtools: @@ -653,7 +653,7 @@ importers: '@itwin/core-bentley': workspace:* '@itwin/eslint-plugin': 5.0.0-dev.1 '@types/flatbuffers': ~1.10.0 - '@types/node': ~20.9.5 + '@types/node': ~20.17.0 '@vitest/coverage-v8': ^2.1.0 eslint: ^9.13.0 flatbuffers: ~1.12.0 @@ -667,12 +667,12 @@ importers: '@itwin/build-tools': link:../../tools/build '@itwin/eslint-plugin': 5.0.0-dev.1_aji6oyyaiulsuzmkdveqwiygte '@types/flatbuffers': 1.10.0 - '@types/node': 20.9.5 - '@vitest/coverage-v8': 2.1.1_vitest@2.1.0 + '@types/node': 20.17.0 + '@vitest/coverage-v8': 2.1.0_vitest@2.1.0 eslint: 9.13.0 rimraf: 3.0.2 typescript: 5.6.2 - vitest: 2.1.0_@types+node@20.9.5 + vitest: 2.1.0_@types+node@20.17.0 ../../core/hypermodeling: specifiers: @@ -734,7 +734,7 @@ importers: '@types/i18next': ^8.4.2 '@types/i18next-browser-languagedetector': ^2.0.1 '@types/mocha': ^10.0.6 - '@types/node': ~20.9.5 + '@types/node': ~20.17.0 babel-loader: ~8.2.5 babel-plugin-istanbul: ~6.1.1 chai: ^4.3.10 @@ -762,7 +762,7 @@ importers: '@types/i18next': 8.4.2 '@types/i18next-browser-languagedetector': 2.0.1 '@types/mocha': 10.0.6 - '@types/node': 20.9.5 + '@types/node': 20.17.0 babel-loader: 8.2.5_webpack@5.97.1 babel-plugin-istanbul: 6.1.1 chai: 4.3.10 @@ -835,7 +835,7 @@ importers: '@types/fs-extra': ^4.0.7 '@types/lodash': ^4.14.202 '@types/mocha': ^10.0.6 - '@types/node': ~20.9.5 + '@types/node': ~20.17.0 '@types/superagent': ^8.1.6 '@types/ws': ^7.0.0 chai: ^4.3.10 @@ -864,7 +864,7 @@ importers: '@types/fs-extra': 4.0.7 '@types/lodash': 4.14.202 '@types/mocha': 10.0.6 - '@types/node': 20.9.5 + '@types/node': 20.17.0 '@types/superagent': 8.1.6 '@types/ws': 7.2.0 chai: 4.3.10 @@ -883,7 +883,7 @@ importers: '@itwin/eslint-plugin': 5.0.0-dev.1 '@types/chai': 4.3.1 '@types/mocha': ^10.0.6 - '@types/node': ~20.9.5 + '@types/node': ~20.17.0 chai: ^4.3.10 cpx2: ^3.0.0 debug: ^2.6.9 @@ -898,7 +898,7 @@ importers: '@itwin/eslint-plugin': 5.0.0-dev.1_aji6oyyaiulsuzmkdveqwiygte '@types/chai': 4.3.1 '@types/mocha': 10.0.6 - '@types/node': 20.9.5 + '@types/node': 20.17.0 chai: 4.3.10 cpx2: 3.0.0 debug: 2.6.9 @@ -1024,7 +1024,7 @@ importers: '@types/chai': 4.3.1 '@types/fs-extra': ^4.0.7 '@types/mocha': ^10.0.6 - '@types/node': ~20.9.5 + '@types/node': ~20.17.0 '@types/semver': 7.3.10 chai: ^4.3.10 cpx2: ^3.0.0 @@ -1043,7 +1043,7 @@ importers: '@types/chai': 4.3.1 '@types/fs-extra': 4.0.7 '@types/mocha': 10.0.6 - '@types/node': 20.9.5 + '@types/node': 20.17.0 '@types/semver': 7.3.10 chai: 4.3.10 cpx2: 3.0.0 @@ -1065,7 +1065,7 @@ importers: '@types/chai': 4.3.1 '@types/fs-extra': ^4.0.7 '@types/mocha': ^10.0.6 - '@types/node': ~20.9.5 + '@types/node': ~20.17.0 chai: ^4.3.10 cpx2: ^3.0.0 eslint: ^9.13.0 @@ -1083,7 +1083,7 @@ importers: '@types/chai': 4.3.1 '@types/fs-extra': 4.0.7 '@types/mocha': 10.0.6 - '@types/node': 20.9.5 + '@types/node': 20.17.0 chai: 4.3.10 cpx2: 3.0.0 eslint: 9.13.0 @@ -1132,7 +1132,7 @@ importers: '@types/chai': 4.3.1 '@types/fs-extra': ^4.0.7 '@types/mocha': ^10.0.6 - '@types/node': ~20.9.5 + '@types/node': ~20.17.0 chai: ^4.3.10 eslint: ^9.13.0 mocha: ^10.2.0 @@ -1148,7 +1148,7 @@ importers: '@types/chai': 4.3.1 '@types/fs-extra': 4.0.7 '@types/mocha': 10.0.6 - '@types/node': 20.9.5 + '@types/node': 20.17.0 chai: 4.3.10 eslint: 9.13.0 mocha: 10.2.0 @@ -1253,7 +1253,7 @@ importers: '@itwin/oidc-signin-tool': ^4.4.0 '@types/chai': 4.3.1 '@types/mocha': ^10.0.6 - '@types/node': ~20.9.5 + '@types/node': ~20.17.0 chai: ^4.3.10 cpx2: ^3.0.0 electron: ^33.0.0 @@ -1275,7 +1275,7 @@ importers: '@itwin/oidc-signin-tool': 4.4.0_67wltvhdskk2oee2c3z2o4tfly '@types/chai': 4.3.1 '@types/mocha': 10.0.6 - '@types/node': 20.9.5 + '@types/node': 20.17.0 chai: 4.3.10 cpx2: 3.0.0 eslint: 9.13.0 @@ -1305,7 +1305,7 @@ importers: '@types/chai-as-promised': ^7 '@types/fs-extra': ^4.0.7 '@types/mocha': ^10.0.6 - '@types/node': ~20.9.5 + '@types/node': ~20.17.0 '@xmldom/xmldom': ~0.8.5 azurite: ^3.32.0 chai: ^4.3.10 @@ -1343,7 +1343,7 @@ importers: '@types/chai-as-promised': 7.1.0 '@types/fs-extra': 4.0.7 '@types/mocha': 10.0.6 - '@types/node': 20.9.5 + '@types/node': 20.17.0 chai: 4.3.10 chai-as-promised: 7.1.1_chai@4.3.10 cpx2: 3.0.0 @@ -1366,7 +1366,7 @@ importers: '@types/chai': 4.3.1 '@types/chai-as-promised': ^7 '@types/mocha': ^10.0.6 - '@types/node': ~20.9.5 + '@types/node': ~20.17.0 '@types/sinon': ^17.0.2 babel-loader: ~8.2.5 babel-plugin-istanbul: ~6.1.1 @@ -1391,7 +1391,7 @@ importers: '@types/chai': 4.3.1 '@types/chai-as-promised': 7.1.0 '@types/mocha': 10.0.6 - '@types/node': 20.9.5 + '@types/node': 20.17.0 '@types/sinon': 17.0.2 babel-loader: 8.2.5_webpack@5.97.1 babel-plugin-istanbul: 6.1.1 @@ -1689,7 +1689,7 @@ importers: '@types/chai-as-promised': ^7 '@types/fs-extra': ^4.0.7 '@types/mocha': ^10.0.6 - '@types/node': ~20.9.5 + '@types/node': ~20.17.0 '@types/sinon': ^17.0.2 '@types/sinon-chai': ^3.2.0 assert: ^2.0.0 @@ -1766,7 +1766,7 @@ importers: '@types/chai-as-promised': 7.1.0 '@types/fs-extra': 4.0.7 '@types/mocha': 10.0.6 - '@types/node': 20.9.5 + '@types/node': 20.17.0 '@types/sinon': 17.0.2 '@types/sinon-chai': 3.2.0 assert: 2.0.0 @@ -1820,7 +1820,7 @@ importers: '@types/chai': 4.3.1 '@types/chai-as-promised': ^7 '@types/mocha': ^10.0.6 - '@types/node': ~20.9.5 + '@types/node': ~20.17.0 assert: ^2.0.0 browserify-zlib: ^0.2.0 chai: ^4.3.10 @@ -1874,7 +1874,7 @@ importers: '@types/chai': 4.3.1 '@types/chai-as-promised': 7.1.0 '@types/mocha': 10.0.6 - '@types/node': 20.9.5 + '@types/node': 20.17.0 assert: 2.0.0 browserify-zlib: 0.2.0 cpx2: 3.0.0 @@ -1916,7 +1916,7 @@ importers: '@types/deep-equal': ^1 '@types/faker': ^4.1.0 '@types/mocha': ^10.0.6 - '@types/node': ~20.9.5 + '@types/node': ~20.17.0 '@types/rimraf': ^2.0.2 '@types/sinon': ^17.0.2 '@types/sinon-chai': ^3.2.0 @@ -1970,7 +1970,7 @@ importers: '@types/deep-equal': 1.0.0 '@types/faker': 4.1.0 '@types/mocha': 10.0.6 - '@types/node': 20.9.5 + '@types/node': 20.17.0 '@types/rimraf': 2.0.2 '@types/sinon': 17.0.2 '@types/sinon-chai': 3.2.0 @@ -2021,7 +2021,7 @@ importers: '@types/chai': 4.3.1 '@types/express': ^4.17.20 '@types/mocha': ^10.0.6 - '@types/node': ~20.9.5 + '@types/node': ~20.17.0 '@types/semver': 7.3.10 '@types/spdy': ^3.4.4 assert: ^2.0.0 @@ -2060,7 +2060,7 @@ importers: '@types/chai': 4.3.1 '@types/express': 4.17.20 '@types/mocha': 10.0.6 - '@types/node': 20.9.5 + '@types/node': 20.17.0 '@types/semver': 7.3.10 '@types/spdy': 3.4.4 assert: 2.0.0 @@ -2102,7 +2102,7 @@ importers: '@types/chai': 4.3.1 '@types/chai-as-promised': ^7 '@types/mocha': ^10.0.6 - '@types/node': ~20.9.5 + '@types/node': ~20.17.0 assert: ^2.0.0 browserify-zlib: ^0.2.0 buffer: ^6.0.3 @@ -2156,7 +2156,7 @@ importers: '@types/chai': 4.3.1 '@types/chai-as-promised': 7.1.0 '@types/mocha': 10.0.6 - '@types/node': 20.9.5 + '@types/node': 20.17.0 assert: 2.0.0 browserify-zlib: 0.2.0 buffer: 6.0.3 @@ -2193,7 +2193,7 @@ importers: '@types/faker': ^4.1.0 '@types/lolex': ^2.1.2 '@types/mocha': ^10.0.6 - '@types/node': ~20.9.5 + '@types/node': ~20.17.0 '@types/object-hash': ^1.3.0 '@types/semver': 7.3.10 '@types/sinon': ^17.0.2 @@ -2245,7 +2245,7 @@ importers: '@types/faker': 4.1.0 '@types/lolex': 2.1.2 '@types/mocha': 10.0.6 - '@types/node': 20.9.5 + '@types/node': 20.17.0 '@types/object-hash': 1.3.0 '@types/semver': 7.3.10 '@types/sinon': 17.0.2 @@ -2462,7 +2462,7 @@ importers: '@itwin/reality-data-client': ^1.2.1 '@types/body-parser': ^1.17.0 '@types/express': ^4.17.20 - '@types/node': ~20.9.5 + '@types/node': ~20.17.0 '@typescript-eslint/parser': ~8.11.0 body-parser: ^1.20.3 browserslist-to-esbuild: ^1.2.0 @@ -2517,7 +2517,7 @@ importers: '@itwin/perf-tools': link:../../tools/perf-tools '@types/body-parser': 1.17.0 '@types/express': 4.17.20 - '@types/node': 20.9.5 + '@types/node': 20.17.0 '@typescript-eslint/parser': 8.11.0_aji6oyyaiulsuzmkdveqwiygte browserslist-to-esbuild: 1.2.0 child_process: 1.0.2 @@ -2540,7 +2540,7 @@ importers: rollup-plugin-visualizer: 5.9.2 rollup-plugin-webpack-stats: 0.2.0 typescript: 5.6.2 - vite: 5.4.6_@types+node@20.9.5 + vite: 5.4.6_@types+node@20.17.0 vite-plugin-env-compatible: 2.0.1 vite-plugin-inspect: 0.8.4_vite@5.4.6 webpack: 5.97.1 @@ -2581,7 +2581,7 @@ importers: '@types/express': ^4.17.20 '@types/express-ws': ^3.0.3 '@types/fs-extra': ^4.0.7 - '@types/node': ~20.9.5 + '@types/node': ~20.17.0 '@typescript-eslint/parser': ~8.11.0 body-parser: ^1.20.3 browserslist-to-esbuild: ^1.2.0 @@ -2650,7 +2650,7 @@ importers: '@types/express': 4.17.20 '@types/express-ws': 3.0.3 '@types/fs-extra': 4.0.7 - '@types/node': 20.9.5 + '@types/node': 20.17.0 '@typescript-eslint/parser': 8.11.0_aji6oyyaiulsuzmkdveqwiygte browserslist-to-esbuild: 1.2.0 child_process: 1.0.2 @@ -2675,7 +2675,7 @@ importers: rollup-plugin-visualizer: 5.9.2 rollup-plugin-webpack-stats: 0.2.0 typescript: 5.6.2 - vite: 5.4.6_@types+node@20.9.5 + vite: 5.4.6_@types+node@20.17.0 vite-plugin-env-compatible: 2.0.1 vite-plugin-inspect: 0.8.4_vite@5.4.6 webpack: 5.97.1 @@ -2688,7 +2688,7 @@ importers: '@itwin/core-common': workspace:* '@itwin/core-geometry': workspace:* '@itwin/eslint-plugin': 5.0.0-dev.1 - '@types/node': ~20.9.5 + '@types/node': ~20.17.0 '@types/yargs': 17.0.19 eslint: ^9.13.0 rimraf: ^3.0.2 @@ -2703,7 +2703,7 @@ importers: devDependencies: '@itwin/build-tools': link:../../tools/build '@itwin/eslint-plugin': 5.0.0-dev.1_aji6oyyaiulsuzmkdveqwiygte - '@types/node': 20.9.5 + '@types/node': 20.17.0 '@types/yargs': 17.0.19 eslint: 9.13.0 rimraf: 3.0.2 @@ -2719,7 +2719,7 @@ importers: '@itwin/eslint-plugin': 5.0.0-dev.1 '@types/chai': 4.3.1 '@types/mocha': ^10.0.6 - '@types/node': ~20.9.5 + '@types/node': ~20.17.0 '@types/yargs': 17.0.19 chai: ^4.3.10 eslint: ^9.13.0 @@ -2739,7 +2739,7 @@ importers: '@itwin/eslint-plugin': 5.0.0-dev.1_aji6oyyaiulsuzmkdveqwiygte '@types/chai': 4.3.1 '@types/mocha': 10.0.6 - '@types/node': 20.9.5 + '@types/node': 20.17.0 '@types/yargs': 17.0.19 eslint: 9.13.0 mocha: 10.2.0 @@ -2756,7 +2756,7 @@ importers: '@itwin/eslint-plugin': 5.0.0-dev.1 '@types/fs-extra': ^4.0.7 '@types/lodash': ^4.14.202 - '@types/node': ~20.9.5 + '@types/node': ~20.17.0 '@types/yargs': 17.0.19 eslint: ^9.13.0 fs-extra: ^8.1.0 @@ -2775,7 +2775,7 @@ importers: '@itwin/eslint-plugin': 5.0.0-dev.1_aji6oyyaiulsuzmkdveqwiygte '@types/fs-extra': 4.0.7 '@types/lodash': 4.14.202 - '@types/node': 20.9.5 + '@types/node': 20.17.0 '@types/yargs': 17.0.19 eslint: 9.13.0 rimraf: 3.0.2 @@ -2791,7 +2791,7 @@ importers: '@itwin/core-orbitgt': workspace:* '@itwin/eslint-plugin': 5.0.0-dev.1 '@types/fs-extra': ^4.0.7 - '@types/node': ~20.9.5 + '@types/node': ~20.17.0 '@types/yargs': 17.0.19 eslint: ^9.13.0 rimraf: ^3.0.2 @@ -2808,7 +2808,7 @@ importers: '@itwin/build-tools': link:../../tools/build '@itwin/eslint-plugin': 5.0.0-dev.1_aji6oyyaiulsuzmkdveqwiygte '@types/fs-extra': 4.0.7 - '@types/node': 20.9.5 + '@types/node': 20.17.0 '@types/yargs': 17.0.19 eslint: 9.13.0 rimraf: 3.0.2 @@ -2824,7 +2824,7 @@ importers: '@itwin/eslint-plugin': 5.0.0-dev.1 '@types/fs-extra': ^4.0.7 '@types/lodash': ^4.14.202 - '@types/node': ~20.9.5 + '@types/node': ~20.17.0 '@types/yargs': 17.0.19 eslint: ^9.13.0 fs-extra: ^8.1.0 @@ -2843,7 +2843,7 @@ importers: '@itwin/eslint-plugin': 5.0.0-dev.1_aji6oyyaiulsuzmkdveqwiygte '@types/fs-extra': 4.0.7 '@types/lodash': 4.14.202 - '@types/node': 20.9.5 + '@types/node': 20.17.0 '@types/yargs': 17.0.19 eslint: 9.13.0 rimraf: 3.0.2 @@ -2853,7 +2853,7 @@ importers: specifiers: '@itwin/eslint-plugin': 5.0.0-dev.1 '@microsoft/api-extractor': ~7.47.10 - '@types/node': ~20.9.5 + '@types/node': ~20.17.0 chalk: ^3.0.0 cpx2: ^3.0.0 cross-spawn: ^7.0.5 @@ -2870,7 +2870,7 @@ importers: wtfnode: ^0.9.1 yargs: ^17.4.0 dependencies: - '@microsoft/api-extractor': 7.47.10_@types+node@20.9.5 + '@microsoft/api-extractor': 7.47.10_@types+node@20.17.0 chalk: 3.0.0 cpx2: 3.0.0 cross-spawn: 7.0.5 @@ -2887,7 +2887,7 @@ importers: yargs: 17.4.0 devDependencies: '@itwin/eslint-plugin': 5.0.0-dev.1_aji6oyyaiulsuzmkdveqwiygte - '@types/node': 20.9.5 + '@types/node': 20.17.0 eslint: 9.13.0 ../../tools/certa: @@ -2899,7 +2899,7 @@ importers: '@types/express': ^4.17.20 '@types/lodash': ^4.14.202 '@types/mocha': ^10.0.6 - '@types/node': ~20.9.5 + '@types/node': ~20.17.0 '@types/yargs': 17.0.19 canonical-path: ^1.0.0 detect-port: ~1.3.0 @@ -2933,7 +2933,7 @@ importers: '@types/express': 4.17.20 '@types/lodash': 4.14.202 '@types/mocha': 10.0.6 - '@types/node': 20.9.5 + '@types/node': 20.17.0 '@types/yargs': 17.0.19 electron: 33.0.0 eslint: 9.13.0 @@ -2955,7 +2955,7 @@ importers: '@types/chai-string': ^1.4.1 '@types/fs-extra': ^4.0.7 '@types/mocha': ^10.0.6 - '@types/node': ~20.9.5 + '@types/node': ~20.17.0 '@xmldom/xmldom': ~0.8.5 chai: ^4.3.10 chai-string: ^1.5.0 @@ -2988,7 +2988,7 @@ importers: '@types/chai-string': 1.4.1 '@types/fs-extra': 4.0.7 '@types/mocha': 10.0.6 - '@types/node': 20.9.5 + '@types/node': 20.17.0 chai: 4.3.10 cpx2: 3.0.0 eslint: 9.13.0 @@ -3374,7 +3374,7 @@ packages: '@babel/traverse': 7.25.3 '@babel/types': 7.25.6 convert-source-map: 2.0.0 - debug: 4.3.6 + debug: 4.4.0 gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -3498,7 +3498,7 @@ packages: '@babel/parser': 7.25.6 '@babel/template': 7.25.0 '@babel/types': 7.25.6 - debug: 4.3.6 + debug: 4.4.0 globals: 11.12.0 transitivePeerDependencies: - supports-color @@ -3645,10 +3645,10 @@ packages: resolution: {integrity: sha512-mib0MBPNxT6xS1Spihn/VZeYGRvhbfjZ/O2/FaRDHc9J3dymtCqL/1Q/iTY5fscqUWvr9TdJjx+ICPmb5Wr4HQ==} dev: true - /@bundled-es-modules/cookie/2.0.0: - resolution: {integrity: sha512-Or6YHg/kamKHpxULAdSqhGqnWFneIXu1NKvvfBBzKGwpVsYuFIQ5aBPHDnnoR3ghW1nvSkALd+EF9iMtY7Vjxw==} + /@bundled-es-modules/cookie/2.0.1: + resolution: {integrity: sha512-8o+5fRPLNbjbdGRRmJj3h6Hh1AQJf2dk3qQ/5ZFb+PXkRNiSoMGGUKlsgLfrxneb72axVJyIYji64E2+nNfYyw==} dependencies: - cookie: 0.5.0 + cookie: 0.7.2 dev: true /@bundled-es-modules/statuses/1.0.1: @@ -3693,7 +3693,7 @@ packages: resolution: {integrity: sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ==} engines: {node: '>=12'} dependencies: - debug: 4.3.6 + debug: 4.4.0 env-paths: 2.2.1 fs-extra: 8.1.0 got: 11.8.6 @@ -3938,7 +3938,7 @@ packages: engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} dependencies: '@eslint/object-schema': 2.1.4 - debug: 4.3.6 + debug: 4.4.0 minimatch: 3.1.2 transitivePeerDependencies: - supports-color @@ -3952,7 +3952,7 @@ packages: engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} dependencies: ajv: 6.12.6 - debug: 4.3.6 + debug: 4.4.0 espree: 10.2.0 globals: 14.0.0 ignore: 5.3.2 @@ -3996,49 +3996,49 @@ packages: resolution: {integrity: sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==} engines: {node: '>=18.18'} - /@inquirer/confirm/3.2.0: - resolution: {integrity: sha512-oOIwPs0Dvq5220Z8lGL/6LHRTEr9TgLHmiI99Rj1PJ1p1czTys+olrgBqZk4E2qC0YTzeHprxSQmoHioVdJ7Lw==} + /@inquirer/confirm/5.1.0: + resolution: {integrity: sha512-osaBbIMEqVFjTX5exoqPXs6PilWQdjaLhGtMDXMXg/yxkHXNq43GlxGyTA35lK2HpzUgDN+Cjh/2AmqCN0QJpw==} engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true dependencies: - '@inquirer/core': 9.2.1 - '@inquirer/type': 1.5.5 + '@inquirer/core': 10.1.1 + '@inquirer/type': 3.0.1 dev: true - /@inquirer/core/9.2.1: - resolution: {integrity: sha512-F2VBt7W/mwqEU4bL0RnHNZmC/OxzNx9cOYxHqnXX3MP6ruYvZUZAW9imgN9+h/uBT/oP8Gh888J2OZSbjSeWcg==} + /@inquirer/core/10.1.1: + resolution: {integrity: sha512-rmZVXy9iZvO3ZStEe/ayuuwIJ23LSF13aPMlLMTQARX6lGUBDHGV8UB5i9MRrfy0+mZwt5/9bdy8llszSD3NQA==} engines: {node: '>=18'} dependencies: - '@inquirer/figures': 1.0.6 - '@inquirer/type': 2.0.0 - '@types/mute-stream': 0.0.4 - '@types/node': 22.7.4 - '@types/wrap-ansi': 3.0.0 + '@inquirer/figures': 1.0.8 + '@inquirer/type': 3.0.1 ansi-escapes: 4.3.2 cli-width: 4.1.0 - mute-stream: 1.0.0 + mute-stream: 2.0.0 signal-exit: 4.1.0 strip-ansi: 6.0.1 wrap-ansi: 6.2.0 yoctocolors-cjs: 2.1.2 + transitivePeerDependencies: + - '@types/node' dev: true - /@inquirer/figures/1.0.6: - resolution: {integrity: sha512-yfZzps3Cso2UbM7WlxKwZQh2Hs6plrbjs1QnzQDZhK2DgyCo6D8AaHps9olkNcUFlcYERMqU3uJSp1gmy3s/qQ==} - engines: {node: '>=18'} - dev: true - - /@inquirer/type/1.5.5: - resolution: {integrity: sha512-MzICLu4yS7V8AA61sANROZ9vT1H3ooca5dSmI1FjZkzq7o/koMsRfQSzRtFo+F3Ao4Sf1C0bpLKejpKB/+j6MA==} + /@inquirer/figures/1.0.8: + resolution: {integrity: sha512-tKd+jsmhq21AP1LhexC0pPwsCxEhGgAkg28byjJAd+xhmIs8LUX8JbUc3vBf3PhLxWiB5EvyBE5X7JSPAqMAqg==} engines: {node: '>=18'} - dependencies: - mute-stream: 1.0.0 dev: true - /@inquirer/type/2.0.0: - resolution: {integrity: sha512-XvJRx+2KR3YXyYtPUUy+qd9i7p+GO9Ko6VIIpWlBrpWwXDv8WLFeHTxz35CfQFUiBMLXlGHhGzys7lqit9gWag==} + /@inquirer/type/3.0.1: + resolution: {integrity: sha512-+ksJMIy92sOAiAccGpcKZUc3bYO07cADnscIxHBknEm3uNts3movSmBofc1908BNy5edKscxYeAdaX1NXkHS6A==} engines: {node: '>=18'} - dependencies: - mute-stream: 1.0.0 + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true dev: true /@isaacs/cliui/8.0.2: @@ -4109,8 +4109,8 @@ packages: reflect-metadata: 0.1.13 dev: false - /@itwin/core-bentley/4.9.5: - resolution: {integrity: sha512-2cFqJnWKdGyNgZziqYHg4KkYVXD3+f4WQ5xhVPkEYffcOpXXz4yFh8nDOZmhgOLAmJo6KDH2x+uNJembcX6wjQ==} + /@itwin/core-bentley/4.9.7: + resolution: {integrity: sha512-c/A0UT+slQTIFMsLon4haYmey/vpdP+MJrly4SaEgC0WHTo06t3qYf0342F3F15DmsnqC2n2DDNx6/n6pUPqOg==} dev: false /@itwin/core-common/4.8.1_67wltvhdskk2oee2c3z2o4tfly: @@ -4341,7 +4341,7 @@ packages: /@itwin/presentation-shared/1.1.0: resolution: {integrity: sha512-H0NiWIYpxPSg4bJdQdSo4epdFUqoza/4UEbRj6nin906Mr2oKWu7Jep9OLbFXTmarMtP+q+5iSlp/eTRhTc/Cg==} dependencies: - '@itwin/core-bentley': 4.9.5 + '@itwin/core-bentley': 4.9.7 dev: false /@itwin/reality-data-client/1.2.1_mdtbcqczpmeuv6yjzfaigjndwi: @@ -4389,7 +4389,7 @@ packages: /@itwin/unified-selection/1.1.1: resolution: {integrity: sha512-myygzispTehbgeZBFbOipyt3AvTr9Lx+QvP5hPG3YKyEvGimAtO3Mh6unwmdCxrM9Ue9w5El63Jbr0N+f+ZdVg==} dependencies: - '@itwin/core-bentley': 4.9.5 + '@itwin/core-bentley': 4.9.7 '@itwin/presentation-shared': 1.1.0 rxjs: 7.8.1 rxjs-for-await: 1.0.0_rxjs@7.8.1 @@ -4477,27 +4477,27 @@ packages: '@babel/runtime': 7.25.0 dev: false - /@microsoft/api-extractor-model/7.29.8_@types+node@20.9.5: + /@microsoft/api-extractor-model/7.29.8_@types+node@20.17.0: resolution: {integrity: sha512-t3Z/xcO6TRbMcnKGVMs4uMzv/gd5j0NhMiJIGjD4cJMeFJ1Hf8wnLSx37vxlRlL0GWlGJhnFgxvnaL6JlS+73g==} dependencies: '@microsoft/tsdoc': 0.15.0 '@microsoft/tsdoc-config': 0.17.0 - '@rushstack/node-core-library': 5.9.0_@types+node@20.9.5 + '@rushstack/node-core-library': 5.9.0_@types+node@20.17.0 transitivePeerDependencies: - '@types/node' dev: false - /@microsoft/api-extractor/7.47.10_@types+node@20.9.5: + /@microsoft/api-extractor/7.47.10_@types+node@20.17.0: resolution: {integrity: sha512-Fx5J3E8sC5EUeqaC85NXql3hXJc7/QO3NEr/jeBgVJwacRaHdkl3pKDhkkJ6yo/GWbRCv6QnyakU0QuKg8bMig==} hasBin: true dependencies: - '@microsoft/api-extractor-model': 7.29.8_@types+node@20.9.5 + '@microsoft/api-extractor-model': 7.29.8_@types+node@20.17.0 '@microsoft/tsdoc': 0.15.0 '@microsoft/tsdoc-config': 0.17.0 - '@rushstack/node-core-library': 5.9.0_@types+node@20.9.5 + '@rushstack/node-core-library': 5.9.0_@types+node@20.17.0 '@rushstack/rig-package': 0.5.3 - '@rushstack/terminal': 0.14.2_@types+node@20.9.5 - '@rushstack/ts-command-line': 4.22.8_@types+node@20.9.5 + '@rushstack/terminal': 0.14.2_@types+node@20.17.0 + '@rushstack/ts-command-line': 4.22.8_@types+node@20.17.0 lodash: 4.17.21 minimatch: 3.0.8 resolve: 1.22.8 @@ -4521,8 +4521,8 @@ packages: resolution: {integrity: sha512-HZpPoABogPvjeJOdzCOSJsXeL/SMCBgBZMVC3X3d7YYp2gf31MfxhUoYUNwf1ERPJOnQc0wkFn9trqI6ZEdZuA==} dev: false - /@mswjs/interceptors/0.35.9: - resolution: {integrity: sha512-SSnyl/4ni/2ViHKkiZb8eajA/eN1DNFaHjhGiLUdZvDz6PKF4COSf/17xqSz64nOo2Ia29SA6B2KNCsyCbVmaQ==} + /@mswjs/interceptors/0.37.3: + resolution: {integrity: sha512-USvgCL/uOGFtVa6SVyRrC8kIAedzRohxIXN5LISlg5C5vLZCn7dgMFVSNhSF9cuBEFrm/O2spDWEZeMnw4ZXYg==} engines: {node: '>=18'} dependencies: '@open-draft/deferred-promise': 2.2.0 @@ -4786,7 +4786,7 @@ packages: /@rtsao/scc/1.1.0: resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} - /@rushstack/node-core-library/5.9.0_@types+node@20.9.5: + /@rushstack/node-core-library/5.9.0_@types+node@20.17.0: resolution: {integrity: sha512-MMsshEWkTbXqxqFxD4gcIUWQOCeBChlGczdZbHfqmNZQFLHB3yWxDFSMHFUdu2/OB9NUk7Awn5qRL+rws4HQNg==} peerDependencies: '@types/node': '*' @@ -4794,7 +4794,7 @@ packages: '@types/node': optional: true dependencies: - '@types/node': 20.9.5 + '@types/node': 20.17.0 ajv: 8.13.0 ajv-draft-04: 1.0.0_ajv@8.13.0 ajv-formats: 3.0.1 @@ -4812,7 +4812,7 @@ packages: strip-json-comments: 3.1.1 dev: false - /@rushstack/terminal/0.14.2_@types+node@20.9.5: + /@rushstack/terminal/0.14.2_@types+node@20.17.0: resolution: {integrity: sha512-2fC1wqu1VCExKC0/L+0noVcFQEXEnoBOtCIex1TOjBzEDWcw8KzJjjj7aTP6mLxepG0XIyn9OufeFb6SFsa+sg==} peerDependencies: '@types/node': '*' @@ -4820,15 +4820,15 @@ packages: '@types/node': optional: true dependencies: - '@rushstack/node-core-library': 5.9.0_@types+node@20.9.5 - '@types/node': 20.9.5 + '@rushstack/node-core-library': 5.9.0_@types+node@20.17.0 + '@types/node': 20.17.0 supports-color: 8.1.1 dev: false - /@rushstack/ts-command-line/4.22.8_@types+node@20.9.5: + /@rushstack/ts-command-line/4.22.8_@types+node@20.17.0: resolution: {integrity: sha512-XbFjOoV7qZHJnSuFUHv0pKaFA4ixyCuki+xMjsMfDwfvQjs5MYG0IK5COal3tRnG7KCDe2l/G+9LrzYE/RJhgg==} dependencies: - '@rushstack/terminal': 0.14.2_@types+node@20.9.5 + '@rushstack/terminal': 0.14.2_@types+node@20.17.0 '@types/argparse': 1.0.38 argparse: 1.0.10 string-argv: 0.3.2 @@ -4836,41 +4836,41 @@ packages: - '@types/node' dev: false - /@shikijs/core/1.23.1: - resolution: {integrity: sha512-NuOVgwcHgVC6jBVH5V7iblziw6iQbWWHrj5IlZI3Fqu2yx9awH7OIQkXIcsHsUmY19ckwSgUMgrqExEyP5A0TA==} + /@shikijs/core/1.24.2: + resolution: {integrity: sha512-BpbNUSKIwbKrRRA+BQj0BEWSw+8kOPKDJevWeSE/xIqGX7K0xrCZQ9kK0nnEQyrzsUoka1l81ZtJ2mGaCA32HQ==} dependencies: - '@shikijs/engine-javascript': 1.23.1 - '@shikijs/engine-oniguruma': 1.23.1 - '@shikijs/types': 1.23.1 - '@shikijs/vscode-textmate': 9.3.0 + '@shikijs/engine-javascript': 1.24.2 + '@shikijs/engine-oniguruma': 1.24.2 + '@shikijs/types': 1.24.2 + '@shikijs/vscode-textmate': 9.3.1 '@types/hast': 3.0.4 hast-util-to-html: 9.0.3 dev: false - /@shikijs/engine-javascript/1.23.1: - resolution: {integrity: sha512-i/LdEwT5k3FVu07SiApRFwRcSJs5QM9+tod5vYCPig1Ywi8GR30zcujbxGQFJHwYD7A5BUqagi8o5KS+LEVgBg==} + /@shikijs/engine-javascript/1.24.2: + resolution: {integrity: sha512-EqsmYBJdLEwEiO4H+oExz34a5GhhnVp+jH9Q/XjPjmBPc6TE/x4/gD0X3i0EbkKKNqXYHHJTJUpOLRQNkEzS9Q==} dependencies: - '@shikijs/types': 1.23.1 - '@shikijs/vscode-textmate': 9.3.0 - oniguruma-to-es: 0.4.1 + '@shikijs/types': 1.24.2 + '@shikijs/vscode-textmate': 9.3.1 + oniguruma-to-es: 0.7.0 dev: false - /@shikijs/engine-oniguruma/1.23.1: - resolution: {integrity: sha512-KQ+lgeJJ5m2ISbUZudLR1qHeH3MnSs2mjFg7bnencgs5jDVPeJ2NVDJ3N5ZHbcTsOIh0qIueyAJnwg7lg7kwXQ==} + /@shikijs/engine-oniguruma/1.24.2: + resolution: {integrity: sha512-ZN6k//aDNWRJs1uKB12pturKHh7GejKugowOFGAuG7TxDRLod1Bd5JhpOikOiFqPmKjKEPtEA6mRCf7q3ulDyQ==} dependencies: - '@shikijs/types': 1.23.1 - '@shikijs/vscode-textmate': 9.3.0 + '@shikijs/types': 1.24.2 + '@shikijs/vscode-textmate': 9.3.1 dev: false - /@shikijs/types/1.23.1: - resolution: {integrity: sha512-98A5hGyEhzzAgQh2dAeHKrWW4HfCMeoFER2z16p5eJ+vmPeF6lZ/elEne6/UCU551F/WqkopqRsr1l2Yu6+A0g==} + /@shikijs/types/1.24.2: + resolution: {integrity: sha512-bdeWZiDtajGLG9BudI0AHet0b6e7FbR0EsE4jpGaI0YwHm/XJunI9+3uZnzFtX65gsyJ6ngCIWUfA4NWRPnBkQ==} dependencies: - '@shikijs/vscode-textmate': 9.3.0 + '@shikijs/vscode-textmate': 9.3.1 '@types/hast': 3.0.4 dev: false - /@shikijs/vscode-textmate/9.3.0: - resolution: {integrity: sha512-jn7/7ky30idSkd/O5yDBfAnVt+JJpepofP/POZ1iMOxK59cOfqIgg/Dj0eFsjOTMw+4ycJN0uhZH/Eb0bs/EUA==} + /@shikijs/vscode-textmate/9.3.1: + resolution: {integrity: sha512-79QfK1393x9Ho60QFyLti+QfdJzRQCVLFb97kOIV7Eo9vQU/roINgk7m24uv0a7AUvN//RDH36FLjjK48v0s9g==} dev: false /@sindresorhus/is/4.6.0: @@ -4986,14 +4986,14 @@ packages: resolution: {integrity: sha512-a2+YeUjPkztKJu5aIF2yArYFQQp8d51wZ7DavSHjFuY1mqVgidGyzEQ41JIVNy82fXj8yPgy2vJmfIywgESW6w==} dependencies: '@types/connect': 3.4.38 - '@types/node': 20.9.5 + '@types/node': 20.17.0 /@types/cacheable-request/6.0.3: resolution: {integrity: sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==} dependencies: '@types/http-cache-semantics': 4.0.4 '@types/keyv': 3.1.4 - '@types/node': 20.9.5 + '@types/node': 20.17.0 '@types/responselike': 1.0.3 /@types/chai-as-promised/7.1.0: @@ -5024,7 +5024,7 @@ packages: /@types/connect/3.4.38: resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} dependencies: - '@types/node': 20.9.5 + '@types/node': 20.17.0 /@types/cookie/0.6.0: resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==} @@ -5037,7 +5037,7 @@ packages: /@types/cpx/1.5.2: resolution: {integrity: sha512-CL9DbTAdf5NYcbYpBTli6JxVIpCAhJp1FeQiXd9SNjbC4o9k6McnHkU0FHgj9UYoN7TVX3poaaBrwFabTY7Skw==} dependencies: - '@types/node': 20.9.5 + '@types/node': 18.16.20 dev: false /@types/debug/4.1.12: @@ -5080,7 +5080,7 @@ packages: /@types/express-serve-static-core/4.19.5: resolution: {integrity: sha512-y6W03tvrACO72aijJ5uF02FRq5cgDR9lUxddQ8vyF+GvmjJQqbzDcJngEjURc+ZsG31VI3hODNZJ2URj86pzmg==} dependencies: - '@types/node': 20.9.5 + '@types/node': 20.17.0 '@types/qs': 6.9.15 '@types/range-parser': 1.2.7 '@types/send': 0.17.4 @@ -5115,13 +5115,13 @@ packages: /@types/fs-extra/4.0.7: resolution: {integrity: sha512-BN48b/2F3kL0Ual7tjcHjj0Fl+nuYKtHa0G/xT3Q43HuCpN7rQD5vIx6Aqnl9x10oBI5xMJh8Ly+FQpP205JlA==} dependencies: - '@types/node': 20.9.5 + '@types/node': 20.17.0 dev: true /@types/fs-extra/8.1.5: resolution: {integrity: sha512-0dzKcwO+S8s2kuF5Z9oUWatQJj5Uq/iqphEtE3GQJVRRYm/tD1LglU2UnXi2A8jLq5umkGouOXOR9y0n613ZwQ==} dependencies: - '@types/node': 20.9.5 + '@types/node': 20.17.0 dev: true /@types/geojson/7946.0.14: @@ -5136,13 +5136,13 @@ packages: dependencies: '@types/events': 3.0.3 '@types/minimatch': 5.1.2 - '@types/node': 20.9.5 + '@types/node': 20.17.0 /@types/glob/7.2.0: resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==} dependencies: '@types/minimatch': 5.1.2 - '@types/node': 20.9.5 + '@types/node': 20.17.0 dev: true /@types/google-protobuf/3.15.6: @@ -5184,12 +5184,12 @@ packages: /@types/jsonwebtoken/8.5.9: resolution: {integrity: sha512-272FMnFGzAVMGtu9tkr29hRL6bZj4Zs1KZNeHLnKqAvp06tAIcarTMwOh8/8bz4FmKRcMxZhZNeUAQsNLoiPhg==} dependencies: - '@types/node': 20.9.5 + '@types/node': 20.17.0 /@types/keyv/3.1.4: resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} dependencies: - '@types/node': 20.9.5 + '@types/node': 20.17.0 /@types/lodash/4.14.202: resolution: {integrity: sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ==} @@ -5225,34 +5225,26 @@ packages: /@types/multiparty/0.0.31: resolution: {integrity: sha512-cAFkeGKH55zJiYUjvXznQ3IdShi15VPcaDYxTm9a/lvLhD5dZgSrS+FmQvdS1/vFVIEolFGM1eZCB1avVpiN3w==} dependencies: - '@types/node': 20.9.5 - dev: true - - /@types/mute-stream/0.0.4: - resolution: {integrity: sha512-CPM9nzrCPPJHQNA9keH9CVkVI+WR5kMa+7XEs5jcGQ0VoAGnLv242w8lIVgwAEfmE4oufJRaTc9PNLQl0ioAow==} - dependencies: - '@types/node': 20.9.5 + '@types/node': 20.17.0 dev: true /@types/node/16.18.105: resolution: {integrity: sha512-w2d0Z9yMk07uH3+Cx0N8lqFyi3yjXZxlbYappPj+AsOlT02OyxyiuNoNHdGt6EuiSm8Wtgp2YV7vWg+GMFrvFA==} dev: true - /@types/node/20.9.5: - resolution: {integrity: sha512-Uq2xbNq0chGg+/WQEU0LJTSs/1nKxz6u1iemLcGomkSnKokbW1fbLqc3HOqCf2JP7KjlL4QkS7oZZTrOQHQYgQ==} - dependencies: - undici-types: 5.26.5 + /@types/node/18.16.20: + resolution: {integrity: sha512-nL54VfDjThdP2UXJXZao5wp76CDiDw4zSRO8d4Tk7UgDqNKGKVEQB0/t3ti63NS+YNNkIQDvwEAF04BO+WYu7Q==} + dev: false - /@types/node/22.7.4: - resolution: {integrity: sha512-y+NPi1rFzDs1NdQHHToqeiX2TIS79SWEAw9GYhkkx8bD0ChpfqC+n2j5OXOCpzfojBEBt6DnEnnG9MY0zk1XLg==} + /@types/node/20.17.0: + resolution: {integrity: sha512-a7zRo0f0eLo9K5X9Wp5cAqTUNGzuFLDG2R7C4HY2BhcMAsxgSPuRvAC1ZB6QkuUQXf0YZAgfOX2ZyrBa2n4nHQ==} dependencies: undici-types: 6.19.8 - dev: true /@types/object-hash/1.3.0: resolution: {integrity: sha512-il4NIe4jTx4lfhkKaksmmGHw5EsVkO8sHWkpJHM9m59r1dtsVadLSrJqdE8zU74NENDAsR3oLIOlooRAXlPLNA==} dependencies: - '@types/node': 20.9.5 + '@types/node': 20.17.0 dev: true /@types/qs/6.9.15: @@ -5264,20 +5256,20 @@ packages: /@types/readable-stream/4.0.15: resolution: {integrity: sha512-oAZ3kw+kJFkEqyh7xORZOku1YAKvsFTogRY8kVl4vHpEKiDkfnSA/My8haRE7fvmix5Zyy+1pwzOi7yycGLBJw==} dependencies: - '@types/node': 20.9.5 + '@types/node': 20.17.0 safe-buffer: 5.1.2 dev: false /@types/responselike/1.0.3: resolution: {integrity: sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==} dependencies: - '@types/node': 20.9.5 + '@types/node': 20.17.0 /@types/rimraf/2.0.2: resolution: {integrity: sha512-Hm/bnWq0TCy7jmjeN5bKYij9vw5GrDFWME4IuxV08278NtU/VdGbzsBohcCUJ7+QMqmUq5hpRKB39HeQWJjztQ==} dependencies: '@types/glob': 5.0.35 - '@types/node': 20.9.5 + '@types/node': 20.17.0 dev: false /@types/semver/7.3.10: @@ -5288,13 +5280,13 @@ packages: resolution: {integrity: sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==} dependencies: '@types/mime': 1.3.5 - '@types/node': 20.9.5 + '@types/node': 20.17.0 /@types/serve-static/1.15.7: resolution: {integrity: sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==} dependencies: '@types/http-errors': 2.0.4 - '@types/node': 20.9.5 + '@types/node': 20.17.0 '@types/send': 0.17.4 /@types/sinon-chai/3.2.0: @@ -5318,13 +5310,13 @@ packages: /@types/source-map-support/0.4.0: resolution: {integrity: sha512-9oVAi1Jlr274pbMGPEe0S3IPImV9knVNafa6E4MookD/fjOZAE6EmLkFX5ZjtZ9OXNPi2FCIZzUSMvwAUUKeSg==} dependencies: - '@types/node': 20.9.5 + '@types/node': 20.17.0 dev: true /@types/spdy/3.4.4: resolution: {integrity: sha512-N9LBlbVRRYq6HgYpPkqQc3a9HJ/iEtVZToW6xlTtJiMhmRJ7jJdV7TaZQJw/Ve/1ePUsQiCTDc4JMuzzag94GA==} dependencies: - '@types/node': 20.9.5 + '@types/node': 20.17.0 dev: true /@types/statuses/2.0.5: @@ -5336,7 +5328,7 @@ packages: dependencies: '@types/cookiejar': 2.1.5 '@types/methods': 1.1.4 - '@types/node': 20.9.5 + '@types/node': 20.17.0 dev: true /@types/supertest/6.0.2: @@ -5349,7 +5341,7 @@ packages: /@types/touch/3.1.2: resolution: {integrity: sha512-6YYYfTc90glAZBvyjpmz6JFLtBRyLWXckmlNgK4R2czsWg63cRCI9Rb3aKJ6LPbw8jpHf7nZdVvMd6gUg4hVsw==} dependencies: - '@types/node': 20.9.5 + '@types/node': 20.17.0 dev: true /@types/tough-cookie/4.0.5: @@ -5368,14 +5360,10 @@ packages: resolution: {integrity: sha512-nH45Lk7oPIJ1RVOF6JgFI6Dy0QpHEzq4QecZhvguxYPDwT8c93prCMqAtiIttm39voZ+DDR+qkNnMpJmMBRqag==} dev: false - /@types/wrap-ansi/3.0.0: - resolution: {integrity: sha512-ltIpx+kM7g/MLRZfkbL7EsCEjfzCcScLpkg37eXEtx5kmrAKBkTJwd1GIAjDSL8wTpM6Hzn5YO4pSb91BEwu1g==} - dev: true - /@types/ws/7.2.0: resolution: {integrity: sha512-HnqczxiZ828df9FUh9OyY7vSOelpQNaj+SLEnDvU74rYijp61ggV7dhmDlMky0oYXKLdVuIG4KvExk8DEqzJgQ==} dependencies: - '@types/node': 20.9.5 + '@types/node': 20.17.0 dev: true /@types/yargs-parser/21.0.3: @@ -5392,7 +5380,7 @@ packages: resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} requiresBuild: true dependencies: - '@types/node': 20.9.5 + '@types/node': 20.17.0 optional: true /@typescript-eslint/eslint-plugin/8.11.0_rim7n4kcr5hd64o3wd6nqnbvgi: @@ -5461,7 +5449,7 @@ packages: dependencies: '@typescript-eslint/typescript-estree': 8.11.0_typescript@5.6.2 '@typescript-eslint/utils': 8.11.0_aji6oyyaiulsuzmkdveqwiygte - debug: 4.3.6 + debug: 4.4.0 ts-api-utils: 1.3.0_typescript@5.6.2 typescript: 5.6.2 transitivePeerDependencies: @@ -5483,7 +5471,7 @@ packages: dependencies: '@typescript-eslint/types': 8.11.0 '@typescript-eslint/visitor-keys': 8.11.0 - debug: 4.3.6 + debug: 4.4.0 fast-glob: 3.3.2 is-glob: 4.0.3 minimatch: 9.0.5 @@ -5515,16 +5503,16 @@ packages: '@typescript-eslint/types': 8.11.0 eslint-visitor-keys: 3.4.3 - /@ungap/structured-clone/1.2.0: - resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} + /@ungap/structured-clone/1.2.1: + resolution: {integrity: sha512-fEzPV3hSkSMltkw152tJKNARhOupqbH96MZWyRjNaYZOMIzbrTeQDG+MTc6Mr2pgzFQzFxAfmhGDNP5QK++2ZA==} dev: false - /@vitest/browser/2.1.1_bbcqthgmodi4rrojsqljgj3bpm: - resolution: {integrity: sha512-wLKqohwlZI24xMIEZAPwv9SVliv1avaIBeE0ou471D++BRPhiw2mubKBczFFIDHXuSL7UXb8/JQK9Ui6ttW9bQ==} + /@vitest/browser/2.1.0_bbcqthgmodi4rrojsqljgj3bpm: + resolution: {integrity: sha512-A75cB40Uv8Q0dSo1vHsCkiMUZwjFyd/BkqfgiaHvNltjAbZ0XGX+VvMtWd/zne+1lfwg32pv+JVYZP8Oagb+ng==} peerDependencies: playwright: '*' safaridriver: '*' - vitest: 2.1.1 + vitest: 2.1.0 webdriverio: '*' peerDependenciesMeta: playwright: @@ -5536,71 +5524,72 @@ packages: dependencies: '@testing-library/dom': 10.4.0 '@testing-library/user-event': 14.5.2_eboxt5b3qr45gcxzx7wxppt6li - '@vitest/mocker': 2.1.1_msw@2.4.9 - '@vitest/utils': 2.1.1 - magic-string: 0.30.11 - msw: 2.4.9_typescript@5.6.2 + '@vitest/mocker': 2.1.0_msw@2.6.9 + '@vitest/utils': 2.1.0 + magic-string: 0.30.17 + msw: 2.6.9_typescript@5.6.2 playwright: 1.47.1 sirv: 2.0.4 tinyrainbow: 1.2.0 - vitest: 2.1.0_@vitest+browser@2.1.1 + vitest: 2.1.0_@vitest+browser@2.1.0 ws: 8.18.0 transitivePeerDependencies: + - '@types/node' - bufferutil - typescript - utf-8-validate - vite dev: true - /@vitest/coverage-v8/2.1.1_vitest@2.1.0: - resolution: {integrity: sha512-md/A7A3c42oTT8JUHSqjP5uKTWJejzUW4jalpvs+rZ27gsURsMU8DEb+8Jf8C6Kj2gwfSHJqobDNBuoqlm0cFw==} + /@vitest/coverage-v8/2.1.0_qvp2nat4f5x6c53yn4p7pzv3mu: + resolution: {integrity: sha512-yqCkr2nrV4o58VcVMxTVkS6Ggxzy7pmSD8JbTbhbH5PsQfUIES1QT716VUzo33wf2lX9EcWYdT3Vl2MMmjR59g==} peerDependencies: - '@vitest/browser': 2.1.1 - vitest: 2.1.1 + '@vitest/browser': 2.1.0 + vitest: 2.1.0 peerDependenciesMeta: '@vitest/browser': optional: true dependencies: '@ampproject/remapping': 2.3.0 '@bcoe/v8-coverage': 0.2.3 - debug: 4.3.6 + '@vitest/browser': 2.1.0_bbcqthgmodi4rrojsqljgj3bpm + debug: 4.4.0 istanbul-lib-coverage: 3.2.2 istanbul-lib-report: 3.0.1 istanbul-lib-source-maps: 5.0.6 istanbul-reports: 3.1.7 - magic-string: 0.30.11 + magic-string: 0.30.17 magicast: 0.3.5 - std-env: 3.7.0 + std-env: 3.8.0 test-exclude: 7.0.1 tinyrainbow: 1.2.0 - vitest: 2.1.0_@types+node@20.9.5 + vitest: 2.1.0_@vitest+browser@2.1.0 transitivePeerDependencies: - supports-color dev: true - /@vitest/coverage-v8/2.1.1_vvzb4akewk7qhprv5gsu3bguym: - resolution: {integrity: sha512-md/A7A3c42oTT8JUHSqjP5uKTWJejzUW4jalpvs+rZ27gsURsMU8DEb+8Jf8C6Kj2gwfSHJqobDNBuoqlm0cFw==} + /@vitest/coverage-v8/2.1.0_vitest@2.1.0: + resolution: {integrity: sha512-yqCkr2nrV4o58VcVMxTVkS6Ggxzy7pmSD8JbTbhbH5PsQfUIES1QT716VUzo33wf2lX9EcWYdT3Vl2MMmjR59g==} peerDependencies: - '@vitest/browser': 2.1.1 - vitest: 2.1.1 + '@vitest/browser': 2.1.0 + vitest: 2.1.0 peerDependenciesMeta: '@vitest/browser': optional: true dependencies: '@ampproject/remapping': 2.3.0 '@bcoe/v8-coverage': 0.2.3 - '@vitest/browser': 2.1.1_bbcqthgmodi4rrojsqljgj3bpm - debug: 4.3.6 + debug: 4.4.0 istanbul-lib-coverage: 3.2.2 istanbul-lib-report: 3.0.1 istanbul-lib-source-maps: 5.0.6 istanbul-reports: 3.1.7 - magic-string: 0.30.11 + magic-string: 0.30.17 magicast: 0.3.5 - std-env: 3.7.0 + std-env: 3.8.0 test-exclude: 7.0.1 tinyrainbow: 1.2.0 - vitest: 2.1.0_@vitest+browser@2.1.1 + vitest: 2.1.0_@types+node@20.17.0 transitivePeerDependencies: - supports-color dev: true @@ -5610,11 +5599,11 @@ packages: dependencies: '@vitest/spy': 2.1.0 '@vitest/utils': 2.1.0 - chai: 5.1.1 + chai: 5.1.2 tinyrainbow: 1.2.0 dev: true - /@vitest/mocker/2.1.0_vite@5.4.6: + /@vitest/mocker/2.1.0_msw@2.6.9: resolution: {integrity: sha512-ZxENovUqhzl+QiOFpagiHUNUuZ1qPd5yYTCYHomGIZOFArzn4mgX2oxZmiAItJWAaXHG6bbpb/DpSPhlk5DgtA==} peerDependencies: msw: ^2.3.5 @@ -5625,14 +5614,14 @@ packages: vite: optional: true dependencies: - '@vitest/spy': 2.1.0 + '@vitest/spy': 2.1.8 estree-walker: 3.0.3 - magic-string: 0.30.11 - vite: 5.4.6_@types+node@20.9.5 + magic-string: 0.30.17 + msw: 2.6.9_typescript@5.6.2 dev: true - /@vitest/mocker/2.1.1_msw@2.4.9: - resolution: {integrity: sha512-LNN5VwOEdJqCmJ/2XJBywB11DLlkbY0ooDJW3uRX5cZyYCrc4PI/ePX0iQhE3BiEGiQmK4GE7Q/PqCkkaiPnrA==} + /@vitest/mocker/2.1.0_vite@5.4.6: + resolution: {integrity: sha512-ZxENovUqhzl+QiOFpagiHUNUuZ1qPd5yYTCYHomGIZOFArzn4mgX2oxZmiAItJWAaXHG6bbpb/DpSPhlk5DgtA==} peerDependencies: msw: ^2.3.5 vite: ^5.0.0 @@ -5642,10 +5631,10 @@ packages: vite: optional: true dependencies: - '@vitest/spy': 2.1.0 + '@vitest/spy': 2.1.8 estree-walker: 3.0.3 - magic-string: 0.30.11 - msw: 2.4.9_typescript@5.6.2 + magic-string: 0.30.17 + vite: 5.4.6_@types+node@20.17.0 dev: true /@vitest/pretty-format/2.1.0: @@ -5654,8 +5643,8 @@ packages: tinyrainbow: 1.2.0 dev: true - /@vitest/pretty-format/2.1.1: - resolution: {integrity: sha512-SjxPFOtuINDUW8/UkElJYQSFtnWX7tMksSGW0vfjxMneFqxVr8YJ979QpMbDW7g+BIiq88RAGDjf7en6rvLPPQ==} + /@vitest/pretty-format/2.1.8: + resolution: {integrity: sha512-9HiSZ9zpqNLKlbIDRWOnAWqgcA7xu+8YxXSekhr0Ykab7PAYFkhkwoqVArPOtJhPmYeE2YHgKZlj3CP36z2AJQ==} dependencies: tinyrainbow: 1.2.0 dev: true @@ -5671,7 +5660,7 @@ packages: resolution: {integrity: sha512-x69CygGMzt9VCO283K2/FYQ+nBrOj66OTKpsPykjCR4Ac3lLV+m85hj9reaIGmjBSsKzVvbxWmjWE3kF5ha3uQ==} dependencies: '@vitest/pretty-format': 2.1.0 - magic-string: 0.30.11 + magic-string: 0.30.17 pathe: 1.1.2 dev: true @@ -5681,19 +5670,17 @@ packages: tinyspy: 3.0.2 dev: true - /@vitest/utils/2.1.0: - resolution: {integrity: sha512-rreyfVe0PuNqJfKYUwfPDfi6rrp0VSu0Wgvp5WBqJonP+4NvXHk48X6oBam1Lj47Hy6jbJtnMj3OcRdrkTP0tA==} + /@vitest/spy/2.1.8: + resolution: {integrity: sha512-5swjf2q95gXeYPevtW0BLk6H8+bPlMb4Vw/9Em4hFxDcaOxS+e0LOX4yqNxoHzMR2akEB2xfpnWUzkZokmgWDg==} dependencies: - '@vitest/pretty-format': 2.1.0 - loupe: 3.1.1 - tinyrainbow: 1.2.0 + tinyspy: 3.0.2 dev: true - /@vitest/utils/2.1.1: - resolution: {integrity: sha512-Y6Q9TsI+qJ2CC0ZKj6VBb+T8UPz593N113nnUykqwANqhgf3QkZeHFlusgKLTqrnVHbj/XDKZcDHol+dxVT+rQ==} + /@vitest/utils/2.1.0: + resolution: {integrity: sha512-rreyfVe0PuNqJfKYUwfPDfi6rrp0VSu0Wgvp5WBqJonP+4NvXHk48X6oBam1Lj47Hy6jbJtnMj3OcRdrkTP0tA==} dependencies: - '@vitest/pretty-format': 2.1.1 - loupe: 3.1.1 + '@vitest/pretty-format': 2.1.0 + loupe: 3.1.2 tinyrainbow: 1.2.0 dev: true @@ -5930,7 +5917,7 @@ packages: resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} engines: {node: '>= 6.0.0'} dependencies: - debug: 4.3.6 + debug: 4.4.0 transitivePeerDependencies: - supports-color dev: true @@ -5939,7 +5926,7 @@ packages: resolution: {integrity: sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==} engines: {node: '>= 14'} dependencies: - debug: 4.3.6 + debug: 4.4.0 transitivePeerDependencies: - supports-color dev: false @@ -6547,10 +6534,10 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true dependencies: - caniuse-lite: 1.0.30001651 - electron-to-chromium: 1.5.7 + caniuse-lite: 1.0.30001687 + electron-to-chromium: 1.5.72 node-releases: 2.0.18 - update-browserslist-db: 1.1.0_browserslist@4.23.3 + update-browserslist-db: 1.1.1_browserslist@4.23.3 dev: true /browserslist/4.24.2: @@ -6677,10 +6664,6 @@ packages: resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} engines: {node: '>=10'} - /caniuse-lite/1.0.30001651: - resolution: {integrity: sha512-9Cf+Xv1jJNe1xPZLGuUXLNkE1BoDkqRqYyFJ9TDYSqhduqA4hu4oR9HluGoWYQC/aj8WHjsGVV+bwkh0+tegRg==} - dev: true - /caniuse-lite/1.0.30001687: resolution: {integrity: sha512-0S/FDhf4ZiqrTUiQ39dKeUjYRjkv7lOZU1Dgif2rIqrTzX/1wV2hfKu9TOm1IHkdSijfLswxTFzl/cvir+SLSQ==} @@ -6733,14 +6716,14 @@ packages: pathval: 1.1.1 type-detect: 4.1.0 - /chai/5.1.1: - resolution: {integrity: sha512-pT1ZgP8rPNqUgieVaEY+ryQr6Q4HXNg8Ei9UnLUrjN4IA7dvQC5JB+/kxVcPNDHyBcc/26CXPkbNzq3qwrOEKA==} + /chai/5.1.2: + resolution: {integrity: sha512-aGtmf24DW6MLHHG5gCx4zaI3uBq3KRtxeVs0DjFH6Z0rDNbsvTxFASFvdj79pxjxZ8/5u3PIiN3IwEIQkiiuPw==} engines: {node: '>=12'} dependencies: assertion-error: 2.0.1 check-error: 2.1.1 deep-eql: 5.0.2 - loupe: 3.1.1 + loupe: 3.1.2 pathval: 2.0.0 dev: true @@ -6827,7 +6810,7 @@ packages: engines: {node: '>=12.13.0'} hasBin: true dependencies: - '@types/node': 20.9.5 + '@types/node': 20.17.0 escape-string-regexp: 4.0.0 is-wsl: 2.2.0 lighthouse-logger: 1.4.2 @@ -7019,15 +7002,15 @@ packages: /cookie-signature/1.0.6: resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} - /cookie/0.5.0: - resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==} - engines: {node: '>= 0.6'} - dev: true - /cookie/0.6.0: resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} engines: {node: '>= 0.6'} + /cookie/0.7.2: + resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} + engines: {node: '>= 0.6'} + dev: true + /cookiejar/2.1.4: resolution: {integrity: sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==} @@ -7106,6 +7089,14 @@ packages: shebang-command: 2.0.0 which: 2.0.2 + /cross-spawn/7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + /crypt/0.0.2: resolution: {integrity: sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==} dev: false @@ -7222,6 +7213,17 @@ packages: dependencies: ms: 2.1.2 + /debug/4.4.0: + resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.3 + /decamelize/1.2.0: resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} engines: {node: '>=0.10.0'} @@ -7466,10 +7468,6 @@ packages: type-fest: 2.19.0 dev: false - /electron-to-chromium/1.5.7: - resolution: {integrity: sha512-6FTNWIWMxMy/ZY6799nBlPtF1DFDQ6VQJ7yyDP27SJNt5lwtQ5ufqVvHylb3fdQefvRcgA3fKcFMJi9OLwBRNw==} - dev: true - /electron-to-chromium/1.5.72: resolution: {integrity: sha512-ZpSAUOZ2Izby7qnZluSrAlGgGQzucmFbN0n64dYzocYxnxV5ufurpj3VgEe4cUp7ir9LmeLxNYo8bVnlM8bQHw==} @@ -7480,7 +7478,7 @@ packages: requiresBuild: true dependencies: '@electron/get': 2.0.3 - '@types/node': 20.9.5 + '@types/node': 20.17.0 extract-zip: 2.0.1 transitivePeerDependencies: - supports-color @@ -8003,7 +8001,7 @@ packages: '@es-joy/jsdoccomment': 0.49.0 are-docs-informative: 0.0.2 comment-parser: 1.4.1 - debug: 4.3.6 + debug: 4.4.0 escape-string-regexp: 4.0.0 eslint: 9.13.0 espree: 10.2.0 @@ -8127,7 +8125,7 @@ packages: '@types/json-schema': 7.0.15 ajv: 6.12.6 chalk: 4.1.2 - cross-spawn: 7.0.5 + cross-spawn: 7.0.6 debug: 4.3.6 escape-string-regexp: 4.0.0 eslint-scope: 8.1.0 @@ -8228,7 +8226,7 @@ packages: resolution: {integrity: sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==} engines: {node: '>=6'} dependencies: - cross-spawn: 7.0.5 + cross-spawn: 7.0.6 get-stream: 4.1.0 is-stream: 1.1.0 npm-run-path: 2.0.2 @@ -8305,7 +8303,7 @@ packages: engines: {node: '>= 10.17.0'} hasBin: true dependencies: - debug: 4.3.6 + debug: 4.4.0 get-stream: 5.2.0 yauzl: 2.10.0 optionalDependencies: @@ -8505,7 +8503,7 @@ packages: resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==} engines: {node: '>=14'} dependencies: - cross-spawn: 7.0.5 + cross-spawn: 7.0.6 signal-exit: 4.1.0 /form-data-encoder/2.1.4: @@ -9038,7 +9036,7 @@ packages: dependencies: '@tootallnate/once': 2.0.0 agent-base: 6.0.2 - debug: 4.3.6 + debug: 4.4.0 transitivePeerDependencies: - supports-color dev: true @@ -9048,7 +9046,7 @@ packages: engines: {node: '>= 14'} dependencies: agent-base: 7.1.1 - debug: 4.3.6 + debug: 4.4.0 transitivePeerDependencies: - supports-color dev: false @@ -9076,7 +9074,7 @@ packages: engines: {node: '>= 6'} dependencies: agent-base: 6.0.2 - debug: 4.3.6 + debug: 4.4.0 transitivePeerDependencies: - supports-color dev: true @@ -9086,7 +9084,7 @@ packages: engines: {node: '>= 14'} dependencies: agent-base: 7.1.1 - debug: 4.3.6 + debug: 4.4.0 transitivePeerDependencies: - supports-color dev: false @@ -9565,7 +9563,7 @@ packages: resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} engines: {node: '>=10'} dependencies: - debug: 4.3.6 + debug: 4.4.0 istanbul-lib-coverage: 3.2.2 source-map: 0.6.1 transitivePeerDependencies: @@ -9576,7 +9574,7 @@ packages: engines: {node: '>=10'} dependencies: '@jridgewell/trace-mapping': 0.3.25 - debug: 4.3.6 + debug: 4.4.0 istanbul-lib-coverage: 3.2.2 transitivePeerDependencies: - supports-color @@ -9647,7 +9645,7 @@ packages: resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} engines: {node: '>= 10.13.0'} dependencies: - '@types/node': 20.9.5 + '@types/node': 20.17.0 merge-stream: 2.0.0 supports-color: 8.1.1 dev: true @@ -9876,7 +9874,7 @@ packages: dependencies: '@types/express': 4.17.20 '@types/jsonwebtoken': 8.5.9 - debug: 4.3.6 + debug: 4.4.0 jose: 2.0.7 limiter: 1.1.5 lru-memoizer: 2.3.0 @@ -10086,10 +10084,8 @@ packages: dependencies: get-func-name: 2.0.2 - /loupe/3.1.1: - resolution: {integrity: sha512-edNu/8D5MKVfGVFRhFf8aAxiTM6Wumfz5XsaatSxlD3w4R1d/WEKUTydCdPGbl9K7QG/Ca3GnDV2sIKIpXRQcw==} - dependencies: - get-func-name: 2.0.2 + /loupe/3.1.2: + resolution: {integrity: sha512-23I4pFZHmAemUnz8WZXbYRSKYj801VDaNv9ETuMh7IrMc7VuVVSo+Z9iLE3ni30+U48iDWfi30d3twAXBYmnCg==} dev: true /lowercase-keys/2.0.0: @@ -10145,6 +10141,12 @@ packages: '@jridgewell/sourcemap-codec': 1.5.0 dev: true + /magic-string/0.30.17: + resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} + dependencies: + '@jridgewell/sourcemap-codec': 1.5.0 + dev: true + /magicast/0.3.5: resolution: {integrity: sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==} dependencies: @@ -10218,7 +10220,7 @@ packages: dependencies: '@types/hast': 3.0.4 '@types/mdast': 4.0.4 - '@ungap/structured-clone': 1.2.0 + '@ungap/structured-clone': 1.2.1 devlop: 1.1.0 micromark-util-sanitize-uri: 2.0.1 trim-lines: 3.0.1 @@ -10491,8 +10493,8 @@ packages: /ms/2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - /msw/2.4.9_typescript@5.6.2: - resolution: {integrity: sha512-1m8xccT6ipN4PTqLinPwmzhxQREuxaEJYdx4nIbggxP8aM7r1e71vE7RtOUSQoAm1LydjGfZKy7370XD/tsuYg==} + /msw/2.6.9_typescript@5.6.2: + resolution: {integrity: sha512-b2z9MvsEOYG5G7jtJasXO3ucHDcqCjf046e9wELIixBbYCRZCEmB4gqcb+C7ASyXBafNBR0D2u31YtG01OdX3A==} engines: {node: '>=18'} hasBin: true requiresBuild: true @@ -10502,11 +10504,12 @@ packages: typescript: optional: true dependencies: - '@bundled-es-modules/cookie': 2.0.0 + '@bundled-es-modules/cookie': 2.0.1 '@bundled-es-modules/statuses': 1.0.1 '@bundled-es-modules/tough-cookie': 0.1.6 - '@inquirer/confirm': 3.2.0 - '@mswjs/interceptors': 0.35.9 + '@inquirer/confirm': 5.1.0 + '@mswjs/interceptors': 0.37.3 + '@open-draft/deferred-promise': 2.2.0 '@open-draft/until': 2.1.0 '@types/cookie': 0.6.0 '@types/statuses': 2.0.5 @@ -10520,6 +10523,8 @@ packages: type-fest: 4.26.1 typescript: 5.6.2 yargs: 17.7.2 + transitivePeerDependencies: + - '@types/node' dev: true /multiparty/4.2.1: @@ -10539,9 +10544,9 @@ packages: readable-stream: 2.3.8 dev: false - /mute-stream/1.0.0: - resolution: {integrity: sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + /mute-stream/2.0.0: + resolution: {integrity: sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==} + engines: {node: ^18.17.0 || >=20.5.0} dev: true /mysql2/3.11.0: @@ -10889,8 +10894,8 @@ packages: mimic-fn: 4.0.0 dev: false - /oniguruma-to-es/0.4.1: - resolution: {integrity: sha512-rNcEohFz095QKGRovP/yqPIKc+nP+Sjs4YTHMv33nMePGKrq/r2eu9Yh4646M5XluGJsUnmwoXuiXE69KDs+fQ==} + /oniguruma-to-es/0.7.0: + resolution: {integrity: sha512-HRaRh09cE0gRS3+wi2zxekB+I5L8C/gN60S+vb11eADHUaB/q4u8wGGOX3GvwvitG8ixaeycZfeoyruKQzUgNg==} dependencies: emoji-regex-xs: 1.0.0 regex: 5.0.2 @@ -12000,7 +12005,7 @@ packages: dependencies: '@types/debug': 4.1.12 '@types/validator': 13.12.0 - debug: 4.3.6 + debug: 4.4.0 dottie: 2.0.6 inflection: 1.13.4 lodash: 4.17.21 @@ -12104,14 +12109,14 @@ packages: /shell-quote/1.8.1: resolution: {integrity: sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==} - /shiki/1.23.1: - resolution: {integrity: sha512-8kxV9TH4pXgdKGxNOkrSMydn1Xf6It8lsle0fiqxf7a1149K1WGtdOu3Zb91T5r1JpvRPxqxU3C2XdZZXQnrig==} + /shiki/1.24.2: + resolution: {integrity: sha512-TR1fi6mkRrzW+SKT5G6uKuc32Dj2EEa7Kj0k8kGqiBINb+C1TiflVOiT9ta6GqOJtC4fraxO5SLUaKBcSY38Fg==} dependencies: - '@shikijs/core': 1.23.1 - '@shikijs/engine-javascript': 1.23.1 - '@shikijs/engine-oniguruma': 1.23.1 - '@shikijs/types': 1.23.1 - '@shikijs/vscode-textmate': 9.3.0 + '@shikijs/core': 1.24.2 + '@shikijs/engine-javascript': 1.24.2 + '@shikijs/engine-oniguruma': 1.24.2 + '@shikijs/types': 1.24.2 + '@shikijs/vscode-textmate': 9.3.1 '@types/hast': 3.0.4 dev: false @@ -12265,7 +12270,7 @@ packages: /spdy-transport/3.0.0: resolution: {integrity: sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==} dependencies: - debug: 4.3.6 + debug: 4.4.0 detect-node: 2.1.0 hpack.js: 2.1.6 obuf: 1.1.2 @@ -12322,8 +12327,8 @@ packages: resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} engines: {node: '>= 0.8'} - /std-env/3.7.0: - resolution: {integrity: sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==} + /std-env/3.8.0: + resolution: {integrity: sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w==} dev: true /stoppable/1.1.0: @@ -12501,7 +12506,7 @@ packages: resolution: {integrity: sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==} engines: {node: '>= 8.0'} dependencies: - debug: 4.3.6 + debug: 4.4.0 transitivePeerDependencies: - supports-color @@ -12666,8 +12671,8 @@ packages: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} dev: true - /tinyexec/0.3.0: - resolution: {integrity: sha512-tVGE0mVJPGb0chKhqmsoosjsS+qUnJVGJpZgsHYQcGoPlG3B51R3PouqTgEGH2Dc9jjFyOqOpix6ZHNMXp1FZg==} + /tinyexec/0.3.1: + resolution: {integrity: sha512-WiCJLEECkO18gwqIp6+hJg0//p23HXp4S+gGtAKu3mI2F2/sXC4FvHvXvB0zJVVaTPhx1/tOwdbRsa1sOBIKqQ==} dev: true /tinypool/1.0.1: @@ -12949,7 +12954,7 @@ packages: lunr: 2.3.9 markdown-it: 14.1.0 minimatch: 9.0.5 - shiki: 1.23.1 + shiki: 1.24.2 typescript: 5.6.2 yaml: 2.6.1 dev: false @@ -13014,12 +13019,8 @@ packages: resolution: {integrity: sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw==} dev: true - /undici-types/5.26.5: - resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} - /undici-types/6.19.8: resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} - dev: true /unicode-trie/2.0.0: resolution: {integrity: sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==} @@ -13078,8 +13079,8 @@ packages: resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} engines: {node: '>= 0.8'} - /update-browserslist-db/1.1.0_browserslist@4.23.3: - resolution: {integrity: sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==} + /update-browserslist-db/1.1.1_browserslist@4.23.3: + resolution: {integrity: sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==} hasBin: true peerDependencies: browserslist: '>= 4.21.0' @@ -13225,7 +13226,7 @@ packages: hasBin: true dependencies: cac: 6.7.14 - debug: 4.3.6 + debug: 4.4.0 pathe: 1.1.2 vite: 5.4.6 transitivePeerDependencies: @@ -13240,15 +13241,15 @@ packages: - terser dev: true - /vite-node/2.1.0_@types+node@20.9.5: + /vite-node/2.1.0_@types+node@20.17.0: resolution: {integrity: sha512-+ybYqBVUjYyIscoLzMWodus2enQDZOpGhcU6HdOVD6n8WZdk12w1GFL3mbnxLs7hPtRtqs1Wo5YF6/Tsr6fmhg==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true dependencies: cac: 6.7.14 - debug: 4.3.6 + debug: 4.4.0 pathe: 1.1.2 - vite: 5.4.6_@types+node@20.9.5 + vite: 5.4.6_@types+node@20.17.0 transitivePeerDependencies: - '@types/node' - less @@ -13287,7 +13288,7 @@ packages: perfect-debounce: 1.0.0 picocolors: 1.0.1 sirv: 2.0.4 - vite: 5.4.6_@types+node@20.9.5 + vite: 5.4.6_@types+node@20.17.0 transitivePeerDependencies: - rollup - supports-color @@ -13343,7 +13344,7 @@ packages: fsevents: 2.3.3 dev: true - /vite/5.4.6_@types+node@20.9.5: + /vite/5.4.6_@types+node@20.17.0: resolution: {integrity: sha512-IeL5f8OO5nylsgzd9tq4qD2QqI0k2CQLGrWD0rCN0EQJZpBK5vJAx0I+GDkMOXxQX/OfFHMuLIx6ddAxGX/k+Q==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true @@ -13374,7 +13375,7 @@ packages: terser: optional: true dependencies: - '@types/node': 20.9.5 + '@types/node': 20.17.0 esbuild: 0.21.5 postcss: 8.4.47 rollup: 4.22.4 @@ -13382,7 +13383,7 @@ packages: fsevents: 2.3.3 dev: true - /vitest/2.1.0_@types+node@20.9.5: + /vitest/2.1.0_@types+node@20.17.0: resolution: {integrity: sha512-XuuEeyNkqbfr0FtAvd9vFbInSSNY1ykCQTYQ0sj9wPy4hx+1gR7gqVNdW0AX2wrrM1wWlN5fnJDjF9xG6mYRSQ==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true @@ -13407,25 +13408,25 @@ packages: jsdom: optional: true dependencies: - '@types/node': 20.9.5 + '@types/node': 20.17.0 '@vitest/expect': 2.1.0 '@vitest/mocker': 2.1.0_vite@5.4.6 - '@vitest/pretty-format': 2.1.1 + '@vitest/pretty-format': 2.1.8 '@vitest/runner': 2.1.0 '@vitest/snapshot': 2.1.0 '@vitest/spy': 2.1.0 '@vitest/utils': 2.1.0 - chai: 5.1.1 - debug: 4.3.6 - magic-string: 0.30.11 + chai: 5.1.2 + debug: 4.4.0 + magic-string: 0.30.17 pathe: 1.1.2 - std-env: 3.7.0 + std-env: 3.8.0 tinybench: 2.9.0 - tinyexec: 0.3.0 + tinyexec: 0.3.1 tinypool: 1.0.1 tinyrainbow: 1.2.0 - vite: 5.4.6_@types+node@20.9.5 - vite-node: 2.1.0_@types+node@20.9.5 + vite: 5.4.6_@types+node@20.17.0 + vite-node: 2.1.0_@types+node@20.17.0 why-is-node-running: 2.3.0 transitivePeerDependencies: - less @@ -13439,7 +13440,7 @@ packages: - terser dev: true - /vitest/2.1.0_@vitest+browser@2.1.1: + /vitest/2.1.0_@vitest+browser@2.1.0: resolution: {integrity: sha512-XuuEeyNkqbfr0FtAvd9vFbInSSNY1ykCQTYQ0sj9wPy4hx+1gR7gqVNdW0AX2wrrM1wWlN5fnJDjF9xG6mYRSQ==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true @@ -13464,21 +13465,21 @@ packages: jsdom: optional: true dependencies: - '@vitest/browser': 2.1.1_bbcqthgmodi4rrojsqljgj3bpm + '@vitest/browser': 2.1.0_bbcqthgmodi4rrojsqljgj3bpm '@vitest/expect': 2.1.0 '@vitest/mocker': 2.1.0_vite@5.4.6 - '@vitest/pretty-format': 2.1.1 + '@vitest/pretty-format': 2.1.8 '@vitest/runner': 2.1.0 '@vitest/snapshot': 2.1.0 '@vitest/spy': 2.1.0 '@vitest/utils': 2.1.0 - chai: 5.1.1 - debug: 4.3.6 - magic-string: 0.30.11 + chai: 5.1.2 + debug: 4.4.0 + magic-string: 0.30.17 pathe: 1.1.2 - std-env: 3.7.0 + std-env: 3.8.0 tinybench: 2.9.0 - tinyexec: 0.3.0 + tinyexec: 0.3.1 tinypool: 1.0.1 tinyrainbow: 1.2.0 vite: 5.4.6 @@ -13797,7 +13798,7 @@ packages: /wkx/0.5.0: resolution: {integrity: sha512-Xng/d4Ichh8uN4l0FToV/258EjMGU9MGcA0HV2d9B/ZpZB3lqQm7nkOdZdm5GhKtLLhAE7PiVQwN4eN+2YJJUg==} dependencies: - '@types/node': 20.9.5 + '@types/node': 20.17.0 dev: false /wms-capabilities/0.4.0: @@ -13993,7 +13994,7 @@ packages: engines: {node: '>=10'} dependencies: cliui: 7.0.4 - escalade: 3.2.0 + escalade: 3.1.2 get-caller-file: 2.0.5 require-directory: 2.1.1 string-width: 4.2.3 diff --git a/core/backend/package.json b/core/backend/package.json index db20750b831d..dc5e094eeaf3 100644 --- a/core/backend/package.json +++ b/core/backend/package.json @@ -72,7 +72,7 @@ "@types/fs-extra": "^4.0.7", "@types/mocha": "^10.0.6", "@types/multiparty": "^0.0.31", - "@types/node": "~20.9.5", + "@types/node": "~20.17.0", "@types/semver": "7.3.10", "@types/sinon": "^17.0.2", "@types/touch": "^3.1.2", @@ -115,4 +115,4 @@ "nyc": { "extends": "./node_modules/@itwin/build-tools/.nycrc" } -} +} \ No newline at end of file diff --git a/core/backend/src/ChangeSummaryManager.ts b/core/backend/src/ChangeSummaryManager.ts index fb8cce70ca97..95e344cae7ad 100644 --- a/core/backend/src/ChangeSummaryManager.ts +++ b/core/backend/src/ChangeSummaryManager.ts @@ -6,7 +6,7 @@ * @module iModels */ -import { AccessToken, assert, DbResult, GuidString, Id64String, IModelStatus, Logger, using } from "@itwin/core-bentley"; +import { AccessToken, assert, DbResult, GuidString, Id64String, IModelStatus, Logger } from "@itwin/core-bentley"; import { ChangedValueState, ChangeOpCode, ChangesetRange, IModelError, IModelVersion } from "@itwin/core-common"; import * as path from "path"; import { BackendLoggerCategory } from "./BackendLoggerCategory"; @@ -101,9 +101,8 @@ export class ChangeSummaryManager { const changesCacheFilePath: string = BriefcaseManager.getChangeCachePathName(iModel.iModelId); if (!IModelJsFs.existsSync(changesCacheFilePath)) { - using(new ECDb(), (changeCacheFile: ECDb) => { - ChangeSummaryManager.createChangeCacheFile(iModel, changeCacheFile, changesCacheFilePath); - }); + using changeCacheFile = new ECDb(); + ChangeSummaryManager.createChangeCacheFile(iModel, changeCacheFile, changesCacheFilePath); } assert(IModelJsFs.existsSync(changesCacheFilePath)); @@ -380,9 +379,8 @@ export class ChangeSummaryManager { if (!IModelJsFs.existsSync(changeset.pathname)) throw new IModelError(IModelStatus.FileNotFound, `Failed to download change set: ${changeset.pathname}`); - let changesFile: ECDb | undefined; try { - changesFile = ChangeSummaryManager.openOrCreateChangesFile(iModel); + using changesFile = ChangeSummaryManager.openOrCreateChangesFile(iModel); assert(changesFile[_nativeDb] !== undefined, "Invalid changesFile - should've caused an exception"); let changeSummaryId = ChangeSummaryManager.isSummaryAlreadyExtracted(changesFile, changesetId); @@ -402,8 +400,6 @@ export class ChangeSummaryManager { changesFile.saveChanges(); return changeSummaryId; } finally { - if (changesFile !== undefined) - changesFile.dispose(); IModelJsFs.unlinkSync(changeset.pathname); } } diff --git a/core/backend/src/ChangedElementsDb.ts b/core/backend/src/ChangedElementsDb.ts index 22fa9feefe54..f21b8e77a0e8 100644 --- a/core/backend/src/ChangedElementsDb.ts +++ b/core/backend/src/ChangedElementsDb.ts @@ -6,7 +6,7 @@ * @module ChangedElementsDb */ -import { AccessToken, DbResult, IDisposable, IModelStatus, OpenMode } from "@itwin/core-bentley"; +import { AccessToken, DbResult, IModelStatus, OpenMode } from "@itwin/core-bentley"; import { ChangeData, ChangedElements, ChangedModels, IModelError } from "@itwin/core-common"; import { IModelJsNative } from "@bentley/imodeljs-native"; import { BriefcaseManager } from "./BriefcaseManager"; @@ -38,14 +38,14 @@ export interface ProcessChangesetOptions { /** An ChangedElementsDb file * @internal */ -export class ChangedElementsDb implements IDisposable { +export class ChangedElementsDb implements Disposable { private _nativeDb: IModelJsNative.ChangedElementsECDb | undefined; constructor() { this._nativeDb = new IModelNative.platform.ChangedElementsECDb(); } - public dispose(): void { + public [Symbol.dispose](): void { if (!this._nativeDb) return; diff --git a/core/backend/src/ChangesetECAdaptor.ts b/core/backend/src/ChangesetECAdaptor.ts index 11623f218e89..764efc702a76 100644 --- a/core/backend/src/ChangesetECAdaptor.ts +++ b/core/backend/src/ChangesetECAdaptor.ts @@ -5,7 +5,7 @@ /** @packageDocumentation * @module ECDb */ -import { DbResult, GuidString, Id64String, IDisposable } from "@itwin/core-bentley"; +import { DbResult, GuidString, Id64String } from "@itwin/core-bentley"; import { AnyDb, SqliteChange, SqliteChangeOp, SqliteChangesetReader, SqliteValueStage } from "./SqliteChangesetReader"; interface IClassRef { @@ -554,7 +554,7 @@ export class PartialECChangeUnifier { * @beta * */ -export class ChangesetECAdaptor implements IDisposable { +export class ChangesetECAdaptor implements Disposable { private readonly _mapCache: ECDbMap; private readonly _tableFilter = new Set(); private readonly _opFilter = new Set(); @@ -639,7 +639,7 @@ export class ChangesetECAdaptor implements IDisposable { /** * dispose current instance and it will also dispose the changeset reader. */ - public dispose(): void { + public [Symbol.dispose](): void { this.close(); } /** diff --git a/core/backend/src/ECDb.ts b/core/backend/src/ECDb.ts index 7299b2dd2523..64468063a1b4 100644 --- a/core/backend/src/ECDb.ts +++ b/core/backend/src/ECDb.ts @@ -5,7 +5,7 @@ /** @packageDocumentation * @module ECDb */ -import { assert, DbResult, IDisposable, Logger, OpenMode } from "@itwin/core-bentley"; +import { assert, DbResult, Logger, OpenMode } from "@itwin/core-bentley"; import { IModelJsNative } from "@bentley/imodeljs-native"; import { DbQueryRequest, ECSchemaProps, ECSqlReader, IModelError, QueryBinder, QueryOptions, QueryOptionsBuilder } from "@itwin/core-common"; import { BackendLoggerCategory } from "./BackendLoggerCategory"; @@ -30,7 +30,7 @@ export enum ECDbOpenMode { /** An ECDb file * @public */ -export class ECDb implements IDisposable { +export class ECDb implements Disposable { private _nativeDb?: IModelJsNative.ECDb; private readonly _statementCache = new StatementCache(); private _sqliteStatementCache = new StatementCache(); @@ -49,7 +49,7 @@ export class ECDb implements IDisposable { /** Call this function when finished with this ECDb object. This releases the native resources held by the * ECDb object. */ - public dispose(): void { + public [Symbol.dispose](): void { if (!this._nativeDb) return; @@ -58,6 +58,11 @@ export class ECDb implements IDisposable { this._nativeDb = undefined; } + /** @deprecated in 5.0 Use [Symbol.dispose] instead. */ + public dispose(): void { + this[Symbol.dispose](); + } + /** Create an ECDb * @param pathName The path to the ECDb file to create. * @throws [IModelError]($common) if the operation failed. @@ -189,7 +194,7 @@ export class ECDb implements IDisposable { */ public withStatement(ecsql: string, callback: (stmt: ECSqlStatement) => T, logErrors = true): T { const stmt = this.prepareStatement(ecsql, logErrors); - const release = () => stmt.dispose(); + const release = () => stmt[Symbol.dispose](); try { const val = callback(stmt); if (val instanceof Promise) { @@ -257,7 +262,7 @@ export class ECDb implements IDisposable { */ public withSqliteStatement(sql: string, callback: (stmt: SqliteStatement) => T, logErrors = true): T { const stmt = this.prepareSqliteStatement(sql, logErrors); - const release = () => stmt.dispose(); + const release = () => stmt[Symbol.dispose](); try { const val: T = callback(stmt); if (val instanceof Promise) { diff --git a/core/backend/src/ECSqlStatement.ts b/core/backend/src/ECSqlStatement.ts index 24d14db4ec7c..7f593e9c3d4c 100644 --- a/core/backend/src/ECSqlStatement.ts +++ b/core/backend/src/ECSqlStatement.ts @@ -6,7 +6,7 @@ * @module ECSQL */ -import { assert, DbResult, GuidString, Id64String, IDisposable } from "@itwin/core-bentley"; +import { assert, DbResult, GuidString, Id64String } from "@itwin/core-bentley"; import { LowAndHighXYZ, Range3d, XAndY, XYAndZ, XYZ } from "@itwin/core-geometry"; import { ECJsNames, ECSqlValueType, IModelError, NavigationBindingValue, NavigationValue, PropertyMetaDataMap, QueryRowFormat } from "@itwin/core-common"; import { IModelJsNative } from "@bentley/imodeljs-native"; @@ -64,7 +64,7 @@ export interface ECSqlRowArg { * - [Code Examples]($docs/learning/backend/ECSQLCodeExamples) illustrate the use of the iTwin.js API for executing and working with ECSQL * @public */ -export class ECSqlStatement implements IterableIterator, IDisposable { +export class ECSqlStatement implements IterableIterator, Disposable { private _stmt: IModelJsNative.ECSqlStatement | undefined; private _sql: string | undefined; private _props = new PropertyMetaDataMap([]); @@ -123,13 +123,18 @@ export class ECSqlStatement implements IterableIterator, IDisposable { * * > Do not call this method directly on a statement that is being managed by a statement cache. */ - public dispose(): void { + public [Symbol.dispose](): void { if (this._stmt) { this._stmt.dispose(); // free native statement this._stmt = undefined; } } + /** @deprecated in 5.0 Use [Symbol.dispose] instead. */ + public dispose(): void { + this[Symbol.dispose](); + } + /** Binds the specified value to the specified ECSQL parameter. * The section "[iTwin.js Types used in ECSQL Parameter Bindings]($docs/learning/ECSQLParameterTypes)" describes the * iTwin.js types to be used for the different ECSQL parameter types. diff --git a/core/backend/src/IModelDb.ts b/core/backend/src/IModelDb.ts index 5cbdbef49985..1de1b04eee69 100644 --- a/core/backend/src/IModelDb.ts +++ b/core/backend/src/IModelDb.ts @@ -445,7 +445,7 @@ export abstract class IModelDb extends IModel { */ public withStatement(ecsql: string, callback: (stmt: ECSqlStatement) => T, logErrors = true): T { const stmt = this.prepareStatement(ecsql, logErrors); - const release = () => stmt.dispose(); + const release = () => stmt[Symbol.dispose](); try { const val = callback(stmt); if (val instanceof Promise) { @@ -592,7 +592,7 @@ export abstract class IModelDb extends IModel { */ public withSqliteStatement(sql: string, callback: (stmt: SqliteStatement) => T, logErrors = true): T { const stmt = this.prepareSqliteStatement(sql, logErrors); - const release = () => stmt.dispose(); + const release = () => stmt[Symbol.dispose](); try { const val: T = callback(stmt); if (val instanceof Promise) { diff --git a/core/backend/src/IModelElementCloneContext.ts b/core/backend/src/IModelElementCloneContext.ts index a86d365e49ed..f0b20b99f685 100644 --- a/core/backend/src/IModelElementCloneContext.ts +++ b/core/backend/src/IModelElementCloneContext.ts @@ -51,7 +51,12 @@ export class IModelElementCloneContext { public get isBetweenIModels(): boolean { return this.sourceDb !== this.targetDb; } /** Dispose any native resources associated with this IModelElementCloneContext. */ - public dispose(): void { this._nativeContext.dispose(); } + public [Symbol.dispose](): void { this._nativeContext.dispose(); } + + /** @deprecated in 5.0 Use [Symbol.dispose] instead. */ + public dispose() { + this[Symbol.dispose](); + } /** Debugging aid that dumps the Id remapping details and other information to the specified output file. * @internal diff --git a/core/backend/src/PromiseMemoizer.ts b/core/backend/src/PromiseMemoizer.ts index 1093415faba9..e98a2c922971 100644 --- a/core/backend/src/PromiseMemoizer.ts +++ b/core/backend/src/PromiseMemoizer.ts @@ -2,7 +2,7 @@ * Copyright (c) Bentley Systems, Incorporated. All rights reserved. * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ -import { IDisposable, Logger } from "@itwin/core-bentley"; +import { Logger } from "@itwin/core-bentley"; import { BackendLoggerCategory } from "./BackendLoggerCategory"; /** Wrapper around a promise that allows synchronous queries of it's state @@ -38,7 +38,7 @@ export type GenerateKeyFnType = (...args: any[]) => string; * The cache is keyed on the input arguments passed to these functions * @internal */ -export class PromiseMemoizer implements IDisposable { +export class PromiseMemoizer implements Disposable { private readonly _cachedPromises: Map> = new Map>(); private readonly _timers: Map = new Map(); private readonly _memoizeFn: MemoizeFnType; @@ -107,7 +107,7 @@ export class PromiseMemoizer implements IDisposable { this._cachedPromises.clear(); } - public dispose() { + public [Symbol.dispose]() { for (const timer of this._timers.values()) clearTimeout(timer); diff --git a/core/backend/src/SQLiteDb.ts b/core/backend/src/SQLiteDb.ts index b487586da4a5..458811bfd8ba 100644 --- a/core/backend/src/SQLiteDb.ts +++ b/core/backend/src/SQLiteDb.ts @@ -211,7 +211,7 @@ export class SQLiteDb { */ public withSqliteStatement(sql: string, callback: (stmt: SqliteStatement) => T): T { const stmt = this.prepareSqliteStatement(sql); - const release = () => stmt.dispose(); + const release = () => stmt[Symbol.dispose](); try { const val = callback(stmt); val instanceof Promise ? val.then(release, release) : release(); @@ -254,12 +254,8 @@ export class SQLiteDb { /** execute an SQL statement */ public executeSQL(sql: string): DbResult { - const stmt = this.prepareSqliteStatement(sql); - try { - return stmt.step(); - } finally { - stmt.dispose(); - } + using stmt = this.prepareSqliteStatement(sql); + return stmt.step(); } } diff --git a/core/backend/src/SqliteChangesetReader.ts b/core/backend/src/SqliteChangesetReader.ts index a449ae905aa6..8895b3f2f883 100644 --- a/core/backend/src/SqliteChangesetReader.ts +++ b/core/backend/src/SqliteChangesetReader.ts @@ -5,7 +5,7 @@ /** @packageDocumentation * @module SQLiteDb */ -import { DbChangeStage, DbOpcode, DbResult, DbValueType, Id64String, IDisposable } from "@itwin/core-bentley"; +import { DbChangeStage, DbOpcode, DbResult, DbValueType, Id64String } from "@itwin/core-bentley"; import { ECDb } from "./ECDb"; import { IModelDb } from "./IModelDb"; import { IModelNative } from "./internal/NativePlatform"; @@ -83,7 +83,7 @@ export interface SqliteChange { * a db provided. * @beta */ -export class SqliteChangesetReader implements IDisposable { +export class SqliteChangesetReader implements Disposable { private readonly _nativeReader = new IModelNative.platform.ChangesetReader(); private _schemaCache = new Map(); private _disableSchemaCheck = false; @@ -400,7 +400,7 @@ export class SqliteChangesetReader implements IDisposable { * Dispose this object * @beta */ - public dispose(): void { + public [Symbol.dispose](): void { this.close(); } } diff --git a/core/backend/src/SqliteStatement.ts b/core/backend/src/SqliteStatement.ts index aa04c469b291..9158ab0b3a12 100644 --- a/core/backend/src/SqliteStatement.ts +++ b/core/backend/src/SqliteStatement.ts @@ -6,7 +6,7 @@ * @module SQLite */ -import { assert, BentleyError, DbResult, GuidString, Id64String, IDisposable, LRUMap } from "@itwin/core-bentley"; +import { assert, BentleyError, DbResult, GuidString, Id64String, LRUMap } from "@itwin/core-bentley"; import { ECJsNames, IModelError } from "@itwin/core-common"; import { IModelJsNative } from "@bentley/imodeljs-native"; import { IModelNative } from "./internal/NativePlatform"; @@ -56,7 +56,7 @@ function checkBind(stat: DbResult) { * > The key to making this strategy work is to phrase a statement in a general way and use placeholders to represent parameters that will vary on each use. * @public */ -export class SqliteStatement implements IterableIterator, IDisposable { +export class SqliteStatement implements IterableIterator, Disposable { private _stmt: IModelJsNative.SqliteStatement | undefined; private _db: IModelJsNative.AnyDb | undefined; @@ -96,7 +96,7 @@ export class SqliteStatement implements IterableIterator, IDisposable { } /** Call this function when finished with this statement. This releases the native resources held by the statement. */ - public dispose(): void { + public [Symbol.dispose](): void { if (this._stmt) { this._stmt.dispose(); // free native statement this._stmt = undefined; @@ -104,6 +104,11 @@ export class SqliteStatement implements IterableIterator, IDisposable { } } + /** @deprecated in 5.0 Use [Symbol.dispose] instead. */ + public dispose() { + this[Symbol.dispose](); + } + /** * Call `step` on this statement and determine whether a new row is available. * Use this method only when this statement has been prepared with a SELECT statement. diff --git a/core/backend/src/rpc-impl/IModelTileRpcImpl.ts b/core/backend/src/rpc-impl/IModelTileRpcImpl.ts index c5f139d645c9..b296ff2129da 100644 --- a/core/backend/src/rpc-impl/IModelTileRpcImpl.ts +++ b/core/backend/src/rpc-impl/IModelTileRpcImpl.ts @@ -110,7 +110,7 @@ class RequestTileTreePropsMemoizer extends TileRequestMemoizer { - this.dispose(); + this[Symbol.dispose](); RequestTileTreePropsMemoizer._instance = undefined; }); } @@ -168,7 +168,7 @@ class RequestTileContentMemoizer extends TileRequestMemoizer { - this.dispose(); + this[Symbol.dispose](); RequestTileContentMemoizer._instance = undefined; }); } diff --git a/core/backend/src/test/SchemaUtils.test.ts b/core/backend/src/test/SchemaUtils.test.ts index 9bea71222bcb..1f8129647e5c 100644 --- a/core/backend/src/test/SchemaUtils.test.ts +++ b/core/backend/src/test/SchemaUtils.test.ts @@ -70,7 +70,7 @@ describe("convertEC2Schemas", () => { const row = stmt.getRow(); propNamesInEntityClass.push(row.name); } - stmt.dispose(); + stmt[Symbol.dispose](); assert.equal(rowCount, 9); assert.isFalse(propNamesInEntityClass.includes("Id")); // The Id property is a reserved keyword and should have been renamed @@ -94,7 +94,7 @@ describe("convertEC2Schemas", () => { const row = stmt.getRow(); propNamesInStructClass.push(row.name); } - stmt.dispose(); + stmt[Symbol.dispose](); assert.equal(rowCount, 3); assert.isTrue(propNamesInStructClass.includes("Id")); // The Id property is not a reserved keyword for Struct classes and should not be renamed diff --git a/core/backend/src/test/TestUtils.ts b/core/backend/src/test/TestUtils.ts index 6dcad49c14e8..41723cfe2ac7 100644 --- a/core/backend/src/test/TestUtils.ts +++ b/core/backend/src/test/TestUtils.ts @@ -5,7 +5,7 @@ import * as path from "path"; import { IModelJsNative, NativeLoggerCategory } from "@bentley/imodeljs-native"; -import { BentleyLoggerCategory, IDisposable, Logger, LogLevel, ProcessDetector } from "@itwin/core-bentley"; +import { BentleyLoggerCategory, Logger, LogLevel, ProcessDetector } from "@itwin/core-bentley"; import { BackendLoggerCategory } from "../BackendLoggerCategory"; import { IModelHost, IModelHostOptions } from "../IModelHost"; import { IModelNative } from "../internal/NativePlatform"; @@ -33,20 +33,25 @@ export class Timer { * would fail unexpectedly in a debug build. In that case the native code assertions can be disabled with * this class. */ -export class DisableNativeAssertions implements IDisposable { +export class DisableNativeAssertions implements Disposable { private _native: IModelJsNative.DisableNativeAssertions | undefined; constructor() { this._native = new IModelNative.platform.DisableNativeAssertions(); } - public dispose(): void { + public [Symbol.dispose](): void { if (!this._native) return; this._native.dispose(); this._native = undefined; } + + /** @deprecated in 5.0 Use [Symbol.dispose] instead. */ + public dispose(): void { + this[Symbol.dispose](); + } } export class TestUtils { diff --git a/core/backend/src/test/ecdb/ECDb.test.ts b/core/backend/src/test/ecdb/ECDb.test.ts index 876f65d19689..e937db906a5f 100644 --- a/core/backend/src/test/ecdb/ECDb.test.ts +++ b/core/backend/src/test/ecdb/ECDb.test.ts @@ -5,7 +5,7 @@ import { assert, expect } from "chai"; import * as path from "path"; import * as sinon from "sinon"; -import { DbResult, Id64, Id64String, Logger, using } from "@itwin/core-bentley"; +import { DbResult, Id64, Id64String, Logger } from "@itwin/core-bentley"; import { ECDb, ECDbOpenMode, ECSqlInsertResult, ECSqlStatement, IModelJsFs, SqliteStatement, SqliteValue, SqliteValueType } from "../../core-backend"; import { KnownTestLocations } from "../KnownTestLocations"; import { ECDbTestHelper } from "./ECDbTestHelper"; @@ -14,9 +14,8 @@ describe("ECDb", () => { const outDir = KnownTestLocations.outputDir; it("should be able to create a new ECDb", () => { - using(ECDbTestHelper.createECDb(outDir, "create.ecdb"), (ecdb: ECDb) => { - assert.isTrue(ecdb.isOpen); - }); + using ecdb = ECDbTestHelper.createECDb(outDir, "create.ecdb"); + assert.isTrue(ecdb.isOpen); }); it("should be able to close an ECDb", () => { @@ -29,47 +28,50 @@ describe("ECDb", () => { it("should be able to open an ECDb", () => { const fileName = "open.ecdb"; const ecdbPath: string = path.join(outDir, fileName); - using(ECDbTestHelper.createECDb(outDir, fileName), (testECDb: ECDb) => { + { + using testECDb = ECDbTestHelper.createECDb(outDir, fileName); assert.isTrue(testECDb.isOpen); - }); + } - using(new ECDb(), (ecdb: ECDb) => { - ecdb.openDb(ecdbPath, ECDbOpenMode.ReadWrite); - assert.isTrue(ecdb.isOpen); - }); + using ecdb = new ECDb(); + ecdb.openDb(ecdbPath, ECDbOpenMode.ReadWrite); + assert.isTrue(ecdb.isOpen); }); it("Open ECDb with upgrade option", () => { const fileName = "open.ecdb"; const ecdbPath: string = path.join(outDir, fileName); - using(ECDbTestHelper.createECDb(outDir, fileName), (testECDb: ECDb) => { + { + using testECDb = ECDbTestHelper.createECDb(outDir, fileName); assert.isTrue(testECDb.isOpen); - }); - - using(new ECDb(), (ecdb: ECDb) => { + } + { + using ecdb = new ECDb(); assert.doesNotThrow(() => ecdb.openDb(ecdbPath, ECDbOpenMode.Readonly)); - }); - - using(new ECDb(), (ecdb: ECDb) => { + } + { + using ecdb = new ECDb(); assert.doesNotThrow(() => ecdb.openDb(ecdbPath, ECDbOpenMode.ReadWrite)); - }); - - using(new ECDb(), (ecdb: ECDb) => { + } + { + using ecdb = new ECDb(); assert.doesNotThrow(() => ecdb.openDb(ecdbPath, ECDbOpenMode.FileUpgrade)); - }); + } + }); it("should be able to import a schema", () => { const fileName = "schemaimport.ecdb"; const ecdbPath: string = path.join(outDir, fileName); let id: Id64String; - using(ECDbTestHelper.createECDb(outDir, fileName, - ` + { + using testECDb = ECDbTestHelper.createECDb(outDir, fileName, + ` - + - - `), (testECDb: ECDb) => { + + `); assert.isTrue(testECDb.isOpen); id = testECDb.withPreparedStatement("INSERT INTO test.Person(Name,Age) VALUES('Mary', 45)", (stmt: ECSqlStatement) => { const res: ECSqlInsertResult = stmt.stepForInsert(); @@ -79,39 +81,39 @@ describe("ECDb", () => { return res.id!; }); testECDb.saveChanges(); - }); + } - using(new ECDb(), (ecdb: ECDb) => { - ecdb.openDb(ecdbPath, ECDbOpenMode.Readonly); - assert.isTrue(ecdb.isOpen); + using ecdb = new ECDb(); + ecdb.openDb(ecdbPath, ECDbOpenMode.Readonly); + assert.isTrue(ecdb.isOpen); - ecdb.withPreparedStatement("SELECT Name, Age FROM test.Person WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { - stmt.bindId(1, id); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - const row = stmt.getRow(); - assert.equal(row.name, "Mary"); - assert.equal(row.age, 45); - }); + ecdb.withPreparedStatement("SELECT Name, Age FROM test.Person WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { + stmt.bindId(1, id); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + const row = stmt.getRow(); + assert.equal(row.name, "Mary"); + assert.equal(row.age, 45); }); }); it("should be able to get schema props", () => { const fileName = "schema-props.ecdb"; const ecdbPath: string = path.join(outDir, fileName); - using(ECDbTestHelper.createECDb(outDir, fileName), (testECDb: ECDb) => { + { + using testECDb = ECDbTestHelper.createECDb(outDir, fileName); assert.isTrue(testECDb.isOpen); - }); - using(new ECDb(), (ecdb) => { - ecdb.openDb(ecdbPath); - const schema = ecdb.getSchemaProps("ECDbMeta"); - assert.equal(schema.name, "ECDbMeta"); - }); + } + using ecdb = new ECDb(); + ecdb.openDb(ecdbPath); + const schema = ecdb.getSchemaProps("ECDbMeta"); + assert.equal(schema.name, "ECDbMeta"); }); it("Run plain SQL", () => { const fileName = "plainseql.ecdb"; const ecdbPath: string = path.join(outDir, fileName); - using(ECDbTestHelper.createECDb(outDir, fileName), (testECDb: ECDb) => { + { + using testECDb = ECDbTestHelper.createECDb(outDir, fileName); assert.isTrue(testECDb.isOpen); testECDb.withPreparedSqliteStatement("CREATE TABLE Test(Id INTEGER PRIMARY KEY, Name TEXT NOT NULL, Code INTEGER)", (stmt: SqliteStatement) => { @@ -141,41 +143,40 @@ describe("ECDb", () => { }); testECDb.saveChanges(); - }); + } - using(new ECDb(), (ecdb: ECDb) => { - ecdb.openDb(ecdbPath, ECDbOpenMode.Readonly); - assert.isTrue(ecdb.isOpen); - - ecdb.withPreparedSqliteStatement("SELECT Id,Name,Code FROM Test ORDER BY Id", (stmt: SqliteStatement) => { - for (let i: number = 1; i <= 4; i++) { - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - assert.equal(stmt.getColumnCount(), 3); - const val0: SqliteValue = stmt.getValue(0); - assert.equal(val0.columnName, "Id"); - assert.equal(val0.type, SqliteValueType.Integer); - assert.isFalse(val0.isNull); - assert.equal(val0.getInteger(), i); - - const val1: SqliteValue = stmt.getValue(1); - assert.equal(val1.columnName, "Name"); - assert.equal(val1.type, SqliteValueType.String); - assert.isFalse(val1.isNull); - assert.equal(val1.getString(), `Dummy ${i}`); - - const val2: SqliteValue = stmt.getValue(2); - assert.equal(val2.columnName, "Code"); - assert.equal(val2.type, SqliteValueType.Integer); - assert.isFalse(val2.isNull); - assert.equal(val2.getInteger(), i * 100); - - const row: any = stmt.getRow(); - assert.equal(row.id, i); - assert.equal(row.name, `Dummy ${i}`); - assert.equal(row.code, i * 100); - } - assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE); - }); + using ecdb = new ECDb(); + ecdb.openDb(ecdbPath, ECDbOpenMode.Readonly); + assert.isTrue(ecdb.isOpen); + + ecdb.withPreparedSqliteStatement("SELECT Id,Name,Code FROM Test ORDER BY Id", (stmt: SqliteStatement) => { + for (let i: number = 1; i <= 4; i++) { + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + assert.equal(stmt.getColumnCount(), 3); + const val0: SqliteValue = stmt.getValue(0); + assert.equal(val0.columnName, "Id"); + assert.equal(val0.type, SqliteValueType.Integer); + assert.isFalse(val0.isNull); + assert.equal(val0.getInteger(), i); + + const val1: SqliteValue = stmt.getValue(1); + assert.equal(val1.columnName, "Name"); + assert.equal(val1.type, SqliteValueType.String); + assert.isFalse(val1.isNull); + assert.equal(val1.getString(), `Dummy ${i}`); + + const val2: SqliteValue = stmt.getValue(2); + assert.equal(val2.columnName, "Code"); + assert.equal(val2.type, SqliteValueType.Integer); + assert.isFalse(val2.isNull); + assert.equal(val2.getInteger(), i * 100); + + const row: any = stmt.getRow(); + assert.equal(row.id, i); + assert.equal(row.name, `Dummy ${i}`); + assert.equal(row.code, i * 100); + } + assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE); }); }); diff --git a/core/backend/src/test/ecdb/ECSqlReader.test.ts b/core/backend/src/test/ecdb/ECSqlReader.test.ts index ef10a7acaeee..6662506adb7b 100644 --- a/core/backend/src/test/ecdb/ECSqlReader.test.ts +++ b/core/backend/src/test/ecdb/ECSqlReader.test.ts @@ -3,10 +3,9 @@ import { assert } from "chai"; * Copyright (c) Bentley Systems, Incorporated. All rights reserved. * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ -import { DbResult, using } from "@itwin/core-bentley"; +import { DbResult } from "@itwin/core-bentley"; import { ECSqlReader, QueryBinder, QueryOptionsBuilder, QueryRowFormat } from "@itwin/core-common"; import { SnapshotDb } from "../../core-backend"; -import { ECDb } from "../../ECDb"; import { ECSqlStatement } from "../../ECSqlStatement"; import { IModelTestUtils } from "../IModelTestUtils"; import { KnownTestLocations } from "../KnownTestLocations"; @@ -28,60 +27,58 @@ describe("ECSqlReader", (() => { const outDir = KnownTestLocations.outputDir; it("ecsql reader simple", async () => { - await using(ECDbTestHelper.createECDb(outDir, "test.ecdb", + using ecdb = ECDbTestHelper.createECDb(outDir, "test.ecdb", ` - `), async (ecdb: ECDb) => { - assert.isTrue(ecdb.isOpen); - ecdb.saveChanges(); - const params = new QueryBinder(); - params.bindIdSet(1, ["0x32"]); - const optionBuilder = new QueryOptionsBuilder(); - optionBuilder.setRowFormat(QueryRowFormat.UseJsPropertyNames); - reader = ecdb.createQueryReader("SELECT ECInstanceId, Name FROM meta.ECClassDef WHERE InVirtualSet(?, ECInstanceId)", params, optionBuilder.getOptions()); - const rows = await reader.toArray(); - assert.equal(rows[0].id, "0x32"); - assert.equal(rows.length, 1); - }); + `); + assert.isTrue(ecdb.isOpen); + ecdb.saveChanges(); + const params = new QueryBinder(); + params.bindIdSet(1, ["0x32"]); + const optionBuilder = new QueryOptionsBuilder(); + optionBuilder.setRowFormat(QueryRowFormat.UseJsPropertyNames); + reader = ecdb.createQueryReader("SELECT ECInstanceId, Name FROM meta.ECClassDef WHERE InVirtualSet(?, ECInstanceId)", params, optionBuilder.getOptions()); + const rows = await reader.toArray(); + assert.equal(rows[0].id, "0x32"); + assert.equal(rows.length, 1); }); it("ecsql reader simple using query reader", async () => { - await using(ECDbTestHelper.createECDb(outDir, "test.ecdb", + using ecdb = ECDbTestHelper.createECDb(outDir, "test.ecdb", ` - `), async (ecdb: ECDb) => { - assert.isTrue(ecdb.isOpen); - - const r = await ecdb.withStatement("INSERT INTO ts.Foo(n) VALUES(20)", async (stmt: ECSqlStatement) => { - return stmt.stepForInsert(); - }); - ecdb.saveChanges(); - assert.equal(r.status, DbResult.BE_SQLITE_DONE); - assert.equal(r.id, "0x1"); - - const params = new QueryBinder(); - params.bindId("firstId", r.id!); - - reader = ecdb.createQueryReader("SELECT ECInstanceId, n FROM ts.Foo WHERE ECInstanceId=:firstId", params, { limit: { count: 1 } }); - assert.isTrue(await reader.step()); - assert.equal(reader.current.id, "0x1"); - assert.equal(reader.current.ecinstanceid, "0x1"); - assert.equal(reader.current.n, 20); - assert.equal(reader.current.ID, "0x1"); - assert.equal(reader.current.ECINSTANCEID, "0x1"); - assert.equal(reader.current[0], "0x1"); - assert.equal(reader.current[1], 20); - - const row0 = reader.current.toRow(); - assert.equal(row0.ECInstanceId, "0x1"); - assert.equal(row0.n, 20); - - assert.isFalse(await reader.step()); - }); + `); + assert.isTrue(ecdb.isOpen); + + const r = await ecdb.withStatement("INSERT INTO ts.Foo(n) VALUES(20)", async (stmt: ECSqlStatement) => { + return stmt.stepForInsert(); + }); + ecdb.saveChanges(); + assert.equal(r.status, DbResult.BE_SQLITE_DONE); + assert.equal(r.id, "0x1"); + + const params = new QueryBinder(); + params.bindId("firstId", r.id!); + + reader = ecdb.createQueryReader("SELECT ECInstanceId, n FROM ts.Foo WHERE ECInstanceId=:firstId", params, { limit: { count: 1 } }); + assert.isTrue(await reader.step()); + assert.equal(reader.current.id, "0x1"); + assert.equal(reader.current.ecinstanceid, "0x1"); + assert.equal(reader.current.n, 20); + assert.equal(reader.current.ID, "0x1"); + assert.equal(reader.current.ECINSTANCEID, "0x1"); + assert.equal(reader.current[0], "0x1"); + assert.equal(reader.current[1], 20); + + const row0 = reader.current.toRow(); + assert.equal(row0.ECInstanceId, "0x1"); + assert.equal(row0.n, 20); + + assert.isFalse(await reader.step()); }); }); diff --git a/core/backend/src/test/ecdb/ECSqlStatement.test.ts b/core/backend/src/test/ecdb/ECSqlStatement.test.ts index 3d7ba228f973..48ae7f305625 100644 --- a/core/backend/src/test/ecdb/ECSqlStatement.test.ts +++ b/core/backend/src/test/ecdb/ECSqlStatement.test.ts @@ -3,7 +3,7 @@ * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ import { assert } from "chai"; -import { DbResult, Guid, GuidString, Id64, Id64String, using } from "@itwin/core-bentley"; +import { DbResult, Guid, GuidString, Id64, Id64String } from "@itwin/core-bentley"; import { NavigationValue, QueryBinder, QueryOptions, QueryOptionsBuilder, QueryRowFormat } from "@itwin/core-common"; import { Point2d, Point3d, Range3d, XAndY, XYAndZ } from "@itwin/core-geometry"; import { _nativeDb, ECDb, ECEnumValue, ECSqlColumnInfo, ECSqlInsertResult, ECSqlStatement, ECSqlValue, SnapshotDb } from "../../core-backend"; @@ -58,426 +58,415 @@ describe("ECSqlStatement", () => { const abbreviatedBlobVal = `{"bytes":${blobVal.byteLength}}`; it("check asynchronous step and stepForInsert methods", async () => { - await using(ECDbTestHelper.createECDb(outDir, "asyncmethodtest.ecdb", + using ecdb = ECDbTestHelper.createECDb(outDir, "asyncmethodtest.ecdb", ` - `), async (ecdb: ECDb) => { - assert.isTrue(ecdb.isOpen); + `); + assert.isTrue(ecdb.isOpen); - const r = await ecdb.withStatement("INSERT INTO ts.Foo(n,dt,fooId) VALUES(20,TIMESTAMP '2018-10-18T12:00:00Z',20)", async (stmt: ECSqlStatement) => { - return stmt.stepForInsert(); - }); - ecdb.saveChanges(); - assert.equal(r.status, DbResult.BE_SQLITE_DONE); - assert.equal(r.id, "0x1"); + const r = await ecdb.withStatement("INSERT INTO ts.Foo(n,dt,fooId) VALUES(20,TIMESTAMP '2018-10-18T12:00:00Z',20)", async (stmt: ECSqlStatement) => { + return stmt.stepForInsert(); }); + ecdb.saveChanges(); + assert.equal(r.status, DbResult.BE_SQLITE_DONE); + assert.equal(r.id, "0x1"); }); it("concurrent query get meta data", async () => { - await using(ECDbTestHelper.createECDb(outDir, "asyncmethodtest.ecdb", + using ecdb = ECDbTestHelper.createECDb(outDir, "asyncmethodtest.ecdb", ` - `), async (ecdb: ECDb) => { - assert.isTrue(ecdb.isOpen); + `); + assert.isTrue(ecdb.isOpen); - await ecdb.withStatement("INSERT INTO ts.Foo(n,dt,fooId) VALUES(20,TIMESTAMP '2018-10-18T12:00:00Z',20)", async (stmt: ECSqlStatement) => { - stmt.stepForInsert(); - }); - await ecdb.withStatement("INSERT INTO ts.Foo(n,dt,fooId) VALUES(30,TIMESTAMP '2019-10-18T12:00:00Z',30)", async (stmt: ECSqlStatement) => { - stmt.stepForInsert(); - }); - ecdb.saveChanges(); - const reader = ecdb.createQueryReader("SELECT * FROM ts.Foo"); - let props = await reader.getMetaData(); - assert.equal(props.length, 5); - let rows = 0; - while (await reader.step()) { - rows++; - } - assert.equal(rows, 2); - props = await reader.getMetaData(); - assert.equal(props.length, 5); + await ecdb.withStatement("INSERT INTO ts.Foo(n,dt,fooId) VALUES(20,TIMESTAMP '2018-10-18T12:00:00Z',20)", async (stmt: ECSqlStatement) => { + stmt.stepForInsert(); }); + await ecdb.withStatement("INSERT INTO ts.Foo(n,dt,fooId) VALUES(30,TIMESTAMP '2019-10-18T12:00:00Z',30)", async (stmt: ECSqlStatement) => { + stmt.stepForInsert(); + }); + ecdb.saveChanges(); + const reader = ecdb.createQueryReader("SELECT * FROM ts.Foo"); + let props = await reader.getMetaData(); + assert.equal(props.length, 5); + let rows = 0; + while (await reader.step()) { + rows++; + } + assert.equal(rows, 2); + props = await reader.getMetaData(); + assert.equal(props.length, 5); }); it("null string accessor", async () => { - await using(ECDbTestHelper.createECDb(outDir, "nullstring.ecdb"), async (ecdb: ECDb) => { - assert.isTrue(ecdb.isOpen); - await ecdb.withPreparedStatement(`VALUES(NULL)`, async (stmt: ECSqlStatement) => { - stmt.step(); - const str = stmt.getValue(0).getString(); - assert.equal(str, ""); - }); + using ecdb = ECDbTestHelper.createECDb(outDir, "nullstring.ecdb"); + assert.isTrue(ecdb.isOpen); + await ecdb.withPreparedStatement(`VALUES(NULL)`, async (stmt: ECSqlStatement) => { + stmt.step(); + const str = stmt.getValue(0).getString(); + assert.equal(str, ""); }); }); it("should page results", async () => { - await using(ECDbTestHelper.createECDb(outDir, "pagingresultset.ecdb", + using ecdb = ECDbTestHelper.createECDb(outDir, "pagingresultset.ecdb", ` - `), async (ecdb: ECDb) => { - assert.isTrue(ecdb.isOpen); - const ROW_COUNT = 27; - // insert test rows - for (let i = 1; i <= ROW_COUNT; i++) { - const r = await ecdb.withStatement(`insert into ts.Foo(n) values(${i})`, async (stmt: ECSqlStatement) => { - return stmt.stepForInsert(); - }); - assert.equal(r.status, DbResult.BE_SQLITE_DONE); - } - ecdb.saveChanges(); - for (let i = 1; i < ROW_COUNT; i++) { - const rowCount = await queryCount(ecdb, "SELECT ECInstanceId, ECClassId, n FROM ts.Foo WHERE n <= ?", new QueryBinder().bindInt(1, i)); - assert.equal(rowCount, i); - } + `); + assert.isTrue(ecdb.isOpen); + const ROW_COUNT = 27; + // insert test rows + for (let i = 1; i <= ROW_COUNT; i++) { + const r = await ecdb.withStatement(`insert into ts.Foo(n) values(${i})`, async (stmt: ECSqlStatement) => { + return stmt.stepForInsert(); + }); + assert.equal(r.status, DbResult.BE_SQLITE_DONE); + } + ecdb.saveChanges(); + for (let i = 1; i < ROW_COUNT; i++) { + const rowCount = await queryCount(ecdb, "SELECT ECInstanceId, ECClassId, n FROM ts.Foo WHERE n <= ?", new QueryBinder().bindInt(1, i)); + assert.equal(rowCount, i); + } - const temp = await queryRows(ecdb, "SELECT ECInstanceId FROM ONLY ts.Foo"); - assert.equal(temp.length, ROW_COUNT); - // query page by page - const PAGE_SIZE = 5; - const QUERY = "SELECT n FROM ts.Foo"; - const EXPECTED_ROW_COUNT = [5, 5, 5, 5, 5, 2]; - const ready = []; - for (let i = 0; i < EXPECTED_ROW_COUNT.length; i++) { - ready.push(queryRows(ecdb, QUERY, undefined, new QueryOptionsBuilder().setLimit({ offset: i * PAGE_SIZE, count: PAGE_SIZE }).getOptions())); - } - // verify if each page has right count of rows - const results = await Promise.all(ready); - for (let i = 0; i < EXPECTED_ROW_COUNT.length; i++) { - assert.equal(results[i].length, EXPECTED_ROW_COUNT[i]); - } - }); + const temp = await queryRows(ecdb, "SELECT ECInstanceId FROM ONLY ts.Foo"); + assert.equal(temp.length, ROW_COUNT); + // query page by page + const PAGE_SIZE = 5; + const QUERY = "SELECT n FROM ts.Foo"; + const EXPECTED_ROW_COUNT = [5, 5, 5, 5, 5, 2]; + const ready = []; + for (let i = 0; i < EXPECTED_ROW_COUNT.length; i++) { + ready.push(queryRows(ecdb, QUERY, undefined, new QueryOptionsBuilder().setLimit({ offset: i * PAGE_SIZE, count: PAGE_SIZE }).getOptions())); + } + // verify if each page has right count of rows + const results = await Promise.all(ready); + for (let i = 0; i < EXPECTED_ROW_COUNT.length; i++) { + assert.equal(results[i].length, EXPECTED_ROW_COUNT[i]); + } }); it("paging use cache statement queryRows()", async () => { - await using(ECDbTestHelper.createECDb(outDir, "pagingresultset.ecdb", + using ecdb = ECDbTestHelper.createECDb(outDir, "pagingresultset.ecdb", ` - `), async (ecdb: ECDb) => { - assert.isTrue(ecdb.isOpen); - const ROW_COUNT = 100; - // insert test rows - for (let i = 1; i <= ROW_COUNT; i++) { - const r = await ecdb.withStatement(`insert into ts.Foo(n) values(${i})`, async (stmt: ECSqlStatement) => { - return stmt.stepForInsert(); - }); - assert.equal(r.status, DbResult.BE_SQLITE_DONE); - } - ecdb.saveChanges(); - // check if varying page number does not require prepare new statements - ecdb.clearStatementCache(); - const rca = await queryRows(ecdb, "SELECT count(*) as nRows FROM ts.Foo"); - assert.equal(rca[0].nRows, 100); // expe - const rc = await queryCount(ecdb, "SELECT * FROM ts.Foo"); - assert.equal(rc, 100); // expe - let rowNo = 0; - for await (const row of ecdb.createQueryReader("SELECT * FROM ts.Foo", undefined, { rowFormat: QueryRowFormat.UseJsPropertyNames })) { - assert.equal(row.n, rowNo + 1); - rowNo = rowNo + 1; - } - assert.equal(rowNo, 100); // expect all rows - }); + `); + assert.isTrue(ecdb.isOpen); + const ROW_COUNT = 100; + // insert test rows + for (let i = 1; i <= ROW_COUNT; i++) { + const r = await ecdb.withStatement(`insert into ts.Foo(n) values(${i})`, async (stmt: ECSqlStatement) => { + return stmt.stepForInsert(); + }); + assert.equal(r.status, DbResult.BE_SQLITE_DONE); + } + ecdb.saveChanges(); + // check if varying page number does not require prepare new statements + ecdb.clearStatementCache(); + const rca = await queryRows(ecdb, "SELECT count(*) as nRows FROM ts.Foo"); + assert.equal(rca[0].nRows, 100); // expe + const rc = await queryCount(ecdb, "SELECT * FROM ts.Foo"); + assert.equal(rc, 100); // expe + let rowNo = 0; + for await (const row of ecdb.createQueryReader("SELECT * FROM ts.Foo", undefined, { rowFormat: QueryRowFormat.UseJsPropertyNames })) { + assert.equal(row.n, rowNo + 1); + rowNo = rowNo + 1; + } + assert.equal(rowNo, 100); // expect all rows }); it("should restart query", async () => { - await using(ECDbTestHelper.createECDb(outDir, "cancelquery.ecdb", + using ecdb = ECDbTestHelper.createECDb(outDir, "cancelquery.ecdb", ` - `), async (ecdb: ECDb) => { - assert.isTrue(ecdb.isOpen); - const ROW_COUNT = 100; - // insert test rows - for (let i = 1; i <= ROW_COUNT; i++) { - const r = await ecdb.withStatement(`insert into ts.Foo(n) values(${i})`, async (stmt: ECSqlStatement) => { - return stmt.stepForInsert(); - }); - assert.equal(r.status, DbResult.BE_SQLITE_DONE); - } - ecdb.saveChanges(); - ConcurrentQuery.resetConfig(ecdb[_nativeDb], { globalQuota: { time: 1 }, ignoreDelay: false }); - - let cancelled = 0; - let successful = 0; - let rowCount = 0; - const scheduleQuery = async (delay: number) => { - return new Promise(async (resolve, reject) => { - try { - const options = new QueryOptionsBuilder(); - options.setDelay(delay); - options.setRowFormat(QueryRowFormat.UseJsPropertyNames); - options.setRestartToken("tag"); - for await (const _row of ecdb.createQueryReader("SELECT * FROM ts.Foo", undefined, options.getOptions())) { - rowCount++; - } - successful++; + `); + assert.isTrue(ecdb.isOpen); + const ROW_COUNT = 100; + // insert test rows + for (let i = 1; i <= ROW_COUNT; i++) { + const r = await ecdb.withStatement(`insert into ts.Foo(n) values(${i})`, async (stmt: ECSqlStatement) => { + return stmt.stepForInsert(); + }); + assert.equal(r.status, DbResult.BE_SQLITE_DONE); + } + ecdb.saveChanges(); + ConcurrentQuery.resetConfig(ecdb[_nativeDb], { globalQuota: { time: 1 }, ignoreDelay: false }); + + let cancelled = 0; + let successful = 0; + let rowCount = 0; + const scheduleQuery = async (delay: number) => { + return new Promise(async (resolve, reject) => { + try { + const options = new QueryOptionsBuilder(); + options.setDelay(delay); + options.setRowFormat(QueryRowFormat.UseJsPropertyNames); + options.setRestartToken("tag"); + for await (const _row of ecdb.createQueryReader("SELECT * FROM ts.Foo", undefined, options.getOptions())) { + rowCount++; + } + successful++; + resolve(); + } catch (err: any) { + // we expect query to be cancelled + if (err.errorNumber === DbResult.BE_SQLITE_INTERRUPT) { + cancelled++; resolve(); - } catch (err: any) { - // we expect query to be cancelled - if (err.errorNumber === DbResult.BE_SQLITE_INTERRUPT) { - cancelled++; - resolve(); - } else { - reject(new Error("rejected")); - } + } else { + reject(new Error("rejected")); } - }); - }; + } + }); + }; - const queries = []; - queries.push(scheduleQuery(5000)); - queries.push(scheduleQuery(0)); + const queries = []; + queries.push(scheduleQuery(5000)); + queries.push(scheduleQuery(0)); - await Promise.all(queries); - // We expect at least one query to be cancelled - assert.isAtLeast(cancelled, 1); - assert.isAtLeast(successful, 1); - assert.isAtLeast(rowCount, 1); - }); + await Promise.all(queries); + // We expect at least one query to be cancelled + assert.isAtLeast(cancelled, 1); + assert.isAtLeast(successful, 1); + assert.isAtLeast(rowCount, 1); }); it("should use cache statement for query()", async () => { - await using(ECDbTestHelper.createECDb(outDir, "pagingresultset.ecdb", + using ecdb = ECDbTestHelper.createECDb(outDir, "pagingresultset.ecdb", ` - `), async (ecdb: ECDb) => { - assert.isTrue(ecdb.isOpen); - const ROW_COUNT = 27; - // insert test rows - for (let i = 1; i <= ROW_COUNT; i++) { - const r = await ecdb.withStatement(`insert into ts.Foo(n) values(${i})`, async (stmt: ECSqlStatement) => { - return stmt.stepForInsert(); - }); - assert.equal(r.status, DbResult.BE_SQLITE_DONE); - } - ecdb.saveChanges(); - // check if varying page number does not require prepare new statements - ecdb.clearStatementCache(); - for (const _testPageSize of [1, 2, 4, 5, 6, 7, 10, ROW_COUNT]) { - let rowNo = 1; - for await (const row of ecdb.createQueryReader("SELECT n FROM ts.Foo WHERE n != ? and ECInstanceId < ?", new QueryBinder().bindInt(1, 123).bindInt(2, 30), { rowFormat: QueryRowFormat.UseJsPropertyNames })) { - assert.equal(row.n, rowNo); - rowNo = rowNo + 1; - } - assert.equal(rowNo, 28); // expect all rows - assert.equal(0, ecdb.getCachedStatementCount()); // there must be single cached statement used with different size pages. + `); + assert.isTrue(ecdb.isOpen); + const ROW_COUNT = 27; + // insert test rows + for (let i = 1; i <= ROW_COUNT; i++) { + const r = await ecdb.withStatement(`insert into ts.Foo(n) values(${i})`, async (stmt: ECSqlStatement) => { + return stmt.stepForInsert(); + }); + assert.equal(r.status, DbResult.BE_SQLITE_DONE); + } + ecdb.saveChanges(); + // check if varying page number does not require prepare new statements + ecdb.clearStatementCache(); + for (const _testPageSize of [1, 2, 4, 5, 6, 7, 10, ROW_COUNT]) { + let rowNo = 1; + for await (const row of ecdb.createQueryReader("SELECT n FROM ts.Foo WHERE n != ? and ECInstanceId < ?", new QueryBinder().bindInt(1, 123).bindInt(2, 30), { rowFormat: QueryRowFormat.UseJsPropertyNames })) { + assert.equal(row.n, rowNo); + rowNo = rowNo + 1; } - }); + assert.equal(rowNo, 28); // expect all rows + assert.equal(0, ecdb.getCachedStatementCount()); // there must be single cached statement used with different size pages. + } }); it("concurrent query binding", async () => { - await using(ECDbTestHelper.createECDb(outDir, "pagingresultset.ecdb", + using ecdb = ECDbTestHelper.createECDb(outDir, "pagingresultset.ecdb", ` - `), async (ecdb: ECDb) => { - assert.isTrue(ecdb.isOpen); - for (let i = 1; i <= 5; i++) { - const r = await ecdb.withPreparedStatement(`insert into ts.Foo(n) values(${i})`, async (stmt: ECSqlStatement) => { - return stmt.stepForInsert(); - }); - assert.equal(r.status, DbResult.BE_SQLITE_DONE); - } - ecdb.saveChanges(); - for await (const row of ecdb.createQueryReader("SELECT count(*) as cnt FROM ts.Foo WHERE n in (:a, :b, :c)", new QueryBinder().bindInt("a", 1).bindInt("b", 2).bindInt("c", 3), { rowFormat: QueryRowFormat.UseJsPropertyNames })) { - assert.equal(row.cnt, 3); - } - for await (const row of ecdb.createQueryReader("SELECT count(*) as cnt FROM ts.Foo WHERE n in (?, ?, ?)", new QueryBinder().bindInt(1, 1).bindInt(2, 2).bindInt(3, 3), { rowFormat: QueryRowFormat.UseJsPropertyNames })) { + `); + assert.isTrue(ecdb.isOpen); + for (let i = 1; i <= 5; i++) { + const r = await ecdb.withPreparedStatement(`insert into ts.Foo(n) values(${i})`, async (stmt: ECSqlStatement) => { + return stmt.stepForInsert(); + }); + assert.equal(r.status, DbResult.BE_SQLITE_DONE); + } + ecdb.saveChanges(); + for await (const row of ecdb.createQueryReader("SELECT count(*) as cnt FROM ts.Foo WHERE n in (:a, :b, :c)", new QueryBinder().bindInt("a", 1).bindInt("b", 2).bindInt("c", 3), { rowFormat: QueryRowFormat.UseJsPropertyNames })) { + assert.equal(row.cnt, 3); + } + for await (const row of ecdb.createQueryReader("SELECT count(*) as cnt FROM ts.Foo WHERE n in (?, ?, ?)", new QueryBinder().bindInt(1, 1).bindInt(2, 2).bindInt(3, 3), { rowFormat: QueryRowFormat.UseJsPropertyNames })) { + assert.equal(row.cnt, 3); + } + const slm = new SequentialLogMatcher(); + slm.append().error().category("ECDb").message("No parameter index found for parameter name: d."); + try { + for await (const row of ecdb.createQueryReader("SELECT count(*) as cnt FROM ts.Foo WHERE n in (:a, :b, :c)", new QueryBinder().bindInt("a", 1).bindInt("b", 2).bindInt("c", 3).bindInt("d", 3), { rowFormat: QueryRowFormat.UseJsPropertyNames })) { assert.equal(row.cnt, 3); } - const slm = new SequentialLogMatcher(); - slm.append().error().category("ECDb").message("No parameter index found for parameter name: d."); - try { - for await (const row of ecdb.createQueryReader("SELECT count(*) as cnt FROM ts.Foo WHERE n in (:a, :b, :c)", new QueryBinder().bindInt("a", 1).bindInt("b", 2).bindInt("c", 3).bindInt("d", 3), { rowFormat: QueryRowFormat.UseJsPropertyNames })) { - assert.equal(row.cnt, 3); - } - assert.isFalse(true); - } catch (e) { assert.isNotNull(e); } - assert.isTrue(slm.finishAndDispose()); - }); + assert.isFalse(true); + } catch (e) { assert.isNotNull(e); } + assert.isTrue(slm.finishAndDispose()); }); it("check HextoId() and IdToHex() ecsql functions", async () => { - await using(ECDbTestHelper.createECDb(outDir, "pagingresultset.ecdb", + using ecdb = ECDbTestHelper.createECDb(outDir, "pagingresultset.ecdb", ` - `), async (ecdb: ECDb) => { - assert.isTrue(ecdb.isOpen); - for (let i = 1; i <= 2; i++) { - const r = await ecdb.withStatement(`insert into ts.Foo(n) values(${i})`, async (stmt: ECSqlStatement) => { - return stmt.stepForInsert(); - }); - assert.equal(r.status, DbResult.BE_SQLITE_DONE); - } - ecdb.saveChanges(); - for await (const row of ecdb.createQueryReader("SELECT IdToHex(ECInstanceId) as hexId, ECInstanceId, HexToId('0x1') as idhex FROM ts.Foo WHERE n = ?", new QueryBinder().bindInt(1, 1), { rowFormat: QueryRowFormat.UseJsPropertyNames })) { - assert.equal(row.hexId, row.id); - assert.equal(row.hexId, row.idhex); - } - }); + `); + assert.isTrue(ecdb.isOpen); + for (let i = 1; i <= 2; i++) { + const r = await ecdb.withStatement(`insert into ts.Foo(n) values(${i})`, async (stmt: ECSqlStatement) => { + return stmt.stepForInsert(); + }); + assert.equal(r.status, DbResult.BE_SQLITE_DONE); + } + ecdb.saveChanges(); + for await (const row of ecdb.createQueryReader("SELECT IdToHex(ECInstanceId) as hexId, ECInstanceId, HexToId('0x1') as idhex FROM ts.Foo WHERE n = ?", new QueryBinder().bindInt(1, 1), { rowFormat: QueryRowFormat.UseJsPropertyNames })) { + assert.equal(row.hexId, row.id); + assert.equal(row.hexId, row.idhex); + } }); it("should bind BeGuid", async () => { - await using(ECDbTestHelper.createECDb(outDir, "pagingresultset.ecdb", + using ecdb = ECDbTestHelper.createECDb(outDir, "pagingresultset.ecdb", ` - `), async (ecdb: ECDb) => { - assert.isTrue(ecdb.isOpen); - const maxRows = 10; - const guids: GuidString[] = []; - for (let i = 0; i < maxRows; i++) { - const r = await ecdb.withPreparedStatement(`insert into ts.Foo(guid) values(?)`, async (stmt: ECSqlStatement) => { - guids.push(Guid.createValue()); - stmt.bindGuid(1, guids[i]); - return stmt.stepForInsert(); + `); + assert.isTrue(ecdb.isOpen); + const maxRows = 10; + const guids: GuidString[] = []; + for (let i = 0; i < maxRows; i++) { + const r = await ecdb.withPreparedStatement(`insert into ts.Foo(guid) values(?)`, async (stmt: ECSqlStatement) => { + guids.push(Guid.createValue()); + stmt.bindGuid(1, guids[i]); + return stmt.stepForInsert(); + }); + assert.equal(r.status, DbResult.BE_SQLITE_DONE); + } + ecdb.saveChanges(); + + const uint8arrayToGuid = (guidArray: any) => { + if (!(guidArray instanceof Uint8Array)) + throw new Error("Expecting a Uint8Array type argument"); + + if (guidArray.byteLength !== 16) + throw new Error("Expecting a Uint8Array of length 16"); + + let guidStr: string = ""; + const part = [0, 4, 6, 8, 10, 16]; + for (let z = 0; z < part.length - 1; z++) { + guidArray.subarray(part[z], part[z + 1]).forEach((c) => { + guidStr += (`00${c.toString(16)}`).slice(-2); }); - assert.equal(r.status, DbResult.BE_SQLITE_DONE); + if (z < part.length - 2) + guidStr += "-"; } - ecdb.saveChanges(); - - const uint8arrayToGuid = (guidArray: any) => { - if (!(guidArray instanceof Uint8Array)) - throw new Error("Expecting a Uint8Array type argument"); - - if (guidArray.byteLength !== 16) - throw new Error("Expecting a Uint8Array of length 16"); - - let guidStr: string = ""; - const part = [0, 4, 6, 8, 10, 16]; - for (let z = 0; z < part.length - 1; z++) { - guidArray.subarray(part[z], part[z + 1]).forEach((c) => { - guidStr += (`00${c.toString(16)}`).slice(-2); - }); - if (z < part.length - 2) - guidStr += "-"; - } - return guidStr; - }; - const guidToUint8Array = (v: GuidString) => { - if (v.length !== 36) - throw new Error("Guid is expected to have 36 characters xxxxxxxx-xxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"); - - const ar = new Uint8Array(16); - const t = v.split("-").join(""); - let i = 0; - for (let z = 0; z < 32; z += 2) { - ar[i++] = parseInt(t.substring(z, z + 2), 16); - } - return ar; - }; - - const testGuid = "74da899a-6dde-406c-bf45-f4547d948f00"; - assert.equal(testGuid, uint8arrayToGuid(guidToUint8Array(testGuid))); - let k = 0; - assert.equal(await query(ecdb, "SELECT guid FROM ts.Foo ORDER BY ECInstanceId", undefined, undefined, (row: any) => { - assert.equal(row.guid, guids[k++]); - }), maxRows); - - // following will not return any guid BLOB ? = STRING - for (const guid of guids) { - assert.equal(await query(ecdb, "SELECT guid FROM ts.Foo WHERE guid=?", new QueryBinder().bindString(1, guid), undefined, (row: any) => { - assert.equal(row.guid, guid); - }), 1); - assert.equal(await query(ecdb, `SELECT guid FROM ts.Foo WHERE guid='${guid}'`, undefined, undefined, (row: any) => { - assert.equal(row.guid, guid); - }), 0); - assert.equal(await query(ecdb, `SELECT guid FROM ts.Foo WHERE guid=StrToGuid('${guid}')`, undefined, undefined, (row: any) => { - assert.equal(row.guid, guid); - }), 1); - assert.equal(await query(ecdb, "SELECT guid FROM ts.Foo WHERE guid=StrToGuid(?)", new QueryBinder().bindString(1, guid), undefined, (row: any) => { - assert.equal(row.guid, guid); - }), 1); - assert.equal(await query(ecdb, "SELECT guid FROM ts.Foo WHERE GuidToStr(guid)=?", new QueryBinder().bindString(1, guid), undefined, (row: any) => { - assert.equal(row.guid, guid); - }), 1); - assert.equal(await query(ecdb, "SELECT guid FROM ts.Foo WHERE guid=?", new QueryBinder().bindBlob(1, guidToUint8Array(guid)), undefined, (row: any) => { - assert.equal(row.guid, guid); - }), 1); - assert.equal(await query(ecdb, "SELECT guid FROM ts.Foo WHERE guid=StrToGuid(?)", new QueryBinder().bindString(1, guid), undefined, (row: any) => { - assert.equal(row.guid, guid); - }), 1); - assert.equal(await query(ecdb, "SELECT GuidToStr(guid) as gstr FROM ts.Foo WHERE guid=StrToGuid(?)", new QueryBinder().bindString(1, guid), undefined, (row: any) => { - assert.equal(row.gstr, guid); - }), 1); + return guidStr; + }; + const guidToUint8Array = (v: GuidString) => { + if (v.length !== 36) + throw new Error("Guid is expected to have 36 characters xxxxxxxx-xxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"); + + const ar = new Uint8Array(16); + const t = v.split("-").join(""); + let i = 0; + for (let z = 0; z < 32; z += 2) { + ar[i++] = parseInt(t.substring(z, z + 2), 16); } - }); + return ar; + }; + + const testGuid = "74da899a-6dde-406c-bf45-f4547d948f00"; + assert.equal(testGuid, uint8arrayToGuid(guidToUint8Array(testGuid))); + let k = 0; + assert.equal(await query(ecdb, "SELECT guid FROM ts.Foo ORDER BY ECInstanceId", undefined, undefined, (row: any) => { + assert.equal(row.guid, guids[k++]); + }), maxRows); + + // following will not return any guid BLOB ? = STRING + for (const guid of guids) { + assert.equal(await query(ecdb, "SELECT guid FROM ts.Foo WHERE guid=?", new QueryBinder().bindString(1, guid), undefined, (row: any) => { + assert.equal(row.guid, guid); + }), 1); + assert.equal(await query(ecdb, `SELECT guid FROM ts.Foo WHERE guid='${guid}'`, undefined, undefined, (row: any) => { + assert.equal(row.guid, guid); + }), 0); + assert.equal(await query(ecdb, `SELECT guid FROM ts.Foo WHERE guid=StrToGuid('${guid}')`, undefined, undefined, (row: any) => { + assert.equal(row.guid, guid); + }), 1); + assert.equal(await query(ecdb, "SELECT guid FROM ts.Foo WHERE guid=StrToGuid(?)", new QueryBinder().bindString(1, guid), undefined, (row: any) => { + assert.equal(row.guid, guid); + }), 1); + assert.equal(await query(ecdb, "SELECT guid FROM ts.Foo WHERE GuidToStr(guid)=?", new QueryBinder().bindString(1, guid), undefined, (row: any) => { + assert.equal(row.guid, guid); + }), 1); + assert.equal(await query(ecdb, "SELECT guid FROM ts.Foo WHERE guid=?", new QueryBinder().bindBlob(1, guidToUint8Array(guid)), undefined, (row: any) => { + assert.equal(row.guid, guid); + }), 1); + assert.equal(await query(ecdb, "SELECT guid FROM ts.Foo WHERE guid=StrToGuid(?)", new QueryBinder().bindString(1, guid), undefined, (row: any) => { + assert.equal(row.guid, guid); + }), 1); + assert.equal(await query(ecdb, "SELECT GuidToStr(guid) as gstr FROM ts.Foo WHERE guid=StrToGuid(?)", new QueryBinder().bindString(1, guid), undefined, (row: any) => { + assert.equal(row.gstr, guid); + }), 1); + } }); it("should bind Ids", async () => { - await using(ECDbTestHelper.createECDb(outDir, "bindids.ecdb"), async (ecdb: ECDb) => { + using ecdb = ECDbTestHelper.createECDb(outDir, "bindids.ecdb"); - assert.isTrue(ecdb.isOpen); + assert.isTrue(ecdb.isOpen); - const verify = async (ecdbToVerify: ECDb, actualRes: ECSqlInsertResult, expectedECInstanceId?: Id64String) => { - if (!expectedECInstanceId) { - assert.notEqual(actualRes.status, DbResult.BE_SQLITE_DONE); - assert.isUndefined(actualRes.id); - return; - } + const verify = async (ecdbToVerify: ECDb, actualRes: ECSqlInsertResult, expectedECInstanceId?: Id64String) => { + if (!expectedECInstanceId) { + assert.notEqual(actualRes.status, DbResult.BE_SQLITE_DONE); + assert.isUndefined(actualRes.id); + return; + } - assert.equal(actualRes.status, DbResult.BE_SQLITE_DONE); - assert.isDefined(actualRes.id); - assert.equal(actualRes.id!, expectedECInstanceId); + assert.equal(actualRes.status, DbResult.BE_SQLITE_DONE); + assert.isDefined(actualRes.id); + assert.equal(actualRes.id!, expectedECInstanceId); - ecdbToVerify.withPreparedStatement("SELECT ECInstanceId, ECClassId, Name FROM ecdbf.ExternalFileInfo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { - stmt.bindId(1, expectedId); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - const row = stmt.getRow(); - assert.equal(row.id, expectedECInstanceId); - assert.equal(row.className, "ECDbFileInfo.ExternalFileInfo"); - assert.equal(row.name, `${Id64.getLocalId(expectedECInstanceId).toString()}.txt`); - }); - assert.equal(await query(ecdb, "SELECT ECInstanceId, ECClassId, Name FROM ecdbf.ExternalFileInfo WHERE ECInstanceId=?", new QueryBinder().bindString(1, expectedId), new QueryOptionsBuilder().setLimit({ count: 1, offset: -1 }).getOptions(), (row) => { - assert.equal(row.id, expectedECInstanceId); - assert.equal(row.className, "ECDbFileInfo.ExternalFileInfo"); - assert.equal(row.name, `${Id64.getLocalId(expectedECInstanceId).toString()}.txt`); - }), 1); - }; - - let expectedId = Id64.fromLocalAndBriefcaseIds(4444, 0); - let r: ECSqlInsertResult = ecdb.withPreparedStatement("INSERT INTO ecdbf.ExternalFileInfo(ECInstanceId,Name) VALUES(?,?)", (stmt: ECSqlStatement) => { + ecdbToVerify.withPreparedStatement("SELECT ECInstanceId, ECClassId, Name FROM ecdbf.ExternalFileInfo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { stmt.bindId(1, expectedId); - stmt.bindString(2, "4444.txt"); - return stmt.stepForInsert(); - }); - await verify(ecdb, r, expectedId); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + const row = stmt.getRow(); + assert.equal(row.id, expectedECInstanceId); + assert.equal(row.className, "ECDbFileInfo.ExternalFileInfo"); + assert.equal(row.name, `${Id64.getLocalId(expectedECInstanceId).toString()}.txt`); + }); + assert.equal(await query(ecdb, "SELECT ECInstanceId, ECClassId, Name FROM ecdbf.ExternalFileInfo WHERE ECInstanceId=?", new QueryBinder().bindString(1, expectedId), new QueryOptionsBuilder().setLimit({ count: 1, offset: -1 }).getOptions(), (row) => { + assert.equal(row.id, expectedECInstanceId); + assert.equal(row.className, "ECDbFileInfo.ExternalFileInfo"); + assert.equal(row.name, `${Id64.getLocalId(expectedECInstanceId).toString()}.txt`); + }), 1); + }; - expectedId = Id64.fromLocalAndBriefcaseIds(4445, 0); - r = ecdb.withPreparedStatement("INSERT INTO ecdbf.ExternalFileInfo(ECInstanceId,Name) VALUES(:id,:name)", (stmt: ECSqlStatement) => { - stmt.bindId("id", expectedId); - stmt.bindString("name", "4445.txt"); + let expectedId = Id64.fromLocalAndBriefcaseIds(4444, 0); + let r: ECSqlInsertResult = ecdb.withPreparedStatement("INSERT INTO ecdbf.ExternalFileInfo(ECInstanceId,Name) VALUES(?,?)", (stmt: ECSqlStatement) => { + stmt.bindId(1, expectedId); + stmt.bindString(2, "4444.txt"); + return stmt.stepForInsert(); + }); + await verify(ecdb, r, expectedId); - return stmt.stepForInsert(); - }); - await verify(ecdb, r, expectedId); + expectedId = Id64.fromLocalAndBriefcaseIds(4445, 0); + r = ecdb.withPreparedStatement("INSERT INTO ecdbf.ExternalFileInfo(ECInstanceId,Name) VALUES(:id,:name)", (stmt: ECSqlStatement) => { + stmt.bindId("id", expectedId); + stmt.bindString("name", "4445.txt"); - expectedId = Id64.fromLocalAndBriefcaseIds(4446, 0); - r = ecdb.withPreparedStatement("INSERT INTO ecdbf.ExternalFileInfo(ECInstanceId,Name) VALUES(?,?)", (stmt: ECSqlStatement) => { - stmt.bindValues([expectedId, "4446.txt"]); - return stmt.stepForInsert(); - }); - await verify(ecdb, r, expectedId); + return stmt.stepForInsert(); + }); + await verify(ecdb, r, expectedId); - expectedId = Id64.fromLocalAndBriefcaseIds(4447, 0); - r = ecdb.withPreparedStatement("INSERT INTO ecdbf.ExternalFileInfo(ECInstanceId,Name) VALUES(:id,:name)", (stmt: ECSqlStatement) => { - stmt.bindValues({ id: expectedId, name: "4447.txt" }); - return stmt.stepForInsert(); - }); - await verify(ecdb, r, expectedId); + expectedId = Id64.fromLocalAndBriefcaseIds(4446, 0); + r = ecdb.withPreparedStatement("INSERT INTO ecdbf.ExternalFileInfo(ECInstanceId,Name) VALUES(?,?)", (stmt: ECSqlStatement) => { + stmt.bindValues([expectedId, "4446.txt"]); + return stmt.stepForInsert(); + }); + await verify(ecdb, r, expectedId); + + expectedId = Id64.fromLocalAndBriefcaseIds(4447, 0); + r = ecdb.withPreparedStatement("INSERT INTO ecdbf.ExternalFileInfo(ECInstanceId,Name) VALUES(:id,:name)", (stmt: ECSqlStatement) => { + stmt.bindValues({ id: expectedId, name: "4447.txt" }); + return stmt.stepForInsert(); }); + await verify(ecdb, r, expectedId); }); it("should bind numeric and date strings", async () => { @@ -501,776 +490,774 @@ describe("ECSqlStatement", () => { slm.append().error().category("ECDb").message(/String must be a valid ISO 8601 date, time or timestamp/gm); slm.append().error().category("ECDb").message(/only BindDateTime or BindText can be called for a column of the DateTime type/gm); - await using(ECDbTestHelper.createECDb(outDir, "bindnumericanddatestrings.ecdb", + using ecdb = ECDbTestHelper.createECDb(outDir, "bindnumericanddatestrings.ecdb", ` - `), async (ecdb: ECDb) => { - assert.isTrue(ecdb.isOpen); - - const r: ECSqlInsertResult = ecdb.withPreparedStatement("INSERT INTO ts.Foo(n,dt,fooId) VALUES(20,TIMESTAMP '2018-10-18T12:00:00Z',20)", (stmt: ECSqlStatement) => { - return stmt.stepForInsert(); - }); - ecdb.saveChanges(); - assert.equal(r.status, DbResult.BE_SQLITE_DONE); - const ecsqln = "SELECT 1 FROM ts.Foo WHERE n=?"; - await ecdb.withPreparedStatement(ecsqln, async (stmt: ECSqlStatement) => { - const nNum: number = 20; - const nStr: string = "20"; - const nDt: string = "2019-01-21T12:00:00Z"; - const nHexStr: string = "0x14"; - - stmt.bindInteger(1, nNum); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - stmt.reset(); - stmt.clearBindings(); - assert.equal(await queryCount(ecdb, ecsqln, new QueryBinder().bindInt(1, nNum), selectSingleRow), 1); - - stmt.bindValue(1, nNum); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - stmt.reset(); - stmt.clearBindings(); - - stmt.getBinder(1).bind(nNum); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - stmt.reset(); - stmt.clearBindings(); - - stmt.bindValues([nNum]); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - stmt.reset(); - stmt.clearBindings(); - - stmt.bindString(1, nStr); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - stmt.reset(); - stmt.clearBindings(); - - assert.equal(await queryCount(ecdb, ecsqln, new QueryBinder().bindString(1, nStr), selectSingleRow), 1); - - stmt.bindValue(1, nStr); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - stmt.reset(); - stmt.clearBindings(); - - stmt.getBinder(1).bind(nStr); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - stmt.reset(); - stmt.clearBindings(); - - stmt.bindValues([nStr]); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - stmt.reset(); - stmt.clearBindings(); + `); + assert.isTrue(ecdb.isOpen); - stmt.bindString(1, nDt); - assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE, "Date time string is not parsed. SQLite just converts it to something which does not match"); - stmt.reset(); - stmt.clearBindings(); - - assert.equal(await queryCount(ecdb, ecsqln, new QueryBinder().bindString(1, nDt), selectSingleRow), 0); - - stmt.bindValue(1, nDt); - assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE, "Date time string is not parsed. SQLite just converts it to something which does not match"); - stmt.reset(); - stmt.clearBindings(); - - stmt.getBinder(1).bind(nDt); - assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE, "Date time string is not parsed. SQLite just converts it to something which does not match"); - stmt.reset(); - stmt.clearBindings(); - - stmt.bindValues([nDt]); - assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE, "Date time string is not parsed. SQLite just converts it to something which does not match"); - stmt.reset(); - stmt.clearBindings(); - - stmt.bindString(1, nHexStr); - assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE, "Hex string is not parsed. SQLite just converts it to something which does not match"); - stmt.reset(); - stmt.clearBindings(); - - assert.equal(await queryCount(ecdb, ecsqln, new QueryBinder().bindString(1, nHexStr), selectSingleRow), 0); - - stmt.bindValue(1, nHexStr); - assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE, "Hex string is not parsed. SQLite just converts it to something which does not match"); - stmt.reset(); - stmt.clearBindings(); - - stmt.getBinder(1).bind(nHexStr); - assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE, "Hex string is not parsed. SQLite just converts it to something which does not match"); - stmt.reset(); - stmt.clearBindings(); - - stmt.bindValues([nHexStr]); - assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE, "Hex string is not parsed. SQLite just converts it to something which does not match"); - stmt.reset(); - stmt.clearBindings(); - }); - - const ecsqldt = "SELECT 1 FROM ts.Foo WHERE dt=?"; - await ecdb.withPreparedStatement(ecsqldt, async (stmt: ECSqlStatement) => { - const dtStr: string = "2018-10-18T12:00:00Z"; - const num: number = 2458410; - const str: string = "2458410"; - const hexStr: string = "0x25832a"; - - stmt.bindDateTime(1, dtStr); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - stmt.reset(); - stmt.clearBindings(); - - assert.equal(await queryCount(ecdb, ecsqldt, new QueryBinder().bindString(1, dtStr)), 1); - stmt.bindString(1, dtStr); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - stmt.reset(); - stmt.clearBindings(); - - stmt.bindValue(1, dtStr); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - stmt.reset(); - stmt.clearBindings(); - - stmt.getBinder(1).bind(dtStr); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - stmt.reset(); - stmt.clearBindings(); - - stmt.bindValues([dtStr]); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - stmt.reset(); - stmt.clearBindings(); - - assert.throw(() => stmt.bindInteger(1, num)); - stmt.clearBindings(); - - assert.equal(await queryCount(ecdb, ecsqldt, QueryBinder.from([num])), 0); - assert.throw(() => stmt.bindValue(1, num)); - stmt.clearBindings(); - - assert.throw(() => stmt.getBinder(1).bind(num)); - stmt.clearBindings(); - - assert.throw(() => stmt.bindValues([num])); - stmt.clearBindings(); - - assert.throw(() => stmt.bindString(1, str)); - stmt.clearBindings(); - - assert.throw(() => stmt.bindValue(1, str)); - stmt.clearBindings(); - - assert.equal(await queryCount(ecdb, ecsqldt, QueryBinder.from([str])), 0); - - assert.throw(() => stmt.getBinder(1).bind(str)); - stmt.clearBindings(); - - assert.throw(() => stmt.bindValues([str])); - stmt.clearBindings(); - - assert.throw(() => stmt.bindString(1, hexStr)); - stmt.clearBindings(); - - assert.equal(await queryCount(ecdb, ecsqldt, QueryBinder.from([hexStr])), 0); - - assert.throw(() => stmt.bindValue(1, hexStr)); - stmt.clearBindings(); - - assert.throw(() => stmt.getBinder(1).bind(hexStr)); - stmt.clearBindings(); - - assert.throw(() => stmt.bindValues([hexStr])); - stmt.clearBindings(); - }); - - const ecsqlfooId = "SELECT 1 FROM ts.Foo WHERE fooId=?"; - await ecdb.withPreparedStatement(ecsqlfooId, async (stmt: ECSqlStatement) => { - const num: number = 20; - const str: string = "20"; - const dt: string = "2019-01-21T12:00:00Z"; - const hexStr: string = "0x14"; - - stmt.bindId(1, hexStr); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - stmt.reset(); - stmt.clearBindings(); - - assert.equal(await queryCount(ecdb, ecsqldt, QueryBinder.from([hexStr])), 0); - - stmt.bindValues([hexStr]); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - stmt.reset(); - stmt.clearBindings(); - - stmt.bindString(1, hexStr); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - stmt.reset(); - stmt.clearBindings(); - - stmt.bindValue(1, hexStr); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - stmt.reset(); - stmt.clearBindings(); - - stmt.getBinder(1).bind(hexStr); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - stmt.reset(); - stmt.clearBindings(); - - stmt.bindValues([hexStr]); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - stmt.reset(); - stmt.clearBindings(); - - stmt.bindString(1, str); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - stmt.reset(); - stmt.clearBindings(); - - assert.equal(await queryCount(ecdb, ecsqldt, QueryBinder.from([str])), 0); - - stmt.bindValue(1, str); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - stmt.reset(); - stmt.clearBindings(); - - stmt.getBinder(1).bind(str); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - stmt.reset(); - stmt.clearBindings(); - - stmt.bindValues([str]); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - stmt.reset(); - stmt.clearBindings(); - - stmt.bindInteger(1, num); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - stmt.reset(); - stmt.clearBindings(); - - assert.equal(await queryCount(ecdb, ecsqldt, QueryBinder.from([num])), 0); - - stmt.bindValue(1, num); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - stmt.reset(); - stmt.clearBindings(); - - stmt.getBinder(1).bind(num); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - stmt.reset(); - stmt.clearBindings(); + const r: ECSqlInsertResult = ecdb.withPreparedStatement("INSERT INTO ts.Foo(n,dt,fooId) VALUES(20,TIMESTAMP '2018-10-18T12:00:00Z',20)", (stmt: ECSqlStatement) => { + return stmt.stepForInsert(); + }); + ecdb.saveChanges(); + assert.equal(r.status, DbResult.BE_SQLITE_DONE); + const ecsqln = "SELECT 1 FROM ts.Foo WHERE n=?"; + await ecdb.withPreparedStatement(ecsqln, async (stmt: ECSqlStatement) => { + const nNum: number = 20; + const nStr: string = "20"; + const nDt: string = "2019-01-21T12:00:00Z"; + const nHexStr: string = "0x14"; + + stmt.bindInteger(1, nNum); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + stmt.reset(); + stmt.clearBindings(); + assert.equal(await queryCount(ecdb, ecsqln, new QueryBinder().bindInt(1, nNum), selectSingleRow), 1); + + stmt.bindValue(1, nNum); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + stmt.reset(); + stmt.clearBindings(); + + stmt.getBinder(1).bind(nNum); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + stmt.reset(); + stmt.clearBindings(); + + stmt.bindValues([nNum]); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + stmt.reset(); + stmt.clearBindings(); + + stmt.bindString(1, nStr); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + stmt.reset(); + stmt.clearBindings(); + + assert.equal(await queryCount(ecdb, ecsqln, new QueryBinder().bindString(1, nStr), selectSingleRow), 1); + + stmt.bindValue(1, nStr); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + stmt.reset(); + stmt.clearBindings(); + + stmt.getBinder(1).bind(nStr); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + stmt.reset(); + stmt.clearBindings(); + + stmt.bindValues([nStr]); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + stmt.reset(); + stmt.clearBindings(); + + stmt.bindString(1, nDt); + assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE, "Date time string is not parsed. SQLite just converts it to something which does not match"); + stmt.reset(); + stmt.clearBindings(); + + assert.equal(await queryCount(ecdb, ecsqln, new QueryBinder().bindString(1, nDt), selectSingleRow), 0); + + stmt.bindValue(1, nDt); + assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE, "Date time string is not parsed. SQLite just converts it to something which does not match"); + stmt.reset(); + stmt.clearBindings(); + + stmt.getBinder(1).bind(nDt); + assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE, "Date time string is not parsed. SQLite just converts it to something which does not match"); + stmt.reset(); + stmt.clearBindings(); + + stmt.bindValues([nDt]); + assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE, "Date time string is not parsed. SQLite just converts it to something which does not match"); + stmt.reset(); + stmt.clearBindings(); + + stmt.bindString(1, nHexStr); + assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE, "Hex string is not parsed. SQLite just converts it to something which does not match"); + stmt.reset(); + stmt.clearBindings(); + + assert.equal(await queryCount(ecdb, ecsqln, new QueryBinder().bindString(1, nHexStr), selectSingleRow), 0); + + stmt.bindValue(1, nHexStr); + assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE, "Hex string is not parsed. SQLite just converts it to something which does not match"); + stmt.reset(); + stmt.clearBindings(); + + stmt.getBinder(1).bind(nHexStr); + assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE, "Hex string is not parsed. SQLite just converts it to something which does not match"); + stmt.reset(); + stmt.clearBindings(); + + stmt.bindValues([nHexStr]); + assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE, "Hex string is not parsed. SQLite just converts it to something which does not match"); + stmt.reset(); + stmt.clearBindings(); + }); - stmt.bindValues([num]); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - stmt.reset(); - stmt.clearBindings(); + const ecsqldt = "SELECT 1 FROM ts.Foo WHERE dt=?"; + await ecdb.withPreparedStatement(ecsqldt, async (stmt: ECSqlStatement) => { + const dtStr: string = "2018-10-18T12:00:00Z"; + const num: number = 2458410; + const str: string = "2458410"; + const hexStr: string = "0x25832a"; - stmt.bindString(1, dt); - assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE, "DateTime string is not parsed into what it means. SQlite just uses its regular string conversion routines which don't match here"); - stmt.reset(); - stmt.clearBindings(); + stmt.bindDateTime(1, dtStr); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + stmt.reset(); + stmt.clearBindings(); - assert.equal(await queryCount(ecdb, ecsqldt, QueryBinder.from([dt])), 0); + assert.equal(await queryCount(ecdb, ecsqldt, new QueryBinder().bindString(1, dtStr)), 1); + stmt.bindString(1, dtStr); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + stmt.reset(); + stmt.clearBindings(); - stmt.bindValue(1, dt); - assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE, "DateTime string is not parsed into what it means. SQlite just uses its regular string conversion routines which don't match here"); - stmt.reset(); - stmt.clearBindings(); + stmt.bindValue(1, dtStr); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + stmt.reset(); + stmt.clearBindings(); - stmt.getBinder(1).bind(dt); - assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE, "DateTime string is not parsed into what it means. SQlite just uses its regular string conversion routines which don't match here"); - stmt.reset(); - stmt.clearBindings(); - - stmt.bindValues([dt]); - assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE, "DateTime string is not parsed into what it means. SQlite just uses its regular string conversion routines which don't match here"); - stmt.reset(); - stmt.clearBindings(); - }); - }); - assert.isTrue(slm.finishAndDispose()); - }); + stmt.getBinder(1).bind(dtStr); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + stmt.reset(); + stmt.clearBindings(); - it("should bind numbers", async () => { - await using(ECDbTestHelper.createECDb(outDir, "bindnumbers.ecdb", - ` - - - - - - - - `), async (ecdb: ECDb) => { - assert.isTrue(ecdb.isOpen); - - const doubleVal: number = 3.5; - let id = await ecdb.withPreparedStatement("INSERT INTO Test.Foo(D,I,L,S,Description) VALUES(?,?,?,?,'bindDouble')", async (stmt: ECSqlStatement) => { - stmt.bindDouble(1, doubleVal); - stmt.bindDouble(2, doubleVal); - stmt.bindDouble(3, doubleVal); - stmt.bindDouble(4, doubleVal); - const r: ECSqlInsertResult = stmt.stepForInsert(); - assert.equal(r.status, DbResult.BE_SQLITE_DONE); - return r.id!; - }); + stmt.bindValues([dtStr]); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + stmt.reset(); + stmt.clearBindings(); - await ecdb.withPreparedStatement("SELECT D,I,L,S FROM Test.Foo WHERE ECInstanceId=?", async (stmt: ECSqlStatement) => { - stmt.bindId(1, id); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - const row = stmt.getRow(); - assert.equal(row.d, doubleVal); - assert.equal(row.i, 3); - assert.equal(row.l, 3); - assert.equal(row.s, "3.5"); - }); + assert.throw(() => stmt.bindInteger(1, num)); + stmt.clearBindings(); - assert.equal(await query(ecdb, "SELECT D,I,L,S FROM Test.Foo WHERE ECInstanceId=?", QueryBinder.from([id]), { limit: { count: 1 } }, (row: any) => { - assert.equal(row.d, doubleVal); - assert.equal(row.i, 3); - assert.equal(row.l, 3); - assert.equal(row.s, "3.5"); - }), 1); + assert.equal(await queryCount(ecdb, ecsqldt, QueryBinder.from([num])), 0); + assert.throw(() => stmt.bindValue(1, num)); + stmt.clearBindings(); - const smallIntVal: number = 3; - id = ecdb.withPreparedStatement("INSERT INTO Test.Foo(D,I,L,S,Description) VALUES(?,?,?,?,'bindInteger, small int')", (stmt: ECSqlStatement) => { - stmt.bindInteger(1, smallIntVal); - stmt.bindInteger(2, smallIntVal); - stmt.bindInteger(3, smallIntVal); - stmt.bindInteger(4, smallIntVal); - const r: ECSqlInsertResult = stmt.stepForInsert(); - assert.equal(r.status, DbResult.BE_SQLITE_DONE); - return r.id!; - }); + assert.throw(() => stmt.getBinder(1).bind(num)); + stmt.clearBindings(); - ecdb.withPreparedStatement("SELECT D,I,L,S FROM Test.Foo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { - stmt.bindId(1, id); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - const row = stmt.getRow(); - assert.equal(row.d, smallIntVal); - assert.equal(row.i, smallIntVal); - assert.equal(row.l, smallIntVal); - assert.equal(row.s, "3"); - }); + assert.throw(() => stmt.bindValues([num])); + stmt.clearBindings(); - assert.equal(await query(ecdb, "SELECT D,I,L,S FROM Test.Foo WHERE ECInstanceId=?", QueryBinder.from([id]), selectSingleRow, (row: any) => { - assert.equal(row.d, smallIntVal); - assert.equal(row.i, smallIntVal); - assert.equal(row.l, smallIntVal); - assert.equal(row.s, "3"); - }), 1); + assert.throw(() => stmt.bindString(1, str)); + stmt.clearBindings(); - const largeUnsafeNumber: number = 12312312312312323654; // too large for int64, but fits into uint64 - assert.isFalse(Number.isSafeInteger(largeUnsafeNumber)); - const largeUnsafeNumberStr: string = "12312312312312323654"; - const largeUnsafeNumberHexStr: string = "0xaade1ed08b0b5e46"; + assert.throw(() => stmt.bindValue(1, str)); + stmt.clearBindings(); - id = ecdb.withPreparedStatement("INSERT INTO Test.Foo(D,I,L,S,Description) VALUES(?,?,?,?,'bindInteger, large unsafe number as string')", (stmt: ECSqlStatement) => { - stmt.bindInteger(1, largeUnsafeNumberStr); - stmt.bindInteger(2, largeUnsafeNumberStr); - stmt.bindInteger(3, largeUnsafeNumberStr); - stmt.bindInteger(4, largeUnsafeNumberStr); - const r: ECSqlInsertResult = stmt.stepForInsert(); - assert.equal(r.status, DbResult.BE_SQLITE_DONE); - return r.id!; - }); + assert.equal(await queryCount(ecdb, ecsqldt, QueryBinder.from([str])), 0); - ecdb.withPreparedStatement("SELECT Str(I) si, HexStr(I) hi, Str(L) sl, HexStr(L) hl FROM Test.Foo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { - stmt.bindId(1, id); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - const row = stmt.getRow(); - assert.equal(row.si, largeUnsafeNumberStr); - assert.equal(row.hi, largeUnsafeNumberHexStr); - assert.equal(row.sl, largeUnsafeNumberStr); - assert.equal(row.hl, largeUnsafeNumberHexStr); - }); + assert.throw(() => stmt.getBinder(1).bind(str)); + stmt.clearBindings(); - // assert.equal(await query(ecdb, "SELECT Str(I) si, HexStr(I) hi, Str(L) sl, HexStr(L) hl FROM Test.Foo WHERE ECInstanceId=?", [id], 1, (row: any) => { - // assert.equal(row.si, largeUnsafeNumberStr); - // assert.equal(row.hi, largeUnsafeNumberHexStr); - // assert.equal(row.sl, largeUnsafeNumberStr); - // assert.equal(row.hl, largeUnsafeNumberHexStr); - // }), 1); - - id = ecdb.withPreparedStatement("INSERT INTO Test.Foo(D,I,L,S,Description) VALUES(?,?,?,?,'bindInteger, large unsafe number as hexstring')", (stmt: ECSqlStatement) => { - stmt.bindInteger(1, largeUnsafeNumberHexStr); - stmt.bindInteger(2, largeUnsafeNumberHexStr); - stmt.bindInteger(3, largeUnsafeNumberHexStr); - stmt.bindInteger(4, largeUnsafeNumberHexStr); - const r: ECSqlInsertResult = stmt.stepForInsert(); - assert.equal(r.status, DbResult.BE_SQLITE_DONE); - return r.id!; - }); + assert.throw(() => stmt.bindValues([str])); + stmt.clearBindings(); - ecdb.withPreparedStatement("SELECT Str(I) si, HexStr(I) hi, Str(L) sl, HexStr(L) hl FROM Test.Foo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { - stmt.bindId(1, id); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - const row = stmt.getRow(); - assert.equal(row.si, largeUnsafeNumberStr); - assert.equal(row.hi, largeUnsafeNumberHexStr); - assert.equal(row.sl, largeUnsafeNumberStr); - assert.equal(row.hl, largeUnsafeNumberHexStr); - }); + assert.throw(() => stmt.bindString(1, hexStr)); + stmt.clearBindings(); - // assert.equal(await query(ecdb, "SELECT Str(I) si, HexStr(I) hi, Str(L) sl, HexStr(L) hl FROM Test.Foo WHERE ECInstanceId=?", [id], 1, (row: any) => { - // assert.equal(row.si, largeUnsafeNumberStr); - // assert.equal(row.hi, largeUnsafeNumberHexStr); - // assert.equal(row.sl, largeUnsafeNumberStr); - // assert.equal(row.hl, largeUnsafeNumberHexStr); - // }), 1); - - id = ecdb.withPreparedStatement("INSERT INTO Test.Foo(D,I,L,S,Description) VALUES(?,?,?,?,'bindString, large unsafe number as string')", (stmt: ECSqlStatement) => { - stmt.bindString(1, largeUnsafeNumberStr); - stmt.bindString(2, largeUnsafeNumberStr); - stmt.bindString(3, largeUnsafeNumberStr); - stmt.bindString(4, largeUnsafeNumberStr); - const r: ECSqlInsertResult = stmt.stepForInsert(); - assert.equal(r.status, DbResult.BE_SQLITE_DONE); - return r.id!; - }); + assert.equal(await queryCount(ecdb, ecsqldt, QueryBinder.from([hexStr])), 0); - // uint64 cannot be bound as string in SQLite. They get converted to reals - ecdb.withPreparedStatement("SELECT D,I,L,S FROM Test.Foo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { - stmt.bindId(1, id); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - const row = stmt.getRow(); - assert.isNumber(row.d); - assert.isNumber(row.i); - assert.isNumber(row.l); - assert.equal(row.s, largeUnsafeNumberStr); - }); + assert.throw(() => stmt.bindValue(1, hexStr)); + stmt.clearBindings(); - assert.equal(await query(ecdb, "SELECT D,I,L,S FROM Test.Foo WHERE ECInstanceId=?", QueryBinder.from([id]), selectSingleRow, (row: any) => { - assert.isNumber(row.d); - assert.isNumber(row.i); - assert.isNumber(row.l); - assert.equal(row.s, largeUnsafeNumberStr); - }), 1); + assert.throw(() => stmt.getBinder(1).bind(hexStr)); + stmt.clearBindings(); - id = ecdb.withPreparedStatement("INSERT INTO Test.Foo(D,I,L,S,Description) VALUES(?,?,?,?,'bindString, large unsafe number as hexstring')", (stmt: ECSqlStatement) => { - stmt.bindString(1, largeUnsafeNumberHexStr); - stmt.bindString(2, largeUnsafeNumberHexStr); - stmt.bindString(3, largeUnsafeNumberHexStr); - stmt.bindString(4, largeUnsafeNumberHexStr); - const r: ECSqlInsertResult = stmt.stepForInsert(); - assert.equal(r.status, DbResult.BE_SQLITE_DONE); - return r.id!; - }); + assert.throw(() => stmt.bindValues([hexStr])); + stmt.clearBindings(); + }); - ecdb.withPreparedStatement("SELECT CAST(D AS TEXT) d,CAST(I AS TEXT) i,CAST(L AS TEXT) l,S FROM Test.Foo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { - stmt.bindId(1, id); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - const row = stmt.getRow(); - assert.equal(row.d, largeUnsafeNumberHexStr); - assert.equal(row.i, largeUnsafeNumberHexStr); - assert.equal(row.l, largeUnsafeNumberHexStr); - assert.equal(row.s, largeUnsafeNumberHexStr); - }); + const ecsqlfooId = "SELECT 1 FROM ts.Foo WHERE fooId=?"; + await ecdb.withPreparedStatement(ecsqlfooId, async (stmt: ECSqlStatement) => { + const num: number = 20; + const str: string = "20"; + const dt: string = "2019-01-21T12:00:00Z"; + const hexStr: string = "0x14"; + + stmt.bindId(1, hexStr); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + stmt.reset(); + stmt.clearBindings(); + + assert.equal(await queryCount(ecdb, ecsqldt, QueryBinder.from([hexStr])), 0); + + stmt.bindValues([hexStr]); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + stmt.reset(); + stmt.clearBindings(); + + stmt.bindString(1, hexStr); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + stmt.reset(); + stmt.clearBindings(); + + stmt.bindValue(1, hexStr); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + stmt.reset(); + stmt.clearBindings(); + + stmt.getBinder(1).bind(hexStr); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + stmt.reset(); + stmt.clearBindings(); + + stmt.bindValues([hexStr]); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + stmt.reset(); + stmt.clearBindings(); + + stmt.bindString(1, str); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + stmt.reset(); + stmt.clearBindings(); + + assert.equal(await queryCount(ecdb, ecsqldt, QueryBinder.from([str])), 0); + + stmt.bindValue(1, str); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + stmt.reset(); + stmt.clearBindings(); + + stmt.getBinder(1).bind(str); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + stmt.reset(); + stmt.clearBindings(); + + stmt.bindValues([str]); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + stmt.reset(); + stmt.clearBindings(); + + stmt.bindInteger(1, num); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + stmt.reset(); + stmt.clearBindings(); + + assert.equal(await queryCount(ecdb, ecsqldt, QueryBinder.from([num])), 0); + + stmt.bindValue(1, num); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + stmt.reset(); + stmt.clearBindings(); + + stmt.getBinder(1).bind(num); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + stmt.reset(); + stmt.clearBindings(); + + stmt.bindValues([num]); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + stmt.reset(); + stmt.clearBindings(); + + stmt.bindString(1, dt); + assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE, "DateTime string is not parsed into what it means. SQlite just uses its regular string conversion routines which don't match here"); + stmt.reset(); + stmt.clearBindings(); + + assert.equal(await queryCount(ecdb, ecsqldt, QueryBinder.from([dt])), 0); + + stmt.bindValue(1, dt); + assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE, "DateTime string is not parsed into what it means. SQlite just uses its regular string conversion routines which don't match here"); + stmt.reset(); + stmt.clearBindings(); + + stmt.getBinder(1).bind(dt); + assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE, "DateTime string is not parsed into what it means. SQlite just uses its regular string conversion routines which don't match here"); + stmt.reset(); + stmt.clearBindings(); + + stmt.bindValues([dt]); + assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE, "DateTime string is not parsed into what it means. SQlite just uses its regular string conversion routines which don't match here"); + stmt.reset(); + stmt.clearBindings(); + }); + assert.isTrue(slm.finishAndDispose()); + }); - assert.equal(await query(ecdb, "SELECT CAST(D AS TEXT) d,CAST(I AS TEXT) i,CAST(L AS TEXT) l,S FROM Test.Foo WHERE ECInstanceId=?", QueryBinder.from([id]), selectSingleRow, (row: any) => { - assert.equal(row.d, largeUnsafeNumberHexStr); - assert.equal(row.i, largeUnsafeNumberHexStr); - assert.equal(row.l, largeUnsafeNumberHexStr); - assert.equal(row.s, largeUnsafeNumberHexStr); - }), 1); + it("should bind numbers", async () => { + using ecdb = ECDbTestHelper.createECDb(outDir, "bindnumbers.ecdb", + ` + + + + + + + + `); + assert.isTrue(ecdb.isOpen); + + const doubleVal: number = 3.5; + let id = await ecdb.withPreparedStatement("INSERT INTO Test.Foo(D,I,L,S,Description) VALUES(?,?,?,?,'bindDouble')", async (stmt: ECSqlStatement) => { + stmt.bindDouble(1, doubleVal); + stmt.bindDouble(2, doubleVal); + stmt.bindDouble(3, doubleVal); + stmt.bindDouble(4, doubleVal); + const r: ECSqlInsertResult = stmt.stepForInsert(); + assert.equal(r.status, DbResult.BE_SQLITE_DONE); + return r.id!; + }); - const largeNegUnsafeNumber: number = -123123123123123236; - assert.isFalse(Number.isSafeInteger(largeNegUnsafeNumber)); - const largeNegUnsafeNumberStr: string = "-123123123123123236"; + await ecdb.withPreparedStatement("SELECT D,I,L,S FROM Test.Foo WHERE ECInstanceId=?", async (stmt: ECSqlStatement) => { + stmt.bindId(1, id); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + const row = stmt.getRow(); + assert.equal(row.d, doubleVal); + assert.equal(row.i, 3); + assert.equal(row.l, 3); + assert.equal(row.s, "3.5"); + }); - id = ecdb.withPreparedStatement("INSERT INTO Test.Foo(D,I,L,S,Description) VALUES(?,?,?,?,'bindInteger, large negative unsafe number as string')", (stmt: ECSqlStatement) => { - stmt.bindInteger(1, largeNegUnsafeNumberStr); - stmt.bindInteger(2, largeNegUnsafeNumberStr); - stmt.bindInteger(3, largeNegUnsafeNumberStr); - stmt.bindInteger(4, largeNegUnsafeNumberStr); - const r: ECSqlInsertResult = stmt.stepForInsert(); - assert.equal(r.status, DbResult.BE_SQLITE_DONE); - return r.id!; - }); + assert.equal(await query(ecdb, "SELECT D,I,L,S FROM Test.Foo WHERE ECInstanceId=?", QueryBinder.from([id]), { limit: { count: 1 } }, (row: any) => { + assert.equal(row.d, doubleVal); + assert.equal(row.i, 3); + assert.equal(row.l, 3); + assert.equal(row.s, "3.5"); + }), 1); + + const smallIntVal: number = 3; + id = ecdb.withPreparedStatement("INSERT INTO Test.Foo(D,I,L,S,Description) VALUES(?,?,?,?,'bindInteger, small int')", (stmt: ECSqlStatement) => { + stmt.bindInteger(1, smallIntVal); + stmt.bindInteger(2, smallIntVal); + stmt.bindInteger(3, smallIntVal); + stmt.bindInteger(4, smallIntVal); + const r: ECSqlInsertResult = stmt.stepForInsert(); + assert.equal(r.status, DbResult.BE_SQLITE_DONE); + return r.id!; + }); - ecdb.withPreparedStatement("SELECT CAST(I AS TEXT) i, CAST(L AS TEXT) l,S FROM Test.Foo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { - stmt.bindId(1, id); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - const row = stmt.getRow(); - assert.equal(row.i, largeNegUnsafeNumberStr); - assert.equal(row.l, largeNegUnsafeNumberStr); - assert.equal(row.s, largeNegUnsafeNumberStr); - }); + ecdb.withPreparedStatement("SELECT D,I,L,S FROM Test.Foo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { + stmt.bindId(1, id); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + const row = stmt.getRow(); + assert.equal(row.d, smallIntVal); + assert.equal(row.i, smallIntVal); + assert.equal(row.l, smallIntVal); + assert.equal(row.s, "3"); + }); - assert.equal(await query(ecdb, "SELECT CAST(I AS TEXT) i, CAST(L AS TEXT) l,S FROM Test.Foo WHERE ECInstanceId=?", QueryBinder.from([id]), selectSingleRow, (row: any) => { - assert.equal(row.i, largeNegUnsafeNumberStr); - assert.equal(row.l, largeNegUnsafeNumberStr); - assert.equal(row.s, largeNegUnsafeNumberStr); - }), 1); + assert.equal(await query(ecdb, "SELECT D,I,L,S FROM Test.Foo WHERE ECInstanceId=?", QueryBinder.from([id]), selectSingleRow, (row: any) => { + assert.equal(row.d, smallIntVal); + assert.equal(row.i, smallIntVal); + assert.equal(row.l, smallIntVal); + assert.equal(row.s, "3"); + }), 1); + + const largeUnsafeNumber: number = 12312312312312323654; // too large for int64, but fits into uint64 + assert.isFalse(Number.isSafeInteger(largeUnsafeNumber)); + const largeUnsafeNumberStr: string = "12312312312312323654"; + const largeUnsafeNumberHexStr: string = "0xaade1ed08b0b5e46"; + + id = ecdb.withPreparedStatement("INSERT INTO Test.Foo(D,I,L,S,Description) VALUES(?,?,?,?,'bindInteger, large unsafe number as string')", (stmt: ECSqlStatement) => { + stmt.bindInteger(1, largeUnsafeNumberStr); + stmt.bindInteger(2, largeUnsafeNumberStr); + stmt.bindInteger(3, largeUnsafeNumberStr); + stmt.bindInteger(4, largeUnsafeNumberStr); + const r: ECSqlInsertResult = stmt.stepForInsert(); + assert.equal(r.status, DbResult.BE_SQLITE_DONE); + return r.id!; + }); - id = ecdb.withPreparedStatement("INSERT INTO Test.Foo(D,I,L,S,Description) VALUES(?,?,?,?,'bindString, large negative unsafe number as string')", (stmt: ECSqlStatement) => { - stmt.bindString(1, largeNegUnsafeNumberStr); - stmt.bindString(2, largeNegUnsafeNumberStr); - stmt.bindString(3, largeNegUnsafeNumberStr); - stmt.bindString(4, largeNegUnsafeNumberStr); - const r: ECSqlInsertResult = stmt.stepForInsert(); - assert.equal(r.status, DbResult.BE_SQLITE_DONE); - return r.id!; - }); + ecdb.withPreparedStatement("SELECT Str(I) si, HexStr(I) hi, Str(L) sl, HexStr(L) hl FROM Test.Foo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { + stmt.bindId(1, id); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + const row = stmt.getRow(); + assert.equal(row.si, largeUnsafeNumberStr); + assert.equal(row.hi, largeUnsafeNumberHexStr); + assert.equal(row.sl, largeUnsafeNumberStr); + assert.equal(row.hl, largeUnsafeNumberHexStr); + }); - ecdb.withPreparedStatement("SELECT CAST(I AS TEXT) i, CAST(L AS TEXT) l,S FROM Test.Foo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { - stmt.bindId(1, id); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - const row = stmt.getRow(); - assert.equal(row.i, largeNegUnsafeNumberStr); - assert.equal(row.l, largeNegUnsafeNumberStr); - assert.equal(row.s, largeNegUnsafeNumberStr); - }); + // assert.equal(await query(ecdb, "SELECT Str(I) si, HexStr(I) hi, Str(L) sl, HexStr(L) hl FROM Test.Foo WHERE ECInstanceId=?", [id], 1, (row: any) => { + // assert.equal(row.si, largeUnsafeNumberStr); + // assert.equal(row.hi, largeUnsafeNumberHexStr); + // assert.equal(row.sl, largeUnsafeNumberStr); + // assert.equal(row.hl, largeUnsafeNumberHexStr); + // }), 1); + + id = ecdb.withPreparedStatement("INSERT INTO Test.Foo(D,I,L,S,Description) VALUES(?,?,?,?,'bindInteger, large unsafe number as hexstring')", (stmt: ECSqlStatement) => { + stmt.bindInteger(1, largeUnsafeNumberHexStr); + stmt.bindInteger(2, largeUnsafeNumberHexStr); + stmt.bindInteger(3, largeUnsafeNumberHexStr); + stmt.bindInteger(4, largeUnsafeNumberHexStr); + const r: ECSqlInsertResult = stmt.stepForInsert(); + assert.equal(r.status, DbResult.BE_SQLITE_DONE); + return r.id!; + }); - assert.equal(await query(ecdb, "SELECT CAST(I AS TEXT) i, CAST(L AS TEXT) l,S FROM Test.Foo WHERE ECInstanceId=?", QueryBinder.from([id]), selectSingleRow, (row: any) => { - assert.equal(row.i, largeNegUnsafeNumberStr); - assert.equal(row.l, largeNegUnsafeNumberStr); - assert.equal(row.s, largeNegUnsafeNumberStr); - }), 1); + ecdb.withPreparedStatement("SELECT Str(I) si, HexStr(I) hi, Str(L) sl, HexStr(L) hl FROM Test.Foo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { + stmt.bindId(1, id); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + const row = stmt.getRow(); + assert.equal(row.si, largeUnsafeNumberStr); + assert.equal(row.hi, largeUnsafeNumberHexStr); + assert.equal(row.sl, largeUnsafeNumberStr); + assert.equal(row.hl, largeUnsafeNumberHexStr); + }); - const largeSafeNumber: number = 1231231231231232; - assert.isTrue(Number.isSafeInteger(largeSafeNumber)); - const largeSafeNumberStr: string = largeSafeNumber.toString(); - const largeSafeNumberHexStr: string = "0x45fcc5c2c8500"; + // assert.equal(await query(ecdb, "SELECT Str(I) si, HexStr(I) hi, Str(L) sl, HexStr(L) hl FROM Test.Foo WHERE ECInstanceId=?", [id], 1, (row: any) => { + // assert.equal(row.si, largeUnsafeNumberStr); + // assert.equal(row.hi, largeUnsafeNumberHexStr); + // assert.equal(row.sl, largeUnsafeNumberStr); + // assert.equal(row.hl, largeUnsafeNumberHexStr); + // }), 1); + + id = ecdb.withPreparedStatement("INSERT INTO Test.Foo(D,I,L,S,Description) VALUES(?,?,?,?,'bindString, large unsafe number as string')", (stmt: ECSqlStatement) => { + stmt.bindString(1, largeUnsafeNumberStr); + stmt.bindString(2, largeUnsafeNumberStr); + stmt.bindString(3, largeUnsafeNumberStr); + stmt.bindString(4, largeUnsafeNumberStr); + const r: ECSqlInsertResult = stmt.stepForInsert(); + assert.equal(r.status, DbResult.BE_SQLITE_DONE); + return r.id!; + }); - id = ecdb.withPreparedStatement("INSERT INTO Test.Foo(D,I,L,S,Description) VALUES(?,?,?,?,'bindInteger, large safe number')", (stmt: ECSqlStatement) => { - stmt.bindInteger(1, largeSafeNumber); - stmt.bindInteger(2, largeSafeNumber); - stmt.bindInteger(3, largeSafeNumber); - stmt.bindInteger(4, largeSafeNumber); - const r: ECSqlInsertResult = stmt.stepForInsert(); - assert.equal(r.status, DbResult.BE_SQLITE_DONE); - return r.id!; - }); + // uint64 cannot be bound as string in SQLite. They get converted to reals + ecdb.withPreparedStatement("SELECT D,I,L,S FROM Test.Foo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { + stmt.bindId(1, id); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + const row = stmt.getRow(); + assert.isNumber(row.d); + assert.isNumber(row.i); + assert.isNumber(row.l); + assert.equal(row.s, largeUnsafeNumberStr); + }); - ecdb.withPreparedStatement("SELECT D,I, Str(I) si, HexStr(I) hi, L, Str(L) sl, HexStr(L) hl,S FROM Test.Foo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { - stmt.bindId(1, id); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - const row = stmt.getRow(); - assert.equal(row.d, largeSafeNumber); - assert.equal(row.i, largeSafeNumber); - assert.equal(row.si, largeSafeNumberStr); - assert.equal(row.hi, largeSafeNumberHexStr); - assert.equal(row.l, largeSafeNumber); - assert.equal(row.sl, largeSafeNumberStr); - assert.equal(row.hl, largeSafeNumberHexStr); - assert.equal(row.s, largeSafeNumberStr); - }); + assert.equal(await query(ecdb, "SELECT D,I,L,S FROM Test.Foo WHERE ECInstanceId=?", QueryBinder.from([id]), selectSingleRow, (row: any) => { + assert.isNumber(row.d); + assert.isNumber(row.i); + assert.isNumber(row.l); + assert.equal(row.s, largeUnsafeNumberStr); + }), 1); + + id = ecdb.withPreparedStatement("INSERT INTO Test.Foo(D,I,L,S,Description) VALUES(?,?,?,?,'bindString, large unsafe number as hexstring')", (stmt: ECSqlStatement) => { + stmt.bindString(1, largeUnsafeNumberHexStr); + stmt.bindString(2, largeUnsafeNumberHexStr); + stmt.bindString(3, largeUnsafeNumberHexStr); + stmt.bindString(4, largeUnsafeNumberHexStr); + const r: ECSqlInsertResult = stmt.stepForInsert(); + assert.equal(r.status, DbResult.BE_SQLITE_DONE); + return r.id!; + }); - // await query(ecdb, "SELECT D,I, Str(I) si, HexStr(I) hi, L, Str(L) sl, HexStr(L) hl,S FROM Test.Foo WHERE ECInstanceId=?", [id], 1, (row: any) => { - // assert.equal(row.d, largeSafeNumber); - // assert.equal(row.i, largeSafeNumber); - // assert.equal(row.si, largeSafeNumberStr); - // assert.equal(row.hi, largeSafeNumberHexStr); - // assert.equal(row.l, largeSafeNumber); - // assert.equal(row.sl, largeSafeNumberStr); - // assert.equal(row.hl, largeSafeNumberHexStr); - // assert.equal(row.s, largeSafeNumberStr); - // }); - - id = ecdb.withPreparedStatement("INSERT INTO Test.Foo(D,I,L,S,Description) VALUES(?,?,?,?,'bindInteger, large safe number as string')", (stmt: ECSqlStatement) => { - stmt.bindInteger(1, largeSafeNumberStr); - stmt.bindInteger(2, largeSafeNumberStr); - stmt.bindInteger(3, largeSafeNumberStr); - stmt.bindInteger(4, largeSafeNumberStr); - const r: ECSqlInsertResult = stmt.stepForInsert(); - assert.equal(r.status, DbResult.BE_SQLITE_DONE); - return r.id!; - }); + ecdb.withPreparedStatement("SELECT CAST(D AS TEXT) d,CAST(I AS TEXT) i,CAST(L AS TEXT) l,S FROM Test.Foo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { + stmt.bindId(1, id); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + const row = stmt.getRow(); + assert.equal(row.d, largeUnsafeNumberHexStr); + assert.equal(row.i, largeUnsafeNumberHexStr); + assert.equal(row.l, largeUnsafeNumberHexStr); + assert.equal(row.s, largeUnsafeNumberHexStr); + }); - ecdb.withPreparedStatement("SELECT D,I,L,S FROM Test.Foo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { - stmt.bindId(1, id); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - const row = stmt.getRow(); - assert.equal(row.d, largeSafeNumber); - assert.equal(row.i, largeSafeNumber); - assert.equal(row.l, largeSafeNumber); - assert.equal(row.s, largeSafeNumberStr); - }); + assert.equal(await query(ecdb, "SELECT CAST(D AS TEXT) d,CAST(I AS TEXT) i,CAST(L AS TEXT) l,S FROM Test.Foo WHERE ECInstanceId=?", QueryBinder.from([id]), selectSingleRow, (row: any) => { + assert.equal(row.d, largeUnsafeNumberHexStr); + assert.equal(row.i, largeUnsafeNumberHexStr); + assert.equal(row.l, largeUnsafeNumberHexStr); + assert.equal(row.s, largeUnsafeNumberHexStr); + }), 1); + + const largeNegUnsafeNumber: number = -123123123123123236; + assert.isFalse(Number.isSafeInteger(largeNegUnsafeNumber)); + const largeNegUnsafeNumberStr: string = "-123123123123123236"; + + id = ecdb.withPreparedStatement("INSERT INTO Test.Foo(D,I,L,S,Description) VALUES(?,?,?,?,'bindInteger, large negative unsafe number as string')", (stmt: ECSqlStatement) => { + stmt.bindInteger(1, largeNegUnsafeNumberStr); + stmt.bindInteger(2, largeNegUnsafeNumberStr); + stmt.bindInteger(3, largeNegUnsafeNumberStr); + stmt.bindInteger(4, largeNegUnsafeNumberStr); + const r: ECSqlInsertResult = stmt.stepForInsert(); + assert.equal(r.status, DbResult.BE_SQLITE_DONE); + return r.id!; + }); - assert.equal(await query(ecdb, "SELECT D,I,L,S FROM Test.Foo WHERE ECInstanceId=?", QueryBinder.from([id]), selectSingleRow, (row: any) => { - assert.equal(row.d, largeSafeNumber); - assert.equal(row.i, largeSafeNumber); - assert.equal(row.l, largeSafeNumber); - assert.equal(row.s, largeSafeNumberStr); - }), 1); + ecdb.withPreparedStatement("SELECT CAST(I AS TEXT) i, CAST(L AS TEXT) l,S FROM Test.Foo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { + stmt.bindId(1, id); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + const row = stmt.getRow(); + assert.equal(row.i, largeNegUnsafeNumberStr); + assert.equal(row.l, largeNegUnsafeNumberStr); + assert.equal(row.s, largeNegUnsafeNumberStr); + }); - id = ecdb.withPreparedStatement("INSERT INTO Test.Foo(D,I,L,S,Description) VALUES(?,?,?,?,'bindInteger, large safe number as hexstring')", (stmt: ECSqlStatement) => { - stmt.bindInteger(1, largeSafeNumberHexStr); - stmt.bindInteger(2, largeSafeNumberHexStr); - stmt.bindInteger(3, largeSafeNumberHexStr); - stmt.bindInteger(4, largeSafeNumberHexStr); - const r: ECSqlInsertResult = stmt.stepForInsert(); - assert.equal(r.status, DbResult.BE_SQLITE_DONE); - return r.id!; - }); + assert.equal(await query(ecdb, "SELECT CAST(I AS TEXT) i, CAST(L AS TEXT) l,S FROM Test.Foo WHERE ECInstanceId=?", QueryBinder.from([id]), selectSingleRow, (row: any) => { + assert.equal(row.i, largeNegUnsafeNumberStr); + assert.equal(row.l, largeNegUnsafeNumberStr); + assert.equal(row.s, largeNegUnsafeNumberStr); + }), 1); + + id = ecdb.withPreparedStatement("INSERT INTO Test.Foo(D,I,L,S,Description) VALUES(?,?,?,?,'bindString, large negative unsafe number as string')", (stmt: ECSqlStatement) => { + stmt.bindString(1, largeNegUnsafeNumberStr); + stmt.bindString(2, largeNegUnsafeNumberStr); + stmt.bindString(3, largeNegUnsafeNumberStr); + stmt.bindString(4, largeNegUnsafeNumberStr); + const r: ECSqlInsertResult = stmt.stepForInsert(); + assert.equal(r.status, DbResult.BE_SQLITE_DONE); + return r.id!; + }); - ecdb.withPreparedStatement("SELECT D,I,L,S FROM Test.Foo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { - stmt.bindId(1, id); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - const row = stmt.getRow(); - assert.equal(row.d, largeSafeNumber); - assert.equal(row.i, largeSafeNumber); - assert.equal(row.l, largeSafeNumber); - assert.equal(row.s, largeSafeNumberStr); // even though it was bound as hex str, it gets converted to int64 before persisting - }); + ecdb.withPreparedStatement("SELECT CAST(I AS TEXT) i, CAST(L AS TEXT) l,S FROM Test.Foo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { + stmt.bindId(1, id); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + const row = stmt.getRow(); + assert.equal(row.i, largeNegUnsafeNumberStr); + assert.equal(row.l, largeNegUnsafeNumberStr); + assert.equal(row.s, largeNegUnsafeNumberStr); + }); - assert.equal(await query(ecdb, "SELECT D,I,L,S FROM Test.Foo WHERE ECInstanceId=?", QueryBinder.from([id]), selectSingleRow, (row: any) => { - assert.equal(row.d, largeSafeNumber); - assert.equal(row.i, largeSafeNumber); - assert.equal(row.l, largeSafeNumber); - assert.equal(row.s, largeSafeNumberStr); // even though it was bound as hex str, it gets converted to int64 before persisting - }), 1); + assert.equal(await query(ecdb, "SELECT CAST(I AS TEXT) i, CAST(L AS TEXT) l,S FROM Test.Foo WHERE ECInstanceId=?", QueryBinder.from([id]), selectSingleRow, (row: any) => { + assert.equal(row.i, largeNegUnsafeNumberStr); + assert.equal(row.l, largeNegUnsafeNumberStr); + assert.equal(row.s, largeNegUnsafeNumberStr); + }), 1); + + const largeSafeNumber: number = 1231231231231232; + assert.isTrue(Number.isSafeInteger(largeSafeNumber)); + const largeSafeNumberStr: string = largeSafeNumber.toString(); + const largeSafeNumberHexStr: string = "0x45fcc5c2c8500"; + + id = ecdb.withPreparedStatement("INSERT INTO Test.Foo(D,I,L,S,Description) VALUES(?,?,?,?,'bindInteger, large safe number')", (stmt: ECSqlStatement) => { + stmt.bindInteger(1, largeSafeNumber); + stmt.bindInteger(2, largeSafeNumber); + stmt.bindInteger(3, largeSafeNumber); + stmt.bindInteger(4, largeSafeNumber); + const r: ECSqlInsertResult = stmt.stepForInsert(); + assert.equal(r.status, DbResult.BE_SQLITE_DONE); + return r.id!; + }); - id = ecdb.withPreparedStatement("INSERT INTO Test.Foo(D,I,L,S,Description) VALUES(?,?,?,?,'bindString, large safe number as string')", (stmt: ECSqlStatement) => { - stmt.bindString(1, largeSafeNumberStr); - stmt.bindString(2, largeSafeNumberStr); - stmt.bindString(3, largeSafeNumberStr); - stmt.bindString(4, largeSafeNumberStr); - const r: ECSqlInsertResult = stmt.stepForInsert(); - assert.equal(r.status, DbResult.BE_SQLITE_DONE); - return r.id!; - }); + ecdb.withPreparedStatement("SELECT D,I, Str(I) si, HexStr(I) hi, L, Str(L) sl, HexStr(L) hl,S FROM Test.Foo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { + stmt.bindId(1, id); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + const row = stmt.getRow(); + assert.equal(row.d, largeSafeNumber); + assert.equal(row.i, largeSafeNumber); + assert.equal(row.si, largeSafeNumberStr); + assert.equal(row.hi, largeSafeNumberHexStr); + assert.equal(row.l, largeSafeNumber); + assert.equal(row.sl, largeSafeNumberStr); + assert.equal(row.hl, largeSafeNumberHexStr); + assert.equal(row.s, largeSafeNumberStr); + }); - ecdb.withPreparedStatement("SELECT D,I,L,S FROM Test.Foo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { - stmt.bindId(1, id); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - const row = stmt.getRow(); - assert.equal(row.d, largeSafeNumber); - assert.equal(row.i, largeSafeNumber); - assert.equal(row.l, largeSafeNumber); - assert.equal(row.s, largeSafeNumberStr); - }); + // await query(ecdb, "SELECT D,I, Str(I) si, HexStr(I) hi, L, Str(L) sl, HexStr(L) hl,S FROM Test.Foo WHERE ECInstanceId=?", [id], 1, (row: any) => { + // assert.equal(row.d, largeSafeNumber); + // assert.equal(row.i, largeSafeNumber); + // assert.equal(row.si, largeSafeNumberStr); + // assert.equal(row.hi, largeSafeNumberHexStr); + // assert.equal(row.l, largeSafeNumber); + // assert.equal(row.sl, largeSafeNumberStr); + // assert.equal(row.hl, largeSafeNumberHexStr); + // assert.equal(row.s, largeSafeNumberStr); + // }); + + id = ecdb.withPreparedStatement("INSERT INTO Test.Foo(D,I,L,S,Description) VALUES(?,?,?,?,'bindInteger, large safe number as string')", (stmt: ECSqlStatement) => { + stmt.bindInteger(1, largeSafeNumberStr); + stmt.bindInteger(2, largeSafeNumberStr); + stmt.bindInteger(3, largeSafeNumberStr); + stmt.bindInteger(4, largeSafeNumberStr); + const r: ECSqlInsertResult = stmt.stepForInsert(); + assert.equal(r.status, DbResult.BE_SQLITE_DONE); + return r.id!; + }); - assert.equal(await query(ecdb, "SELECT D,I,L,S FROM Test.Foo WHERE ECInstanceId=?", QueryBinder.from([id]), selectSingleRow, (row: any) => { - assert.equal(row.d, largeSafeNumber); - assert.equal(row.i, largeSafeNumber); - assert.equal(row.l, largeSafeNumber); - assert.equal(row.s, largeSafeNumberStr); // even though it was bound as hex str, it gets converted to int64 before persisting - }), 1); + ecdb.withPreparedStatement("SELECT D,I,L,S FROM Test.Foo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { + stmt.bindId(1, id); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + const row = stmt.getRow(); + assert.equal(row.d, largeSafeNumber); + assert.equal(row.i, largeSafeNumber); + assert.equal(row.l, largeSafeNumber); + assert.equal(row.s, largeSafeNumberStr); + }); - // SQLite does not parse hex strs bound as strings. - id = ecdb.withPreparedStatement("INSERT INTO Test.Foo(D,I,L,S,Description) VALUES(?,?,?,?,'bindString, large safe number as hexstring')", (stmt: ECSqlStatement) => { - stmt.bindString(1, largeSafeNumberHexStr); - stmt.bindString(2, largeSafeNumberHexStr); - stmt.bindString(3, largeSafeNumberHexStr); - stmt.bindString(4, largeSafeNumberHexStr); - const r: ECSqlInsertResult = stmt.stepForInsert(); - assert.equal(r.status, DbResult.BE_SQLITE_DONE); - return r.id!; - }); + assert.equal(await query(ecdb, "SELECT D,I,L,S FROM Test.Foo WHERE ECInstanceId=?", QueryBinder.from([id]), selectSingleRow, (row: any) => { + assert.equal(row.d, largeSafeNumber); + assert.equal(row.i, largeSafeNumber); + assert.equal(row.l, largeSafeNumber); + assert.equal(row.s, largeSafeNumberStr); + }), 1); + + id = ecdb.withPreparedStatement("INSERT INTO Test.Foo(D,I,L,S,Description) VALUES(?,?,?,?,'bindInteger, large safe number as hexstring')", (stmt: ECSqlStatement) => { + stmt.bindInteger(1, largeSafeNumberHexStr); + stmt.bindInteger(2, largeSafeNumberHexStr); + stmt.bindInteger(3, largeSafeNumberHexStr); + stmt.bindInteger(4, largeSafeNumberHexStr); + const r: ECSqlInsertResult = stmt.stepForInsert(); + assert.equal(r.status, DbResult.BE_SQLITE_DONE); + return r.id!; + }); - ecdb.withPreparedStatement("SELECT CAST(D AS TEXT) d,CAST(I AS TEXT) i,CAST(L AS TEXT) l,S FROM Test.Foo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { - stmt.bindId(1, id); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - const row = stmt.getRow(); - assert.equal(row.d, largeSafeNumberHexStr); - assert.equal(row.i, largeSafeNumberHexStr); - assert.equal(row.l, largeSafeNumberHexStr); - assert.equal(row.s, largeSafeNumberHexStr); - }); + ecdb.withPreparedStatement("SELECT D,I,L,S FROM Test.Foo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { + stmt.bindId(1, id); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + const row = stmt.getRow(); + assert.equal(row.d, largeSafeNumber); + assert.equal(row.i, largeSafeNumber); + assert.equal(row.l, largeSafeNumber); + assert.equal(row.s, largeSafeNumberStr); // even though it was bound as hex str, it gets converted to int64 before persisting + }); - assert.equal(await query(ecdb, "SELECT CAST(D AS TEXT) d,CAST(I AS TEXT) i,CAST(L AS TEXT) l,S FROM Test.Foo WHERE ECInstanceId=?", QueryBinder.from([id]), selectSingleRow, (row: any) => { - assert.equal(row.d, largeSafeNumberHexStr); - assert.equal(row.i, largeSafeNumberHexStr); - assert.equal(row.l, largeSafeNumberHexStr); - assert.equal(row.s, largeSafeNumberHexStr); - }), 1); + assert.equal(await query(ecdb, "SELECT D,I,L,S FROM Test.Foo WHERE ECInstanceId=?", QueryBinder.from([id]), selectSingleRow, (row: any) => { + assert.equal(row.d, largeSafeNumber); + assert.equal(row.i, largeSafeNumber); + assert.equal(row.l, largeSafeNumber); + assert.equal(row.s, largeSafeNumberStr); // even though it was bound as hex str, it gets converted to int64 before persisting + }), 1); + + id = ecdb.withPreparedStatement("INSERT INTO Test.Foo(D,I,L,S,Description) VALUES(?,?,?,?,'bindString, large safe number as string')", (stmt: ECSqlStatement) => { + stmt.bindString(1, largeSafeNumberStr); + stmt.bindString(2, largeSafeNumberStr); + stmt.bindString(3, largeSafeNumberStr); + stmt.bindString(4, largeSafeNumberStr); + const r: ECSqlInsertResult = stmt.stepForInsert(); + assert.equal(r.status, DbResult.BE_SQLITE_DONE); + return r.id!; + }); - const largeNegSafeNumber: number = -1231231231231232; - assert.isTrue(Number.isSafeInteger(largeNegSafeNumber)); - const largeNegSafeNumberStr: string = largeNegSafeNumber.toString(); + ecdb.withPreparedStatement("SELECT D,I,L,S FROM Test.Foo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { + stmt.bindId(1, id); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + const row = stmt.getRow(); + assert.equal(row.d, largeSafeNumber); + assert.equal(row.i, largeSafeNumber); + assert.equal(row.l, largeSafeNumber); + assert.equal(row.s, largeSafeNumberStr); + }); - id = ecdb.withPreparedStatement("INSERT INTO Test.Foo(D,I,L,S,Description) VALUES(?,?,?,?,'bindInteger, large negative safe number')", (stmt: ECSqlStatement) => { - stmt.bindInteger(1, largeNegSafeNumber); - stmt.bindInteger(2, largeNegSafeNumber); - stmt.bindInteger(3, largeNegSafeNumber); - stmt.bindInteger(4, largeNegSafeNumber); - const r: ECSqlInsertResult = stmt.stepForInsert(); - assert.equal(r.status, DbResult.BE_SQLITE_DONE); - return r.id!; - }); + assert.equal(await query(ecdb, "SELECT D,I,L,S FROM Test.Foo WHERE ECInstanceId=?", QueryBinder.from([id]), selectSingleRow, (row: any) => { + assert.equal(row.d, largeSafeNumber); + assert.equal(row.i, largeSafeNumber); + assert.equal(row.l, largeSafeNumber); + assert.equal(row.s, largeSafeNumberStr); // even though it was bound as hex str, it gets converted to int64 before persisting + }), 1); + + // SQLite does not parse hex strs bound as strings. + id = ecdb.withPreparedStatement("INSERT INTO Test.Foo(D,I,L,S,Description) VALUES(?,?,?,?,'bindString, large safe number as hexstring')", (stmt: ECSqlStatement) => { + stmt.bindString(1, largeSafeNumberHexStr); + stmt.bindString(2, largeSafeNumberHexStr); + stmt.bindString(3, largeSafeNumberHexStr); + stmt.bindString(4, largeSafeNumberHexStr); + const r: ECSqlInsertResult = stmt.stepForInsert(); + assert.equal(r.status, DbResult.BE_SQLITE_DONE); + return r.id!; + }); - ecdb.withPreparedStatement("SELECT D,I,L,S FROM Test.Foo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { - stmt.bindId(1, id); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - const row = stmt.getRow(); - assert.equal(row.d, largeNegSafeNumber); - assert.equal(row.i, largeNegSafeNumber); - assert.equal(row.l, largeNegSafeNumber); - assert.equal(row.s, largeNegSafeNumberStr); - }); + ecdb.withPreparedStatement("SELECT CAST(D AS TEXT) d,CAST(I AS TEXT) i,CAST(L AS TEXT) l,S FROM Test.Foo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { + stmt.bindId(1, id); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + const row = stmt.getRow(); + assert.equal(row.d, largeSafeNumberHexStr); + assert.equal(row.i, largeSafeNumberHexStr); + assert.equal(row.l, largeSafeNumberHexStr); + assert.equal(row.s, largeSafeNumberHexStr); + }); - assert.equal(await query(ecdb, "SELECT D,I,L,S FROM Test.Foo WHERE ECInstanceId=?", QueryBinder.from([id]), selectSingleRow, (row: any) => { - assert.equal(row.d, largeNegSafeNumber); - assert.equal(row.i, largeNegSafeNumber); - assert.equal(row.l, largeNegSafeNumber); - assert.equal(row.s, largeNegSafeNumberStr); - }), 1); + assert.equal(await query(ecdb, "SELECT CAST(D AS TEXT) d,CAST(I AS TEXT) i,CAST(L AS TEXT) l,S FROM Test.Foo WHERE ECInstanceId=?", QueryBinder.from([id]), selectSingleRow, (row: any) => { + assert.equal(row.d, largeSafeNumberHexStr); + assert.equal(row.i, largeSafeNumberHexStr); + assert.equal(row.l, largeSafeNumberHexStr); + assert.equal(row.s, largeSafeNumberHexStr); + }), 1); + + const largeNegSafeNumber: number = -1231231231231232; + assert.isTrue(Number.isSafeInteger(largeNegSafeNumber)); + const largeNegSafeNumberStr: string = largeNegSafeNumber.toString(); + + id = ecdb.withPreparedStatement("INSERT INTO Test.Foo(D,I,L,S,Description) VALUES(?,?,?,?,'bindInteger, large negative safe number')", (stmt: ECSqlStatement) => { + stmt.bindInteger(1, largeNegSafeNumber); + stmt.bindInteger(2, largeNegSafeNumber); + stmt.bindInteger(3, largeNegSafeNumber); + stmt.bindInteger(4, largeNegSafeNumber); + const r: ECSqlInsertResult = stmt.stepForInsert(); + assert.equal(r.status, DbResult.BE_SQLITE_DONE); + return r.id!; + }); - id = ecdb.withPreparedStatement("INSERT INTO Test.Foo(D,I,L,S,Description) VALUES(?,?,?,?,'bindInteger, large negative safe number as string')", (stmt: ECSqlStatement) => { - stmt.bindInteger(1, largeNegSafeNumberStr); - stmt.bindInteger(2, largeNegSafeNumberStr); - stmt.bindInteger(3, largeNegSafeNumberStr); - stmt.bindInteger(4, largeNegSafeNumberStr); - const r: ECSqlInsertResult = stmt.stepForInsert(); - assert.equal(r.status, DbResult.BE_SQLITE_DONE); - return r.id!; - }); + ecdb.withPreparedStatement("SELECT D,I,L,S FROM Test.Foo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { + stmt.bindId(1, id); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + const row = stmt.getRow(); + assert.equal(row.d, largeNegSafeNumber); + assert.equal(row.i, largeNegSafeNumber); + assert.equal(row.l, largeNegSafeNumber); + assert.equal(row.s, largeNegSafeNumberStr); + }); - ecdb.withPreparedStatement("SELECT D,I,L,S FROM Test.Foo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { - stmt.bindId(1, id); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - const row = stmt.getRow(); - assert.equal(row.d, largeNegSafeNumber); - assert.equal(row.i, largeNegSafeNumber); - assert.equal(row.l, largeNegSafeNumber); - assert.equal(row.s, largeNegSafeNumberStr); - }); + assert.equal(await query(ecdb, "SELECT D,I,L,S FROM Test.Foo WHERE ECInstanceId=?", QueryBinder.from([id]), selectSingleRow, (row: any) => { + assert.equal(row.d, largeNegSafeNumber); + assert.equal(row.i, largeNegSafeNumber); + assert.equal(row.l, largeNegSafeNumber); + assert.equal(row.s, largeNegSafeNumberStr); + }), 1); + + id = ecdb.withPreparedStatement("INSERT INTO Test.Foo(D,I,L,S,Description) VALUES(?,?,?,?,'bindInteger, large negative safe number as string')", (stmt: ECSqlStatement) => { + stmt.bindInteger(1, largeNegSafeNumberStr); + stmt.bindInteger(2, largeNegSafeNumberStr); + stmt.bindInteger(3, largeNegSafeNumberStr); + stmt.bindInteger(4, largeNegSafeNumberStr); + const r: ECSqlInsertResult = stmt.stepForInsert(); + assert.equal(r.status, DbResult.BE_SQLITE_DONE); + return r.id!; + }); - await query(ecdb, "SELECT D,I,L,S FROM Test.Foo WHERE ECInstanceId=?", QueryBinder.from([id]), selectSingleRow, (row: any) => { - assert.equal(row.d, largeNegSafeNumber); - assert.equal(row.i, largeNegSafeNumber); - assert.equal(row.l, largeNegSafeNumber); - assert.equal(row.s, largeNegSafeNumberStr); - }); + ecdb.withPreparedStatement("SELECT D,I,L,S FROM Test.Foo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { + stmt.bindId(1, id); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + const row = stmt.getRow(); + assert.equal(row.d, largeNegSafeNumber); + assert.equal(row.i, largeNegSafeNumber); + assert.equal(row.l, largeNegSafeNumber); + assert.equal(row.s, largeNegSafeNumberStr); + }); - id = ecdb.withPreparedStatement("INSERT INTO Test.Foo(D,I,L,S,Description) VALUES(?,?,?,?,'bindString, large negative safe number as string')", (stmt: ECSqlStatement) => { - stmt.bindString(1, largeNegSafeNumberStr); - stmt.bindString(2, largeNegSafeNumberStr); - stmt.bindString(3, largeNegSafeNumberStr); - stmt.bindString(4, largeNegSafeNumberStr); - const r: ECSqlInsertResult = stmt.stepForInsert(); - assert.equal(r.status, DbResult.BE_SQLITE_DONE); - return r.id!; - }); + await query(ecdb, "SELECT D,I,L,S FROM Test.Foo WHERE ECInstanceId=?", QueryBinder.from([id]), selectSingleRow, (row: any) => { + assert.equal(row.d, largeNegSafeNumber); + assert.equal(row.i, largeNegSafeNumber); + assert.equal(row.l, largeNegSafeNumber); + assert.equal(row.s, largeNegSafeNumberStr); + }); - ecdb.withPreparedStatement("SELECT D,I,L,S FROM Test.Foo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { - stmt.bindId(1, id); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - const row = stmt.getRow(); - assert.equal(row.d, largeNegSafeNumber); - assert.equal(row.i, largeNegSafeNumber); - assert.equal(row.l, largeNegSafeNumber); - assert.equal(row.s, largeNegSafeNumberStr); - }); + id = ecdb.withPreparedStatement("INSERT INTO Test.Foo(D,I,L,S,Description) VALUES(?,?,?,?,'bindString, large negative safe number as string')", (stmt: ECSqlStatement) => { + stmt.bindString(1, largeNegSafeNumberStr); + stmt.bindString(2, largeNegSafeNumberStr); + stmt.bindString(3, largeNegSafeNumberStr); + stmt.bindString(4, largeNegSafeNumberStr); + const r: ECSqlInsertResult = stmt.stepForInsert(); + assert.equal(r.status, DbResult.BE_SQLITE_DONE); + return r.id!; + }); - await query(ecdb, "SELECT D,I,L,S FROM Test.Foo WHERE ECInstanceId=?", QueryBinder.from([id]), selectSingleRow, (row: any) => { - assert.equal(row.d, largeNegSafeNumber); - assert.equal(row.i, largeNegSafeNumber); - assert.equal(row.l, largeNegSafeNumber); - assert.equal(row.s, largeNegSafeNumberStr); - }); + ecdb.withPreparedStatement("SELECT D,I,L,S FROM Test.Foo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { + stmt.bindId(1, id); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + const row = stmt.getRow(); + assert.equal(row.d, largeNegSafeNumber); + assert.equal(row.i, largeNegSafeNumber); + assert.equal(row.l, largeNegSafeNumber); + assert.equal(row.s, largeNegSafeNumberStr); + }); + await query(ecdb, "SELECT D,I,L,S FROM Test.Foo WHERE ECInstanceId=?", QueryBinder.from([id]), selectSingleRow, (row: any) => { + assert.equal(row.d, largeNegSafeNumber); + assert.equal(row.i, largeNegSafeNumber); + assert.equal(row.l, largeNegSafeNumber); + assert.equal(row.s, largeNegSafeNumberStr); }); + }); it("should bind primitives", async () => { - await using(ECDbTestHelper.createECDb(outDir, "bindprimitives.ecdb", + using ecdb = ECDbTestHelper.createECDb(outDir, "bindprimitives.ecdb", ` @@ -1297,155 +1284,154 @@ describe("ECSqlStatement", () => { - `), async (ecdb) => { - assert.isTrue(ecdb.isOpen); - - const boolVal = true; - const doubleVal = 3.5; - const dtVal: string = "2018-01-23T12:24:00.000"; - const intVal = 3; - const p2dVal = new Point2d(1, 2); - const p3dVal = new Point3d(1, 2, 3); - const strVal: string = "Hello world"; - - const verify = async (expectedId: Id64String) => { - await ecdb.withPreparedStatement("SELECT Bl,Bo,D,Dt,I,P2d,P3d,S,Struct.Bl s_bl,Struct.Bo s_bo,Struct.D s_d,Struct.Dt s_dt,Struct.I s_i,Struct.P2d s_p2d,Struct.P3d s_p3d,Struct.S s_s FROM test.Foo WHERE ECInstanceId=?", async (stmt: ECSqlStatement) => { - stmt.bindId(1, expectedId); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - const row = stmt.getRow(); - assert.deepEqual(row.bl, blobVal); - const f64 = new Float64Array(row.bl.buffer); - const r2 = new Range3d(...f64); - assert.deepEqual(r2, testRange); - assert.equal(row.bo, boolVal); - assert.equal(row.d, doubleVal); - assert.equal(row.dt, dtVal); - assert.equal(row.i, intVal); - assert.equal(row.p2d.x, p2dVal.x); - assert.equal(row.p2d.y, p2dVal.y); - assert.equal(row.p3d.x, p3dVal.x); - assert.equal(row.p3d.y, p3dVal.y); - assert.equal(row.p3d.z, p3dVal.z); - assert.equal(row.s, strVal); - - assert.deepEqual(row.s_bl, blobVal); - assert.equal(row.s_bo, boolVal); - assert.equal(row.s_d, doubleVal); - assert.equal(row.s_dt, dtVal); - assert.equal(row.s_i, intVal); - assert.equal(row.s_p2d.x, p2dVal.x); - assert.equal(row.s_p2d.y, p2dVal.y); - assert.equal(row.s_p3d.x, p3dVal.x); - assert.equal(row.s_p3d.y, p3dVal.y); - assert.equal(row.s_p3d.z, p3dVal.z); - assert.equal(row.s_s, strVal); - - assert.equal(await query(ecdb, "SELECT Bl,Bo,D,Dt,I,P2d,P3d,S,Struct.Bl s_bl,Struct.Bo s_bo,Struct.D s_d,Struct.Dt s_dt,Struct.I s_i,Struct.P2d s_p2d,Struct.P3d s_p3d,Struct.S s_s FROM test.Foo WHERE ECInstanceId=?", QueryBinder.from([expectedId]), selectSingleRow, (row1: any) => { - assert.deepEqual(row1.bl, blobVal); - const f64a = new Float64Array(row1.bl.buffer); - const r2a = new Range3d(...f64a); - assert.deepEqual(r2a, testRange); - assert.equal(row1.bo, boolVal); - assert.equal(row1.d, doubleVal); - assert.equal(row1.dt, dtVal); - assert.equal(row1.i, intVal); - assert.equal(row1.p2d.x, p2dVal.x); - assert.equal(row1.p2d.y, p2dVal.y); - assert.equal(row1.p3d.x, p3dVal.x); - assert.equal(row1.p3d.y, p3dVal.y); - assert.equal(row1.p3d.z, p3dVal.z); - assert.equal(row1.s, strVal); - - assert.deepEqual(row1.s_bl, blobVal); - assert.equal(row1.s_bo, boolVal); - assert.equal(row1.s_d, doubleVal); - assert.equal(row1.s_dt, dtVal); - assert.equal(row1.s_i, intVal); - assert.equal(row1.s_p2d.x, p2dVal.x); - assert.equal(row1.s_p2d.y, p2dVal.y); - assert.equal(row1.s_p3d.x, p3dVal.x); - assert.equal(row1.s_p3d.y, p3dVal.y); - assert.equal(row1.s_p3d.z, p3dVal.z); - assert.equal(row1.s_s, strVal); - }), 1); - }); - }; - - const ids = new Array(); - ecdb.withPreparedStatement("INSERT INTO test.Foo(Bl,Bo,D,Dt,I,P2d,P3d,S,Struct.Bl,Struct.Bo,Struct.D,Struct.Dt,Struct.I,Struct.P2d,Struct.P3d,Struct.S) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", (stmt: ECSqlStatement) => { - stmt.bindBlob(1, blobVal); - stmt.bindBoolean(2, boolVal); - stmt.bindDouble(3, doubleVal); - stmt.bindDateTime(4, dtVal); - stmt.bindInteger(5, intVal); - stmt.bindPoint2d(6, p2dVal); - stmt.bindPoint3d(7, p3dVal); - stmt.bindString(8, strVal); - stmt.bindBlob(9, blobVal); - stmt.bindBoolean(10, boolVal); - stmt.bindDouble(11, doubleVal); - stmt.bindDateTime(12, dtVal); - stmt.bindInteger(13, intVal); - stmt.bindPoint2d(14, p2dVal); - stmt.bindPoint3d(15, p3dVal); - stmt.bindString(16, strVal); - - let res: ECSqlInsertResult = stmt.stepForInsert(); - assert.equal(res.status, DbResult.BE_SQLITE_DONE); - ids.push(res.id!); - stmt.reset(); - stmt.clearBindings(); - stmt.bindValues([blobVal, boolVal, doubleVal, dtVal, intVal, p2dVal, p3dVal, strVal, blobVal, boolVal, doubleVal, dtVal, intVal, p2dVal, p3dVal, strVal]); - - res = stmt.stepForInsert(); - assert.equal(res.status, DbResult.BE_SQLITE_DONE); - ids.push(res.id!); - }); - - ecdb.withPreparedStatement("INSERT INTO test.Foo(Bl,Bo,D,Dt,I,P2d,P3d,S,Struct.Bl,Struct.Bo,Struct.D,Struct.Dt,Struct.I,Struct.P2d,Struct.P3d,Struct.S) VALUES(:bl,:bo,:d,:dt,:i,:p2d,:p3d,:s,:s_bl,:s_bo,:s_d,:s_dt,:s_i,:s_p2d,:s_p3d,:s_s)", (stmt: ECSqlStatement) => { - stmt.bindBlob("bl", blobVal); - stmt.bindBoolean("bo", boolVal); - stmt.bindDouble("d", doubleVal); - stmt.bindDateTime("dt", dtVal); - stmt.bindInteger("i", intVal); - stmt.bindPoint2d("p2d", p2dVal); - stmt.bindPoint3d("p3d", p3dVal); - stmt.bindString("s", strVal); - - stmt.bindBlob("s_bl", blobVal); - stmt.bindBoolean("s_bo", boolVal); - stmt.bindDouble("s_d", doubleVal); - stmt.bindDateTime("s_dt", dtVal); - stmt.bindInteger("s_i", intVal); - stmt.bindPoint2d("s_p2d", p2dVal); - stmt.bindPoint3d("s_p3d", p3dVal); - stmt.bindString("s_s", strVal); - - let res: ECSqlInsertResult = stmt.stepForInsert(); - assert.equal(res.status, DbResult.BE_SQLITE_DONE); - ids.push(res.id!); - stmt.reset(); - stmt.clearBindings(); - stmt.bindValues({ - bl: blobVal, bo: boolVal, d: doubleVal, dt: dtVal, - i: intVal, p2d: p2dVal, p3d: p3dVal, s: strVal, - s_bl: blobVal, s_bo: boolVal, s_d: doubleVal, s_dt: dtVal, - s_i: intVal, s_p2d: p2dVal, s_p3d: p3dVal, s_s: strVal, - }); + `); + assert.isTrue(ecdb.isOpen); + + const boolVal = true; + const doubleVal = 3.5; + const dtVal: string = "2018-01-23T12:24:00.000"; + const intVal = 3; + const p2dVal = new Point2d(1, 2); + const p3dVal = new Point3d(1, 2, 3); + const strVal: string = "Hello world"; + + const verify = async (expectedId: Id64String) => { + await ecdb.withPreparedStatement("SELECT Bl,Bo,D,Dt,I,P2d,P3d,S,Struct.Bl s_bl,Struct.Bo s_bo,Struct.D s_d,Struct.Dt s_dt,Struct.I s_i,Struct.P2d s_p2d,Struct.P3d s_p3d,Struct.S s_s FROM test.Foo WHERE ECInstanceId=?", async (stmt: ECSqlStatement) => { + stmt.bindId(1, expectedId); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + const row = stmt.getRow(); + assert.deepEqual(row.bl, blobVal); + const f64 = new Float64Array(row.bl.buffer); + const r2 = new Range3d(...f64); + assert.deepEqual(r2, testRange); + assert.equal(row.bo, boolVal); + assert.equal(row.d, doubleVal); + assert.equal(row.dt, dtVal); + assert.equal(row.i, intVal); + assert.equal(row.p2d.x, p2dVal.x); + assert.equal(row.p2d.y, p2dVal.y); + assert.equal(row.p3d.x, p3dVal.x); + assert.equal(row.p3d.y, p3dVal.y); + assert.equal(row.p3d.z, p3dVal.z); + assert.equal(row.s, strVal); - res = stmt.stepForInsert(); - assert.equal(res.status, DbResult.BE_SQLITE_DONE); - ids.push(res.id!); + assert.deepEqual(row.s_bl, blobVal); + assert.equal(row.s_bo, boolVal); + assert.equal(row.s_d, doubleVal); + assert.equal(row.s_dt, dtVal); + assert.equal(row.s_i, intVal); + assert.equal(row.s_p2d.x, p2dVal.x); + assert.equal(row.s_p2d.y, p2dVal.y); + assert.equal(row.s_p3d.x, p3dVal.x); + assert.equal(row.s_p3d.y, p3dVal.y); + assert.equal(row.s_p3d.z, p3dVal.z); + assert.equal(row.s_s, strVal); + + assert.equal(await query(ecdb, "SELECT Bl,Bo,D,Dt,I,P2d,P3d,S,Struct.Bl s_bl,Struct.Bo s_bo,Struct.D s_d,Struct.Dt s_dt,Struct.I s_i,Struct.P2d s_p2d,Struct.P3d s_p3d,Struct.S s_s FROM test.Foo WHERE ECInstanceId=?", QueryBinder.from([expectedId]), selectSingleRow, (row1: any) => { + assert.deepEqual(row1.bl, blobVal); + const f64a = new Float64Array(row1.bl.buffer); + const r2a = new Range3d(...f64a); + assert.deepEqual(r2a, testRange); + assert.equal(row1.bo, boolVal); + assert.equal(row1.d, doubleVal); + assert.equal(row1.dt, dtVal); + assert.equal(row1.i, intVal); + assert.equal(row1.p2d.x, p2dVal.x); + assert.equal(row1.p2d.y, p2dVal.y); + assert.equal(row1.p3d.x, p3dVal.x); + assert.equal(row1.p3d.y, p3dVal.y); + assert.equal(row1.p3d.z, p3dVal.z); + assert.equal(row1.s, strVal); + + assert.deepEqual(row1.s_bl, blobVal); + assert.equal(row1.s_bo, boolVal); + assert.equal(row1.s_d, doubleVal); + assert.equal(row1.s_dt, dtVal); + assert.equal(row1.s_i, intVal); + assert.equal(row1.s_p2d.x, p2dVal.x); + assert.equal(row1.s_p2d.y, p2dVal.y); + assert.equal(row1.s_p3d.x, p3dVal.x); + assert.equal(row1.s_p3d.y, p3dVal.y); + assert.equal(row1.s_p3d.z, p3dVal.z); + assert.equal(row1.s_s, strVal); + }), 1); }); + }; + + const ids = new Array(); + ecdb.withPreparedStatement("INSERT INTO test.Foo(Bl,Bo,D,Dt,I,P2d,P3d,S,Struct.Bl,Struct.Bo,Struct.D,Struct.Dt,Struct.I,Struct.P2d,Struct.P3d,Struct.S) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", (stmt: ECSqlStatement) => { + stmt.bindBlob(1, blobVal); + stmt.bindBoolean(2, boolVal); + stmt.bindDouble(3, doubleVal); + stmt.bindDateTime(4, dtVal); + stmt.bindInteger(5, intVal); + stmt.bindPoint2d(6, p2dVal); + stmt.bindPoint3d(7, p3dVal); + stmt.bindString(8, strVal); + stmt.bindBlob(9, blobVal); + stmt.bindBoolean(10, boolVal); + stmt.bindDouble(11, doubleVal); + stmt.bindDateTime(12, dtVal); + stmt.bindInteger(13, intVal); + stmt.bindPoint2d(14, p2dVal); + stmt.bindPoint3d(15, p3dVal); + stmt.bindString(16, strVal); + + let res: ECSqlInsertResult = stmt.stepForInsert(); + assert.equal(res.status, DbResult.BE_SQLITE_DONE); + ids.push(res.id!); + stmt.reset(); + stmt.clearBindings(); + stmt.bindValues([blobVal, boolVal, doubleVal, dtVal, intVal, p2dVal, p3dVal, strVal, blobVal, boolVal, doubleVal, dtVal, intVal, p2dVal, p3dVal, strVal]); + + res = stmt.stepForInsert(); + assert.equal(res.status, DbResult.BE_SQLITE_DONE); + ids.push(res.id!); + }); - for (const id of ids) { - await verify(id); - } + ecdb.withPreparedStatement("INSERT INTO test.Foo(Bl,Bo,D,Dt,I,P2d,P3d,S,Struct.Bl,Struct.Bo,Struct.D,Struct.Dt,Struct.I,Struct.P2d,Struct.P3d,Struct.S) VALUES(:bl,:bo,:d,:dt,:i,:p2d,:p3d,:s,:s_bl,:s_bo,:s_d,:s_dt,:s_i,:s_p2d,:s_p3d,:s_s)", (stmt: ECSqlStatement) => { + stmt.bindBlob("bl", blobVal); + stmt.bindBoolean("bo", boolVal); + stmt.bindDouble("d", doubleVal); + stmt.bindDateTime("dt", dtVal); + stmt.bindInteger("i", intVal); + stmt.bindPoint2d("p2d", p2dVal); + stmt.bindPoint3d("p3d", p3dVal); + stmt.bindString("s", strVal); + + stmt.bindBlob("s_bl", blobVal); + stmt.bindBoolean("s_bo", boolVal); + stmt.bindDouble("s_d", doubleVal); + stmt.bindDateTime("s_dt", dtVal); + stmt.bindInteger("s_i", intVal); + stmt.bindPoint2d("s_p2d", p2dVal); + stmt.bindPoint3d("s_p3d", p3dVal); + stmt.bindString("s_s", strVal); + + let res: ECSqlInsertResult = stmt.stepForInsert(); + assert.equal(res.status, DbResult.BE_SQLITE_DONE); + ids.push(res.id!); + stmt.reset(); + stmt.clearBindings(); + stmt.bindValues({ + bl: blobVal, bo: boolVal, d: doubleVal, dt: dtVal, + i: intVal, p2d: p2dVal, p3d: p3dVal, s: strVal, + s_bl: blobVal, s_bo: boolVal, s_d: doubleVal, s_dt: dtVal, + s_i: intVal, s_p2d: p2dVal, s_p3d: p3dVal, s_s: strVal, + }); + + res = stmt.stepForInsert(); + assert.equal(res.status, DbResult.BE_SQLITE_DONE); + ids.push(res.id!); }); + + for (const id of ids) { + await verify(id); + } }); it("should bind structs", async () => { - await using(ECDbTestHelper.createECDb(outDir, "bindstructs.ecdb", + using ecdb = ECDbTestHelper.createECDb(outDir, "bindstructs.ecdb", ` @@ -1462,84 +1448,83 @@ describe("ECSqlStatement", () => { - `), async (ecdb) => { - assert.isTrue(ecdb.isOpen); - - const structVal = { - bl: blobVal, bo: true, d: 3.5, - dt: "2018-01-23T12:24:00.000", - i: 3, p2d: new Point2d(1, 2), p3d: new Point3d(1, 2, 3), s: "Hello World", - }; - - const verify = async (expectedId: Id64String) => { - await ecdb.withPreparedStatement("SELECT Struct FROM test.Foo WHERE ECInstanceId=?", async (stmt: ECSqlStatement) => { - stmt.bindId(1, expectedId); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - const row = stmt.getRow(); - assert.isTrue(blobEqual(row.struct.bl, structVal.bl)); - assert.equal(row.struct.bo, structVal.bo); - assert.equal(row.struct.d, structVal.d); - assert.equal(row.struct.dt, structVal.dt); - assert.equal(row.struct.i, structVal.i); - assert.equal(row.struct.p2d.x, structVal.p2d.x); - assert.equal(row.struct.p2d.y, structVal.p2d.y); - assert.equal(row.struct.p3d.x, structVal.p3d.x); - assert.equal(row.struct.p3d.y, structVal.p3d.y); - assert.equal(row.struct.p3d.z, structVal.p3d.z); - assert.equal(row.struct.s, structVal.s); - - assert.equal(await query(ecdb, "SELECT Struct FROM test.Foo WHERE ECInstanceId=?", QueryBinder.from([expectedId]), selectSingleRow, (row1: any) => { - assert.isTrue(blobEqual(row1.struct.bl, structVal.bl)); - assert.equal(row1.struct.bo, structVal.bo); - assert.equal(row1.struct.d, structVal.d); - assert.equal(row1.struct.dt, structVal.dt); - assert.equal(row1.struct.i, structVal.i); - assert.equal(row1.struct.p2d.x, structVal.p2d.x); - assert.equal(row1.struct.p2d.y, structVal.p2d.y); - assert.equal(row1.struct.p3d.x, structVal.p3d.x); - assert.equal(row1.struct.p3d.y, structVal.p3d.y); - assert.equal(row1.struct.p3d.z, structVal.p3d.z); - assert.equal(row1.struct.s, structVal.s); - }), 1); - }); - }; - await ecdb.withPreparedStatement("INSERT INTO test.Foo(Struct) VALUES(?)", async (stmt: ECSqlStatement) => { - stmt.bindStruct(1, structVal); - const res: ECSqlInsertResult = stmt.stepForInsert(); - assert.equal(res.status, DbResult.BE_SQLITE_DONE); - assert.isDefined(res.id); - await verify(res.id!); - }); + `); + assert.isTrue(ecdb.isOpen); - await ecdb.withPreparedStatement("INSERT INTO test.Foo(Struct) VALUES(?)", async (stmt: ECSqlStatement) => { - stmt.bindValues([structVal]); - const res: ECSqlInsertResult = stmt.stepForInsert(); - assert.equal(res.status, DbResult.BE_SQLITE_DONE); - assert.isDefined(res.id); - await verify(res.id!); - }); + const structVal = { + bl: blobVal, bo: true, d: 3.5, + dt: "2018-01-23T12:24:00.000", + i: 3, p2d: new Point2d(1, 2), p3d: new Point3d(1, 2, 3), s: "Hello World", + }; - await ecdb.withPreparedStatement("INSERT INTO test.Foo(Struct) VALUES(:str)", async (stmt: ECSqlStatement) => { - stmt.bindStruct("str", structVal); - const res: ECSqlInsertResult = stmt.stepForInsert(); - assert.equal(res.status, DbResult.BE_SQLITE_DONE); - assert.isDefined(res.id); - await verify(res.id!); + const verify = async (expectedId: Id64String) => { + await ecdb.withPreparedStatement("SELECT Struct FROM test.Foo WHERE ECInstanceId=?", async (stmt: ECSqlStatement) => { + stmt.bindId(1, expectedId); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + const row = stmt.getRow(); + assert.isTrue(blobEqual(row.struct.bl, structVal.bl)); + assert.equal(row.struct.bo, structVal.bo); + assert.equal(row.struct.d, structVal.d); + assert.equal(row.struct.dt, structVal.dt); + assert.equal(row.struct.i, structVal.i); + assert.equal(row.struct.p2d.x, structVal.p2d.x); + assert.equal(row.struct.p2d.y, structVal.p2d.y); + assert.equal(row.struct.p3d.x, structVal.p3d.x); + assert.equal(row.struct.p3d.y, structVal.p3d.y); + assert.equal(row.struct.p3d.z, structVal.p3d.z); + assert.equal(row.struct.s, structVal.s); + + assert.equal(await query(ecdb, "SELECT Struct FROM test.Foo WHERE ECInstanceId=?", QueryBinder.from([expectedId]), selectSingleRow, (row1: any) => { + assert.isTrue(blobEqual(row1.struct.bl, structVal.bl)); + assert.equal(row1.struct.bo, structVal.bo); + assert.equal(row1.struct.d, structVal.d); + assert.equal(row1.struct.dt, structVal.dt); + assert.equal(row1.struct.i, structVal.i); + assert.equal(row1.struct.p2d.x, structVal.p2d.x); + assert.equal(row1.struct.p2d.y, structVal.p2d.y); + assert.equal(row1.struct.p3d.x, structVal.p3d.x); + assert.equal(row1.struct.p3d.y, structVal.p3d.y); + assert.equal(row1.struct.p3d.z, structVal.p3d.z); + assert.equal(row1.struct.s, structVal.s); + }), 1); }); + }; + await ecdb.withPreparedStatement("INSERT INTO test.Foo(Struct) VALUES(?)", async (stmt: ECSqlStatement) => { + stmt.bindStruct(1, structVal); + const res: ECSqlInsertResult = stmt.stepForInsert(); + assert.equal(res.status, DbResult.BE_SQLITE_DONE); + assert.isDefined(res.id); + await verify(res.id!); + }); - await ecdb.withPreparedStatement("INSERT INTO test.Foo(Struct) VALUES(:str)", async (stmt: ECSqlStatement) => { - stmt.bindValues({ str: structVal }); - const res: ECSqlInsertResult = stmt.stepForInsert(); - assert.equal(res.status, DbResult.BE_SQLITE_DONE); - assert.isDefined(res.id); - await verify(res.id!); - }); + await ecdb.withPreparedStatement("INSERT INTO test.Foo(Struct) VALUES(?)", async (stmt: ECSqlStatement) => { + stmt.bindValues([structVal]); + const res: ECSqlInsertResult = stmt.stepForInsert(); + assert.equal(res.status, DbResult.BE_SQLITE_DONE); + assert.isDefined(res.id); + await verify(res.id!); + }); + await ecdb.withPreparedStatement("INSERT INTO test.Foo(Struct) VALUES(:str)", async (stmt: ECSqlStatement) => { + stmt.bindStruct("str", structVal); + const res: ECSqlInsertResult = stmt.stepForInsert(); + assert.equal(res.status, DbResult.BE_SQLITE_DONE); + assert.isDefined(res.id); + await verify(res.id!); }); + + await ecdb.withPreparedStatement("INSERT INTO test.Foo(Struct) VALUES(:str)", async (stmt: ECSqlStatement) => { + stmt.bindValues({ str: structVal }); + const res: ECSqlInsertResult = stmt.stepForInsert(); + assert.equal(res.status, DbResult.BE_SQLITE_DONE); + assert.isDefined(res.id); + await verify(res.id!); + }); + }); it("should bind arrays", async () => { - await using(ECDbTestHelper.createECDb(outDir, "bindarrays.ecdb", + using ecdb = ECDbTestHelper.createECDb(outDir, "bindarrays.ecdb", ` @@ -1550,97 +1535,96 @@ describe("ECSqlStatement", () => { - `), async (ecdb) => { - assert.isTrue(ecdb.isOpen); - - const intArray = [1, 2, 3]; - const dtArray = ["2018-01-23T00:00:00.000", "2018-01-23T16:39:00.000"]; - const addressArray = [{ city: "London", zip: 10000 }, { city: "Manchester", zip: 20000 }, { city: "Edinburgh", zip: 30000 }]; - - const verify = async (expectedId: Id64String) => { - await ecdb.withPreparedStatement("SELECT I_Array, Dt_Array, Addresses FROM test.Foo WHERE ECInstanceId=?", async (stmt: ECSqlStatement) => { - stmt.bindId(1, expectedId); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - const row = stmt.getRow(); - - // don't know why assert.equal doesn't work on arrays directly - assert.equal(row.i_Array.length, intArray.length); - for (let i = 0; i < intArray.length; i++) { - assert.equal(row.i_Array[i], intArray[i]); - } + `); + assert.isTrue(ecdb.isOpen); - assert.equal(row.dt_Array.length, dtArray.length); - for (let i = 0; i < dtArray.length; i++) { - assert.equal(row.dt_Array[i], dtArray[i]); - } + const intArray = [1, 2, 3]; + const dtArray = ["2018-01-23T00:00:00.000", "2018-01-23T16:39:00.000"]; + const addressArray = [{ city: "London", zip: 10000 }, { city: "Manchester", zip: 20000 }, { city: "Edinburgh", zip: 30000 }]; - assert.equal(row.addresses.length, addressArray.length); - for (let i = 0; i < addressArray.length; i++) { - assert.equal(row.addresses[i].city, addressArray[i].city); - assert.equal(row.addresses[i].zip, addressArray[i].zip); - } - }); + const verify = async (expectedId: Id64String) => { + await ecdb.withPreparedStatement("SELECT I_Array, Dt_Array, Addresses FROM test.Foo WHERE ECInstanceId=?", async (stmt: ECSqlStatement) => { + stmt.bindId(1, expectedId); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + const row = stmt.getRow(); - assert.equal(await query(ecdb, "SELECT I_Array, Dt_Array, Addresses FROM test.Foo WHERE ECInstanceId=?", QueryBinder.from([expectedId]), selectSingleRow, (row: any) => { - // don't know why assert.equal doesn't work on arrays directly - assert.equal(row.i_Array.length, intArray.length); - for (let i = 0; i < intArray.length; i++) { - assert.equal(row.i_Array[i], intArray[i]); - } + // don't know why assert.equal doesn't work on arrays directly + assert.equal(row.i_Array.length, intArray.length); + for (let i = 0; i < intArray.length; i++) { + assert.equal(row.i_Array[i], intArray[i]); + } - assert.equal(row.dt_Array.length, dtArray.length); - for (let i = 0; i < dtArray.length; i++) { - assert.equal(row.dt_Array[i], dtArray[i]); - } + assert.equal(row.dt_Array.length, dtArray.length); + for (let i = 0; i < dtArray.length; i++) { + assert.equal(row.dt_Array[i], dtArray[i]); + } - assert.equal(row.addresses.length, addressArray.length); - for (let i = 0; i < addressArray.length; i++) { - assert.equal(row.addresses[i].city, addressArray[i].city); - assert.equal(row.addresses[i].zip, addressArray[i].zip); - } - }), 1); - }; - - await ecdb.withPreparedStatement("INSERT INTO test.Foo(I_Array,Dt_Array,Addresses) VALUES(?,?,?)", async (stmt: ECSqlStatement) => { - stmt.bindArray(1, intArray); - stmt.bindArray(2, dtArray); - stmt.bindArray(3, addressArray); - const res: ECSqlInsertResult = stmt.stepForInsert(); - assert.equal(res.status, DbResult.BE_SQLITE_DONE); - assert.isDefined(res.id); - await verify(res.id!); + assert.equal(row.addresses.length, addressArray.length); + for (let i = 0; i < addressArray.length; i++) { + assert.equal(row.addresses[i].city, addressArray[i].city); + assert.equal(row.addresses[i].zip, addressArray[i].zip); + } }); - await ecdb.withPreparedStatement("INSERT INTO test.Foo(I_Array,Dt_Array,Addresses) VALUES(?,?,?)", async (stmt: ECSqlStatement) => { - stmt.bindValues([intArray, dtArray, addressArray]); - const res: ECSqlInsertResult = stmt.stepForInsert(); - assert.equal(res.status, DbResult.BE_SQLITE_DONE); - assert.isDefined(res.id); - await verify(res.id!); - }); + assert.equal(await query(ecdb, "SELECT I_Array, Dt_Array, Addresses FROM test.Foo WHERE ECInstanceId=?", QueryBinder.from([expectedId]), selectSingleRow, (row: any) => { + // don't know why assert.equal doesn't work on arrays directly + assert.equal(row.i_Array.length, intArray.length); + for (let i = 0; i < intArray.length; i++) { + assert.equal(row.i_Array[i], intArray[i]); + } - await ecdb.withPreparedStatement("INSERT INTO test.Foo(I_Array,Dt_Array,Addresses) VALUES(:iarray,:dtarray,:addresses)", async (stmt: ECSqlStatement) => { - stmt.bindArray("iarray", intArray); - stmt.bindArray("dtarray", dtArray); - stmt.bindArray("addresses", addressArray); - const res: ECSqlInsertResult = stmt.stepForInsert(); - assert.equal(res.status, DbResult.BE_SQLITE_DONE); - assert.isDefined(res.id); - await verify(res.id!); - }); + assert.equal(row.dt_Array.length, dtArray.length); + for (let i = 0; i < dtArray.length; i++) { + assert.equal(row.dt_Array[i], dtArray[i]); + } - await ecdb.withPreparedStatement("INSERT INTO test.Foo(I_Array,Dt_Array,Addresses) VALUES(:iarray,:dtarray,:addresses)", async (stmt: ECSqlStatement) => { - stmt.bindValues({ iarray: intArray, dtarray: dtArray, addresses: addressArray }); - const res: ECSqlInsertResult = stmt.stepForInsert(); - assert.equal(res.status, DbResult.BE_SQLITE_DONE); - assert.isDefined(res.id); - await verify(res.id!); - }); + assert.equal(row.addresses.length, addressArray.length); + for (let i = 0; i < addressArray.length; i++) { + assert.equal(row.addresses[i].city, addressArray[i].city); + assert.equal(row.addresses[i].zip, addressArray[i].zip); + } + }), 1); + }; + + await ecdb.withPreparedStatement("INSERT INTO test.Foo(I_Array,Dt_Array,Addresses) VALUES(?,?,?)", async (stmt: ECSqlStatement) => { + stmt.bindArray(1, intArray); + stmt.bindArray(2, dtArray); + stmt.bindArray(3, addressArray); + const res: ECSqlInsertResult = stmt.stepForInsert(); + assert.equal(res.status, DbResult.BE_SQLITE_DONE); + assert.isDefined(res.id); + await verify(res.id!); + }); + + await ecdb.withPreparedStatement("INSERT INTO test.Foo(I_Array,Dt_Array,Addresses) VALUES(?,?,?)", async (stmt: ECSqlStatement) => { + stmt.bindValues([intArray, dtArray, addressArray]); + const res: ECSqlInsertResult = stmt.stepForInsert(); + assert.equal(res.status, DbResult.BE_SQLITE_DONE); + assert.isDefined(res.id); + await verify(res.id!); + }); + + await ecdb.withPreparedStatement("INSERT INTO test.Foo(I_Array,Dt_Array,Addresses) VALUES(:iarray,:dtarray,:addresses)", async (stmt: ECSqlStatement) => { + stmt.bindArray("iarray", intArray); + stmt.bindArray("dtarray", dtArray); + stmt.bindArray("addresses", addressArray); + const res: ECSqlInsertResult = stmt.stepForInsert(); + assert.equal(res.status, DbResult.BE_SQLITE_DONE); + assert.isDefined(res.id); + await verify(res.id!); + }); + + await ecdb.withPreparedStatement("INSERT INTO test.Foo(I_Array,Dt_Array,Addresses) VALUES(:iarray,:dtarray,:addresses)", async (stmt: ECSqlStatement) => { + stmt.bindValues({ iarray: intArray, dtarray: dtArray, addresses: addressArray }); + const res: ECSqlInsertResult = stmt.stepForInsert(); + assert.equal(res.status, DbResult.BE_SQLITE_DONE); + assert.isDefined(res.id); + await verify(res.id!); }); }); it("should bind navigation", async () => { - await using(ECDbTestHelper.createECDb(outDir, "bindnavigation.ecdb", + using ecdb = ECDbTestHelper.createECDb(outDir, "bindnavigation.ecdb", ` @@ -1657,76 +1641,75 @@ describe("ECSqlStatement", () => { - `), async (ecdb) => { - - assert.isTrue(ecdb.isOpen); - - const parentId: Id64String = ecdb.withStatement("INSERT INTO test.Parent(Code) VALUES('Parent 1')", (stmt: ECSqlStatement) => { - const res: ECSqlInsertResult = stmt.stepForInsert(); - assert.equal(res.status, DbResult.BE_SQLITE_DONE); - assert.isDefined(res.id); - return res.id!; - }); - - const childIds = new Array(); - ecdb.withStatement("INSERT INTO test.Child(Name,Parent) VALUES(?,?)", (stmt: ECSqlStatement) => { - stmt.bindString(1, "Child 1"); - stmt.bindNavigation(2, { id: parentId, relClassName: "Test.ParentHasChildren" }); - let res: ECSqlInsertResult = stmt.stepForInsert(); - assert.equal(res.status, DbResult.BE_SQLITE_DONE); - assert.isDefined(res.id); - childIds.push(res.id!); - - stmt.reset(); - stmt.clearBindings(); - - stmt.bindValues(["Child 2", { id: parentId, relClassName: "Test.ParentHasChildren" }]); - res = stmt.stepForInsert(); - assert.equal(res.status, DbResult.BE_SQLITE_DONE); - assert.isDefined(res.id); - childIds.push(res.id!); - }); + `); - ecdb.withStatement("INSERT INTO test.Child(Name,Parent) VALUES(:name,:parent)", (stmt: ECSqlStatement) => { - stmt.bindString("name", "Child 3"); - stmt.bindNavigation("parent", { id: parentId, relClassName: "Test.ParentHasChildren" }); - let res: ECSqlInsertResult = stmt.stepForInsert(); - assert.equal(res.status, DbResult.BE_SQLITE_DONE); - assert.isDefined(res.id); - childIds.push(res.id!); + assert.isTrue(ecdb.isOpen); - stmt.reset(); - stmt.clearBindings(); + const parentId: Id64String = ecdb.withStatement("INSERT INTO test.Parent(Code) VALUES('Parent 1')", (stmt: ECSqlStatement) => { + const res: ECSqlInsertResult = stmt.stepForInsert(); + assert.equal(res.status, DbResult.BE_SQLITE_DONE); + assert.isDefined(res.id); + return res.id!; + }); - stmt.bindValues({ name: "Child 4", parent: { id: parentId, relClassName: "Test.ParentHasChildren" } }); - res = stmt.stepForInsert(); - assert.equal(res.status, DbResult.BE_SQLITE_DONE); - assert.isDefined(res.id); - childIds.push(res.id!); - }); + const childIds = new Array(); + ecdb.withStatement("INSERT INTO test.Child(Name,Parent) VALUES(?,?)", (stmt: ECSqlStatement) => { + stmt.bindString(1, "Child 1"); + stmt.bindNavigation(2, { id: parentId, relClassName: "Test.ParentHasChildren" }); + let res: ECSqlInsertResult = stmt.stepForInsert(); + assert.equal(res.status, DbResult.BE_SQLITE_DONE); + assert.isDefined(res.id); + childIds.push(res.id!); + + stmt.reset(); + stmt.clearBindings(); + + stmt.bindValues(["Child 2", { id: parentId, relClassName: "Test.ParentHasChildren" }]); + res = stmt.stepForInsert(); + assert.equal(res.status, DbResult.BE_SQLITE_DONE); + assert.isDefined(res.id); + childIds.push(res.id!); + }); - ecdb.withPreparedStatement("SELECT Name,Parent FROM test.Child ORDER BY Name", (stmt: ECSqlStatement) => { - let rowCount: number = 0; - while (stmt.step() === DbResult.BE_SQLITE_ROW) { - rowCount++; - const row = stmt.getRow(); - assert.equal(row.name, `Child ${rowCount}`); - const parent: NavigationValue = row.parent as NavigationValue; - assert.equal(parent.id, parentId); - assert.equal(parent.relClassName, "Test.ParentHasChildren"); - } - assert.equal(rowCount, 4); - }); + ecdb.withStatement("INSERT INTO test.Child(Name,Parent) VALUES(:name,:parent)", (stmt: ECSqlStatement) => { + stmt.bindString("name", "Child 3"); + stmt.bindNavigation("parent", { id: parentId, relClassName: "Test.ParentHasChildren" }); + let res: ECSqlInsertResult = stmt.stepForInsert(); + assert.equal(res.status, DbResult.BE_SQLITE_DONE); + assert.isDefined(res.id); + childIds.push(res.id!); + + stmt.reset(); + stmt.clearBindings(); + + stmt.bindValues({ name: "Child 4", parent: { id: parentId, relClassName: "Test.ParentHasChildren" } }); + res = stmt.stepForInsert(); + assert.equal(res.status, DbResult.BE_SQLITE_DONE); + assert.isDefined(res.id); + childIds.push(res.id!); + }); - let rowCount2: number = 0; - assert.equal(await query(ecdb, "SELECT Name,Parent FROM test.Child ORDER BY Name", QueryBinder.from([]), undefined, (row: any) => { - rowCount2++; - assert.equal(row.name, `Child ${rowCount2}`); + ecdb.withPreparedStatement("SELECT Name,Parent FROM test.Child ORDER BY Name", (stmt: ECSqlStatement) => { + let rowCount: number = 0; + while (stmt.step() === DbResult.BE_SQLITE_ROW) { + rowCount++; + const row = stmt.getRow(); + assert.equal(row.name, `Child ${rowCount}`); const parent: NavigationValue = row.parent as NavigationValue; assert.equal(parent.id, parentId); assert.equal(parent.relClassName, "Test.ParentHasChildren"); - }), 4); + } + assert.equal(rowCount, 4); }); + + let rowCount2: number = 0; + assert.equal(await query(ecdb, "SELECT Name,Parent FROM test.Child ORDER BY Name", QueryBinder.from([]), undefined, (row: any) => { + rowCount2++; + assert.equal(row.name, `Child ${rowCount2}`); + const parent: NavigationValue = row.parent as NavigationValue; + assert.equal(parent.id, parentId); + assert.equal(parent.relClassName, "Test.ParentHasChildren"); + }), 4); }); it("should bind Range3d for parameter in spatial sql function", async () => { @@ -1751,98 +1734,96 @@ describe("ECSqlStatement", () => { }); it("should bind Range3d", async () => { - await using(ECDbTestHelper.createECDb(outDir, "bindrange3d.ecdb", + using ecdb = ECDbTestHelper.createECDb(outDir, "bindrange3d.ecdb", ` - `), async (ecdb) => { + `); - assert.isTrue(ecdb.isOpen); + assert.isTrue(ecdb.isOpen); - const id: Id64String = ecdb.withPreparedStatement("INSERT INTO test.Foo([Range3d]) VALUES(?)", (stmt: ECSqlStatement) => { - stmt.bindRange3d(1, testRange); - const res: ECSqlInsertResult = stmt.stepForInsert(); - assert.equal(res.status, DbResult.BE_SQLITE_DONE); - assert.isDefined(res.id); - return res.id!; - }); - ecdb.saveChanges(); - ecdb.withPreparedStatement("SELECT [Range3d] FROM test.Foo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { - stmt.bindId(1, id); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - const rangeBlob: Uint8Array = stmt.getValue(0).getBlob(); - const rangeFloatArray = new Float64Array(rangeBlob.buffer); - assert.equal(rangeFloatArray.length, 6); - const actualRange = new Range3d(...rangeFloatArray); - assert.isTrue(actualRange.isAlmostEqual(testRange)); - }); + const id: Id64String = ecdb.withPreparedStatement("INSERT INTO test.Foo([Range3d]) VALUES(?)", (stmt: ECSqlStatement) => { + stmt.bindRange3d(1, testRange); + const res: ECSqlInsertResult = stmt.stepForInsert(); + assert.equal(res.status, DbResult.BE_SQLITE_DONE); + assert.isDefined(res.id); + return res.id!; + }); + ecdb.saveChanges(); + ecdb.withPreparedStatement("SELECT [Range3d] FROM test.Foo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { + stmt.bindId(1, id); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + const rangeBlob: Uint8Array = stmt.getValue(0).getBlob(); + const rangeFloatArray = new Float64Array(rangeBlob.buffer); + assert.equal(rangeFloatArray.length, 6); + const actualRange = new Range3d(...rangeFloatArray); + assert.isTrue(actualRange.isAlmostEqual(testRange)); }); }); it("should bind IdSets", async () => { - await using(ECDbTestHelper.createECDb(outDir, "bindids.ecdb"), async (ecdb: ECDb) => { - assert.isTrue(ecdb.isOpen); - - const idNumbers: number[] = [4444, 4545, 1234, 6758, 1312]; - ecdb.withPreparedStatement("INSERT INTO ecdbf.ExternalFileInfo(ECInstanceId,Name) VALUES(?,?)", (stmt: ECSqlStatement) => { - idNumbers.forEach((idNum: number) => { - const expectedId = Id64.fromLocalAndBriefcaseIds(idNum, 0); - stmt.bindId(1, expectedId); - stmt.bindString(2, `${idNum}.txt`); - const r: ECSqlInsertResult = stmt.stepForInsert(); - assert.equal(r.status, DbResult.BE_SQLITE_DONE); - assert.isDefined(r.id); - assert.equal(r.id!, expectedId); - ecdb.saveChanges(); - - ecdb.withStatement(`SELECT ECInstanceId, ECClassId, Name FROM ecdbf.ExternalFileInfo WHERE ECInstanceId=${expectedId}`, (confstmt: ECSqlStatement) => { - assert.equal(confstmt.step(), DbResult.BE_SQLITE_ROW); - const row = confstmt.getRow(); - assert.equal(row.id, expectedId); - assert.equal(row.className, "ECDbFileInfo.ExternalFileInfo"); - assert.equal(row.name, `${Id64.getLocalId(expectedId).toString()}.txt`); - }); - stmt.reset(); - stmt.clearBindings(); - }); - }); - - ecdb.withPreparedStatement("SELECT ECInstanceId, ECClassId, Name from ecdbf.ExternalFileInfo WHERE InVirtualSet(?, ECInstanceId)", (stmt: ECSqlStatement) => { - let idSet: Id64String[] = []; - stmt.bindIdSet(1, idSet); - let result = stmt.step(); - assert.equal(result, DbResult.BE_SQLITE_DONE); - stmt.reset(); - stmt.clearBindings(); + using ecdb = ECDbTestHelper.createECDb(outDir, "bindids.ecdb"); + assert.isTrue(ecdb.isOpen); - idSet = [Id64.fromLocalAndBriefcaseIds(idNumbers[2], 0)]; - stmt.bindIdSet(1, idSet); - result = stmt.step(); - assert.equal(result, DbResult.BE_SQLITE_ROW); - let row = stmt.getRow(); - assert.equal(row.name, `${idNumbers[2]}.txt`); + const idNumbers: number[] = [4444, 4545, 1234, 6758, 1312]; + ecdb.withPreparedStatement("INSERT INTO ecdbf.ExternalFileInfo(ECInstanceId,Name) VALUES(?,?)", (stmt: ECSqlStatement) => { + idNumbers.forEach((idNum: number) => { + const expectedId = Id64.fromLocalAndBriefcaseIds(idNum, 0); + stmt.bindId(1, expectedId); + stmt.bindString(2, `${idNum}.txt`); + const r: ECSqlInsertResult = stmt.stepForInsert(); + assert.equal(r.status, DbResult.BE_SQLITE_DONE); + assert.isDefined(r.id); + assert.equal(r.id!, expectedId); + ecdb.saveChanges(); + + ecdb.withStatement(`SELECT ECInstanceId, ECClassId, Name FROM ecdbf.ExternalFileInfo WHERE ECInstanceId=${expectedId}`, (confstmt: ECSqlStatement) => { + assert.equal(confstmt.step(), DbResult.BE_SQLITE_ROW); + const row = confstmt.getRow(); + assert.equal(row.id, expectedId); + assert.equal(row.className, "ECDbFileInfo.ExternalFileInfo"); + assert.equal(row.name, `${Id64.getLocalId(expectedId).toString()}.txt`); + }); stmt.reset(); stmt.clearBindings(); - - idSet.push(idNumbers[0].toString()); - stmt.bindIdSet(1, idSet); - result = stmt.step(); - assert.equal(result, DbResult.BE_SQLITE_ROW); - row = stmt.getRow(); - assert.equal(row.name, `${idNumbers[2]}.txt`); - result = stmt.step(); - assert.equal(result, DbResult.BE_SQLITE_ROW); - row = stmt.getRow(); - assert.equal(row.name, `${idNumbers[0]}.txt`); }); }); + + ecdb.withPreparedStatement("SELECT ECInstanceId, ECClassId, Name from ecdbf.ExternalFileInfo WHERE InVirtualSet(?, ECInstanceId)", (stmt: ECSqlStatement) => { + let idSet: Id64String[] = []; + stmt.bindIdSet(1, idSet); + let result = stmt.step(); + assert.equal(result, DbResult.BE_SQLITE_DONE); + stmt.reset(); + stmt.clearBindings(); + + idSet = [Id64.fromLocalAndBriefcaseIds(idNumbers[2], 0)]; + stmt.bindIdSet(1, idSet); + result = stmt.step(); + assert.equal(result, DbResult.BE_SQLITE_ROW); + let row = stmt.getRow(); + assert.equal(row.name, `${idNumbers[2]}.txt`); + stmt.reset(); + stmt.clearBindings(); + + idSet.push(idNumbers[0].toString()); + stmt.bindIdSet(1, idSet); + result = stmt.step(); + assert.equal(result, DbResult.BE_SQLITE_ROW); + row = stmt.getRow(); + assert.equal(row.name, `${idNumbers[2]}.txt`); + result = stmt.step(); + assert.equal(result, DbResult.BE_SQLITE_ROW); + row = stmt.getRow(); + assert.equal(row.name, `${idNumbers[0]}.txt`); + }); }); /* This test doesn't do anything specific with the binder life time but just runs a few scenarios with and without statement cache to test that stuff works fine */ it("check ECSqlBinder life time", async () => { - await using(ECDbTestHelper.createECDb(outDir, "ecsqlbinderlifetime.ecdb", + using ecdb = ECDbTestHelper.createECDb(outDir, "ecsqlbinderlifetime.ecdb", ` @@ -1854,65 +1835,49 @@ describe("ECSqlStatement", () => { - `), async (ecdb) => { - - assert.isTrue(ecdb.isOpen); + `); - let id1: Id64String, id2: Id64String; + assert.isTrue(ecdb.isOpen); - // *** test without statement cache - using(ecdb.prepareStatement("INSERT INTO test.Person(Name,Age,Location) VALUES(?,?,?)"), (stmt: ECSqlStatement) => { - stmt.bindString(1, "Mary Miller"); - stmt.bindInteger(2, 30); - stmt.bindStruct(3, { Street: "2000 Main Street", City: "New York", Zip: 12311 }); + let id1: Id64String, id2: Id64String; - const res: ECSqlInsertResult = stmt.stepForInsert(); - assert.equal(res.status, DbResult.BE_SQLITE_DONE); - assert.isDefined(res.id); - id1 = res.id!; - assert.isTrue(Id64.isValidId64(id1)); - }); + // *** test without statement cache + { + using stmt = ecdb.prepareStatement("INSERT INTO test.Person(Name,Age,Location) VALUES(?,?,?)"); + stmt.bindString(1, "Mary Miller"); + stmt.bindInteger(2, 30); + stmt.bindStruct(3, { Street: "2000 Main Street", City: "New York", Zip: 12311 }); - // *** test withstatement cache - ecdb.withPreparedStatement("INSERT INTO test.Person(Name,Age,Location) VALUES(?,?,?)", (stmt: ECSqlStatement) => { - stmt.bindString(1, "Mary Miller"); - stmt.bindInteger(2, 30); - stmt.bindStruct(3, { Street: "2000 Main Street", City: "New York", Zip: 12311 }); - - const res: ECSqlInsertResult = stmt.stepForInsert(); - assert.equal(res.status, DbResult.BE_SQLITE_DONE); - assert.isDefined(res.id); - id2 = res.id!; - assert.isTrue(Id64.isValidId64(id2)); - }); + const res: ECSqlInsertResult = stmt.stepForInsert(); + assert.equal(res.status, DbResult.BE_SQLITE_DONE); + assert.isDefined(res.id); + id1 = res.id!; + assert.isTrue(Id64.isValidId64(id1)); + } - using(ecdb.prepareStatement("SELECT ECInstanceId,ECClassId,Name,Age,Location FROM test.Person ORDER BY ECInstanceId"), (stmt: ECSqlStatement) => { - let rowCount = 0; - while (stmt.step() === DbResult.BE_SQLITE_ROW) { - rowCount++; - const row = stmt.getRow(); - if (rowCount === 1) - assert.equal(row.id, id1); - else - assert.equal(row.id, id2); - - assert.equal(row.className, "Test.Person"); - assert.equal(row.name, "Mary Miller"); - assert.equal(row.age, 30); - assert.equal(row.location.street, "2000 Main Street"); - assert.equal(row.location.city, "New York"); - assert.equal(row.location.zip, 12311); - } - assert.equal(rowCount, 2); - }); + // *** test withstatement cache + ecdb.withPreparedStatement("INSERT INTO test.Person(Name,Age,Location) VALUES(?,?,?)", (stmt: ECSqlStatement) => { + stmt.bindString(1, "Mary Miller"); + stmt.bindInteger(2, 30); + stmt.bindStruct(3, { Street: "2000 Main Street", City: "New York", Zip: 12311 }); + + const res: ECSqlInsertResult = stmt.stepForInsert(); + assert.equal(res.status, DbResult.BE_SQLITE_DONE); + assert.isDefined(res.id); + id2 = res.id!; + assert.isTrue(Id64.isValidId64(id2)); + }); - let rowCount2: number = 0; - assert.equal(await query(ecdb, "SELECT ECInstanceId,ECClassId,Name,Age,Location FROM test.Person ORDER BY ECInstanceId", QueryBinder.from([]), undefined, (row: any) => { - rowCount2++; - if (rowCount2 === 1) + { + using stmt = ecdb.prepareStatement("SELECT ECInstanceId,ECClassId,Name,Age,Location FROM test.Person ORDER BY ECInstanceId"); + let rowCount = 0; + while (stmt.step() === DbResult.BE_SQLITE_ROW) { + rowCount++; + const row = stmt.getRow(); + if (rowCount === 1) assert.equal(row.id, id1); else - assert.equal(row.id, id2); + assert.equal(row.id, id2!); assert.equal(row.className, "Test.Person"); assert.equal(row.name, "Mary Miller"); @@ -1920,12 +1885,29 @@ describe("ECSqlStatement", () => { assert.equal(row.location.street, "2000 Main Street"); assert.equal(row.location.city, "New York"); assert.equal(row.location.zip, 12311); - }), 2); - }); + } + assert.equal(rowCount, 2); + } + + let rowCount2: number = 0; + assert.equal(await query(ecdb, "SELECT ECInstanceId,ECClassId,Name,Age,Location FROM test.Person ORDER BY ECInstanceId", QueryBinder.from([]), undefined, (row: any) => { + rowCount2++; + if (rowCount2 === 1) + assert.equal(row.id, id1); + else + assert.equal(row.id, id2); + + assert.equal(row.className, "Test.Person"); + assert.equal(row.name, "Mary Miller"); + assert.equal(row.age, 30); + assert.equal(row.location.street, "2000 Main Street"); + assert.equal(row.location.city, "New York"); + assert.equal(row.location.zip, 12311); + }), 2); }); it("getRow() with primitives values", async () => { - await using(ECDbTestHelper.createECDb(outDir, "getprimitives.ecdb", + using ecdb = ECDbTestHelper.createECDb(outDir, "getprimitives.ecdb", ` @@ -1939,276 +1921,274 @@ describe("ECSqlStatement", () => { - `), async (ecdb: ECDb) => { - assert.isTrue(ecdb.isOpen); - - const boolVal: boolean = true; - const doubleVal: number = 3.5; - const dtVal: string = "2018-01-23T12:24:00.000"; - const intVal: number = 3; - const p2dVal = new Point2d(1, 2); - const p3dVal = new Point3d(1, 2, 3); - const strVal: string = "Hello world"; - - const id: Id64String = ecdb.withPreparedStatement("INSERT INTO test.Foo(Bl,Bo,D,Dt,I,P2d,P3d,S) VALUES(?,?,?,?,?,?,?,?)", (stmt: ECSqlStatement) => { - stmt.bindBlob(1, blobVal); - stmt.bindBoolean(2, boolVal); - stmt.bindDouble(3, doubleVal); - stmt.bindDateTime(4, dtVal); - stmt.bindInteger(5, intVal); - stmt.bindPoint2d(6, p2dVal); - stmt.bindPoint3d(7, p3dVal); - stmt.bindString(8, strVal); - const res: ECSqlInsertResult = stmt.stepForInsert(); - assert.equal(res.status, DbResult.BE_SQLITE_DONE); - return res.id!; - }); - - ecdb.withPreparedStatement("SELECT ECInstanceId, ECClassId, Bl,Bo,D,Dt,I,P2d,P3d,S FROM test.Foo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { - stmt.bindId(1, id); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - const row = stmt.getRow(); - assert.equal(row.id, id); - assert.equal(row.className, "Test.Foo"); - assert.deepEqual(row.bl, blobVal); - assert.equal(row.bo, boolVal); - assert.equal(row.d, doubleVal); - assert.equal(row.dt, dtVal); - assert.equal(row.i, intVal); - assert.equal(row.p2d.x, p2dVal.x); - assert.equal(row.p2d.y, p2dVal.y); - assert.equal(row.p3d.x, p3dVal.x); - assert.equal(row.p3d.y, p3dVal.y); - assert.equal(row.p3d.z, p3dVal.z); - assert.equal(row.s, strVal); - }); - - assert.equal(await query(ecdb, "SELECT ECInstanceId, ECClassId, Bl FROM test.Foo WHERE ECInstanceId=?", QueryBinder.from([id]), { abbreviateBlobs: true, ...selectSingleRow }, (row: any) => { - assert.equal(row.id, id); - assert.equal(row.className, "Test.Foo"); - assert.deepEqual(row.bl, abbreviatedBlobVal); - }), 1); - - assert.equal(await query(ecdb, "SELECT ECInstanceId, ECClassId, Bl FROM test.Foo WHERE ECInstanceId=?", QueryBinder.from([id]), { abbreviateBlobs: false, ...selectSingleRow }, (row: any) => { - assert.equal(row.id, id); - assert.equal(row.className, "Test.Foo"); - assert.deepEqual(row.bl, blobVal); - }), 1); - - // assert.equal(await query(ecdb, "SELECT ECInstanceId, ECClassId, Bl,Bo,D,Dt,I,P2d,P3d,S FROM test.Foo WHERE ECInstanceId=?", [id], 1, (row: any) => { - // assert.equal(row.id, id); - // assert.equal(row.className, "Test.Foo"); - // assert.deepEqual(row.bl, blobVal); - // assert.equal(row.bo, boolVal); - // assert.equal(row.d, doubleVal); - // assert.equal(row.dt, dtVal); - // assert.equal(row.i, intVal); - // assert.equal(row.p2d.x, p2dVal.x); - // assert.equal(row.p2d.y, p2dVal.y); - // assert.equal(row.p3d.x, p3dVal.x); - // assert.equal(row.p3d.y, p3dVal.y); - // assert.equal(row.p3d.z, p3dVal.z); - // assert.equal(row.s, strVal); - // }), 1); - - ecdb.withPreparedStatement("SELECT Bl AS Blobby, I+10, Lower(S), Upper(S) CapitalS FROM test.Foo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { - stmt.bindId(1, id); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - const row = stmt.getRow(); - assert.deepEqual(row.blobby, blobVal); - assert.equal(row["[I] + 10"], intVal + 10); - assert.equal(row["lower([S])"], strVal.toLowerCase()); - assert.equal(row.capitalS, strVal.toUpperCase()); - }); - - // assert.equal(await query(ecdb, "SELECT Bl AS Blobby, I+10, Lower(S), Upper(S) CapitalS FROM test.Foo WHERE ECInstanceId=?", [id], 1, (row: any) => { - // assert.deepEqual(row.blobby, blobVal); - // assert.equal(row["[I] + 10"], intVal + 10); - // assert.equal(row["lower([S])"], strVal.toLowerCase()); - // assert.equal(row.capitalS, strVal.toUpperCase()); - // }), 1); - - const testSchemaId: Id64String = ecdb.withPreparedStatement("SELECT ECInstanceId FROM meta.ECSchemaDef WHERE Name='Test'", (stmt: ECSqlStatement) => { - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - const row = stmt.getRow(); - assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE); - return Id64.fromJSON(row.id); - }); + `); + assert.isTrue(ecdb.isOpen); + + const boolVal: boolean = true; + const doubleVal: number = 3.5; + const dtVal: string = "2018-01-23T12:24:00.000"; + const intVal: number = 3; + const p2dVal = new Point2d(1, 2); + const p3dVal = new Point3d(1, 2, 3); + const strVal: string = "Hello world"; + + const id: Id64String = ecdb.withPreparedStatement("INSERT INTO test.Foo(Bl,Bo,D,Dt,I,P2d,P3d,S) VALUES(?,?,?,?,?,?,?,?)", (stmt: ECSqlStatement) => { + stmt.bindBlob(1, blobVal); + stmt.bindBoolean(2, boolVal); + stmt.bindDouble(3, doubleVal); + stmt.bindDateTime(4, dtVal); + stmt.bindInteger(5, intVal); + stmt.bindPoint2d(6, p2dVal); + stmt.bindPoint3d(7, p3dVal); + stmt.bindString(8, strVal); + const res: ECSqlInsertResult = stmt.stepForInsert(); + assert.equal(res.status, DbResult.BE_SQLITE_DONE); + return res.id!; + }); - const fooClassId: Id64String = ecdb.withPreparedStatement("SELECT ECInstanceId FROM meta.ECClassDef WHERE Name='Foo'", (stmt: ECSqlStatement) => { - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - const row = stmt.getRow(); - assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE); - return Id64.fromJSON(row.id); - }); + ecdb.withPreparedStatement("SELECT ECInstanceId, ECClassId, Bl,Bo,D,Dt,I,P2d,P3d,S FROM test.Foo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { + stmt.bindId(1, id); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + const row = stmt.getRow(); + assert.equal(row.id, id); + assert.equal(row.className, "Test.Foo"); + assert.deepEqual(row.bl, blobVal); + assert.equal(row.bo, boolVal); + assert.equal(row.d, doubleVal); + assert.equal(row.dt, dtVal); + assert.equal(row.i, intVal); + assert.equal(row.p2d.x, p2dVal.x); + assert.equal(row.p2d.y, p2dVal.y); + assert.equal(row.p3d.x, p3dVal.x); + assert.equal(row.p3d.y, p3dVal.y); + assert.equal(row.p3d.z, p3dVal.z); + assert.equal(row.s, strVal); + }); - ecdb.withPreparedStatement("SELECT s.ECInstanceId, c.ECInstanceId, c.Name, s.Name FROM meta.ECClassDef c JOIN meta.ECSchemaDef s ON c.Schema.Id=s.ECInstanceId WHERE s.Name='Test' AND c.Name='Foo'", (stmt: ECSqlStatement) => { - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - const row = stmt.getRow(); - assert.equal(row.id, testSchemaId); - assert.equal(row.id_1, fooClassId); - }); + assert.equal(await query(ecdb, "SELECT ECInstanceId, ECClassId, Bl FROM test.Foo WHERE ECInstanceId=?", QueryBinder.from([id]), { abbreviateBlobs: true, ...selectSingleRow }, (row: any) => { + assert.equal(row.id, id); + assert.equal(row.className, "Test.Foo"); + assert.deepEqual(row.bl, abbreviatedBlobVal); + }), 1); + + assert.equal(await query(ecdb, "SELECT ECInstanceId, ECClassId, Bl FROM test.Foo WHERE ECInstanceId=?", QueryBinder.from([id]), { abbreviateBlobs: false, ...selectSingleRow }, (row: any) => { + assert.equal(row.id, id); + assert.equal(row.className, "Test.Foo"); + assert.deepEqual(row.bl, blobVal); + }), 1); + + // assert.equal(await query(ecdb, "SELECT ECInstanceId, ECClassId, Bl,Bo,D,Dt,I,P2d,P3d,S FROM test.Foo WHERE ECInstanceId=?", [id], 1, (row: any) => { + // assert.equal(row.id, id); + // assert.equal(row.className, "Test.Foo"); + // assert.deepEqual(row.bl, blobVal); + // assert.equal(row.bo, boolVal); + // assert.equal(row.d, doubleVal); + // assert.equal(row.dt, dtVal); + // assert.equal(row.i, intVal); + // assert.equal(row.p2d.x, p2dVal.x); + // assert.equal(row.p2d.y, p2dVal.y); + // assert.equal(row.p3d.x, p3dVal.x); + // assert.equal(row.p3d.y, p3dVal.y); + // assert.equal(row.p3d.z, p3dVal.z); + // assert.equal(row.s, strVal); + // }), 1); + + ecdb.withPreparedStatement("SELECT Bl AS Blobby, I+10, Lower(S), Upper(S) CapitalS FROM test.Foo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { + stmt.bindId(1, id); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + const row = stmt.getRow(); + assert.deepEqual(row.blobby, blobVal); + assert.equal(row["[I] + 10"], intVal + 10); + assert.equal(row["lower([S])"], strVal.toLowerCase()); + assert.equal(row.capitalS, strVal.toUpperCase()); + }); - assert.equal(await query(ecdb, "SELECT s.ECInstanceId, c.ECInstanceId, c.Name, s.Name FROM meta.ECClassDef c JOIN meta.ECSchemaDef s ON c.Schema.Id=s.ECInstanceId WHERE s.Name='Test' AND c.Name='Foo'", QueryBinder.from([]), selectSingleRow, (row: any) => { - assert.equal(row.id, testSchemaId); - assert.equal(row.id_1, fooClassId); - }), 1); + // assert.equal(await query(ecdb, "SELECT Bl AS Blobby, I+10, Lower(S), Upper(S) CapitalS FROM test.Foo WHERE ECInstanceId=?", [id], 1, (row: any) => { + // assert.deepEqual(row.blobby, blobVal); + // assert.equal(row["[I] + 10"], intVal + 10); + // assert.equal(row["lower([S])"], strVal.toLowerCase()); + // assert.equal(row.capitalS, strVal.toUpperCase()); + // }), 1); + + const testSchemaId: Id64String = ecdb.withPreparedStatement("SELECT ECInstanceId FROM meta.ECSchemaDef WHERE Name='Test'", (stmt: ECSqlStatement) => { + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + const row = stmt.getRow(); + assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE); + return Id64.fromJSON(row.id); + }); - ecdb.withPreparedStatement("SELECT count(*) cnt FROM meta.ECSchemaDef", (stmt: ECSqlStatement) => { - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - const row = stmt.getRow(); - assert.isDefined(row.cnt); - assert.equal(typeof (row.cnt), "number"); - assert.equal(row.cnt, 6); - }); + const fooClassId: Id64String = ecdb.withPreparedStatement("SELECT ECInstanceId FROM meta.ECClassDef WHERE Name='Foo'", (stmt: ECSqlStatement) => { + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + const row = stmt.getRow(); + assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE); + return Id64.fromJSON(row.id); + }); - assert.equal(await query(ecdb, "SELECT count(*) cnt FROM meta.ECSchemaDef", QueryBinder.from([]), selectSingleRow, (row: any) => { - assert.isDefined(row.cnt); - assert.equal(typeof (row.cnt), "number"); - assert.equal(row.cnt, 6); - }), 1); + ecdb.withPreparedStatement("SELECT s.ECInstanceId, c.ECInstanceId, c.Name, s.Name FROM meta.ECClassDef c JOIN meta.ECSchemaDef s ON c.Schema.Id=s.ECInstanceId WHERE s.Name='Test' AND c.Name='Foo'", (stmt: ECSqlStatement) => { + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + const row = stmt.getRow(); + assert.equal(row.id, testSchemaId); + assert.equal(row.id_1, fooClassId); + }); - ecdb.withPreparedStatement("SELECT 1 FROM meta.ECSchemaDef LIMIT 1", (stmt: ECSqlStatement) => { - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - const row = stmt.getRow(); - assert.equal(typeof (row["1"]), "number"); - assert.equal(row["1"], 1); - }); + assert.equal(await query(ecdb, "SELECT s.ECInstanceId, c.ECInstanceId, c.Name, s.Name FROM meta.ECClassDef c JOIN meta.ECSchemaDef s ON c.Schema.Id=s.ECInstanceId WHERE s.Name='Test' AND c.Name='Foo'", QueryBinder.from([]), selectSingleRow, (row: any) => { + assert.equal(row.id, testSchemaId); + assert.equal(row.id_1, fooClassId); + }), 1); + + ecdb.withPreparedStatement("SELECT count(*) cnt FROM meta.ECSchemaDef", (stmt: ECSqlStatement) => { + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + const row = stmt.getRow(); + assert.isDefined(row.cnt); + assert.equal(typeof (row.cnt), "number"); + assert.equal(row.cnt, 6); + }); - assert.equal(await query(ecdb, "SELECT 1 FROM meta.ECSchemaDef LIMIT 1", QueryBinder.from([]), undefined, (row: any) => { - assert.equal(typeof (row["1"]), "number"); - assert.equal(row["1"], 1); - }), 1); + assert.equal(await query(ecdb, "SELECT count(*) cnt FROM meta.ECSchemaDef", QueryBinder.from([]), selectSingleRow, (row: any) => { + assert.isDefined(row.cnt); + assert.equal(typeof (row.cnt), "number"); + assert.equal(row.cnt, 6); + }), 1); + + ecdb.withPreparedStatement("SELECT 1 FROM meta.ECSchemaDef LIMIT 1", (stmt: ECSqlStatement) => { + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + const row = stmt.getRow(); + assert.equal(typeof (row["1"]), "number"); + assert.equal(row["1"], 1); + }); - ecdb.withPreparedStatement("SELECT NULL FROM meta.ECSchemaDef LIMIT 1", (stmt: ECSqlStatement) => { - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - const row = stmt.getRow(); - assert.equal(Object.entries(row).length, 0); - }); + assert.equal(await query(ecdb, "SELECT 1 FROM meta.ECSchemaDef LIMIT 1", QueryBinder.from([]), undefined, (row: any) => { + assert.equal(typeof (row["1"]), "number"); + assert.equal(row["1"], 1); + }), 1); - assert.equal(await query(ecdb, "SELECT NULL FROM meta.ECSchemaDef LIMIT 1", QueryBinder.from([]), undefined, (row: any) => { - assert.equal(Object.entries(row).length, 0); - }), 1); + ecdb.withPreparedStatement("SELECT NULL FROM meta.ECSchemaDef LIMIT 1", (stmt: ECSqlStatement) => { + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + const row = stmt.getRow(); + assert.equal(Object.entries(row).length, 0); }); + + assert.equal(await query(ecdb, "SELECT NULL FROM meta.ECSchemaDef LIMIT 1", QueryBinder.from([]), undefined, (row: any) => { + assert.equal(Object.entries(row).length, 0); + }), 1); }); it("getRow() with abbreviated blobs", async () => { - await using(ECDbTestHelper.createECDb(outDir, "getblobs.ecdb", + using ecdb = ECDbTestHelper.createECDb(outDir, "getblobs.ecdb", ` - `), async (ecdb: ECDb) => { - assert.isTrue(ecdb.isOpen); - - const singleBlobVal = blobVal.slice(0, 1); - const abbreviatedSingleBlobVal = `{"bytes":${singleBlobVal.byteLength}}`; - const emptyBlobVal = new Uint8Array(); - - const fullId: Id64String = ecdb.withPreparedStatement("INSERT INTO test.Foo(Bl) VALUES(?)", (stmt: ECSqlStatement) => { - stmt.bindBlob(1, blobVal); - const res: ECSqlInsertResult = stmt.stepForInsert(); - assert.equal(res.status, DbResult.BE_SQLITE_DONE); - return res.id!; - }); - - const singleId: Id64String = ecdb.withPreparedStatement("INSERT INTO test.Foo(Bl) VALUES(?)", (stmt: ECSqlStatement) => { - stmt.bindBlob(1, singleBlobVal); - const res: ECSqlInsertResult = stmt.stepForInsert(); - assert.equal(res.status, DbResult.BE_SQLITE_DONE); - return res.id!; - }); - - const emptyId: Id64String = ecdb.withPreparedStatement("INSERT INTO test.Foo(Bl) VALUES(?)", (stmt: ECSqlStatement) => { - stmt.bindBlob(1, emptyBlobVal); - const res: ECSqlInsertResult = stmt.stepForInsert(); - assert.equal(res.status, DbResult.BE_SQLITE_DONE); - return res.id!; - }); - - const nullId: Id64String = ecdb.withPreparedStatement("INSERT INTO test.Foo(Bl) VALUES(?)", (stmt: ECSqlStatement) => { - stmt.bindNull(1); - const res: ECSqlInsertResult = stmt.stepForInsert(); - assert.equal(res.status, DbResult.BE_SQLITE_DONE); - return res.id!; - }); - - assert.equal(await query(ecdb, "SELECT ECInstanceId, ECClassId, Bl FROM test.Foo WHERE ECInstanceId=?", QueryBinder.from([fullId]), { abbreviateBlobs: true, ...selectSingleRow }, (row: any) => { - assert.equal(row.id, fullId); - assert.equal(row.className, "Test.Foo"); - assert.deepEqual(row.bl, abbreviatedBlobVal); - }), 1); - - assert.equal(await query(ecdb, "SELECT ECInstanceId, ECClassId, Bl FROM test.Foo WHERE ECInstanceId=?", QueryBinder.from([fullId]), { abbreviateBlobs: false, ...selectSingleRow }, (row: any) => { - assert.equal(row.id, fullId); - assert.equal(row.className, "Test.Foo"); - assert.deepEqual(row.bl, blobVal); - }), 1); - - assert.equal(await query(ecdb, "SELECT ECInstanceId, ECClassId, Bl FROM test.Foo WHERE ECInstanceId=?", QueryBinder.from([fullId]), selectSingleRow, (row: any) => { - assert.equal(row.id, fullId); - assert.equal(row.className, "Test.Foo"); - assert.deepEqual(row.bl, blobVal); - }), 1); - - assert.equal(await query(ecdb, "SELECT ECInstanceId, ECClassId, Bl FROM test.Foo WHERE ECInstanceId=?", QueryBinder.from([singleId]), { abbreviateBlobs: true, ...selectSingleRow }, (row: any) => { - assert.equal(row.id, singleId); - assert.equal(row.className, "Test.Foo"); - assert.deepEqual(row.bl, abbreviatedSingleBlobVal); - }), 1); - - assert.equal(await query(ecdb, "SELECT ECInstanceId, ECClassId, Bl FROM test.Foo WHERE ECInstanceId=?", QueryBinder.from([singleId]), { abbreviateBlobs: false, ...selectSingleRow }, (row: any) => { - assert.equal(row.id, singleId); - assert.equal(row.className, "Test.Foo"); - assert.deepEqual(row.bl, singleBlobVal); - }), 1); - - assert.equal(await query(ecdb, "SELECT ECInstanceId, ECClassId, Bl FROM test.Foo WHERE ECInstanceId=?", QueryBinder.from([singleId]), { ...selectSingleRow }, (row: any) => { - assert.equal(row.id, singleId); - assert.equal(row.className, "Test.Foo"); - assert.deepEqual(row.bl, singleBlobVal); - }), 1); - - assert.equal(await query(ecdb, "SELECT ECInstanceId, ECClassId, Bl FROM test.Foo WHERE ECInstanceId=?", QueryBinder.from([emptyId]), { abbreviateBlobs: true, ...selectSingleRow }, (row: any) => { - assert.equal(row.id, emptyId); - assert.equal(row.className, "Test.Foo"); - assert.deepEqual(row.bl, "{\"bytes\":0}"); - }), 1); - - assert.equal(await query(ecdb, "SELECT ECInstanceId, ECClassId, Bl FROM test.Foo WHERE ECInstanceId=?", QueryBinder.from([emptyId]), { abbreviateBlobs: false, ...selectSingleRow }, (row: any) => { - assert.equal(row.id, emptyId); - assert.equal(row.className, "Test.Foo"); - assert.deepEqual(row.bl.length, 0); - }), 1); - - assert.equal(await query(ecdb, "SELECT ECInstanceId, ECClassId, Bl FROM test.Foo WHERE ECInstanceId=?", QueryBinder.from([emptyId]), selectSingleRow, (row: any) => { - assert.equal(row.id, emptyId); - assert.equal(row.className, "Test.Foo"); - assert.deepEqual(row.bl.length, 0); - }), 1); + `); + assert.isTrue(ecdb.isOpen); + + const singleBlobVal = blobVal.slice(0, 1); + const abbreviatedSingleBlobVal = `{"bytes":${singleBlobVal.byteLength}}`; + const emptyBlobVal = new Uint8Array(); + + const fullId: Id64String = ecdb.withPreparedStatement("INSERT INTO test.Foo(Bl) VALUES(?)", (stmt: ECSqlStatement) => { + stmt.bindBlob(1, blobVal); + const res: ECSqlInsertResult = stmt.stepForInsert(); + assert.equal(res.status, DbResult.BE_SQLITE_DONE); + return res.id!; + }); - assert.equal(await query(ecdb, "SELECT ECInstanceId, ECClassId, Bl FROM test.Foo WHERE ECInstanceId=?", QueryBinder.from([nullId]), { abbreviateBlobs: true, ...selectSingleRow }, (row: any) => { - assert.equal(row.id, nullId); - assert.equal(row.className, "Test.Foo"); - assert.deepEqual(row.bl, undefined); - }), 1); + const singleId: Id64String = ecdb.withPreparedStatement("INSERT INTO test.Foo(Bl) VALUES(?)", (stmt: ECSqlStatement) => { + stmt.bindBlob(1, singleBlobVal); + const res: ECSqlInsertResult = stmt.stepForInsert(); + assert.equal(res.status, DbResult.BE_SQLITE_DONE); + return res.id!; + }); - assert.equal(await query(ecdb, "SELECT ECInstanceId, ECClassId, Bl FROM test.Foo WHERE ECInstanceId=?", QueryBinder.from([nullId]), { abbreviateBlobs: false, ...selectSingleRow }, (row: any) => { - assert.equal(row.id, nullId); - assert.equal(row.className, "Test.Foo"); - assert.deepEqual(row.bl, undefined); - }), 1); + const emptyId: Id64String = ecdb.withPreparedStatement("INSERT INTO test.Foo(Bl) VALUES(?)", (stmt: ECSqlStatement) => { + stmt.bindBlob(1, emptyBlobVal); + const res: ECSqlInsertResult = stmt.stepForInsert(); + assert.equal(res.status, DbResult.BE_SQLITE_DONE); + return res.id!; + }); - assert.equal(await query(ecdb, "SELECT ECInstanceId, ECClassId, Bl FROM test.Foo WHERE ECInstanceId=?", QueryBinder.from([nullId]), selectSingleRow, (row: any) => { - assert.equal(row.id, nullId); - assert.equal(row.className, "Test.Foo"); - assert.deepEqual(row.bl, undefined); - }), 1); + const nullId: Id64String = ecdb.withPreparedStatement("INSERT INTO test.Foo(Bl) VALUES(?)", (stmt: ECSqlStatement) => { + stmt.bindNull(1); + const res: ECSqlInsertResult = stmt.stepForInsert(); + assert.equal(res.status, DbResult.BE_SQLITE_DONE); + return res.id!; }); + + assert.equal(await query(ecdb, "SELECT ECInstanceId, ECClassId, Bl FROM test.Foo WHERE ECInstanceId=?", QueryBinder.from([fullId]), { abbreviateBlobs: true, ...selectSingleRow }, (row: any) => { + assert.equal(row.id, fullId); + assert.equal(row.className, "Test.Foo"); + assert.deepEqual(row.bl, abbreviatedBlobVal); + }), 1); + + assert.equal(await query(ecdb, "SELECT ECInstanceId, ECClassId, Bl FROM test.Foo WHERE ECInstanceId=?", QueryBinder.from([fullId]), { abbreviateBlobs: false, ...selectSingleRow }, (row: any) => { + assert.equal(row.id, fullId); + assert.equal(row.className, "Test.Foo"); + assert.deepEqual(row.bl, blobVal); + }), 1); + + assert.equal(await query(ecdb, "SELECT ECInstanceId, ECClassId, Bl FROM test.Foo WHERE ECInstanceId=?", QueryBinder.from([fullId]), selectSingleRow, (row: any) => { + assert.equal(row.id, fullId); + assert.equal(row.className, "Test.Foo"); + assert.deepEqual(row.bl, blobVal); + }), 1); + + assert.equal(await query(ecdb, "SELECT ECInstanceId, ECClassId, Bl FROM test.Foo WHERE ECInstanceId=?", QueryBinder.from([singleId]), { abbreviateBlobs: true, ...selectSingleRow }, (row: any) => { + assert.equal(row.id, singleId); + assert.equal(row.className, "Test.Foo"); + assert.deepEqual(row.bl, abbreviatedSingleBlobVal); + }), 1); + + assert.equal(await query(ecdb, "SELECT ECInstanceId, ECClassId, Bl FROM test.Foo WHERE ECInstanceId=?", QueryBinder.from([singleId]), { abbreviateBlobs: false, ...selectSingleRow }, (row: any) => { + assert.equal(row.id, singleId); + assert.equal(row.className, "Test.Foo"); + assert.deepEqual(row.bl, singleBlobVal); + }), 1); + + assert.equal(await query(ecdb, "SELECT ECInstanceId, ECClassId, Bl FROM test.Foo WHERE ECInstanceId=?", QueryBinder.from([singleId]), { ...selectSingleRow }, (row: any) => { + assert.equal(row.id, singleId); + assert.equal(row.className, "Test.Foo"); + assert.deepEqual(row.bl, singleBlobVal); + }), 1); + + assert.equal(await query(ecdb, "SELECT ECInstanceId, ECClassId, Bl FROM test.Foo WHERE ECInstanceId=?", QueryBinder.from([emptyId]), { abbreviateBlobs: true, ...selectSingleRow }, (row: any) => { + assert.equal(row.id, emptyId); + assert.equal(row.className, "Test.Foo"); + assert.deepEqual(row.bl, "{\"bytes\":0}"); + }), 1); + + assert.equal(await query(ecdb, "SELECT ECInstanceId, ECClassId, Bl FROM test.Foo WHERE ECInstanceId=?", QueryBinder.from([emptyId]), { abbreviateBlobs: false, ...selectSingleRow }, (row: any) => { + assert.equal(row.id, emptyId); + assert.equal(row.className, "Test.Foo"); + assert.deepEqual(row.bl.length, 0); + }), 1); + + assert.equal(await query(ecdb, "SELECT ECInstanceId, ECClassId, Bl FROM test.Foo WHERE ECInstanceId=?", QueryBinder.from([emptyId]), selectSingleRow, (row: any) => { + assert.equal(row.id, emptyId); + assert.equal(row.className, "Test.Foo"); + assert.deepEqual(row.bl.length, 0); + }), 1); + + assert.equal(await query(ecdb, "SELECT ECInstanceId, ECClassId, Bl FROM test.Foo WHERE ECInstanceId=?", QueryBinder.from([nullId]), { abbreviateBlobs: true, ...selectSingleRow }, (row: any) => { + assert.equal(row.id, nullId); + assert.equal(row.className, "Test.Foo"); + assert.deepEqual(row.bl, undefined); + }), 1); + + assert.equal(await query(ecdb, "SELECT ECInstanceId, ECClassId, Bl FROM test.Foo WHERE ECInstanceId=?", QueryBinder.from([nullId]), { abbreviateBlobs: false, ...selectSingleRow }, (row: any) => { + assert.equal(row.id, nullId); + assert.equal(row.className, "Test.Foo"); + assert.deepEqual(row.bl, undefined); + }), 1); + + assert.equal(await query(ecdb, "SELECT ECInstanceId, ECClassId, Bl FROM test.Foo WHERE ECInstanceId=?", QueryBinder.from([nullId]), selectSingleRow, (row: any) => { + assert.equal(row.id, nullId); + assert.equal(row.className, "Test.Foo"); + assert.deepEqual(row.bl, undefined); + }), 1); }); it("getRow() with navigation properties and relationships", async () => { - await using(ECDbTestHelper.createECDb(outDir, "getnavandrels.ecdb", + using ecdb = ECDbTestHelper.createECDb(outDir, "getnavandrels.ecdb", ` @@ -2225,128 +2205,127 @@ describe("ECSqlStatement", () => { - `), async (ecdb) => { - assert.isTrue(ecdb.isOpen); - let rowCount: number; - const parentId: Id64String = ecdb.withPreparedStatement("INSERT INTO test.Parent(Code) VALUES('Parent 1')", (stmt: ECSqlStatement) => { - const res: ECSqlInsertResult = stmt.stepForInsert(); - assert.equal(res.status, DbResult.BE_SQLITE_DONE); - assert.isDefined(res.id); - return res.id!; - }); - - const childIds = new Array(); - ecdb.withPreparedStatement("INSERT INTO test.Child(Name,Parent) VALUES(?,?)", (stmt: ECSqlStatement) => { - stmt.bindString(1, "Child 1"); - stmt.bindNavigation(2, { id: parentId, relClassName: "Test.ParentHasChildren" }); - let res: ECSqlInsertResult = stmt.stepForInsert(); - assert.equal(res.status, DbResult.BE_SQLITE_DONE); - assert.isDefined(res.id); - childIds.push(res.id!); - - stmt.reset(); - stmt.clearBindings(); - - stmt.bindValues(["Child 2", { id: parentId, relClassName: "Test.ParentHasChildren" }]); - res = stmt.stepForInsert(); - assert.equal(res.status, DbResult.BE_SQLITE_DONE); - assert.isDefined(res.id); - childIds.push(res.id!); - }); + `); + assert.isTrue(ecdb.isOpen); + let rowCount: number; + const parentId: Id64String = ecdb.withPreparedStatement("INSERT INTO test.Parent(Code) VALUES('Parent 1')", (stmt: ECSqlStatement) => { + const res: ECSqlInsertResult = stmt.stepForInsert(); + assert.equal(res.status, DbResult.BE_SQLITE_DONE); + assert.isDefined(res.id); + return res.id!; + }); - ecdb.withPreparedStatement("SELECT Name,Parent FROM test.Child ORDER BY Name", (stmt: ECSqlStatement) => { - rowCount = 0; - while (stmt.step() === DbResult.BE_SQLITE_ROW) { - rowCount++; - const row = stmt.getRow(); - assert.equal(row.name, `Child ${rowCount}`); - assert.equal(row.parent.id, parentId); - assert.equal(row.parent.relClassName, "Test.ParentHasChildren"); - } - assert.equal(rowCount, 2); - }); + const childIds = new Array(); + ecdb.withPreparedStatement("INSERT INTO test.Child(Name,Parent) VALUES(?,?)", (stmt: ECSqlStatement) => { + stmt.bindString(1, "Child 1"); + stmt.bindNavigation(2, { id: parentId, relClassName: "Test.ParentHasChildren" }); + let res: ECSqlInsertResult = stmt.stepForInsert(); + assert.equal(res.status, DbResult.BE_SQLITE_DONE); + assert.isDefined(res.id); + childIds.push(res.id!); + + stmt.reset(); + stmt.clearBindings(); + + stmt.bindValues(["Child 2", { id: parentId, relClassName: "Test.ParentHasChildren" }]); + res = stmt.stepForInsert(); + assert.equal(res.status, DbResult.BE_SQLITE_DONE); + assert.isDefined(res.id); + childIds.push(res.id!); + }); + ecdb.withPreparedStatement("SELECT Name,Parent FROM test.Child ORDER BY Name", (stmt: ECSqlStatement) => { rowCount = 0; - assert.equal(await query(ecdb, "SELECT Name,Parent FROM test.Child ORDER BY Name", QueryBinder.from([]), undefined, (row: any) => { + while (stmt.step() === DbResult.BE_SQLITE_ROW) { rowCount++; + const row = stmt.getRow(); assert.equal(row.name, `Child ${rowCount}`); assert.equal(row.parent.id, parentId); assert.equal(row.parent.relClassName, "Test.ParentHasChildren"); - }), 2); - - ecdb.withPreparedStatement("SELECT Name,Parent.Id,Parent.RelECClassId, Parent.Id myParentId, Parent.RelECClassId myParentRelClassId FROM test.Child ORDER BY Name", (stmt: ECSqlStatement) => { - rowCount = 0; - while (stmt.step() === DbResult.BE_SQLITE_ROW) { - rowCount++; - const row = stmt.getRow(); - assert.equal(row.name, `Child ${rowCount}`); - assert.equal(row["parent.id"], parentId); - assert.equal(row["parent.relClassName"], "Test.ParentHasChildren"); - assert.equal(row.myParentId, parentId); - assert.isTrue(Id64.isValidId64(row.myParentRelClassId)); - } - assert.equal(rowCount, 2); - }); + } + assert.equal(rowCount, 2); + }); + + rowCount = 0; + assert.equal(await query(ecdb, "SELECT Name,Parent FROM test.Child ORDER BY Name", QueryBinder.from([]), undefined, (row: any) => { + rowCount++; + assert.equal(row.name, `Child ${rowCount}`); + assert.equal(row.parent.id, parentId); + assert.equal(row.parent.relClassName, "Test.ParentHasChildren"); + }), 2); + ecdb.withPreparedStatement("SELECT Name,Parent.Id,Parent.RelECClassId, Parent.Id myParentId, Parent.RelECClassId myParentRelClassId FROM test.Child ORDER BY Name", (stmt: ECSqlStatement) => { rowCount = 0; - assert.equal(await query(ecdb, "SELECT Name,Parent.Id,Parent.RelECClassId, Parent.Id myParentId, Parent.RelECClassId myParentRelClassId FROM test.Child ORDER BY Name", QueryBinder.from([]), undefined, (row: any) => { + while (stmt.step() === DbResult.BE_SQLITE_ROW) { rowCount++; + const row = stmt.getRow(); assert.equal(row.name, `Child ${rowCount}`); assert.equal(row["parent.id"], parentId); assert.equal(row["parent.relClassName"], "Test.ParentHasChildren"); assert.equal(row.myParentId, parentId); assert.isTrue(Id64.isValidId64(row.myParentRelClassId)); - }), 2); - - const childId: Id64String = childIds[0]; - ecdb.withPreparedStatement("SELECT ECInstanceId,ECClassId,SourceECInstanceId,SourceECClassId,TargetECInstanceId,TargetECClassId FROM test.ParentHasChildren WHERE TargetECInstanceId=?", (stmt: ECSqlStatement) => { - stmt.bindId(1, childId); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - const row = stmt.getRow(); - assert.equal(row.id, childId); - assert.equal(row.className, "Test.ParentHasChildren"); - assert.equal(row.sourceId, parentId); - assert.equal(row.sourceClassName, "Test.Parent"); - assert.equal(row.targetId, childId); - assert.equal(row.targetClassName, "Test.Child"); - }); + } + assert.equal(rowCount, 2); + }); - assert.equal(await query(ecdb, "SELECT ECInstanceId,ECClassId,SourceECInstanceId,SourceECClassId,TargetECInstanceId,TargetECClassId FROM test.ParentHasChildren WHERE TargetECInstanceId=?", QueryBinder.from([childId]), undefined, (row: any) => { - assert.equal(row.id, childId); - assert.equal(row.className, "Test.ParentHasChildren"); - assert.equal(row.sourceId, parentId); - assert.equal(row.sourceClassName, "Test.Parent"); - assert.equal(row.targetId, childId); - assert.equal(row.targetClassName, "Test.Child"); - }), 1); + rowCount = 0; + assert.equal(await query(ecdb, "SELECT Name,Parent.Id,Parent.RelECClassId, Parent.Id myParentId, Parent.RelECClassId myParentRelClassId FROM test.Child ORDER BY Name", QueryBinder.from([]), undefined, (row: any) => { + rowCount++; + assert.equal(row.name, `Child ${rowCount}`); + assert.equal(row["parent.id"], parentId); + assert.equal(row["parent.relClassName"], "Test.ParentHasChildren"); + assert.equal(row.myParentId, parentId); + assert.isTrue(Id64.isValidId64(row.myParentRelClassId)); + }), 2); + + const childId: Id64String = childIds[0]; + ecdb.withPreparedStatement("SELECT ECInstanceId,ECClassId,SourceECInstanceId,SourceECClassId,TargetECInstanceId,TargetECClassId FROM test.ParentHasChildren WHERE TargetECInstanceId=?", (stmt: ECSqlStatement) => { + stmt.bindId(1, childId); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + const row = stmt.getRow(); + assert.equal(row.id, childId); + assert.equal(row.className, "Test.ParentHasChildren"); + assert.equal(row.sourceId, parentId); + assert.equal(row.sourceClassName, "Test.Parent"); + assert.equal(row.targetId, childId); + assert.equal(row.targetClassName, "Test.Child"); + }); - ecdb.withPreparedStatement("SELECT ECInstanceId as MyId,ECClassId as MyClassId,SourceECInstanceId As MySourceId,SourceECClassId As MySourceClassId,TargetECInstanceId As MyTargetId,TargetECClassId As MyTargetClassId FROM test.ParentHasChildren WHERE TargetECInstanceId=?", (stmt: ECSqlStatement) => { - stmt.bindId(1, childId); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - const row = stmt.getRow(); - assert.equal(row.myId, childId); - assert.isTrue(Id64.isValidId64(row.myClassId)); - assert.equal(row.mySourceId, parentId); - assert.isTrue(Id64.isValidId64(row.mySourceClassId)); - assert.equal(row.myTargetId, childId); - assert.isTrue(Id64.isValidId64(row.myTargetClassId)); - }); + assert.equal(await query(ecdb, "SELECT ECInstanceId,ECClassId,SourceECInstanceId,SourceECClassId,TargetECInstanceId,TargetECClassId FROM test.ParentHasChildren WHERE TargetECInstanceId=?", QueryBinder.from([childId]), undefined, (row: any) => { + assert.equal(row.id, childId); + assert.equal(row.className, "Test.ParentHasChildren"); + assert.equal(row.sourceId, parentId); + assert.equal(row.sourceClassName, "Test.Parent"); + assert.equal(row.targetId, childId); + assert.equal(row.targetClassName, "Test.Child"); + }), 1); + + ecdb.withPreparedStatement("SELECT ECInstanceId as MyId,ECClassId as MyClassId,SourceECInstanceId As MySourceId,SourceECClassId As MySourceClassId,TargetECInstanceId As MyTargetId,TargetECClassId As MyTargetClassId FROM test.ParentHasChildren WHERE TargetECInstanceId=?", (stmt: ECSqlStatement) => { + stmt.bindId(1, childId); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + const row = stmt.getRow(); + assert.equal(row.myId, childId); + assert.isTrue(Id64.isValidId64(row.myClassId)); + assert.equal(row.mySourceId, parentId); + assert.isTrue(Id64.isValidId64(row.mySourceClassId)); + assert.equal(row.myTargetId, childId); + assert.isTrue(Id64.isValidId64(row.myTargetClassId)); + }); - assert.equal(await query(ecdb, "SELECT ECInstanceId as MyId,ECClassId as MyClassId,SourceECInstanceId As MySourceId,SourceECClassId As MySourceClassId,TargetECInstanceId As MyTargetId,TargetECClassId As MyTargetClassId FROM test.ParentHasChildren WHERE TargetECInstanceId=?", QueryBinder.from([childId]), undefined, (row: any) => { - rowCount++; - assert.equal(row.myId, childId); - assert.isTrue(Id64.isValidId64(row.myClassId)); - assert.equal(row.mySourceId, parentId); - assert.isTrue(Id64.isValidId64(row.mySourceClassId)); - assert.equal(row.myTargetId, childId); - assert.isTrue(Id64.isValidId64(row.myTargetClassId)); - }), 1); + assert.equal(await query(ecdb, "SELECT ECInstanceId as MyId,ECClassId as MyClassId,SourceECInstanceId As MySourceId,SourceECClassId As MySourceClassId,TargetECInstanceId As MyTargetId,TargetECClassId As MyTargetClassId FROM test.ParentHasChildren WHERE TargetECInstanceId=?", QueryBinder.from([childId]), undefined, (row: any) => { + rowCount++; + assert.equal(row.myId, childId); + assert.isTrue(Id64.isValidId64(row.myClassId)); + assert.equal(row.mySourceId, parentId); + assert.isTrue(Id64.isValidId64(row.mySourceClassId)); + assert.equal(row.myTargetId, childId); + assert.isTrue(Id64.isValidId64(row.myTargetClassId)); + }), 1); - }); }); it("getRow() with structs", async () => { - await using(ECDbTestHelper.createECDb(outDir, "getstructs.ecdb", + using ecdb = ECDbTestHelper.createECDb(outDir, "getstructs.ecdb", ` @@ -2363,105 +2342,104 @@ describe("ECSqlStatement", () => { - `), async (ecdb) => { - assert.isTrue(ecdb.isOpen); - - const boolVal: boolean = true; - const doubleVal: number = 3.5; - const dtVal: string = "2018-01-23T12:24:00.000"; - const intVal: number = 3; - const p2dVal: XAndY = { x: 1, y: 2 }; - const p3dVal: XYAndZ = { x: 1, y: 2, z: 3 }; - const stringVal: string = "Hello World"; - - const id: Id64String = ecdb.withPreparedStatement("INSERT INTO test.Foo(Struct) VALUES(?)", (stmt: ECSqlStatement) => { - stmt.bindStruct(1, { bl: blobVal, bo: boolVal, d: doubleVal, dt: dtVal, i: intVal, p2d: p2dVal, p3d: p3dVal, s: stringVal }); - const res: ECSqlInsertResult = stmt.stepForInsert(); - assert.equal(res.status, DbResult.BE_SQLITE_DONE); - assert.isDefined(res.id); - return res.id!; - }); - - const expectedStruct = { bl: blobVal, bo: boolVal, d: doubleVal, dt: dtVal, i: intVal, p2d: p2dVal, p3d: p3dVal, s: stringVal }; - ecdb.withPreparedStatement("SELECT Struct FROM test.Foo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { - stmt.bindId(1, id); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - const row: any = stmt.getRow(); - assert.deepEqual(row.struct.bl, expectedStruct.bl); - assert.equal(row.struct.bo, expectedStruct.bo); - assert.equal(row.struct.d, expectedStruct.d); - assert.equal(row.struct.dt, expectedStruct.dt); - assert.equal(row.struct.i, expectedStruct.i); - assert.equal(row.struct.p2d.x, expectedStruct.p2d.x); - assert.equal(row.struct.p2d.y, expectedStruct.p2d.y); - assert.equal(row.struct.p3d.x, expectedStruct.p3d.x); - assert.equal(row.struct.p3d.y, expectedStruct.p3d.y); - assert.equal(row.struct.p3d.z, expectedStruct.p3d.z); - assert.equal(row.struct.s, expectedStruct.s); - }); - - assert.equal(await query(ecdb, "SELECT Struct FROM test.Foo WHERE ECInstanceId=?", QueryBinder.from([id]), undefined, (row: any) => { - assert.deepEqual(row.struct.bl, expectedStruct.bl); - assert.equal(row.struct.bo, expectedStruct.bo); - assert.equal(row.struct.d, expectedStruct.d); - assert.equal(row.struct.dt, expectedStruct.dt); - assert.equal(row.struct.i, expectedStruct.i); - assert.equal(row.struct.p2d.x, expectedStruct.p2d.x); - assert.equal(row.struct.p2d.y, expectedStruct.p2d.y); - assert.equal(row.struct.p3d.x, expectedStruct.p3d.x); - assert.equal(row.struct.p3d.y, expectedStruct.p3d.y); - assert.equal(row.struct.p3d.z, expectedStruct.p3d.z); - assert.equal(row.struct.s, expectedStruct.s); - }), 1); + `); + assert.isTrue(ecdb.isOpen); + + const boolVal: boolean = true; + const doubleVal: number = 3.5; + const dtVal: string = "2018-01-23T12:24:00.000"; + const intVal: number = 3; + const p2dVal: XAndY = { x: 1, y: 2 }; + const p3dVal: XYAndZ = { x: 1, y: 2, z: 3 }; + const stringVal: string = "Hello World"; + + const id: Id64String = ecdb.withPreparedStatement("INSERT INTO test.Foo(Struct) VALUES(?)", (stmt: ECSqlStatement) => { + stmt.bindStruct(1, { bl: blobVal, bo: boolVal, d: doubleVal, dt: dtVal, i: intVal, p2d: p2dVal, p3d: p3dVal, s: stringVal }); + const res: ECSqlInsertResult = stmt.stepForInsert(); + assert.equal(res.status, DbResult.BE_SQLITE_DONE); + assert.isDefined(res.id); + return res.id!; + }); - ecdb.withPreparedStatement("SELECT Struct FROM test.Foo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { - stmt.bindId(1, id); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - const actualStruct: any = stmt.getValue(0).getStruct(); - assert.deepEqual(actualStruct.bl, expectedStruct.bl); - assert.equal(actualStruct.bo, expectedStruct.bo); - assert.equal(actualStruct.d, expectedStruct.d); - assert.equal(actualStruct.dt, expectedStruct.dt); - assert.equal(actualStruct.i, expectedStruct.i); - assert.equal(actualStruct.p2d.x, expectedStruct.p2d.x); - assert.equal(actualStruct.p2d.y, expectedStruct.p2d.y); - assert.equal(actualStruct.p3d.x, expectedStruct.p3d.x); - assert.equal(actualStruct.p3d.y, expectedStruct.p3d.y); - assert.equal(actualStruct.p3d.z, expectedStruct.p3d.z); - assert.equal(actualStruct.s, expectedStruct.s); - }); + const expectedStruct = { bl: blobVal, bo: boolVal, d: doubleVal, dt: dtVal, i: intVal, p2d: p2dVal, p3d: p3dVal, s: stringVal }; + ecdb.withPreparedStatement("SELECT Struct FROM test.Foo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { + stmt.bindId(1, id); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + const row: any = stmt.getRow(); + assert.deepEqual(row.struct.bl, expectedStruct.bl); + assert.equal(row.struct.bo, expectedStruct.bo); + assert.equal(row.struct.d, expectedStruct.d); + assert.equal(row.struct.dt, expectedStruct.dt); + assert.equal(row.struct.i, expectedStruct.i); + assert.equal(row.struct.p2d.x, expectedStruct.p2d.x); + assert.equal(row.struct.p2d.y, expectedStruct.p2d.y); + assert.equal(row.struct.p3d.x, expectedStruct.p3d.x); + assert.equal(row.struct.p3d.y, expectedStruct.p3d.y); + assert.equal(row.struct.p3d.z, expectedStruct.p3d.z); + assert.equal(row.struct.s, expectedStruct.s); + }); - ecdb.withPreparedStatement("SELECT Struct.Bl, Struct.Bo, Struct.D, Struct.Dt, Struct.I, Struct.P2d, Struct.P3d, Struct.S FROM test.Foo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { - stmt.bindId(1, id); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - const row: any = stmt.getRow(); - assert.deepEqual(row["struct.Bl"], expectedStruct.bl); - assert.equal(row["struct.Bo"], expectedStruct.bo); - assert.equal(row["struct.D"], expectedStruct.d); - assert.equal(row["struct.Dt"], expectedStruct.dt); - assert.equal(row["struct.I"], expectedStruct.i); - assert.equal(row["struct.P2d"].x, expectedStruct.p2d.x); - assert.equal(row["struct.P2d"].y, expectedStruct.p2d.y); - assert.equal(row["struct.P3d"].x, expectedStruct.p3d.x); - assert.equal(row["struct.P3d"].y, expectedStruct.p3d.y); - assert.equal(row["struct.P3d"].z, expectedStruct.p3d.z); - assert.equal(row["struct.S"], expectedStruct.s); - }); + assert.equal(await query(ecdb, "SELECT Struct FROM test.Foo WHERE ECInstanceId=?", QueryBinder.from([id]), undefined, (row: any) => { + assert.deepEqual(row.struct.bl, expectedStruct.bl); + assert.equal(row.struct.bo, expectedStruct.bo); + assert.equal(row.struct.d, expectedStruct.d); + assert.equal(row.struct.dt, expectedStruct.dt); + assert.equal(row.struct.i, expectedStruct.i); + assert.equal(row.struct.p2d.x, expectedStruct.p2d.x); + assert.equal(row.struct.p2d.y, expectedStruct.p2d.y); + assert.equal(row.struct.p3d.x, expectedStruct.p3d.x); + assert.equal(row.struct.p3d.y, expectedStruct.p3d.y); + assert.equal(row.struct.p3d.z, expectedStruct.p3d.z); + assert.equal(row.struct.s, expectedStruct.s); + }), 1); + + ecdb.withPreparedStatement("SELECT Struct FROM test.Foo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { + stmt.bindId(1, id); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + const actualStruct: any = stmt.getValue(0).getStruct(); + assert.deepEqual(actualStruct.bl, expectedStruct.bl); + assert.equal(actualStruct.bo, expectedStruct.bo); + assert.equal(actualStruct.d, expectedStruct.d); + assert.equal(actualStruct.dt, expectedStruct.dt); + assert.equal(actualStruct.i, expectedStruct.i); + assert.equal(actualStruct.p2d.x, expectedStruct.p2d.x); + assert.equal(actualStruct.p2d.y, expectedStruct.p2d.y); + assert.equal(actualStruct.p3d.x, expectedStruct.p3d.x); + assert.equal(actualStruct.p3d.y, expectedStruct.p3d.y); + assert.equal(actualStruct.p3d.z, expectedStruct.p3d.z); + assert.equal(actualStruct.s, expectedStruct.s); + }); - assert.equal(await query(ecdb, "SELECT Struct.Bl, Struct.Bo, Struct.D, Struct.Dt, Struct.I, Struct.P2d, Struct.P3d, Struct.S FROM test.Foo WHERE ECInstanceId=?", QueryBinder.from([id]), undefined, (row: any) => { - assert.deepEqual(row["struct.Bl"], expectedStruct.bl); - assert.equal(row["struct.Bo"], expectedStruct.bo); - assert.equal(row["struct.D"], expectedStruct.d); - assert.equal(row["struct.Dt"], expectedStruct.dt); - assert.equal(row["struct.I"], expectedStruct.i); - assert.equal(row["struct.P2d"].x, expectedStruct.p2d.x); - assert.equal(row["struct.P2d"].y, expectedStruct.p2d.y); - assert.equal(row["struct.P3d"].x, expectedStruct.p3d.x); - assert.equal(row["struct.P3d"].y, expectedStruct.p3d.y); - assert.equal(row["struct.P3d"].z, expectedStruct.p3d.z); - assert.equal(row["struct.S"], expectedStruct.s); - }), 1); + ecdb.withPreparedStatement("SELECT Struct.Bl, Struct.Bo, Struct.D, Struct.Dt, Struct.I, Struct.P2d, Struct.P3d, Struct.S FROM test.Foo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { + stmt.bindId(1, id); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + const row: any = stmt.getRow(); + assert.deepEqual(row["struct.Bl"], expectedStruct.bl); + assert.equal(row["struct.Bo"], expectedStruct.bo); + assert.equal(row["struct.D"], expectedStruct.d); + assert.equal(row["struct.Dt"], expectedStruct.dt); + assert.equal(row["struct.I"], expectedStruct.i); + assert.equal(row["struct.P2d"].x, expectedStruct.p2d.x); + assert.equal(row["struct.P2d"].y, expectedStruct.p2d.y); + assert.equal(row["struct.P3d"].x, expectedStruct.p3d.x); + assert.equal(row["struct.P3d"].y, expectedStruct.p3d.y); + assert.equal(row["struct.P3d"].z, expectedStruct.p3d.z); + assert.equal(row["struct.S"], expectedStruct.s); }); + + assert.equal(await query(ecdb, "SELECT Struct.Bl, Struct.Bo, Struct.D, Struct.Dt, Struct.I, Struct.P2d, Struct.P3d, Struct.S FROM test.Foo WHERE ECInstanceId=?", QueryBinder.from([id]), undefined, (row: any) => { + assert.deepEqual(row["struct.Bl"], expectedStruct.bl); + assert.equal(row["struct.Bo"], expectedStruct.bo); + assert.equal(row["struct.D"], expectedStruct.d); + assert.equal(row["struct.Dt"], expectedStruct.dt); + assert.equal(row["struct.I"], expectedStruct.i); + assert.equal(row["struct.P2d"].x, expectedStruct.p2d.x); + assert.equal(row["struct.P2d"].y, expectedStruct.p2d.y); + assert.equal(row["struct.P3d"].x, expectedStruct.p3d.x); + assert.equal(row["struct.P3d"].y, expectedStruct.p3d.y); + assert.equal(row["struct.P3d"].z, expectedStruct.p3d.z); + assert.equal(row["struct.S"], expectedStruct.s); + }), 1); }); it("check HexStr() sql function", async () => { @@ -2473,7 +2451,7 @@ describe("ECSqlStatement", () => { slm.append().error().category("ECDb").message(/Failed to prepare function expression/gm); slm.append().error().category("ECDb").message(/Step failed for ECSQL/gm); - await using(ECDbTestHelper.createECDb(outDir, "hexstrfunction.ecdb", + using ecdb = ECDbTestHelper.createECDb(outDir, "hexstrfunction.ecdb", ` @@ -2487,85 +2465,84 @@ describe("ECSqlStatement", () => { - `), async (ecdb) => { - assert.isTrue(ecdb.isOpen); - - const expectedRow = { - bl: blobVal, bo: true, d: 3.5, dt: "2018-01-23T12:24:00.000", - i: 3, l: 12312312312312, p2d: { x: 1, y: 2 }, p3d: { x: 1, y: 2, z: 3 }, s: "Hello World", - }; - - const id: Id64String = ecdb.withPreparedStatement("INSERT INTO test.Foo(Bl,Bo,D,Dt,I,L,P2d,P3d,S) VALUES(:bl,:bo,:d,:dt,:i,:l,:p2d,:p3d,:s)", (stmt: ECSqlStatement) => { - stmt.bindValues({ - bl: blobVal, bo: expectedRow.bo, d: expectedRow.d, - dt: expectedRow.dt, i: expectedRow.i, l: expectedRow.l, p2d: expectedRow.p2d, p3d: expectedRow.p3d, s: expectedRow.s, - }); - const res: ECSqlInsertResult = stmt.stepForInsert(); - assert.equal(res.status, DbResult.BE_SQLITE_DONE); - assert.isDefined(res.id); - return res.id!; - }); + `); + assert.isTrue(ecdb.isOpen); + + const expectedRow = { + bl: blobVal, bo: true, d: 3.5, dt: "2018-01-23T12:24:00.000", + i: 3, l: 12312312312312, p2d: { x: 1, y: 2 }, p3d: { x: 1, y: 2, z: 3 }, s: "Hello World", + }; + + const id: Id64String = ecdb.withPreparedStatement("INSERT INTO test.Foo(Bl,Bo,D,Dt,I,L,P2d,P3d,S) VALUES(:bl,:bo,:d,:dt,:i,:l,:p2d,:p3d,:s)", (stmt: ECSqlStatement) => { + stmt.bindValues({ + bl: blobVal, bo: expectedRow.bo, d: expectedRow.d, + dt: expectedRow.dt, i: expectedRow.i, l: expectedRow.l, p2d: expectedRow.p2d, p3d: expectedRow.p3d, s: expectedRow.s, + }); + const res: ECSqlInsertResult = stmt.stepForInsert(); + assert.equal(res.status, DbResult.BE_SQLITE_DONE); + assert.isDefined(res.id); + return res.id!; + }); - ecdb.saveChanges(); - ecdb.withPreparedStatement("SELECT I, HexStr(I) hex FROM test.Foo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { - stmt.bindId(1, id); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - const row: any = stmt.getRow(); - assert.equal(row.i, expectedRow.i); - assert.equal(row.hex, "0x3"); - }); + ecdb.saveChanges(); + ecdb.withPreparedStatement("SELECT I, HexStr(I) hex FROM test.Foo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { + stmt.bindId(1, id); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + const row: any = stmt.getRow(); + assert.equal(row.i, expectedRow.i); + assert.equal(row.hex, "0x3"); + }); - ecdb.withPreparedStatement("SELECT L, HexStr(L) hex FROM test.Foo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { - stmt.bindId(1, id); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - const row: any = stmt.getRow(); - assert.equal(row.l, expectedRow.l); - assert.equal(row.hex, "0xb32af0071f8"); - }); + ecdb.withPreparedStatement("SELECT L, HexStr(L) hex FROM test.Foo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { + stmt.bindId(1, id); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + const row: any = stmt.getRow(); + assert.equal(row.l, expectedRow.l); + assert.equal(row.hex, "0xb32af0071f8"); + }); - ecdb.withPreparedStatement("SELECT Bl, HexStr(Bl) hex FROM test.Foo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { - stmt.bindId(1, id); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ERROR); - }); + ecdb.withPreparedStatement("SELECT Bl, HexStr(Bl) hex FROM test.Foo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { + stmt.bindId(1, id); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ERROR); + }); - ecdb.withPreparedStatement("SELECT Bo, HexStr(Bo) hex FROM test.Foo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { - stmt.bindId(1, id); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - const row: any = stmt.getRow(); - assert.equal(row.bo, expectedRow.bo); - assert.equal(row.hex, "0x1"); - }); + ecdb.withPreparedStatement("SELECT Bo, HexStr(Bo) hex FROM test.Foo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { + stmt.bindId(1, id); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + const row: any = stmt.getRow(); + assert.equal(row.bo, expectedRow.bo); + assert.equal(row.hex, "0x1"); + }); - ecdb.withPreparedStatement("SELECT D, HexStr(D) hex FROM test.Foo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { - stmt.bindId(1, id); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ERROR); - }); + ecdb.withPreparedStatement("SELECT D, HexStr(D) hex FROM test.Foo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { + stmt.bindId(1, id); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ERROR); + }); - ecdb.withPreparedStatement("SELECT Dt, HexStr(Dt) hex FROM test.Foo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { - stmt.bindId(1, id); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ERROR); - }); + ecdb.withPreparedStatement("SELECT Dt, HexStr(Dt) hex FROM test.Foo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { + stmt.bindId(1, id); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ERROR); + }); - // SQL functions cannot take points. So here preparation already fails - assert.throw(() => ecdb.withPreparedStatement("SELECT P2d, HexStr(P2d) hex FROM test.Foo WHERE ECInstanceId=?", () => { - assert.fail(); - })); + // SQL functions cannot take points. So here preparation already fails + assert.throw(() => ecdb.withPreparedStatement("SELECT P2d, HexStr(P2d) hex FROM test.Foo WHERE ECInstanceId=?", () => { + assert.fail(); + })); - // SQL functions cannot take points. So here preparation already fails - assert.throw(() => ecdb.withPreparedStatement("SELECT P3d, HexStr(P3d) hex FROM test.Foo WHERE ECInstanceId=?", () => { - assert.fail(); - })); + // SQL functions cannot take points. So here preparation already fails + assert.throw(() => ecdb.withPreparedStatement("SELECT P3d, HexStr(P3d) hex FROM test.Foo WHERE ECInstanceId=?", () => { + assert.fail(); + })); - ecdb.withPreparedStatement("SELECT S, HexStr(S) hex FROM test.Foo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { - stmt.bindId(1, id); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ERROR); - }); + ecdb.withPreparedStatement("SELECT S, HexStr(S) hex FROM test.Foo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { + stmt.bindId(1, id); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ERROR); }); assert.isTrue(slm.finishAndDispose()); }); it("check ec enums", async () => { - await using(ECDbTestHelper.createECDb(outDir, "ecenums.ecdb", + using ecdb = ECDbTestHelper.createECDb(outDir, "ecenums.ecdb", ` @@ -2581,96 +2558,95 @@ describe("ECSqlStatement", () => { - `), async (ecdb: ECDb) => { - assert.isTrue(ecdb.isOpen); - - const id: Id64String = ecdb.withPreparedStatement("INSERT INTO test.Foo(MyStat,MyStats,MyDomain,MyDomains) VALUES(test.Status.[On],?,test.Domain.Org,?)", (stmt: ECSqlStatement) => { - stmt.bindValue(1, [1, 2]); - stmt.bindValue(2, ["Org", "Com"]); - const res: ECSqlInsertResult = stmt.stepForInsert(); - assert.equal(res.status, DbResult.BE_SQLITE_DONE); - assert.isDefined(res.id); - return res.id!; - }); - - ecdb.withPreparedStatement("SELECT MyStat,MyStats, MyDomain,MyDomains FROM test.Foo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { - stmt.bindId(1, id); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - // getRow just returns the enum values - const row: any = stmt.getRow(); - assert.equal(row.myStat, 1); - assert.deepEqual(row.myStats, [1, 2]); - assert.equal(row.myDomain, "Org"); - assert.deepEqual(row.myDomains, ["Org", "Com"]); - - const myStatVal: ECSqlValue = stmt.getValue(0); - assert.isFalse(myStatVal.isNull); - assert.isTrue(myStatVal.columnInfo.isEnum()); - assert.equal(myStatVal.getInteger(), 1); - assert.deepEqual(myStatVal.getEnum(), [{ schema: "Test", name: "Status", key: "On", value: 1 }]); - - const myStatsVal: ECSqlValue = stmt.getValue(1); - assert.isFalse(myStatsVal.isNull); - assert.isTrue(myStatsVal.columnInfo.isEnum()); - assert.deepEqual(myStatsVal.getArray(), [1, 2]); - const actualStatsEnums: ECEnumValue[][] = []; - for (const arrayElement of myStatsVal.getArrayIterator()) { - actualStatsEnums.push(arrayElement.getEnum()!); - } - assert.equal(actualStatsEnums.length, 2); - assert.deepEqual(actualStatsEnums[0], [{ schema: "Test", name: "Status", key: "On", value: 1 }]); - assert.deepEqual(actualStatsEnums[1], [{ schema: "Test", name: "Status", key: "Off", value: 2 }]); - - const myDomainVal: ECSqlValue = stmt.getValue(2); - assert.isFalse(myDomainVal.isNull); - assert.isTrue(myDomainVal.columnInfo.isEnum()); - assert.equal(myDomainVal.getString(), "Org"); - assert.deepEqual(myDomainVal.getEnum(), [{ schema: "Test", name: "Domain", key: "Org", value: "Org" }]); - - const myDomainsVal: ECSqlValue = stmt.getValue(3); - assert.isFalse(myDomainsVal.isNull); - assert.isTrue(myDomainsVal.columnInfo.isEnum()); - assert.deepEqual(myDomainsVal.getArray(), ["Org", "Com"]); - const actualDomainsEnums: ECEnumValue[][] = []; - for (const arrayElement of myDomainsVal.getArrayIterator()) { - actualDomainsEnums.push(arrayElement.getEnum()!); - } - assert.equal(actualDomainsEnums.length, 2); - assert.deepEqual(actualDomainsEnums[0], [{ schema: "Test", name: "Domain", key: "Org", value: "Org" }]); - assert.deepEqual(actualDomainsEnums[1], [{ schema: "Test", name: "Domain", key: "Com", value: "Com" }]); - }); - - assert.equal(await query(ecdb, "SELECT MyStat,MyStats, MyDomain,MyDomains FROM test.Foo WHERE ECInstanceId=?", QueryBinder.from([id]), undefined, (row: any) => { - assert.equal(row.myStat, 1); - assert.deepEqual(row.myStats, [1, 2]); - assert.equal(row.myDomain, "Org"); - assert.deepEqual(row.myDomains, ["Org", "Com"]); - }), 1); + `); + assert.isTrue(ecdb.isOpen); + + const id: Id64String = ecdb.withPreparedStatement("INSERT INTO test.Foo(MyStat,MyStats,MyDomain,MyDomains) VALUES(test.Status.[On],?,test.Domain.Org,?)", (stmt: ECSqlStatement) => { + stmt.bindValue(1, [1, 2]); + stmt.bindValue(2, ["Org", "Com"]); + const res: ECSqlInsertResult = stmt.stepForInsert(); + assert.equal(res.status, DbResult.BE_SQLITE_DONE); + assert.isDefined(res.id); + return res.id!; + }); - // test some enums in the built-in schemas - ecdb.withPreparedStatement("SELECT Type,Modifier FROM meta.ECClassDef WHERE Name='Foo'", (stmt: ECSqlStatement) => { - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - // getRow just returns the enum values - const row: any = stmt.getRow(); - assert.deepEqual(row, { type: 0, modifier: 2 }); - - const typeVal: ECSqlValue = stmt.getValue(0); - assert.isFalse(typeVal.isNull); - assert.isTrue(typeVal.columnInfo.isEnum()); - assert.equal(typeVal.getInteger(), 0); - assert.deepEqual(typeVal.getEnum(), [{ schema: "ECDbMeta", name: "ECClassType", key: "Entity", value: 0 }]); - - const modifierVal: ECSqlValue = stmt.getValue(1); - assert.isFalse(modifierVal.isNull); - assert.isTrue(modifierVal.columnInfo.isEnum()); - assert.equal(modifierVal.getInteger(), 2); - assert.deepEqual(modifierVal.getEnum(), [{ schema: "ECDbMeta", name: "ECClassModifier", key: "Sealed", value: 2 }]); - }); + ecdb.withPreparedStatement("SELECT MyStat,MyStats, MyDomain,MyDomains FROM test.Foo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { + stmt.bindId(1, id); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + // getRow just returns the enum values + const row: any = stmt.getRow(); + assert.equal(row.myStat, 1); + assert.deepEqual(row.myStats, [1, 2]); + assert.equal(row.myDomain, "Org"); + assert.deepEqual(row.myDomains, ["Org", "Com"]); + + const myStatVal: ECSqlValue = stmt.getValue(0); + assert.isFalse(myStatVal.isNull); + assert.isTrue(myStatVal.columnInfo.isEnum()); + assert.equal(myStatVal.getInteger(), 1); + assert.deepEqual(myStatVal.getEnum(), [{ schema: "Test", name: "Status", key: "On", value: 1 }]); + + const myStatsVal: ECSqlValue = stmt.getValue(1); + assert.isFalse(myStatsVal.isNull); + assert.isTrue(myStatsVal.columnInfo.isEnum()); + assert.deepEqual(myStatsVal.getArray(), [1, 2]); + const actualStatsEnums: ECEnumValue[][] = []; + for (const arrayElement of myStatsVal.getArrayIterator()) { + actualStatsEnums.push(arrayElement.getEnum()!); + } + assert.equal(actualStatsEnums.length, 2); + assert.deepEqual(actualStatsEnums[0], [{ schema: "Test", name: "Status", key: "On", value: 1 }]); + assert.deepEqual(actualStatsEnums[1], [{ schema: "Test", name: "Status", key: "Off", value: 2 }]); + + const myDomainVal: ECSqlValue = stmt.getValue(2); + assert.isFalse(myDomainVal.isNull); + assert.isTrue(myDomainVal.columnInfo.isEnum()); + assert.equal(myDomainVal.getString(), "Org"); + assert.deepEqual(myDomainVal.getEnum(), [{ schema: "Test", name: "Domain", key: "Org", value: "Org" }]); + + const myDomainsVal: ECSqlValue = stmt.getValue(3); + assert.isFalse(myDomainsVal.isNull); + assert.isTrue(myDomainsVal.columnInfo.isEnum()); + assert.deepEqual(myDomainsVal.getArray(), ["Org", "Com"]); + const actualDomainsEnums: ECEnumValue[][] = []; + for (const arrayElement of myDomainsVal.getArrayIterator()) { + actualDomainsEnums.push(arrayElement.getEnum()!); + } + assert.equal(actualDomainsEnums.length, 2); + assert.deepEqual(actualDomainsEnums[0], [{ schema: "Test", name: "Domain", key: "Org", value: "Org" }]); + assert.deepEqual(actualDomainsEnums[1], [{ schema: "Test", name: "Domain", key: "Com", value: "Com" }]); + }); - assert.equal(await query(ecdb, "SELECT Type,Modifier FROM meta.ECClassDef WHERE Name='Foo'", QueryBinder.from([id]), undefined, (row: any) => { - assert.deepEqual(row, { type: 0, modifier: 2 }); - }), 1); + assert.equal(await query(ecdb, "SELECT MyStat,MyStats, MyDomain,MyDomains FROM test.Foo WHERE ECInstanceId=?", QueryBinder.from([id]), undefined, (row: any) => { + assert.equal(row.myStat, 1); + assert.deepEqual(row.myStats, [1, 2]); + assert.equal(row.myDomain, "Org"); + assert.deepEqual(row.myDomains, ["Org", "Com"]); + }), 1); + + // test some enums in the built-in schemas + ecdb.withPreparedStatement("SELECT Type,Modifier FROM meta.ECClassDef WHERE Name='Foo'", (stmt: ECSqlStatement) => { + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + // getRow just returns the enum values + const row: any = stmt.getRow(); + assert.deepEqual(row, { type: 0, modifier: 2 }); + + const typeVal: ECSqlValue = stmt.getValue(0); + assert.isFalse(typeVal.isNull); + assert.isTrue(typeVal.columnInfo.isEnum()); + assert.equal(typeVal.getInteger(), 0); + assert.deepEqual(typeVal.getEnum(), [{ schema: "ECDbMeta", name: "ECClassType", key: "Entity", value: 0 }]); + + const modifierVal: ECSqlValue = stmt.getValue(1); + assert.isFalse(modifierVal.isNull); + assert.isTrue(modifierVal.columnInfo.isEnum()); + assert.equal(modifierVal.getInteger(), 2); + assert.deepEqual(modifierVal.getEnum(), [{ schema: "ECDbMeta", name: "ECClassModifier", key: "Sealed", value: 2 }]); }); + + assert.equal(await query(ecdb, "SELECT Type,Modifier FROM meta.ECClassDef WHERE Name='Foo'", QueryBinder.from([id]), undefined, (row: any) => { + assert.deepEqual(row, { type: 0, modifier: 2 }); + }), 1); }); it("check ORed ECEnums", async () => { @@ -2678,7 +2654,7 @@ describe("ECSqlStatement", () => { slm.append().error().category("ECDb").message(/The value 9 cannot be broken down into a combination of ECEnumerators/gm); slm.append().error().category("ECDb").message(/The value 'gov,de' cannot be broken down into a combination of ECEnumerators/gm); - await using(ECDbTestHelper.createECDb(outDir, "oredecenums.ecdb", + using ecdb = ECDbTestHelper.createECDb(outDir, "oredecenums.ecdb", ` @@ -2694,209 +2670,206 @@ describe("ECSqlStatement", () => { - `), async (ecdb: ECDb) => { - assert.isTrue(ecdb.isOpen); - - const ids: { unored: Id64String, ored: Id64String, unmatched: Id64String } = ecdb.withPreparedStatement("INSERT INTO test.Foo(MyColor,MyDomain) VALUES(?,?)", (stmt: ECSqlStatement) => { - stmt.bindValue(1, 4); - stmt.bindValue(2, "com"); - let res: ECSqlInsertResult = stmt.stepForInsert(); - assert.equal(res.status, DbResult.BE_SQLITE_DONE); - assert.isDefined(res.id); - const unored: Id64String = res.id!; - stmt.reset(); - stmt.clearBindings(); - - stmt.bindValue(1, 5); - stmt.bindValue(2, "gov,com"); - res = stmt.stepForInsert(); - assert.equal(res.status, DbResult.BE_SQLITE_DONE); - assert.isDefined(res.id); - const ored: Id64String = res.id!; - stmt.reset(); - stmt.clearBindings(); - - stmt.bindValue(1, 9); - stmt.bindValue(2, "gov,de"); - res = stmt.stepForInsert(); - assert.equal(res.status, DbResult.BE_SQLITE_DONE); - assert.isDefined(res.id); - const unmatched: Id64String = res.id!; - stmt.reset(); - stmt.clearBindings(); - - return { unored, ored, unmatched }; - }); - - ecdb.withPreparedStatement("SELECT MyColor,MyDomain FROM test.Foo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { - stmt.bindId(1, ids.unored); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - // getRow just returns the enum values - let row: any = stmt.getRow(); - assert.equal(row.myColor, 4); - assert.equal(row.myDomain, "com"); - - let colVal: ECSqlValue = stmt.getValue(0); - assert.isFalse(colVal.isNull); - assert.isTrue(colVal.columnInfo.isEnum()); - assert.equal(colVal.getInteger(), 4); - assert.deepEqual(colVal.getEnum(), [{ schema: "Test", name: "Color", key: "Blue", value: 4 }]); - - let domainVal: ECSqlValue = stmt.getValue(1); - assert.isFalse(domainVal.isNull); - assert.isTrue(domainVal.columnInfo.isEnum()); - assert.equal(domainVal.getString(), "com"); - assert.deepEqual(domainVal.getEnum(), [{ schema: "Test", name: "Domain", key: "Com", value: "com" }]); - stmt.reset(); - stmt.clearBindings(); - - stmt.bindId(1, ids.ored); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - // getRow just returns the enum values - row = stmt.getRow(); - assert.equal(row.myColor, 5); - assert.equal(row.myDomain, "gov,com"); - - colVal = stmt.getValue(0); - assert.isFalse(colVal.isNull); - assert.isTrue(colVal.columnInfo.isEnum()); - assert.equal(colVal.getInteger(), 5); - assert.deepEqual(colVal.getEnum(), [{ schema: "Test", name: "Color", key: "Red", value: 1 }, { schema: "Test", name: "Color", key: "Blue", value: 4 }]); - - domainVal = stmt.getValue(1); - assert.isFalse(domainVal.isNull); - assert.isTrue(domainVal.columnInfo.isEnum()); - assert.equal(domainVal.getString(), "gov,com"); - assert.deepEqual(domainVal.getEnum(), [{ schema: "Test", name: "Domain", key: "Com", value: "com" }, { schema: "Test", name: "Domain", key: "Gov", value: "gov" }]); - - stmt.reset(); - stmt.clearBindings(); - - stmt.bindId(1, ids.unmatched); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - // getRow just returns the enum values - row = stmt.getRow(); - assert.equal(row.myColor, 9); - assert.equal(row.myDomain, "gov,de"); - - colVal = stmt.getValue(0); - assert.isFalse(colVal.isNull); - assert.isTrue(colVal.columnInfo.isEnum()); - assert.equal(colVal.getInteger(), 9); - assert.isUndefined(colVal.getEnum()); - - domainVal = stmt.getValue(1); - assert.isFalse(domainVal.isNull); - assert.isTrue(domainVal.columnInfo.isEnum()); - assert.equal(domainVal.getString(), "gov,de"); - assert.isUndefined(domainVal.getEnum()); - }); - - assert.equal(await query(ecdb, "SELECT MyColor,MyDomain FROM test.Foo WHERE ECInstanceId=?", QueryBinder.from([ids.unored]), undefined, (row: any) => { - assert.equal(row.myColor, 4); - assert.equal(row.myDomain, "com"); - }), 1); - - assert.equal(await query(ecdb, "SELECT MyColor,MyDomain FROM test.Foo WHERE ECInstanceId=?", QueryBinder.from([ids.ored]), undefined, (row: any) => { - assert.equal(row.myColor, 5); - assert.equal(row.myDomain, "gov,com"); - }), 1); + `); + assert.isTrue(ecdb.isOpen); + + const ids: { unored: Id64String, ored: Id64String, unmatched: Id64String } = ecdb.withPreparedStatement("INSERT INTO test.Foo(MyColor,MyDomain) VALUES(?,?)", (stmt: ECSqlStatement) => { + stmt.bindValue(1, 4); + stmt.bindValue(2, "com"); + let res: ECSqlInsertResult = stmt.stepForInsert(); + assert.equal(res.status, DbResult.BE_SQLITE_DONE); + assert.isDefined(res.id); + const unored: Id64String = res.id!; + stmt.reset(); + stmt.clearBindings(); + + stmt.bindValue(1, 5); + stmt.bindValue(2, "gov,com"); + res = stmt.stepForInsert(); + assert.equal(res.status, DbResult.BE_SQLITE_DONE); + assert.isDefined(res.id); + const ored: Id64String = res.id!; + stmt.reset(); + stmt.clearBindings(); + + stmt.bindValue(1, 9); + stmt.bindValue(2, "gov,de"); + res = stmt.stepForInsert(); + assert.equal(res.status, DbResult.BE_SQLITE_DONE); + assert.isDefined(res.id); + const unmatched: Id64String = res.id!; + stmt.reset(); + stmt.clearBindings(); + + return { unored, ored, unmatched }; + }); - assert.equal(await query(ecdb, "SELECT MyColor,MyDomain FROM test.Foo WHERE ECInstanceId=?", QueryBinder.from([ids.unmatched]), undefined, (row: any) => { - assert.equal(row.myColor, 9); - assert.equal(row.myDomain, "gov,de"); - }), 1); + ecdb.withPreparedStatement("SELECT MyColor,MyDomain FROM test.Foo WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { + stmt.bindId(1, ids.unored); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + // getRow just returns the enum values + let row: any = stmt.getRow(); + assert.equal(row.myColor, 4); + assert.equal(row.myDomain, "com"); + + let colVal: ECSqlValue = stmt.getValue(0); + assert.isFalse(colVal.isNull); + assert.isTrue(colVal.columnInfo.isEnum()); + assert.equal(colVal.getInteger(), 4); + assert.deepEqual(colVal.getEnum(), [{ schema: "Test", name: "Color", key: "Blue", value: 4 }]); + + let domainVal: ECSqlValue = stmt.getValue(1); + assert.isFalse(domainVal.isNull); + assert.isTrue(domainVal.columnInfo.isEnum()); + assert.equal(domainVal.getString(), "com"); + assert.deepEqual(domainVal.getEnum(), [{ schema: "Test", name: "Domain", key: "Com", value: "com" }]); + stmt.reset(); + stmt.clearBindings(); + + stmt.bindId(1, ids.ored); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + // getRow just returns the enum values + row = stmt.getRow(); + assert.equal(row.myColor, 5); + assert.equal(row.myDomain, "gov,com"); + + colVal = stmt.getValue(0); + assert.isFalse(colVal.isNull); + assert.isTrue(colVal.columnInfo.isEnum()); + assert.equal(colVal.getInteger(), 5); + assert.deepEqual(colVal.getEnum(), [{ schema: "Test", name: "Color", key: "Red", value: 1 }, { schema: "Test", name: "Color", key: "Blue", value: 4 }]); + + domainVal = stmt.getValue(1); + assert.isFalse(domainVal.isNull); + assert.isTrue(domainVal.columnInfo.isEnum()); + assert.equal(domainVal.getString(), "gov,com"); + assert.deepEqual(domainVal.getEnum(), [{ schema: "Test", name: "Domain", key: "Com", value: "com" }, { schema: "Test", name: "Domain", key: "Gov", value: "gov" }]); + + stmt.reset(); + stmt.clearBindings(); + + stmt.bindId(1, ids.unmatched); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + // getRow just returns the enum values + row = stmt.getRow(); + assert.equal(row.myColor, 9); + assert.equal(row.myDomain, "gov,de"); + + colVal = stmt.getValue(0); + assert.isFalse(colVal.isNull); + assert.isTrue(colVal.columnInfo.isEnum()); + assert.equal(colVal.getInteger(), 9); + assert.isUndefined(colVal.getEnum()); + + domainVal = stmt.getValue(1); + assert.isFalse(domainVal.isNull); + assert.isTrue(domainVal.columnInfo.isEnum()); + assert.equal(domainVal.getString(), "gov,de"); + assert.isUndefined(domainVal.getEnum()); + }); - // test some enums in the built-in schemas - ecdb.withPreparedStatement("SELECT CustomAttributeContainerType caType FROM meta.ECClassDef WHERE Type=meta.ECClassType.CustomAttribute AND Name='DateTimeInfo'", (stmt: ECSqlStatement) => { - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - const row: any = stmt.getRow(); - assert.equal(row.caType, 160); - - const caTypeVal: ECSqlValue = stmt.getValue(0); - assert.isFalse(caTypeVal.isNull); - assert.isTrue(caTypeVal.columnInfo.isEnum()); - assert.equal(caTypeVal.getInteger(), 160); - assert.deepEqual(caTypeVal.getEnum(), [ - { schema: "ECDbMeta", name: "ECCustomAttributeContainerType", key: "PrimitiveProperty", value: 32 }, - { schema: "ECDbMeta", name: "ECCustomAttributeContainerType", key: "PrimitiveArrayProperty", value: 128 }]); - }); - assert.equal(await query(ecdb, "SELECT CustomAttributeContainerType caType FROM meta.ECClassDef WHERE Type=meta.ECClassType.CustomAttribute AND Name='DateTimeInfo'", QueryBinder.from([ids.unmatched]), undefined, (row: any) => { - assert.equal(row.caType, 160); - }), 1); + assert.equal(await query(ecdb, "SELECT MyColor,MyDomain FROM test.Foo WHERE ECInstanceId=?", QueryBinder.from([ids.unored]), undefined, (row: any) => { + assert.equal(row.myColor, 4); + assert.equal(row.myDomain, "com"); + }), 1); + + assert.equal(await query(ecdb, "SELECT MyColor,MyDomain FROM test.Foo WHERE ECInstanceId=?", QueryBinder.from([ids.ored]), undefined, (row: any) => { + assert.equal(row.myColor, 5); + assert.equal(row.myDomain, "gov,com"); + }), 1); + + assert.equal(await query(ecdb, "SELECT MyColor,MyDomain FROM test.Foo WHERE ECInstanceId=?", QueryBinder.from([ids.unmatched]), undefined, (row: any) => { + assert.equal(row.myColor, 9); + assert.equal(row.myDomain, "gov,de"); + }), 1); + + // test some enums in the built-in schemas + ecdb.withPreparedStatement("SELECT CustomAttributeContainerType caType FROM meta.ECClassDef WHERE Type=meta.ECClassType.CustomAttribute AND Name='DateTimeInfo'", (stmt: ECSqlStatement) => { + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + const row: any = stmt.getRow(); + assert.equal(row.caType, 160); + + const caTypeVal: ECSqlValue = stmt.getValue(0); + assert.isFalse(caTypeVal.isNull); + assert.isTrue(caTypeVal.columnInfo.isEnum()); + assert.equal(caTypeVal.getInteger(), 160); + assert.deepEqual(caTypeVal.getEnum(), [ + { schema: "ECDbMeta", name: "ECCustomAttributeContainerType", key: "PrimitiveProperty", value: 32 }, + { schema: "ECDbMeta", name: "ECCustomAttributeContainerType", key: "PrimitiveArrayProperty", value: 128 }]); }); + assert.equal(await query(ecdb, "SELECT CustomAttributeContainerType caType FROM meta.ECClassDef WHERE Type=meta.ECClassType.CustomAttribute AND Name='DateTimeInfo'", QueryBinder.from([ids.unmatched]), undefined, (row: any) => { + assert.equal(row.caType, 160); + }), 1); assert.isTrue(slm.finishAndDispose()); }); it("should get native sql", async () => { - await using(ECDbTestHelper.createECDb(outDir, "asyncmethodtest.ecdb", + using ecdb = ECDbTestHelper.createECDb(outDir, "asyncmethodtest.ecdb", ` - `), async (ecdb: ECDb) => { - assert.isTrue(ecdb.isOpen); + `); + assert.isTrue(ecdb.isOpen); - const r = await ecdb.withPreparedStatement("INSERT INTO ts.Foo(n,dt,fooId) VALUES(20,TIMESTAMP '2018-10-18T12:00:00Z',20)", async (stmt: ECSqlStatement) => { - const nativesql: string = stmt.getNativeSql(); - assert.isTrue(nativesql.startsWith("INSERT INTO [ts_Foo]")); - return stmt.stepForInsert(); - }); - ecdb.saveChanges(); - assert.equal(r.status, DbResult.BE_SQLITE_DONE); - assert.equal(r.id, "0x1"); + const r = await ecdb.withPreparedStatement("INSERT INTO ts.Foo(n,dt,fooId) VALUES(20,TIMESTAMP '2018-10-18T12:00:00Z',20)", async (stmt: ECSqlStatement) => { + const nativesql: string = stmt.getNativeSql(); + assert.isTrue(nativesql.startsWith("INSERT INTO [ts_Foo]")); + return stmt.stepForInsert(); }); + ecdb.saveChanges(); + assert.equal(r.status, DbResult.BE_SQLITE_DONE); + assert.equal(r.id, "0x1"); }); it("check column info", async () => { - await using(ECDbTestHelper.createECDb(outDir, "columnInfo.ecdb", + using ecdb = ECDbTestHelper.createECDb(outDir, "columnInfo.ecdb", ` - `), async (ecdb: ECDb) => { - assert.isTrue(ecdb.isOpen); - - const id: Id64String = ecdb.withPreparedStatement("INSERT INTO test.MyClass(MyProperty) VALUES('Value')", (stmt: ECSqlStatement) => { - const res: ECSqlInsertResult = stmt.stepForInsert(); - assert.equal(res.status, DbResult.BE_SQLITE_DONE); - assert.isDefined(res.id); - return res.id!; - }); + `); + assert.isTrue(ecdb.isOpen); + + const id: Id64String = ecdb.withPreparedStatement("INSERT INTO test.MyClass(MyProperty) VALUES('Value')", (stmt: ECSqlStatement) => { + const res: ECSqlInsertResult = stmt.stepForInsert(); + assert.equal(res.status, DbResult.BE_SQLITE_DONE); + assert.isDefined(res.id); + return res.id!; + }); - ecdb.withPreparedStatement("SELECT MyProperty as MyAlias, 1 as MyGenerated FROM test.MyClass WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { - stmt.bindId(1, id); - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - // getRow just returns the enum values - const row: any = stmt.getRow(); - assert.equal(row.myAlias, "Value"); - assert.equal(row.myGenerated, 1); - - const val0: ECSqlValue = stmt.getValue(0); - const colInfo0: ECSqlColumnInfo = val0.columnInfo; - - assert.equal(colInfo0.getPropertyName(), "MyAlias"); - const accessString0 = colInfo0.getAccessString(); - assert.equal(accessString0, "MyAlias"); - const originPropertyName = colInfo0.getOriginPropertyName(); - assert.isDefined(originPropertyName); - assert.equal(originPropertyName, "MyProperty"); - - const val1: ECSqlValue = stmt.getValue(1); - const colInfo1: ECSqlColumnInfo = val1.columnInfo; - - assert.equal(colInfo1.getPropertyName(), "MyGenerated"); - const accessString1 = colInfo1.getAccessString(); - assert.equal(accessString1, "MyGenerated"); - assert.isUndefined(colInfo1.getOriginPropertyName()); - }); + ecdb.withPreparedStatement("SELECT MyProperty as MyAlias, 1 as MyGenerated FROM test.MyClass WHERE ECInstanceId=?", (stmt: ECSqlStatement) => { + stmt.bindId(1, id); + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + // getRow just returns the enum values + const row: any = stmt.getRow(); + assert.equal(row.myAlias, "Value"); + assert.equal(row.myGenerated, 1); + + const val0: ECSqlValue = stmt.getValue(0); + const colInfo0: ECSqlColumnInfo = val0.columnInfo; + + assert.equal(colInfo0.getPropertyName(), "MyAlias"); + const accessString0 = colInfo0.getAccessString(); + assert.equal(accessString0, "MyAlias"); + const originPropertyName = colInfo0.getOriginPropertyName(); + assert.isDefined(originPropertyName); + assert.equal(originPropertyName, "MyProperty"); + + const val1: ECSqlValue = stmt.getValue(1); + const colInfo1: ECSqlColumnInfo = val1.columnInfo; + + assert.equal(colInfo1.getPropertyName(), "MyGenerated"); + const accessString1 = colInfo1.getAccessString(); + assert.equal(accessString1, "MyGenerated"); + assert.isUndefined(colInfo1.getOriginPropertyName()); }); }); it("check access string metadata in nested struct", async () => { - await using(ECDbTestHelper.createECDb(outDir, "columnInfo.ecdb", + using ecdb = ECDbTestHelper.createECDb(outDir, "columnInfo.ecdb", ` @@ -2927,114 +2900,113 @@ describe("ECSqlStatement", () => { - `), async (ecdb: ECDb) => { - assert.isTrue(ecdb.isOpen); + `); + assert.isTrue(ecdb.isOpen); - ecdb.withPreparedStatement("INSERT INTO Test.A (f.c.a, f.c.b, f.d, g) VALUES ('f.c.a' ,'f.c.b', 'f.d', 'g')", (stmt: ECSqlStatement) => { - const res: ECSqlInsertResult = stmt.stepForInsert(); - assert.equal(res.status, DbResult.BE_SQLITE_DONE); - assert.isDefined(res.id); - }); + ecdb.withPreparedStatement("INSERT INTO Test.A (f.c.a, f.c.b, f.d, g) VALUES ('f.c.a' ,'f.c.b', 'f.d', 'g')", (stmt: ECSqlStatement) => { + const res: ECSqlInsertResult = stmt.stepForInsert(); + assert.equal(res.status, DbResult.BE_SQLITE_DONE); + assert.isDefined(res.id); + }); - ecdb.withPreparedStatement("SELECT f, f.c.a, f.c.b, f.d, g FROM Test.A", (stmt: ECSqlStatement) => { - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - // getRow just returns the enum values - const row: any = stmt.getRow(); - assert.equal(row.f.c.a, "f.c.a"); - assert.equal(row.f.c.b, "f.c.b"); - assert.equal(row.f.d, "f.d"); - assert.equal(row.g, "g"); - - const val0: ECSqlValue = stmt.getValue(0); - const colInfo0: ECSqlColumnInfo = val0.columnInfo; - - assert.equal(colInfo0.getPropertyName(), "f"); - const accessString0 = colInfo0.getAccessString(); - assert.equal(accessString0, "f"); - const originPropertyName0 = colInfo0.getOriginPropertyName(); - assert.isDefined(originPropertyName0); - assert.equal(originPropertyName0, "f"); - - const val1: ECSqlValue = stmt.getValue(1); - const colInfo1: ECSqlColumnInfo = val1.columnInfo; - - assert.equal(colInfo1.getPropertyName(), "a"); - const accessString1 = colInfo1.getAccessString(); - assert.equal(accessString1, "f.c.a"); - const originPropertyName1 = colInfo1.getOriginPropertyName(); - assert.isDefined(originPropertyName1); - assert.equal(originPropertyName1, "a"); - - const val2: ECSqlValue = stmt.getValue(2); - const colInfo2: ECSqlColumnInfo = val2.columnInfo; - - assert.equal(colInfo2.getPropertyName(), "b"); - const accessString2 = colInfo2.getAccessString(); - assert.equal(accessString2, "f.c.b"); - const originPropertyName2 = colInfo2.getOriginPropertyName(); - assert.isDefined(originPropertyName2); - assert.equal(originPropertyName2, "b"); - - const val3: ECSqlValue = stmt.getValue(3); - const colInfo3: ECSqlColumnInfo = val3.columnInfo; - - assert.equal(colInfo3.getPropertyName(), "d"); - const accessString3 = colInfo3.getAccessString(); - assert.equal(accessString3, "f.d"); - const originPropertyName3 = colInfo3.getOriginPropertyName(); - assert.isDefined(originPropertyName3); - assert.equal(originPropertyName3, "d"); - - const val4: ECSqlValue = stmt.getValue(4); - const colInfo4: ECSqlColumnInfo = val4.columnInfo; - - assert.equal(colInfo4.getPropertyName(), "g"); - const accessString4 = colInfo4.getAccessString(); - assert.equal(accessString4, "g"); - const originPropertyName4 = colInfo4.getOriginPropertyName(); - assert.isDefined(originPropertyName4); - assert.equal(originPropertyName4, "g"); - }); + ecdb.withPreparedStatement("SELECT f, f.c.a, f.c.b, f.d, g FROM Test.A", (stmt: ECSqlStatement) => { + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + // getRow just returns the enum values + const row: any = stmt.getRow(); + assert.equal(row.f.c.a, "f.c.a"); + assert.equal(row.f.c.b, "f.c.b"); + assert.equal(row.f.d, "f.d"); + assert.equal(row.g, "g"); + + const val0: ECSqlValue = stmt.getValue(0); + const colInfo0: ECSqlColumnInfo = val0.columnInfo; + + assert.equal(colInfo0.getPropertyName(), "f"); + const accessString0 = colInfo0.getAccessString(); + assert.equal(accessString0, "f"); + const originPropertyName0 = colInfo0.getOriginPropertyName(); + assert.isDefined(originPropertyName0); + assert.equal(originPropertyName0, "f"); + + const val1: ECSqlValue = stmt.getValue(1); + const colInfo1: ECSqlColumnInfo = val1.columnInfo; + + assert.equal(colInfo1.getPropertyName(), "a"); + const accessString1 = colInfo1.getAccessString(); + assert.equal(accessString1, "f.c.a"); + const originPropertyName1 = colInfo1.getOriginPropertyName(); + assert.isDefined(originPropertyName1); + assert.equal(originPropertyName1, "a"); + + const val2: ECSqlValue = stmt.getValue(2); + const colInfo2: ECSqlColumnInfo = val2.columnInfo; + + assert.equal(colInfo2.getPropertyName(), "b"); + const accessString2 = colInfo2.getAccessString(); + assert.equal(accessString2, "f.c.b"); + const originPropertyName2 = colInfo2.getOriginPropertyName(); + assert.isDefined(originPropertyName2); + assert.equal(originPropertyName2, "b"); + + const val3: ECSqlValue = stmt.getValue(3); + const colInfo3: ECSqlColumnInfo = val3.columnInfo; + + assert.equal(colInfo3.getPropertyName(), "d"); + const accessString3 = colInfo3.getAccessString(); + assert.equal(accessString3, "f.d"); + const originPropertyName3 = colInfo3.getOriginPropertyName(); + assert.isDefined(originPropertyName3); + assert.equal(originPropertyName3, "d"); + + const val4: ECSqlValue = stmt.getValue(4); + const colInfo4: ECSqlColumnInfo = val4.columnInfo; + + assert.equal(colInfo4.getPropertyName(), "g"); + const accessString4 = colInfo4.getAccessString(); + assert.equal(accessString4, "g"); + const originPropertyName4 = colInfo4.getOriginPropertyName(); + assert.isDefined(originPropertyName4); + assert.equal(originPropertyName4, "g"); + }); - ecdb.withPreparedStatement("INSERT INTO Test.B (h.a, h.b, i) VALUES ('h.a' ,'h.b', 'i')", (stmt: ECSqlStatement) => { - const res: ECSqlInsertResult = stmt.stepForInsert(); - assert.equal(res.status, DbResult.BE_SQLITE_DONE); - assert.isDefined(res.id); - }); + ecdb.withPreparedStatement("INSERT INTO Test.B (h.a, h.b, i) VALUES ('h.a' ,'h.b', 'i')", (stmt: ECSqlStatement) => { + const res: ECSqlInsertResult = stmt.stepForInsert(); + assert.equal(res.status, DbResult.BE_SQLITE_DONE); + assert.isDefined(res.id); + }); - ecdb.withPreparedStatement("SELECT h, i FROM Test.B", (stmt: ECSqlStatement) => { - assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); - // getRow just returns the enum values - const row: any = stmt.getRow(); - assert.equal(row.h.a, "h.a"); - assert.equal(row.h.b, "h.b"); - assert.equal(row.i, "i"); - - const val0: ECSqlValue = stmt.getValue(0); - const colInfo0: ECSqlColumnInfo = val0.columnInfo; - - assert.equal(colInfo0.getPropertyName(), "h"); - const accessString0 = colInfo0.getAccessString(); - assert.equal(accessString0, "h"); - const originPropertyName0 = colInfo0.getOriginPropertyName(); - assert.isDefined(originPropertyName0); - assert.equal(originPropertyName0, "h"); - - const val1: ECSqlValue = stmt.getValue(1); - const colInfo1: ECSqlColumnInfo = val1.columnInfo; - - assert.equal(colInfo1.getPropertyName(), "i"); - const accessString1 = colInfo1.getAccessString(); - assert.equal(accessString1, "i"); - const originPropertyName1 = colInfo1.getOriginPropertyName(); - assert.isDefined(originPropertyName1); - assert.equal(originPropertyName1, "i"); - }); + ecdb.withPreparedStatement("SELECT h, i FROM Test.B", (stmt: ECSqlStatement) => { + assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW); + // getRow just returns the enum values + const row: any = stmt.getRow(); + assert.equal(row.h.a, "h.a"); + assert.equal(row.h.b, "h.b"); + assert.equal(row.i, "i"); + + const val0: ECSqlValue = stmt.getValue(0); + const colInfo0: ECSqlColumnInfo = val0.columnInfo; + + assert.equal(colInfo0.getPropertyName(), "h"); + const accessString0 = colInfo0.getAccessString(); + assert.equal(accessString0, "h"); + const originPropertyName0 = colInfo0.getOriginPropertyName(); + assert.isDefined(originPropertyName0); + assert.equal(originPropertyName0, "h"); + + const val1: ECSqlValue = stmt.getValue(1); + const colInfo1: ECSqlColumnInfo = val1.columnInfo; + + assert.equal(colInfo1.getPropertyName(), "i"); + const accessString1 = colInfo1.getAccessString(); + assert.equal(accessString1, "i"); + const originPropertyName1 = colInfo1.getOriginPropertyName(); + assert.isDefined(originPropertyName1); + assert.equal(originPropertyName1, "i"); }); }); it("ecsql statements with QueryBinder", async () => { - await using(ECDbTestHelper.createECDb(outDir, "test.ecdb", + using ecdb = ECDbTestHelper.createECDb(outDir, "test.ecdb", ` @@ -3055,104 +3027,103 @@ describe("ECSqlStatement", () => { - `), async (ecdb: ECDb) => { - assert.isTrue(ecdb.isOpen); - - const booleanValue = true; - const blobValue = new Uint8Array([0, 0, 0]); - const doubleValue = 12.12; - const customIdValue = "1234"; - const customIdSetValue = ["0x9"]; - const intValue = 10; - const longValue = 1e9; - const stringValue = "test string value"; - const point2dValue = new Point2d(10, 20); - const point3dValue = new Point3d(15, 30, 45); - const structValue = { structClassProperty: "test string value for struct property" }; - - let r = await ecdb.withPreparedStatement( - `INSERT INTO ts.Foo(booleanProperty, blobProperty, doubleProperty, customIdProperty, customIdSetProperty, intProperty, longProperty, stringProperty, nullProperty, point2dProperty, point3dProperty) + `); + assert.isTrue(ecdb.isOpen); + + const booleanValue = true; + const blobValue = new Uint8Array([0, 0, 0]); + const doubleValue = 12.12; + const customIdValue = "1234"; + const customIdSetValue = ["0x9"]; + const intValue = 10; + const longValue = 1e9; + const stringValue = "test string value"; + const point2dValue = new Point2d(10, 20); + const point3dValue = new Point3d(15, 30, 45); + const structValue = { structClassProperty: "test string value for struct property" }; + + let r = await ecdb.withPreparedStatement( + `INSERT INTO ts.Foo(booleanProperty, blobProperty, doubleProperty, customIdProperty, customIdSetProperty, intProperty, longProperty, stringProperty, nullProperty, point2dProperty, point3dProperty) VALUES(:booleanValue, :blobValue, :doubleValue, :customIdValue, :customIdSetValue, :intValue, :longValue, :stringValue, :nullValue, :point2dValue, :point3dValue)`, - async (stmt: ECSqlStatement) => { - stmt.bindBoolean("booleanValue", booleanValue); - stmt.bindBlob("blobValue", blobValue); - stmt.bindDouble("doubleValue", doubleValue); - stmt.bindId("customIdValue", customIdValue); - stmt.bindId("customIdSetValue", customIdSetValue[0]); - stmt.bindInteger("intValue", intValue); - stmt.bindInteger("longValue", longValue); - stmt.bindString("stringValue", stringValue); - stmt.bindNull("nullValue"); - stmt.bindPoint2d("point2dValue", point2dValue); - stmt.bindPoint3d("point3dValue", point3dValue); - return stmt.stepForInsert(); - }, - ); - - ecdb.saveChanges(); - assert.equal(r.status, DbResult.BE_SQLITE_DONE); - assert.equal(r.id, "0x1"); - - const params = new QueryBinder(); - params.bindBoolean("booleanValue", booleanValue); - params.bindBlob("blobValue", blobValue); - params.bindDouble("doubleValue", doubleValue); - params.bindId("customIdValue", customIdValue); - params.bindInt("intValue", intValue); - params.bindLong("longValue", longValue); - params.bindString("stringValue", stringValue); - params.bindPoint2d("point2dValue", point2dValue); - params.bindPoint3d("point3dValue", point3dValue); - params.bindIdSet("customIdSetValue", customIdSetValue); - - let reader = ecdb.createQueryReader( - `SELECT booleanProperty, blobProperty, doubleProperty, customIdProperty, customIdSetProperty, intProperty, longProperty, stringProperty, nullProperty, point2dProperty, point3dProperty FROM ts.Foo + async (stmt: ECSqlStatement) => { + stmt.bindBoolean("booleanValue", booleanValue); + stmt.bindBlob("blobValue", blobValue); + stmt.bindDouble("doubleValue", doubleValue); + stmt.bindId("customIdValue", customIdValue); + stmt.bindId("customIdSetValue", customIdSetValue[0]); + stmt.bindInteger("intValue", intValue); + stmt.bindInteger("longValue", longValue); + stmt.bindString("stringValue", stringValue); + stmt.bindNull("nullValue"); + stmt.bindPoint2d("point2dValue", point2dValue); + stmt.bindPoint3d("point3dValue", point3dValue); + return stmt.stepForInsert(); + }, + ); + + ecdb.saveChanges(); + assert.equal(r.status, DbResult.BE_SQLITE_DONE); + assert.equal(r.id, "0x1"); + + const params = new QueryBinder(); + params.bindBoolean("booleanValue", booleanValue); + params.bindBlob("blobValue", blobValue); + params.bindDouble("doubleValue", doubleValue); + params.bindId("customIdValue", customIdValue); + params.bindInt("intValue", intValue); + params.bindLong("longValue", longValue); + params.bindString("stringValue", stringValue); + params.bindPoint2d("point2dValue", point2dValue); + params.bindPoint3d("point3dValue", point3dValue); + params.bindIdSet("customIdSetValue", customIdSetValue); + + let reader = ecdb.createQueryReader( + `SELECT booleanProperty, blobProperty, doubleProperty, customIdProperty, customIdSetProperty, intProperty, longProperty, stringProperty, nullProperty, point2dProperty, point3dProperty FROM ts.Foo WHERE booleanProperty = :booleanValue AND blobProperty = :blobValue AND doubleProperty = :doubleValue AND customIdProperty = :customIdValue AND InVirtualSet(:customIdSetValue, customIdSetProperty) AND intProperty = :intValue AND longProperty = :longValue AND stringProperty = :stringValue AND point2dProperty = :point2dValue AND point3dProperty = :point3dValue`, - params, - ); - const row = (await reader.toArray())[0]; - - assert.isNotNull(row); - assert.equal(row[0], booleanValue); - assert.deepEqual(row[1], blobValue); - assert.equal(row[2], doubleValue); - assert.equal(row[3], customIdValue); - assert.equal(row[4], "9"); - assert.equal(row[5], intValue); - assert.equal(row[6], longValue); - assert.equal(row[7], stringValue); - assert.equal(row[8], null); - assert.deepEqual(row[9], { X: 10, Y: 20 }); - assert.deepEqual(row[10], { X: 15, Y: 30, Z: 45 }); - - assert.isFalse(await reader.step()); - - r = await ecdb.withPreparedStatement( - "INSERT INTO ts.Baz(structProperty) VALUES(:structValue)", - async (stmt: ECSqlStatement) => { - stmt.bindStruct("structValue", structValue); - return stmt.stepForInsert(); - }, - ); - - ecdb.saveChanges(); - assert.equal(r.status, DbResult.BE_SQLITE_DONE); - assert.equal(r.id, "0x2"); + params, + ); + const row = (await reader.toArray())[0]; + + assert.isNotNull(row); + assert.equal(row[0], booleanValue); + assert.deepEqual(row[1], blobValue); + assert.equal(row[2], doubleValue); + assert.equal(row[3], customIdValue); + assert.equal(row[4], "9"); + assert.equal(row[5], intValue); + assert.equal(row[6], longValue); + assert.equal(row[7], stringValue); + assert.equal(row[8], null); + assert.deepEqual(row[9], { X: 10, Y: 20 }); + assert.deepEqual(row[10], { X: 15, Y: 30, Z: 45 }); + + assert.isFalse(await reader.step()); + + r = await ecdb.withPreparedStatement( + "INSERT INTO ts.Baz(structProperty) VALUES(:structValue)", + async (stmt: ECSqlStatement) => { + stmt.bindStruct("structValue", structValue); + return stmt.stepForInsert(); + }, + ); - reader = ecdb.createQueryReader( - `SELECT * FROM ts.Baz`, - ); + ecdb.saveChanges(); + assert.equal(r.status, DbResult.BE_SQLITE_DONE); + assert.equal(r.id, "0x2"); - await reader.step(); + reader = ecdb.createQueryReader( + `SELECT * FROM ts.Baz`, + ); - assert.deepEqual(reader.current.structProperty, structValue); + await reader.step(); - const paramsWithStruct = new QueryBinder(); - paramsWithStruct.bindStruct("structValue", structValue); - reader = ecdb.createQueryReader("SELECT * FROM ts.Baz WHERE structProperty = :structValue", paramsWithStruct); + assert.deepEqual(reader.current.structProperty, structValue); - await assert.isRejected(reader.toArray(), "Struct type binding not supported"); - }); + const paramsWithStruct = new QueryBinder(); + paramsWithStruct.bindStruct("structValue", structValue); + reader = ecdb.createQueryReader("SELECT * FROM ts.Baz WHERE structProperty = :structValue", paramsWithStruct); + + await assert.isRejected(reader.toArray(), "Struct type binding not supported"); }); }); diff --git a/core/backend/src/test/ecdb/SqliteStatement.test.ts b/core/backend/src/test/ecdb/SqliteStatement.test.ts index 767833d8cf74..79314cf5da39 100644 --- a/core/backend/src/test/ecdb/SqliteStatement.test.ts +++ b/core/backend/src/test/ecdb/SqliteStatement.test.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { assert } from "chai"; import * as path from "path"; -import { DbResult, using } from "@itwin/core-bentley"; +import { DbResult } from "@itwin/core-bentley"; import { Range3d } from "@itwin/core-geometry"; import { ECDb, ECDbOpenMode, SqliteStatement, SqliteValueType } from "../../core-backend"; import { KnownTestLocations } from "../KnownTestLocations"; @@ -19,426 +19,423 @@ describe("SqliteStatement", () => { const blobVal = new Uint8Array(new Range3d(1.2, 2.3, 3.4, 4.5, 5.6, 6.7).toFloat64Array().buffer); it("create table, insert, select with ecdb", () => { - using(ECDbTestHelper.createECDb(outDir, "sqlitestatement.ecdb"), (ecdb: ECDb) => { - assert.isTrue(ecdb.isOpen); - - ecdb.withSqliteStatement("CREATE TABLE MyTable(id INTEGER PRIMARY KEY, stringcol TEXT, intcol INTEGER, doublecol REAL, blobcol)", (stmt: SqliteStatement) => { - assert.isFalse(stmt.isReadonly); - assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE); - }); - - const stmt1 = "INSERT INTO MyTable(stringcol,intcol,doublecol,blobcol) VALUES(?,?,?,?)"; - ecdb.withPreparedSqliteStatement(stmt1, (stmt) => { - assert.isFalse(stmt.isReadonly); - stmt.bindValue(1, stringVal); - stmt.bindValue(2, intVal); - stmt.bindValue(3, doubleVal); - stmt.bindValue(4, blobVal); - assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE); - }); - - ecdb.withPreparedSqliteStatement(stmt1, (stmt) => { - stmt.maybeBindString(1, stringVal); - stmt.maybeBindInteger(2, intVal); - stmt.maybeBindDouble(3, doubleVal); - stmt.maybeBindBlob(4, blobVal); - assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE); - }); - - ecdb.withPreparedSqliteStatement(stmt1, (stmt) => { - assert.isFalse(stmt.isReadonly); - stmt.bindValues([stringVal, intVal, doubleVal, blobVal]); - assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE); - }); - - const stmt2 = "INSERT INTO MyTable(stringcol,intcol,doublecol,blobcol) VALUES(:string,:int,:double,:blob)"; - ecdb.withPreparedSqliteStatement(stmt2, (stmt: SqliteStatement) => { - assert.isFalse(stmt.isReadonly); - stmt.bindValue(":string", stringVal); - stmt.bindValue(":int", intVal); - stmt.bindValue(":double", doubleVal); - stmt.bindValue(":blob", blobVal); - assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE); - }); - - ecdb.withPreparedSqliteStatement(stmt2, (stmt: SqliteStatement) => { - assert.isFalse(stmt.isReadonly); - stmt.bindValues({ ":string": stringVal, ":int": intVal, ":double": doubleVal, ":blob": blobVal }); - assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE); - }); - - ecdb.saveChanges(); - - ecdb.withPreparedSqliteStatement("SELECT id,stringcol,intcol,doublecol,blobcol FROM MyTable", (stmt: SqliteStatement) => { - assert.isTrue(stmt.isReadonly); - let rowCount = 0; - while (stmt.step() === DbResult.BE_SQLITE_ROW) { - rowCount++; - assert.equal(stmt.getColumnCount(), 5); - const idSqlVal = stmt.getValue(0); - assert.isFalse(idSqlVal.isNull); - assert.equal(idSqlVal.type, SqliteValueType.Integer); - assert.isDefined(idSqlVal.value); - assert.equal(idSqlVal.value, rowCount); - assert.equal(idSqlVal.getInteger(), rowCount); - assert.equal(idSqlVal.columnName, "id"); - - const stringSqlVal = stmt.getValue(1); - assert.isFalse(stringSqlVal.isNull); - assert.equal(stringSqlVal.type, SqliteValueType.String); - assert.isDefined(stringSqlVal.value); - assert.equal(stringSqlVal.value, stringVal); - assert.equal(stringSqlVal.getString(), stringVal); - assert.equal(stringSqlVal.columnName, "stringcol"); - - const intSqlVal = stmt.getValue(2); - assert.isFalse(intSqlVal.isNull); - assert.equal(intSqlVal.type, SqliteValueType.Integer); - assert.isDefined(intSqlVal.value); - assert.equal(intSqlVal.value, intVal); - assert.equal(intSqlVal.getInteger(), intVal); - assert.equal(intSqlVal.columnName, "intcol"); - - const doubleSqlVal = stmt.getValue(3); - assert.isFalse(doubleSqlVal.isNull); - assert.equal(doubleSqlVal.type, SqliteValueType.Double); - assert.isDefined(doubleSqlVal.value); - assert.equal(doubleSqlVal.value, doubleVal); - assert.equal(doubleSqlVal.getDouble(), doubleVal); - assert.equal(doubleSqlVal.columnName, "doublecol"); - - const blobSqlVal = stmt.getValue(4); - assert.isFalse(blobSqlVal.isNull); - assert.equal(blobSqlVal.type, SqliteValueType.Blob); - assert.isDefined(blobSqlVal.value); - assert.equal((blobSqlVal.value as Uint8Array).byteLength, blobVal.byteLength); - assert.equal(blobSqlVal.getBlob().byteLength, blobVal.byteLength); - assert.equal(blobSqlVal.columnName, "blobcol"); - } - assert.equal(rowCount, 5); - }); + using ecdb = ECDbTestHelper.createECDb(outDir, "sqlitestatement.ecdb"); + assert.isTrue(ecdb.isOpen); - ecdb.withPreparedSqliteStatement("SELECT id,stringcol,intcol,doublecol,blobcol FROM MyTable", (stmt: SqliteStatement) => { - assert.isTrue(stmt.isReadonly); - let rowCount = 0; - while (stmt.step() === DbResult.BE_SQLITE_ROW) { - rowCount++; - const row = stmt.getRow(); - assert.isDefined(row.id); - assert.equal(row.id, rowCount); + ecdb.withSqliteStatement("CREATE TABLE MyTable(id INTEGER PRIMARY KEY, stringcol TEXT, intcol INTEGER, doublecol REAL, blobcol)", (stmt: SqliteStatement) => { + assert.isFalse(stmt.isReadonly); + assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE); + }); - assert.isDefined(row.stringcol); - assert.equal(row.stringcol, stringVal); + const stmt1 = "INSERT INTO MyTable(stringcol,intcol,doublecol,blobcol) VALUES(?,?,?,?)"; + ecdb.withPreparedSqliteStatement(stmt1, (stmt) => { + assert.isFalse(stmt.isReadonly); + stmt.bindValue(1, stringVal); + stmt.bindValue(2, intVal); + stmt.bindValue(3, doubleVal); + stmt.bindValue(4, blobVal); + assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE); + }); - assert.isDefined(row.intcol); - assert.equal(row.intcol, intVal); + ecdb.withPreparedSqliteStatement(stmt1, (stmt) => { + stmt.maybeBindString(1, stringVal); + stmt.maybeBindInteger(2, intVal); + stmt.maybeBindDouble(3, doubleVal); + stmt.maybeBindBlob(4, blobVal); + assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE); + }); - assert.isDefined(row.doublecol); - assert.equal(row.doublecol, doubleVal); + ecdb.withPreparedSqliteStatement(stmt1, (stmt) => { + assert.isFalse(stmt.isReadonly); + stmt.bindValues([stringVal, intVal, doubleVal, blobVal]); + assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE); + }); - assert.isDefined(row.blobcol); - assert.equal((row.blobcol as Uint8Array).byteLength, blobVal.byteLength); - } - assert.equal(rowCount, 5); - }); + const stmt2 = "INSERT INTO MyTable(stringcol,intcol,doublecol,blobcol) VALUES(:string,:int,:double,:blob)"; + ecdb.withPreparedSqliteStatement(stmt2, (stmt: SqliteStatement) => { + assert.isFalse(stmt.isReadonly); + stmt.bindValue(":string", stringVal); + stmt.bindValue(":int", intVal); + stmt.bindValue(":double", doubleVal); + stmt.bindValue(":blob", blobVal); + assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE); + }); - ecdb.withPreparedSqliteStatement("SELECT id,stringcol,intcol,doublecol,blobcol FROM MyTable", (stmt: SqliteStatement) => { - assert.isTrue(stmt.isReadonly); - let rowCount = 0; - for (const row of stmt) { - rowCount++; - assert.isDefined(row.id); - assert.equal(row.id, rowCount); + ecdb.withPreparedSqliteStatement(stmt2, (stmt: SqliteStatement) => { + assert.isFalse(stmt.isReadonly); + stmt.bindValues({ ":string": stringVal, ":int": intVal, ":double": doubleVal, ":blob": blobVal }); + assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE); + }); - assert.isDefined(row.stringcol); - assert.equal(row.stringcol, stringVal); + ecdb.saveChanges(); + + ecdb.withPreparedSqliteStatement("SELECT id,stringcol,intcol,doublecol,blobcol FROM MyTable", (stmt: SqliteStatement) => { + assert.isTrue(stmt.isReadonly); + let rowCount = 0; + while (stmt.step() === DbResult.BE_SQLITE_ROW) { + rowCount++; + assert.equal(stmt.getColumnCount(), 5); + const idSqlVal = stmt.getValue(0); + assert.isFalse(idSqlVal.isNull); + assert.equal(idSqlVal.type, SqliteValueType.Integer); + assert.isDefined(idSqlVal.value); + assert.equal(idSqlVal.value, rowCount); + assert.equal(idSqlVal.getInteger(), rowCount); + assert.equal(idSqlVal.columnName, "id"); + + const stringSqlVal = stmt.getValue(1); + assert.isFalse(stringSqlVal.isNull); + assert.equal(stringSqlVal.type, SqliteValueType.String); + assert.isDefined(stringSqlVal.value); + assert.equal(stringSqlVal.value, stringVal); + assert.equal(stringSqlVal.getString(), stringVal); + assert.equal(stringSqlVal.columnName, "stringcol"); + + const intSqlVal = stmt.getValue(2); + assert.isFalse(intSqlVal.isNull); + assert.equal(intSqlVal.type, SqliteValueType.Integer); + assert.isDefined(intSqlVal.value); + assert.equal(intSqlVal.value, intVal); + assert.equal(intSqlVal.getInteger(), intVal); + assert.equal(intSqlVal.columnName, "intcol"); + + const doubleSqlVal = stmt.getValue(3); + assert.isFalse(doubleSqlVal.isNull); + assert.equal(doubleSqlVal.type, SqliteValueType.Double); + assert.isDefined(doubleSqlVal.value); + assert.equal(doubleSqlVal.value, doubleVal); + assert.equal(doubleSqlVal.getDouble(), doubleVal); + assert.equal(doubleSqlVal.columnName, "doublecol"); + + const blobSqlVal = stmt.getValue(4); + assert.isFalse(blobSqlVal.isNull); + assert.equal(blobSqlVal.type, SqliteValueType.Blob); + assert.isDefined(blobSqlVal.value); + assert.equal((blobSqlVal.value as Uint8Array).byteLength, blobVal.byteLength); + assert.equal(blobSqlVal.getBlob().byteLength, blobVal.byteLength); + assert.equal(blobSqlVal.columnName, "blobcol"); + } + assert.equal(rowCount, 5); + }); - assert.isDefined(row.intcol); - assert.equal(row.intcol, intVal); + ecdb.withPreparedSqliteStatement("SELECT id,stringcol,intcol,doublecol,blobcol FROM MyTable", (stmt: SqliteStatement) => { + assert.isTrue(stmt.isReadonly); + let rowCount = 0; + while (stmt.step() === DbResult.BE_SQLITE_ROW) { + rowCount++; + const row = stmt.getRow(); + assert.isDefined(row.id); + assert.equal(row.id, rowCount); - assert.isDefined(row.doublecol); - assert.equal(row.doublecol, doubleVal); + assert.isDefined(row.stringcol); + assert.equal(row.stringcol, stringVal); - assert.isDefined(row.blobcol); - assert.equal((row.blobcol as Uint8Array).byteLength, blobVal.byteLength); - } - assert.equal(rowCount, 5); - }); + assert.isDefined(row.intcol); + assert.equal(row.intcol, intVal); + + assert.isDefined(row.doublecol); + assert.equal(row.doublecol, doubleVal); + + assert.isDefined(row.blobcol); + assert.equal((row.blobcol as Uint8Array).byteLength, blobVal.byteLength); + } + assert.equal(rowCount, 5); + }); + + ecdb.withPreparedSqliteStatement("SELECT id,stringcol,intcol,doublecol,blobcol FROM MyTable", (stmt: SqliteStatement) => { + assert.isTrue(stmt.isReadonly); + let rowCount = 0; + for (const row of stmt) { + rowCount++; + assert.isDefined(row.id); + assert.equal(row.id, rowCount); + + assert.isDefined(row.stringcol); + assert.equal(row.stringcol, stringVal); + + assert.isDefined(row.intcol); + assert.equal(row.intcol, intVal); + + assert.isDefined(row.doublecol); + assert.equal(row.doublecol, doubleVal); + + assert.isDefined(row.blobcol); + assert.equal((row.blobcol as Uint8Array).byteLength, blobVal.byteLength); + } + assert.equal(rowCount, 5); }); }); it("null values handling", () => { - using(ECDbTestHelper.createECDb(outDir, "bindnull.ecdb"), (ecdb: ECDb) => { - assert.isTrue(ecdb.isOpen); - - ecdb.withSqliteStatement("CREATE TABLE MyTable(id INTEGER PRIMARY KEY, stringcol TEXT, intcol INTEGER, doublecol REAL, blobcol)", (stmt: SqliteStatement) => { - assert.isFalse(stmt.isReadonly); - assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE); - }); - - ecdb.withPreparedSqliteStatement("INSERT INTO MyTable(stringcol,intcol,doublecol,blobcol) VALUES(?,?,?,?)", (stmt: SqliteStatement) => { - assert.isFalse(stmt.isReadonly); - stmt.bindValue(1, undefined); - stmt.bindValue(2, undefined); - stmt.bindValue(3, undefined); - stmt.bindValue(4, undefined); - assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE); - }); - - ecdb.withPreparedSqliteStatement("INSERT INTO MyTable(stringcol,intcol,doublecol,blobcol) VALUES(?,?,?,?)", (stmt: SqliteStatement) => { - assert.isFalse(stmt.isReadonly); - stmt.bindValues([]); - assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE); - }); - - ecdb.withPreparedSqliteStatement("INSERT INTO MyTable(stringcol,intcol,doublecol,blobcol) VALUES(?,?,?,?)", (stmt: SqliteStatement) => { - assert.isFalse(stmt.isReadonly); - stmt.bindValues([undefined, undefined]); - assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE); - }); - - ecdb.withPreparedSqliteStatement("INSERT INTO MyTable(stringcol,intcol,doublecol,blobcol) VALUES(:string,:int,:double,:blob)", (stmt: SqliteStatement) => { - assert.isFalse(stmt.isReadonly); - stmt.bindValue(":string", undefined); - stmt.bindValue(":int", undefined); - stmt.bindValue(":double", undefined); - stmt.bindValue(":blob", undefined); - assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE); - }); - - ecdb.withPreparedSqliteStatement("INSERT INTO MyTable(stringcol,intcol,doublecol,blobcol) VALUES(?,?,?,?)", (stmt: SqliteStatement) => { - assert.isFalse(stmt.isReadonly); - stmt.bindValues({}); - assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE); - }); - - ecdb.withPreparedSqliteStatement("INSERT INTO MyTable(stringcol,intcol,doublecol,blobcol) VALUES(?,?,?,?)", (stmt: SqliteStatement) => { - assert.isFalse(stmt.isReadonly); - stmt.bindValues({ ":string": undefined, ":int": undefined }); - assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE); - }); - - ecdb.withPreparedSqliteStatement("INSERT INTO MyTable(stringcol,intcol,doublecol,blobcol) VALUES(?,?,?,?)", (stmt: SqliteStatement) => { - stmt.maybeBindString(1, undefined); - stmt.maybeBindInteger(2, undefined); - stmt.maybeBindDouble(3, undefined); - stmt.maybeBindBlob(4, undefined); - assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE); - }); - - ecdb.saveChanges(); - - ecdb.withPreparedSqliteStatement("SELECT id,stringcol,intcol,doublecol,blobcol FROM MyTable", (stmt: SqliteStatement) => { - assert.isTrue(stmt.isReadonly); - let rowCount = 0; - while (stmt.step() === DbResult.BE_SQLITE_ROW) { - rowCount++; - for (let i = 0; i < stmt.getColumnCount(); i++) { - const sqlVal = stmt.getValue(i); - if (i === 0) { - assert.isFalse(sqlVal.isNull); - assert.equal(sqlVal.type, SqliteValueType.Integer); - assert.equal(sqlVal.getInteger(), rowCount); - } else { - assert.isTrue(sqlVal.isNull); - assert.equal(sqlVal.type, SqliteValueType.Null); - } + using ecdb = ECDbTestHelper.createECDb(outDir, "bindnull.ecdb"); + assert.isTrue(ecdb.isOpen); + + ecdb.withSqliteStatement("CREATE TABLE MyTable(id INTEGER PRIMARY KEY, stringcol TEXT, intcol INTEGER, doublecol REAL, blobcol)", (stmt: SqliteStatement) => { + assert.isFalse(stmt.isReadonly); + assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE); + }); + + ecdb.withPreparedSqliteStatement("INSERT INTO MyTable(stringcol,intcol,doublecol,blobcol) VALUES(?,?,?,?)", (stmt: SqliteStatement) => { + assert.isFalse(stmt.isReadonly); + stmt.bindValue(1, undefined); + stmt.bindValue(2, undefined); + stmt.bindValue(3, undefined); + stmt.bindValue(4, undefined); + assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE); + }); + + ecdb.withPreparedSqliteStatement("INSERT INTO MyTable(stringcol,intcol,doublecol,blobcol) VALUES(?,?,?,?)", (stmt: SqliteStatement) => { + assert.isFalse(stmt.isReadonly); + stmt.bindValues([]); + assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE); + }); + + ecdb.withPreparedSqliteStatement("INSERT INTO MyTable(stringcol,intcol,doublecol,blobcol) VALUES(?,?,?,?)", (stmt: SqliteStatement) => { + assert.isFalse(stmt.isReadonly); + stmt.bindValues([undefined, undefined]); + assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE); + }); + + ecdb.withPreparedSqliteStatement("INSERT INTO MyTable(stringcol,intcol,doublecol,blobcol) VALUES(:string,:int,:double,:blob)", (stmt: SqliteStatement) => { + assert.isFalse(stmt.isReadonly); + stmt.bindValue(":string", undefined); + stmt.bindValue(":int", undefined); + stmt.bindValue(":double", undefined); + stmt.bindValue(":blob", undefined); + assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE); + }); + + ecdb.withPreparedSqliteStatement("INSERT INTO MyTable(stringcol,intcol,doublecol,blobcol) VALUES(?,?,?,?)", (stmt: SqliteStatement) => { + assert.isFalse(stmt.isReadonly); + stmt.bindValues({}); + assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE); + }); + + ecdb.withPreparedSqliteStatement("INSERT INTO MyTable(stringcol,intcol,doublecol,blobcol) VALUES(?,?,?,?)", (stmt: SqliteStatement) => { + assert.isFalse(stmt.isReadonly); + stmt.bindValues({ ":string": undefined, ":int": undefined }); + assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE); + }); + + ecdb.withPreparedSqliteStatement("INSERT INTO MyTable(stringcol,intcol,doublecol,blobcol) VALUES(?,?,?,?)", (stmt: SqliteStatement) => { + stmt.maybeBindString(1, undefined); + stmt.maybeBindInteger(2, undefined); + stmt.maybeBindDouble(3, undefined); + stmt.maybeBindBlob(4, undefined); + assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE); + }); + + ecdb.saveChanges(); + + ecdb.withPreparedSqliteStatement("SELECT id,stringcol,intcol,doublecol,blobcol FROM MyTable", (stmt: SqliteStatement) => { + assert.isTrue(stmt.isReadonly); + let rowCount = 0; + while (stmt.step() === DbResult.BE_SQLITE_ROW) { + rowCount++; + for (let i = 0; i < stmt.getColumnCount(); i++) { + const sqlVal = stmt.getValue(i); + if (i === 0) { + assert.isFalse(sqlVal.isNull); + assert.equal(sqlVal.type, SqliteValueType.Integer); + assert.equal(sqlVal.getInteger(), rowCount); + } else { + assert.isTrue(sqlVal.isNull); + assert.equal(sqlVal.type, SqliteValueType.Null); } } + } - assert.equal(rowCount, 7); - }); + assert.equal(rowCount, 7); }); }); it("ids and guids", () => { - using(ECDbTestHelper.createECDb(outDir, "idsandguids.ecdb"), (ecdb: ECDb) => { - assert.isTrue(ecdb.isOpen); - - ecdb.withSqliteStatement("CREATE TABLE MyTable(id INTEGER PRIMARY KEY, guid BLOB)", (stmt: SqliteStatement) => { - assert.isFalse(stmt.isReadonly); - assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE); - }); - - ecdb.withSqliteStatement("INSERT INTO MyTable(id,guid) VALUES(?,?)", (stmt: SqliteStatement) => { - assert.isFalse(stmt.isReadonly); - stmt.bindValue(1, { id: "0x11" }); - stmt.bindValue(2, { guid: "370cea34-8415-4f81-b54c-85040eb3111e" }); - assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE); - stmt.reset(); - stmt.clearBindings(); - - stmt.bindValues([{ id: "0x12" }, { guid: "f9f1eb6e-1171-4f45-ba90-55c856056341" }]); - assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE); - stmt.reset(); - stmt.clearBindings(); - }); - - ecdb.withSqliteStatement("INSERT INTO MyTable(id,guid) VALUES(:id,:guid)", (stmt: SqliteStatement) => { - assert.isFalse(stmt.isReadonly); - stmt.bindValue(":id", { id: "0x13" }); - stmt.bindValue(":guid", { guid: "370cea34-8415-4f81-b54c-85040eb3111e" }); - assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE); - stmt.reset(); - stmt.clearBindings(); - - stmt.bindValues({ ":id": { id: "0x14" }, ":guid": { guid: "f9f1eb6e-1171-4f45-ba90-55c856056341" } }); - assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE); - stmt.reset(); - stmt.clearBindings(); - }); - - ecdb.withSqliteStatement("SELECT id,guid FROM MyTable", (stmt: SqliteStatement) => { - assert.isTrue(stmt.isReadonly); - let rowCount = 0; - while (stmt.step() === DbResult.BE_SQLITE_ROW) { - rowCount++; - const expectedId = rowCount + 16; - const idVal = stmt.getValue(0); - assert.equal(expectedId, idVal.getInteger()); - assert.equal(typeof (idVal.value), "number"); - assert.equal(expectedId, idVal.value); - assert.equal(expectedId, Number.parseInt(idVal.getId(), 16)); - - const guidVal = stmt.getValue(1); - assert.instanceOf(guidVal.value, Uint8Array); - - if (rowCount % 2 !== 0) - assert.equal("370cea34-8415-4f81-b54c-85040eb3111e", guidVal.getGuid()); - else - assert.equal("f9f1eb6e-1171-4f45-ba90-55c856056341", guidVal.getGuid()); - - const row = stmt.getRow(); - assert.isDefined(row.id); - assert.equal(typeof (row.id), "number"); - assert.equal(expectedId, row.id); - - assert.isDefined(row.guid); - assert.instanceOf(row.guid, Uint8Array); - } - assert.equal(4, rowCount); - }); - ecdb.saveChanges(); + using ecdb = ECDbTestHelper.createECDb(outDir, "idsandguids.ecdb"); + assert.isTrue(ecdb.isOpen); + + ecdb.withSqliteStatement("CREATE TABLE MyTable(id INTEGER PRIMARY KEY, guid BLOB)", (stmt: SqliteStatement) => { + assert.isFalse(stmt.isReadonly); + assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE); }); + + ecdb.withSqliteStatement("INSERT INTO MyTable(id,guid) VALUES(?,?)", (stmt: SqliteStatement) => { + assert.isFalse(stmt.isReadonly); + stmt.bindValue(1, { id: "0x11" }); + stmt.bindValue(2, { guid: "370cea34-8415-4f81-b54c-85040eb3111e" }); + assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE); + stmt.reset(); + stmt.clearBindings(); + + stmt.bindValues([{ id: "0x12" }, { guid: "f9f1eb6e-1171-4f45-ba90-55c856056341" }]); + assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE); + stmt.reset(); + stmt.clearBindings(); + }); + + ecdb.withSqliteStatement("INSERT INTO MyTable(id,guid) VALUES(:id,:guid)", (stmt: SqliteStatement) => { + assert.isFalse(stmt.isReadonly); + stmt.bindValue(":id", { id: "0x13" }); + stmt.bindValue(":guid", { guid: "370cea34-8415-4f81-b54c-85040eb3111e" }); + assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE); + stmt.reset(); + stmt.clearBindings(); + + stmt.bindValues({ ":id": { id: "0x14" }, ":guid": { guid: "f9f1eb6e-1171-4f45-ba90-55c856056341" } }); + assert.equal(stmt.step(), DbResult.BE_SQLITE_DONE); + stmt.reset(); + stmt.clearBindings(); + }); + + ecdb.withSqliteStatement("SELECT id,guid FROM MyTable", (stmt: SqliteStatement) => { + assert.isTrue(stmt.isReadonly); + let rowCount = 0; + while (stmt.step() === DbResult.BE_SQLITE_ROW) { + rowCount++; + const expectedId = rowCount + 16; + const idVal = stmt.getValue(0); + assert.equal(expectedId, idVal.getInteger()); + assert.equal(typeof (idVal.value), "number"); + assert.equal(expectedId, idVal.value); + assert.equal(expectedId, Number.parseInt(idVal.getId(), 16)); + + const guidVal = stmt.getValue(1); + assert.instanceOf(guidVal.value, Uint8Array); + + if (rowCount % 2 !== 0) + assert.equal("370cea34-8415-4f81-b54c-85040eb3111e", guidVal.getGuid()); + else + assert.equal("f9f1eb6e-1171-4f45-ba90-55c856056341", guidVal.getGuid()); + + const row = stmt.getRow(); + assert.isDefined(row.id); + assert.equal(typeof (row.id), "number"); + assert.equal(expectedId, row.id); + + assert.isDefined(row.guid); + assert.instanceOf(row.guid, Uint8Array); + } + assert.equal(4, rowCount); + }); + ecdb.saveChanges(); }); it("run cached sql", () => { const fileName = "sqlitesqlagainstreadonlyconnection.ecdb"; const ecdbPath = path.join(outDir, fileName); - using(ECDbTestHelper.createECDb(outDir, fileName), (ecdb: ECDb) => { - assert.isTrue(ecdb.isOpen); - }); - - using(new ECDb(), (ecdb: ECDb) => { - ecdb.openDb(ecdbPath, ECDbOpenMode.Readonly); - assert.isTrue(ecdb.isOpen); - - let stmt0: SqliteStatement | undefined; - ecdb.withPreparedSqliteStatement("SELECT Name,StrData FROM be_Prop WHERE Namespace='ec_Db'", (stmt: SqliteStatement) => { - stmt0 = stmt; - let rowCount = 0; - while (stmt.step() === DbResult.BE_SQLITE_ROW) { - rowCount++; - assert.equal(stmt.getColumnCount(), 2); - const nameVal = stmt.getValue(0); - assert.equal(nameVal.columnName, "Name"); - assert.equal(nameVal.type, SqliteValueType.String); - assert.isFalse(nameVal.isNull); - const name = nameVal.getString(); - - const versionVal = stmt.getValue(1); - assert.equal(versionVal.columnName, "StrData"); - assert.equal(versionVal.type, SqliteValueType.String); - assert.isFalse(versionVal.isNull); - const profileVersion: any = JSON.parse(versionVal.getString()); - - assert.isTrue(name === "SchemaVersion" || name === "InitialSchemaVersion"); - if (name === "SchemaVersion") { - assert.equal(profileVersion.major, 4); - assert.equal(profileVersion.minor, 0); - assert.equal(profileVersion.sub1, 0); - assert.isAtLeast(profileVersion.sub2, 1); - } else if (name === "InitialSchemaVersion") { - assert.equal(profileVersion.major, 4); - assert.equal(profileVersion.minor, 0); - assert.equal(profileVersion.sub1, 0); - assert.isAtLeast(profileVersion.sub2, 1); - } + { + using testEcdb = ECDbTestHelper.createECDb(outDir, fileName); + assert.isTrue(testEcdb.isOpen); + } + + using ecdb = new ECDb(); + ecdb.openDb(ecdbPath, ECDbOpenMode.Readonly); + assert.isTrue(ecdb.isOpen); + + let stmt0: SqliteStatement | undefined; + ecdb.withPreparedSqliteStatement("SELECT Name,StrData FROM be_Prop WHERE Namespace='ec_Db'", (stmt: SqliteStatement) => { + stmt0 = stmt; + let rowCount = 0; + while (stmt.step() === DbResult.BE_SQLITE_ROW) { + rowCount++; + assert.equal(stmt.getColumnCount(), 2); + const nameVal = stmt.getValue(0); + assert.equal(nameVal.columnName, "Name"); + assert.equal(nameVal.type, SqliteValueType.String); + assert.isFalse(nameVal.isNull); + const name = nameVal.getString(); + + const versionVal = stmt.getValue(1); + assert.equal(versionVal.columnName, "StrData"); + assert.equal(versionVal.type, SqliteValueType.String); + assert.isFalse(versionVal.isNull); + const profileVersion: any = JSON.parse(versionVal.getString()); + + assert.isTrue(name === "SchemaVersion" || name === "InitialSchemaVersion"); + if (name === "SchemaVersion") { + assert.equal(profileVersion.major, 4); + assert.equal(profileVersion.minor, 0); + assert.equal(profileVersion.sub1, 0); + assert.isAtLeast(profileVersion.sub2, 1); + } else if (name === "InitialSchemaVersion") { + assert.equal(profileVersion.major, 4); + assert.equal(profileVersion.minor, 0); + assert.equal(profileVersion.sub1, 0); + assert.isAtLeast(profileVersion.sub2, 1); } - assert.equal(rowCount, 2); - }); - assert.isTrue(stmt0?.isPrepared, "stmt0 is in the cache"); - - ecdb.resetSqliteCache(3); // reset the statement cache to only hold 3 members so we can exercise overflowing it - assert.isFalse(stmt0?.isPrepared, "reset cache clears stmt0"); - - let stmt1: SqliteStatement | undefined; - let stmt2: SqliteStatement | undefined; - let stmt2a: SqliteStatement | undefined; - let stmt3: SqliteStatement | undefined; - let stmt4: SqliteStatement | undefined; - let stmt5: SqliteStatement | undefined; - ecdb.withPreparedSqliteStatement("SELECT 1", (stmt) => stmt1 = stmt); - assert.isTrue(stmt1?.isPrepared, "stmt1 is in the cache"); - ecdb.withPreparedSqliteStatement("SELECT 2", (stmt) => stmt2 = stmt); - assert.isTrue(stmt2?.isPrepared, "stmt2 is in the cache"); - ecdb.withPreparedSqliteStatement("SELECT 3", (stmt) => stmt3 = stmt); - assert.isTrue(stmt3?.isPrepared, "stmt3 is in the cache"); - ecdb.withPreparedSqliteStatement("SELECT 4", (stmt) => stmt4 = stmt); - assert.isTrue(stmt4?.isPrepared, "stmt4 is in the cache"); - assert.isFalse(stmt1?.isPrepared, "stmt1 was cleared from the cache"); - ecdb.withPreparedSqliteStatement("SELECT 2", (stmt) => stmt2a = stmt); - assert.equal(stmt2, stmt2a, "statement 2 gets reused, moved to most recent"); - assert.isTrue(stmt3?.isPrepared, "statement 3 is still cached"); - ecdb.withPreparedSqliteStatement("SELECT 5", (stmt) => stmt5 = stmt); - assert.isTrue(stmt5?.isPrepared, "statement 5 is cached"); - assert.isFalse(stmt3?.isPrepared, "statement 3 was lru and was dropped"); - - let nested1: SqliteStatement | undefined; - ecdb.withPreparedSqliteStatement("SELECT 1", (stmt) => { - stmt1 = stmt; - ecdb.withPreparedSqliteStatement("SELECT 1", (nested) => nested1 = nested); - }); - assert.notEqual(stmt1, nested1, "shouldn't reuse an in-use statement"); - assert.isFalse(stmt1?.isPrepared, "outer 1 is not cached"); - assert.isTrue(nested1?.isPrepared, "nested1 is cached"); - assert.isTrue(stmt2?.isPrepared, "stmt2 is in the cache"); - assert.isTrue(stmt5?.isPrepared, "stmt5 is in the cache"); + } + assert.equal(rowCount, 2); }); + assert.isTrue(stmt0?.isPrepared, "stmt0 is in the cache"); + + ecdb.resetSqliteCache(3); // reset the statement cache to only hold 3 members so we can exercise overflowing it + assert.isFalse(stmt0?.isPrepared, "reset cache clears stmt0"); + + let stmt1: SqliteStatement | undefined; + let stmt2: SqliteStatement | undefined; + let stmt2a: SqliteStatement | undefined; + let stmt3: SqliteStatement | undefined; + let stmt4: SqliteStatement | undefined; + let stmt5: SqliteStatement | undefined; + ecdb.withPreparedSqliteStatement("SELECT 1", (stmt) => stmt1 = stmt); + assert.isTrue(stmt1?.isPrepared, "stmt1 is in the cache"); + ecdb.withPreparedSqliteStatement("SELECT 2", (stmt) => stmt2 = stmt); + assert.isTrue(stmt2?.isPrepared, "stmt2 is in the cache"); + ecdb.withPreparedSqliteStatement("SELECT 3", (stmt) => stmt3 = stmt); + assert.isTrue(stmt3?.isPrepared, "stmt3 is in the cache"); + ecdb.withPreparedSqliteStatement("SELECT 4", (stmt) => stmt4 = stmt); + assert.isTrue(stmt4?.isPrepared, "stmt4 is in the cache"); + assert.isFalse(stmt1?.isPrepared, "stmt1 was cleared from the cache"); + ecdb.withPreparedSqliteStatement("SELECT 2", (stmt) => stmt2a = stmt); + assert.equal(stmt2, stmt2a, "statement 2 gets reused, moved to most recent"); + assert.isTrue(stmt3?.isPrepared, "statement 3 is still cached"); + ecdb.withPreparedSqliteStatement("SELECT 5", (stmt) => stmt5 = stmt); + assert.isTrue(stmt5?.isPrepared, "statement 5 is cached"); + assert.isFalse(stmt3?.isPrepared, "statement 3 was lru and was dropped"); + + let nested1: SqliteStatement | undefined; + ecdb.withPreparedSqliteStatement("SELECT 1", (stmt) => { + stmt1 = stmt; + ecdb.withPreparedSqliteStatement("SELECT 1", (nested) => nested1 = nested); + }); + assert.notEqual(stmt1, nested1, "shouldn't reuse an in-use statement"); + assert.isFalse(stmt1?.isPrepared, "outer 1 is not cached"); + assert.isTrue(nested1?.isPrepared, "nested1 is cached"); + assert.isTrue(stmt2?.isPrepared, "stmt2 is in the cache"); + assert.isTrue(stmt5?.isPrepared, "stmt5 is in the cache"); }); // This test generate no log when run as suite but is successful when only this fixture run. it("check prepare logErrors flag", () => { const fileName = "logErrors.ecdb"; const ecdbPath = path.join(outDir, fileName); - using(ECDbTestHelper.createECDb(outDir, fileName), (ecdb: ECDb) => { - assert.isTrue(ecdb.isOpen); - }); - using(new ECDb(), (ecdb: ECDb) => { - ecdb.openDb(ecdbPath, ECDbOpenMode.Readonly); - assert.isTrue(ecdb.isOpen); - // expect log message when statement fails - let slm = new SequentialLogMatcher(); - slm.append().error().category("BeSQLite").message("Error \"no such table: def (BE_SQLITE_ERROR)\" preparing SQL: SELECT abc FROM def"); - assert.throw(() => ecdb.withSqliteStatement("SELECT abc FROM def", () => { }), "no such table: def (BE_SQLITE_ERROR)"); - assert.isTrue(slm.finishAndDispose(), "logMatcher should detect log"); - - // now pass suppress log error which mean we should not get the error - slm = new SequentialLogMatcher(); - slm.append().error().category("BeSQLite").message("Error \"no such table: def (BE_SQLITE_ERROR)\" preparing SQL: SELECT abc FROM def"); - assert.throw(() => ecdb.withSqliteStatement("SELECT abc FROM def", () => { }, /* logErrors = */ false), "no such table: def (BE_SQLITE_ERROR)"); - assert.isFalse(slm.finishAndDispose(), "logMatcher should not detect log"); - - // expect log message when statement fails - slm = new SequentialLogMatcher(); - slm.append().error().category("ECDb").message("ECClass 'abc.def' does not exist or could not be loaded."); - assert.throw(() => ecdb.withPreparedStatement("SELECT abc FROM abc.def", () => { }), "ECClass 'abc.def' does not exist or could not be loaded."); - assert.isTrue(slm.finishAndDispose(), "logMatcher should detect log"); - - // now pass suppress log error which mean we should not get the error - slm = new SequentialLogMatcher(); - slm.append().error().category("ECDb").message("ECClass 'abc.def' does not exist or could not be loaded."); - assert.throw(() => ecdb.withPreparedStatement("SELECT abc FROM abc.def", () => { }, /* logErrors = */ false), ""); // BUG: we do not see error message - assert.isFalse(slm.finishAndDispose(), "logMatcher should not detect log"); - }); + { + using testEcdb = ECDbTestHelper.createECDb(outDir, fileName); + assert.isTrue(testEcdb.isOpen); + } + using ecdb = new ECDb(); + ecdb.openDb(ecdbPath, ECDbOpenMode.Readonly); + assert.isTrue(ecdb.isOpen); + // expect log message when statement fails + let slm = new SequentialLogMatcher(); + slm.append().error().category("BeSQLite").message("Error \"no such table: def (BE_SQLITE_ERROR)\" preparing SQL: SELECT abc FROM def"); + assert.throw(() => ecdb.withSqliteStatement("SELECT abc FROM def", () => { }), "no such table: def (BE_SQLITE_ERROR)"); + assert.isTrue(slm.finishAndDispose(), "logMatcher should detect log"); + + // now pass suppress log error which mean we should not get the error + slm = new SequentialLogMatcher(); + slm.append().error().category("BeSQLite").message("Error \"no such table: def (BE_SQLITE_ERROR)\" preparing SQL: SELECT abc FROM def"); + assert.throw(() => ecdb.withSqliteStatement("SELECT abc FROM def", () => { }, /* logErrors = */ false), "no such table: def (BE_SQLITE_ERROR)"); + assert.isFalse(slm.finishAndDispose(), "logMatcher should not detect log"); + + // expect log message when statement fails + slm = new SequentialLogMatcher(); + slm.append().error().category("ECDb").message("ECClass 'abc.def' does not exist or could not be loaded."); + assert.throw(() => ecdb.withPreparedStatement("SELECT abc FROM abc.def", () => { }), "ECClass 'abc.def' does not exist or could not be loaded."); + assert.isTrue(slm.finishAndDispose(), "logMatcher should detect log"); + + // now pass suppress log error which mean we should not get the error + slm = new SequentialLogMatcher(); + slm.append().error().category("ECDb").message("ECClass 'abc.def' does not exist or could not be loaded."); + assert.throw(() => ecdb.withPreparedStatement("SELECT abc FROM abc.def", () => { }, /* logErrors = */ false), ""); // BUG: we do not see error message + assert.isFalse(slm.finishAndDispose(), "logMatcher should not detect log"); }); }); diff --git a/core/backend/src/test/imodel/IModel.test.ts b/core/backend/src/test/imodel/IModel.test.ts index 7df8d44cff86..140ff3ff015b 100644 --- a/core/backend/src/test/imodel/IModel.test.ts +++ b/core/backend/src/test/imodel/IModel.test.ts @@ -6,7 +6,7 @@ import { assert, expect } from "chai"; import * as path from "path"; import * as semver from "semver"; import * as sinon from "sinon"; -import { DbResult, Guid, GuidString, Id64, Id64String, Logger, OpenMode, ProcessDetector, using } from "@itwin/core-bentley"; +import { DbResult, Guid, GuidString, Id64, Id64String, Logger, OpenMode, ProcessDetector } from "@itwin/core-bentley"; import { AxisAlignedBox3d, BisCodeSpec, BriefcaseIdValue, ChangesetIdWithIndex, Code, CodeScopeSpec, CodeSpec, ColorByName, ColorDef, DefinitionElementProps, DisplayStyleProps, DisplayStyleSettings, DisplayStyleSettingsProps, EcefLocation, ElementProps, EntityMetaData, EntityProps, FilePropertyProps, @@ -699,25 +699,24 @@ describe("iModel", () => { }); it("should throw on invalid tile requests", async () => { - await using(new DisableNativeAssertions(), async (_r) => { - let error = await getIModelError(imodel1.tiles.requestTileTreeProps("0x12345")); - expectIModelError(IModelStatus.InvalidId, error); + using _r = new DisableNativeAssertions(); + let error = await getIModelError(imodel1.tiles.requestTileTreeProps("0x12345")); + expectIModelError(IModelStatus.InvalidId, error); - error = await getIModelError(imodel1.tiles.requestTileTreeProps("NotAValidId")); - expectIModelError(IModelStatus.InvalidId, error); + error = await getIModelError(imodel1.tiles.requestTileTreeProps("NotAValidId")); + expectIModelError(IModelStatus.InvalidId, error); - error = await getIModelError(imodel1.tiles.requestTileContent("0x1c", "0/0/0/0")); - expectIModelError(IModelStatus.InvalidId, error); + error = await getIModelError(imodel1.tiles.requestTileContent("0x1c", "0/0/0/0")); + expectIModelError(IModelStatus.InvalidId, error); - error = await getIModelError(imodel1.tiles.requestTileContent("0x12345", "0/0/0/0/1")); - expectIModelError(IModelStatus.InvalidId, error); + error = await getIModelError(imodel1.tiles.requestTileContent("0x12345", "0/0/0/0/1")); + expectIModelError(IModelStatus.InvalidId, error); - error = await getIModelError(imodel1.tiles.requestTileContent("0x1c", "V/W/X/Y/Z")); - expectIModelError(IModelStatus.InvalidId, error); + error = await getIModelError(imodel1.tiles.requestTileContent("0x1c", "V/W/X/Y/Z")); + expectIModelError(IModelStatus.InvalidId, error); - error = await getIModelError(imodel1.tiles.requestTileContent("0x1c", "NotAValidId")); - expectIModelError(IModelStatus.InvalidId, error); - }); + error = await getIModelError(imodel1.tiles.requestTileContent("0x1c", "NotAValidId")); + expectIModelError(IModelStatus.InvalidId, error); }); // NOTE: this test can be removed when the deprecated executeQuery method is removed @@ -2536,10 +2535,9 @@ describe("iModel", () => { const invalidSql = "SELECT * FROM InvalidSchemaName:InvalidClassName LIMIT 1"; assert.throws(() => imodel1.prepareStatement(invalidSql, false)); assert.isUndefined(imodel1.tryPrepareStatement(invalidSql)); - const statement: ECSqlStatement | undefined = imodel1.tryPrepareStatement(sql); + using statement: ECSqlStatement | undefined = imodel1.tryPrepareStatement(sql); assert.isDefined(statement); assert.isTrue(statement?.isPrepared); - statement!.dispose(); }); it("containsClass", () => { diff --git a/core/backend/src/test/standalone/ChangesetReader.test.ts b/core/backend/src/test/standalone/ChangesetReader.test.ts index cbab0c0291c7..3dad684bd3b6 100644 --- a/core/backend/src/test/standalone/ChangesetReader.test.ts +++ b/core/backend/src/test/standalone/ChangesetReader.test.ts @@ -259,7 +259,7 @@ describe("Changeset Reader API", async () => { if (true || "test local changes") { const reader = SqliteChangesetReader.openLocalChanges({ db: rwIModel, disableSchemaCheck: true }); - const adaptor = new ECChangesetAdaptor(reader); + using adaptor = new ECChangesetAdaptor(reader); const cci = new PartialECChangeUnifier(); while (adaptor.step()) { cci.appendFrom(adaptor); @@ -327,7 +327,6 @@ describe("Changeset Reader API", async () => { stage: "New", fallbackClassId: undefined, }); - adaptor.dispose(); } const targetDir = path.join(KnownTestLocations.outputDir, rwIModelId, "changesets"); await rwIModel.pushChanges({ description: "schema changeset", accessToken: adminToken }); @@ -396,7 +395,7 @@ describe("Changeset Reader API", async () => { } if (true || "test changeset file") { const reader = SqliteChangesetReader.openFile({ fileName: changesets[2].pathname, db: rwIModel, disableSchemaCheck: true }); - const adaptor = new ECChangesetAdaptor(reader); + using adaptor = new ECChangesetAdaptor(reader); const cci = new PartialECChangeUnifier(); while (adaptor.step()) { cci.appendFrom(adaptor); @@ -464,11 +463,10 @@ describe("Changeset Reader API", async () => { stage: "New", fallbackClassId: undefined, }); - adaptor.dispose(); } if (true || "test ChangesetAdaptor.acceptClass()") { const reader = SqliteChangesetReader.openFile({ fileName: changesets[2].pathname, db: rwIModel, disableSchemaCheck: true }); - const adaptor = new ECChangesetAdaptor(reader); + using adaptor = new ECChangesetAdaptor(reader); adaptor.acceptClass("TestDomain.Test2dElement"); const cci = new PartialECChangeUnifier(); while (adaptor.step()) { @@ -477,11 +475,10 @@ describe("Changeset Reader API", async () => { const changes = Array.from(cci.instances); assert.equal(changes.length, 1); assert.equal(changes[0].$meta?.classFullName, "TestDomain:Test2dElement"); - adaptor.dispose(); } if (true || "test ChangesetAdaptor.adaptor()") { const reader = SqliteChangesetReader.openFile({ fileName: changesets[2].pathname, db: rwIModel, disableSchemaCheck: true }); - const adaptor = new ECChangesetAdaptor(reader); + using adaptor = new ECChangesetAdaptor(reader); adaptor.acceptOp("Updated"); const cci = new PartialECChangeUnifier(); while (adaptor.step()) { @@ -497,7 +494,6 @@ describe("Changeset Reader API", async () => { assert.equal(changes[1].$meta?.classFullName, "BisCore:DrawingModel"); assert.equal(changes[1].$meta?.op, "Updated"); assert.equal(changes[1].$meta?.stage, "Old"); - adaptor.dispose(); } rwIModel.close(); }); diff --git a/core/backend/src/test/standalone/TxnManager.test.ts b/core/backend/src/test/standalone/TxnManager.test.ts index ccc26a719748..fe1163b5551e 100644 --- a/core/backend/src/test/standalone/TxnManager.test.ts +++ b/core/backend/src/test/standalone/TxnManager.test.ts @@ -338,7 +338,7 @@ describe("TxnManager", () => { })); } - public dispose(): void { + public [Symbol.dispose](): void { for (const cleanup of this._cleanup) cleanup(); @@ -346,10 +346,9 @@ describe("TxnManager", () => { } public static test(txns: TxnManager, event: BeEvent<(changes: TxnChangedEntities) => void>, func: (accum: EventAccumulator) => void): void { - const accum = new EventAccumulator(txns); + using accum = new EventAccumulator(txns); accum.listen(event); func(accum); - accum.dispose(); } public static testElements(iModel: StandaloneDb, func: (accum: EventAccumulator) => void): void { diff --git a/core/bentley/package.json b/core/bentley/package.json index f499d5f7a479..617fa5ebfdf1 100644 --- a/core/bentley/package.json +++ b/core/bentley/package.json @@ -37,7 +37,7 @@ "@itwin/build-tools": "workspace:*", "@itwin/eslint-plugin": "5.0.0-dev.1", "@opentelemetry/api": "1.0.4", - "@types/node": "~20.9.5", + "@types/node": "~20.17.0", "@vitest/coverage-v8": "^2.1.0", "eslint": "^9.13.0", "rimraf": "^3.0.2", @@ -47,4 +47,4 @@ "nyc": { "extends": "./node_modules/@itwin/build-tools/.nycrc" } -} +} \ No newline at end of file diff --git a/core/bentley/src/Disposable.ts b/core/bentley/src/Disposable.ts index cd4e1363de81..b04379976d13 100644 --- a/core/bentley/src/Disposable.ts +++ b/core/bentley/src/Disposable.ts @@ -6,6 +6,10 @@ * @module Utils */ +/* eslint-disable @typescript-eslint/no-deprecated */ +(Symbol as any).dispose ??= Symbol("Symbol.dispose"); +(Symbol as any).asyncDispose ??= Symbol("Symbol.asyncDispose"); + /** Interface adopted by a type which has deterministic cleanup logic. * For example: * - Most rendering-related types, such as [[RenderGraphic]] and [[Viewport]], own WebGL resources which must be explicitly released when no longer needed. @@ -19,6 +23,7 @@ * * Implementations of IDisposable tend to be more "low-level" types. The disposal of such types is often handled on your behalf. * However, always consult the documentation for an IDisposable type to determine under what circumstances you are expected to explicitly dispose of it. + * @deprecated in 5.0 Use builtin Disposable type instead. * @public */ export interface IDisposable { @@ -30,12 +35,21 @@ export interface IDisposable { /** * A type guard that checks whether the given argument implements `IDisposable` interface + * @deprecated in 5.0 Use isDisposable instead. * @public */ export function isIDisposable(obj: unknown): obj is IDisposable { return !!obj && (obj instanceof Object) && !!(obj as IDisposable).dispose && (typeof (obj as IDisposable).dispose === "function"); } +/** + * A type guard that checks whether the given argument implements `Disposable` interface + * @public + */ +export function isDisposable(obj: unknown): obj is Disposable { + return !!obj && (obj instanceof Object) && !!(obj as Disposable)[Symbol.dispose] && (typeof (obj as Disposable)[Symbol.dispose] === "function"); +} + /** Convenience function for disposing of a disposable object that may be undefined. * This is primarily used to simplify implementations of [[IDisposable.dispose]]. * As a simple example: @@ -54,9 +68,19 @@ export function isIDisposable(obj: unknown): obj is IDisposable { * @returns undefined * @public */ -export function dispose(disposable?: IDisposable): undefined { - if (undefined !== disposable) - disposable.dispose(); +export function dispose(disposable?: Disposable): undefined; +/** + * @deprecated in 5.0 Use builtin Disposable type instead. + * @public + */ +export function dispose(disposable?: IDisposable): undefined; // eslint-disable-line @typescript-eslint/unified-signatures +export function dispose(disposable?: Disposable | IDisposable): undefined { + if (undefined !== disposable) { + if (Symbol.dispose in disposable) + disposable[Symbol.dispose](); + else + disposable.dispose(); + } return undefined; } @@ -65,12 +89,22 @@ export function dispose(disposable?: IDisposable): undefined { * @returns undefined * @public */ -export function disposeArray(list?: IDisposable[]): undefined { +export function disposeArray(list?: Disposable[]): undefined; +/** + * @deprecated in 5.0 Use builtin Disposable type instead. + * @public + */ +export function disposeArray(list?: IDisposable[]): undefined; // eslint-disable-line @typescript-eslint/unified-signatures +export function disposeArray(list?: Disposable[] | IDisposable[]): undefined { if (undefined === list) return undefined; - for (const entry of list) - dispose(entry); + for (const entry of list) { + if (Symbol.dispose in entry) + entry[Symbol.dispose](); + else + entry.dispose(); + } list.length = 0; return undefined; @@ -81,6 +115,7 @@ export function disposeArray(list?: IDisposable[]): undefined { * of this function is equal to return value of func. If func throws, this function also throws (after * disposing the resource). * @public + * @deprecated in 5.0 Use `using` declarations instead. */ export function using(resources: T | T[], func: (...r: T[]) => TResult): TResult { if (!Array.isArray(resources)) diff --git a/core/bentley/src/Logger.ts b/core/bentley/src/Logger.ts index 02bc5fb8598f..0ed7b9890151 100644 --- a/core/bentley/src/Logger.ts +++ b/core/bentley/src/Logger.ts @@ -9,7 +9,6 @@ import { BeEvent } from "./BeEvent"; import { BentleyError, IModelStatus, LoggingMetaData } from "./BentleyError"; import { BentleyLoggerCategory } from "./BentleyLoggerCategory"; -import { IDisposable } from "./Disposable"; import { staticLoggerMetadata } from "./internal/staticLoggerMetadata"; /** Defines the *signature* for a log function. @@ -71,13 +70,13 @@ export class Logger { return Logger._onLogLevelChanged; } - private static _categoryFilter: {[categoryName: string]: LogLevel | undefined} = {}; + private static _categoryFilter: { [categoryName: string]: LogLevel | undefined } = {}; /** Maps category names to the least severe level at which messages in that category should be displayed, * or `undefined` if a minimum has not been defined. * @see [[setLevel]] to change the minimum logging level for a category. */ - public static get categoryFilter(): Readonly<{[categoryName: string]: LogLevel | undefined}> { + public static get categoryFilter(): Readonly<{ [categoryName: string]: LogLevel | undefined }> { // NOTE: this property is accessed by native code. return this._categoryFilter; } @@ -263,7 +262,7 @@ export class Logger { */ public static logException(category: string, err: any, log: LogFunction = (_category, message, metaData) => Logger.logError(_category, message, metaData)): void { log(category, Logger.getExceptionMessage(err), () => { - return { ...BentleyError.getErrorMetadata(err), exceptionType: err?.constructor?.name ?? ""}; + return { ...BentleyError.getErrorMetadata(err), exceptionType: err?.constructor?.name ?? "" }; }); } @@ -307,7 +306,7 @@ export class Logger { * Enable those, if you want to capture timings. * @public */ -export class PerfLogger implements IDisposable { +export class PerfLogger implements Disposable { private static _severity: LogLevel = LogLevel.Info; private _operation: string; @@ -340,8 +339,13 @@ export class PerfLogger implements IDisposable { }); } - public dispose(): void { + public [Symbol.dispose](): void { this.logMessage(); } + + /** @deprecated in 5.0 Use [Symbol.dispose] instead. */ + public dispose(): void { + this[Symbol.dispose](); + } } diff --git a/core/bentley/src/test/Disposable.test.ts b/core/bentley/src/test/Disposable.test.ts index 9e40f7ec4881..66c66371b0cd 100644 --- a/core/bentley/src/test/Disposable.test.ts +++ b/core/bentley/src/test/Disposable.test.ts @@ -6,6 +6,7 @@ import { assert, describe, it } from "vitest"; import { DisposableList, IDisposable, using } from "../core-bentley"; import { isIDisposable } from "../Disposable"; +/* eslint-disable @typescript-eslint/no-deprecated */ class CallbackDisposable implements IDisposable { private _callback: () => void; constructor(callback: () => void) { diff --git a/core/bentley/src/test/Logger.test.ts b/core/bentley/src/test/Logger.test.ts index a88b153b1a21..38f36399e723 100644 --- a/core/bentley/src/test/Logger.test.ts +++ b/core/bentley/src/test/Logger.test.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import { assert, describe, expect, it } from "vitest"; import { BentleyError, LoggingMetaData } from "../BentleyError"; -import { using } from "../Disposable"; import { Logger, LogLevel, PerfLogger } from "../Logger"; import { staticLoggerMetadata } from "../internal/staticLoggerMetadata"; import { BeDuration } from "../Time"; @@ -414,16 +413,18 @@ describe("Logger", () => { } }, undefined); - await using(new PerfLogger("mytestroutine"), async (_r) => { + { + using _r = new PerfLogger("mytestroutine"); await BeDuration.wait(10); - }); + } assert.isEmpty(perfMessages); Logger.setLevel("Performance", LogLevel.Info); - await using(new PerfLogger("mytestroutine2"), async (_r) => { + { + using _r = new PerfLogger("mytestroutine2"); await BeDuration.wait(10); - }); + } assert.equal(perfMessages.length, 2); assert.equal(perfMessages[0], "mytestroutine2,START"); @@ -433,18 +434,20 @@ describe("Logger", () => { perfMessages.pop(); perfMessages.pop(); - const outerPerf = new PerfLogger("outer call"); - const innerPerf = new PerfLogger("inner call"); - for (let i = 0; i < 1000; i++) { - if (i % 2 === 0) - continue; - } - innerPerf.dispose(); - for (let i = 0; i < 1000; i++) { - if (i % 2 === 0) - continue; + { + using _outerPerf = new PerfLogger("outer call"); + { + using _innerPerf = new PerfLogger("inner call"); + for (let i = 0; i < 1000; i++) { + if (i % 2 === 0) + continue; + } + } + for (let i = 0; i < 1000; i++) { + if (i % 2 === 0) + continue; + } } - outerPerf.dispose(); assert.equal(perfMessages.length, 4); assert.equal(perfMessages[0], "outer call,START"); assert.equal(perfMessages[1], "inner call,START"); diff --git a/core/bentley/vitest.config.mts b/core/bentley/vitest.config.mts index 7ab32697945d..a097449d1c80 100644 --- a/core/bentley/vitest.config.mts +++ b/core/bentley/vitest.config.mts @@ -1,5 +1,8 @@ import { coverageConfigDefaults, defineConfig } from 'vitest/config'; export default defineConfig({ + esbuild: { + target: "es2022", + }, test: { dir: "src", coverage: { diff --git a/core/common/package.json b/core/common/package.json index 0260866ede4f..866f0de16c57 100644 --- a/core/common/package.json +++ b/core/common/package.json @@ -51,7 +51,7 @@ "@itwin/object-storage-core": "^2.2.5", "@types/chai": "4.3.1", "@types/flatbuffers": "~1.10.0", - "@types/node": "~20.9.5", + "@types/node": "~20.17.0", "@vitest/coverage-v8": "^2.1.0", "eslint": "^9.13.0", "nyc": "^15.1.0", @@ -63,4 +63,4 @@ "extends": "./node_modules/@itwin/build-tools/.nycrc", "all": true } -} +} \ No newline at end of file diff --git a/core/common/src/RenderTexture.ts b/core/common/src/RenderTexture.ts index 275a0b460e73..a6f9efbc244b 100644 --- a/core/common/src/RenderTexture.ts +++ b/core/common/src/RenderTexture.ts @@ -6,7 +6,7 @@ * @module Rendering */ -import { compareStrings, Guid, GuidString, Id64String, IDisposable } from "@itwin/core-bentley"; +import { compareStrings, Guid, GuidString, Id64String } from "@itwin/core-bentley"; /** Identifies an image to be used to produce a [[RenderTexture]] for a given purpose - for example, * as part of a [[SkyBox]]. If the string is a valid `Id64String`, it refers to a persistent [Texture]($backend) element stored in an iModel. @@ -22,7 +22,7 @@ export type TextureImageSpec = Id64String | string; * @see [RenderSystem.createTextureFromElement]($frontend) to obtain a texture from a [Texture]($backend) element. * @public */ -export abstract class RenderTexture implements IDisposable { +export abstract class RenderTexture implements Disposable { /** Indicates the type of texture. */ public readonly type: RenderTexture.Type; /** Used for ordered comparisons, e.g. in DisplayParams.compareForMerge */ @@ -43,7 +43,12 @@ export abstract class RenderTexture implements IDisposable { * the caller is responsible for invoking this method when it is finished using the texture; otherwise, the [RenderSystem]($frontend) will handle * its disposal. */ - public abstract dispose(): void; + public [Symbol.dispose]() { + this.dispose(); // eslint-disable-line @typescript-eslint/no-deprecated + } + + /** @deprecated in 5.0 Will be made protected in a future release. Use [Symbol.dispose] instead. */ + public abstract dispose(): void; // eslint-disable-line @typescript-eslint/no-deprecated /** An [OrderedComparator]($bentley) that compares this texture against `other`. */ public compare(other: RenderTexture): number { diff --git a/core/common/src/rpc/core/RpcRequest.ts b/core/common/src/rpc/core/RpcRequest.ts index 53b0bae0aee9..f6a87bb20dbf 100644 --- a/core/common/src/rpc/core/RpcRequest.ts +++ b/core/common/src/rpc/core/RpcRequest.ts @@ -504,7 +504,7 @@ export abstract class RpcRequest { } this.setStatus(RpcRequestStatus.Resolved); - this.dispose(); + this[Symbol.dispose](); } private resolveRaw() { @@ -516,7 +516,7 @@ export abstract class RpcRequest { this.setLastUpdatedTime(); this._resolveRaw(this._response); this.setStatus(RpcRequestStatus.Resolved); - this.dispose(); + this[Symbol.dispose](); } protected reject(reason: any): void { @@ -532,11 +532,11 @@ export abstract class RpcRequest { } this.setStatus(RpcRequestStatus.Rejected); - this.dispose(); + this[Symbol.dispose](); } /** @internal */ - public dispose(): void { + public [Symbol.dispose](): void { this.setStatus(RpcRequestStatus.Disposed); this._raw = undefined; this._response = undefined; diff --git a/core/common/vitest.config.mts b/core/common/vitest.config.mts index 7ab32697945d..a097449d1c80 100644 --- a/core/common/vitest.config.mts +++ b/core/common/vitest.config.mts @@ -1,5 +1,8 @@ import { coverageConfigDefaults, defineConfig } from 'vitest/config'; export default defineConfig({ + esbuild: { + target: "es2022", + }, test: { dir: "src", coverage: { diff --git a/core/ecschema-editing/package.json b/core/ecschema-editing/package.json index 3c62fbc2733b..3bf41e15cb49 100644 --- a/core/ecschema-editing/package.json +++ b/core/ecschema-editing/package.json @@ -46,7 +46,7 @@ "@types/chai": "4.3.1", "@types/chai-as-promised": "^7", "@types/mocha": "^10.0.6", - "@types/node": "~20.9.5", + "@types/node": "~20.17.0", "@types/sinon": "^17.0.2", "@xmldom/xmldom": "~0.8.5", "benchmark": "^2.1.4", @@ -68,4 +68,4 @@ "nyc": { "extends": "./node_modules/@itwin/build-tools/.nycrc" } -} +} \ No newline at end of file diff --git a/core/ecschema-locaters/package.json b/core/ecschema-locaters/package.json index 63b4785c6d6f..d20dab2354b3 100644 --- a/core/ecschema-locaters/package.json +++ b/core/ecschema-locaters/package.json @@ -57,7 +57,7 @@ "@types/fs-extra": "^4.0.7", "@types/glob": "^5.0.35", "@types/mocha": "^10.0.6", - "@types/node": "~20.9.5", + "@types/node": "~20.17.0", "@types/sinon": "^17.0.2", "chai": "^4.3.10", "chai-as-promised": "^7.1.1", @@ -81,4 +81,4 @@ "extends": "./node_modules/@itwin/build-tools/.nycrc", "sourceMap": false } -} +} \ No newline at end of file diff --git a/core/ecschema-metadata/package.json b/core/ecschema-metadata/package.json index 8fc722dd6e8e..30569e9af556 100644 --- a/core/ecschema-metadata/package.json +++ b/core/ecschema-metadata/package.json @@ -45,7 +45,7 @@ "@types/chai": "4.3.1", "@types/chai-as-promised": "^7", "@types/mocha": "^10.0.6", - "@types/node": "~20.9.5", + "@types/node": "~20.17.0", "@types/sinon": "^17.0.2", "@xmldom/xmldom": "~0.8.5", "benchmark": "^2.1.4", @@ -66,4 +66,4 @@ "nyc": { "extends": "./node_modules/@itwin/build-tools/.nycrc" } -} +} \ No newline at end of file diff --git a/core/electron/package.json b/core/electron/package.json index e77208d471e0..dab614012055 100644 --- a/core/electron/package.json +++ b/core/electron/package.json @@ -52,7 +52,7 @@ "@itwin/eslint-plugin": "5.0.0-dev.1", "@types/chai": "4.3.1", "@types/mocha": "^10.0.6", - "@types/node": "~20.9.5", + "@types/node": "~20.17.0", "chai": "^4.3.10", "cpx2": "^3.0.0", "electron": "^33.0.0", @@ -70,4 +70,4 @@ "open": "^7.0.0", "username": "^7.0.0" } -} +} \ No newline at end of file diff --git a/core/electron/src/common/ElectronRpcRequest.ts b/core/electron/src/common/ElectronRpcRequest.ts index 0b11a7ed075a..c2af59652a75 100644 --- a/core/electron/src/common/ElectronRpcRequest.ts +++ b/core/electron/src/common/ElectronRpcRequest.ts @@ -51,8 +51,8 @@ export class ElectronRpcRequest extends RpcRequest { } /** @internal */ - public override dispose() { + public override[Symbol.dispose]() { this.protocol.requests.delete(this.id); - super.dispose(); + super[Symbol.dispose](); } } diff --git a/core/express-server/package.json b/core/express-server/package.json index f2c3b27fc961..7fe00963c919 100644 --- a/core/express-server/package.json +++ b/core/express-server/package.json @@ -43,7 +43,7 @@ "@types/chai": "4.3.1", "@types/express": "^4.17.20", "@types/mocha": "^10.0.6", - "@types/node": "~20.9.5", + "@types/node": "~20.17.0", "@types/sinon": "^17.0.2", "@types/supertest": "^6.0.2", "@types/express-ws": "^3.0.3", @@ -67,4 +67,4 @@ "nyc": { "extends": "./node_modules/@itwin/build-tools/.nycrc" } -} +} \ No newline at end of file diff --git a/core/frontend-devtools/src/effects/Explosion.ts b/core/frontend-devtools/src/effects/Explosion.ts index 575afd1b01af..695f328500b9 100644 --- a/core/frontend-devtools/src/effects/Explosion.ts +++ b/core/frontend-devtools/src/effects/Explosion.ts @@ -97,17 +97,17 @@ class ParticleSystem { this._origin = randomPositionInRange(iModel.projectExtents); - this._dispose = iModel.onClose.addListener(() => this.dispose()); + this._dispose = iModel.onClose.addListener(() => this[Symbol.dispose]()); } - public dispose(): void { + public [Symbol.dispose](): void { if (this._dispose) { this._dispose(); this._dispose = undefined; } IModelApp.viewManager.dropDecorator(this); - this._texture.dispose(); + this._texture[Symbol.dispose](); } public update(): void { @@ -120,7 +120,7 @@ class ParticleSystem { if (numParticles === 0) { this._numEmissions--; if (this._numEmissions < 0) - this.dispose(); + this[Symbol.dispose](); else this._particles = this._emitter.emit(); diff --git a/core/frontend-devtools/src/effects/Snow.ts b/core/frontend-devtools/src/effects/Snow.ts index f99c89aada2e..f2b1ed0c9a46 100644 --- a/core/frontend-devtools/src/effects/Snow.ts +++ b/core/frontend-devtools/src/effects/Snow.ts @@ -66,7 +66,7 @@ export class SnowDecorator implements Decorator { /** The viewport being decorated. */ public readonly viewport: Viewport; /** Invoked when this decorator is to be destroyed. */ - public readonly dispose: VoidFunction; + public readonly [Symbol.dispose]: VoidFunction; /** The initial width and height of the viewport, from which we randomly select each particle's initial position. */ private readonly _dimensions: Point2d; /** The list of particles being drawn. */ @@ -92,15 +92,15 @@ export class SnowDecorator implements Decorator { // Transfer ownership of the texture to the new decorator. const tex = this._texture; this._texture = undefined; - this.dispose(); + this[Symbol.dispose](); new SnowDecorator(viewport, tex); }); // When the viewport is destroyed, dispose of this decorator too. - const removeOnDispose = viewport.onDisposed.addListener(() => this.dispose()); + const removeOnDispose = viewport.onDisposed.addListener(() => this[Symbol.dispose]()); const removeDecorator = IModelApp.viewManager.addDecorator(this); - this.dispose = () => { + this[Symbol.dispose] = () => { removeDecorator(); removeOnRender(); removeOnDispose(); @@ -221,7 +221,7 @@ export class SnowDecorator implements Decorator { enable = undefined === decorator; if (undefined !== decorator && !enable) - decorator.dispose(); + decorator[Symbol.dispose](); else if (undefined === decorator && enable) { // Create a texture to use for the particles. // Note: the decorator takes ownership of the texture, and disposes of it when the decorator is disposed. diff --git a/core/frontend-devtools/src/widgets/DiagnosticsPanel.ts b/core/frontend-devtools/src/widgets/DiagnosticsPanel.ts index cbcf2bc2f8af..3da8a159b4c1 100644 --- a/core/frontend-devtools/src/widgets/DiagnosticsPanel.ts +++ b/core/frontend-devtools/src/widgets/DiagnosticsPanel.ts @@ -104,7 +104,7 @@ export class DiagnosticsPanel { public get element(): HTMLElement { return this._element; } - public dispose(): void { + public [Symbol.dispose](): void { dispose(this._fpsTracker); dispose(this._memoryTracker); dispose(this._tileMemoryBreakdown); diff --git a/core/frontend-devtools/src/widgets/FpsTracker.ts b/core/frontend-devtools/src/widgets/FpsTracker.ts index 5492f13a28d0..5e6893ac6ca6 100644 --- a/core/frontend-devtools/src/widgets/FpsTracker.ts +++ b/core/frontend-devtools/src/widgets/FpsTracker.ts @@ -30,7 +30,7 @@ export class FpsTracker { }).label; } - public dispose(): void { + public [Symbol.dispose](): void { this.toggle(false); } diff --git a/core/frontend-devtools/src/widgets/GpuProfiler.ts b/core/frontend-devtools/src/widgets/GpuProfiler.ts index e25e6f6ff89d..1799d4d02ef5 100644 --- a/core/frontend-devtools/src/widgets/GpuProfiler.ts +++ b/core/frontend-devtools/src/widgets/GpuProfiler.ts @@ -135,7 +135,7 @@ export class GpuProfiler { parent.appendChild(this._div); } - public dispose(): void { + public [Symbol.dispose](): void { this._debugControl.resultsCallback = undefined; } diff --git a/core/frontend-devtools/src/widgets/MemoryTracker.ts b/core/frontend-devtools/src/widgets/MemoryTracker.ts index 9cdc858a8675..dcd6f1f52ac8 100644 --- a/core/frontend-devtools/src/widgets/MemoryTracker.ts +++ b/core/frontend-devtools/src/widgets/MemoryTracker.ts @@ -226,7 +226,7 @@ export class MemoryTracker { parent.appendChild(this._div); } - public dispose(): void { + public [Symbol.dispose](): void { this.clearInterval(); } diff --git a/core/frontend-devtools/src/widgets/RenderCommandBreakdown.ts b/core/frontend-devtools/src/widgets/RenderCommandBreakdown.ts index 8c173cd006e4..ec1c8fcec1a6 100644 --- a/core/frontend-devtools/src/widgets/RenderCommandBreakdown.ts +++ b/core/frontend-devtools/src/widgets/RenderCommandBreakdown.ts @@ -34,7 +34,7 @@ export class RenderCommandBreakdown { this._total.innerText = "Total: 0"; } - public dispose(): void { + public [Symbol.dispose](): void { this.clearInterval(); } diff --git a/core/frontend-devtools/src/widgets/TileMemoryBreakdown.ts b/core/frontend-devtools/src/widgets/TileMemoryBreakdown.ts index 0b7fb9363374..f1cc54659eb9 100644 --- a/core/frontend-devtools/src/widgets/TileMemoryBreakdown.ts +++ b/core/frontend-devtools/src/widgets/TileMemoryBreakdown.ts @@ -188,7 +188,7 @@ export class TileMemoryBreakdown { } } - public dispose(): void { + public [Symbol.dispose](): void { this.clearInterval(); } diff --git a/core/frontend-devtools/src/widgets/TileStatisticsTracker.ts b/core/frontend-devtools/src/widgets/TileStatisticsTracker.ts index 9f0e8f9d36ad..165fff63bf86 100644 --- a/core/frontend-devtools/src/widgets/TileStatisticsTracker.ts +++ b/core/frontend-devtools/src/widgets/TileStatisticsTracker.ts @@ -106,7 +106,7 @@ export class TileStatisticsTracker { parent.appendChild(this._div); } - public dispose(): void { + public [Symbol.dispose](): void { this.clearInterval(); } diff --git a/core/frontend-devtools/src/widgets/ToolSettingsTracker.ts b/core/frontend-devtools/src/widgets/ToolSettingsTracker.ts index 03f099feab33..a95111400fb9 100644 --- a/core/frontend-devtools/src/widgets/ToolSettingsTracker.ts +++ b/core/frontend-devtools/src/widgets/ToolSettingsTracker.ts @@ -219,5 +219,5 @@ export class ToolSettingsTracker { }); } - public dispose(): void { } + public [Symbol.dispose](): void { } } diff --git a/core/frontend/src/BriefcaseConnection.ts b/core/frontend/src/BriefcaseConnection.ts index 62ad925a3ffb..4b0750f6c48b 100644 --- a/core/frontend/src/BriefcaseConnection.ts +++ b/core/frontend/src/BriefcaseConnection.ts @@ -312,7 +312,7 @@ export class BriefcaseConnection extends IModelConnection { await this._modelsMonitor.close(); this.beforeClose(); - this.txns.dispose(); + this.txns[Symbol.dispose](); this._isClosed = true; await IpcApp.appFunctionIpc.closeIModel(this._fileKey); diff --git a/core/frontend/src/BriefcaseTxns.ts b/core/frontend/src/BriefcaseTxns.ts index 6c4abbda5c46..1066442c3cf1 100644 --- a/core/frontend/src/BriefcaseTxns.ts +++ b/core/frontend/src/BriefcaseTxns.ts @@ -115,7 +115,7 @@ export class BriefcaseTxns extends BriefcaseNotificationHandler implements TxnNo } /** @internal */ - public dispose(): void { + public [Symbol.dispose](): void { if (this._cleanup) { this._cleanup(); this._cleanup = undefined; diff --git a/core/frontend/src/DrawingViewState.ts b/core/frontend/src/DrawingViewState.ts index 15c0e1fe2ffc..411d12dde155 100644 --- a/core/frontend/src/DrawingViewState.ts +++ b/core/frontend/src/DrawingViewState.ts @@ -230,8 +230,8 @@ class SectionAttachment { this._drawingExtents.z = Math.abs(this._drawingExtents.z); } - public dispose(): void { - this.viewport.dispose(); + public [Symbol.dispose](): void { + this.viewport[Symbol.dispose](); } public addToScene(context: SceneContext): void { diff --git a/core/frontend/src/EnvironmentDecorations.ts b/core/frontend/src/EnvironmentDecorations.ts index 163dc2035808..6e7625aa51ee 100644 --- a/core/frontend/src/EnvironmentDecorations.ts +++ b/core/frontend/src/EnvironmentDecorations.ts @@ -58,7 +58,7 @@ export class EnvironmentDecorations { this.loadGround(); } - public dispose(): void { + public [Symbol.dispose](): void { this._ground = undefined; this._sky.params = this._sky.promise = undefined; diff --git a/core/frontend/src/GraphicalEditingScope.ts b/core/frontend/src/GraphicalEditingScope.ts index b15abd238e5c..f24014a498e0 100644 --- a/core/frontend/src/GraphicalEditingScope.ts +++ b/core/frontend/src/GraphicalEditingScope.ts @@ -96,7 +96,7 @@ export class GraphicalEditingScope extends BriefcaseNotificationHandler implemen const scopeStarted = await IpcApp.appFunctionIpc.toggleGraphicalEditingScope(imodel.key, true); assert(scopeStarted); // If it didn't, the backend threw an error. } catch (e) { - scope.dispose(); + scope[Symbol.dispose](); throw e; } @@ -122,7 +122,7 @@ export class GraphicalEditingScope extends BriefcaseNotificationHandler implemen try { this.onExited.raiseEvent(this); } finally { - this.dispose(); + this[Symbol.dispose](); } } } @@ -159,7 +159,7 @@ export class GraphicalEditingScope extends BriefcaseNotificationHandler implemen this._cleanup = this.registerImpl(); } - private dispose(): void { + private [Symbol.dispose](): void { this._disposed = true; this.onExiting.clear(); @@ -174,6 +174,11 @@ export class GraphicalEditingScope extends BriefcaseNotificationHandler implemen } } + /** @deprecated in 5.0 Use [Symbol.dispose] instead. */ + public dispose() { + this[Symbol.dispose](); + } + /** @internal */ public notifyGeometryChanged(props: ModelGeometryChangesProps[]) { const changes = ModelGeometryChanges.iterable(props); diff --git a/core/frontend/src/IModelConnection.ts b/core/frontend/src/IModelConnection.ts index 327d5d1841ed..75fcd98bf3c4 100644 --- a/core/frontend/src/IModelConnection.ts +++ b/core/frontend/src/IModelConnection.ts @@ -248,7 +248,7 @@ export abstract class IModelConnection extends IModel { protected beforeClose(): void { this.onClose.raiseEvent(this); // event for this connection IModelConnection.onClose.raiseEvent(this); // event for all connections - this.tiles.dispose(); + this.tiles[Symbol.dispose](); this.subcategories.onIModelConnectionClose(); } diff --git a/core/frontend/src/NoRenderApp.ts b/core/frontend/src/NoRenderApp.ts index af497be68431..e13229b3190b 100644 --- a/core/frontend/src/NoRenderApp.ts +++ b/core/frontend/src/NoRenderApp.ts @@ -40,7 +40,7 @@ export class NullTarget extends RenderTarget { public override setFlashed(): void { } public setViewRect(): void { } public override onResized(): void { } - public override dispose(): void { } + public override[Symbol.dispose](): void { } public updateViewRect(): boolean { return false; } public readPixels(): void { } public get screenSpaceEffects(): Iterable { return []; } diff --git a/core/frontend/src/SheetViewState.ts b/core/frontend/src/SheetViewState.ts index e8998a39da29..c27cd2e6980c 100644 --- a/core/frontend/src/SheetViewState.ts +++ b/core/frontend/src/SheetViewState.ts @@ -288,9 +288,9 @@ class ViewAttachments { } } - public dispose(): void { + public [Symbol.dispose](): void { for (const attachment of this._attachments) - attachment.dispose(); + attachment[Symbol.dispose](); this._attachments.length = 0; } @@ -606,14 +606,13 @@ class AttachmentTarget extends MockRender.OffScreenTarget { } /** Draws the contents of a view attachment into a sheet view. */ -interface Attachment { +interface Attachment extends Disposable { readonly areAllTileTreesLoaded: boolean; addToScene: (context: SceneContext) => void; discloseTileTrees: (trees: DisclosedTileTreeSet) => void; readonly zDepth: number; collectStatistics: (stats: RenderMemory.Statistics) => void; viewAttachmentProps: ViewAttachmentProps; - dispose(): void; readonly viewport?: Viewport; } @@ -748,8 +747,8 @@ class OrthographicAttachment { this._hiddenLineSettings = style.settings.hiddenLineSettings; } - public dispose(): void { - this._viewport.dispose(); + public [Symbol.dispose](): void { + this._viewport[Symbol.dispose](); } public discloseTileTrees(trees: DisclosedTileTreeSet): void { @@ -974,8 +973,8 @@ class RasterAttachment { this.zDepth = Frustum2d.depthFromDisplayPriority(props.jsonProperties?.displayPriority ?? 0); } - public dispose(): void { - this._viewport?.dispose(); + public [Symbol.dispose](): void { + this._viewport?.[Symbol.dispose](); } public get viewAttachmentProps() { diff --git a/core/frontend/src/SubCategoriesCache.ts b/core/frontend/src/SubCategoriesCache.ts index c7d0849832d4..86e8e9461ce4 100644 --- a/core/frontend/src/SubCategoriesCache.ts +++ b/core/frontend/src/SubCategoriesCache.ts @@ -69,7 +69,7 @@ export class SubCategoriesCache { public async loadAllUsedSpatialSubCategories(): Promise { try { const results = await this._imodel.queryAllUsedSpatialSubCategories(); - if (undefined !== results){ + if (undefined !== results) { this.processResults(results, new Set(), false); } } catch { @@ -110,7 +110,7 @@ export class SubCategoriesCache { } private processResults(result: SubCategoriesCache.Result, missing: Id64Set, override: boolean = true): void { - for (const row of result){ + for (const row of result) { this.add(row.parentId, row.id, SubCategoriesCache.createSubCategoryAppearance(row.appearance), override); } @@ -271,7 +271,7 @@ export namespace SubCategoriesCache { } /** Cancel all requests and empty the queue. */ - public dispose(): void { + public [Symbol.dispose](): void { if (undefined !== this._request) { assert(undefined !== this._current); this._request.cancel(); diff --git a/core/frontend/src/Tiles.ts b/core/frontend/src/Tiles.ts index 08ba6600a9e1..bf065408b430 100644 --- a/core/frontend/src/Tiles.ts +++ b/core/frontend/src/Tiles.ts @@ -39,7 +39,7 @@ class TreeOwner implements TileTreeOwner { return this.tileTree; } - public dispose(): void { + public [Symbol.dispose](): void { this._tileTree = dispose(this._tileTree); this._loadStatus = TileTreeLoadStatus.NotLoaded; } @@ -101,7 +101,7 @@ export class Tiles implements Iterable<{ supplier: TileTreeSupplier, id: any, ow } /** @internal */ - public dispose(): void { + public [Symbol.dispose](): void { this.reset(); this._disposed = true; } @@ -111,7 +111,7 @@ export class Tiles implements Iterable<{ supplier: TileTreeSupplier, id: any, ow */ public reset(): void { for (const supplier of this._treesBySupplier) - supplier[1].forEach((_key, value) => value.dispose()); + supplier[1].forEach((_key, value) => value[Symbol.dispose]()); this._treesBySupplier.clear(); } @@ -186,7 +186,7 @@ export class Tiles implements Iterable<{ supplier: TileTreeSupplier, id: any, ow const trees = this._treesBySupplier.get(supplier); const tree = trees?.get(id); if (tree) { - tree.dispose(); + tree[Symbol.dispose](); trees?.delete(id); } } @@ -197,7 +197,7 @@ export class Tiles implements Iterable<{ supplier: TileTreeSupplier, id: any, ow if (undefined === trees) return; - trees.forEach((_key, value) => value.dispose()); + trees.forEach((_key, value) => value[Symbol.dispose]()); this._treesBySupplier.delete(supplier); } @@ -208,7 +208,7 @@ export class Tiles implements Iterable<{ supplier: TileTreeSupplier, id: any, ow } /** Iterate over all of the TileTreeOwners. */ - public * [Symbol.iterator](): Iterator<{ supplier: TileTreeSupplier, id: any, owner: TileTreeOwner }> { + public *[Symbol.iterator](): Iterator<{ supplier: TileTreeSupplier, id: any, owner: TileTreeOwner }> { for (const [supplier, dict] of this._treesBySupplier) { for (const entry of dict) yield { supplier, id: entry.key, owner: entry.value }; @@ -239,7 +239,7 @@ export class Tiles implements Iterable<{ supplier: TileTreeSupplier, id: any, ow const tree = owner.tileTree; if (undefined !== tree && tree.lastSelectedTime.milliseconds < olderThan.milliseconds) if (undefined === exclude || !exclude.has(tree)) - owner.dispose(); + owner[Symbol.dispose](); }); } } diff --git a/core/frontend/src/ViewManager.ts b/core/frontend/src/ViewManager.ts index 40ba01f3360b..d65e47d23258 100644 --- a/core/frontend/src/ViewManager.ts +++ b/core/frontend/src/ViewManager.ts @@ -324,7 +324,7 @@ export class ViewManager implements Iterable { this.updateRenderToScreen(); if (disposeOfViewport) - vp.dispose(); + vp[Symbol.dispose](); if (this._doIdleWork && this._viewports.length === 0) this._beginIdleWork(); diff --git a/core/frontend/src/ViewState.ts b/core/frontend/src/ViewState.ts index 6cc551a4db0a..0be8cc8a2d3f 100644 --- a/core/frontend/src/ViewState.ts +++ b/core/frontend/src/ViewState.ts @@ -1137,7 +1137,7 @@ export abstract class ViewState extends ElementState { this.forEachModelTreeRef((ref) => { const tree = ref.treeOwner.tileTree; if (undefined !== tree && (undefined === modelIds || Id64.has(modelIds, tree.modelId))) { - ref.treeOwner.dispose(); + ref.treeOwner[Symbol.dispose](); refreshed = true; } }); diff --git a/core/frontend/src/Viewport.ts b/core/frontend/src/Viewport.ts index 066f9c15d583..3d26f9327619 100644 --- a/core/frontend/src/Viewport.ts +++ b/core/frontend/src/Viewport.ts @@ -7,7 +7,7 @@ */ import { - asInstanceOf, assert, BeDuration, BeEvent, BeTimePoint, Constructor, dispose, Id64, Id64Arg, Id64Set, Id64String, IDisposable, isInstanceOf, + asInstanceOf, assert, BeDuration, BeEvent, BeTimePoint, Constructor, dispose, Id64, Id64Arg, Id64Set, Id64String, isInstanceOf, StopWatch, } from "@itwin/core-bentley"; import { @@ -288,7 +288,7 @@ export interface ReadPixelsArgs { * @public * @extensions */ -export abstract class Viewport implements IDisposable, TileUser { +export abstract class Viewport implements Disposable, TileUser { /** Event called whenever this viewport is synchronized with its [[ViewState]]. * @note This event is invoked *very* frequently. To avoid negatively impacting performance, consider using one of the more specific Viewport events; * otherwise, avoid performing excessive computations in response to this event. @@ -1148,17 +1148,22 @@ export abstract class Viewport implements IDisposable, TileUser { IModelApp.tileAdmin.registerUser(this); } - public dispose(): void { + public [Symbol.dispose](): void { if (this.isDisposed) return; this._target = dispose(this._target); - this.subcategories.dispose(); + this.subcategories[Symbol.dispose](); IModelApp.tileAdmin.forgetUser(this); this.onDisposed.raiseEvent(this); this.detachFromView(); } + /** @deprecated in 5.0 Use [Symbol.dispose] instead. */ + public dispose() { + this[Symbol.dispose](); + } + private setView(view: ViewState): void { if (view === this._view) return; @@ -3086,8 +3091,8 @@ export class ScreenViewport extends Viewport { } /** @internal */ - public override dispose(): void { - super.dispose(); + public override[Symbol.dispose](): void { + super[Symbol.dispose](); this._decorationCache.clear(); } diff --git a/core/frontend/src/internal/render/RenderGeometry.ts b/core/frontend/src/internal/render/RenderGeometry.ts index b33dce30d6e0..6b18880aa2c5 100644 --- a/core/frontend/src/internal/render/RenderGeometry.ts +++ b/core/frontend/src/internal/render/RenderGeometry.ts @@ -6,12 +6,11 @@ * @module Rendering */ -import { IDisposable } from "@itwin/core-bentley"; import { RenderMemory } from "../../render/RenderMemory"; import { Range3d } from "@itwin/core-geometry"; /** An opaque representation of geometry allocated by a [[RenderSystem]] to be supplied to [[RenderSystem.createRenderGraphic]]. */ -export interface RenderGeometry extends IDisposable, RenderMemory.Consumer { +export interface RenderGeometry extends Disposable, RenderMemory.Consumer { readonly renderGeometryType: "mesh" | "polyline" | "point-string" | "point-cloud" | "reality-mesh"; readonly isInstanceable: boolean; readonly isDisposed: boolean; diff --git a/core/frontend/src/render/Decorations.ts b/core/frontend/src/render/Decorations.ts index 172ed5de1fb3..f393cb84099c 100644 --- a/core/frontend/src/render/Decorations.ts +++ b/core/frontend/src/render/Decorations.ts @@ -6,7 +6,7 @@ * @module Rendering */ -import { dispose, disposeArray, IDisposable } from "@itwin/core-bentley"; +import { dispose, disposeArray } from "@itwin/core-bentley"; import { CanvasDecorationList } from "./CanvasDecoration"; import { GraphicList, RenderGraphic } from "./RenderGraphic"; @@ -14,7 +14,7 @@ import { GraphicList, RenderGraphic } from "./RenderGraphic"; * @public * @extensions */ -export class Decorations implements IDisposable { +export class Decorations implements Disposable { private _skyBox?: RenderGraphic; private _viewBackground?: RenderGraphic; // drawn first, view units, with no zbuffer, smooth shading, default lighting. e.g., a skybox private _normal?: GraphicList; // drawn with zbuffer, with scene lighting @@ -66,7 +66,7 @@ export class Decorations implements IDisposable { this._viewOverlay = viewOverlay; } - public dispose() { + public [Symbol.dispose]() { this.skyBox = undefined; this.viewBackground = undefined; this.world = undefined; @@ -74,4 +74,9 @@ export class Decorations implements IDisposable { this.viewOverlay = undefined; this.normal = undefined; } + + /** @deprecated in 5.0 Use [Symbol.dispose] instead. */ + public dispose() { + this[Symbol.dispose](); + } } diff --git a/core/frontend/src/render/GraphicBranch.ts b/core/frontend/src/render/GraphicBranch.ts index 88b62db8823b..d5af56ef1f27 100644 --- a/core/frontend/src/render/GraphicBranch.ts +++ b/core/frontend/src/render/GraphicBranch.ts @@ -6,7 +6,7 @@ * @module Rendering */ -import { disposeArray, Id64String, IDisposable } from "@itwin/core-bentley"; +import { disposeArray, Id64String } from "@itwin/core-bentley"; import { FeatureAppearanceProvider, HiddenLine, RealityModelDisplaySettings, RenderSchedule, ViewFlagOverrides, ViewFlags, } from "@itwin/core-common"; @@ -40,7 +40,7 @@ export interface GraphicBranchFrustum { * @public * @extensions */ -export class GraphicBranch implements IDisposable /* , RenderMemory.Consumer */ { +export class GraphicBranch implements Disposable /* , RenderMemory.Consumer */ { /** The child nodes of this branch */ public readonly entries: RenderGraphic[] = []; /** If true, when the branch is disposed of, the RenderGraphics in its entries array will also be disposed */ @@ -108,10 +108,15 @@ export class GraphicBranch implements IDisposable /* , RenderMemory.Consumer */ } /** Disposes of all graphics in this branch, if and only if [[ownsEntries]] is true. */ - public dispose() { + public [Symbol.dispose]() { this.clear(); } + /** @deprecated in 5.0 Use [Symbol.dispose] instead. */ + public dispose() { + this[Symbol.dispose](); + } + /** Returns true if this branch contains no graphics. */ public get isEmpty(): boolean { return 0 === this.entries.length; diff --git a/core/frontend/src/render/MockRender.ts b/core/frontend/src/render/MockRender.ts index 0c34ef16f531..4c208139de6c 100644 --- a/core/frontend/src/render/MockRender.ts +++ b/core/frontend/src/render/MockRender.ts @@ -110,7 +110,7 @@ export namespace MockRender { export class Branch extends Graphic { public constructor(public readonly branch: GraphicBranch, public readonly transform: Transform, public readonly options?: GraphicBranchOptions) { super(); } - public override dispose() { this.branch.dispose(); } + public override dispose() { this.branch[Symbol.dispose](); } } export class Batch extends Graphic { @@ -129,7 +129,7 @@ export namespace MockRender { public constructor(public readonly renderGeometryType: "mesh" | "polyline" | "point-string") { } - public dispose(): void { this.isDisposed = true; } + public [Symbol.dispose](): void { this.isDisposed = true; } public collectStatistics(): void { } public computeRange() { return new Range3d(); } } @@ -137,7 +137,7 @@ export namespace MockRender { /** @internal */ export class AreaPattern implements RenderAreaPattern { public readonly [_implementationProhibited] = "renderAreaPattern"; - public dispose(): void { } + public [Symbol.dispose](): void { } public collectStatistics(): void { } } diff --git a/core/frontend/src/render/RenderGraphic.ts b/core/frontend/src/render/RenderGraphic.ts index a5f60f100b00..1ede6b0d3f62 100644 --- a/core/frontend/src/render/RenderGraphic.ts +++ b/core/frontend/src/render/RenderGraphic.ts @@ -6,7 +6,6 @@ * @module Rendering */ -import { IDisposable } from "@itwin/core-bentley"; import { RenderMemory } from "./RenderMemory"; import { Range3d } from "@itwin/core-geometry"; @@ -18,8 +17,13 @@ import { Range3d } from "@itwin/core-geometry"; * @public * @extensions */ -export abstract class RenderGraphic implements IDisposable /* , RenderMemory.Consumer */ { - public abstract dispose(): void; +export abstract class RenderGraphic implements Disposable /* , RenderMemory.Consumer */ { + public [Symbol.dispose](): void { + this.dispose(); // eslint-disable-line @typescript-eslint/no-deprecated + } + + /** @deprecated in 5.0 Will be made protected in a future release. Use [Symbol.dispose] instead. */ + public abstract dispose(): void; // eslint-disable-line @typescript-eslint/no-deprecated /** @internal */ public abstract collectStatistics(stats: RenderMemory.Statistics): void; @@ -43,7 +47,7 @@ export abstract class RenderGraphicOwner extends RenderGraphic { /** Does nothing. To dispose of the owned graphic, use [[disposeGraphic]]. */ public dispose(): void { } /** Disposes of the owned graphic. */ - public disposeGraphic(): void { this.graphic.dispose(); } + public disposeGraphic(): void { this.graphic[Symbol.dispose](); } /** @internal */ public collectStatistics(stats: RenderMemory.Statistics): void { this.graphic.collectStatistics(stats); } /** @internal */ diff --git a/core/frontend/src/render/RenderPlanarClassifier.ts b/core/frontend/src/render/RenderPlanarClassifier.ts index 8fa420f403af..c9439ac0477c 100644 --- a/core/frontend/src/render/RenderPlanarClassifier.ts +++ b/core/frontend/src/render/RenderPlanarClassifier.ts @@ -6,7 +6,7 @@ * @module Rendering */ -import { Id64String, IDisposable } from "@itwin/core-bentley"; +import { Id64String } from "@itwin/core-bentley"; import { Transform } from "@itwin/core-geometry"; import { PlanarClipMaskState } from "../PlanarClipMaskState"; import { SpatialClassifierTileTreeReference, Tile } from "../tile/internal"; @@ -17,8 +17,8 @@ export interface PlanarClassifierTarget { modelId: Id64String, tiles: Tile[], lo /** An opaque representation of a planar classifier applied to geometry within a [[Viewport]]. * @internal */ -export abstract class RenderPlanarClassifier implements IDisposable { - public abstract dispose(): void; +export abstract class RenderPlanarClassifier implements Disposable { + public abstract [Symbol.dispose](): void; public abstract collectGraphics(context: SceneContext, target: PlanarClassifierTarget): void; public abstract setSource(classifierTreeRef?: SpatialClassifierTileTreeReference, planarClipMask?: PlanarClipMaskState): void; } diff --git a/core/frontend/src/render/RenderSystem.ts b/core/frontend/src/render/RenderSystem.ts index ddf1fb77aefe..76a8229cb0b9 100644 --- a/core/frontend/src/render/RenderSystem.ts +++ b/core/frontend/src/render/RenderSystem.ts @@ -6,7 +6,7 @@ * @module Rendering */ -import { base64StringToUint8Array, Id64String, IDisposable } from "@itwin/core-bentley"; +import { base64StringToUint8Array, Id64String } from "@itwin/core-bentley"; import { ColorDef, ColorIndex, ElementAlignedBox3d, FeatureIndex, FeatureIndexType, FillFlags, Frustum, Gradient, ImageBuffer, ImageBufferFormat, ImageSource, ImageSourceFormat, isValidImageSourceFormat, PackedFeatureTable, QParams3d, QPoint3dList, RenderFeatureTable, RenderMaterial, RenderTexture, SkyGradient, TextureProps, TextureTransparency, @@ -58,8 +58,8 @@ import { GraphicTemplate } from "./GraphicTemplate"; /** An opaque representation of a texture draped on geometry within a [[Viewport]]. * @internal */ -export abstract class RenderTextureDrape implements IDisposable { - public abstract dispose(): void; +export abstract class RenderTextureDrape implements Disposable { + public abstract [Symbol.dispose](): void; /** @internal */ public abstract collectStatistics(stats: RenderMemory.Statistics): void; @@ -153,8 +153,8 @@ export interface RenderSystemDebugControl { } /** @internal */ -export abstract class RenderTerrainGeometry implements IDisposable, RenderMemory.Consumer { - public abstract dispose(): void; +export abstract class RenderTerrainGeometry implements Disposable, RenderMemory.Consumer { + public abstract [Symbol.dispose](): void; public abstract get transform(): Transform | undefined; public abstract collectStatistics(stats: RenderMemory.Statistics): void; } @@ -173,7 +173,7 @@ export class TerrainTexture { ) { } public cloneWithClip(clipRectangle: Range2d) { - return new TerrainTexture (this.texture, this.featureId, this.scale, this.translate, this.targetRectangle, this.layerIndex, this.transparency, clipRectangle); + return new TerrainTexture(this.texture, this.featureId, this.scale, this.translate, this.targetRectangle, this.layerIndex, this.transparency, clipRectangle); } } /** @internal */ @@ -219,7 +219,7 @@ export interface PlanarGridProps { /** An opaque representation of instructions for repeatedly drawing a [[RenderGeometry]] to pattern a planar region, to be supplied to [[RenderSystem.createRenderGraphic]]. * @internal */ -export interface RenderAreaPattern extends IDisposable, RenderMemory.Consumer { +export interface RenderAreaPattern extends Disposable, RenderMemory.Consumer { readonly [_implementationProhibited]: "renderAreaPattern"; } @@ -295,7 +295,7 @@ export interface CreateGraphicFromTemplateArgs { * @public * @extensions */ -export abstract class RenderSystem implements IDisposable { +export abstract class RenderSystem implements Disposable { /** Options used to initialize the RenderSystem. These are primarily used for feature-gating. * This object is frozen and cannot be modified after the RenderSystem is created. * @internal @@ -322,8 +322,12 @@ export abstract class RenderSystem implements IDisposable { /** @internal */ public abstract get isValid(): boolean; - /** @internal */ - public abstract dispose(): void; + public [Symbol.dispose]() { + this.dispose(); // eslint-disable-line @typescript-eslint/no-deprecated + } + + /** @deprecated in 5.0 Will be made protected in a future release. Use [Symbol.dispose] instead. */ + public abstract dispose(): void; // eslint-disable-line @typescript-eslint/no-deprecated /** The maximum permitted width or height of a texture supported by this render system. */ public get maxTextureSize(): number { return 0; } diff --git a/core/frontend/src/render/RenderTarget.ts b/core/frontend/src/render/RenderTarget.ts index 63e8c552973a..4fa36949b8fe 100644 --- a/core/frontend/src/render/RenderTarget.ts +++ b/core/frontend/src/render/RenderTarget.ts @@ -6,7 +6,7 @@ * @module Rendering */ -import { Id64String, IDisposable } from "@itwin/core-bentley"; +import { Id64String } from "@itwin/core-bentley"; import { Frustum, ImageBuffer } from "@itwin/core-common"; import { Point2d, XAndY } from "@itwin/core-geometry"; import { IModelConnection } from "../IModelConnection"; @@ -75,7 +75,7 @@ export interface RenderTargetDebugControl { * Application code never interacts directly with a `RenderTarget` - it interacts with the `Viewport`'s API which forwards requests to the `RenderTarget`. * @public */ -export abstract class RenderTarget implements IDisposable, RenderMemory.Consumer { +export abstract class RenderTarget implements Disposable, RenderMemory.Consumer { /** @internal */ protected abstract readonly [_implementationProhibited]: unknown; @@ -139,7 +139,7 @@ export abstract class RenderTarget implements IDisposable, RenderMemory.Consumer } /** @internal */ - public dispose(): void { } + public [Symbol.dispose](): void { } /** @internal */ public reset(): void { } /** @internal */ diff --git a/core/frontend/src/render/VisibleFeature.ts b/core/frontend/src/render/VisibleFeature.ts index 87eb09f90351..998ae6ac5a34 100644 --- a/core/frontend/src/render/VisibleFeature.ts +++ b/core/frontend/src/render/VisibleFeature.ts @@ -85,7 +85,7 @@ class ExpiringIterable implements Iterable { this._features = features; } - public dispose(): void { + public [Symbol.dispose](): void { this._disposed = true; this._features = []; } @@ -97,12 +97,8 @@ class ExpiringIterable implements Iterable { } function invokeCallback(features: Iterable, callback: QueryVisibleFeaturesCallback): void { - const iterable = new ExpiringIterable(features); - try { - callback(iterable); - } finally { - iterable.dispose(); - } + using iterable = new ExpiringIterable(features); + callback(iterable); } /** Features read from pixels rendered by a viewport. */ diff --git a/core/frontend/src/render/webgl/AtmosphereUniforms.ts b/core/frontend/src/render/webgl/AtmosphereUniforms.ts index 6dae852e3711..8f7de0c7828c 100644 --- a/core/frontend/src/render/webgl/AtmosphereUniforms.ts +++ b/core/frontend/src/render/webgl/AtmosphereUniforms.ts @@ -179,5 +179,9 @@ export class AtmosphereUniforms implements WebGLDisposable, SyncTarget { return true; } - public dispose() { } + public [Symbol.dispose]() { } + /** @deprecated in 5.0 Use [Symbol.dispose] instead. */ + public dispose() { + this[Symbol.dispose](); + } } diff --git a/core/frontend/src/render/webgl/AttributeBuffers.ts b/core/frontend/src/render/webgl/AttributeBuffers.ts index 54b68d24905e..d98edf93a2de 100644 --- a/core/frontend/src/render/webgl/AttributeBuffers.ts +++ b/core/frontend/src/render/webgl/AttributeBuffers.ts @@ -87,9 +87,13 @@ export class BuffersContainer implements WebGLDisposable { this._vao = new VAOHandle(this._context); } + /** @deprecated in 5.0 Use [Symbol.dispose] instead. */ + public dispose() { + this[Symbol.dispose](); + } // NB: BufferHandle objects contained within BufferHandleLinkage entries are disposed where they are created because they could be shared among multiple BuffersContainer objects. - public dispose(): void { - this._vao.dispose(); + public [Symbol.dispose](): void { + this._vao[Symbol.dispose](); } public get isDisposed(): boolean { @@ -156,8 +160,13 @@ export class VAOHandle implements WebGLDisposable { public get isDisposed(): boolean { return this._arrayObject === undefined; } + /** @deprecated in 5.0 Use [Symbol.dispose] instead. */ + public dispose() { + this[Symbol.dispose](); + } + /** Frees the WebGL vertex array object */ - public dispose(): void { + public [Symbol.dispose](): void { if (!this.isDisposed) { this._context.deleteVertexArray(this._arrayObject!); this._arrayObject = undefined; @@ -206,7 +215,7 @@ export class BufferHandle implements WebGLDisposable { public get bytesUsed(): number { return this._bytesUsed; } /** Frees the WebGL buffer */ - public dispose(): void { + public [Symbol.dispose](): void { if (!this.isDisposed) { System.instance.context.deleteBuffer(this._glBuffer!); this._glBuffer = undefined; diff --git a/core/frontend/src/render/webgl/BackgroundMapDrape.ts b/core/frontend/src/render/webgl/BackgroundMapDrape.ts index 28cdf6cad26b..8e7e98d51df4 100644 --- a/core/frontend/src/render/webgl/BackgroundMapDrape.ts +++ b/core/frontend/src/render/webgl/BackgroundMapDrape.ts @@ -55,8 +55,8 @@ export class BackgroundMapDrape extends TextureDrape { public override get isDisposed(): boolean { return super.isDisposed && undefined === this._fbo; } - public override dispose() { - super.dispose(); + public override[Symbol.dispose]() { + super[Symbol.dispose](); this._fbo = dispose(this._fbo); } @@ -85,7 +85,7 @@ export class BackgroundMapDrape extends TextureDrape { const requiredHeight = requiredWidth; if (requiredWidth !== this._width || requiredHeight !== this._height) - this.dispose(); + this[Symbol.dispose](); this._width = requiredWidth; this._height = requiredHeight; diff --git a/core/frontend/src/render/webgl/CachedGeometry.ts b/core/frontend/src/render/webgl/CachedGeometry.ts index 6581f845e698..af9bca8223f9 100644 --- a/core/frontend/src/render/webgl/CachedGeometry.ts +++ b/core/frontend/src/render/webgl/CachedGeometry.ts @@ -103,7 +103,7 @@ export abstract class CachedGeometry implements WebGLDisposable, RenderMemory.Co // Draws this geometry public abstract draw(): void; - public abstract dispose(): void; + public abstract [Symbol.dispose](): void; // Intended to be overridden by specific subclasses public get materialInfo(): MaterialInfo | undefined { return undefined; } @@ -252,7 +252,7 @@ export class IndexedGeometryParams implements WebGLDisposable { && this.indices.isDisposed; } - public dispose() { + public [Symbol.dispose]() { dispose(this.buffers); dispose(this.positions); dispose(this.indices); @@ -272,7 +272,7 @@ export abstract class IndexedGeometry extends CachedGeometry { public get isDisposed(): boolean { return this._params.isDisposed; } - public dispose() { + public [Symbol.dispose]() { dispose(this._params); } @@ -385,7 +385,7 @@ export class SkyBoxGeometryParams implements WebGLDisposable { public get isDisposed(): boolean { return this.buffers.isDisposed && this.positions.isDisposed; } - public dispose() { + public [Symbol.dispose]() { dispose(this.buffers); dispose(this.positions); } @@ -442,7 +442,7 @@ export class SkyBoxQuadsGeometry extends CachedGeometry { public get isDisposed(): boolean { return this._params.isDisposed; } - public dispose() { + public [Symbol.dispose]() { dispose(this._params); } @@ -727,8 +727,8 @@ export class SkySphereViewportQuadGeometry extends ViewportQuadGeometry { public override get isDisposed(): boolean { return super.isDisposed && this._worldPosBuff.isDisposed; } - public override dispose() { - super.dispose(); + public override[Symbol.dispose]() { + super[Symbol.dispose](); dispose(this._worldPosBuff); } } @@ -1101,7 +1101,7 @@ export class ScreenPointsGeometry extends CachedGeometry { public get isDisposed(): boolean { return this.buffers.isDisposed && this._positions.isDisposed; } - public dispose() { + public [Symbol.dispose]() { dispose(this.buffers); dispose(this._positions); } @@ -1166,7 +1166,7 @@ export class PolylineBuffers implements WebGLDisposable { && this.nextIndicesAndParams.isDisposed; } - public dispose() { + public [Symbol.dispose]() { dispose(this.buffers); dispose(this.indices); dispose(this.prevIndices); diff --git a/core/frontend/src/render/webgl/ClippingProgram.ts b/core/frontend/src/render/webgl/ClippingProgram.ts index e43846427d37..d44de9cc7f58 100644 --- a/core/frontend/src/render/webgl/ClippingProgram.ts +++ b/core/frontend/src/render/webgl/ClippingProgram.ts @@ -37,9 +37,14 @@ export class ClippingProgram { return numPlanes > 0 ? this._program : undefined; } - public dispose(): void { + public [Symbol.dispose](): void { this._program = dispose(this._program); } + + /** @deprecated in 5.0 Use [Symbol.dispose] instead. */ + public dispose(): void { + this[Symbol.dispose](); + } } /** @internal */ diff --git a/core/frontend/src/render/webgl/Contours.ts b/core/frontend/src/render/webgl/Contours.ts index ed02b11c3762..91dc8a2388f5 100644 --- a/core/frontend/src/render/webgl/Contours.ts +++ b/core/frontend/src/render/webgl/Contours.ts @@ -56,7 +56,7 @@ export class Contours implements WebGLDisposable { private _initialize(map: RenderFeatureTable) { assert(0 < map.numFeatures); this._numFeatures = map.numFeatures; - const dims = computeDimensions(this._numFeatures, 1/8, 0, System.instance.maxTextureSize); + const dims = computeDimensions(this._numFeatures, 1 / 8, 0, System.instance.maxTextureSize); const width = dims.width; const height = dims.height; assert(width * height * 8 >= this._numFeatures); @@ -96,7 +96,7 @@ export class Contours implements WebGLDisposable { let byteOut = 0; let dataIndex = 0; for (const feature of map.iterable(scratchPackedFeature)) { - dataIndex = Math.floor (feature.index * 0.5); + dataIndex = Math.floor(feature.index * 0.5); even = (feature.index & 1) === 0; const terrainNdx = subCatMap.get(feature.subCategoryId.lower, feature.subCategoryId.upper) ?? defaultNdx; if (even) @@ -120,7 +120,7 @@ export class Contours implements WebGLDisposable { public get isDisposed(): boolean { return undefined === this._lut; } - public dispose() { + public [Symbol.dispose]() { this._lut = dispose(this._lut); return undefined; } diff --git a/core/frontend/src/render/webgl/Disposable.ts b/core/frontend/src/render/webgl/Disposable.ts index 1701dbc7fcb2..786144746c34 100644 --- a/core/frontend/src/render/webgl/Disposable.ts +++ b/core/frontend/src/render/webgl/Disposable.ts @@ -2,13 +2,12 @@ * Copyright (c) Bentley Systems, Incorporated. All rights reserved. * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ -import { IDisposable } from "@itwin/core-bentley"; /** Interface implemented by any type that potentially owns WebGL resources that must be explicitly freed. * Resources are freed in the inherited `dispose` method. * @internal */ -export interface WebGLDisposable extends IDisposable { +export interface WebGLDisposable extends Disposable { /** Test whether the object currently holds any unreleased WebGL resources. * This property should *always* return false after `dispose` has been called. * @returns true if the object has released any and all WebGL resources it may have previously owned. diff --git a/core/frontend/src/render/webgl/EDL.ts b/core/frontend/src/render/webgl/EDL.ts index e2a3a6d3dd52..6cce84d24d1b 100644 --- a/core/frontend/src/render/webgl/EDL.ts +++ b/core/frontend/src/render/webgl/EDL.ts @@ -48,11 +48,11 @@ class Bundle implements WebGLDisposable { const edlFiltTex2 = TextureHandle.createForAttachment(width >> 1, height >> 1, GL.Texture.Format.Rgba, GL.Texture.DataType.UnsignedByte); const edlFiltTex4 = TextureHandle.createForAttachment(width >> 2, height >> 2, GL.Texture.Format.Rgba, GL.Texture.DataType.UnsignedByte); if (undefined === edlCalcTex1 || undefined === edlCalcTex2 || undefined === edlCalcTex4 || undefined === edlFiltTex2 || undefined === edlFiltTex4) { - dispose (edlCalcTex1); - dispose (edlCalcTex2); - dispose (edlCalcTex4); - dispose (edlFiltTex2); - dispose (edlFiltTex4); + dispose(edlCalcTex1); + dispose(edlCalcTex2); + dispose(edlCalcTex4); + dispose(edlFiltTex2); + dispose(edlFiltTex4); return undefined; } const edlCalcFbo1 = FrameBuffer.create([edlCalcTex1]); @@ -61,11 +61,11 @@ class Bundle implements WebGLDisposable { const edlFiltFbo2 = FrameBuffer.create([edlFiltTex2]); const edlFiltFbo4 = FrameBuffer.create([edlFiltTex4]); if (undefined === edlCalcFbo1 || undefined === edlCalcFbo2 || undefined === edlCalcFbo4 || undefined === edlFiltFbo2 || undefined === edlFiltFbo4) { - dispose (edlCalcFbo1); - dispose (edlCalcFbo2); - dispose (edlCalcFbo4); - dispose (edlFiltFbo2); - dispose (edlFiltFbo4); + dispose(edlCalcFbo1); + dispose(edlCalcFbo2); + dispose(edlCalcFbo4); + dispose(edlFiltFbo2); + dispose(edlFiltFbo4); return undefined; } return new Bundle(edlCalcTex1, edlCalcTex2, edlCalcTex4, edlFiltTex2, edlFiltTex4, edlCalcFbo1, edlCalcFbo2, edlCalcFbo4, edlFiltFbo2, edlFiltFbo4); @@ -93,7 +93,7 @@ class Bundle implements WebGLDisposable { && undefined === this.edlMixGeom; } - public dispose(): void { + public [Symbol.dispose](): void { this.edlCalcTex1 = dispose(this.edlCalcTex1); this.edlCalcTex2 = dispose(this.edlCalcTex2); this.edlCalcTex4 = dispose(this.edlCalcTex4); @@ -184,13 +184,13 @@ export class EyeDomeLighting implements RenderMemory.Consumer, WebGLDisposable { public get isDisposed(): boolean { return undefined === this._bundle && undefined === this._edlFinalFbo; } - public dispose() { + public [Symbol.dispose]() { this._bundle = dispose(this._bundle); - this._edlFinalFbo = dispose (this._edlFinalFbo); + this._edlFinalFbo = dispose(this._edlFinalFbo); } public reset() { - this.dispose(); + this[Symbol.dispose](); } /** calculate EyeDomeLighting at specified quality using screen space shaders @@ -207,8 +207,8 @@ export class EyeDomeLighting implements RenderMemory.Consumer, WebGLDisposable { // NB: have to test and create MS buffer as well if useMsBuffers, not outputting to depth const finalBufs = edlParams.curFbo.getColorTargets(edlParams.useMsBuffers, 0); if (undefined === this._edlFinalFbo || this._edlFinalBufs?.tex !== finalBufs.tex || - (edlParams.useMsBuffers && this._edlFinalBufs?.msBuf !== finalBufs.msBuf)) { - this._edlFinalFbo = dispose (this._edlFinalFbo); + (edlParams.useMsBuffers && this._edlFinalBufs?.msBuf !== finalBufs.msBuf)) { + this._edlFinalFbo = dispose(this._edlFinalFbo); this._edlFinalBufs = finalBufs; const filters = [GL.MultiSampling.Filter.Linear]; this._edlFinalFbo = FrameBuffer.create([this._edlFinalBufs.tex], undefined, @@ -242,8 +242,8 @@ export class EyeDomeLighting implements RenderMemory.Consumer, WebGLDisposable { const ct4 = bundle.edlCalcTex4; const ctd = this._depth.getHandle()!; bundle.edlCalcFullGeom = [EDLCalcFullGeometry.createGeometry(ct1.getHandle()!, ctd, 1, ct1.width, ct1.height), - EDLCalcFullGeometry.createGeometry(ct1.getHandle()!, ctd, 2, ct2!.width, ct2!.height), - EDLCalcFullGeometry.createGeometry(ct1.getHandle()!, ctd, 4, ct4!.width, ct4!.height)]; + EDLCalcFullGeometry.createGeometry(ct1.getHandle()!, ctd, 2, ct2!.width, ct2!.height), + EDLCalcFullGeometry.createGeometry(ct1.getHandle()!, ctd, 4, ct4!.width, ct4!.height)]; } const edlFiltFbos: FrameBuffer[] = [bundle.edlFiltFbo2!, bundle.edlFiltFbo4!]; @@ -252,7 +252,7 @@ export class EyeDomeLighting implements RenderMemory.Consumer, WebGLDisposable { const ft4 = bundle.edlCalcTex4; const ftd = this._depth.getHandle()!; bundle.edlFiltGeom = [EDLFilterGeometry.createGeometry(ft2!.getHandle()!, ftd, 2, ft2!.width, ft2!.height), - EDLFilterGeometry.createGeometry(ft4!.getHandle()!, ftd, 4, ft4!.width, ft4!.height)]; + EDLFilterGeometry.createGeometry(ft4!.getHandle()!, ftd, 4, ft4!.width, ft4!.height)]; } const gl = System.instance.context; @@ -266,8 +266,8 @@ export class EyeDomeLighting implements RenderMemory.Consumer, WebGLDisposable { }); if (edlParams.edlFilter && i > 0) { - fbStack.execute(edlFiltFbos[i-1], true, false, () => { - const params = getDrawParams(this._target, bundle.edlFiltGeom![i-1]!); + fbStack.execute(edlFiltFbos[i - 1], true, false, () => { + const params = getDrawParams(this._target, bundle.edlFiltGeom![i - 1]!); this._target.techniques.draw(params); }); } diff --git a/core/frontend/src/render/webgl/EdgeGeometry.ts b/core/frontend/src/render/webgl/EdgeGeometry.ts index e56838441b54..2cf9614d3131 100644 --- a/core/frontend/src/render/webgl/EdgeGeometry.ts +++ b/core/frontend/src/render/webgl/EdgeGeometry.ts @@ -47,7 +47,7 @@ export class EdgeGeometry extends MeshGeometry { && this._endPointAndQuadIndices.isDisposed; } - public dispose() { + public [Symbol.dispose]() { dispose(this.buffers); dispose(this._indices); dispose(this._endPointAndQuadIndices); @@ -105,8 +105,8 @@ export class SilhouetteEdgeGeometry extends EdgeGeometry { public override get isDisposed(): boolean { return super.isDisposed && this._normalPairs.isDisposed; } - public override dispose() { - super.dispose(); + public override[Symbol.dispose]() { + super[Symbol.dispose](); dispose(this._normalPairs); } @@ -140,7 +140,7 @@ export class PolylineEdgeGeometry extends MeshGeometry { public get isDisposed(): boolean { return this._buffers.isDisposed; } - public dispose() { + public [Symbol.dispose]() { dispose(this._buffers); } diff --git a/core/frontend/src/render/webgl/FeatureOverrides.ts b/core/frontend/src/render/webgl/FeatureOverrides.ts index f2d6495083d3..aa766447713c 100644 --- a/core/frontend/src/render/webgl/FeatureOverrides.ts +++ b/core/frontend/src/render/webgl/FeatureOverrides.ts @@ -378,7 +378,7 @@ export class FeatureOverrides implements WebGLDisposable { public get isDisposed(): boolean { return undefined === this._lut; } - public dispose() { + public [Symbol.dispose]() { this._lut = dispose(this._lut); if (this._cleanup) { this._cleanup(); diff --git a/core/frontend/src/render/webgl/FrameBuffer.ts b/core/frontend/src/render/webgl/FrameBuffer.ts index 855f32b72f38..1b7a983316cb 100644 --- a/core/frontend/src/render/webgl/FrameBuffer.ts +++ b/core/frontend/src/render/webgl/FrameBuffer.ts @@ -60,8 +60,8 @@ export class FrameBuffer implements WebGLDisposable { public getColorTargets(useMSBuffers: boolean, ndx: number): { tex: TextureHandle, msBuf: RenderBufferMultiSample | undefined } { let msBuf; if (useMSBuffers) { - assert (ndx < this._colorMsBuffers.length); - msBuf = this._colorMsBuffers[ndx]; + assert(ndx < this._colorMsBuffers.length); + msBuf = this._colorMsBuffers[ndx]; } assert(ndx < this._colorTextures.length); return { tex: this._colorTextures[ndx], msBuf }; @@ -140,7 +140,7 @@ export class FrameBuffer implements WebGLDisposable { return new FrameBuffer(fbo, colorTextures, depthBuffer, colorMsBuffers, msFilters, depthBufferMs); } - public dispose(): void { + public [Symbol.dispose](): void { // NB: The FrameBuffer does not *own* the textures and depth buffer. if (!this.isDisposed) { System.instance.context.deleteFramebuffer(this._fbo!); diff --git a/core/frontend/src/render/webgl/Graphic.ts b/core/frontend/src/render/webgl/Graphic.ts index e7ad1728411d..636ea700c82f 100644 --- a/core/frontend/src/render/webgl/Graphic.ts +++ b/core/frontend/src/render/webgl/Graphic.ts @@ -52,7 +52,7 @@ export class GraphicOwner extends Graphic { public get isDisposed(): boolean { return this._isDisposed; } public dispose(): void { this._isDisposed = true; } public disposeGraphic(): void { - this.graphic.dispose(); + this.graphic[Symbol.dispose](); } public collectStatistics(stats: RenderMemory.Statistics): void { this.graphic.collectStatistics(stats); @@ -98,9 +98,9 @@ export class PerTargetBatchData { this.target = target; } - public dispose(): void { + public [Symbol.dispose](): void { this._thematicSensors = dispose(this._thematicSensors); - this._contours = this._contours?.dispose(); + this._contours = this._contours?.[Symbol.dispose](); for (const value of this._featureOverrides.values()) dispose(value); @@ -133,7 +133,7 @@ export class PerTargetBatchData { public getContours(batch: Batch): Contours { if (this._contours && !this._contours.matchesTargetAndFeatureCount(this.target, batch.featureTable)) - this._contours = this._contours.dispose(); + this._contours = this._contours[Symbol.dispose](); if (!this._contours) { this._contours = Contours.createFromTarget(this.target, batch.options); @@ -162,7 +162,7 @@ export class PerTargetBatchData { const ovrs = this._featureOverrides.get(source); if (ovrs) { this._featureOverrides.delete(source); - ovrs.dispose(); + ovrs[Symbol.dispose](); } } } @@ -176,10 +176,10 @@ export class PerTargetData { this._batch = batch; } - public dispose(): void { + public [Symbol.dispose](): void { for (const data of this._data) { data.target.onBatchDisposed(this._batch); - data.dispose(); + data[Symbol.dispose](); } this._data.length = 0; @@ -198,7 +198,7 @@ export class PerTargetData { return; const data = this._data[index]; - data.dispose(); + data[Symbol.dispose](); this._data.splice(index, 1); } @@ -289,7 +289,7 @@ export class Batch extends Graphic { public dispose() { dispose(this.graphic); - this.perTargetData.dispose(); + this.perTargetData[Symbol.dispose](); this._isDisposed = true; } @@ -392,7 +392,7 @@ export class Branch extends Graphic { } public dispose() { - this.branch.dispose(); + this.branch[Symbol.dispose](); } public override get isPickable(): boolean { @@ -445,7 +445,7 @@ export class AnimationTransformBranch extends Graphic { } public override dispose() { - this.graphic.dispose(); + this.graphic[Symbol.dispose](); } public override get isDisposed() { diff --git a/core/frontend/src/render/webgl/IndexedEdgeGeometry.ts b/core/frontend/src/render/webgl/IndexedEdgeGeometry.ts index deaeb2dd6687..b209e8711042 100644 --- a/core/frontend/src/render/webgl/IndexedEdgeGeometry.ts +++ b/core/frontend/src/render/webgl/IndexedEdgeGeometry.ts @@ -37,7 +37,7 @@ export class EdgeLUT implements WebGLDisposable { this.silhouettePadding = silhouettePadding; } - public dispose(): void { + public [Symbol.dispose](): void { dispose(this.texture); } @@ -76,7 +76,7 @@ export class IndexedEdgeGeometry extends MeshGeometry { this._indices = indices; } - public dispose(): void { + public [Symbol.dispose](): void { dispose(this._buffers); dispose(this._indices); dispose(this.edgeLut); diff --git a/core/frontend/src/render/webgl/InstancedGeometry.ts b/core/frontend/src/render/webgl/InstancedGeometry.ts index 8c8b8b54f690..ad2ab8b0fe41 100644 --- a/core/frontend/src/render/webgl/InstancedGeometry.ts +++ b/core/frontend/src/render/webgl/InstancedGeometry.ts @@ -110,7 +110,7 @@ export class InstanceBuffersData extends InstanceData { return new InstanceBuffersData(count, tfBuf, transformCenter, symBuf, idBuf, disableDisposal); } - public dispose(): void { + public [Symbol.dispose](): void { if (!this._noDispose) { dispose(this.transforms); dispose(this.featureIds); @@ -220,7 +220,7 @@ export class InstanceBuffers { return new InstanceBuffers(instances.buffers, range); } - public dispose() { + public [Symbol.dispose]() { dispose(this._data); } @@ -332,7 +332,7 @@ export class PatternBuffers extends InstanceData { return this.offsets.isDisposed; } - public dispose(): void { + public [Symbol.dispose](): void { dispose(this.offsets); } @@ -439,8 +439,8 @@ export class InstancedGeometry extends CachedGeometry { return !this._ownsBuffers || this._buffers.isDisposed; } - public dispose() { - this._repr.dispose(); + public [Symbol.dispose]() { + this._repr[Symbol.dispose](); if (this._ownsBuffers) dispose(this._buffers); } diff --git a/core/frontend/src/render/webgl/Layer.ts b/core/frontend/src/render/webgl/Layer.ts index 11151ae5d581..4a00a3026df4 100644 --- a/core/frontend/src/render/webgl/Layer.ts +++ b/core/frontend/src/render/webgl/Layer.ts @@ -23,7 +23,7 @@ abstract class GraphicWrapper extends Graphic { } public dispose(): void { - this.graphic.dispose(); + this.graphic[Symbol.dispose](); } public get isDisposed(): boolean { diff --git a/core/frontend/src/render/webgl/Mesh.ts b/core/frontend/src/render/webgl/Mesh.ts index 9a8f2ac1e4d3..46ee0ed3bd14 100644 --- a/core/frontend/src/render/webgl/Mesh.ts +++ b/core/frontend/src/render/webgl/Mesh.ts @@ -63,7 +63,7 @@ export class MeshRenderGeometry implements RenderGeometry { return data ? new this(data, params) : undefined; } - public dispose() { + public [Symbol.dispose]() { if (this.noDispose) { return; } diff --git a/core/frontend/src/render/webgl/MeshData.ts b/core/frontend/src/render/webgl/MeshData.ts index bd72698aba18..c4f072866e4a 100644 --- a/core/frontend/src/render/webgl/MeshData.ts +++ b/core/frontend/src/render/webgl/MeshData.ts @@ -101,10 +101,10 @@ export class MeshData implements WebGLDisposable { public get isDisposed(): boolean { return undefined === this.texture && this.lut.isDisposed; } - public dispose() { + public [Symbol.dispose]() { dispose(this.lut); if (this._ownsTexture) - this.texture!.dispose(); + this.texture![Symbol.dispose](); } public get isGlyph() { return undefined !== this.texture && this.texture.isGlyph; } diff --git a/core/frontend/src/render/webgl/PlanarClassifier.ts b/core/frontend/src/render/webgl/PlanarClassifier.ts index c2d0484635f3..1bc20b7f2e18 100644 --- a/core/frontend/src/render/webgl/PlanarClassifier.ts +++ b/core/frontend/src/render/webgl/PlanarClassifier.ts @@ -64,7 +64,7 @@ class ClassifierTextures implements WebGLDisposable { && this.hilite.isDisposed; } - public dispose(): void { + public [Symbol.dispose](): void { dispose(this.color); dispose(this.feature); dispose(this.hilite); @@ -105,7 +105,7 @@ class ClassifierFrameBuffers implements WebGLDisposable { return this.textures.isDisposed && this._hilite.isDisposed && this._fbo.isDisposed && this._clearGeom.isDisposed; } - public dispose(): void { + public [Symbol.dispose](): void { dispose(this._fbo); dispose(this._clearGeom); dispose(this.textures); @@ -161,7 +161,7 @@ abstract class SingleTextureFrameBuffer implements WebGLDisposable { this.texture = textureAndFbo.texture; this.fbo = textureAndFbo.fbo; } - public dispose(): void { + public [Symbol.dispose](): void { dispose(this.texture); dispose(this.fbo); } @@ -335,7 +335,7 @@ export class PlanarClassifier extends RenderPlanarClassifier implements RenderMe public get isDisposed(): boolean { return undefined === this._classifierBuffers; } - public dispose() { + public [Symbol.dispose]() { this._classifierBuffers = dispose(this._classifierBuffers); this._maskBuffer = dispose(this._maskBuffer); this._classifierCombinedBuffer = dispose(this._classifierCombinedBuffer); @@ -410,7 +410,7 @@ export class PlanarClassifier extends RenderPlanarClassifier implements RenderMe const requiredWidth = maxTextureSize; if (requiredWidth !== this._width || requiredHeight !== this._height) - this.dispose(); + this[Symbol.dispose](); this._width = requiredWidth; this._height = requiredHeight; @@ -470,11 +470,11 @@ export class PlanarClassifier extends RenderPlanarClassifier implements RenderMe builder.setSymbology(ColorDef.blue, ColorDef.blue, 2); builder.addFrustum(this._frustum); - builder.setSymbology(ColorDef.from(0,200,0,222), ColorDef.from(0,200,0,222), 2); + builder.setSymbology(ColorDef.from(0, 200, 0, 222), ColorDef.from(0, 200, 0, 222), 2); builder.addFrustumSides(context.viewingSpace.getFrustum()); - builder.setSymbology(ColorDef.from(200,0,0,222), ColorDef.from(200,0,0,222), 2); + builder.setSymbology(ColorDef.from(200, 0, 0, 222), ColorDef.from(200, 0, 0, 222), 2); builder.addFrustumSides(this._debugFrustum!); - builder.setSymbology(ColorDef.from(0,0,200,222), ColorDef.from(0,0,200,222), 2); + builder.setSymbology(ColorDef.from(0, 0, 200, 222), ColorDef.from(0, 0, 200, 222), 2); builder.addFrustumSides(this._frustum); this._debugFrustumGraphic = builder.finish(); context.outputGraphic(this._debugFrustumGraphic); diff --git a/core/frontend/src/render/webgl/PointCloud.ts b/core/frontend/src/render/webgl/PointCloud.ts index b7bc831af47b..c32d116120f8 100644 --- a/core/frontend/src/render/webgl/PointCloud.ts +++ b/core/frontend/src/render/webgl/PointCloud.ts @@ -41,7 +41,7 @@ export class PointCloudGeometry extends CachedGeometry implements RenderGeometry public override get supportsThematicDisplay() { return true; } public get overrideColorMix() { return .5; } // This could be a setting from either the mesh or the override if required. - public dispose() { + public [Symbol.dispose]() { if (!this.noDispose) { dispose(this.buffers); dispose(this._vertices); diff --git a/core/frontend/src/render/webgl/PointString.ts b/core/frontend/src/render/webgl/PointString.ts index fdefe2844805..5b878e471ef3 100644 --- a/core/frontend/src/render/webgl/PointString.ts +++ b/core/frontend/src/render/webgl/PointString.ts @@ -89,7 +89,7 @@ export class PointStringGeometry extends LUTGeometry implements RenderGeometry { && this.indices.isDisposed; } - public dispose() { + public [Symbol.dispose]() { if (!this.noDispose) { dispose(this.buffers); dispose(this.lut); diff --git a/core/frontend/src/render/webgl/Polyline.ts b/core/frontend/src/render/webgl/Polyline.ts index eeea0c96bfcc..c78ae657b8c1 100644 --- a/core/frontend/src/render/webgl/Polyline.ts +++ b/core/frontend/src/render/webgl/Polyline.ts @@ -57,7 +57,7 @@ export class PolylineGeometry extends LUTGeometry implements RenderGeometry { public get isDisposed(): boolean { return this._buffers.isDisposed && this.lut.isDisposed; } - public dispose() { + public [Symbol.dispose]() { if (!this.noDispose) { dispose(this.lut); dispose(this._buffers); diff --git a/core/frontend/src/render/webgl/RealityMesh.ts b/core/frontend/src/render/webgl/RealityMesh.ts index 2e51a0b961a7..3aaa6ddbbe12 100644 --- a/core/frontend/src/render/webgl/RealityMesh.ts +++ b/core/frontend/src/render/webgl/RealityMesh.ts @@ -7,7 +7,7 @@ * @module WebGL */ -import { assert, dispose, disposeArray, IDisposable, UintArray } from "@itwin/core-bentley"; +import { assert, dispose, disposeArray, UintArray } from "@itwin/core-bentley"; import { ColorDef, Quantization, RenderTexture } from "@itwin/core-common"; import { Matrix4d, Range2d, Range3d, Transform, Vector2d } from "@itwin/core-geometry"; import { GraphicBranch } from "../GraphicBranch"; @@ -45,11 +45,11 @@ class ProjectedTexture { } type TerrainOrProjectedTexture = TerrainTexture | ProjectedTexture; -class RealityTextureParam implements IDisposable { +class RealityTextureParam implements Disposable { constructor(public texture: RenderTexture | undefined, private _projectedTextureOrMatrix: ProjectedTexture | Matrix4) { } public get isProjected() { return this._projectedTextureOrMatrix instanceof ProjectedTexture; } - public dispose(): void { + public [Symbol.dispose](): void { this.texture = dispose(this.texture); } @@ -120,7 +120,7 @@ class RealityTextureParam implements IDisposable { } /** @internal */ -export class RealityTextureParams implements IDisposable { +export class RealityTextureParams implements Disposable { constructor(public params: RealityTextureParam[]) { } public static create(textures: TerrainOrProjectedTexture[]) { const maxTexturesPerMesh = System.instance.maxRealityImageryLayers; @@ -167,7 +167,7 @@ export class RealityTextureParams implements IDisposable { return new RealityTextureParams(textureParams); } - public dispose(): void { + public [Symbol.dispose](): void { disposeArray(this.params); } } @@ -221,8 +221,8 @@ export class RealityMeshGeometryParams extends IndexedGeometryParams { } public get bytesUsed(): number { return this.positions.bytesUsed + (undefined === this.normals ? 0 : this.normals.bytesUsed) + this.uvParams.bytesUsed + this.indices.bytesUsed; } - public override dispose() { - super.dispose(); + public override[Symbol.dispose]() { + super[Symbol.dispose](); dispose(this.uvParams); } } @@ -273,12 +273,12 @@ export class RealityMeshGeometry extends IndexedGeometry implements RenderGeomet this._indexType = 1 === bytesPerIndex ? GL.DataType.UnsignedByte : (2 === bytesPerIndex ? GL.DataType.UnsignedShort : GL.DataType.UnsignedInt); } - public override dispose() { + public override[Symbol.dispose]() { if (this.noDispose) { return; } - super.dispose(); + super[Symbol.dispose](); dispose(this._realityMeshParams); if (true !== this._disableTextureDisposal) dispose(this.textureParams); @@ -384,7 +384,7 @@ export class RealityMeshGeometry extends IndexedGeometry implements RenderGeomet branch.add(system.createBatch(primitive!, featureTable, mesh.getRange(), { tileId })); } - return system.createBranch(branch, realityMesh._transform ? realityMesh._transform : Transform.createIdentity(), {disableClipStyle: params.disableClipStyle}); + return system.createBranch(branch, realityMesh._transform ? realityMesh._transform : Transform.createIdentity(), { disableClipStyle: params.disableClipStyle }); } public collectStatistics(stats: RenderMemory.Statistics): void { diff --git a/core/frontend/src/render/webgl/RenderBuffer.ts b/core/frontend/src/render/webgl/RenderBuffer.ts index 28587a16c548..6a881f473b91 100644 --- a/core/frontend/src/render/webgl/RenderBuffer.ts +++ b/core/frontend/src/render/webgl/RenderBuffer.ts @@ -47,7 +47,7 @@ export class RenderBuffer implements WebGLDisposable { public get isDisposed(): boolean { return this._glBuffer === undefined || this._glBuffer === null; } - public dispose(): void { + public [Symbol.dispose](): void { if (!this.isDisposed) { System.instance.context.deleteRenderbuffer(this._glBuffer!); this._glBuffer = undefined; @@ -110,7 +110,7 @@ export class RenderBufferMultiSample implements WebGLDisposable { public get isDisposed(): boolean { return this._glBuffer === undefined || this._glBuffer === null; } - public dispose(): void { + public [Symbol.dispose](): void { if (!this.isDisposed) { System.instance.context.deleteRenderbuffer(this._glBuffer!); this._glBuffer = undefined; diff --git a/core/frontend/src/render/webgl/SceneCompositor.ts b/core/frontend/src/render/webgl/SceneCompositor.ts index 5c25606c2625..68faf50498b7 100644 --- a/core/frontend/src/render/webgl/SceneCompositor.ts +++ b/core/frontend/src/render/webgl/SceneCompositor.ts @@ -96,7 +96,7 @@ class Textures implements WebGLDisposable, RenderMemory.Consumer { && undefined === this.volClassBlendMsBuff; } - public dispose() { + public [Symbol.dispose]() { this.accumulation = dispose(this.accumulation); this.revealage = dispose(this.revealage); this.color = dispose(this.color); @@ -463,7 +463,7 @@ class FrameBuffers implements WebGLDisposable { && undefined === this.idsAndAltZComposite && undefined === this.edlDrawCol; } - public dispose() { + public [Symbol.dispose]() { this.opaqueColor = dispose(this.opaqueColor); this.opaqueAndCompositeColor = dispose(this.opaqueAndCompositeColor); this.depthAndOrder = dispose(this.depthAndOrder); @@ -584,7 +584,7 @@ class Geometry implements WebGLDisposable, RenderMemory.Consumer { && undefined === this.clearTranslucent && undefined === this.clearPickAndColor; } - public dispose() { + public [Symbol.dispose]() { this.composite = dispose(this.composite); this.occlusion = dispose(this.occlusion); this.occlusionXBlur = dispose(this.occlusionXBlur); @@ -808,7 +808,7 @@ export abstract class SceneCompositor implements WebGLDisposable, RenderMemory.C protected _needHiddenEdges: boolean; public abstract get isDisposed(): boolean; - public abstract dispose(): void; + public abstract [Symbol.dispose](): void; public abstract preDraw(): void; public abstract draw(_commands: RenderCommands): void; public abstract drawForReadPixels(_commands: RenderCommands, sceneOverlays: GraphicList, worldOverlayDecorations: GraphicList | undefined, viewOverlayDecorations: GraphicList | undefined): void; @@ -1307,7 +1307,7 @@ class Compositor extends SceneCompositor { this._geom.disableVolumeClassifier(); this._textures.disableVolumeClassifier(); if (undefined !== this._vcAltDepthStencil) { - this._vcAltDepthStencil.dispose(); + this._vcAltDepthStencil[Symbol.dispose](); this._vcAltDepthStencil = undefined; } this._haveVolumeClassifier = false; @@ -1376,7 +1376,7 @@ class Compositor extends SceneCompositor { this._geom.disableVolumeClassifier(); this._textures.disableVolumeClassifier(); if (undefined !== this._vcAltDepthStencil) { - this._vcAltDepthStencil.dispose(); + this._vcAltDepthStencil[Symbol.dispose](); this._vcAltDepthStencil = undefined; } this._haveVolumeClassifier = false; @@ -1643,7 +1643,7 @@ class Compositor extends SceneCompositor { && this.eyeDomeLighting.isDisposed; } - public dispose() { + public [Symbol.dispose]() { this.reset(); dispose(this.solarShadowMap); dispose(this.eyeDomeLighting); diff --git a/core/frontend/src/render/webgl/ScreenSpaceEffect.ts b/core/frontend/src/render/webgl/ScreenSpaceEffect.ts index adeee3a6be54..6ebf9f572c84 100644 --- a/core/frontend/src/render/webgl/ScreenSpaceEffect.ts +++ b/core/frontend/src/render/webgl/ScreenSpaceEffect.ts @@ -149,7 +149,7 @@ export class ScreenSpaceEffects { this._copyGeometry = copyGeometry; } - public dispose(): void { + public [Symbol.dispose](): void { dispose(this._effectGeometry); dispose(this._copyGeometry); } @@ -239,7 +239,7 @@ export class ScreenSpaceEffects { system.techniques.draw(effectParams); }); - effectFbo.dispose(); + effectFbo[Symbol.dispose](); } } } diff --git a/core/frontend/src/render/webgl/ShaderProgram.ts b/core/frontend/src/render/webgl/ShaderProgram.ts index 42b199b6fef7..5bff3e9486c6 100644 --- a/core/frontend/src/render/webgl/ShaderProgram.ts +++ b/core/frontend/src/render/webgl/ShaderProgram.ts @@ -151,7 +151,7 @@ export class ShaderProgram implements WebGLDisposable { public get isDisposed(): boolean { return this._glProgram === undefined; } - public dispose(): void { + public [Symbol.dispose](): void { if (!this.isDisposed) { assert(!this._inUse); System.instance.context.deleteProgram(this._glProgram!); @@ -160,6 +160,11 @@ export class ShaderProgram implements WebGLDisposable { } } + /** @deprecated in 5.0 Use [Symbol.dispose] instead. */ + public dispose(): void { + this[Symbol.dispose](); + } + public get glProgram(): WebGLProgram | undefined { return this._glProgram; } public get isUncompiled() { return CompileStatus.Uncompiled === this._status; } public get isCompiled() { return CompileStatus.Success === this._status; } @@ -653,7 +658,7 @@ export class ShaderProgram implements WebGLDisposable { /** Context in which ShaderPrograms are executed. Avoids switching shaders unnecessarily. * Ensures shader programs are compiled before use and un-bound when scope is disposed. - * This class must *only* be used inside a using() function! + * Instances of this class must *only* be declared with the `using` keyword! * @internal */ export class ShaderProgramExecutor { @@ -673,12 +678,17 @@ export class ShaderProgramExecutor { public get isDisposed(): boolean { return this._isDisposed; } /** Clears the current program to be executed. This does not free WebGL resources, since those are owned by Techniques. */ - public dispose() { + public [Symbol.dispose]() { this.changeProgram(undefined); ShaderProgramExecutor.freeParams(); this._isDisposed = true; } + /** @deprecated in 5.0 Use [Symbol.dispose] instead. */ + public dispose() { + this[Symbol.dispose](); + } + public setProgram(program: ShaderProgram): boolean { return this.changeProgram(program); } public get isValid() { return undefined !== this._program; } public get target() { return this.params.target; } diff --git a/core/frontend/src/render/webgl/SolarShadowMap.ts b/core/frontend/src/render/webgl/SolarShadowMap.ts index 6ff9b612cf04..476d1435368f 100644 --- a/core/frontend/src/render/webgl/SolarShadowMap.ts +++ b/core/frontend/src/render/webgl/SolarShadowMap.ts @@ -163,7 +163,7 @@ class Bundle implements WebGLDisposable { && this.evsmGeom.isDisposed; } - public dispose(): void { + public [Symbol.dispose](): void { dispose(this.depthTexture); dispose(this.shadowMapTexture); dispose(this.fbo); @@ -266,14 +266,14 @@ export class SolarShadowMap implements RenderMemory.Consumer, WebGLDisposable { public get isDisposed(): boolean { return undefined === this._bundle && 0 === this._graphics.length; } - public dispose() { + public [Symbol.dispose]() { this._bundle = dispose(this._bundle); this.clearGraphics(true); } private clearGraphics(notify: boolean) { for (const graphic of this._graphics) - graphic.dispose(); + graphic[Symbol.dispose](); this._graphics.length = 0; if (notify) diff --git a/core/frontend/src/render/webgl/SurfaceGeometry.ts b/core/frontend/src/render/webgl/SurfaceGeometry.ts index 7c1558d9c9c7..023a01a8c4d6 100644 --- a/core/frontend/src/render/webgl/SurfaceGeometry.ts +++ b/core/frontend/src/render/webgl/SurfaceGeometry.ts @@ -49,7 +49,7 @@ export class SurfaceGeometry extends MeshGeometry { && this._indices.isDisposed; } - public dispose() { + public [Symbol.dispose]() { dispose(this._buffers); dispose(this._indices); } diff --git a/core/frontend/src/render/webgl/System.ts b/core/frontend/src/render/webgl/System.ts index 83b6bf61fc02..d28a8f8daa80 100644 --- a/core/frontend/src/render/webgl/System.ts +++ b/core/frontend/src/render/webgl/System.ts @@ -104,7 +104,7 @@ export class IdMap implements WebGLDisposable { return 0 === this.textures.size && 0 === this.gradients.size; } - public dispose() { + public [Symbol.dispose]() { const textureArr = Array.from(this.textures.values()); const gradientArr = this.gradients.extractArrays().values; diff --git a/core/frontend/src/render/webgl/Target.ts b/core/frontend/src/render/webgl/Target.ts index d22e9b623a7b..ea62e25e64a9 100644 --- a/core/frontend/src/render/webgl/Target.ts +++ b/core/frontend/src/render/webgl/Target.ts @@ -6,7 +6,7 @@ * @module WebGL */ -import { assert, dispose, Id64, Id64String, IDisposable } from "@itwin/core-bentley"; +import { assert, dispose, Id64, Id64String } from "@itwin/core-bentley"; import { Point2d, Point3d, Range3d, Transform, XAndY, XYZ } from "@itwin/core-geometry"; import { AmbientOcclusion, AnalysisStyle, Frustum, ImageBuffer, ImageBufferFormat, Npc, RenderMode, RenderTexture, ThematicDisplayMode, ViewFlags, @@ -295,14 +295,14 @@ export abstract class Target extends RenderTarget implements RenderTargetDebugCo const depth = System.instance.createDepthBuffer(rect.width, rect.height, 1); if (undefined === depth) { - color.dispose(); + color[Symbol.dispose](); return undefined; } this._fbo = FrameBuffer.create([color], depth); if (undefined === this._fbo) { - color.dispose(); - depth.dispose(); + color[Symbol.dispose](); + depth[Symbol.dispose](); return undefined; } @@ -326,7 +326,7 @@ export abstract class Target extends RenderTarget implements RenderTargetDebugCo dispose(db); } - public override dispose() { + public override[Symbol.dispose]() { this.reset(); this.disposeFbo(); dispose(this._compositor); @@ -441,11 +441,11 @@ export abstract class Target extends RenderTarget implements RenderTargetDebugCo }); } - private changeDrapesOrClassifiers(oldMap: Map | undefined, newMap: Map | undefined): void { + private changeDrapesOrClassifiers(oldMap: Map | undefined, newMap: Map | undefined): void { if (undefined === newMap) { if (undefined !== oldMap) for (const value of oldMap.values()) - value.dispose(); + value[Symbol.dispose](); return; } @@ -453,7 +453,7 @@ export abstract class Target extends RenderTarget implements RenderTargetDebugCo if (undefined !== oldMap) { for (const entry of oldMap) if (newMap.get(entry[0]) !== entry[1]) - entry[1].dispose(); + entry[1][Symbol.dispose](); } } public changeTextureDrapes(textureDrapes: TextureDrapeMap | undefined) { @@ -557,7 +557,7 @@ export abstract class Target extends RenderTarget implements RenderTargetDebugCo * The primary difference is that in the former case we retain the SceneCompositor. */ public override reset(): void { - this.graphics.dispose(); + this.graphics[Symbol.dispose](); this._worldDecorations = dispose(this._worldDecorations); dispose(this.uniforms.thematic); @@ -1331,11 +1331,11 @@ export class OnScreenTarget extends Target { && super.isDisposed; } - public override dispose() { + public override[Symbol.dispose]() { this._blitGeom = dispose(this._blitGeom); this._scratchProgParams = undefined; this._scratchDrawParams = undefined; - super.dispose(); + super[Symbol.dispose](); } public override collectStatistics(stats: RenderMemory.Statistics): void { diff --git a/core/frontend/src/render/webgl/TargetGraphics.ts b/core/frontend/src/render/webgl/TargetGraphics.ts index 7c56d2882626..38616f4661df 100644 --- a/core/frontend/src/render/webgl/TargetGraphics.ts +++ b/core/frontend/src/render/webgl/TargetGraphics.ts @@ -22,7 +22,7 @@ export class TargetGraphics { private _dynamics?: GraphicList; private _decorations?: Decorations; - public dispose(): void { + public [Symbol.dispose](): void { this.foreground.length = this.background.length = this.overlays.length = 0; this._dynamics = disposeArray(this._dynamics); this._decorations = dispose(this._decorations); diff --git a/core/frontend/src/render/webgl/Technique.ts b/core/frontend/src/render/webgl/Technique.ts index 030798b93b74..11a1772dfe8f 100644 --- a/core/frontend/src/render/webgl/Technique.ts +++ b/core/frontend/src/render/webgl/Technique.ts @@ -6,7 +6,7 @@ * @module WebGL */ -import { assert, dispose, using } from "@itwin/core-bentley"; +import { assert, dispose } from "@itwin/core-bentley"; import { BlurType } from "./CachedGeometry"; import { ClippingProgram, createClippingProgram } from "./ClippingProgram"; import { WebGLDisposable } from "./Disposable"; @@ -82,8 +82,13 @@ export class SingularTechnique implements Technique { public get isDisposed(): boolean { return this.program.isDisposed; } + public [Symbol.dispose](): void { + this.program[Symbol.dispose](); + } + + /** @deprecated in 5.0 Use [Symbol.dispose] instead. */ public dispose(): void { - dispose(this.program); + this[Symbol.dispose](); } } @@ -136,25 +141,31 @@ export abstract class VariedTechnique implements Technique { private _isDisposed = false; public get isDisposed(): boolean { return this._isDisposed; } - public dispose(): void { + public [Symbol.dispose](): void { if (this._isDisposed) return; for (const program of this._basicPrograms) { assert(undefined !== program); - dispose(program); + program[Symbol.dispose](); } this._basicPrograms.length = 0; for (const clipShaderObj of this._clippingPrograms) { assert(undefined !== clipShaderObj); - clipShaderObj.dispose(); + clipShaderObj[Symbol.dispose](); } this._clippingPrograms.length = 0; this._isDisposed = true; } + /** @deprecated in 5.0 Use [Symbol.dispose] instead. */ + public dispose(): void { + this[Symbol.dispose](); + } + + protected constructor(numPrograms: number) { this._basicPrograms.length = numPrograms; } @@ -773,7 +784,7 @@ abstract class MultipleTechnique implements Technique { return allCompiled; } - public dispose(): void { + public [Symbol.dispose](): void { if (this._isDisposed) return; @@ -955,10 +966,10 @@ export class Techniques implements WebGLDisposable { public execute(target: Target, commands: DrawCommands, renderPass: RenderPass) { assert(RenderPass.None !== renderPass, "invalid render pass"); - using(new ShaderProgramExecutor(target, renderPass), (executor: ShaderProgramExecutor) => { - for (const command of commands) - command.execute(executor); - }); + using executor = new ShaderProgramExecutor(target, renderPass); + for (const command of commands) + command.execute(executor); + System.instance.frameBufferStack.markTargetsDirty(); } @@ -972,23 +983,28 @@ export class Techniques implements WebGLDisposable { public draw(params: DrawParams): void { const tech = this.getTechnique(params.geometry.techniqueId); const program = tech.getShader(TechniqueFlags.defaults); - using(new ShaderProgramExecutor(params.target, params.renderPass, program), (executor: ShaderProgramExecutor) => { - assert(executor.isValid); - if (executor.isValid) { - executor.draw(params); - } - }); + + using executor = new ShaderProgramExecutor(params.target, params.renderPass, program); + assert(executor.isValid); + if (executor.isValid) { + executor.draw(params); + } System.instance.frameBufferStack.markTargetsDirty(); } public get isDisposed(): boolean { return 0 === this._list.length; } - public dispose(): void { + public [Symbol.dispose](): void { for (const tech of this._list) dispose(tech); this._list.length = 0; } + /** @deprecated in 5.0 Use [Symbol.dispose] instead. */ + public dispose(): void { + this[Symbol.dispose](); + } + // Chiefly for tests - compiles all shader programs - more generally programs are compiled on demand. public compileShaders(): boolean { let allCompiled = true; diff --git a/core/frontend/src/render/webgl/Texture.ts b/core/frontend/src/render/webgl/Texture.ts index 1bfd11ac65d8..16ce01ec176e 100644 --- a/core/frontend/src/render/webgl/Texture.ts +++ b/core/frontend/src/render/webgl/Texture.ts @@ -367,7 +367,7 @@ export abstract class TextureHandle implements WebGLDisposable { public get isDisposed(): boolean { return this._glTexture === undefined; } - public dispose() { + public [Symbol.dispose]() { if (!this.isDisposed) { System.instance.disposeTexture(this._glTexture!); this._glTexture = undefined; diff --git a/core/frontend/src/render/webgl/TextureDrape.ts b/core/frontend/src/render/webgl/TextureDrape.ts index 48f6f6192ac0..afe1385f7065 100644 --- a/core/frontend/src/render/webgl/TextureDrape.ts +++ b/core/frontend/src/render/webgl/TextureDrape.ts @@ -30,7 +30,7 @@ export abstract class TextureDrape implements RenderTextureDrape, RenderMemory.C public get isDisposed(): boolean { return undefined === this.texture; } - public dispose() { + public [Symbol.dispose]() { this._texture = dispose(this._texture); } diff --git a/core/frontend/src/render/webgl/ThematicSensors.ts b/core/frontend/src/render/webgl/ThematicSensors.ts index 6cd09e628b77..cf8392603fc0 100644 --- a/core/frontend/src/render/webgl/ThematicSensors.ts +++ b/core/frontend/src/render/webgl/ThematicSensors.ts @@ -63,7 +63,7 @@ export class ThematicSensors implements WebGLDisposable { public get isDisposed(): boolean { return this._texture.handle.isDisposed; } - public dispose(): void { + public [Symbol.dispose](): void { dispose(this._texture.handle); } diff --git a/core/frontend/src/render/webgl/ThematicUniforms.ts b/core/frontend/src/render/webgl/ThematicUniforms.ts index ebf40611addf..0b4908ebf630 100644 --- a/core/frontend/src/render/webgl/ThematicUniforms.ts +++ b/core/frontend/src/render/webgl/ThematicUniforms.ts @@ -200,7 +200,7 @@ export class ThematicUniforms implements WebGLDisposable { return undefined === this._texture && undefined === this._sensors; } - public dispose() { + public [Symbol.dispose]() { this._texture = dispose(this._texture); this._sensors = dispose(this._sensors); } diff --git a/core/frontend/src/render/webgl/VertexLUT.ts b/core/frontend/src/render/webgl/VertexLUT.ts index e61fb10922db..0cee520e4ae6 100644 --- a/core/frontend/src/render/webgl/VertexLUT.ts +++ b/core/frontend/src/render/webgl/VertexLUT.ts @@ -55,7 +55,7 @@ export class AuxChannelLUT implements WebGLDisposable { public get isDisposed(): boolean { return this.texture.isDisposed; } - public dispose() { + public [Symbol.dispose]() { dispose(this.texture); } @@ -115,7 +115,7 @@ export class VertexLUT implements WebGLDisposable { public get isDisposed(): boolean { return this.texture.isDisposed; } - public dispose() { + public [Symbol.dispose]() { dispose(this.texture); } } diff --git a/core/frontend/src/render/webgl/VisibleTileFeatures.ts b/core/frontend/src/render/webgl/VisibleTileFeatures.ts index 05a44ebac083..755c87903b75 100644 --- a/core/frontend/src/render/webgl/VisibleTileFeatures.ts +++ b/core/frontend/src/render/webgl/VisibleTileFeatures.ts @@ -67,35 +67,32 @@ function isFeatureVisible(feature: PackedFeature, target: Target, includeNonLoca function* commandIterator(features: VisibleTileFeatures, pass: RenderPass) { const commands = features.renderCommands.getCommands(pass); - const executor = new ShaderProgramExecutor(features.target, pass); - try { - for (const command of commands) { - if (command.opcode !== "drawPrimitive") - command.execute(executor); + using executor = new ShaderProgramExecutor(features.target, pass); + + for (const command of commands) { + if (command.opcode !== "drawPrimitive") + command.execute(executor); - if (command.opcode !== "pushBatch") - continue; + if (command.opcode !== "pushBatch") + continue; - const ovrs = command.batch.getOverrides(features.target); - if (ovrs.allHidden) - continue; + const ovrs = command.batch.getOverrides(features.target); + if (ovrs.allHidden) + continue; - const scratchFeature = PackedFeature.createWithIndex(); - const table = command.batch.featureTable; - for (const feature of table.iterable(scratchFeature)) { - if (!ovrs.anyOverridden || isFeatureVisible(feature, features.target, features.includeNonLocatable)) { - yield { - elementId: Id64.fromUint32PairObject(feature.elementId), - subCategoryId: Id64.fromUint32PairObject(feature.subCategoryId), - geometryClass: feature.geometryClass, - modelId: Id64.fromUint32PairObject(feature.modelId), - iModel: command.batch.batchIModel ?? features.iModel, - }; - } + const scratchFeature = PackedFeature.createWithIndex(); + const table = command.batch.featureTable; + for (const feature of table.iterable(scratchFeature)) { + if (!ovrs.anyOverridden || isFeatureVisible(feature, features.target, features.includeNonLocatable)) { + yield { + elementId: Id64.fromUint32PairObject(feature.elementId), + subCategoryId: Id64.fromUint32PairObject(feature.subCategoryId), + geometryClass: feature.geometryClass, + modelId: Id64.fromUint32PairObject(feature.modelId), + iModel: command.batch.batchIModel ?? features.iModel, + }; } } - } finally { - executor.dispose(); } } diff --git a/core/frontend/src/test/SpatialViewState.test.ts b/core/frontend/src/test/SpatialViewState.test.ts index 66ef00e8dab2..95b86d1e439a 100644 --- a/core/frontend/src/test/SpatialViewState.test.ts +++ b/core/frontend/src/test/SpatialViewState.test.ts @@ -42,7 +42,7 @@ describe("SpatialViewState", () => { tileTree: undefined, loadStatus: TileTreeLoadStatus.NotLoaded, load: () => undefined, - dispose: () => undefined, + [Symbol.dispose]: () => undefined, loadTree: async () => Promise.resolve(undefined), }; } diff --git a/core/frontend/src/test/ViewManager.test.ts b/core/frontend/src/test/ViewManager.test.ts index 59754f8b61a5..99666b7f7461 100644 --- a/core/frontend/src/test/ViewManager.test.ts +++ b/core/frontend/src/test/ViewManager.test.ts @@ -25,14 +25,13 @@ describe("ViewManager", () => { }); it("should resize fbo properly after dropping a recently-resized viewport", async () => { - const vp = openBlankViewport({ width: 32, height: 32 }); + using vp = openBlankViewport({ width: 32, height: 32 }); IModelApp.viewManager.addViewport(vp); vp.renderFrame(); vp.vpDiv.style.width = vp.vpDiv.style.height = "3px"; IModelApp.viewManager.dropViewport(vp, false); vp.renderFrame(); expect((vp.target as OnScreenTarget).checkFboDimensions()).toBe(true); - vp.dispose(); }); /** Dropping and immediately re-adding an unresized viewport to the view manager would result in a black rendering @@ -48,7 +47,7 @@ describe("ViewManager", () => { * This test verifies that this problem has been resolved. */ it("should not render black when dropping and re-adding viewport with same dimensions", async () => { - const vp = openBlankViewport({ width: 32, height: 32 }); + using vp = openBlankViewport({ width: 32, height: 32 }); vp.displayStyle.backgroundColor = ColorDef.red; IModelApp.viewManager.addViewport(vp); vp.renderFrame(); @@ -57,7 +56,6 @@ describe("ViewManager", () => { IModelApp.viewManager.addViewport(vp); vp.renderFrame(); expectColors(vp, [ColorDef.red]); - vp.dispose(); }); it("should dispose of viewport when onShutdown is called", async () => { diff --git a/core/frontend/src/test/Viewport.test.ts b/core/frontend/src/test/Viewport.test.ts index 853208dfc046..b3a707add146 100644 --- a/core/frontend/src/test/Viewport.test.ts +++ b/core/frontend/src/test/Viewport.test.ts @@ -54,9 +54,8 @@ describe("Viewport", () => { function test(ctor: (typeof ScreenVp | typeof OffScreenVp)): void { const iModel = createBlankConnection(); const view = SpatialViewState.createBlank(iModel, { x: 0, y: 0, z: 0 }, { x: 1, y: 1, z: 1 }); - const vp = ctor.createVp(view); + using vp = ctor.createVp(view); expect(vp.initialized).toBe(true); - vp.dispose(); } test(ScreenVp); @@ -205,7 +204,7 @@ describe("Viewport", () => { viewport.view.displayStyle = new DisplayStyle3dState({} as any, viewport.iModel); expectBackgroundMap(false); expectTerrain(false); - viewport.dispose(); + viewport[Symbol.dispose](); }); it("updates when display style is assigned to", () => { @@ -566,13 +565,13 @@ describe("Viewport", () => { // BlankViewport.dispose also closes the iModel and removes the viewport's div from the DOM. // We don't want that until the test completes. - const dispose = vp.dispose; // eslint-disable-line @typescript-eslint/unbound-method - vp.dispose = ScreenViewport.prototype.dispose; // eslint-disable-line @typescript-eslint/unbound-method - vp.dispose(); + const dispose = vp[Symbol.dispose]; + vp[Symbol.dispose] = ScreenViewport.prototype[Symbol.dispose]; + vp[Symbol.dispose](); vp.readPixels(vp.viewRect, Pixel.Selector.All, (pixels) => expect(pixels).toBeUndefined()); - vp.dispose = dispose; + vp[Symbol.dispose] = dispose; }); }); @@ -711,7 +710,7 @@ describe("Viewport", () => { const stub = vi.spyOn(Viewport.prototype, "mapLayerFromIds").mockImplementation(function (_mapTreeId: Id64String, _layerTreeId: Id64String) { return []; }); - const fakePixelData = {modelId: "123", elementId: "456"}; + const fakePixelData = { modelId: "123", elementId: "456" }; expect(vp.isPixelSelectable(fakePixelData as any)).toBe(true); stub.mockRestore(); }); diff --git a/core/frontend/src/test/ViewportSync.test.ts b/core/frontend/src/test/ViewportSync.test.ts index 3eba71def9d3..2e329ed23341 100644 --- a/core/frontend/src/test/ViewportSync.test.ts +++ b/core/frontend/src/test/ViewportSync.test.ts @@ -29,8 +29,8 @@ describe("TwoWayViewportSync", () => { }); afterEach(() => { - vp1.dispose(); - vp2.dispose(); + vp1[Symbol.dispose](); + vp2[Symbol.dispose](); }); function isSameFrustum() { @@ -187,7 +187,7 @@ describe("connectViewports", () => { afterEach(() => { for (const vp of vps) - vp.dispose(); + vp[Symbol.dispose](); vps.length = 0; }); diff --git a/core/frontend/src/test/openBlankViewport.ts b/core/frontend/src/test/openBlankViewport.ts index f7c7cfba9ccb..95803821b62c 100644 --- a/core/frontend/src/test/openBlankViewport.ts +++ b/core/frontend/src/test/openBlankViewport.ts @@ -54,9 +54,9 @@ export function openBlankViewport(options?: BlankViewportOptions): ScreenViewpor class BlankViewport extends ScreenViewport { public ownedIModel?: BlankConnection; - public override dispose(): void { + public override[Symbol.dispose](): void { document.body.removeChild(this.parentDiv); - super.dispose(); + super[Symbol.dispose](); this.ownedIModel?.closeSync(); } } @@ -74,27 +74,19 @@ export type TestBlankViewportOptions = BlankViewportOptions & { test: (vp: Scree * @internal */ export function testBlankViewport(args: TestBlankViewportOptions | ((vp: ScreenViewport) => void)): void { - const vp = openBlankViewport(typeof args === "function" ? undefined : args); - try { - if (typeof args === "function") - args(vp); - else - args.test(vp); - } finally { - vp.dispose(); - } + using vp = openBlankViewport(typeof args === "function" ? undefined : args); + if (typeof args === "function") + args(vp); + else + args.test(vp); } /** Open a viewport for a blank spatial view, invoke a test function, then dispose of the viewport and remove it from the DOM. * @internal */ export async function testBlankViewportAsync(args: ((vp: ScreenViewport) => Promise)): Promise { - const vp = openBlankViewport(typeof args === "function" ? undefined : args); - try { - await args(vp); - } finally { - vp.dispose(); - } + using vp = openBlankViewport(typeof args === "function" ? undefined : args); + await args(vp); } function compareFeatures(lhs?: Feature, rhs?: Feature): number { @@ -250,7 +242,7 @@ export function readUniqueFeatures(vp: Viewport, readRect?: ViewRect, excludeNon features.insert(pixel.feature); } }, - readRect, excludeNonLocatable, excludedElements); + readRect, excludeNonLocatable, excludedElements); return features; } diff --git a/core/frontend/src/test/render/EnvironmentDecorations.test.ts b/core/frontend/src/test/render/EnvironmentDecorations.test.ts index 7d3fb287e8d7..f78dd130b47b 100644 --- a/core/frontend/src/test/render/EnvironmentDecorations.test.ts +++ b/core/frontend/src/test/render/EnvironmentDecorations.test.ts @@ -173,7 +173,7 @@ describe("EnvironmentDecorations", () => { expect(dec.sky.promise).toBeUndefined(); expect(dec.sky.params).toBeDefined(); - dec.dispose(); + dec[Symbol.dispose](); expect(disposed).toBe(true); expect(dec.ground).toBeUndefined(); expect(dec.sky.promise).toBeUndefined(); diff --git a/core/frontend/src/test/render/FrameStats.test.ts b/core/frontend/src/test/render/FrameStats.test.ts index afe04a954e0c..9ae40e0de250 100644 --- a/core/frontend/src/test/render/FrameStats.test.ts +++ b/core/frontend/src/test/render/FrameStats.test.ts @@ -25,16 +25,12 @@ describe("FrameStats", () => { }); function testViewport(width: number, height: number, callback: (vp: ScreenViewport) => void): void { - const vp = openBlankViewport({ width, height }); + using vp = openBlankViewport({ width, height }); vp.viewFlags = vp.viewFlags.copy({ acsTriad: false, grid: false }); IModelApp.viewManager.addViewport(vp); - try { - callback(vp); - } finally { - vp.dispose(); - } + callback(vp); } it("should receive frame statistics from render loop when enabled", async () => { diff --git a/core/frontend/src/test/render/GraphicBuilder.test.ts b/core/frontend/src/test/render/GraphicBuilder.test.ts index 0b4dbfac3f70..de66cef29915 100644 --- a/core/frontend/src/test/render/GraphicBuilder.test.ts +++ b/core/frontend/src/test/render/GraphicBuilder.test.ts @@ -38,7 +38,7 @@ describe("GraphicBuilder", () => { viewport = openBlankViewport(); }); - afterEach(() => viewport.dispose()); + afterEach(() => viewport[Symbol.dispose]()); afterAll(async () => { await imodel.close(); @@ -180,7 +180,7 @@ describe("GraphicBuilder", () => { } function createTriangle(): Point3d[] { - return [ new Point3d(0, 0, 0), new Point3d(100, 0, 0), new Point3d(0, 100, 0) ]; + return [new Point3d(0, 0, 0), new Point3d(100, 0, 0), new Point3d(0, 100, 0)]; } it("should preserve polyface normals", () => { @@ -199,7 +199,7 @@ describe("GraphicBuilder", () => { const gfBuilder = IModelApp.renderSystem.createGraphic({ placement: Transform.createIdentity(), type: GraphicType.WorldDecoration, viewport, wantNormals: requestNormals }); gfBuilder.addPolyface(pfBuilder.claimPolyface(), false); const gf = gfBuilder.finish(); - gf.dispose(); + gf[Symbol.dispose](); expect(createMeshInvoked).toBe(true); }; @@ -217,7 +217,7 @@ describe("GraphicBuilder", () => { const builder = IModelApp.renderSystem.createGraphic({ placement: Transform.createIdentity(), type: GraphicType.WorldDecoration, viewport, wantNormals }); builder.addShape(createTriangle()); const gf = builder.finish(); - gf.dispose(); + gf[Symbol.dispose](); expect(createMeshInvoked).toBe(true); }; @@ -260,7 +260,7 @@ describe("GraphicBuilder", () => { addToGraphic(builder); const gf = builder.finish(); - gf.dispose(); + gf[Symbol.dispose](); expect(createMeshInvoked).toBe(true); } diff --git a/core/frontend/src/test/render/GraphicTemplate.test.ts b/core/frontend/src/test/render/GraphicTemplate.test.ts index aa32a681f33b..933ad1200a4b 100644 --- a/core/frontend/src/test/render/GraphicTemplate.test.ts +++ b/core/frontend/src/test/render/GraphicTemplate.test.ts @@ -38,7 +38,7 @@ describe("GraphicTemplate", () => { expectDisposed(template, false); const graphic = IModelApp.renderSystem.createGraphicFromTemplate({ template }); - graphic.dispose(); + graphic[Symbol.dispose](); expectDisposed(template, false); }); diff --git a/core/frontend/src/test/render/RenderGraphic.test.ts b/core/frontend/src/test/render/RenderGraphic.test.ts index 4f2669292a6a..b8bb4d3e04d7 100644 --- a/core/frontend/src/test/render/RenderGraphic.test.ts +++ b/core/frontend/src/test/render/RenderGraphic.test.ts @@ -2,20 +2,19 @@ * Copyright (c) Bentley Systems, Incorporated. All rights reserved. * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ -/* eslint-disable @typescript-eslint/unbound-method */ + import { describe, expect, it } from "vitest"; -import { IDisposable } from "@itwin/core-bentley"; import { Transform } from "@itwin/core-geometry"; import { ElementAlignedBox3d, RenderFeatureTable } from "@itwin/core-common"; import { GraphicBranch, GraphicBranchOptions } from "../../render/GraphicBranch"; import { MockRender } from "../../render/MockRender"; import { RenderGraphic } from "../../render/RenderGraphic"; -function addIsDisposed(disposable: IDisposable): void { +function addIsDisposed(disposable: Disposable): void { (disposable as any).isDisposed = false; - const dispose = disposable.dispose; - disposable.dispose = () => { + const dispose = disposable[Symbol.dispose]; + disposable[Symbol.dispose] = () => { (disposable as any).isDisposed = true; dispose.call(disposable); }; @@ -28,9 +27,9 @@ class Branch extends GraphicBranch { super(ownsEntries); } - public override dispose() { + public override[Symbol.dispose]() { this.isDisposed = true; - super.dispose(); + super[Symbol.dispose](); } } @@ -78,8 +77,8 @@ describe("RenderGraphic", () => { const owned = system.makeGraphic(); const owner = system.createGraphicOwner(owned); - unowned.dispose(); - owner.dispose(); + unowned[Symbol.dispose](); + owner[Symbol.dispose](); expect(isDisposed(unowned)).toBe(true); expect(isDisposed(owner)).toBe(true); @@ -101,12 +100,12 @@ describe("GraphicBranch", () => { const branch = new Branch(false); branch.add(unowned); - owningBranch.dispose(); + owningBranch[Symbol.dispose](); expect(isDisposed(owningBranch)).toBe(true); expect(isDisposed(owned)).toBe(true); expect(owningBranch.entries.length).toBe(0); - branch.dispose(); + branch[Symbol.dispose](); expect(isDisposed(branch)).toBe(true); expect(isDisposed(unowned)).toBe(false); expect(branch.entries.length).toBe(0); @@ -122,7 +121,7 @@ describe("GraphicBranch", () => { branch.add(owner); branch.add(unowned); - branch.dispose(); + branch[Symbol.dispose](); expect(isDisposed(branch)).toBe(true); expect(branch.entries.length).toBe(0); expect(isDisposed(owner)).toBe(true); diff --git a/core/frontend/src/test/render/RenderInstances.test.ts b/core/frontend/src/test/render/RenderInstances.test.ts index a3c9ba261aaf..25691b0df9c6 100644 --- a/core/frontend/src/test/render/RenderInstances.test.ts +++ b/core/frontend/src/test/render/RenderInstances.test.ts @@ -71,9 +71,9 @@ describe("InstanceBuffers", () => { expect(b.isDisposed).toBe(false); expect(c.isDisposed).toBe(false); - a.dispose(); - b.dispose(); - c.dispose(); + a[Symbol.dispose](); + b[Symbol.dispose](); + c[Symbol.dispose](); expect(a.isDisposed).toBe(true); expect(b.isDisposed).toBe(true); expect(c.isDisposed).toBe(false); @@ -84,7 +84,7 @@ describe("InstanceBuffers", () => { const buffers = InstanceBuffers.fromParams(params, () => new Range3d())!; expect(buffers.isDisposed).toBe(false); - buffers.dispose(); + buffers[Symbol.dispose](); expect(buffers.isDisposed).toBe(true); }); @@ -97,7 +97,7 @@ describe("InstanceBuffers", () => { const buffers = InstanceBuffers.fromRenderInstances(instances, new Range3d()); expect(buffers.isDisposed).toBe(false); - buffers.dispose(); + buffers[Symbol.dispose](); expect(buffers.isDisposed).toBe(false); }); }); @@ -202,7 +202,7 @@ describe("RenderInstances", () => { } }`; - const vp = openBlankViewport({ height: 100, width: 100 }); + using vp = openBlankViewport({ height: 100, width: 100 }); vp.viewFlags = vp.viewFlags.copy({ renderMode: RenderMode.SmoothShade, visibleEdges: false, lighting: false }); vp.view.setStandardRotation(StandardViewId.Iso); const viewVolume = Range3d.create(vp.iModel.projectExtents.center); @@ -238,7 +238,7 @@ describe("RenderInstances", () => { instancesBuilder.add({ feature: "0x6", transform: Transform.createTranslationXYZ(0, -1, 0), - symbology: { color: {r: 0, g: 0, b: 255 } }, + symbology: { color: { r: 0, g: 0, b: 255 } }, }); const instances = IModelApp.renderSystem.createRenderInstances(instancesBuilder.finish())!; expect(instances[_featureTable]!.numFeatures).toEqual(4); @@ -265,8 +265,6 @@ describe("RenderInstances", () => { const features = readUniqueFeatures(vp); expect(features.length).toEqual(4); expect(features.contains(new Feature("0x3"))).toBe(true); - - vp.dispose(); }); it("renders the same template with different symbologies", () => { @@ -322,7 +320,7 @@ describe("RenderInstances", () => { }, }); - const vp = openBlankViewport({ height: 100, width: 100 }); + using vp = openBlankViewport({ height: 100, width: 100 }); vp.displayStyle.backgroundColor = ColorDef.black; vp.renderFrame(); @@ -331,7 +329,7 @@ describe("RenderInstances", () => { const background = colors.get(Color.fromColorDef(ColorDef.black))!; const red = colors.get(Color.fromColorDef(ColorDef.red))!; const blue = colors.get(Color.fromColorDef(ColorDef.blue))!; - const green= colors.get(Color.fromColorDef(ColorDef.green))!; + const green = colors.get(Color.fromColorDef(ColorDef.green))!; const white = colors.get(Color.fromColorDef(ColorDef.white))!; // dashed - fewer pixels @@ -342,7 +340,5 @@ describe("RenderInstances", () => { expect(green).greaterThan(red); // most of view is background expect(background).greaterThan(green); - - vp.dispose(); }); }); diff --git a/core/frontend/src/test/render/VisibleFeature.test.ts b/core/frontend/src/test/render/VisibleFeature.test.ts index 53f219eba397..bcaa204878d6 100644 --- a/core/frontend/src/test/render/VisibleFeature.test.ts +++ b/core/frontend/src/test/render/VisibleFeature.test.ts @@ -23,7 +23,7 @@ describe("Visible feature query", () => { afterEach(() => { if (viewport) { - viewport.dispose(); + viewport[Symbol.dispose](); viewport = undefined; } }); @@ -45,7 +45,7 @@ describe("Visible feature query", () => { if (view.viewFlags.acsTriad || view.viewFlags.grid) view.viewFlags = view.viewFlags.copy({ acsTriad: false, grid: false }); - const vp = ScreenViewport.create(div, view); + using vp = ScreenViewport.create(div, view); IModelApp.viewManager.addViewport(vp); expect(vp.target.debugControl).toBeDefined(); vp.target.debugControl!.devicePixelRatioOverride = devicePixelRatio ?? 1; @@ -55,7 +55,6 @@ describe("Visible feature query", () => { try { callback(vp); } finally { - vp.dispose(); document.body.removeChild(div); } } diff --git a/core/frontend/src/test/render/primitives/MeshBuilder.test.ts b/core/frontend/src/test/render/primitives/MeshBuilder.test.ts index 3e874ff072fd..06808792117c 100644 --- a/core/frontend/src/test/render/primitives/MeshBuilder.test.ts +++ b/core/frontend/src/test/render/primitives/MeshBuilder.test.ts @@ -39,7 +39,7 @@ describe("Mesh Builder Tests", () => { }); afterAll(async () => { - viewport.dispose(); + viewport[Symbol.dispose](); await MockRender.App.shutdown(); }); @@ -63,7 +63,7 @@ describe("Mesh Builder Tests", () => { }); it("addStrokePointLists", () => { - const primBuilder = new PrimitiveBuilder(IModelApp.renderSystem, {type: GraphicType.Scene, viewport }); + const primBuilder = new PrimitiveBuilder(IModelApp.renderSystem, { type: GraphicType.Scene, viewport }); const pointA = new Point3d(-100, 0, 0); const pointB = new Point3d(0, 100, 0); @@ -390,7 +390,7 @@ describe("Mesh Builder Tests", () => { }); function createMeshBuilder(type: MeshPrimitiveType, range: Range3d, options?: Partial>): MeshBuilder { - options = options ?? { }; + options = options ?? {}; const tolerance = options.tolerance ?? 0.15; return MeshBuilder.create({ quantizePositions: false, diff --git a/core/frontend/src/test/render/primitives/MeshBuilderMap.test.ts b/core/frontend/src/test/render/primitives/MeshBuilderMap.test.ts index 988ea51c8f45..94b495b1109b 100644 --- a/core/frontend/src/test/render/primitives/MeshBuilderMap.test.ts +++ b/core/frontend/src/test/render/primitives/MeshBuilderMap.test.ts @@ -52,7 +52,7 @@ describe("MeshBuilderMap Tests", () => { }); afterEach(() => { - viewport.dispose(); + viewport[Symbol.dispose](); }); it("constructor", () => { diff --git a/core/frontend/src/test/render/primitives/VertexTableSplitter.test.ts b/core/frontend/src/test/render/primitives/VertexTableSplitter.test.ts index f7f844f66355..569f5ff1d5d6 100644 --- a/core/frontend/src/test/render/primitives/VertexTableSplitter.test.ts +++ b/core/frontend/src/test/render/primitives/VertexTableSplitter.test.ts @@ -98,7 +98,7 @@ function makePointStringParams(pts: Point[], colors: ColorDef | ColorDef[], unqu linePixels: LinePixels.Solid, flags: { isPlanar: true, isDisjoint: true }, points, - polylines: [[...new Array(points.length).keys()] ], + polylines: [[...new Array(points.length).keys()]], }; const params = createPointStringParams(args, IModelApp.renderSystem.maxTextureSize)!; @@ -218,7 +218,7 @@ interface TriMeshPoint extends Point { function makeTriangleStrip(firstPoint: TriMeshPoint, numTriangles: number, adjustPt?: (pt: TriMeshPoint) => TriMeshPoint): TriMeshPoint[] { adjustPt = adjustPt ?? ((pt: TriMeshPoint) => pt); - const strip = [ adjustPt(firstPoint) ]; + const strip = [adjustPt(firstPoint)]; const pointCount = numTriangles + 2; for (let i = 1; i < pointCount; i++) strip.push(adjustPt({ ...firstPoint, x: firstPoint.x + i })); @@ -378,9 +378,9 @@ function expectPolyline(polyline: TesselatedPolyline, expected: PolylineIndices[ interface Edges { // index, other index, quad index - segments?: Array<[ number, number, number ]>; + segments?: Array<[number, number, number]>; // segments plus oct-encoded normal pair - silhouettes?: Array<[ number, number, number, number ]>; + silhouettes?: Array<[number, number, number, number]>; polylines?: PolylineIndices[]; } @@ -542,7 +542,7 @@ describe("VertexTableSplitter", () => { it("reconstructs or collapses color tables and remaps color indices", () => { const featureTable = makePackedFeatureTable("0x1", "0x2"); - const colors = [ ColorDef.red, ColorDef.green, ColorDef.blue ]; + const colors = [ColorDef.red, ColorDef.green, ColorDef.blue]; const points = [ { x: 1, color: 2, feature: 0 }, @@ -560,7 +560,7 @@ describe("VertexTableSplitter", () => { }); expect(split.size).toEqual(2); - expectPointStrings(split.get(1)!, [ ColorDef.blue, ColorDef.red ], [ + expectPointStrings(split.get(1)!, [ColorDef.blue, ColorDef.red], [ { x: 1, color: 0, feature: 0 }, { x: 2, color: 1, feature: 0 }, ]); @@ -609,7 +609,7 @@ describe("VertexTableSplitter", () => { const p1 = split.get(0x2)!; expectDimensions(p1, 3, 3); - expectPointStrings(p1, [ ColorDef.red, ColorDef.green ], [ + expectPointStrings(p1, [ColorDef.red, ColorDef.green], [ { x: 0, color: 0, feature: 0 }, { x: 1, color: 1, feature: 0 }, ]); @@ -635,7 +635,7 @@ describe("VertexTableSplitter", () => { ]); }); function makeSurface(adjustPt?: (pt: TriMeshPoint) => TriMeshPoint): { params: MeshParams, colors: ColorDef | ColorDef[], featureTable: PackedFeatureTable, mesh: TriMesh } { - let colors: ColorDef | ColorDef[] = [ ColorDef.red, ColorDef.green, ColorDef.blue ]; + let colors: ColorDef | ColorDef[] = [ColorDef.red, ColorDef.green, ColorDef.blue]; const featureTable = makePackedFeatureTable("0x1", "0x2", "0x3"); const mesh: TriMesh = { points: [ @@ -687,7 +687,7 @@ describe("VertexTableSplitter", () => { expectMesh(split.get(1)!, { texture, - colors: texture ? ColorDef.from(1, 2, 3) : [ ColorDef.blue, ColorDef.red ], + colors: texture ? ColorDef.from(1, 2, 3) : [ColorDef.blue, ColorDef.red], points: [ ...makeTriangleStrip({ x: 0, color: 0, feature: 0 }, 2, adjustPt), ...makeTriangleStrip({ x: 10, color: 1, feature: 0 }, 1, adjustPt), @@ -815,7 +815,7 @@ describe("VertexTableSplitter", () => { [0, 1, 2, 0xfedcba98], [1, 2, 3, 0xffffffff], ], - polylines: edges.polylines!.slice(3, 5).map((p) => [ p[0] - 7, p[1] - 7, p[2] - 7, p[3] ]), + polylines: edges.polylines!.slice(3, 5).map((p) => [p[0] - 7, p[1] - 7, p[2] - 7, p[3]]), }); expectEdges(split.get(3)!.edges, { @@ -828,7 +828,7 @@ describe("VertexTableSplitter", () => { [2, 3, 1, 789], [1, 4, 2, 0xdeadbeef], ], - polylines: edges.polylines!.slice(5, 10).map((p) => [ p[0] - 14, p[1] - 14, p[2] - 14, p[3] ]), + polylines: edges.polylines!.slice(5, 10).map((p) => [p[0] - 14, p[1] - 14, p[2] - 14, p[3]]), }); }); diff --git a/core/frontend/src/test/render/webgl/BufferHandle.test.ts b/core/frontend/src/test/render/webgl/BufferHandle.test.ts index ae98d55d327c..8ce3590b2fab 100644 --- a/core/frontend/src/test/render/webgl/BufferHandle.test.ts +++ b/core/frontend/src/test/render/webgl/BufferHandle.test.ts @@ -15,7 +15,7 @@ describe("BufferHandle", () => { it("disposes", () => { const buf = new BufferHandle(GL.Buffer.Target.ArrayBuffer); expect(buf.isDisposed).toBe(false); - buf.dispose(); + buf[Symbol.dispose](); expect(buf.isDisposed).toBe(true); }); diff --git a/core/frontend/src/test/render/webgl/Decorations.test.ts b/core/frontend/src/test/render/webgl/Decorations.test.ts index 87738e2fde21..5897bf6699fa 100644 --- a/core/frontend/src/test/render/webgl/Decorations.test.ts +++ b/core/frontend/src/test/render/webgl/Decorations.test.ts @@ -58,7 +58,7 @@ describe("Decorations", () => { }); afterEach(() => { - viewport.dispose(); + viewport[Symbol.dispose](); TestDecorator.dropAll(); }); diff --git a/core/frontend/src/test/render/webgl/FeatureOverrides.test.ts b/core/frontend/src/test/render/webgl/FeatureOverrides.test.ts index 6c66ad0c1dc1..fce197bd1861 100644 --- a/core/frontend/src/test/render/webgl/FeatureOverrides.test.ts +++ b/core/frontend/src/test/render/webgl/FeatureOverrides.test.ts @@ -250,23 +250,23 @@ describe("FeatureOverrides", () => { } } - t2.dispose(); + t2[Symbol.dispose](); for (const batch of batches) { expect(batch.perTargetData.data.length).toEqual(1); expect(batch.perTargetData.data[0].target).toEqual(t1); expect(batch.perTargetData.data[0].featureOverrides.size).toEqual(2); } - ba1.dispose(); + ba1[Symbol.dispose](); expect(ba1.perTargetData.data.length).toEqual(0); expect(ba1.isDisposed).toBe(true); expect(ba2.isDisposed).toBe(false); - t1.dispose(); + t1[Symbol.dispose](); s1.onSourceDisposed.raiseEvent(); expect(ba2.perTargetData.data.length).toEqual(0); - ba2.dispose(); + ba2[Symbol.dispose](); }); it("updates when HiliteSet changes", () => { @@ -308,7 +308,7 @@ describe("FeatureOverrides", () => { IModelApp.viewManager.addViewport(vp); const target = vp.target as Target; - expect(target).toBeInstanceOf(Target); + expect(target).toBeInstanceOf(Target); vp.view.createScene = (context) => { context.scene.foreground.push(b1); @@ -319,14 +319,14 @@ describe("FeatureOverrides", () => { function expectHilited(batch: Batch, featureIndex: 0 | 1, expectToBeHilited: boolean): void { const ptd = batch.perTargetData.data[0]; if (!ptd) { - expect(expectToBeHilited).toBe(false); + expect(expectToBeHilited).toBe(false); return; } const ovrs = ptd.featureOverrides.get(undefined); - expect(ovrs).toBeDefined(); + expect(ovrs).toBeDefined(); const data = ovrs!.lutData!; - expect(data).toBeDefined(); + expect(data).toBeDefined(); const numBytesPerFeature = 12; // 3 RGBA values per feature expect(data.length).toEqual(2 * numBytesPerFeature); @@ -334,19 +334,19 @@ describe("FeatureOverrides", () => { const tex = new Texture2DDataUpdater(data); const flags = tex.getOvrFlagsAtIndex(featureIndex * numBytesPerFeature); const isHilited = 0 !== (flags & OvrFlags.Hilited); - expect(isHilited).toEqual(expectToBeHilited); + expect(isHilited).toEqual(expectToBeHilited); } setup(); vp.renderFrame(); - expect(target.hilites).toEqual(vp.iModel.hilited); - expect(b1.perTargetData.data.length).toEqual(1); + expect(target.hilites).toEqual(vp.iModel.hilited); + expect(b1.perTargetData.data.length).toEqual(1); const expected = new Set(expectedHilitedElements ? (typeof expectedHilitedElements === "string" ? [expectedHilitedElements] : expectedHilitedElements) : []); if (expected.size > 0) { - expect(b1.perTargetData.data.length).toEqual(1); - expect(b2.perTargetData.data.length).toEqual(1); + expect(b1.perTargetData.data.length).toEqual(1); + expect(b2.perTargetData.data.length).toEqual(1); } expectHilited(b1, 0, expected.has(e11)); @@ -373,10 +373,10 @@ describe("FeatureOverrides", () => { for (const el of allElems) { reset(); test(el, () => { - expect(h.elements.isEmpty).toBe(true); + expect(h.elements.isEmpty).toBe(true); h.elements.addId(el); - expect(h.elements.isEmpty).toBe(false); - expect(h.elements.hasId(el)).toBe(true); + expect(h.elements.isEmpty).toBe(false); + expect(h.elements.hasId(el)).toBe(true); }); } diff --git a/core/frontend/src/test/render/webgl/PickableGraphics.test.ts b/core/frontend/src/test/render/webgl/PickableGraphics.test.ts index 5e1aa0d04043..4953d33ffcc0 100644 --- a/core/frontend/src/test/render/webgl/PickableGraphics.test.ts +++ b/core/frontend/src/test/render/webgl/PickableGraphics.test.ts @@ -41,7 +41,7 @@ describe("Pickable graphic", () => { }); afterEach(() => { - viewport.dispose(); + viewport[Symbol.dispose](); TestDecorator.dropAll(); }); diff --git a/core/frontend/src/test/render/webgl/RenderMemory.test.ts b/core/frontend/src/test/render/webgl/RenderMemory.test.ts index 4b702fd0831b..d0f3108ba326 100644 --- a/core/frontend/src/test/render/webgl/RenderMemory.test.ts +++ b/core/frontend/src/test/render/webgl/RenderMemory.test.ts @@ -30,11 +30,11 @@ function createMeshGeometry(opts?: { texture?: RenderTexture, includeEdges?: boo if (opts?.texture) { textureMapping = { texture: opts.texture, - uvParams: [new Point2d(0, 1), new Point2d(1, 1), new Point2d(0, 0), new Point2d(1, 0) ], + uvParams: [new Point2d(0, 1), new Point2d(1, 1), new Point2d(0, 0), new Point2d(1, 0)], }; } - const points = [ new Point3d(0, 0, 0), new Point3d(1, 0, 0), new Point3d(0, 1, 0), new Point3d(1, 1, 0) ]; + const points = [new Point3d(0, 0, 0), new Point3d(1, 0, 0), new Point3d(0, 1, 0), new Point3d(1, 1, 0)]; const qpoints = new QPoint3dList(QParams3d.fromRange(Range3d.createXYZXYZ(0, 0, 0, 1, 1, 1))); for (const point of points) qpoints.add(point); @@ -199,11 +199,11 @@ describe("RenderMemory", () => { it("reports zero memory after disposal", () => { const mesh = createGraphic(createMeshGeometry()); expect(getBytesUsed(mesh)).greaterThan(0); - mesh.dispose(); + mesh[Symbol.dispose](); expectBytesUsed(0, mesh); const texture = createTexture(imodel, false); - texture.dispose(); + texture[Symbol.dispose](); expectBytesUsed(0, texture); }); @@ -217,7 +217,7 @@ describe("RenderMemory", () => { const graphic = createGraphic(mesh, params); expectBytesUsed(getBytesUsed(mesh) + numInstanceBytes, graphic); - graphic.dispose(); + graphic[Symbol.dispose](); expectBytesUsed(0, mesh); expectBytesUsed(0, graphic); }); @@ -230,7 +230,7 @@ describe("RenderMemory", () => { const graphic = createGraphic(mesh, params); expectBytesUsed(getBytesUsed(mesh) + numInstanceBytes, graphic); - graphic.dispose(); + graphic[Symbol.dispose](); expectBytesUsed(0, mesh); expectBytesUsed(0, graphic); }); diff --git a/core/frontend/src/test/render/webgl/SurfaceTransparency.test.ts b/core/frontend/src/test/render/webgl/SurfaceTransparency.test.ts index 4807782ebe99..dc39cf1760d1 100644 --- a/core/frontend/src/test/render/webgl/SurfaceTransparency.test.ts +++ b/core/frontend/src/test/render/webgl/SurfaceTransparency.test.ts @@ -24,7 +24,7 @@ function createMesh(transparency: number, mat?: RenderMaterial | RenderTexture): const colors = new ColorIndex(); colors.initUniform(ColorDef.from(255, 0, 0, transparency)); - const points = [ new Point3d(0, 0, 0), new Point3d(1, 0, 0), new Point3d(0, 1, 0), new Point3d(1, 1, 0) ]; + const points = [new Point3d(0, 0, 0), new Point3d(1, 0, 0), new Point3d(0, 1, 0), new Point3d(1, 1, 0)]; const qpoints = new QPoint3dList(QParams3d.fromRange(Range3d.createXYZXYZ(0, 0, 0, 1, 1, 1))); for (const point of points) qpoints.add(point); @@ -47,7 +47,7 @@ function createMesh(transparency: number, mat?: RenderMaterial | RenderTexture): } if (texture) - args.textureMapping = { texture, uvParams: [ new Point2d(0, 1), new Point2d(1, 1), new Point2d(0, 0), new Point2d(1, 0) ] }; + args.textureMapping = { texture, uvParams: [new Point2d(0, 1), new Point2d(1, 1), new Point2d(0, 0), new Point2d(1, 0)] }; const params = createMeshParams(args, IModelApp.renderSystem.maxTextureSize, "non-indexed" !== IModelApp.tileAdmin.edgeOptions.type); return IModelApp.renderSystem.createMesh(params)!; @@ -95,7 +95,7 @@ describe("Surface transparency", () => { }); afterEach(() => { - viewport.dispose(); + viewport[Symbol.dispose](); }); afterAll(async () => { @@ -124,17 +124,17 @@ describe("Surface transparency", () => { const graphic = setup(viewport.view as SpatialViewState); const mesh = graphic as MeshGraphic; - expect(mesh).instanceof(MeshGraphic); + expect(mesh).instanceof(MeshGraphic); const primitive = (mesh as any)._primitives[0] as Primitive; - expect(primitive).instanceof(Primitive); - expect(primitive.cachedGeometry).instanceof(SurfaceGeometry); + expect(primitive).instanceof(Primitive); + expect(primitive.cachedGeometry).instanceof(SurfaceGeometry); const plan = createRenderPlanFromViewport(viewport); viewport.target.changeRenderPlan(plan); const primPass = primitive.getPass(viewport.target as Target); - expect(Pass.rendersOpaqueAndTranslucent(primPass)).toBe(false); - expect(Pass.toRenderPass(primPass as SinglePass)).toEqual(pass); + expect(Pass.rendersOpaqueAndTranslucent(primPass)).toBe(false); + expect(Pass.toRenderPass(primPass as SinglePass)).toEqual(pass); } function expectOpaque(setup: SetupFunc): void { @@ -267,7 +267,7 @@ describe("Surface transparency", () => { ownership: { iModel: imodel, key: imodel.transientIds.getNext() }, image: { source: img, transparency: TextureTransparency.Translucent }, }); - expect(tx).toBeDefined(); + expect(tx).toBeDefined(); expectTranslucent(() => createMesh(0, tx)); expectTranslucent(() => createMesh(127, tx)); diff --git a/core/frontend/src/test/render/webgl/System.test.ts b/core/frontend/src/test/render/webgl/System.test.ts index 3d7bfffbb3a5..ca3d13f10d86 100644 --- a/core/frontend/src/test/render/webgl/System.test.ts +++ b/core/frontend/src/test/render/webgl/System.test.ts @@ -177,7 +177,7 @@ describe("System", () => { function requestThematicGradient(stepCount: number) { const symb = Gradient.Symb.fromJSON({ mode: Gradient.Mode.Thematic, - thematicSettings: {stepCount}, + thematicSettings: { stepCount }, keys: [{ value: 0.6804815398789292, color: 610 }, { value: 0.731472008309797, color: 229 }], }); return IModelApp.renderSystem.getGradientTexture(symb, imodel); @@ -186,7 +186,7 @@ describe("System", () => { it("should properly request a thematic gradient texture", async () => { const g1 = requestThematicGradient(5); expect(g1).toBeDefined(); - g1!.dispose(); + g1![Symbol.dispose](); }); it("should properly cache and reuse thematic gradient textures", async () => { @@ -195,8 +195,8 @@ describe("System", () => { const g2 = requestThematicGradient(5); expect(g2).toBeDefined(); expect(g2 === g1).toBe(true); - g1!.dispose(); - g2!.dispose(); + g1![Symbol.dispose](); + g2![Symbol.dispose](); }); it("should properly create separate thematic gradient textures if thematic settings differ", async () => { @@ -205,8 +205,8 @@ describe("System", () => { const g2 = requestThematicGradient(6); expect(g2).toBeDefined(); expect(g2 === g1).toBe(false); - g1!.dispose(); - g2!.dispose(); + g1![Symbol.dispose](); + g2![Symbol.dispose](); }); async function requestTexture(key: string | undefined, source?: ImageSource): Promise { @@ -240,7 +240,7 @@ describe("System", () => { expect(t1).toEqual(t2); expect(t1).toBeDefined(); - t1!.dispose(); + t1![Symbol.dispose](); }); it("should decode each different image once", async () => { @@ -259,8 +259,8 @@ describe("System", () => { expect(t1).toBeDefined(); expect(t2).toBeDefined(); - t1!.dispose(); - t2!.dispose(); + t1![Symbol.dispose](); + t2![Symbol.dispose](); }); it("should not record pending requests for unnamed textures", async () => { @@ -273,8 +273,8 @@ describe("System", () => { const t2 = await p2; expect(t1).not.toEqual(t2); - t1!.dispose(); - t2!.dispose(); + t1![Symbol.dispose](); + t2![Symbol.dispose](); }); it("should not record requests for previously-created textures", async () => { @@ -298,7 +298,7 @@ describe("System", () => { const t3 = await p3; expect(t3).toEqual(t1); - t1!.dispose(); + t1![Symbol.dispose](); }); it("should return undefined and delete pending request on error", async () => { @@ -319,7 +319,7 @@ describe("System", () => { expect(t2).toBeDefined(); expectPendingRequests(0); - t2!.dispose(); + t2![Symbol.dispose](); }); it("should return undefined after render system is disposed", async () => { @@ -447,7 +447,7 @@ describe("System", () => { expect(actual).toEqual(expected); }; - test({ }, defaults); + test({}, defaults); test(defaults); const color = { r: 1, g: 127, b: 255 }; diff --git a/core/frontend/src/test/tile/LRUTileList.test.ts b/core/frontend/src/test/tile/LRUTileList.test.ts index 870530a2e924..6ed15bcae7c9 100644 --- a/core/frontend/src/test/tile/LRUTileList.test.ts +++ b/core/frontend/src/test/tile/LRUTileList.test.ts @@ -319,7 +319,7 @@ describe("LRUTileList", () => { expect(tile.tileUserIds).toBeDefined(); } - list.dispose(); + list[Symbol.dispose](); expect(list.head).toEqual(list.sentinel); expect(list.tail).toEqual(list.sentinel); expect(list.totalBytesUsed).toEqual(0); diff --git a/core/frontend/src/test/tile/TileAdmin.test.ts b/core/frontend/src/test/tile/TileAdmin.test.ts index c30a9935b137..12b04e126f10 100644 --- a/core/frontend/src/test/tile/TileAdmin.test.ts +++ b/core/frontend/src/test/tile/TileAdmin.test.ts @@ -103,7 +103,7 @@ describe("TileAdmin", () => { stats.addTexture(this._size); } - public unionRange() {} + public unionRange() { } } class TestTile extends Tile { @@ -176,7 +176,7 @@ describe("TileAdmin", () => { public get rootTile(): TestTile { return this._rootTile; } public get is3d() { return true; } public get maxDepth() { return undefined; } - public get viewFlagOverrides() { return { }; } + public get viewFlagOverrides() { return {}; } protected _selectTiles(args: TileDrawArgs): Tile[] { const tiles = []; @@ -199,7 +199,7 @@ describe("TileAdmin", () => { args.drawGraphics(); } - public prune() {} + public prune() { } } class Supplier implements TileTreeSupplier { @@ -377,7 +377,7 @@ describe("TileAdmin", () => { expect(isLinked(tiles[2])).toBe(false); expect(admin.totalTileContentBytes).toEqual(3); - trees[3].dispose(); + trees[3][Symbol.dispose](); expect(isLinked(tiles[3])).toBe(false); expect(admin.totalTileContentBytes).toEqual(0); }); @@ -549,7 +549,7 @@ describe("TileAdmin", () => { expect(admin.totalTileContentBytes).toEqual(11); // Disposing the viewport marks all previously-selected tiles as no longer selected by it - but they remain in the LRU list. - vp1.dispose(); + vp1[Symbol.dispose](); expect(isLinked(tile1)).toBe(true); expect(isLinked(tile2)).toBe(true); expect(admin.totalTileContentBytes).toEqual(11); @@ -558,7 +558,7 @@ describe("TileAdmin", () => { expect(isLinked(tile2)).toBe(true); expect(admin.totalTileContentBytes).toEqual(10); - vp2.dispose(); + vp2[Symbol.dispose](); expect(isLinked(tile2)).toBe(true); expect(admin.totalTileContentBytes).toEqual(10); admin.process(); diff --git a/core/frontend/src/test/tile/TiledGraphicsProvider.test.ts b/core/frontend/src/test/tile/TiledGraphicsProvider.test.ts index aa561336c1ee..5c7833601d5b 100644 --- a/core/frontend/src/test/tile/TiledGraphicsProvider.test.ts +++ b/core/frontend/src/test/tile/TiledGraphicsProvider.test.ts @@ -155,7 +155,7 @@ describe("TiledGraphicsProvider", () => { }); afterEach(() => { - viewport.dispose(); + viewport[Symbol.dispose](); }); afterAll(async () => { diff --git a/core/frontend/src/tile/ClassifierTileTree.ts b/core/frontend/src/tile/ClassifierTileTree.ts index a93527ce841f..6b17cc68c800 100644 --- a/core/frontend/src/tile/ClassifierTileTree.ts +++ b/core/frontend/src/tile/ClassifierTileTree.ts @@ -36,7 +36,7 @@ class ClassifierTreeSupplier implements TileTreeSupplier { tileTree: undefined, loadStatus: TileTreeLoadStatus.NotFound, load: () => undefined, - dispose: () => undefined, + [Symbol.dispose]: () => undefined, loadTree: async () => undefined, iModel: undefined as unknown as IModelConnection, }; diff --git a/core/frontend/src/tile/DynamicIModelTile.ts b/core/frontend/src/tile/DynamicIModelTile.ts index a27dbdc68f2b..affa43070f80 100644 --- a/core/frontend/src/tile/DynamicIModelTile.ts +++ b/core/frontend/src/tile/DynamicIModelTile.ts @@ -124,7 +124,7 @@ class RootTile extends DynamicIModelTile implements FeatureAppearanceProvider { let tile = this._elements.findEquivalent((t: ElementTile) => compareStrings(t.contentId, change.id)); if (change.type === DbOpcode.Delete) { if (tile) { - tile.dispose(); + tile[Symbol.dispose](); this._elements.remove(tile); } } else { @@ -220,7 +220,7 @@ class ElementTile extends Tile { if (partitionIndex < children.length) { const expired = children.splice(partitionIndex); for (const child of expired) - child.dispose(); + child[Symbol.dispose](); } // Restore ordering. @@ -293,7 +293,7 @@ class ElementTile extends Tile { // Discard out-dated graphics. assert(undefined !== this.children); for (const child of this.children) - child.dispose(); + child[Symbol.dispose](); this.children.length = 0; } diff --git a/core/frontend/src/tile/IModelTileTree.ts b/core/frontend/src/tile/IModelTileTree.ts index 1614bec03d34..d24bb553ca9d 100644 --- a/core/frontend/src/tile/IModelTileTree.ts +++ b/core/frontend/src/tile/IModelTileTree.ts @@ -95,10 +95,10 @@ function findElementChangesForModel(changes: Iterable, mod /** No graphical editing scope is currently active. */ class StaticState { public readonly type = "static"; - public readonly dispose: () => void; + public readonly [Symbol.dispose]!: () => void; public constructor(root: RootTile) { - this.dispose = GraphicalEditingScope.onEnter.addOnce((scope: GraphicalEditingScope) => { + this[Symbol.dispose] = GraphicalEditingScope.onEnter.addOnce((scope: GraphicalEditingScope) => { root.transition(new InteractiveState(scope, root)); }); } @@ -107,7 +107,7 @@ class StaticState { /** A graphical editing scope is currently active, but no elements in the tile tree's model have been modified. */ class InteractiveState { public readonly type = "interactive"; - public readonly dispose: () => void; + public readonly [Symbol.dispose]!: () => void; public constructor(scope: GraphicalEditingScope, root: RootTile) { const removeEndingListener = scope.onExiting.addOnce((_) => { @@ -121,7 +121,7 @@ class InteractiveState { root.transition(new DynamicState(root, elemChanges, scope)); }); - this.dispose = () => { + this[Symbol.dispose] = () => { removeEndingListener(); removeGeomListener(); }; @@ -134,9 +134,9 @@ class DynamicState { public readonly rootTile: DynamicIModelTile; private readonly _dispose: () => void; - public dispose(): void { + public [Symbol.dispose](): void { this._dispose(); - this.rootTile.dispose(); + this.rootTile[Symbol.dispose](); } public constructor(root: RootTile, elemChanges: Iterable, scope: GraphicalEditingScope) { @@ -163,7 +163,7 @@ class DynamicState { /** The tile tree has been disposed. */ class DisposedState { public readonly type = "disposed"; - public dispose(): void { } + public [Symbol.dispose](): void { } } const disposedState = new DisposedState(); @@ -220,9 +220,9 @@ class RootTile extends Tile { this.loadChildren(); } - public override dispose(): void { + public override[Symbol.dispose](): void { this.transition(disposedState); - super.dispose(); + super[Symbol.dispose](); } protected _loadChildren(resolve: (children: Tile[] | undefined) => void, _reject: (error: Error) => void): void { @@ -301,7 +301,7 @@ class RootTile extends Tile { this.children.push(newState.rootTile); } - this._tileState.dispose(); + this._tileState[Symbol.dispose](); this._tileState = newState; if (resetRange) @@ -392,9 +392,9 @@ export class IModelTileTree extends TileTree { }); } - public override dispose(): void { + public override[Symbol.dispose](): void { this.decoder.release(); - super.dispose(); + super[Symbol.dispose](); } public get maxDepth() { return 32; } diff --git a/core/frontend/src/tile/ImdlDecoder.ts b/core/frontend/src/tile/ImdlDecoder.ts index df74a3b66650..c409ffcb6f25 100644 --- a/core/frontend/src/tile/ImdlDecoder.ts +++ b/core/frontend/src/tile/ImdlDecoder.ts @@ -60,7 +60,7 @@ export interface AcquireImdlDecoderArgs { * Decoders are reference-counted, because they make use of reference-counted [[ImdlParser]]s internally. * The caller of this function increments the reference count of the decoder and is responsible * for decrementing it by calling [[ImdlDecoder.release]] when it is no longer needed. Typically, a decoder's lifetime is tied to the - * lifetime of some [IDisposable]($bentley) object like a [[TileTree]] - acquired in the constructor, and released in the `dispose` method. + * lifetime of some `Disposable` object like a [[TileTree]] - acquired in the constructor, and released in the `[Symbol.dispose]` method. * @internal */ export function acquireImdlDecoder(args: AcquireImdlDecoderArgs): ImdlDecoder { diff --git a/core/frontend/src/tile/LRUTileList.ts b/core/frontend/src/tile/LRUTileList.ts index a90f4bb61296..17aaf384dcd1 100644 --- a/core/frontend/src/tile/LRUTileList.ts +++ b/core/frontend/src/tile/LRUTileList.ts @@ -222,7 +222,7 @@ export class LRUTileList { this._head = this._tail = this._sentinel = { bytesUsed: 0 }; } - public dispose(): void { + public [Symbol.dispose](): void { let node: LRUTileListNode | undefined = this._head; let next: LRUTileListNode | undefined; while (node) { diff --git a/core/frontend/src/tile/OrbitGtTileTree.ts b/core/frontend/src/tile/OrbitGtTileTree.ts index ff40b134b1d3..3b7cde6a0f62 100644 --- a/core/frontend/src/tile/OrbitGtTileTree.ts +++ b/core/frontend/src/tile/OrbitGtTileTree.ts @@ -217,8 +217,8 @@ class OrbitGtTileGraphic extends TileUsageMarker { this.mark(viewport, time); } - public dispose(): void { - this.graphic.dispose(); + public [Symbol.dispose](): void { + this.graphic[Symbol.dispose](); } } @@ -243,15 +243,15 @@ export class OrbitGtTileTree extends TileTree { return this._ecefTransform; } - public override dispose(): void { + public override[Symbol.dispose](): void { if (this.isDisposed) return; for (const graphic of this._tileGraphics.values()) - graphic.dispose(); + graphic[Symbol.dispose](); this._tileGraphics.clear(); - super.dispose(); + super[Symbol.dispose](); } protected _selectTiles(_args: TileDrawArgs): Tile[] { return []; } @@ -262,7 +262,7 @@ export class OrbitGtTileTree extends TileTree { private _doPrune(olderThan: BeTimePoint) { for (const [key, graphic] of this._tileGraphics) if (graphic.isExpired(olderThan)) { - graphic.dispose(); + graphic[Symbol.dispose](); this._tileGraphics.delete(key); } } @@ -365,7 +365,7 @@ export namespace OrbitGtTileTree { function isValidSASToken(downloadUrl: string): boolean { // Create fake URL for and parameter parsing and SAS token URI parsing - if(!downloadUrl.startsWith("http")) + if (!downloadUrl.startsWith("http")) downloadUrl = `http://x.com/x?${downloadUrl}`; const sasUrl = new URL(downloadUrl); @@ -384,7 +384,7 @@ export namespace OrbitGtTileTree { function isValidOrbitGtBlobProps(props: OrbitGtBlobProps): boolean { // Check main OrbitGtBlobProps fields are defined - if(!props.accountName || !props.containerName || !props.blobFileName || !props.sasToken) + if (!props.accountName || !props.containerName || !props.blobFileName || !props.sasToken) return false; // Check SAS token is valid @@ -399,7 +399,7 @@ export namespace OrbitGtTileTree { let blobStringUrl: string; if (isContextShare) { const realityData = rdSource ? rdSource.realityData : undefined; - if (rdSource === undefined || realityData === undefined ) + if (rdSource === undefined || realityData === undefined) return undefined; const docRootName = realityData.rootDocument; if (!docRootName) @@ -413,7 +413,7 @@ export namespace OrbitGtTileTree { const orbitGtBlobProps = RealityDataSource.createOrbitGtBlobPropsFromKey(rdSourceKey); if (orbitGtBlobProps === undefined) return undefined; - if(!isValidOrbitGtBlobProps(orbitGtBlobProps)) + if (!isValidOrbitGtBlobProps(orbitGtBlobProps)) return undefined; const { accountName, containerName, blobFileName, sasToken } = orbitGtBlobProps; blobStringUrl = blobFileName; diff --git a/core/frontend/src/tile/PrimaryTileTree.ts b/core/frontend/src/tile/PrimaryTileTree.ts index d387b70b6ec6..e658b4194988 100644 --- a/core/frontend/src/tile/PrimaryTileTree.ts +++ b/core/frontend/src/tile/PrimaryTileTree.ts @@ -54,7 +54,7 @@ class PrimaryTreeSupplier implements TileTreeSupplier { public compareTileTreeIds(lhs: PrimaryTreeId, rhs: PrimaryTreeId): number { // NB: we don't compare isPlanProjection or is3d - they should always have the same value for a given modelId. return compareStrings(lhs.modelId, rhs.modelId) || compareIModelTileTreeIds(lhs.treeId, rhs.treeId) - || comparePossiblyUndefined((x, y) => x.compareTo(y), lhs.timeline, rhs.timeline); + || comparePossiblyUndefined((x, y) => x.compareTo(y), lhs.timeline, rhs.timeline); } public async createTileTree(id: PrimaryTreeId, iModel: IModelConnection): Promise { @@ -125,7 +125,7 @@ export function disposeTileTreesForGeometricModels(modelIds: Set, iM const id = kvp.id as PrimaryTreeId; assert(undefined !== id.modelId); if (modelIds.has(id.modelId)) - kvp.owner.dispose(); + kvp.owner[Symbol.dispose](); } } @@ -490,7 +490,7 @@ export class ModelMapLayerTileTreeReference extends MapLayerTileTreeReference { } /** @internal */ export function createModelMapLayerTileTreeReference(layerSettings: ModelMapLayerSettings, layerIndex: number, iModel: IModelConnection): ModelMapLayerTileTreeReference | undefined { - const classifier = SpatialClassifier.fromModelMapLayer(layerSettings); + const classifier = SpatialClassifier.fromModelMapLayer(layerSettings); return classifier ? new ModelMapLayerTileTreeReference(layerSettings, classifier, layerIndex, iModel) : undefined; } diff --git a/core/frontend/src/tile/Tile.ts b/core/frontend/src/tile/Tile.ts index 0b5e0401b627..7965d9fe4a15 100644 --- a/core/frontend/src/tile/Tile.ts +++ b/core/frontend/src/tile/Tile.ts @@ -166,12 +166,17 @@ export abstract class Tile { } /** Dispose of resources held by this tile and all of its children, marking it and all of its children as "abandoned". */ - public dispose(): void { + public [Symbol.dispose](): void { this.disposeContents(); this._state = TileState.Abandoned; this.disposeChildren(); } + /** @deprecated in 5.0 Use [Symbol.dispose] instead. */ + public dispose() { + this[Symbol.dispose](); + } + /** This tile's child tiles, if they exist and are loaded. The children are fully contained within this tile's volume and provide higher-resolution graphics than this tile. * @see [[loadChildren]] */ @@ -194,7 +199,7 @@ export abstract class Tile { * @see [[ImageryMapTile.isOutOfLodRange]]. * @alpha */ - public get isOutOfLodRange(): boolean { return false;} + public get isOutOfLodRange(): boolean { return false; } /** @public */ public setNotFound(): void { @@ -376,7 +381,7 @@ export abstract class Tile { return; for (const child of children) - child.dispose(); + child[Symbol.dispose](); this._childrenLoadStatus = TileTreeLoadStatus.NotLoaded; this._children = undefined; diff --git a/core/frontend/src/tile/TileAdmin.ts b/core/frontend/src/tile/TileAdmin.ts index 497d69a5c9b6..68a6d9f9848d 100644 --- a/core/frontend/src/tile/TileAdmin.ts +++ b/core/frontend/src/tile/TileAdmin.ts @@ -580,7 +580,7 @@ export class TileAdmin { this._tileUserSetsForRequests.clear(); this._tileUsagePerUser.clear(); this._tileTreePropsRequests.length = 0; - this._lruList.dispose(); + this._lruList[Symbol.dispose](); } /** Returns the union of the input set and the input TileUser, to be associated with a [[TileRequest]]. diff --git a/core/frontend/src/tile/TileTree.ts b/core/frontend/src/tile/TileTree.ts index 1925cf3bb796..7d6dd600b202 100644 --- a/core/frontend/src/tile/TileTree.ts +++ b/core/frontend/src/tile/TileTree.ts @@ -142,7 +142,7 @@ export abstract class TileTree { public get isDisposed(): boolean { return this._isDisposed; } /** Dispose of this tree and any resources owned by it. This is typically invoked by a [[TileTreeOwner]]. */ - public dispose(): void { + public [Symbol.dispose](): void { if (this.isDisposed) return; @@ -150,6 +150,11 @@ export abstract class TileTree { dispose(this.rootTile); } + /** @deprecated in 5.0 Use [Symbol.dispose] instead. */ + public dispose() { + this[Symbol.dispose](); + } + /** @internal */ public collectStatistics(stats: RenderMemory.Statistics): void { this.rootTile.collectStatistics(stats); diff --git a/core/frontend/src/tile/TileTreeOwner.ts b/core/frontend/src/tile/TileTreeOwner.ts index 0c5893c22579..c5eab520a4ef 100644 --- a/core/frontend/src/tile/TileTreeOwner.ts +++ b/core/frontend/src/tile/TileTreeOwner.ts @@ -41,7 +41,7 @@ export interface TileTreeOwner { /** Do not call this directly. * @internal */ - dispose(): void; + [Symbol.dispose](): void; /** Waits for [[load]], then resolves. It is generally preferable to call [[load]] directly rather than `await`ing this method. */ loadTree(): Promise; diff --git a/core/frontend/src/tile/map/ImageryTileTree.ts b/core/frontend/src/tile/map/ImageryTileTree.ts index 15e3d7e0fefc..baa092c6d3b1 100644 --- a/core/frontend/src/tile/map/ImageryTileTree.ts +++ b/core/frontend/src/tile/map/ImageryTileTree.ts @@ -6,7 +6,7 @@ * @module Tiles */ -import { assert, compareBooleans, compareNumbers, compareStrings, compareStringsOrUndefined, dispose, Logger} from "@itwin/core-bentley"; +import { assert, compareBooleans, compareNumbers, compareStrings, compareStringsOrUndefined, dispose, Logger } from "@itwin/core-bentley"; import { Angle, Range3d, Transform } from "@itwin/core-geometry"; import { Cartographic, ImageMapLayerSettings, ImageSource, MapLayerSettings, RenderTexture, ViewFlagOverrides } from "@itwin/core-common"; import { IModelApp } from "../../IModelApp"; @@ -44,7 +44,7 @@ export class ImageryMapTile extends RealityTile { public get texture() { return this._texture; } public get tilingScheme() { return this.imageryTree.tilingScheme; } public override get isDisplayable() { return (this.depth > 1) && super.isDisplayable; } - public override get isOutOfLodRange(): boolean { return this._outOfLodRange;} + public override get isOutOfLodRange(): boolean { return this._outOfLodRange; } public override setContent(content: ImageryTileContent): void { this._texture = content.imageryTexture; // No dispose - textures may be shared by terrain tiles so let garbage collector dispose them. @@ -57,10 +57,10 @@ export class ImageryMapTile extends RealityTile { public selectCartoDrapeTiles(drapeTiles: ImageryMapTile[], highResolutionReplacementTiles: ImageryMapTile[], rectangleToDrape: MapCartoRectangle, drapePixelSize: number, args: TileDrawArgs): TileTreeLoadStatus { // Base draping overlap on width rather than height so that tiling schemes with multiple root nodes overlay correctly. const isSmallerThanDrape = (this.rectangle.xLength() / this.maximumSize) < drapePixelSize; - if ( (this.isLeaf ) // Include leaves so tiles get stretched past max LOD levels. (Only for base imagery layer) + if ((this.isLeaf) // Include leaves so tiles get stretched past max LOD levels. (Only for base imagery layer) || isSmallerThanDrape || this._anyChildNotFound) { - if (this.isOutOfLodRange ) { + if (this.isOutOfLodRange) { drapeTiles.push(this); this.setIsReady(); } else if (this.isLeaf && !isSmallerThanDrape && !this._anyChildNotFound) { @@ -120,7 +120,7 @@ export class ImageryMapTile extends RealityTile { const rectangle = imageryTree.tilingScheme.tileXYToRectangle(quadId.column, quadId.row, quadId.level); const range = Range3d.createXYZXYZ(rectangle.low.x, rectangle.low.x, 0, rectangle.high.x, rectangle.high.y, 0); const maximumSize = imageryTree.imageryLoader.maximumScreenSize; - const tile = new ImageryMapTile({ parent: this, isLeaf: childrenAreLeaves, contentId: quadId.contentId, range, maximumSize}, imageryTree, quadId, rectangle); + const tile = new ImageryMapTile({ parent: this, isLeaf: childrenAreLeaves, contentId: quadId.contentId, range, maximumSize }, imageryTree, quadId, rectangle); children.push(tile); }); @@ -150,9 +150,9 @@ export class ImageryMapTile extends RealityTile { private disposeTexture(): void { this._texture = dispose(this._texture); } - public override dispose() { + public override[Symbol.dispose]() { this._mapTileUsageCount = 0; - super.dispose(); + super[Symbol.dispose](); } } @@ -168,7 +168,7 @@ export class ImageryTileTreeState { /** Get the scale range visibility of the imagery tile tree. * @returns the scale range visibility of the imagery tile tree. */ - public getScaleRangeVisibility() {return this._scaleRangeVis;} + public getScaleRangeVisibility() { return this._scaleRangeVis; } /** Makes a deep copy of the current object. */ @@ -368,7 +368,7 @@ class ImageryMapLayerTreeSupplier implements TileTreeSupplier { const modelId = iModel.transientIds.getNext(); const tilingScheme = imageryProvider.tilingScheme; - const rootLevel = (1 === tilingScheme.numberOfLevelZeroTilesX && 1 === tilingScheme.numberOfLevelZeroTilesY) ? 0 : -1; + const rootLevel = (1 === tilingScheme.numberOfLevelZeroTilesX && 1 === tilingScheme.numberOfLevelZeroTilesY) ? 0 : -1; const rootTileId = new QuadId(rootLevel, 0, 0).contentId; const rootRange = Range3d.createXYZXYZ(-Angle.piRadians, -Angle.piOver2Radians, 0, Angle.piRadians, Angle.piOver2Radians, 0); const rootTileProps = { contentId: rootTileId, range: rootRange, maximumSize: 0 }; diff --git a/core/frontend/vitest.config.mts b/core/frontend/vitest.config.mts index 5a9d476f8ce5..50d4b0364b37 100644 --- a/core/frontend/vitest.config.mts +++ b/core/frontend/vitest.config.mts @@ -2,6 +2,9 @@ import { coverageConfigDefaults, defineConfig } from 'vitest/config'; import { viteStaticCopy } from 'vite-plugin-static-copy'; export default defineConfig({ + esbuild: { + target: "es2022", + }, test: { dir: "src", setupFiles: "./src/test/setupTests.ts", diff --git a/core/geometry/package.json b/core/geometry/package.json index 4c70d2796cfc..2d6c80157824 100644 --- a/core/geometry/package.json +++ b/core/geometry/package.json @@ -40,7 +40,7 @@ "@itwin/build-tools": "workspace:*", "@itwin/eslint-plugin": "5.0.0-dev.1", "@types/flatbuffers": "~1.10.0", - "@types/node": "~20.9.5", + "@types/node": "~20.17.0", "@vitest/coverage-v8": "^2.1.0", "eslint": "^9.13.0", "rimraf": "^3.0.2", @@ -51,4 +51,4 @@ "@itwin/core-bentley": "workspace:*", "flatbuffers": "~1.12.0" } -} +} \ No newline at end of file diff --git a/core/geometry/vitest.config.mts b/core/geometry/vitest.config.mts index 45ac268abffc..412e2081678f 100644 --- a/core/geometry/vitest.config.mts +++ b/core/geometry/vitest.config.mts @@ -1,5 +1,8 @@ import { coverageConfigDefaults, defineConfig } from 'vitest/config'; export default defineConfig({ + esbuild: { + target: "es2022", + }, test: { dir: "src/test", setupFiles: "./src/test/setupTests.ts", diff --git a/core/hypermodeling/src/HyperModeling.ts b/core/hypermodeling/src/HyperModeling.ts index 267808121f82..010f01874e80 100644 --- a/core/hypermodeling/src/HyperModeling.ts +++ b/core/hypermodeling/src/HyperModeling.ts @@ -226,7 +226,7 @@ export class HyperModeling { if (start) { return this._start(viewport); } else { - decorator?.dispose(); + decorator?.[Symbol.dispose](); return undefined; } } @@ -267,7 +267,7 @@ export class HyperModeling { */ public static stop(viewport: ScreenViewport): void { const decorator = HyperModelingDecorator.getForViewport(viewport); - decorator?.dispose(); + decorator?.[Symbol.dispose](); } /** @internal */ diff --git a/core/hypermodeling/src/HyperModelingDecorator.ts b/core/hypermodeling/src/HyperModelingDecorator.ts index bd6109f5e30d..19dc842099c1 100644 --- a/core/hypermodeling/src/HyperModelingDecorator.ts +++ b/core/hypermodeling/src/HyperModelingDecorator.ts @@ -183,7 +183,7 @@ export class HyperModelingDecorator implements Decorator { }); this._removeEventListeners.push(this.viewport.onViewportChanged.addListener((_, changeFlags) => this.onViewportChanged(changeFlags))); - this._removeEventListeners.push(this.viewport.onDisposed.addListener(() => this.dispose())); + this._removeEventListeners.push(this.viewport.onDisposed.addListener(() => this[Symbol.dispose]())); for (const marker of markers.markers) { marker.onMouseEnterEvent.addListener((mkr) => this.showToolbarAfterTimeout(mkr)); @@ -196,7 +196,7 @@ export class HyperModelingDecorator implements Decorator { private onViewportChanged(changeFlags: ChangeFlags): void { if (this.viewport.iModel !== this._iModel) { - this.dispose(); + this[Symbol.dispose](); return; } @@ -225,7 +225,7 @@ export class HyperModelingDecorator implements Decorator { } /** @internal */ - public dispose(): void { + public [Symbol.dispose](): void { if (!IModelApp.viewManager.dropDecorator(this)) return; diff --git a/core/i18n/package.json b/core/i18n/package.json index 7fc826775c31..f0a921fdf445 100644 --- a/core/i18n/package.json +++ b/core/i18n/package.json @@ -51,7 +51,7 @@ "@types/i18next": "^8.4.2", "@types/i18next-browser-languagedetector": "^2.0.1", "@types/mocha": "^10.0.6", - "@types/node": "~20.9.5", + "@types/node": "~20.17.0", "babel-loader": "~8.2.5", "babel-plugin-istanbul": "~6.1.1", "chai": "^4.3.10", @@ -73,4 +73,4 @@ "i18next-browser-languagedetector": "^6.1.2", "i18next-http-backend": "^1.4.4" } -} +} \ No newline at end of file diff --git a/core/mobile/package.json b/core/mobile/package.json index 821dca114d68..feffabfa9fe6 100644 --- a/core/mobile/package.json +++ b/core/mobile/package.json @@ -53,7 +53,7 @@ "@types/fs-extra": "^4.0.7", "@types/lodash": "^4.14.202", "@types/mocha": "^10.0.6", - "@types/node": "~20.9.5", + "@types/node": "~20.17.0", "@types/superagent": "^8.1.6", "@types/ws": "^7.0.0", "chai": "^4.3.10", @@ -65,4 +65,4 @@ "rimraf": "^3.0.2", "typescript": "~5.6.2" } -} +} \ No newline at end of file diff --git a/core/mobile/src/backend/MobileRpcServer.ts b/core/mobile/src/backend/MobileRpcServer.ts index 49a81da3e03e..bc69b488ba92 100644 --- a/core/mobile/src/backend/MobileRpcServer.ts +++ b/core/mobile/src/backend/MobileRpcServer.ts @@ -133,7 +133,7 @@ export class MobileRpcServer { MobileRpcServer.interop.handler(message, this._connectionId); } - public dispose() { + public [Symbol.dispose]() { clearInterval(this._pingTimer); if (this._connection) { MobileRpcServer.interop.sendString = () => { }; @@ -184,7 +184,7 @@ export function setupMobileRpc() { } retainUvLoop = setInterval(() => { }, 1000); - server.dispose(); + server[Symbol.dispose](); usePendingSender(); server = null; (global as any).__iTwinJsRpcReady = false; @@ -210,7 +210,7 @@ export function setupMobileRpc() { return; } - server.dispose(); + server[Symbol.dispose](); server = null; }); diff --git a/core/mobile/src/common/MobileIpc.ts b/core/mobile/src/common/MobileIpc.ts index d1929e4d75e0..f365204ce644 100644 --- a/core/mobile/src/common/MobileIpc.ts +++ b/core/mobile/src/common/MobileIpc.ts @@ -62,10 +62,9 @@ export class MobileIpcTransport extends IpcWebSocketTransport { } private async sendToBackend(message: IpcWebSocketMessage) { - const request = new MobileRpcRequest(this._client, "send", [message]); + using request = new MobileRpcRequest(this._client, "send", [message]); const encoded = await MobileRpcProtocol.encodeRequest(request); this._protocol.sendToBackend(encoded); - request.dispose(); } private sendToFrontend(message: IpcWebSocketMessage) { diff --git a/core/orbitgt/package.json b/core/orbitgt/package.json index 720b6cbc5a8f..7f660d10e159 100644 --- a/core/orbitgt/package.json +++ b/core/orbitgt/package.json @@ -36,7 +36,7 @@ "@itwin/eslint-plugin": "5.0.0-dev.1", "@types/chai": "4.3.1", "@types/mocha": "^10.0.6", - "@types/node": "~20.9.5", + "@types/node": "~20.17.0", "chai": "^4.3.10", "cpx2": "^3.0.0", "debug": "^2.6.9", @@ -49,4 +49,4 @@ "nyc": { "extends": "./node_modules/@itwin/build-tools/.nycrc" } -} +} \ No newline at end of file diff --git a/docs/changehistory/NextVersion.md b/docs/changehistory/NextVersion.md index 93f7ba54f029..29f6b96cbaa5 100644 --- a/docs/changehistory/NextVersion.md +++ b/docs/changehistory/NextVersion.md @@ -8,6 +8,7 @@ Table of contents: - [Selection set](#selection-set) - [API deprecations](#api-deprecations) + - [@itwin/core-bentley](#itwincore-bentley) - [@itwin/core-frontend](#itwincore-frontend) - [@itwin/presentation-common](#itwinpresentation-common) - [Breaking Changes](#breaking-changes) @@ -33,6 +34,32 @@ Because the `SelectionSet` now stores additional types of ids, existing code tha ## API deprecations +### @itwin/core-bentley + +- The [IDisposable]($core-bentley) interface, along with related [isIDisposable]($core-bentley) and [using]($core-bentley) utilities, have been deprecated in favor of [TypeScript's built-in](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-2.html#using-declarations-and-explicit-resource-management) `Disposable` type and `using` declarations (from the upcoming [Explicit Resource Management](https://github.com/tc39/proposal-explicit-resource-management) feature in ECMAScript). + + For example, the following: + + ```typescript + import { using } from "@itwin/core-bentley"; + export function doSomeWork() { + using(new SomethingDisposable(), (temp) => { + // do something with temp + }); + } + ``` + + should now be rewritten as: + + ```typescript + export function doSomeWork() { + using temp = new SomethingDisposable(); + // do something with temp + } + ``` + + > Note that while public types with deterministic cleanup logic in iTwin.js will continue to implement _both_ `IDisposable` and `Disposable` until the former is fully removed in iTwin.js 7.0 (in accordance with our [API support policy](../learning/api-support-policies)), disposable objects should still only be disposed once - _either_ with [IDisposable.dispose]($core-bentley) _or_ `Symbol.dispose()` but not both! Where possible, prefer `using` declarations or the [dispose]($core-bentley) helper function over directly calling either method. + ### @itwin/core-frontend - Deprecated [SelectionSet]($core-frontend)-related APIs: @@ -85,7 +112,7 @@ The following previously-deprecated APIs have been removed: As of iTwin.js 5.0, the following packages have been removed and are no longer available: -| Removed | Replacement | -| ------------------------------ | --------------------------------------------------------- | +| Removed | Replacement | +| ------------------------------ | ---------------------------------------------------------------------------------------------------------------------- | | `@itwin/core-webpack-tools` | We no longer recommend using [webpack](https://webpack.js.org/) and instead recommend using [Vite](https://vite.dev/). | -| `@itwin/backend-webpack-tools` | We no longer recommend webpack-ing backends, which was previously recommended to shrink the size of backends. | +| `@itwin/backend-webpack-tools` | We no longer recommend webpack-ing backends, which was previously recommended to shrink the size of backends. | diff --git a/domains/analytical/backend/package.json b/domains/analytical/backend/package.json index a2550f6ef445..c842f76b8aeb 100644 --- a/domains/analytical/backend/package.json +++ b/domains/analytical/backend/package.json @@ -49,7 +49,7 @@ "@types/chai": "4.3.1", "@types/fs-extra": "^4.0.7", "@types/mocha": "^10.0.6", - "@types/node": "~20.9.5", + "@types/node": "~20.17.0", "@types/semver": "7.3.10", "chai": "^4.3.10", "cpx2": "^3.0.0", @@ -66,4 +66,4 @@ "nyc": { "extends": "./node_modules/@itwin/build-tools/.nycrc" } -} +} \ No newline at end of file diff --git a/domains/linear-referencing/backend/package.json b/domains/linear-referencing/backend/package.json index 308a22af660e..6e55eb9353ca 100644 --- a/domains/linear-referencing/backend/package.json +++ b/domains/linear-referencing/backend/package.json @@ -51,7 +51,7 @@ "@types/chai": "4.3.1", "@types/fs-extra": "^4.0.7", "@types/mocha": "^10.0.6", - "@types/node": "~20.9.5", + "@types/node": "~20.17.0", "chai": "^4.3.10", "cpx2": "^3.0.0", "eslint": "^9.13.0", @@ -66,4 +66,4 @@ "nyc": { "extends": "./node_modules/@itwin/build-tools/.nycrc" } -} +} \ No newline at end of file diff --git a/domains/physical-material/backend/package.json b/domains/physical-material/backend/package.json index 948a5fca6b92..8600bf543c6e 100644 --- a/domains/physical-material/backend/package.json +++ b/domains/physical-material/backend/package.json @@ -49,7 +49,7 @@ "@types/chai": "4.3.1", "@types/fs-extra": "^4.0.7", "@types/mocha": "^10.0.6", - "@types/node": "~20.9.5", + "@types/node": "~20.17.0", "chai": "^4.3.10", "eslint": "^9.13.0", "mocha": "^10.2.0", @@ -63,4 +63,4 @@ "nyc": { "extends": "./node_modules/@itwin/build-tools/.nycrc" } -} +} \ No newline at end of file diff --git a/example-code/app/package.json b/example-code/app/package.json index 379a60c75d09..77a499f3c406 100644 --- a/example-code/app/package.json +++ b/example-code/app/package.json @@ -31,7 +31,7 @@ "@itwin/oidc-signin-tool": "^4.4.0", "@types/chai": "4.3.1", "@types/mocha": "^10.0.6", - "@types/node": "~20.9.5", + "@types/node": "~20.17.0", "chai": "^4.3.10", "cpx2": "^3.0.0", "eslint": "^9.13.0", @@ -54,4 +54,4 @@ "reporter-options": "mochaFile=lib/test/junit_results.xml", "timeout": 999999 } -} +} \ No newline at end of file diff --git a/example-code/snippets/package.json b/example-code/snippets/package.json index 6ad27f902cb6..ace45ae2ffa6 100644 --- a/example-code/snippets/package.json +++ b/example-code/snippets/package.json @@ -44,7 +44,7 @@ "@types/chai-as-promised": "^7", "@types/fs-extra": "^4.0.7", "@types/mocha": "^10.0.6", - "@types/node": "~20.9.5", + "@types/node": "~20.17.0", "chai": "^4.3.10", "chai-as-promised": "^7.1.1", "cpx2": "^3.0.0", @@ -67,4 +67,4 @@ "reporter-options": "mochaFile=lib/test/junit_results.xml", "timeout": 999999 } -} +} \ No newline at end of file diff --git a/extensions/frontend-tiles/package.json b/extensions/frontend-tiles/package.json index a1fed9176ee3..66af59c88a1c 100644 --- a/extensions/frontend-tiles/package.json +++ b/extensions/frontend-tiles/package.json @@ -50,7 +50,7 @@ "@types/chai": "4.3.1", "@types/chai-as-promised": "^7", "@types/mocha": "^10.0.6", - "@types/node": "~20.9.5", + "@types/node": "~20.17.0", "@types/sinon": "^17.0.2", "babel-loader": "~8.2.5", "babel-plugin-istanbul": "~6.1.1", @@ -65,4 +65,4 @@ "typescript": "~5.6.2", "webpack": "^5.97.1" } -} +} \ No newline at end of file diff --git a/extensions/frontend-tiles/src/BatchedSpatialTileTreeRefs.ts b/extensions/frontend-tiles/src/BatchedSpatialTileTreeRefs.ts index 2f1b4361f5f8..429934ba5a60 100644 --- a/extensions/frontend-tiles/src/BatchedSpatialTileTreeRefs.ts +++ b/extensions/frontend-tiles/src/BatchedSpatialTileTreeRefs.ts @@ -206,7 +206,7 @@ class ProxyTileTreeReference extends TileTreeReference { tileTree: undefined, loadStatus: TileTreeLoadStatus.NotLoaded, load: () => undefined, - dispose: () => { }, + [Symbol.dispose]: () => { }, loadTree: async () => Promise.resolve(undefined), }; } diff --git a/extensions/frontend-tiles/src/BatchedTileTree.ts b/extensions/frontend-tiles/src/BatchedTileTree.ts index f1552d20a0c8..286c449f1cdc 100644 --- a/extensions/frontend-tiles/src/BatchedTileTree.ts +++ b/extensions/frontend-tiles/src/BatchedTileTree.ts @@ -52,9 +52,9 @@ export class BatchedTileTree extends TileTree { }); } - public override dispose(): void { + public override[Symbol.dispose](): void { this.decoder.release(); - super.dispose(); + super[Symbol.dispose](); } public override get rootTile(): BatchedTile { @@ -70,7 +70,7 @@ export class BatchedTileTree extends TileTree { } public override get viewFlagOverrides(): ViewFlagOverrides { - return frontendTilesOptions.enableEdges ?{ } : defaultViewFlags; + return frontendTilesOptions.enableEdges ? {} : defaultViewFlags; } // eslint-disable-next-line @typescript-eslint/naming-convention diff --git a/extensions/frontend-tiles/src/test/GraphicsProvider/GraphicRepresentationProvider.test.ts b/extensions/frontend-tiles/src/test/GraphicsProvider/GraphicRepresentationProvider.test.ts index e0bdeaf215de..730dda74ce6a 100644 --- a/extensions/frontend-tiles/src/test/GraphicsProvider/GraphicRepresentationProvider.test.ts +++ b/extensions/frontend-tiles/src/test/GraphicsProvider/GraphicRepresentationProvider.test.ts @@ -179,7 +179,7 @@ describe("obtainGraphicRepresentationUrl", () => { before(async () => IModelApp.startup()); after(async () => IModelApp.shutdown()); - async function fetchSources(resource: NodeJS.fetch.RequestInfo | RequestInfo): Promise { + async function fetchSources(resource: URL | RequestInfo): Promise { expect(typeof resource).to.equal("string"); const url = resource as string; diff --git a/extensions/frontend-tiles/src/test/GraphicsProvider/GraphicsProvider.test.ts b/extensions/frontend-tiles/src/test/GraphicsProvider/GraphicsProvider.test.ts index a8399c869715..88b3b6c3e021 100644 --- a/extensions/frontend-tiles/src/test/GraphicsProvider/GraphicsProvider.test.ts +++ b/extensions/frontend-tiles/src/test/GraphicsProvider/GraphicsProvider.test.ts @@ -98,7 +98,7 @@ async function makeExportsResponse(props: ExportsProps): Promise { const accessToken = "this-is-a-fake-access-token"; -async function fetchExports(resource: NodeJS.fetch.RequestInfo | RequestInfo, exportProps: ExportProps[]): Promise { +async function fetchExports(resource: URL | RequestInfo, exportProps: ExportProps[]): Promise { expect(typeof resource).to.equal("string"); const url = resource as string; diff --git a/extensions/map-layers-formats/src/Tools/GeometryTerrainDraper.ts b/extensions/map-layers-formats/src/Tools/GeometryTerrainDraper.ts index 7815add08b9a..e2888533723e 100644 --- a/extensions/map-layers-formats/src/Tools/GeometryTerrainDraper.ts +++ b/extensions/map-layers-formats/src/Tools/GeometryTerrainDraper.ts @@ -5,7 +5,8 @@ import { CollectTileStatus, DisclosedTileTreeSet, GeometryTileTreeReference, IModelApp, - Tile, TileGeometryCollector, TileUser, Viewport } from "@itwin/core-frontend"; + Tile, TileGeometryCollector, TileUser, Viewport +} from "@itwin/core-frontend"; import { Angle, ConvexClipPlaneSet, CurvePrimitive, GrowableXYZArray, IndexedPolyface, IndexedPolyfaceSubsetVisitor, Loop, Point3d, Polyface, PolyfaceClip, PolyfaceQuery, PolygonOps, Range3d, Ray3d, SweepLineStringToFacetsOptions, Transform, Vector3d } from "@itwin/core-geometry"; import { Logger } from "@itwin/core-bentley"; @@ -34,7 +35,7 @@ class LineSegmentCollector extends TileGeometryCollector { status = "reject"; } - Logger.logTrace(loggerCategory, `collectTile - tile: ${tile.contentId} status: ${status } isReady: ${tile.isReady} status:${tile.loadStatus}`); + Logger.logTrace(loggerCategory, `collectTile - tile: ${tile.contentId} status: ${status} isReady: ${tile.isReady} status:${tile.loadStatus}`); return status; } @@ -66,7 +67,7 @@ export class GeometryTerrainDraper implements TileUser { IModelApp.tileAdmin.registerUser(this); } - public dispose(): void { + public [Symbol.dispose](): void { IModelApp.tileAdmin.forgetUser(this); } @@ -90,7 +91,7 @@ export class GeometryTerrainDraper implements TileUser { const topFacets: number[] = []; const facetNormal = Vector3d.createZero(); - for (const visitor = mesh.createVisitor(0); visitor.moveToNextFacet(); ) { + for (const visitor = mesh.createVisitor(0); visitor.moveToNextFacet();) { if (PolygonOps.unitNormal(visitor.point, facetNormal)) { const theta = facetNormal.angleFromPerpendicular(sweepVector); if (!theta.isMagnitudeLessThanOrEqual(this.sideAngle)) { // skip side facet @@ -170,14 +171,14 @@ export class GeometryTerrainDraper implements TileUser { expandedRange.extendZOnly(-this.maxDistanceZ); expandedRange.extendZOnly(this.maxDistanceZ); - const collector = new TileGeometryCollector({chordTolerance, range: expandedRange, user: this }); + const collector = new TileGeometryCollector({ chordTolerance, range: expandedRange, user: this }); this.treeRef.collectTileGeometry(collector); collector.requestMissingTiles(); if (collector.isAllGeometryLoaded && collector.polyfaces.length > 0) { for (const polyface of collector.polyfaces) { // Im assuming a single polyface here since we are draping a single point - const facetLocation = PolyfaceQuery.intersectRay3d(polyface, Ray3d.create(point, Vector3d.unitZ() )); + const facetLocation = PolyfaceQuery.intersectRay3d(polyface, Ray3d.create(point, Vector3d.unitZ())); if (!facetLocation) continue; outPoint.setFromPoint3d(facetLocation.point); diff --git a/extensions/map-layers-formats/src/Tools/MapFeatureInfoDecorator.ts b/extensions/map-layers-formats/src/Tools/MapFeatureInfoDecorator.ts index 768143d5fa0a..31f6e7a589ac 100644 --- a/extensions/map-layers-formats/src/Tools/MapFeatureInfoDecorator.ts +++ b/extensions/map-layers-formats/src/Tools/MapFeatureInfoDecorator.ts @@ -210,7 +210,7 @@ export class MapFeatureInfoDecorator implements Decorator { if (this._draper) { // Dispose draper every time? - this._draper.dispose(); + this._draper[Symbol.dispose](); this._draper = undefined; } }; diff --git a/full-stack-tests/backend/src/HubUtility.ts b/full-stack-tests/backend/src/HubUtility.ts index da91c9ecabde..45a8cbffe34f 100644 --- a/full-stack-tests/backend/src/HubUtility.ts +++ b/full-stack-tests/backend/src/HubUtility.ts @@ -115,9 +115,8 @@ export class HubUtility { const earliestChangesetIndex = earliestIndex > 0 ? earliestIndex - 1 : 0; // Query results exclude earliest specified changeset const latestChangesetIndex = latestIndex; // Query results include latest specified change set - const perfLogger = new PerfLogger("HubUtility.downloadChangesets -> Download Changesets"); + using _perfLogger = new PerfLogger("HubUtility.downloadChangesets -> Download Changesets"); await IModelHost.hubAccess.downloadChangesets({ accessToken, iModelId, range: { first: earliestChangesetIndex, end: latestChangesetIndex }, targetDir: changesetsPath }); - perfLogger.dispose(); return changesets; } @@ -135,7 +134,7 @@ export class HubUtility { // Download the seed file const seedPathname = path.join(downloadDir, "seed", iModelId.concat(".bim")); if (!IModelJsFs.existsSync(seedPathname)) { - const perfLogger = new PerfLogger("HubUtility.downloadIModelById -> Download Seed File"); + using _perfLogger = new PerfLogger("HubUtility.downloadIModelById -> Download Seed File"); await V1CheckpointManager.downloadCheckpoint({ localFile: seedPathname, checkpoint: { @@ -148,7 +147,6 @@ export class HubUtility { }, }, }); - perfLogger.dispose(); } // Download the change sets @@ -228,7 +226,7 @@ export class HubUtility { }); } - perfLogger.dispose(); + perfLogger[Symbol.dispose](); nativeDb.closeFile(); return results; diff --git a/full-stack-tests/backend/src/integration/ApplyChangeSets.test.ts b/full-stack-tests/backend/src/integration/ApplyChangeSets.test.ts index b801d6011fa6..5c5af67848c9 100644 --- a/full-stack-tests/backend/src/integration/ApplyChangeSets.test.ts +++ b/full-stack-tests/backend/src/integration/ApplyChangeSets.test.ts @@ -88,7 +88,7 @@ async function validateAllChangesetOperationsOnDisk(iModelDir: string) { /** Applies changesets one by one (for debugging) */ function applyChangesetsToNativeDb(nativeDb: IModelJsNative.DgnDb, changeSets: ChangesetFileProps[]): ChangeSetStatus { - const perfLogger = new PerfLogger(`Applying change sets]}`); + using _perfLogger = new PerfLogger(`Applying change sets]}`); // Apply change sets one by one to debug any issues let count = 0; @@ -100,11 +100,9 @@ function applyChangesetsToNativeDb(nativeDb: IModelJsNative.DgnDb, changeSets: C Logger.logInfo(HubUtility.logCategory, "Successfully applied Changeset", () => ({ ...changeSet, status })); } catch (err: any) { Logger.logError(HubUtility.logCategory, `Error applying Changeset ${err.errorNumber}`, () => ({ ...changeSet })); - perfLogger.dispose(); return err.errorNumber; } } - perfLogger.dispose(); return ChangeSetStatus.Success; } diff --git a/full-stack-tests/backend/src/integration/ChangeSummary.test.ts b/full-stack-tests/backend/src/integration/ChangeSummary.test.ts index 3a85a99afd9b..9b7458d91cf9 100644 --- a/full-stack-tests/backend/src/integration/ChangeSummary.test.ts +++ b/full-stack-tests/backend/src/integration/ChangeSummary.test.ts @@ -318,11 +318,11 @@ describe("ChangeSummary", () => { let perfLogger = new PerfLogger("CreateChangeSummaries"); await ChangeSummaryManager.createChangeSummaries({ accessToken, iTwinId, iModelId, range: { first: 0 } }); - perfLogger.dispose(); + perfLogger[Symbol.dispose](); perfLogger = new PerfLogger("IModelDb.open"); const iModel = await HubWrappers.downloadAndOpenBriefcase({ accessToken, iTwinId, iModelId }); - perfLogger.dispose(); + perfLogger[Symbol.dispose](); try { assert.exists(iModel); ChangeSummaryManager.attachChangeCache(iModel); @@ -340,7 +340,7 @@ describe("ChangeSummary", () => { const csum: ChangeSummary = ChangeSummaryManager.queryChangeSummary(iModel, Id64.fromJSON(row.id)); changeSummaries.push(csum); } - perfLogger.dispose(); + perfLogger[Symbol.dispose](); }); for (const changeSummary of changeSummaries) { @@ -384,7 +384,7 @@ describe("ChangeSummary", () => { content.instanceChanges.push(instanceChange); } - perfLogger.dispose(); + perfLogger[Symbol.dispose](); }); IModelJsFs.writeFileSync(filePath, JSON.stringify(content)); @@ -437,7 +437,7 @@ describe("ChangeSummary", () => { // Validate that the second change summary captures the change to the parent correctly try { - const changeSummaryIds = await ChangeSummaryManager.createChangeSummaries({ accessToken, iTwinId: iModel.iTwinId, iModelId, range: { first: 0 }}); + const changeSummaryIds = await ChangeSummaryManager.createChangeSummaries({ accessToken, iTwinId: iModel.iTwinId, iModelId, range: { first: 0 } }); assert.strictEqual(2, changeSummaryIds.length); ChangeSummaryManager.attachChangeCache(iModel); @@ -495,7 +495,7 @@ describe("ChangeSummary", () => { // User2 applies the change set and extracts the change summary await iModel.pullChanges({ accessToken: userContext2 }); - const changeSummariesIds = await ChangeSummaryManager.createChangeSummaries({ accessToken: userContext2, iTwinId: iModel.iTwinId, iModelId: iModel.iModelId, range: { first: 0 }}); + const changeSummariesIds = await ChangeSummaryManager.createChangeSummaries({ accessToken: userContext2, iTwinId: iModel.iTwinId, iModelId: iModel.iModelId, range: { first: 0 } }); if (changeSummariesIds.length !== 1) throw new Error("ChangeSet summary extraction returned invalid ChangeSet summary IDs."); diff --git a/full-stack-tests/backend/src/perftest/Sqlite.test.ts b/full-stack-tests/backend/src/perftest/Sqlite.test.ts index 2bb83ff784f8..d0871173a2d8 100644 --- a/full-stack-tests/backend/src/perftest/Sqlite.test.ts +++ b/full-stack-tests/backend/src/perftest/Sqlite.test.ts @@ -6,7 +6,7 @@ import * as fs from "fs"; import * as os from "os"; import * as path from "path"; import * as readline from "readline"; -import { DbResult, OpenMode, StopWatch, using } from "@itwin/core-bentley"; +import { DbResult, OpenMode, StopWatch } from "@itwin/core-bentley"; import { ECDb, ECDbOpenMode, SQLiteDb, SqliteStatement } from "@itwin/core-backend"; import { KnownTestLocations } from "@itwin/core-backend/lib/cjs/test/index"; @@ -28,32 +28,32 @@ async function reportProgress(prefix: string, c: number, m: number) { } async function createSeedFile(pathName: string, tbl: string, nCols: number, nRows: number, startId: number) { const kMaxLengthOfString = 11; - await using(new ECDb(), async (ecdb) => { - ecdb.createDb(pathName); - const cols = []; - for (let i = 0; i < nCols; i++) { - cols.push(`[c${i}]`); - } - const sp = new StopWatch(undefined, true); - process.stdout.write(`Creating seed file ... ${pathName}\n`); - ecdb.withPreparedSqliteStatement(`create table [${tbl}](id integer primary key,${cols.join(",")});`, (stmt) => stmt.step()); - await using(ecdb.prepareSqliteStatement(`insert into ${tbl} values(?${",?".repeat(nCols)});`), async (stmt: SqliteStatement) => { - for (let i = 0; i < nRows; i++) { - stmt.reset(); - stmt.clearBindings(); - stmt.bindValue(1, startId + i); - for (let j = 2; j < nCols; j++) { - const randStr = makeRandStr(Math.round(Math.random() * kMaxLengthOfString + 1)); - stmt.bindValue(j, randStr); - } - stmt.step(); - await reportProgress("Generating seed file ...", i + 1, nRows); + using ecdb = new ECDb() + ecdb.createDb(pathName); + const cols = []; + for (let i = 0; i < nCols; i++) { + cols.push(`[c${i}]`); + } + const sp = new StopWatch(undefined, true); + process.stdout.write(`Creating seed file ... ${pathName}\n`); + ecdb.withPreparedSqliteStatement(`create table [${tbl}](id integer primary key,${cols.join(",")});`, (stmt) => stmt.step()); + { + using stmt = ecdb.prepareSqliteStatement(`insert into ${tbl} values(?${",?".repeat(nCols)});`); + for (let i = 0; i < nRows; i++) { + stmt.reset(); + stmt.clearBindings(); + stmt.bindValue(1, startId + i); + for (let j = 2; j < nCols; j++) { + const randStr = makeRandStr(Math.round(Math.random() * kMaxLengthOfString + 1)); + stmt.bindValue(j, randStr); } - }); - ecdb.saveChanges(); - sp.stop(); - process.stdout.write(`Completed in ${sp.elapsedSeconds} sec\n`); - }); + stmt.step(); + await reportProgress("Generating seed file ...", i + 1, nRows); + } + } + ecdb.saveChanges(); + sp.stop(); + process.stdout.write(`Completed in ${sp.elapsedSeconds} sec\n`); } async function readRow(stmt: SqliteStatement, id: number, nParam: number = 1): Promise { stmt.reset(); @@ -158,14 +158,13 @@ async function runReadTest(param: ReadParams) { const result: number[] = []; while (r++ < param.runCount) { process.stdout.write(`Run ... [${r}/${param.runCount}] `); - await using(new ECDb(), async (ecdb: ECDb) => { - ecdb.openDb(testFilepath, ECDbOpenMode.Readonly); - if (!ecdb.isOpen) - throw new Error(`changePageSize() fail to open file ${testFilepath}`); - await ecdb.withPreparedSqliteStatement(`select * from ${testTableName} where id=?`, async (stmt: SqliteStatement) => { - const elapsedTime = await simulateRowRead(stmt, param.probabilityOfConsecutiveReads, param.percentageOfRowsToRead, param.startId, param.startId + param.seedRowCount); - result.push(elapsedTime); - }); + using ecdb = new ECDb(); + ecdb.openDb(testFilepath, ECDbOpenMode.Readonly); + if (!ecdb.isOpen) + throw new Error(`changePageSize() fail to open file ${testFilepath}`); + await ecdb.withPreparedSqliteStatement(`select * from ${testTableName} where id=?`, async (stmt: SqliteStatement) => { + const elapsedTime = await simulateRowRead(stmt, param.probabilityOfConsecutiveReads, param.percentageOfRowsToRead, param.startId, param.startId + param.seedRowCount); + result.push(elapsedTime); }); } diff --git a/full-stack-tests/core/package.json b/full-stack-tests/core/package.json index 506e7dbce6f5..2702e0debe23 100644 --- a/full-stack-tests/core/package.json +++ b/full-stack-tests/core/package.json @@ -70,7 +70,7 @@ "@types/chai-as-promised": "^7", "@types/fs-extra": "^4.0.7", "@types/mocha": "^10.0.6", - "@types/node": "~20.9.5", + "@types/node": "~20.17.0", "@types/sinon": "^17.0.2", "@types/sinon-chai": "^3.2.0", "assert": "^2.0.0", diff --git a/full-stack-tests/core/src/frontend/TestViewport.ts b/full-stack-tests/core/src/frontend/TestViewport.ts index 6c1ebfde5454..e06f93bcb664 100644 --- a/full-stack-tests/core/src/frontend/TestViewport.ts +++ b/full-stack-tests/core/src/frontend/TestViewport.ts @@ -274,10 +274,10 @@ export class ScreenTestViewport extends ScreenViewport implements TestableViewpo return this.waitForRenderFrame(); } - public override dispose(): void { + public override[Symbol.dispose](): void { if (!this.isDisposed) { IModelApp.viewManager.dropViewport(this, false); // do not allow dropViewport() to call dispose()... - super.dispose(); + super[Symbol.dispose](); document.body.removeChild(this.parentDiv); } } @@ -330,13 +330,12 @@ export async function testOnScreenViewport(viewId: Id64String, imodel: IModelCon return; // ###TODO: Make ScreenTestViewport integrate properly with the (non-continuous) render loop... - const onscreen = await createOnScreenTestViewport(viewId, imodel, width, height, devicePixelRatio); + using onscreen = await createOnScreenTestViewport(viewId, imodel, width, height, devicePixelRatio); onscreen.continuousRendering = true; try { await test(onscreen); } finally { onscreen.continuousRendering = false; - onscreen.dispose(); } } @@ -344,12 +343,8 @@ export async function testOffScreenViewport(viewId: Id64String, imodel: IModelCo if (!IModelApp.initialized) return; - const offscreen = await createOffScreenTestViewport(viewId, imodel, width, height); - try { - await test(offscreen); - } finally { - offscreen.dispose(); - } + using offscreen = await createOffScreenTestViewport(viewId, imodel, width, height); + await test(offscreen); } // Execute a test against both an off-screen and on-screen viewport. diff --git a/full-stack-tests/core/src/frontend/ViewportChangedHandler.ts b/full-stack-tests/core/src/frontend/ViewportChangedHandler.ts index 8e1a5773fcf4..bcb28407f357 100644 --- a/full-stack-tests/core/src/frontend/ViewportChangedHandler.ts +++ b/full-stack-tests/core/src/frontend/ViewportChangedHandler.ts @@ -79,7 +79,7 @@ export class ViewportChangedHandler { this.expect(ChangeFlag.Initial, undefined, () => undefined); } - public dispose() { + public [Symbol.dispose]() { Viewport.undoDelay = this._undoDelay; for (const removal of this._removals) @@ -88,20 +88,6 @@ export class ViewportChangedHandler { this._removals.length = 0; } - /** Install a ViewportChangedHandler, execute the specified function, and uninstall the handler. */ - public static test(vp: Viewport, func: (mon: ViewportChangedHandler) => void): void { - const mon = new ViewportChangedHandler(vp); - func(mon); - mon.dispose(); - } - - /** Async version of test(). */ - public static async testAsync(vp: Viewport, func: (mon: ViewportChangedHandler) => Promise): Promise { - const mon = new ViewportChangedHandler(vp); - await func(mon); - mon.dispose(); - } - /** Assert that executing the supplied function causes events to be omitted resulting in the specified flags. */ public expect(flags: ChangeFlag, state: ViewportState | undefined, func: () => void): void { if (undefined === state) diff --git a/full-stack-tests/core/src/frontend/standalone/AttachView.test.ts b/full-stack-tests/core/src/frontend/standalone/AttachView.test.ts index 8ccfca5f5709..dd0f6ba83c96 100644 --- a/full-stack-tests/core/src/frontend/standalone/AttachView.test.ts +++ b/full-stack-tests/core/src/frontend/standalone/AttachView.test.ts @@ -27,7 +27,7 @@ describe("ViewState attached to Viewport", async () => { afterEach(() => { if (vp && !vp.isDisposed) - vp.dispose(); + vp[Symbol.dispose](); }); async function loadView(id = "0x34"): Promise { @@ -47,7 +47,7 @@ describe("ViewState attached to Viewport", async () => { const view = await loadView(); vp = ScreenViewport.create(div, view); expect(view.isAttachedToViewport).to.be.true; - vp.dispose(); + vp[Symbol.dispose](); expect(view.isAttachedToViewport).to.be.false; }); @@ -136,7 +136,7 @@ describe("ViewState attached to Viewport", async () => { expectChanges(false, false, true); reset(); - vp.dispose(); + vp[Symbol.dispose](); view.modelSelector.models.add("0xa"); view.categorySelector.categories.add("0xb"); view.categorySelector = view.categorySelector.clone(); diff --git a/full-stack-tests/core/src/frontend/standalone/EmphasizeElements.test.ts b/full-stack-tests/core/src/frontend/standalone/EmphasizeElements.test.ts index d36c15b534d2..7cb84ca2252f 100644 --- a/full-stack-tests/core/src/frontend/standalone/EmphasizeElements.test.ts +++ b/full-stack-tests/core/src/frontend/standalone/EmphasizeElements.test.ts @@ -381,14 +381,14 @@ describe("EmphasizeElements tests", () => { it("to/from JSON", async () => { function roundTrip(populate: (emph: EmphasizeElements, vp: ScreenViewport) => void): void { - const vp1 = ScreenViewport.create(viewDiv, spatialView.clone()); + using vp1 = ScreenViewport.create(viewDiv, spatialView.clone()); EmphasizeElements.clear(vp1); const before = EmphasizeElements.getOrCreate(vp1); populate(before, vp1); const inputJson = JSON.stringify(before.toJSON(vp1)); - const vp2 = ScreenViewport.create(viewDiv, spatialView.clone()); + using vp2 = ScreenViewport.create(viewDiv, spatialView.clone()); const after = EmphasizeElements.getOrCreate(vp2); after.fromJSON(JSON.parse(inputJson), vp2); const outputJson = JSON.stringify(after.toJSON(vp2)); @@ -437,9 +437,6 @@ describe("EmphasizeElements tests", () => { EmphasizeElements.clear(vp1); EmphasizeElements.clear(vp2); - - vp1.dispose(); - vp2.dispose(); } roundTrip((emph, _vp) => { diff --git a/full-stack-tests/core/src/frontend/standalone/GraphicalEditingScope.test.ts b/full-stack-tests/core/src/frontend/standalone/GraphicalEditingScope.test.ts index e1d3a1a47dca..10b9bdf94e28 100644 --- a/full-stack-tests/core/src/frontend/standalone/GraphicalEditingScope.test.ts +++ b/full-stack-tests/core/src/frontend/standalone/GraphicalEditingScope.test.ts @@ -9,7 +9,8 @@ import { BeDuration, compareStrings, DbOpcode, Guid, Id64String, OpenMode, Proce import { Point3d, Range3d, Transform } from "@itwin/core-geometry"; import { BatchType, ChangedEntities, ElementGeometryChange, IModelError, RenderSchedule } from "@itwin/core-common"; import { - BriefcaseConnection, DynamicIModelTile, GeometricModel3dState, GraphicalEditingScope, IModelTileTree, IModelTileTreeParams, OnScreenTarget, TileLoadPriority } from "@itwin/core-frontend"; + BriefcaseConnection, DynamicIModelTile, GeometricModel3dState, GraphicalEditingScope, IModelTileTree, IModelTileTreeParams, OnScreenTarget, TileLoadPriority +} from "@itwin/core-frontend"; import { addAllowedChannel, coreFullStackTestIpc, deleteElements, initializeEditTools, insertLineElement, makeLineSegment, makeModelCode, transformElements } from "../Editing"; import { TestUtility } from "../TestUtility"; import { testOnScreenViewport } from "../TestViewport"; @@ -317,7 +318,7 @@ describe("GraphicalEditingScope", () => { await expectTreeState(tree1, "static", 0, modelRange); const tree0 = createTileTree(); - tree0.dispose(); + tree0[Symbol.dispose](); await expectTreeState(tree0, "disposed", 0, modelRange); // Enter an editing scope. @@ -375,13 +376,13 @@ describe("GraphicalEditingScope", () => { const tree2 = trees.pop()!; await expectTreeState(tree0, "disposed", 0, modelRange); await expectTreeState(trees, "interactive", 0, modelRange); - tree2.dispose(); + tree2[Symbol.dispose](); await expectTreeState(tree2, "disposed", 0, modelRange); await scope.exit(); await expectTreeState(trees, "static", 0, modelRange); for (const tree of trees) { - tree.dispose(); + tree[Symbol.dispose](); await expectTreeState(tree, "disposed", 0, modelRange); } }); @@ -461,7 +462,7 @@ describe("GraphicalEditingScope", () => { // Enter an editing scope. const scope = await imodel.enterEditingScope(); - const tree = createTileTree(); + using tree = createTileTree(); await expectTileState(tree, elementRange); // Move an element (+1 in Y). @@ -486,8 +487,6 @@ describe("GraphicalEditingScope", () => { // Terminate the scope. await scope.exit(); - - tree.dispose(); }); it("edited elements should be updated by scheduling scripts", async () => { diff --git a/full-stack-tests/core/src/frontend/standalone/Markup.test.ts b/full-stack-tests/core/src/frontend/standalone/Markup.test.ts index 980e91d6482b..82bdab0bdb46 100644 --- a/full-stack-tests/core/src/frontend/standalone/Markup.test.ts +++ b/full-stack-tests/core/src/frontend/standalone/Markup.test.ts @@ -23,7 +23,7 @@ describe("Markup tests", async () => { }); after(async () => { - vp.dispose(); + vp[Symbol.dispose](); await imodel?.close(); await TestUtility.shutdownFrontend(); }); diff --git a/full-stack-tests/core/src/frontend/standalone/PerModelCategoryVisibility.test.ts b/full-stack-tests/core/src/frontend/standalone/PerModelCategoryVisibility.test.ts index c11d3bd805f4..4a53aaf8f608 100644 --- a/full-stack-tests/core/src/frontend/standalone/PerModelCategoryVisibility.test.ts +++ b/full-stack-tests/core/src/frontend/standalone/PerModelCategoryVisibility.test.ts @@ -91,7 +91,7 @@ describe("Per-model category visibility overrides", () => { }); afterEach(() => { - vp.dispose(); + vp[Symbol.dispose](); }); after(async () => { @@ -286,7 +286,7 @@ describe("Per-model category visibility overrides with setOverrides function", ( }); afterEach(() => { - vp.dispose(); + vp[Symbol.dispose](); }); after(async () => { @@ -308,8 +308,8 @@ describe("Per-model category visibility overrides with setOverrides function", ( // Turn on category 2f for model 1c, and turn off category 17 for model 1f (latter is no-op because already off). const pmcv = vp.perModelCategoryVisibility; const overrides: PerModelCategoryVisibility.Props[] = []; - overrides.push({modelId: "0x1c", categoryIds: "0x2f", visOverride: show}); - overrides.push({modelId: "0x1f", categoryIds: "0x17", visOverride: hide}); + overrides.push({ modelId: "0x1c", categoryIds: "0x2f", visOverride: show }); + overrides.push({ modelId: "0x1f", categoryIds: "0x17", visOverride: hide }); await pmcv.setOverrides(overrides); expect(pmcv.getOverride("0x1c", "0x2f")).to.equal(show); @@ -347,9 +347,9 @@ describe("Per-model category visibility overrides with setOverrides function", ( // Model 1c turns category 31 off. Model 1f turns category 17 on and category 2d off. const pmcv = vp.perModelCategoryVisibility; const overrides: PerModelCategoryVisibility.Props[] = []; - overrides.push({modelId: "0x1c", categoryIds: ["0x31"], visOverride: hide}); - overrides.push({modelId: "0x1f", categoryIds: ["0x17"], visOverride: show}); - overrides.push({modelId: "0x1f", categoryIds: "0x2d", visOverride: hide}); + overrides.push({ modelId: "0x1c", categoryIds: ["0x31"], visOverride: hide }); + overrides.push({ modelId: "0x1f", categoryIds: ["0x17"], visOverride: show }); + overrides.push({ modelId: "0x1f", categoryIds: "0x2d", visOverride: hide }); await pmcv.setOverrides(overrides); expect(pmcv.getOverride("0x1c", "0x31")).to.equal(hide); expect(pmcv.getOverride("0x1f", "0x17")).to.equal(show); @@ -403,8 +403,8 @@ describe("Per-model category visibility overrides with setOverrides function", ( // vp.perModelCategoryVisibility.setOverride("0x1c", ["0x2f", "0x31", "0x2d"], show); // vp.perModelCategoryVisibility.setOverride("0x1c", "0x17", hide); const overrides: PerModelCategoryVisibility.Props[] = []; - overrides.push({modelId: "0x1c", categoryIds: ["0x2f", "0x31", "0x2d"], visOverride: show}); - overrides.push({modelId: "0x1c", categoryIds: ["0x17"], visOverride: hide}); + overrides.push({ modelId: "0x1c", categoryIds: ["0x2f", "0x31", "0x2d"], visOverride: show }); + overrides.push({ modelId: "0x1c", categoryIds: ["0x17"], visOverride: hide }); await vp.perModelCategoryVisibility.setOverrides(overrides); ovrs = new Overrides(vp); @@ -430,10 +430,10 @@ describe("Per-model category visibility overrides with setOverrides function", ( it("supports iteration", async () => { const pmcv = vp.perModelCategoryVisibility; const overrides: PerModelCategoryVisibility.Props[] = []; - overrides.push({modelId: "0x1c", categoryIds: ["0x2f", "0x31"], visOverride: show}); - overrides.push({modelId: "0x1c", categoryIds: ["0x2d"], visOverride:hide}); - overrides.push({modelId: "0x1d", categoryIds: "0x2d", visOverride: show}); - overrides.push({modelId: "0x1d", categoryIds: ["0x2f", "0x2e"], visOverride: hide}); + overrides.push({ modelId: "0x1c", categoryIds: ["0x2f", "0x31"], visOverride: show }); + overrides.push({ modelId: "0x1c", categoryIds: ["0x2d"], visOverride: hide }); + overrides.push({ modelId: "0x1d", categoryIds: "0x2d", visOverride: show }); + overrides.push({ modelId: "0x1d", categoryIds: ["0x2f", "0x2e"], visOverride: hide }); await pmcv.setOverrides(overrides); let nIterations = 0; diff --git a/full-stack-tests/core/src/frontend/standalone/PrimitiveBuilder.test.ts b/full-stack-tests/core/src/frontend/standalone/PrimitiveBuilder.test.ts index 0c0408766b20..7d1bab52d3e0 100644 --- a/full-stack-tests/core/src/frontend/standalone/PrimitiveBuilder.test.ts +++ b/full-stack-tests/core/src/frontend/standalone/PrimitiveBuilder.test.ts @@ -36,7 +36,7 @@ describe("PrimitiveBuilder", () => { }); after(async () => { - viewport?.dispose(); + viewport?.[Symbol.dispose](); await imodel?.close(); await TestUtility.shutdownFrontend(); }); diff --git a/full-stack-tests/core/src/frontend/standalone/RenderTarget.test.ts b/full-stack-tests/core/src/frontend/standalone/RenderTarget.test.ts index d63a4fafa30a..f7a77ce158e2 100644 --- a/full-stack-tests/core/src/frontend/standalone/RenderTarget.test.ts +++ b/full-stack-tests/core/src/frontend/standalone/RenderTarget.test.ts @@ -659,14 +659,11 @@ describe("RenderTarget", () => { it("should render off-screen if multiple viewports exist", async () => { const rect = new ViewRect(0, 0, 100, 100); - const vp0 = await createOnScreenTestViewport("0x24", imodel, rect.width, rect.height); + using vp0 = await createOnScreenTestViewport("0x24", imodel, rect.width, rect.height); expect(vp0.rendersToScreen).to.be.true; // when only one viewport is on the view manager, it should render using system canvas. - const vp1 = await createOnScreenTestViewport("0x24", imodel, rect.width, rect.height); + using vp1 = await createOnScreenTestViewport("0x24", imodel, rect.width, rect.height); expect(vp0.rendersToScreen).to.be.false; expect(vp1.rendersToScreen).to.be.false; - - vp0.dispose(); - vp1.dispose(); }); it("should clip using a single plane", async () => { diff --git a/full-stack-tests/core/src/frontend/standalone/SubCategoriesCache.test.ts b/full-stack-tests/core/src/frontend/standalone/SubCategoriesCache.test.ts index a24e88ac0f49..6f013ac69c3b 100644 --- a/full-stack-tests/core/src/frontend/standalone/SubCategoriesCache.test.ts +++ b/full-stack-tests/core/src/frontend/standalone/SubCategoriesCache.test.ts @@ -137,7 +137,7 @@ describe("SubCategoriesCache", () => { const q = new Queue(imodel); q.expectEmpty(); - q.dispose(); + q[Symbol.dispose](); q.expectEmpty(true); }); @@ -294,7 +294,7 @@ describe("SubCategoriesCache", () => { promise.then(() => promiseFulfilled = true); // eslint-disable-line @typescript-eslint/no-floating-promises q.expectMembers(true, false, true); - q.dispose(); + q[Symbol.dispose](); q.expectEmpty(true); // The promise will fulfill. The results will be added to the cache, but our processing function will not execute. @@ -314,7 +314,7 @@ describe("SubCategoriesCache", () => { // Dispose, then request same category. Should be ignored. let processed = false; - q.dispose(); + q[Symbol.dispose](); q.q("0x17", () => processed = true); q.expectEmpty(true); expect(processed).to.be.false; @@ -322,7 +322,7 @@ describe("SubCategoriesCache", () => { it("should not process pending asynchronous requests after disposal", async () => { const q = new Queue(imodel); - q.q("0x17", () => q.dispose()); + q.q("0x17", () => q[Symbol.dispose]()); let processedPending = false; q.q("0x2d", () => processedPending = true); @@ -337,7 +337,7 @@ describe("SubCategoriesCache", () => { const q = new Queue(imodel); // Asynchronous request to load category. - q.q("0x17", () => q.dispose()); + q.q("0x17", () => q[Symbol.dispose]()); // Request same category, which would normally be processed synchronously as soon as first request completes. let processedPending = false; @@ -352,7 +352,7 @@ describe("SubCategoriesCache", () => { it("should not create requests after disposal", () => { const q = new Queue(imodel); - q.dispose(); + q[Symbol.dispose](); q.q("0x17"); q.expectEmpty(true); }); diff --git a/full-stack-tests/core/src/frontend/standalone/Transparency.test.ts b/full-stack-tests/core/src/frontend/standalone/Transparency.test.ts index 76c397dd9cc7..fa7b44f86b97 100644 --- a/full-stack-tests/core/src/frontend/standalone/Transparency.test.ts +++ b/full-stack-tests/core/src/frontend/standalone/Transparency.test.ts @@ -25,7 +25,7 @@ class TransparencyDecorator { private readonly _graphics: RenderGraphicOwner[] = []; private readonly _symbologyOverrides = new Map(); - public dispose(): void { + public [Symbol.dispose](): void { for (const graphic of this._graphics) graphic.disposeGraphic(); @@ -34,7 +34,7 @@ class TransparencyDecorator { } public reset(): void { - this.dispose(); + this[Symbol.dispose](); } public decorate(context: DecorateContext): void { @@ -107,7 +107,7 @@ describe("Transparency", async () => { }); afterEach(() => { - decorator.dispose(); + decorator[Symbol.dispose](); IModelApp.viewManager.dropDecorator(decorator); }); diff --git a/full-stack-tests/core/src/frontend/standalone/ViewportChangedEvents.test.ts b/full-stack-tests/core/src/frontend/standalone/ViewportChangedEvents.test.ts index 0a8f69592c2c..536e2f42e136 100644 --- a/full-stack-tests/core/src/frontend/standalone/ViewportChangedEvents.test.ts +++ b/full-stack-tests/core/src/frontend/standalone/ViewportChangedEvents.test.ts @@ -62,7 +62,7 @@ describe("Viewport changed events", async () => { afterEach(() => { if (vp) - vp.dispose(); + vp[Symbol.dispose](); }); // Make an Id64 for testImodel which has briefcase Id=1 @@ -76,56 +76,55 @@ describe("Viewport changed events", async () => { vp = ScreenViewport.create(viewDiv, view); // Viewport-changed events are not dispatched immediately - they are accumulated between frames and dispatched from inside Viewport.renderFrame(). - ViewportChangedHandler.test(vp, (mon) => { - // No event if the set is already empty when we clear it. - mon.expect(ChangeFlag.None, undefined, () => vp.clearNeverDrawn()); - mon.expect(ChangeFlag.None, undefined, () => vp.clearAlwaysDrawn()); - - // Assigning the set always raises an event. - const idSet = new Set(); - idSet.add("0x123"); - mon.expect(ChangeFlag.AlwaysDrawn, undefined, () => vp.setAlwaysDrawn(idSet, false)); - mon.expect(ChangeFlag.AlwaysDrawn, undefined, () => vp.setAlwaysDrawn(idSet, true)); - mon.expect(ChangeFlag.NeverDrawn, undefined, () => vp.setNeverDrawn(idSet)); - - // Clearing raises event if set was assigned. - mon.expect(ChangeFlag.NeverDrawn, undefined, () => vp.clearNeverDrawn()); - mon.expect(ChangeFlag.AlwaysDrawn, undefined, () => vp.clearAlwaysDrawn()); - - // Clearing again will not re-raise because already cleared. - mon.expect(ChangeFlag.None, undefined, () => vp.clearNeverDrawn()); - mon.expect(ChangeFlag.None, undefined, () => vp.clearAlwaysDrawn()); - - // Setting repeatedly to same set raises each time, because we're not going to compare to previous set every time it changes. - mon.expect(ChangeFlag.AlwaysDrawn, undefined, () => vp.setAlwaysDrawn(idSet, true)); - mon.expect(ChangeFlag.AlwaysDrawn, undefined, () => vp.setAlwaysDrawn(idSet, true)); - - // Setting to an empty set, and also setting the 'exclusive' flags - effectively means no elements should draw. - idSet.clear(); - mon.expect(ChangeFlag.AlwaysDrawn, undefined, () => vp.setAlwaysDrawn(idSet, true)); - // Raises even though set was already empty, because this resets the 'exclusive' flag. - mon.expect(ChangeFlag.AlwaysDrawn, undefined, () => vp.clearAlwaysDrawn()); - // Exclusive flag no longer set and set is empty, so no event. - mon.expect(ChangeFlag.None, undefined, () => vp.clearAlwaysDrawn()); - - // Multiple changes in between frames produce a single event. - idSet.add("0x123"); - mon.expect(ChangeFlag.AlwaysDrawn | ChangeFlag.NeverDrawn, undefined, () => { - for (let i = 0; i < 5; i++) { - vp.setAlwaysDrawn(idSet); - vp.clearAlwaysDrawn(); - vp.setNeverDrawn(idSet); - vp.clearNeverDrawn(); - } - }); - - // Always/never-drawn unaffected by undo/redo - vp.saveViewUndo(); - vp.doUndo(); - mon.expect(ChangeFlag.None, undefined, () => undefined); - vp.doRedo(); - mon.expect(ChangeFlag.None, undefined, () => undefined); + using mon = new ViewportChangedHandler(vp); + // No event if the set is already empty when we clear it. + mon.expect(ChangeFlag.None, undefined, () => vp.clearNeverDrawn()); + mon.expect(ChangeFlag.None, undefined, () => vp.clearAlwaysDrawn()); + + // Assigning the set always raises an event. + const idSet = new Set(); + idSet.add("0x123"); + mon.expect(ChangeFlag.AlwaysDrawn, undefined, () => vp.setAlwaysDrawn(idSet, false)); + mon.expect(ChangeFlag.AlwaysDrawn, undefined, () => vp.setAlwaysDrawn(idSet, true)); + mon.expect(ChangeFlag.NeverDrawn, undefined, () => vp.setNeverDrawn(idSet)); + + // Clearing raises event if set was assigned. + mon.expect(ChangeFlag.NeverDrawn, undefined, () => vp.clearNeverDrawn()); + mon.expect(ChangeFlag.AlwaysDrawn, undefined, () => vp.clearAlwaysDrawn()); + + // Clearing again will not re-raise because already cleared. + mon.expect(ChangeFlag.None, undefined, () => vp.clearNeverDrawn()); + mon.expect(ChangeFlag.None, undefined, () => vp.clearAlwaysDrawn()); + + // Setting repeatedly to same set raises each time, because we're not going to compare to previous set every time it changes. + mon.expect(ChangeFlag.AlwaysDrawn, undefined, () => vp.setAlwaysDrawn(idSet, true)); + mon.expect(ChangeFlag.AlwaysDrawn, undefined, () => vp.setAlwaysDrawn(idSet, true)); + + // Setting to an empty set, and also setting the 'exclusive' flags - effectively means no elements should draw. + idSet.clear(); + mon.expect(ChangeFlag.AlwaysDrawn, undefined, () => vp.setAlwaysDrawn(idSet, true)); + // Raises even though set was already empty, because this resets the 'exclusive' flag. + mon.expect(ChangeFlag.AlwaysDrawn, undefined, () => vp.clearAlwaysDrawn()); + // Exclusive flag no longer set and set is empty, so no event. + mon.expect(ChangeFlag.None, undefined, () => vp.clearAlwaysDrawn()); + + // Multiple changes in between frames produce a single event. + idSet.add("0x123"); + mon.expect(ChangeFlag.AlwaysDrawn | ChangeFlag.NeverDrawn, undefined, () => { + for (let i = 0; i < 5; i++) { + vp.setAlwaysDrawn(idSet); + vp.clearAlwaysDrawn(); + vp.setNeverDrawn(idSet); + vp.clearNeverDrawn(); + } }); + + // Always/never-drawn unaffected by undo/redo + vp.saveViewUndo(); + vp.doUndo(); + mon.expect(ChangeFlag.None, undefined, () => undefined); + vp.doRedo(); + mon.expect(ChangeFlag.None, undefined, () => undefined); }); it("should be dispatched when display style is modified using Viewport APIs", async () => { @@ -133,150 +132,147 @@ describe("Viewport changed events", async () => { view.setStandardRotation(StandardViewId.RightIso); vp = ScreenViewport.create(viewDiv, view); - ViewportChangedHandler.test(vp, (mon) => { - // No event if equivalent flags - let newFlags = vp.viewFlags.copy({}); - mon.expect(ChangeFlag.None, undefined, () => vp.viewFlags = newFlags); - - // ViewFlags which do not affect symbology overrides - newFlags = newFlags.with("lighting", !newFlags.lighting); - mon.expect(ChangeFlag.DisplayStyle, ViewportState.RenderPlan, () => vp.viewFlags = newFlags); - - // ViewFlags which affect symbology overrides - newFlags = newFlags.with("constructions", !newFlags.constructions); - mon.expect(ChangeFlag.DisplayStyle, ViewportState.RenderPlan, () => vp.viewFlags = newFlags); - - // Modifying the style's properties directly also produces an event. - mon.expect(ChangeFlag.DisplayStyle, ViewportState.RenderPlan, () => { - vp.displayStyle.backgroundColor = ColorDef.red; - vp.displayStyle.viewFlags = new ViewFlags(); - }); - - // Modify display style through Viewport API. - vp.saveViewUndo(); - mon.expect(ChangeFlag.DisplayStyle | ChangeFlag.FeatureOverrideProvider, ViewportState.RenderPlan, () => { - const newStyle = vp.displayStyle.clone(); - newStyle.backgroundColor = ColorDef.red; - vp.displayStyle = newStyle; - }); - - // Change ClipStyle - mon.expect(ChangeFlag.DisplayStyle | ChangeFlag.FeatureOverrideProvider, ViewportState.RenderPlan, () => vp.clipStyle = ClipStyle.fromJSON({ cutStyle: { appearance: { weight: 12 } } })); - - // Modify view flags through Viewport's displayStyle property. - vp.saveViewUndo(); - mon.expect(ChangeFlag.DisplayStyle | ChangeFlag.FeatureOverrideProvider, ViewportState.RenderPlan, () => { - const newStyle = vp.displayStyle.clone(); - newStyle.viewFlags = newStyle.viewFlags.with("constructions", !newStyle.viewFlags.constructions); - vp.displayStyle = newStyle; - }); - - vp.saveViewUndo(); - - // Override subcategories directly on display style without going through Viewport API => produces event - const ovr = SubCategoryOverride.fromJSON({ color: ColorDef.green.tbgr }); - mon.expect(ChangeFlag.DisplayStyle | ChangeFlag.FeatureOverrideProvider, ViewportState.RenderPlan, () => vp.displayStyle.overrideSubCategory("0x123", ovr)); - - // Override by replacing display style on Viewport - vp.saveViewUndo(); - mon.expect(ChangeFlag.DisplayStyle | ChangeFlag.FeatureOverrideProvider, ViewportState.RenderPlan, () => { - const style = vp.displayStyle.clone(); - style.overrideSubCategory("0x123", ovr); - vp.displayStyle = style; - }); - - // Apply same override via Viewport method. Does not check if override actually differs. - vp.saveViewUndo(); - mon.expect(ChangeFlag.DisplayStyle | ChangeFlag.ViewedModels | ChangeFlag.FeatureOverrideProvider, ViewportState.RenderPlan, () => { - // Because this is same override as already set, saveViewUndo will not save in undo buffer unless we make some other actual change to the ViewState - vp.overrideSubCategory("0x123", ovr); - vp.changeViewedModels(new Set()); - }); - - // Apply different override to same subcategory - vp.saveViewUndo(); - mon.expect(ChangeFlag.DisplayStyle | ChangeFlag.FeatureOverrideProvider, ViewportState.RenderPlan, () => vp.overrideSubCategory("0x123", SubCategoryOverride.fromJSON({ color: ColorDef.red.tbgr }))); + using mon = new ViewportChangedHandler(vp); + // No event if equivalent flags + let newFlags = vp.viewFlags.copy({}); + mon.expect(ChangeFlag.None, undefined, () => vp.viewFlags = newFlags); + + // ViewFlags which do not affect symbology overrides + newFlags = newFlags.with("lighting", !newFlags.lighting); + mon.expect(ChangeFlag.DisplayStyle, ViewportState.RenderPlan, () => vp.viewFlags = newFlags); + + // ViewFlags which affect symbology overrides + newFlags = newFlags.with("constructions", !newFlags.constructions); + mon.expect(ChangeFlag.DisplayStyle, ViewportState.RenderPlan, () => vp.viewFlags = newFlags); + + // Modifying the style's properties directly also produces an event. + mon.expect(ChangeFlag.DisplayStyle, ViewportState.RenderPlan, () => { + vp.displayStyle.backgroundColor = ColorDef.red; + vp.displayStyle.viewFlags = new ViewFlags(); + }); + + // Modify display style through Viewport API. + vp.saveViewUndo(); + mon.expect(ChangeFlag.DisplayStyle | ChangeFlag.FeatureOverrideProvider, ViewportState.RenderPlan, () => { + const newStyle = vp.displayStyle.clone(); + newStyle.backgroundColor = ColorDef.red; + vp.displayStyle = newStyle; }); + + // Change ClipStyle + mon.expect(ChangeFlag.DisplayStyle | ChangeFlag.FeatureOverrideProvider, ViewportState.RenderPlan, () => vp.clipStyle = ClipStyle.fromJSON({ cutStyle: { appearance: { weight: 12 } } })); + + // Modify view flags through Viewport's displayStyle property. + vp.saveViewUndo(); + mon.expect(ChangeFlag.DisplayStyle | ChangeFlag.FeatureOverrideProvider, ViewportState.RenderPlan, () => { + const newStyle = vp.displayStyle.clone(); + newStyle.viewFlags = newStyle.viewFlags.with("constructions", !newStyle.viewFlags.constructions); + vp.displayStyle = newStyle; + }); + + vp.saveViewUndo(); + + // Override subcategories directly on display style without going through Viewport API => produces event + const ovr = SubCategoryOverride.fromJSON({ color: ColorDef.green.tbgr }); + mon.expect(ChangeFlag.DisplayStyle | ChangeFlag.FeatureOverrideProvider, ViewportState.RenderPlan, () => vp.displayStyle.overrideSubCategory("0x123", ovr)); + + // Override by replacing display style on Viewport + vp.saveViewUndo(); + mon.expect(ChangeFlag.DisplayStyle | ChangeFlag.FeatureOverrideProvider, ViewportState.RenderPlan, () => { + const style = vp.displayStyle.clone(); + style.overrideSubCategory("0x123", ovr); + vp.displayStyle = style; + }); + + // Apply same override via Viewport method. Does not check if override actually differs. + vp.saveViewUndo(); + mon.expect(ChangeFlag.DisplayStyle | ChangeFlag.ViewedModels | ChangeFlag.FeatureOverrideProvider, ViewportState.RenderPlan, () => { + // Because this is same override as already set, saveViewUndo will not save in undo buffer unless we make some other actual change to the ViewState + vp.overrideSubCategory("0x123", ovr); + vp.changeViewedModels(new Set()); + }); + + // Apply different override to same subcategory + vp.saveViewUndo(); + mon.expect(ChangeFlag.DisplayStyle | ChangeFlag.FeatureOverrideProvider, ViewportState.RenderPlan, () => vp.overrideSubCategory("0x123", SubCategoryOverride.fromJSON({ color: ColorDef.red.tbgr }))); }); it("should be dispatched when display style is modified directly", async () => { const view = await testBim.views.load("0x34") as SpatialViewState; vp = ScreenViewport.create(viewDiv, view); - ViewportChangedHandler.test(vp, (mon) => { - const expectNoChange = (func: () => void) => mon.expect(ChangeFlag.None, undefined, func); - const expectChange = (func: () => void) => mon.expect(ChangeFlag.DisplayStyle, ViewportState.RenderPlan, func); - const expectOverrideChange = (func: () => void) => mon.expect(ChangeFlag.DisplayStyle | ChangeFlag.FeatureOverrideProvider, ViewportState.RenderPlan, func); + using mon = new ViewportChangedHandler(vp); + const expectNoChange = (func: () => void) => mon.expect(ChangeFlag.None, undefined, func); + const expectChange = (func: () => void) => mon.expect(ChangeFlag.DisplayStyle, ViewportState.RenderPlan, func); + const expectOverrideChange = (func: () => void) => mon.expect(ChangeFlag.DisplayStyle | ChangeFlag.FeatureOverrideProvider, ViewportState.RenderPlan, func); - expectNoChange(() => view.displayStyle = view.displayStyle); - expectOverrideChange(() => view.displayStyle = view.displayStyle.clone()); + expectNoChange(() => view.displayStyle = view.displayStyle); + expectOverrideChange(() => view.displayStyle = view.displayStyle.clone()); - const style = view.getDisplayStyle3d(); - const settings = style.settings; + const style = view.getDisplayStyle3d(); + const settings = style.settings; - let vf = settings.viewFlags.copy({}); - expectNoChange(() => settings.viewFlags = vf); - vf = vf.with("transparency", !vf.transparency); - expectChange(() => settings.viewFlags = vf); + let vf = settings.viewFlags.copy({}); + expectNoChange(() => settings.viewFlags = vf); + vf = vf.with("transparency", !vf.transparency); + expectChange(() => settings.viewFlags = vf); - expectOverrideChange(() => settings.overrideSubCategory("0x123", SubCategoryOverride.fromJSON({ color: ColorDef.blue.tbgr }))); - expectOverrideChange(() => settings.overrideModelAppearance("0xabc", FeatureAppearance.fromJSON({ weight: 10 }))); - expectOverrideChange(() => settings.dropModelAppearanceOverride("0xabc")); + expectOverrideChange(() => settings.overrideSubCategory("0x123", SubCategoryOverride.fromJSON({ color: ColorDef.blue.tbgr }))); + expectOverrideChange(() => settings.overrideModelAppearance("0xabc", FeatureAppearance.fromJSON({ weight: 10 }))); + expectOverrideChange(() => settings.dropModelAppearanceOverride("0xabc")); - expectChange(() => settings.backgroundColor = ColorDef.red); - expectNoChange(() => settings.backgroundColor = ColorDef.red); + expectChange(() => settings.backgroundColor = ColorDef.red); + expectNoChange(() => settings.backgroundColor = ColorDef.red); - expectChange(() => settings.monochromeColor = ColorDef.green); - expectNoChange(() => settings.monochromeColor = ColorDef.green); - expectChange(() => settings.monochromeMode = MonochromeMode.Flat); - expectNoChange(() => settings.monochromeMode = MonochromeMode.Flat); + expectChange(() => settings.monochromeColor = ColorDef.green); + expectNoChange(() => settings.monochromeColor = ColorDef.green); + expectChange(() => settings.monochromeMode = MonochromeMode.Flat); + expectNoChange(() => settings.monochromeMode = MonochromeMode.Flat); - expectOverrideChange(() => settings.clipStyle = ClipStyle.fromJSON({ cutStyle: { appearance: { weight: 5 } } })); + expectOverrideChange(() => settings.clipStyle = ClipStyle.fromJSON({ cutStyle: { appearance: { weight: 5 } } })); - expectNoChange(() => settings.analysisFraction = settings.analysisFraction); - mon.expect(ChangeFlag.DisplayStyle, ViewportState.AnalysisFraction, () => settings.analysisFraction = 0.123456); - mon.expect(ChangeFlag.DisplayStyle, ViewportState.AnalysisFraction | ViewportState.RenderPlan, () => settings.analysisStyle = AnalysisStyle.fromJSON({ displacement: { channelName: "source" } })); + expectNoChange(() => settings.analysisFraction = settings.analysisFraction); + mon.expect(ChangeFlag.DisplayStyle, ViewportState.AnalysisFraction, () => settings.analysisFraction = 0.123456); + mon.expect(ChangeFlag.DisplayStyle, ViewportState.AnalysisFraction | ViewportState.RenderPlan, () => settings.analysisStyle = AnalysisStyle.fromJSON({ displacement: { channelName: "source" } })); - mon.expect(ChangeFlag.DisplayStyle | ChangeFlag.FeatureOverrideProvider, ViewportState.TimePoint, () => settings.timePoint = 43); - expectNoChange(() => settings.timePoint = 43); + mon.expect(ChangeFlag.DisplayStyle | ChangeFlag.FeatureOverrideProvider, ViewportState.TimePoint, () => settings.timePoint = 43); + expectNoChange(() => settings.timePoint = 43); - mon.expect(ChangeFlag.DisplayStyle | ChangeFlag.FeatureOverrideProvider, ViewportState.TimePoint | ViewportState.Scene, () => settings.scheduleScriptProps = [{ modelId: "0x123", elementTimelines: [] }]); - mon.expect(ChangeFlag.DisplayStyle | ChangeFlag.FeatureOverrideProvider, ViewportState.TimePoint | ViewportState.Scene, () => settings.scheduleScriptProps = undefined); - // If assignment to scheduleScriptProps produces no net change, no event. - expectNoChange(() => settings.scheduleScriptProps = undefined); + mon.expect(ChangeFlag.DisplayStyle | ChangeFlag.FeatureOverrideProvider, ViewportState.TimePoint | ViewportState.Scene, () => settings.scheduleScriptProps = [{ modelId: "0x123", elementTimelines: [] }]); + mon.expect(ChangeFlag.DisplayStyle | ChangeFlag.FeatureOverrideProvider, ViewportState.TimePoint | ViewportState.Scene, () => settings.scheduleScriptProps = undefined); + // If assignment to scheduleScriptProps produces no net change, no event. + expectNoChange(() => settings.scheduleScriptProps = undefined); - expectChange(() => settings.hiddenLineSettings = settings.hiddenLineSettings.override({ transThreshold: 1.0 - settings.hiddenLineSettings.transThreshold })); - expectNoChange(() => settings.hiddenLineSettings = settings.hiddenLineSettings.override({})); + expectChange(() => settings.hiddenLineSettings = settings.hiddenLineSettings.override({ transThreshold: 1.0 - settings.hiddenLineSettings.transThreshold })); + expectNoChange(() => settings.hiddenLineSettings = settings.hiddenLineSettings.override({})); - expectNoChange(() => settings.lights = settings.lights.clone()); - expectChange(() => settings.lights = settings.lights.clone({ numCels: settings.lights.numCels + 1 })); - expectNoChange(() => settings.lights = settings.lights.clone({ numCels: settings.lights.numCels })); + expectNoChange(() => settings.lights = settings.lights.clone()); + expectChange(() => settings.lights = settings.lights.clone({ numCels: settings.lights.numCels + 1 })); + expectNoChange(() => settings.lights = settings.lights.clone({ numCels: settings.lights.numCels })); - expectNoChange(() => settings.solarShadows = settings.solarShadows.clone({ color: settings.solarShadows.color.toColorDef().toJSON() })); - expectChange(() => settings.solarShadows = settings.solarShadows.clone({ color: 123 })); + expectNoChange(() => settings.solarShadows = settings.solarShadows.clone({ color: settings.solarShadows.color.toColorDef().toJSON() })); + expectChange(() => settings.solarShadows = settings.solarShadows.clone({ color: 123 })); - const thematicProps = settings.thematic.toJSON(); - expectNoChange(() => settings.thematic = ThematicDisplay.fromJSON(thematicProps)); - thematicProps.range = { low: 123, high: 456 }; - expectChange(() => settings.thematic = ThematicDisplay.fromJSON(thematicProps)); + const thematicProps = settings.thematic.toJSON(); + expectNoChange(() => settings.thematic = ThematicDisplay.fromJSON(thematicProps)); + thematicProps.range = { low: 123, high: 456 }; + expectChange(() => settings.thematic = ThematicDisplay.fromJSON(thematicProps)); - expectChange(() => settings.ambientOcclusionSettings = AmbientOcclusion.Settings.fromJSON({ bias: 42, maxDistance: 24 })); - expectChange(() => settings.environment = settings.environment.withDisplay({ ground: !settings.environment.displayGround })); + expectChange(() => settings.ambientOcclusionSettings = AmbientOcclusion.Settings.fromJSON({ bias: 42, maxDistance: 24 })); + expectChange(() => settings.environment = settings.environment.withDisplay({ ground: !settings.environment.displayGround })); - expectChange(() => settings.setPlanProjectionSettings("0xabcdef", undefined)); - expectChange(() => settings.setPlanProjectionSettings("0xfedcba", PlanProjectionSettings.fromJSON({ elevation: 42 }))); - }); + expectChange(() => settings.setPlanProjectionSettings("0xabcdef", undefined)); + expectChange(() => settings.setPlanProjectionSettings("0xfedcba", PlanProjectionSettings.fromJSON({ elevation: 42 }))); }); it("should be dispatched when overrides are applied to the display style", async () => { vp = ScreenViewport.create(viewDiv, await testBim.views.load("0x34")); - ViewportChangedHandler.test(vp, (mon) => { - const settings = vp.view.displayStyle.settings; + using mon = new ViewportChangedHandler(vp); + const settings = vp.view.displayStyle.settings; - mon.expect(ChangeFlag.DisplayStyle, ViewportState.Controller, () => settings.applyOverrides({ viewflags: { backgroundMap: !settings.viewFlags.backgroundMap } })); - mon.expect(ChangeFlag.DisplayStyle, ViewportState.RenderPlan, () => settings.applyOverrides({ backgroundColor: 0xabcdef })); - mon.expect(ChangeFlag.DisplayStyle | ChangeFlag.FeatureOverrideProvider, ViewportState.TimePoint | ViewportState.Scene, () => settings.applyOverrides({ scheduleScript: [{ modelId: "0x321", elementTimelines: [] }] })); - }); + mon.expect(ChangeFlag.DisplayStyle, ViewportState.Controller, () => settings.applyOverrides({ viewflags: { backgroundMap: !settings.viewFlags.backgroundMap } })); + mon.expect(ChangeFlag.DisplayStyle, ViewportState.RenderPlan, () => settings.applyOverrides({ backgroundColor: 0xabcdef })); + mon.expect(ChangeFlag.DisplayStyle | ChangeFlag.FeatureOverrideProvider, ViewportState.TimePoint | ViewportState.Scene, () => settings.applyOverrides({ scheduleScript: [{ modelId: "0x321", elementTimelines: [] }] })); }); it("should be dispatched when background map is modified using Viewport APIs", async () => { @@ -284,31 +280,29 @@ describe("Viewport changed events", async () => { view.setStandardRotation(StandardViewId.RightIso); vp = ScreenViewport.create(viewDiv, view); - ViewportChangedHandler.test(vp, (mon) => { - let vf = vp.viewFlags.with("backgroundMap", !vp.viewFlags.backgroundMap); - mon.expect(ChangeFlag.DisplayStyle, ViewportState.Controller, () => vp.viewFlags = vf); + using mon = new ViewportChangedHandler(vp); + let vf = vp.viewFlags.with("backgroundMap", !vp.viewFlags.backgroundMap); + mon.expect(ChangeFlag.DisplayStyle, ViewportState.Controller, () => vp.viewFlags = vf); - vf = vf.with("backgroundMap", !vf.backgroundMap); - mon.expect(ChangeFlag.DisplayStyle, ViewportState.Controller, () => vp.viewFlags = vf); + vf = vf.with("backgroundMap", !vf.backgroundMap); + mon.expect(ChangeFlag.DisplayStyle, ViewportState.Controller, () => vp.viewFlags = vf); - mon.expect(ChangeFlag.DisplayStyle, ViewportState.Controller, () => vp.backgroundMapSettings = vp.backgroundMapSettings.clone({ groundBias: 123 })); - mon.expect(ChangeFlag.DisplayStyle, ViewportState.Controller, () => vp.changeBackgroundMapProps({ groundBias: 456 })); - }); + mon.expect(ChangeFlag.DisplayStyle, ViewportState.Controller, () => vp.backgroundMapSettings = vp.backgroundMapSettings.clone({ groundBias: 123 })); + mon.expect(ChangeFlag.DisplayStyle, ViewportState.Controller, () => vp.changeBackgroundMapProps({ groundBias: 456 })); }); it("should be dispatched when background map is modified directly", async () => { const view = await testBim.views.load("0x34") as SpatialViewState; vp = ScreenViewport.create(viewDiv, view); - ViewportChangedHandler.test(vp, (mon) => { - const settings = view.displayStyle.settings; - const vf = settings.viewFlags.with("backgroundMap", !settings.viewFlags.backgroundMap); - mon.expect(ChangeFlag.DisplayStyle, ViewportState.Controller, () => settings.viewFlags = vf); - mon.expect(ChangeFlag.None, undefined, () => settings.viewFlags = vf); + using mon = new ViewportChangedHandler(vp); + const settings = view.displayStyle.settings; + const vf = settings.viewFlags.with("backgroundMap", !settings.viewFlags.backgroundMap); + mon.expect(ChangeFlag.DisplayStyle, ViewportState.Controller, () => settings.viewFlags = vf); + mon.expect(ChangeFlag.None, undefined, () => settings.viewFlags = vf); - mon.expect(ChangeFlag.DisplayStyle, ViewportState.Controller, () => settings.backgroundMap = settings.backgroundMap.clone({ groundBias: 654 })); - mon.expect(ChangeFlag.DisplayStyle, ViewportState.Controller, () => settings.backgroundMap = settings.backgroundMap.clone({ groundBias: 321 })); - }); + mon.expect(ChangeFlag.DisplayStyle, ViewportState.Controller, () => settings.backgroundMap = settings.backgroundMap.clone({ groundBias: 654 })); + mon.expect(ChangeFlag.DisplayStyle, ViewportState.Controller, () => settings.backgroundMap = settings.backgroundMap.clone({ groundBias: 321 })); }); it("should invalidate scene when shadows are on", async () => { @@ -316,24 +310,23 @@ describe("Viewport changed events", async () => { view.setStandardRotation(StandardViewId.RightIso); vp = ScreenViewport.create(viewDiv, view); - ViewportChangedHandler.test(vp, (mon) => { - mon.expect(ChangeFlag.DisplayStyle, ViewportState.RenderPlan, () => vp.viewFlags = vp.viewFlags.with("shadows", true)); + using mon = new ViewportChangedHandler(vp); + mon.expect(ChangeFlag.DisplayStyle, ViewportState.RenderPlan, () => vp.viewFlags = vp.viewFlags.with("shadows", true)); - const idSet = new Set(); - idSet.add("0x321"); - mon.expect(ChangeFlag.AlwaysDrawn, ViewportState.Scene, () => vp.setAlwaysDrawn(idSet)); - mon.expect(ChangeFlag.AlwaysDrawn, ViewportState.Scene, () => vp.clearAlwaysDrawn()); - mon.expect(ChangeFlag.None, undefined, () => vp.clearAlwaysDrawn()); + const idSet = new Set(); + idSet.add("0x321"); + mon.expect(ChangeFlag.AlwaysDrawn, ViewportState.Scene, () => vp.setAlwaysDrawn(idSet)); + mon.expect(ChangeFlag.AlwaysDrawn, ViewportState.Scene, () => vp.clearAlwaysDrawn()); + mon.expect(ChangeFlag.None, undefined, () => vp.clearAlwaysDrawn()); - idSet.add("0x123"); - mon.expect(ChangeFlag.NeverDrawn, ViewportState.Scene, () => vp.setNeverDrawn(idSet)); - mon.expect(ChangeFlag.NeverDrawn, ViewportState.Scene, () => vp.clearNeverDrawn()); - mon.expect(ChangeFlag.None, undefined, () => vp.clearNeverDrawn()); + idSet.add("0x123"); + mon.expect(ChangeFlag.NeverDrawn, ViewportState.Scene, () => vp.setNeverDrawn(idSet)); + mon.expect(ChangeFlag.NeverDrawn, ViewportState.Scene, () => vp.clearNeverDrawn()); + mon.expect(ChangeFlag.None, undefined, () => vp.clearNeverDrawn()); - mon.expect(ChangeFlag.FeatureOverrideProvider, ViewportState.Scene, () => vp.setFeatureOverrideProviderChanged()); + mon.expect(ChangeFlag.FeatureOverrideProvider, ViewportState.Scene, () => vp.setFeatureOverrideProviderChanged()); - mon.expect(ChangeFlag.ViewedCategories, ViewportState.Scene, () => vp.changeCategoryDisplay(["0xa", "0xb"], true)); - }); + mon.expect(ChangeFlag.ViewedCategories, ViewportState.Scene, () => vp.changeCategoryDisplay(["0xa", "0xb"], true)); }); function changeView(viewport: Viewport, view: ViewState): void { @@ -343,212 +336,206 @@ describe("Viewport changed events", async () => { it("should be dispatched when displayed 2d models change", async () => { vp = ScreenViewport.create(viewDiv, await testImodel.views.load(id64(0x20))); // views model 0x19 - await ViewportChangedHandler.testAsync(vp, async (mon) => { - // changeModelDisplay is no-op for 2d views - mon.expect(ChangeFlag.None, undefined, () => expect(vp.changeModelDisplay(id64(0x19), false)).to.be.false); - mon.expect(ChangeFlag.None, undefined, () => expect(vp.changeModelDisplay(id64(0x27), true)).to.be.false); - const viewedModels = new Set(); - viewedModels.add(id64(0x27)); - mon.expect(ChangeFlag.None, undefined, () => expect(vp.changeViewedModels(viewedModels)).to.be.false); - - // Switching to a different 2d view of the same model should not produce model-changed event - const view20 = await testImodel.views.load(id64(0x20)); // views model 0x1e - mon.expect(ChangeFlag.ViewState, ViewportState.Controller, () => changeView(vp, view20)); - - // Switching to a different 2d view of a different model should produce model-changed event - // Note: new view also has different categories enabled. - const view35 = await testImodel.views.load(id64(0x35)); // views model 0x1e - mon.expect(ChangeFlag.ViewedModels | ChangeFlag.ViewedCategories | ChangeFlag.DisplayStyle | ChangeFlag.ViewState, ViewportState.Controller, () => changeView(vp, view35)); - - // Switch back to previous view. - // Note: changeView(vp, ) clears undo stack so cannot/needn't test undo/redo here. - mon.expect(ChangeFlag.ViewedModels | ChangeFlag.ViewedCategories | ChangeFlag.DisplayStyle | ChangeFlag.ViewState, ViewportState.Controller, () => changeView(vp, view20.clone())); - }); + using mon = new ViewportChangedHandler(vp); + // changeModelDisplay is no-op for 2d views + mon.expect(ChangeFlag.None, undefined, () => expect(vp.changeModelDisplay(id64(0x19), false)).to.be.false); + mon.expect(ChangeFlag.None, undefined, () => expect(vp.changeModelDisplay(id64(0x27), true)).to.be.false); + const viewedModels = new Set(); + viewedModels.add(id64(0x27)); + mon.expect(ChangeFlag.None, undefined, () => expect(vp.changeViewedModels(viewedModels)).to.be.false); + + // Switching to a different 2d view of the same model should not produce model-changed event + const view20 = await testImodel.views.load(id64(0x20)); // views model 0x1e + mon.expect(ChangeFlag.ViewState, ViewportState.Controller, () => changeView(vp, view20)); + + // Switching to a different 2d view of a different model should produce model-changed event + // Note: new view also has different categories enabled. + const view35 = await testImodel.views.load(id64(0x35)); // views model 0x1e + mon.expect(ChangeFlag.ViewedModels | ChangeFlag.ViewedCategories | ChangeFlag.DisplayStyle | ChangeFlag.ViewState, ViewportState.Controller, () => changeView(vp, view35)); + + // Switch back to previous view. + // Note: changeView(vp, ) clears undo stack so cannot/needn't test undo/redo here. + mon.expect(ChangeFlag.ViewedModels | ChangeFlag.ViewedCategories | ChangeFlag.DisplayStyle | ChangeFlag.ViewState, ViewportState.Controller, () => changeView(vp, view20.clone())); }); it("should be dispatched when model selector is modified using Viewport APIs", async () => { vp = ScreenViewport.create(viewDiv, await testBim.views.load("0x34")); - await ViewportChangedHandler.testAsync(vp, async (mon) => { - // adding a model which is already present produces no event - mon.expect(ChangeFlag.None, undefined, () => vp.changeModelDisplay("0x1c", true)); - - // removing a model not present produces no event - mon.expect(ChangeFlag.None, undefined, () => vp.changeModelDisplay("0x9876543", false)); - - // setting viewed models directly always produces event - we don't check if contents of set exactly match current set - let selectedModels = (vp.view as SpatialViewState).modelSelector.models; - mon.expect(ChangeFlag.ViewedModels, ViewportState.Scene, () => vp.changeViewedModels(selectedModels)); - selectedModels = new Set(); - selectedModels.add("0x1c"); - mon.expect(ChangeFlag.ViewedModels, ViewportState.Scene, () => vp.changeViewedModels(selectedModels)); - - mon.expect(ChangeFlag.ViewedModels, ViewportState.Scene, () => { - vp.changeModelDisplay("0x1c", false); - vp.changeModelDisplay("0x1f", true); - }); - - // Viewport is now viewing model 0x1f. - // Replacing viewed models with same set [ 0x1f ] produces event - selectedModels.clear(); - selectedModels.add("0x1f"); - mon.expect(ChangeFlag.ViewedModels, ViewportState.Scene, () => vp.changeViewedModels(selectedModels)); + using mon = new ViewportChangedHandler(vp); + // adding a model which is already present produces no event + mon.expect(ChangeFlag.None, undefined, () => vp.changeModelDisplay("0x1c", true)); + + // removing a model not present produces no event + mon.expect(ChangeFlag.None, undefined, () => vp.changeModelDisplay("0x9876543", false)); + + // setting viewed models directly always produces event - we don't check if contents of set exactly match current set + let selectedModels = (vp.view as SpatialViewState).modelSelector.models; + mon.expect(ChangeFlag.ViewedModels, ViewportState.Scene, () => vp.changeViewedModels(selectedModels)); + selectedModels = new Set(); + selectedModels.add("0x1c"); + mon.expect(ChangeFlag.ViewedModels, ViewportState.Scene, () => vp.changeViewedModels(selectedModels)); + + mon.expect(ChangeFlag.ViewedModels, ViewportState.Scene, () => { + vp.changeModelDisplay("0x1c", false); + vp.changeModelDisplay("0x1f", true); }); + + // Viewport is now viewing model 0x1f. + // Replacing viewed models with same set [ 0x1f ] produces event + selectedModels.clear(); + selectedModels.add("0x1f"); + mon.expect(ChangeFlag.ViewedModels, ViewportState.Scene, () => vp.changeViewedModels(selectedModels)); }); it("should be dispatched when model selector is modified directly", async () => { const view = await testBim.views.load("0x34") as SpatialViewState; vp = ScreenViewport.create(viewDiv, view); - ViewportChangedHandler.test(vp, (mon) => { - const expectChange = (func: () => void) => mon.expect(ChangeFlag.ViewedModels, ViewportState.Scene, func); - const expectNoChange = (func: () => void) => mon.expect(ChangeFlag.None, undefined, func); + using mon = new ViewportChangedHandler(vp); + const expectChange = (func: () => void) => mon.expect(ChangeFlag.ViewedModels, ViewportState.Scene, func); + const expectNoChange = (func: () => void) => mon.expect(ChangeFlag.None, undefined, func); - expectNoChange(() => view.modelSelector = view.modelSelector); - expectChange(() => view.modelSelector = view.modelSelector.clone()); + expectNoChange(() => view.modelSelector = view.modelSelector); + expectChange(() => view.modelSelector = view.modelSelector.clone()); - const models = view.modelSelector.models; - expectChange(() => models.add("0xabc")); - expectNoChange(() => models.add("0xabc")); + const models = view.modelSelector.models; + expectChange(() => models.add("0xabc")); + expectNoChange(() => models.add("0xabc")); - expectChange(() => models.delete("0xabc")); - expectNoChange(() => models.delete("0xabc")); + expectChange(() => models.delete("0xabc")); + expectNoChange(() => models.delete("0xabc")); - expectChange(() => models.clear()); - expectNoChange(() => models.clear()); + expectChange(() => models.clear()); + expectNoChange(() => models.clear()); - // We don't check if the input's contents exactly match the current contents. - const modelIds = new Set(["0x1", "0x2"]); - expectChange(() => view.modelSelector.models = modelIds); - expectChange(() => view.modelSelector.models = modelIds); - }); + // We don't check if the input's contents exactly match the current contents. + const modelIds = new Set(["0x1", "0x2"]); + expectChange(() => view.modelSelector.models = modelIds); + expectChange(() => view.modelSelector.models = modelIds); }); it("should be dispatched when category selector is modified using Viewport APIs", async () => { vp = ScreenViewport.create(viewDiv, await testImodel.views.load(id64(0x15))); // view category selector 0x0f - await ViewportChangedHandler.testAsync(vp, async (mon) => { - mon.expect(ChangeFlag.ViewedCategories, undefined, () => vp.changeCategoryDisplay(id64(0x01), true)); + using mon = new ViewportChangedHandler(vp); + mon.expect(ChangeFlag.ViewedCategories, undefined, () => vp.changeCategoryDisplay(id64(0x01), true)); - // We're not viewing 0x1a, so this will not produce an event. - mon.expect(ChangeFlag.None, undefined, () => vp.changeCategoryDisplay(id64(0x1a), false)); + // We're not viewing 0x1a, so this will not produce an event. + mon.expect(ChangeFlag.None, undefined, () => vp.changeCategoryDisplay(id64(0x1a), false)); - // Two changes which produce no net change still produce event - we do not track net changes - vp.saveViewUndo(); - mon.expect(ChangeFlag.ViewedCategories, undefined, () => { - vp.changeCategoryDisplay(id64(0x01), false); - vp.changeCategoryDisplay(id64(0x01), true); - }); - - // Undo/redo with no net change produces no event - vp.saveViewUndo(); - mon.expect(ChangeFlag.None, undefined, () => vp.doUndo()); - mon.expect(ChangeFlag.None, undefined, () => vp.doRedo()); + // Two changes which produce no net change still produce event - we do not track net changes + vp.saveViewUndo(); + mon.expect(ChangeFlag.ViewedCategories, undefined, () => { + vp.changeCategoryDisplay(id64(0x01), false); + vp.changeCategoryDisplay(id64(0x01), true); + }); - // Switching to a different view with same category selector produces no category-changed event - const view13 = await testImodel.views.load(id64(0x13)); - mon.expect(ChangeFlag.ViewState | ChangeFlag.DisplayStyle, ViewportState.Controller, () => changeView(vp, view13)); + // Undo/redo with no net change produces no event + vp.saveViewUndo(); + mon.expect(ChangeFlag.None, undefined, () => vp.doUndo()); + mon.expect(ChangeFlag.None, undefined, () => vp.doRedo()); - // Switching to a different view with different category selector produces event - const view17 = await testImodel.views.load(id64(0x17)); - mon.expect(ChangeFlag.ViewState | ChangeFlag.DisplayStyle | ChangeFlag.ViewedCategories, ViewportState.Controller, () => changeView(vp, view17)); + // Switching to a different view with same category selector produces no category-changed event + const view13 = await testImodel.views.load(id64(0x13)); + mon.expect(ChangeFlag.ViewState | ChangeFlag.DisplayStyle, ViewportState.Controller, () => changeView(vp, view13)); - // Changing category selector, then switching to a view with same categories enabled produces no event. - mon.expect(ChangeFlag.ViewedCategories, undefined, () => { - vp.changeCategoryDisplay(vp.view.categorySelector.categories, false); - vp.changeCategoryDisplay(view13.categorySelector.categories, true); - }); + // Switching to a different view with different category selector produces event + const view17 = await testImodel.views.load(id64(0x17)); + mon.expect(ChangeFlag.ViewState | ChangeFlag.DisplayStyle | ChangeFlag.ViewedCategories, ViewportState.Controller, () => changeView(vp, view17)); - mon.expect(ChangeFlag.ViewState | ChangeFlag.ViewedCategories | ChangeFlag.DisplayStyle, ViewportState.Controller, () => changeView(vp, view13)); + // Changing category selector, then switching to a view with same categories enabled produces no event. + mon.expect(ChangeFlag.ViewedCategories, undefined, () => { + vp.changeCategoryDisplay(vp.view.categorySelector.categories, false); + vp.changeCategoryDisplay(view13.categorySelector.categories, true); }); + + mon.expect(ChangeFlag.ViewState | ChangeFlag.ViewedCategories | ChangeFlag.DisplayStyle, ViewportState.Controller, () => changeView(vp, view13)); }); it("should be dispatched when category selector is modified directly", async () => { vp = ScreenViewport.create(viewDiv, await testImodel.views.load(id64(0x15))); - ViewportChangedHandler.test(vp, (mon) => { - const expectChange = (func: () => void) => mon.expect(ChangeFlag.ViewedCategories, undefined, func); - const expectNoChange = (func: () => void) => mon.expect(ChangeFlag.None, undefined, func); + using mon = new ViewportChangedHandler(vp); + const expectChange = (func: () => void) => mon.expect(ChangeFlag.ViewedCategories, undefined, func); + const expectNoChange = (func: () => void) => mon.expect(ChangeFlag.None, undefined, func); - expectChange(() => vp.view.categorySelector = vp.view.categorySelector.clone()); - expectNoChange(() => vp.view.categorySelector = vp.view.categorySelector); + expectChange(() => vp.view.categorySelector = vp.view.categorySelector.clone()); + expectNoChange(() => vp.view.categorySelector = vp.view.categorySelector); - const categories = vp.view.categorySelector.categories; - expectChange(() => categories.add("0x123")); - expectNoChange(() => categories.add("0x123")); + const categories = vp.view.categorySelector.categories; + expectChange(() => categories.add("0x123")); + expectNoChange(() => categories.add("0x123")); - expectChange(() => categories.delete("0x123")); - expectNoChange(() => categories.delete("0x123")); + expectChange(() => categories.delete("0x123")); + expectNoChange(() => categories.delete("0x123")); - expectChange(() => categories.clear()); - expectNoChange(() => categories.clear()); + expectChange(() => categories.clear()); + expectNoChange(() => categories.clear()); - // We don't check if the input's contents exactly match the current contents. - const catIds = new Set(["0xa", "0xb"]); - expectChange(() => vp.view.categorySelector.categories = catIds); - expectChange(() => vp.view.categorySelector.categories = catIds); - }); + // We don't check if the input's contents exactly match the current contents. + const catIds = new Set(["0xa", "0xb"]); + expectChange(() => vp.view.categorySelector.categories = catIds); + expectChange(() => vp.view.categorySelector.categories = catIds); }); it("should be dispatched when per-model category visibility changes", async () => { vp = ScreenViewport.create(viewDiv, await testBim.views.load("0x34")); const vis = vp.perModelCategoryVisibility; - ViewportChangedHandler.test(vp, (mon) => { - expect(vis.getOverride("0x1c", "0x1234")).to.equal(PerModelCategoryVisibility.Override.None); + using mon = new ViewportChangedHandler(vp); + expect(vis.getOverride("0x1c", "0x1234")).to.equal(PerModelCategoryVisibility.Override.None); - // No net change => no event - mon.expect(ChangeFlag.None, undefined, () => vis.setOverride("0x1c", "0x1234", PerModelCategoryVisibility.Override.None)); - expect(vis.getOverride("0x1c", "0x1234")).to.equal(PerModelCategoryVisibility.Override.None); + // No net change => no event + mon.expect(ChangeFlag.None, undefined, () => vis.setOverride("0x1c", "0x1234", PerModelCategoryVisibility.Override.None)); + expect(vis.getOverride("0x1c", "0x1234")).to.equal(PerModelCategoryVisibility.Override.None); - mon.expect(ChangeFlag.ViewedCategoriesPerModel, undefined, () => vis.setOverride("0x1c", "0x1234", PerModelCategoryVisibility.Override.Show)); - expect(vis.getOverride("0x1c", "0x1234")).to.equal(PerModelCategoryVisibility.Override.Show); + mon.expect(ChangeFlag.ViewedCategoriesPerModel, undefined, () => vis.setOverride("0x1c", "0x1234", PerModelCategoryVisibility.Override.Show)); + expect(vis.getOverride("0x1c", "0x1234")).to.equal(PerModelCategoryVisibility.Override.Show); - mon.expect(ChangeFlag.ViewedCategoriesPerModel, undefined, () => vis.setOverride("0x1c", "0x1234", PerModelCategoryVisibility.Override.Hide)); - expect(vis.getOverride("0x1c", "0x1234")).to.equal(PerModelCategoryVisibility.Override.Hide); + mon.expect(ChangeFlag.ViewedCategoriesPerModel, undefined, () => vis.setOverride("0x1c", "0x1234", PerModelCategoryVisibility.Override.Hide)); + expect(vis.getOverride("0x1c", "0x1234")).to.equal(PerModelCategoryVisibility.Override.Hide); - mon.expect(ChangeFlag.None, undefined, () => vis.clearOverrides("0x9876")); + mon.expect(ChangeFlag.None, undefined, () => vis.clearOverrides("0x9876")); - mon.expect(ChangeFlag.ViewedCategoriesPerModel, undefined, () => vis.clearOverrides()); - expect(vis.getOverride("0x1c", "0x1234")).to.equal(PerModelCategoryVisibility.Override.None); + mon.expect(ChangeFlag.ViewedCategoriesPerModel, undefined, () => vis.clearOverrides()); + expect(vis.getOverride("0x1c", "0x1234")).to.equal(PerModelCategoryVisibility.Override.None); - mon.expect(ChangeFlag.None, undefined, () => vis.clearOverrides()); + mon.expect(ChangeFlag.None, undefined, () => vis.clearOverrides()); - const idSet = new Set(); - idSet.add("0x1234567"); - mon.expect(ChangeFlag.None, undefined, () => vis.setOverride(new Set(), new Set(), PerModelCategoryVisibility.Override.Show)); - mon.expect(ChangeFlag.None, undefined, () => vis.setOverride(idSet, new Set(), PerModelCategoryVisibility.Override.Show)); - mon.expect(ChangeFlag.None, undefined, () => vis.setOverride(new Set(), idSet, PerModelCategoryVisibility.Override.Show)); + const idSet = new Set(); + idSet.add("0x1234567"); + mon.expect(ChangeFlag.None, undefined, () => vis.setOverride(new Set(), new Set(), PerModelCategoryVisibility.Override.Show)); + mon.expect(ChangeFlag.None, undefined, () => vis.setOverride(idSet, new Set(), PerModelCategoryVisibility.Override.Show)); + mon.expect(ChangeFlag.None, undefined, () => vis.setOverride(new Set(), idSet, PerModelCategoryVisibility.Override.Show)); - const idList = ["0x1234567"]; - mon.expect(ChangeFlag.None, undefined, () => vis.setOverride([], [], PerModelCategoryVisibility.Override.Show)); - mon.expect(ChangeFlag.None, undefined, () => vis.setOverride(idList, [], PerModelCategoryVisibility.Override.Show)); - mon.expect(ChangeFlag.None, undefined, () => vis.setOverride([], idList, PerModelCategoryVisibility.Override.Show)); + const idList = ["0x1234567"]; + mon.expect(ChangeFlag.None, undefined, () => vis.setOverride([], [], PerModelCategoryVisibility.Override.Show)); + mon.expect(ChangeFlag.None, undefined, () => vis.setOverride(idList, [], PerModelCategoryVisibility.Override.Show)); + mon.expect(ChangeFlag.None, undefined, () => vis.setOverride([], idList, PerModelCategoryVisibility.Override.Show)); - const modelIdList = ["0x1", "0x2", "0x3"]; - const catIdList = ["0xa", "0xb"]; - mon.expect(ChangeFlag.ViewedCategoriesPerModel, undefined, () => vis.setOverride(modelIdList, catIdList, PerModelCategoryVisibility.Override.Show)); - for (const modelId of modelIdList) - for (const catId of catIdList) - expect(vis.getOverride(modelId, catId)).to.equal(PerModelCategoryVisibility.Override.Show); + const modelIdList = ["0x1", "0x2", "0x3"]; + const catIdList = ["0xa", "0xb"]; + mon.expect(ChangeFlag.ViewedCategoriesPerModel, undefined, () => vis.setOverride(modelIdList, catIdList, PerModelCategoryVisibility.Override.Show)); + for (const modelId of modelIdList) + for (const catId of catIdList) + expect(vis.getOverride(modelId, catId)).to.equal(PerModelCategoryVisibility.Override.Show); - // No net change - mon.expect(ChangeFlag.None, undefined, () => vis.setOverride(modelIdList, catIdList, PerModelCategoryVisibility.Override.Show)); + // No net change + mon.expect(ChangeFlag.None, undefined, () => vis.setOverride(modelIdList, catIdList, PerModelCategoryVisibility.Override.Show)); - modelIdList.shift(); // remove "0x1" - catIdList.shift(); // remove "0xa" - mon.expect(ChangeFlag.ViewedCategoriesPerModel, undefined, () => vis.setOverride(modelIdList, catIdList, PerModelCategoryVisibility.Override.Hide)); - expect(vis.getOverride("0x1", "0xa")).to.equal(PerModelCategoryVisibility.Override.Show); - expect(vis.getOverride("0x1", "0xb")).to.equal(PerModelCategoryVisibility.Override.Show); - expect(vis.getOverride("0x2", "0xa")).to.equal(PerModelCategoryVisibility.Override.Show); - expect(vis.getOverride("0x2", "0xb")).to.equal(PerModelCategoryVisibility.Override.Hide); - expect(vis.getOverride("0x3", "0xa")).to.equal(PerModelCategoryVisibility.Override.Show); - expect(vis.getOverride("0x3", "0xb")).to.equal(PerModelCategoryVisibility.Override.Hide); + modelIdList.shift(); // remove "0x1" + catIdList.shift(); // remove "0xa" + mon.expect(ChangeFlag.ViewedCategoriesPerModel, undefined, () => vis.setOverride(modelIdList, catIdList, PerModelCategoryVisibility.Override.Hide)); + expect(vis.getOverride("0x1", "0xa")).to.equal(PerModelCategoryVisibility.Override.Show); + expect(vis.getOverride("0x1", "0xb")).to.equal(PerModelCategoryVisibility.Override.Show); + expect(vis.getOverride("0x2", "0xa")).to.equal(PerModelCategoryVisibility.Override.Show); + expect(vis.getOverride("0x2", "0xb")).to.equal(PerModelCategoryVisibility.Override.Hide); + expect(vis.getOverride("0x3", "0xa")).to.equal(PerModelCategoryVisibility.Override.Show); + expect(vis.getOverride("0x3", "0xb")).to.equal(PerModelCategoryVisibility.Override.Hide); - mon.expect(ChangeFlag.ViewedCategoriesPerModel, undefined, () => vis.clearOverrides(["0x1"])); - expect(vis.getOverride("0x1", "0xa")).to.equal(PerModelCategoryVisibility.Override.None); - expect(vis.getOverride("0x1", "0xb")).to.equal(PerModelCategoryVisibility.Override.None); - }); + mon.expect(ChangeFlag.ViewedCategoriesPerModel, undefined, () => vis.clearOverrides(["0x1"])); + expect(vis.getOverride("0x1", "0xa")).to.equal(PerModelCategoryVisibility.Override.None); + expect(vis.getOverride("0x1", "0xb")).to.equal(PerModelCategoryVisibility.Override.None); }); it("should be dispatched when feature override provider changes", async () => { @@ -561,30 +548,29 @@ describe("Viewport changed events", async () => { }, }; - ViewportChangedHandler.test(vp, (mon) => { - // Changing the provider => event - mon.expect(ChangeFlag.FeatureOverrideProvider, undefined, () => vp.addFeatureOverrideProvider(provider)); - expect(overridesAdded).to.be.true; - overridesAdded = false; - - // Explicitly notifying provider's state has changed => event - mon.expect(ChangeFlag.FeatureOverrideProvider, undefined, () => vp.setFeatureOverrideProviderChanged()); - expect(overridesAdded).to.be.true; - overridesAdded = false; - - // Setting provider to same value => no event - mon.expect(ChangeFlag.None, undefined, () => vp.addFeatureOverrideProvider(provider)); - expect(overridesAdded).to.be.false; - - // Actually changing the provider => event - mon.expect(ChangeFlag.FeatureOverrideProvider, undefined, () => { - const prov = vp.findFeatureOverrideProvider((_) => true); - expect(prov).not.to.be.undefined; - if (prov) - vp.dropFeatureOverrideProvider(prov); - }); - expect(overridesAdded).to.be.false; + using mon = new ViewportChangedHandler(vp); + // Changing the provider => event + mon.expect(ChangeFlag.FeatureOverrideProvider, undefined, () => vp.addFeatureOverrideProvider(provider)); + expect(overridesAdded).to.be.true; + overridesAdded = false; + + // Explicitly notifying provider's state has changed => event + mon.expect(ChangeFlag.FeatureOverrideProvider, undefined, () => vp.setFeatureOverrideProviderChanged()); + expect(overridesAdded).to.be.true; + overridesAdded = false; + + // Setting provider to same value => no event + mon.expect(ChangeFlag.None, undefined, () => vp.addFeatureOverrideProvider(provider)); + expect(overridesAdded).to.be.false; + + // Actually changing the provider => event + mon.expect(ChangeFlag.FeatureOverrideProvider, undefined, () => { + const prov = vp.findFeatureOverrideProvider((_) => true); + expect(prov).not.to.be.undefined; + if (prov) + vp.dropFeatureOverrideProvider(prov); }); + expect(overridesAdded).to.be.false; }); it("should be dispatched when changing ViewState", async () => { @@ -594,28 +580,27 @@ describe("Viewport changed events", async () => { const view3d17 = await testImodel.views.load(id64(0x17)); // cat sel 0e, mod sel 14 vp = ScreenViewport.create(viewDiv, view2d20.clone()); - ViewportChangedHandler.test(vp, (mon) => { - // No effective change to view - mon.expect(ChangeFlag.ViewState, ViewportState.Controller, () => changeView(vp, view2d20.clone())); + using mon = new ViewportChangedHandler(vp); + // No effective change to view + mon.expect(ChangeFlag.ViewState, ViewportState.Controller, () => changeView(vp, view2d20.clone())); - // 2d => 2d - mon.expect(ChangeFlag.ViewState | ChangeFlag.ViewedCategories | ChangeFlag.ViewedModels | ChangeFlag.DisplayStyle, ViewportState.Controller, () => changeView(vp, view2d2e.clone())); + // 2d => 2d + mon.expect(ChangeFlag.ViewState | ChangeFlag.ViewedCategories | ChangeFlag.ViewedModels | ChangeFlag.DisplayStyle, ViewportState.Controller, () => changeView(vp, view2d2e.clone())); - // 2d => 3d - mon.expect(ChangeFlag.ViewState | ChangeFlag.ViewedCategories | ChangeFlag.ViewedModels | ChangeFlag.DisplayStyle, ViewportState.Controller, () => changeView(vp, view3d15.clone())); + // 2d => 3d + mon.expect(ChangeFlag.ViewState | ChangeFlag.ViewedCategories | ChangeFlag.ViewedModels | ChangeFlag.DisplayStyle, ViewportState.Controller, () => changeView(vp, view3d15.clone())); - // No effective change - mon.expect(ChangeFlag.ViewState, ViewportState.Controller, () => changeView(vp, view3d15.clone())); + // No effective change + mon.expect(ChangeFlag.ViewState, ViewportState.Controller, () => changeView(vp, view3d15.clone())); - // 3d => 3d - same model selector, same display style, different category selector - mon.expect(ChangeFlag.ViewState | ChangeFlag.ViewedCategories, ViewportState.Controller, () => changeView(vp, view3d17.clone())); + // 3d => 3d - same model selector, same display style, different category selector + mon.expect(ChangeFlag.ViewState | ChangeFlag.ViewedCategories, ViewportState.Controller, () => changeView(vp, view3d17.clone())); - // 3d => 2d - mon.expect(ChangeFlag.ViewState | ChangeFlag.ViewedCategories | ChangeFlag.ViewedModels | ChangeFlag.DisplayStyle, ViewportState.Controller, () => changeView(vp, view2d20.clone())); + // 3d => 2d + mon.expect(ChangeFlag.ViewState | ChangeFlag.ViewedCategories | ChangeFlag.ViewedModels | ChangeFlag.DisplayStyle, ViewportState.Controller, () => changeView(vp, view2d20.clone())); - // Pass the exact same ViewState reference => no "ViewState changed" event. - mon.expect(ChangeFlag.None, undefined, () => changeView(vp, vp.view)); - }); + // Pass the exact same ViewState reference => no "ViewState changed" event. + mon.expect(ChangeFlag.None, undefined, () => changeView(vp, vp.view)); // Test the immediately-fire onChangeView event. let numEvents = 0; @@ -640,25 +625,24 @@ describe("Viewport changed events", async () => { const view = await testBim.views.load("0x34") as SpatialViewState; vp = ScreenViewport.create(viewDiv, view); - ViewportChangedHandler.test(vp, (mon) => { - const expectChange = (state: ViewportState, func: () => void) => mon.expect(ChangeFlag.None, state, func); - - expectChange(ViewportState.RenderPlan, () => view.details.clipVector = ClipVector.fromJSON([{ - shape: { - points: [ - [0, 0, 0], [1, 0, 0], [1, 1, 0], [0, 0, 0], - ], - }, - }])); - - expectChange(ViewportState.Scene, () => view.details.modelClipGroups = new ModelClipGroups([ModelClipGroup.fromJSON({ models: ["0x123"] })])); - expectChange(ViewportState.Scene, () => view.modelDisplayTransformProvider = { - getModelDisplayTransform: () => { - return { - transform: Transform.createIdentity(), - }; - }, - }); + using mon = new ViewportChangedHandler(vp); + const expectChange = (state: ViewportState, func: () => void) => mon.expect(ChangeFlag.None, state, func); + + expectChange(ViewportState.RenderPlan, () => view.details.clipVector = ClipVector.fromJSON([{ + shape: { + points: [ + [0, 0, 0], [1, 0, 0], [1, 1, 0], [0, 0, 0], + ], + }, + }])); + + expectChange(ViewportState.Scene, () => view.details.modelClipGroups = new ModelClipGroups([ModelClipGroup.fromJSON({ models: ["0x123"] })])); + expectChange(ViewportState.Scene, () => view.modelDisplayTransformProvider = { + getModelDisplayTransform: () => { + return { + transform: Transform.createIdentity(), + }; + }, }); }); @@ -688,7 +672,7 @@ describe("Viewport changed events", async () => { expect(vp.renderPlanValid).to.be.true; expect(vp2.renderPlanValid).to.be.true; - vp2.dispose(); + vp2[Symbol.dispose](); document.body.removeChild(div2); }); diff --git a/full-stack-tests/core/src/frontend/standalone/tile/Disposable.test.ts b/full-stack-tests/core/src/frontend/standalone/tile/Disposable.test.ts index 226c8e1dc253..d90a8ddb68db 100644 --- a/full-stack-tests/core/src/frontend/standalone/tile/Disposable.test.ts +++ b/full-stack-tests/core/src/frontend/standalone/tile/Disposable.test.ts @@ -3,7 +3,7 @@ * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ import { assert, expect } from "chai"; -import { ByteStream, IDisposable } from "@itwin/core-bentley"; +import { ByteStream } from "@itwin/core-bentley"; import { ColorByName, ColorDef, ColorIndex, FeatureIndex, FillFlags, ImageBuffer, ImageBufferFormat, QParams3d, QPoint3dList, RenderTexture } from "@itwin/core-common"; import { Decorations, GraphicList, GraphicType, ImdlReader, IModelApp, IModelConnection, OffScreenViewport, PlanarClassifierMap, PlanarClassifierTarget, @@ -167,7 +167,7 @@ describe("Disposal of System", () => { assert.isFalse(isDisposed(texture0!)); assert.isFalse(isDisposed(texture1!)); - system.dispose(); + system[Symbol.dispose](); // Post-disposal assert.isTrue(isDisposed(texture0!)); @@ -238,15 +238,15 @@ describe("Disposal of WebGL Resources", () => { assert.isFalse(isDisposed(meshGraphic1)); assert.isFalse(isDisposed(tileGraphic)); - meshGraphic0.dispose(); - meshGraphic1.dispose(); + meshGraphic0[Symbol.dispose](); + meshGraphic1[Symbol.dispose](); // Post-disposal of graphic 0 and graphic 1 assert.isTrue(isDisposed(meshGraphic0)); assert.isTrue(isDisposed(meshGraphic1)); assert.isFalse(isDisposed(tileGraphic)); - tileGraphic.dispose(); + tileGraphic[Symbol.dispose](); // Post-disposal of tileGraphic assert.isTrue(isDisposed(tileGraphic)); @@ -274,12 +274,12 @@ describe("Disposal of WebGL Resources", () => { expect(tx).not.to.be.undefined; expect(tx.isDisposed).to.be.false; - blitGeom = target._blitGeom as IDisposable; + blitGeom = target._blitGeom as Disposable; expect(blitGeom === undefined).to.equal(vp instanceof OffScreenViewport); if (blitGeom) expect(blitGeom.isDisposed).to.be.false; - vp.dispose(); + vp[Symbol.dispose](); expect(vp.isDisposed).to.be.true; expect(target.isDisposed).to.be.true; @@ -298,7 +298,7 @@ describe("Disposal of WebGL Resources", () => { public constructor() { super(); } public collectGraphics(_context: SceneContext, _target: PlanarClassifierTarget): void { } public setSource(_classifierTreeRef?: TileTreeReference, _planarClipMask?: PlanarClipMaskState): void { } - public dispose(): void { + public [Symbol.dispose](): void { expect(this.disposed).to.be.false; this.disposed = true; } @@ -309,7 +309,7 @@ describe("Disposal of WebGL Resources", () => { public constructor() { super(); } public collectGraphics(_context: SceneContext): void { } public collectStatistics(_stats: RenderMemory.Statistics): void { } - public dispose(): void { + public [Symbol.dispose](): void { expect(this.disposed).to.be.false; this.disposed = true; } @@ -317,7 +317,7 @@ describe("Disposal of WebGL Resources", () => { interface ClassifierOrDrape { disposed: boolean; - dispose(): void; + [Symbol.dispose](): void; } async function testClassifiersOrDrapes( @@ -396,7 +396,7 @@ describe("Disposal of WebGL Resources", () => { expect(c2.disposed).to.be.true; // Dispose of the target. - vp.dispose(); + vp[Symbol.dispose](); expect(target[key]).to.be.undefined; expect(c1.disposed).to.be.true; } @@ -454,8 +454,8 @@ describe("Disposal of WebGL Resources", () => { assert.isFalse(isDisposed(texture)); assert.isFalse(isDisposed(graphic)); - system.dispose(); - graphic.dispose(); + system[Symbol.dispose](); + graphic[Symbol.dispose](); // Post-disposal of non-related items assert.isFalse(isDisposed(target)); @@ -473,7 +473,7 @@ describe("Disposal of WebGL Resources", () => { const clipMask = exposedTarget.clipMask; const environmentMap = exposedTarget.environmentMap; const diffuseMap = exposedTarget.diffuseMap; - target.dispose(); + target[Symbol.dispose](); // Post-disposal of target (not owned resource checks) if (batches.length > 0 && !allOverridesSharedWithTarget(target, batches)) diff --git a/full-stack-tests/core/src/frontend/standalone/tile/Unloading.test.ts b/full-stack-tests/core/src/frontend/standalone/tile/Unloading.test.ts index 32d0408b6375..a6fcd4e40c07 100644 --- a/full-stack-tests/core/src/frontend/standalone/tile/Unloading.test.ts +++ b/full-stack-tests/core/src/frontend/standalone/tile/Unloading.test.ts @@ -56,8 +56,8 @@ describe("Tile unloading", async () => { } it("should mark usage", async () => { - const vp1 = await createOnScreenTestViewport("0x41", imodel, 100, 100); - const vp2 = await createOnScreenTestViewport("0x41", imodel, 100, 100); + using vp1 = await createOnScreenTestViewport("0x41", imodel, 100, 100); + using vp2 = await createOnScreenTestViewport("0x41", imodel, 100, 100); const now = BeTimePoint.now(); const later = now.plus(BeDuration.fromSeconds(10)); @@ -93,9 +93,6 @@ describe("Tile unloading", async () => { expect(admin.isTileInUse(marker)).to.be.false; expect(marker.isExpired(now)).to.be.false; expect(marker.isExpired(later)).to.be.true; - - vp1.dispose(); - vp2.dispose(); }); it("should not dispose of displayed tiles", async () => { diff --git a/full-stack-tests/ecschema-rpc-interface/package.json b/full-stack-tests/ecschema-rpc-interface/package.json index c8147acf9f58..820f2d238732 100644 --- a/full-stack-tests/ecschema-rpc-interface/package.json +++ b/full-stack-tests/ecschema-rpc-interface/package.json @@ -58,7 +58,7 @@ "@types/chai": "4.3.1", "@types/chai-as-promised": "^7", "@types/mocha": "^10.0.6", - "@types/node": "~20.9.5", + "@types/node": "~20.17.0", "assert": "^2.0.0", "browserify-zlib": "^0.2.0", "cpx2": "^3.0.0", @@ -75,4 +75,4 @@ "webpack": "^5.97.1", "webpack-cli": "^5.0.1" } -} +} \ No newline at end of file diff --git a/full-stack-tests/presentation/package.json b/full-stack-tests/presentation/package.json index 292443f8c9b7..530748988b06 100644 --- a/full-stack-tests/presentation/package.json +++ b/full-stack-tests/presentation/package.json @@ -45,7 +45,7 @@ "@types/deep-equal": "^1", "@types/faker": "^4.1.0", "@types/mocha": "^10.0.6", - "@types/node": "~20.9.5", + "@types/node": "~20.17.0", "@types/rimraf": "^2.0.2", "@types/sinon": "^17.0.2", "@types/sinon-chai": "^3.2.0", @@ -106,4 +106,4 @@ "./lib/**/*.test.js" ] } -} +} \ No newline at end of file diff --git a/full-stack-tests/presentation/src/backend/Diagnostics.test.ts b/full-stack-tests/presentation/src/backend/Diagnostics.test.ts index 21783288a54d..f12a09f983fb 100644 --- a/full-stack-tests/presentation/src/backend/Diagnostics.test.ts +++ b/full-stack-tests/presentation/src/backend/Diagnostics.test.ts @@ -5,7 +5,6 @@ import { expect } from "chai"; import * as sinon from "sinon"; import { IModelDb, SnapshotDb } from "@itwin/core-backend"; -import { using } from "@itwin/core-bentley"; import { Presentation, PresentationManager } from "@itwin/presentation-backend"; import { ChildNodeSpecificationTypes, Diagnostics, DiagnosticsLogEntry, PresentationError, Ruleset, RuleTypes } from "@itwin/presentation-common"; import { initialize, terminate } from "../IntegrationTests"; @@ -40,47 +39,44 @@ describe("Diagnostics", async () => { it("includes diagnostics if request takes longer than minimum duration", async () => { const requestDiagnosticsSpy = sinon.spy(); - await using(new PresentationManager(), async (manager) => { - await manager.getNodes({ - imodel, - rulesetOrId: ruleset, - diagnostics: { - perf: { minimumDuration: 1 }, - handler: requestDiagnosticsSpy, - }, - }); + using manager = new PresentationManager(); + await manager.getNodes({ + imodel, + rulesetOrId: ruleset, + diagnostics: { + perf: { minimumDuration: 1 }, + handler: requestDiagnosticsSpy, + }, }); expect(requestDiagnosticsSpy).to.be.calledOnceWith(sinon.match((d: Diagnostics) => d && d.logs && d.logs.length > 0)); }); it("doesn't include diagnostics if request takes less time than minimum duration", async () => { const requestDiagnosticsSpy = sinon.spy(); - await using(new PresentationManager(), async (manager) => { - await manager.getNodes({ - imodel, - rulesetOrId: ruleset, - diagnostics: { - perf: { minimumDuration: 5000 }, - handler: requestDiagnosticsSpy, - }, - }); + using manager = new PresentationManager(); + await manager.getNodes({ + imodel, + rulesetOrId: ruleset, + diagnostics: { + perf: { minimumDuration: 5000 }, + handler: requestDiagnosticsSpy, + }, }); expect(requestDiagnosticsSpy).to.not.be.called; }); it("includes diagnostics if request fails", async () => { const requestDiagnosticsSpy = sinon.spy(); + using manager = new PresentationManager(); await expect( - using(new PresentationManager(), async (manager) => { - await manager.getNodes({ - imodel, - rulesetOrId: ruleset, - instanceFilter: {} as any, - diagnostics: { - dev: "error", - handler: requestDiagnosticsSpy, - }, - }); + manager.getNodes({ + imodel, + rulesetOrId: ruleset, + instanceFilter: {} as any, + diagnostics: { + dev: "error", + handler: requestDiagnosticsSpy, + }, }), ).to.eventually.be.rejectedWith(PresentationError); expect(requestDiagnosticsSpy).to.be.calledOnceWith(sinon.match((d: Diagnostics) => d && d.logs && d.logs.length > 0)); @@ -89,14 +85,13 @@ describe("Diagnostics", async () => { it("doesn't report request diagnostics if not requested when manager diagnostics requested", async () => { const managerDiagnosticsSpy = sinon.spy(); const requestDiagnosticsSpy = sinon.spy(); - await using(new PresentationManager({ diagnostics: { dev: true, editor: true, perf: true, handler: managerDiagnosticsSpy } }), async (manager) => { - await manager.getNodes({ - imodel, - rulesetOrId: ruleset, - diagnostics: { - handler: requestDiagnosticsSpy, - }, - }); + using manager = new PresentationManager({ diagnostics: { dev: true, editor: true, perf: true, handler: managerDiagnosticsSpy } }); + await manager.getNodes({ + imodel, + rulesetOrId: ruleset, + diagnostics: { + handler: requestDiagnosticsSpy, + }, }); expect(requestDiagnosticsSpy).to.not.be.called; expect(managerDiagnosticsSpy).to.be.calledOnce; @@ -105,17 +100,16 @@ describe("Diagnostics", async () => { it("doesn't report manager diagnostics if not requested when request diagnostics requested", async () => { const managerDiagnosticsSpy = sinon.spy(); const requestDiagnosticsSpy = sinon.spy(); - await using(new PresentationManager({ diagnostics: { handler: managerDiagnosticsSpy } }), async (manager) => { - await manager.getNodes({ - imodel, - rulesetOrId: ruleset, - diagnostics: { - dev: true, - editor: true, - perf: true, - handler: requestDiagnosticsSpy, - }, - }); + using manager = new PresentationManager({ diagnostics: { handler: managerDiagnosticsSpy } }); + await manager.getNodes({ + imodel, + rulesetOrId: ruleset, + diagnostics: { + dev: true, + editor: true, + perf: true, + handler: requestDiagnosticsSpy, + }, }); expect(requestDiagnosticsSpy).to.be.calledOnce; expect(managerDiagnosticsSpy).to.not.be.called; @@ -126,22 +120,18 @@ describe("Diagnostics", async () => { const managerDiagnosticsSpy = sinon.spy(); const requestDiagnosticsContext = {}; const requestDiagnosticsSpy = sinon.spy(); - await using( - new PresentationManager({ - diagnostics: { perf: true, dev: "trace", handler: managerDiagnosticsSpy, requestContextSupplier: () => managerDiagnosticsContext }, - }), - async (manager) => { - await manager.getNodes({ - imodel, - rulesetOrId: ruleset, - diagnostics: { - editor: "trace", - handler: requestDiagnosticsSpy, - requestContextSupplier: () => requestDiagnosticsContext, - }, - }); + using manager = new PresentationManager({ + diagnostics: { perf: true, dev: "trace", handler: managerDiagnosticsSpy, requestContextSupplier: () => managerDiagnosticsContext }, + }); + await manager.getNodes({ + imodel, + rulesetOrId: ruleset, + diagnostics: { + editor: "trace", + handler: requestDiagnosticsSpy, + requestContextSupplier: () => requestDiagnosticsContext, }, - ); + }); expect(managerDiagnosticsSpy).be.calledOnceWithExactly( sinon.match((d: Diagnostics) => { function isPerfOrDevLog(entry: DiagnosticsLogEntry): boolean { diff --git a/full-stack-tests/presentation/src/backend/NativePlatform.test.ts b/full-stack-tests/presentation/src/backend/NativePlatform.test.ts index 17cbe1b83784..e740c796ac53 100644 --- a/full-stack-tests/presentation/src/backend/NativePlatform.test.ts +++ b/full-stack-tests/presentation/src/backend/NativePlatform.test.ts @@ -36,7 +36,7 @@ describe("NativePlatform", () => { }); afterEach(() => { - nativePlatform.dispose(); + nativePlatform[Symbol.dispose](); try { imodel.close(); } catch {} diff --git a/full-stack-tests/presentation/src/backend/PresentationManager.test.ts b/full-stack-tests/presentation/src/backend/PresentationManager.test.ts index ce4890ee43cc..b899a9a8a31b 100644 --- a/full-stack-tests/presentation/src/backend/PresentationManager.test.ts +++ b/full-stack-tests/presentation/src/backend/PresentationManager.test.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { expect } from "chai"; import { IModelDb, SnapshotDb } from "@itwin/core-backend"; -import { BeEvent, Guid, using } from "@itwin/core-bentley"; +import { BeEvent, Guid } from "@itwin/core-bentley"; import { UnitSystemKey } from "@itwin/core-quantity"; import { Schema, SchemaContext, SchemaInfo, SchemaKey, SchemaMatchType } from "@itwin/ecschema-metadata"; import { PresentationManager, PresentationManagerProps } from "@itwin/presentation-backend"; @@ -148,21 +148,20 @@ describe("PresentationManager", () => { }); async function getAreaDisplayValue(unitSystem: UnitSystemKey, defaultFormats?: FormatsMap): Promise { - return using(new PresentationManager({ defaultFormats, defaultLocale: "en-PSEUDO", ...config }), async (manager) => { - const descriptor = await manager.getContentDescriptor({ - imodel, - rulesetOrId: ruleset, - keys, - displayType: "Grid", - unitSystem, - }); - expect(descriptor).to.not.be.undefined; - const field = getFieldByLabel(descriptor!.fields, "cm2"); - const content = await manager.getContent({ imodel, rulesetOrId: ruleset, keys, descriptor: descriptor!, unitSystem }); - const displayValues = content!.contentSet[0].values.rc_generic_PhysicalObject_ncc_MyProp_areaElementAspect as DisplayValuesArray; - expect(displayValues.length).is.eq(1); - return ((displayValues[0] as DisplayValuesMap).displayValues as DisplayValuesMap)[field.name]!; + using manager = new PresentationManager({ defaultFormats, defaultLocale: "en-PSEUDO", ...config }); + const descriptor = await manager.getContentDescriptor({ + imodel, + rulesetOrId: ruleset, + keys, + displayType: "Grid", + unitSystem, }); + expect(descriptor).to.not.be.undefined; + const field = getFieldByLabel(descriptor!.fields, "cm2"); + const content = await manager.getContent({ imodel, rulesetOrId: ruleset, keys, descriptor: descriptor!, unitSystem }); + const displayValues = content!.contentSet[0].values.rc_generic_PhysicalObject_ncc_MyProp_areaElementAspect as DisplayValuesArray; + expect(displayValues.length).is.eq(1); + return ((displayValues[0] as DisplayValuesMap).displayValues as DisplayValuesMap)[field.name]!; } }); }); @@ -170,53 +169,50 @@ describe("PresentationManager", () => { describe("getElementProperties", () => { it("returns properties for some elements of class 'PhysicalObject", async () => { - await using(new PresentationManager(), async (manager) => { - const properties: ElementProperties[] = []; - const { iterator } = await manager.getElementProperties({ imodel, elementClasses: ["Generic:PhysicalObject"] }); - for await (const items of iterator()) { - properties.push(...items); - } - expect(properties).to.matchSnapshot(); - }); + using manager = new PresentationManager(); + const properties: ElementProperties[] = []; + const { iterator } = await manager.getElementProperties({ imodel, elementClasses: ["Generic:PhysicalObject"] }); + for await (const items of iterator()) { + properties.push(...items); + } + expect(properties).to.matchSnapshot(); }); it("returns properties of specific elements by element ID", async () => { - await using(new PresentationManager(), async (manager) => { - const properties: ElementProperties[] = []; - const { iterator } = await manager.getElementProperties({ imodel, elementIds: ["0x74", "0x1", "0x75"] }); - for await (const items of iterator()) { - properties.push(...items); - } - expect(properties).to.matchSnapshot(); - }); + using manager = new PresentationManager(); + const properties: ElementProperties[] = []; + const { iterator } = await manager.getElementProperties({ imodel, elementIds: ["0x74", "0x1", "0x75"] }); + for await (const items of iterator()) { + properties.push(...items); + } + expect(properties).to.matchSnapshot(); }); }); describe("Cancel request", () => { it("cancels 'getNodes' request", async () => { - await using(new PresentationManager(), async (manager) => { - const cancelEvent = new BeEvent<() => void>(); - const promise = manager.getNodes({ - imodel, - rulesetOrId: { - id: "ruleset", - rules: [ - { - ruleType: RuleTypes.RootNodes, - specifications: [ - { - specType: ChildNodeSpecificationTypes.InstanceNodesOfSpecificClasses, - classes: { schemaName: "Generic", classNames: ["PhysicalObject"] }, - }, - ], - }, - ], - }, - cancelEvent, - }); - cancelEvent.raiseEvent(); - await expect(promise).to.eventually.be.rejectedWith(PresentationError).and.have.property("errorNumber", PresentationStatus.Canceled); + using manager = new PresentationManager(); + const cancelEvent = new BeEvent<() => void>(); + const promise = manager.getNodes({ + imodel, + rulesetOrId: { + id: "ruleset", + rules: [ + { + ruleType: RuleTypes.RootNodes, + specifications: [ + { + specType: ChildNodeSpecificationTypes.InstanceNodesOfSpecificClasses, + classes: { schemaName: "Generic", classNames: ["PhysicalObject"] }, + }, + ], + }, + ], + }, + cancelEvent, }); + cancelEvent.raiseEvent(); + await expect(promise).to.eventually.be.rejectedWith(PresentationError).and.have.property("errorNumber", PresentationStatus.Canceled); }); }); }); diff --git a/full-stack-tests/presentation/src/backend/ReadWrite.test.ts b/full-stack-tests/presentation/src/backend/ReadWrite.test.ts index 7da130cedc45..ac888dc07e71 100644 --- a/full-stack-tests/presentation/src/backend/ReadWrite.test.ts +++ b/full-stack-tests/presentation/src/backend/ReadWrite.test.ts @@ -39,7 +39,7 @@ describe("ReadWrite", () => { const imodelPath = imodel.pathName; imodel.close(); fs.unlinkSync(imodelPath); - manager.dispose(); + manager[Symbol.dispose](); }); describe("Handling read-write operations", () => { diff --git a/full-stack-tests/presentation/src/frontend/Localization.test.ts b/full-stack-tests/presentation/src/frontend/Localization.test.ts index 38ac647f0589..28c765b14e3f 100644 --- a/full-stack-tests/presentation/src/frontend/Localization.test.ts +++ b/full-stack-tests/presentation/src/frontend/Localization.test.ts @@ -303,7 +303,7 @@ describe("Localization", async () => { }); afterEach(async () => { - frontends.forEach((f) => f.dispose()); + frontends.forEach((f) => f[Symbol.dispose]()); }); it("handles multiple simultaneous requests from different frontends with different locales", async () => { diff --git a/full-stack-tests/presentation/src/frontend/RulesetVariables.test.ts b/full-stack-tests/presentation/src/frontend/RulesetVariables.test.ts index 439d1cb6032c..cd20acaeb5da 100644 --- a/full-stack-tests/presentation/src/frontend/RulesetVariables.test.ts +++ b/full-stack-tests/presentation/src/frontend/RulesetVariables.test.ts @@ -258,7 +258,7 @@ describe("Ruleset Variables", async () => { afterEach(async () => { await imodel.close(); - frontends.forEach((f) => f.dispose()); + frontends.forEach((f) => f[Symbol.dispose]()); }); it("handles multiple simultaneous requests from different frontends with ruleset variables", async () => { @@ -285,7 +285,7 @@ describe("Ruleset Variables", async () => { afterEach(async () => { await imodel.close(); - frontend.dispose(); + frontend[Symbol.dispose](); }); it("can use the same frontend-registered ruleset variables after backend is reset", async () => { diff --git a/full-stack-tests/presentation/src/frontend/Rulesets.test.ts b/full-stack-tests/presentation/src/frontend/Rulesets.test.ts index 73d9884aed59..2a650abe979b 100644 --- a/full-stack-tests/presentation/src/frontend/Rulesets.test.ts +++ b/full-stack-tests/presentation/src/frontend/Rulesets.test.ts @@ -3,9 +3,8 @@ * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ import { expect } from "chai"; -import { using } from "@itwin/core-bentley"; import { IModelConnection } from "@itwin/core-frontend"; -import { ChildNodeSpecificationTypes, RegisteredRuleset, Ruleset, RuleTypes } from "@itwin/presentation-common"; +import { ChildNodeSpecificationTypes, Ruleset, RuleTypes } from "@itwin/presentation-common"; import { Presentation, PresentationManager } from "@itwin/presentation-frontend"; import { initialize, resetBackend, terminate } from "../IntegrationTests"; import { collect } from "../Utils"; @@ -58,12 +57,10 @@ describe("Rulesets", async () => { }); it("creates ruleset from json and gets root node using it", async () => { - await using>(await Presentation.presentation.rulesets().add(RULESET_1), async () => { - const rootNodes = await Presentation.presentation.getNodesIterator({ imodel, rulesetOrId: RULESET_1.id }).then(async (x) => collect(x.items)); - expect(rootNodes.length).to.be.equal(1); - expect(rootNodes[0].label.displayValue).to.equal("label 1"); - }); - await Presentation.presentation.rulesets().clear(); + using _registered = await Presentation.presentation.rulesets().add(RULESET_1); + const rootNodes = await Presentation.presentation.getNodesIterator({ imodel, rulesetOrId: RULESET_1.id }).then(async (x) => collect(x.items)); + expect(rootNodes.length).to.be.equal(1); + expect(rootNodes[0].label.displayValue).to.equal("label 1"); }); it("removes ruleset", async () => { @@ -104,7 +101,7 @@ describe("Rulesets", async () => { }); afterEach(async () => { - frontends.forEach((f) => f.dispose()); + frontends.forEach((f) => f[Symbol.dispose]()); }); it("handles multiple simultaneous requests from different frontends with different rulesets with same id", async () => { @@ -126,7 +123,7 @@ describe("Rulesets", async () => { expect(nodes[i][0].label.displayValue).to.eq(`label ${i + 1}`); }); - registeredRulesets.forEach((r) => r.dispose()); + registeredRulesets.forEach((r) => r[Symbol.dispose]()); }); }); @@ -138,23 +135,22 @@ describe("Rulesets", async () => { }); afterEach(async () => { - frontend.dispose(); + frontend[Symbol.dispose](); }); it("can use the same frontend-registered ruleset after backend is reset", async () => { const props = { imodel, rulesetOrId: RULESET_1.id }; - await using>(await frontend.rulesets().add(RULESET_1), async () => { - const rootNodes1 = await frontend.getNodesIterator(props).then(async (x) => collect(x.items)); - expect(rootNodes1.length).to.be.equal(1); - expect(rootNodes1[0].label.displayValue).to.be.equal("label 1"); + using _registered = await frontend.rulesets().add(RULESET_1); + const rootNodes1 = await frontend.getNodesIterator(props).then(async (x) => collect(x.items)); + expect(rootNodes1.length).to.be.equal(1); + expect(rootNodes1[0].label.displayValue).to.be.equal("label 1"); - resetBackend(); + resetBackend(); - const rootNodes2 = await frontend.getNodesIterator(props).then(async (x) => collect(x.items)); - expect(rootNodes2.length).to.be.equal(1); - expect(rootNodes2[0].label.displayValue).to.be.equal("label 1"); - expect(rootNodes2).to.deep.eq(rootNodes1); - }); + const rootNodes2 = await frontend.getNodesIterator(props).then(async (x) => collect(x.items)); + expect(rootNodes2.length).to.be.equal(1); + expect(rootNodes2[0].label.displayValue).to.be.equal("label 1"); + expect(rootNodes2).to.deep.eq(rootNodes1); }); }); }); diff --git a/full-stack-tests/presentation/src/frontend/content/ArrayProperties.test.ts b/full-stack-tests/presentation/src/frontend/content/ArrayProperties.test.ts index f57e0381ff38..c9462c32a47f 100644 --- a/full-stack-tests/presentation/src/frontend/content/ArrayProperties.test.ts +++ b/full-stack-tests/presentation/src/frontend/content/ArrayProperties.test.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { expect } from "chai"; -import { Guid, using } from "@itwin/core-bentley"; +import { Guid } from "@itwin/core-bentley"; import { IModelConnection } from "@itwin/core-frontend"; import { Content, ContentSpecificationTypes, DefaultContentDisplayTypes, InstanceKey, KeySet, Ruleset, RuleTypes } from "@itwin/presentation-common"; import { PresentationManager } from "@itwin/presentation-frontend"; @@ -61,19 +61,18 @@ describeContentTestSuite("Array properties", () => { async function getContent(imodel: IModelConnection, key: InstanceKey): Promise { const keys = new KeySet([key]); - return using(PresentationManager.create(), async (manager) => { - const descriptor = await manager.getContentDescriptor({ - imodel, - rulesetOrId: ruleset, - keys, - displayType: DefaultContentDisplayTypes.Grid, - }); - expect(descriptor).to.not.be.undefined; - const content = await manager - .getContentIterator({ imodel, rulesetOrId: ruleset, keys, descriptor: descriptor! }) - .then(async (x) => x && new Content(x.descriptor, await collect(x.items))); - expect(content).to.not.be.undefined; - return content!; + using manager = PresentationManager.create(); + const descriptor = await manager.getContentDescriptor({ + imodel, + rulesetOrId: ruleset, + keys, + displayType: DefaultContentDisplayTypes.Grid, }); + expect(descriptor).to.not.be.undefined; + const content = await manager + .getContentIterator({ imodel, rulesetOrId: ruleset, keys, descriptor: descriptor! }) + .then(async (x) => x && new Content(x.descriptor, await collect(x.items))); + expect(content).to.not.be.undefined; + return content!; } }); diff --git a/full-stack-tests/presentation/src/frontend/content/PropertyValueFormatting.test.ts b/full-stack-tests/presentation/src/frontend/content/PropertyValueFormatting.test.ts index 75d32daaeca2..df4ed8a77099 100644 --- a/full-stack-tests/presentation/src/frontend/content/PropertyValueFormatting.test.ts +++ b/full-stack-tests/presentation/src/frontend/content/PropertyValueFormatting.test.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { expect } from "chai"; -import { Guid, using } from "@itwin/core-bentley"; +import { Guid } from "@itwin/core-bentley"; import { IModelConnection } from "@itwin/core-frontend"; import { Content, ContentSpecificationTypes, DisplayValue, FormatsMap, InstanceKey, KeySet, Ruleset, RuleTypes } from "@itwin/presentation-common"; import { PresentationManager, PresentationManagerProps } from "@itwin/presentation-frontend"; @@ -305,20 +305,19 @@ describeContentTestSuite("Property value formatting", ({ getDefaultSuiteIModel } return schemas; }, }; - return using(PresentationManager.create(props), async (manager) => { - const descriptor = await manager.getContentDescriptor({ - imodel, - rulesetOrId: ruleset, - keys, - displayType: "Grid", - unitSystem, - }); - expect(descriptor).to.not.be.undefined; - const content = await manager - .getContentIterator({ imodel, rulesetOrId: ruleset, keys, descriptor: descriptor!, unitSystem }) - .then(async (x) => x && new Content(x.descriptor, await collect(x.items))); - expect(content).to.not.be.undefined; - return content!; + using manager = PresentationManager.create(props); + const descriptor = await manager.getContentDescriptor({ + imodel, + rulesetOrId: ruleset, + keys, + displayType: "Grid", + unitSystem, }); + expect(descriptor).to.not.be.undefined; + const content = await manager + .getContentIterator({ imodel, rulesetOrId: ruleset, keys, descriptor: descriptor!, unitSystem }) + .then(async (x) => x && new Content(x.descriptor, await collect(x.items))); + expect(content).to.not.be.undefined; + return content!; } }); diff --git a/full-stack-tests/presentation/src/frontend/hierarchies/GettingNodeInstancesCount.test.ts b/full-stack-tests/presentation/src/frontend/hierarchies/GettingNodeInstancesCount.test.ts index 0fc5c890460d..ef4382a6afdd 100644 --- a/full-stack-tests/presentation/src/frontend/hierarchies/GettingNodeInstancesCount.test.ts +++ b/full-stack-tests/presentation/src/frontend/hierarchies/GettingNodeInstancesCount.test.ts @@ -5,9 +5,8 @@ import { expect } from "chai"; import * as faker from "faker"; -import { using } from "@itwin/core-bentley"; import { IModelConnection } from "@itwin/core-frontend"; -import { ChildNodeSpecificationTypes, ECInstancesNodeKey, getInstancesCount, KeySet, RegisteredRuleset, Ruleset, RuleTypes } from "@itwin/presentation-common"; +import { ChildNodeSpecificationTypes, ECInstancesNodeKey, getInstancesCount, KeySet, Ruleset, RuleTypes } from "@itwin/presentation-common"; import { Presentation } from "@itwin/presentation-frontend"; import { initialize, terminate } from "../../IntegrationTests"; import { collect } from "../../Utils"; @@ -52,46 +51,45 @@ describe("Hierarchies", () => { }, ], }; - await using>(await Presentation.presentation.rulesets().add(ruleset), async () => { - const rootNodes = await Presentation.presentation.getNodesIterator({ imodel, rulesetOrId: ruleset.id }).then(async (x) => collect(x.items)); - expect(rootNodes).to.matchSnapshot(); - /* - The result should look like this (all grouping nodes): - Label Grouped Instances Count - Definition Model 1 - Dictionary Model 1 - Document List 2 - Group Model 1 - Link Model 1 - Physical Model 1 - Repository Model 1 + using _registered = await Presentation.presentation.rulesets().add(ruleset); + const rootNodes = await Presentation.presentation.getNodesIterator({ imodel, rulesetOrId: ruleset.id }).then(async (x) => collect(x.items)); + expect(rootNodes).to.matchSnapshot(); + /* + The result should look like this (all grouping nodes): + Label Grouped Instances Count + Definition Model 1 + Dictionary Model 1 + Document List 2 + Group Model 1 + Link Model 1 + Physical Model 1 + Repository Model 1 - we're going to count instances for: - - one of the definition model node keys - - dictionary model's instance key - - document list grouping node key - the result should be 1 + 1 + 2 = 4 - */ + we're going to count instances for: + - one of the definition model node keys + - dictionary model's instance key + - document list grouping node key + the result should be 1 + 1 + 2 = 4 + */ - const definitionModelNodes = await Presentation.presentation - .getNodesIterator({ - imodel, - rulesetOrId: ruleset.id, - parentKey: rootNodes[0].key, - }) - .then(async (x) => collect(x.items)); - const dictionaryModelNodes = await Presentation.presentation - .getNodesIterator({ - imodel, - rulesetOrId: ruleset.id, - parentKey: rootNodes[1].key, - }) - .then(async (x) => collect(x.items)); + const definitionModelNodes = await Presentation.presentation + .getNodesIterator({ + imodel, + rulesetOrId: ruleset.id, + parentKey: rootNodes[0].key, + }) + .then(async (x) => collect(x.items)); + const dictionaryModelNodes = await Presentation.presentation + .getNodesIterator({ + imodel, + rulesetOrId: ruleset.id, + parentKey: rootNodes[1].key, + }) + .then(async (x) => collect(x.items)); - const keys = new KeySet([definitionModelNodes[0].key, ...(dictionaryModelNodes[0].key as ECInstancesNodeKey).instanceKeys, rootNodes[2].key]); - const instancesCount = getInstancesCount(keys); - expect(instancesCount).to.eq(4); - }); + const keys = new KeySet([definitionModelNodes[0].key, ...(dictionaryModelNodes[0].key as ECInstancesNodeKey).instanceKeys, rootNodes[2].key]); + const instancesCount = getInstancesCount(keys); + expect(instancesCount).to.eq(4); }); }); }); diff --git a/full-stack-tests/presentation/src/frontend/hierarchies/Infrastructure.test.ts b/full-stack-tests/presentation/src/frontend/hierarchies/Infrastructure.test.ts index 25dd8519cd41..b0ab370d0a7d 100644 --- a/full-stack-tests/presentation/src/frontend/hierarchies/Infrastructure.test.ts +++ b/full-stack-tests/presentation/src/frontend/hierarchies/Infrastructure.test.ts @@ -38,7 +38,7 @@ describe("Hierarchies", () => { }); afterEach(async () => { - frontend.dispose(); + frontend[Symbol.dispose](); }); it("gets child nodes after backend is reset", async () => { diff --git a/full-stack-tests/rpc-interface/package.json b/full-stack-tests/rpc-interface/package.json index 670db2b8891d..5bd77a108d4a 100644 --- a/full-stack-tests/rpc-interface/package.json +++ b/full-stack-tests/rpc-interface/package.json @@ -64,7 +64,7 @@ "@types/chai": "4.3.1", "@types/chai-as-promised": "^7", "@types/mocha": "^10.0.6", - "@types/node": "~20.9.5", + "@types/node": "~20.17.0", "assert": "^2.0.0", "browserify-zlib": "^0.2.0", "buffer": "^6.0.3", @@ -82,4 +82,4 @@ "webpack": "^5.97.1", "webpack-cli": "^5.0.1" } -} +} \ No newline at end of file diff --git a/full-stack-tests/rpc/package.json b/full-stack-tests/rpc/package.json index 5fde423088de..beafd9310de0 100644 --- a/full-stack-tests/rpc/package.json +++ b/full-stack-tests/rpc/package.json @@ -38,7 +38,7 @@ "@types/chai": "4.3.1", "@types/express": "^4.17.20", "@types/mocha": "^10.0.6", - "@types/node": "~20.9.5", + "@types/node": "~20.17.0", "@types/semver": "7.3.10", "@types/spdy": "^3.4.4", "assert": "^2.0.0", diff --git a/full-stack-tests/rpc/src/frontend/RpcInterface.test.ts b/full-stack-tests/rpc/src/frontend/RpcInterface.test.ts index 5c7846eb40a3..1345d800fe30 100644 --- a/full-stack-tests/rpc/src/frontend/RpcInterface.test.ts +++ b/full-stack-tests/rpc/src/frontend/RpcInterface.test.ts @@ -608,10 +608,10 @@ describe("RpcInterface", () => { return RpcSerializedValue.create(this.parameters[0]); } - public override dispose(): void { + public override[Symbol.dispose](): void { ++completed; assert.equal(this.parameters[0], (this as any)._raw); - super.dispose(); + super[Symbol.dispose](); } } diff --git a/presentation/backend/package.json b/presentation/backend/package.json index 161332828998..dbc966a015e1 100644 --- a/presentation/backend/package.json +++ b/presentation/backend/package.json @@ -64,7 +64,7 @@ "@types/faker": "^4.1.0", "@types/lolex": "^2.1.2", "@types/mocha": "^10.0.6", - "@types/node": "~20.9.5", + "@types/node": "~20.17.0", "@types/object-hash": "^1.3.0", "@types/semver": "7.3.10", "@types/sinon": "^17.0.2", @@ -99,4 +99,4 @@ "nyc": { "extends": "./node_modules/@itwin/build-tools/.nycrc" } -} +} \ No newline at end of file diff --git a/presentation/backend/src/presentation-backend/NativePlatform.ts b/presentation/backend/src/presentation-backend/NativePlatform.ts index 8e32d79e2c80..f26f536a75f1 100644 --- a/presentation/backend/src/presentation-backend/NativePlatform.ts +++ b/presentation/backend/src/presentation-backend/NativePlatform.ts @@ -7,7 +7,7 @@ */ import { _nativeDb, IModelDb, IModelJsNative, IModelNative } from "@itwin/core-backend"; -import { assert, BeEvent, IDisposable } from "@itwin/core-bentley"; +import { assert, BeEvent } from "@itwin/core-bentley"; import { FormatProps } from "@itwin/core-quantity"; import { DiagnosticsScopeLogs, @@ -72,7 +72,7 @@ export interface NativePlatformResponse { } /** @internal */ -export interface NativePlatformDefinition extends IDisposable { +export interface NativePlatformDefinition extends Disposable { getImodelAddon(imodel: IModelDb): any; setupRulesetDirectories(directories: string[]): NativePlatformResponse; @@ -177,7 +177,7 @@ export const createDefaultNativePlatform = (props: DefaultNativePlatformProps): } return this.createSuccessResponse(response); } - public dispose() { + public [Symbol.dispose]() { this._nativeAddon.dispose(); } public async forceLoadSchemas(db: any): Promise> { diff --git a/presentation/backend/src/presentation-backend/Presentation.ts b/presentation/backend/src/presentation-backend/Presentation.ts index e8248bcdca31..c4ae2c442eb5 100644 --- a/presentation/backend/src/presentation-backend/Presentation.ts +++ b/presentation/backend/src/presentation-backend/Presentation.ts @@ -152,7 +152,7 @@ export class Presentation { */ public static terminate(): void { if (this._clientsStorage) { - this._clientsStorage.dispose(); + this._clientsStorage[Symbol.dispose](); this._clientsStorage = undefined; } if (this._disposeIModelOpenedListener) { @@ -165,7 +165,7 @@ export class Presentation { } RpcManager.unregisterImpl(PresentationRpcInterface); if (this._rpcImpl) { - this._rpcImpl.dispose(); + this._rpcImpl[Symbol.dispose](); this._rpcImpl = undefined; } if (this._disposeIpcHandler) { @@ -188,7 +188,7 @@ export class Presentation { } private static disposeClientManager(_id: string, storeItem: ClientStoreItem) { - storeItem.manager.dispose(); + storeItem.manager[Symbol.dispose](); } /** diff --git a/presentation/backend/src/presentation-backend/PresentationManager.ts b/presentation/backend/src/presentation-backend/PresentationManager.ts index 2450b9978587..65e006675dd7 100644 --- a/presentation/backend/src/presentation-backend/PresentationManager.ts +++ b/presentation/backend/src/presentation-backend/PresentationManager.ts @@ -448,8 +448,14 @@ export class PresentationManager { } /** Dispose the presentation manager. Must be called to clean up native resources. */ + public [Symbol.dispose]() { + this._detail[Symbol.dispose](); + } + + /** @deprecated in 5.0 Use [Symbol.dispose] instead. */ + // istanbul ignore next public dispose() { - this._detail.dispose(); + this[Symbol.dispose](); } /** @internal */ diff --git a/presentation/backend/src/presentation-backend/PresentationManagerDetail.ts b/presentation/backend/src/presentation-backend/PresentationManagerDetail.ts index d1b943dc6096..e21d4ac3ef3c 100644 --- a/presentation/backend/src/presentation-backend/PresentationManagerDetail.ts +++ b/presentation/backend/src/presentation-backend/PresentationManagerDetail.ts @@ -5,7 +5,7 @@ import * as hash from "object-hash"; import * as path from "path"; import { IModelDb, IModelJsNative, IpcHost } from "@itwin/core-backend"; -import { BeEvent, IDisposable, Logger } from "@itwin/core-bentley"; +import { BeEvent, Logger } from "@itwin/core-bentley"; import { UnitSystemKey } from "@itwin/core-quantity"; import { Content, @@ -62,7 +62,7 @@ import { RulesetManager, RulesetManagerImpl } from "./RulesetManager"; import { BackendDiagnosticsAttribute, BackendDiagnosticsOptions, combineDiagnosticsOptions, getElementKey, reportDiagnostics } from "./Utils"; /** @internal */ -export class PresentationManagerDetail implements IDisposable { +export class PresentationManagerDetail implements Disposable { private _disposed: boolean; private _nativePlatform: NativePlatformDefinition | undefined; private _onManagerUsed: (() => void) | undefined; @@ -93,12 +93,12 @@ export class PresentationManagerDetail implements IDisposable { this._diagnosticsOptions = params.diagnostics; } - public dispose(): void { + public [Symbol.dispose](): void { if (this._disposed) { return; } - this.getNativePlatform().dispose(); + this.getNativePlatform()[Symbol.dispose](); this._nativePlatform = undefined; this._disposed = true; diff --git a/presentation/backend/src/presentation-backend/PresentationRpcImpl.ts b/presentation/backend/src/presentation-backend/PresentationRpcImpl.ts index 848112dbe70e..a399a5dacbcb 100644 --- a/presentation/backend/src/presentation-backend/PresentationRpcImpl.ts +++ b/presentation/backend/src/presentation-backend/PresentationRpcImpl.ts @@ -7,7 +7,7 @@ */ import { IModelDb, RpcTrace } from "@itwin/core-backend"; -import { assert, BeEvent, Id64String, IDisposable, Logger } from "@itwin/core-bentley"; +import { assert, BeEvent, Id64String, Logger } from "@itwin/core-bentley"; import { IModelRpcProps } from "@itwin/core-common"; import { buildElementProperties, @@ -84,7 +84,7 @@ const DEFAULT_REQUEST_TIMEOUT = 5000; * * @internal */ -export class PresentationRpcImpl extends PresentationRpcInterface implements IDisposable { +export class PresentationRpcImpl extends PresentationRpcInterface implements Disposable { private _requestTimeout: number; private _pendingRequests: TemporaryStorage>; private _cancelEvents: Map void>>; @@ -112,8 +112,8 @@ export class PresentationRpcImpl extends PresentationRpcInterface implements IDi this._cancelEvents = new Map void>>(); } - public dispose() { - this._pendingRequests.dispose(); + public [Symbol.dispose]() { + this._pendingRequests[Symbol.dispose](); } public get requestTimeout() { diff --git a/presentation/backend/src/presentation-backend/TemporaryStorage.ts b/presentation/backend/src/presentation-backend/TemporaryStorage.ts index 3a8995f13904..9af5d9690601 100644 --- a/presentation/backend/src/presentation-backend/TemporaryStorage.ts +++ b/presentation/backend/src/presentation-backend/TemporaryStorage.ts @@ -6,7 +6,7 @@ * @module Core */ -import { assert, IDisposable } from "@itwin/core-bentley"; +import { assert } from "@itwin/core-bentley"; import { PresentationError, PresentationStatus } from "@itwin/presentation-common"; /** @@ -64,7 +64,7 @@ interface TemporaryValue { * * @internal */ -export class TemporaryStorage implements IDisposable { +export class TemporaryStorage implements Disposable { private _timer?: NodeJS.Timeout; protected _values: Map>; public readonly props: TemporaryStorageProps; @@ -84,7 +84,7 @@ export class TemporaryStorage implements IDisposable { * Destructor. Must be called to clean up the stored values * and other resources */ - public dispose() { + public [Symbol.dispose]() { if (this._timer) { clearInterval(this._timer); } diff --git a/presentation/backend/src/test/NativePlatform.test.ts b/presentation/backend/src/test/NativePlatform.test.ts index 1bd1424a2ae2..096721485078 100644 --- a/presentation/backend/src/test/NativePlatform.test.ts +++ b/presentation/backend/src/test/NativePlatform.test.ts @@ -44,13 +44,13 @@ describe("default NativePlatform", () => { }); afterEach(async () => { - nativePlatform.dispose(); + nativePlatform[Symbol.dispose](); await IModelHost.shutdown(); }); it("calls addon's dispose", async () => { addonMock.setup((x) => x.dispose()).verifiable(); - nativePlatform.dispose(); + nativePlatform[Symbol.dispose](); addonMock.verifyAll(); }); diff --git a/presentation/backend/src/test/PresentationManager.test.ts b/presentation/backend/src/test/PresentationManager.test.ts index b3aa28ac894a..9ee9e92d8d0d 100644 --- a/presentation/backend/src/test/PresentationManager.test.ts +++ b/presentation/backend/src/test/PresentationManager.test.ts @@ -9,7 +9,7 @@ import * as path from "path"; import * as sinon from "sinon"; import * as moq from "typemoq"; import { ECSqlStatement, ECSqlValue, IModelDb, IModelHost, IModelJsNative, IModelNative, IpcHost } from "@itwin/core-backend"; -import { DbResult, Id64, Id64String, using } from "@itwin/core-bentley"; +import { DbResult, Id64, Id64String } from "@itwin/core-bentley"; import { SchemaContext } from "@itwin/ecschema-metadata"; import { ArrayTypeDescription, @@ -154,18 +154,17 @@ describe("PresentationManager", () => { describe("uses default native library implementation if not overridden", () => { it("creates without props", () => { const constructorSpy = sinon.spy(IModelNative.platform, "ECPresentationManager"); - using(new PresentationManager(), (manager) => { - expect((manager.getNativePlatform() as any)._nativeAddon).instanceOf(IModelNative.platform.ECPresentationManager); - expect(constructorSpy).to.be.calledOnceWithExactly({ - id: "", - taskAllocationsMap: { [Number.MAX_SAFE_INTEGER]: 2 }, - updateCallback: noopUpdatesHandler, - cacheConfig: { mode: HierarchyCacheMode.Disk, directory: "" }, - contentCacheSize: undefined, - workerConnectionCacheSize: undefined, - useMmap: undefined, - defaultFormats: {}, - }); + using manager = new PresentationManager(); + expect((manager.getNativePlatform() as any)._nativeAddon).instanceOf(IModelNative.platform.ECPresentationManager); + expect(constructorSpy).to.be.calledOnceWithExactly({ + id: "", + taskAllocationsMap: { [Number.MAX_SAFE_INTEGER]: 2 }, + updateCallback: noopUpdatesHandler, + cacheConfig: { mode: HierarchyCacheMode.Disk, directory: "" }, + contentCacheSize: undefined, + workerConnectionCacheSize: undefined, + useMmap: undefined, + defaultFormats: {}, }); }); @@ -206,27 +205,27 @@ describe("PresentationManager", () => { const expectedCacheConfig = { mode: HierarchyCacheMode.Memory, }; - using(new PresentationManager(props), (manager) => { - expect((manager.getNativePlatform() as any)._nativeAddon).instanceOf(IModelNative.platform.ECPresentationManager); - expect(constructorSpy).to.be.calledOnceWithExactly({ - id: props.id, - taskAllocationsMap: { [Number.MAX_SAFE_INTEGER]: 999 }, - updateCallback: noopUpdatesHandler, - cacheConfig: expectedCacheConfig, - contentCacheSize: 999, - workerConnectionCacheSize: 123, - defaultFormats: { - length: [{ unitSystems: [NativePresentationUnitSystem.BritishImperial], serializedFormat: JSON.stringify(formatProps) }], - area: [{ unitSystems: [NativePresentationUnitSystem.UsCustomary], serializedFormat: JSON.stringify(formatProps) }], - }, - useMmap: 666, - }); + using manager = new PresentationManager(props); + expect((manager.getNativePlatform() as any)._nativeAddon).instanceOf(IModelNative.platform.ECPresentationManager); + expect(constructorSpy).to.be.calledOnceWithExactly({ + id: props.id, + taskAllocationsMap: { [Number.MAX_SAFE_INTEGER]: 999 }, + updateCallback: noopUpdatesHandler, + cacheConfig: expectedCacheConfig, + contentCacheSize: 999, + workerConnectionCacheSize: 123, + defaultFormats: { + length: [{ unitSystems: [NativePresentationUnitSystem.BritishImperial], serializedFormat: JSON.stringify(formatProps) }], + area: [{ unitSystems: [NativePresentationUnitSystem.UsCustomary], serializedFormat: JSON.stringify(formatProps) }], + }, + useMmap: 666, }); }); it("creates with disk cache config", () => { const constructorSpy = sinon.spy(IModelNative.platform, "ECPresentationManager"); - using(new PresentationManager({ caching: { hierarchies: { mode: HierarchyCacheMode.Disk } } }), (manager) => { + { + using manager = new PresentationManager({ caching: { hierarchies: { mode: HierarchyCacheMode.Disk } } }); expect((manager.getNativePlatform() as any)._nativeAddon).instanceOf(IModelNative.platform.ECPresentationManager); expect(constructorSpy).to.be.calledOnceWithExactly({ id: "", @@ -238,7 +237,7 @@ describe("PresentationManager", () => { useMmap: undefined, defaultFormats: {}, }); - }); + } constructorSpy.resetHistory(); const cacheConfig = { mode: HierarchyCacheMode.Disk, @@ -246,7 +245,8 @@ describe("PresentationManager", () => { memoryCacheSize: 123, }; const expectedConfig = { ...cacheConfig, directory: path.resolve(cacheConfig.directory) }; - using(new PresentationManager({ caching: { hierarchies: cacheConfig } }), (manager) => { + { + using manager = new PresentationManager({ caching: { hierarchies: cacheConfig } }); expect((manager.getNativePlatform() as any)._nativeAddon).instanceOf(IModelNative.platform.ECPresentationManager); expect(constructorSpy).to.be.calledOnceWithExactly({ id: "", @@ -258,12 +258,13 @@ describe("PresentationManager", () => { useMmap: undefined, defaultFormats: {}, }); - }); + } }); it("creates with hybrid cache config", () => { const constructorSpy = sinon.spy(IModelNative.platform, "ECPresentationManager"); - using(new PresentationManager({ caching: { hierarchies: { mode: HierarchyCacheMode.Hybrid } } }), (manager) => { + { + using manager = new PresentationManager({ caching: { hierarchies: { mode: HierarchyCacheMode.Hybrid } } }); expect((manager.getNativePlatform() as any)._nativeAddon).instanceOf(IModelNative.platform.ECPresentationManager); expect(constructorSpy).to.be.calledOnceWithExactly({ id: "", @@ -275,7 +276,7 @@ describe("PresentationManager", () => { useMmap: undefined, defaultFormats: {}, }); - }); + } constructorSpy.resetHistory(); const cacheConfig: HybridCacheConfig = { mode: HierarchyCacheMode.Hybrid, @@ -289,7 +290,8 @@ describe("PresentationManager", () => { ...cacheConfig, disk: { ...cacheConfig.disk, directory: path.resolve(cacheConfig.disk!.directory!) }, }; - using(new PresentationManager({ caching: { hierarchies: cacheConfig } }), (manager) => { + { + using manager = new PresentationManager({ caching: { hierarchies: cacheConfig } }); expect((manager.getNativePlatform() as any)._nativeAddon).instanceOf(IModelNative.platform.ECPresentationManager); expect(constructorSpy).to.be.calledOnceWithExactly({ id: "", @@ -301,23 +303,21 @@ describe("PresentationManager", () => { useMmap: undefined, defaultFormats: {}, }); - }); + } }); it("creates with ipc updates handler for IPC hosts", () => { sinon.stub(IpcHost, "isValid").get(() => true); const constructorSpy = sinon.spy(IModelNative.platform, "ECPresentationManager"); - using(new PresentationManager(), (_) => { - expect(constructorSpy.firstCall.firstArg.updateCallback).to.eq(ipcUpdatesHandler); - }); + using _ = new PresentationManager(); + expect(constructorSpy.firstCall.firstArg.updateCallback).to.eq(ipcUpdatesHandler); }); }); it("uses addon implementation supplied through props", () => { const nativePlatformMock = moq.Mock.ofType(); - using(new PresentationManager({ addon: nativePlatformMock.object }), (manager) => { - expect(manager.getNativePlatform()).eq(nativePlatformMock.object); - }); + using manager = new PresentationManager({ addon: nativePlatformMock.object }); + expect(manager.getNativePlatform()).eq(nativePlatformMock.object); }); describe("addon setup based on props", () => { @@ -330,9 +330,7 @@ describe("PresentationManager", () => { const dirs = ["test1", "test2", "test2"]; const addonDirs = ["test1", "test2"]; addon.setup((x) => x.setupRulesetDirectories(addonDirs)).verifiable(); - using(new PresentationManager({ addon: addon.object, rulesetDirectories: dirs }), (pm: PresentationManager) => { - pm; - }); + using _pm = new PresentationManager({ addon: addon.object, rulesetDirectories: dirs }); addon.verifyAll(); }); @@ -340,31 +338,30 @@ describe("PresentationManager", () => { const dirs = ["test1", "test2", "test2"]; const addonDirs = ["test1", "test2"]; addon.setup((x) => x.setupSupplementalRulesetDirectories(addonDirs)).verifiable(); - using(new PresentationManager({ addon: addon.object, supplementalRulesetDirectories: dirs }), (_pm: PresentationManager) => {}); + { + using _pm = new PresentationManager({ addon: addon.object, supplementalRulesetDirectories: dirs }); + } addon.verifyAll(); }); it("sets up active locale if supplied [deprecated]", () => { const locale = faker.random.locale(); - using(new PresentationManager({ addon: addon.object, defaultLocale: locale }), (manager) => { - expect(manager.activeLocale).to.eq(locale); // eslint-disable-line @typescript-eslint/no-deprecated - }); + using manager = new PresentationManager({ addon: addon.object, defaultLocale: locale }); + expect(manager.activeLocale).to.eq(locale); // eslint-disable-line @typescript-eslint/no-deprecated }); }); }); describe("props", () => { it("returns empty object if initialized without props", () => { - using(new PresentationManager(undefined), (newManager) => { - expect(newManager.props).to.deep.eq({}); - }); + using newManager = new PresentationManager(undefined); + expect(newManager.props).to.deep.eq({}); }); it("returns initialization props", () => { const props = {}; - using(new PresentationManager(props), (newManager) => { - expect(newManager.props).to.equal(props); - }); + using newManager = new PresentationManager(props); + expect(newManager.props).to.equal(props); }); }); @@ -378,70 +375,67 @@ describe("PresentationManager", () => { const imodelMock = moq.Mock.ofType(); const rulesetId = faker.random.word(); const unitSystem = "metric"; - await using(new PresentationManager({ addon: addonMock.object }), async (manager) => { - addonMock - .setup(async (x) => - x.handleRequest( - moq.It.isAny(), - moq.It.is((serializedRequest: string): boolean => { - const request = JSON.parse(serializedRequest); - return request.params.unitSystem === NativePresentationUnitSystem.Metric; - }), - undefined, - ), - ) - .returns(async () => ({ result: "null" })) - .verifiable(moq.Times.once()); - await manager.getContentDescriptor({ imodel: imodelMock.object, rulesetOrId: rulesetId, displayType: "", keys: new KeySet(), unitSystem }); - addonMock.verifyAll(); - }); + using manager = new PresentationManager({ addon: addonMock.object }); + addonMock + .setup(async (x) => + x.handleRequest( + moq.It.isAny(), + moq.It.is((serializedRequest: string): boolean => { + const request = JSON.parse(serializedRequest); + return request.params.unitSystem === NativePresentationUnitSystem.Metric; + }), + undefined, + ), + ) + .returns(async () => ({ result: "null" })) + .verifiable(moq.Times.once()); + await manager.getContentDescriptor({ imodel: imodelMock.object, rulesetOrId: rulesetId, displayType: "", keys: new KeySet(), unitSystem }); + addonMock.verifyAll(); }); it("uses manager's defaultUnitSystem when not specified in request options", async () => { const imodelMock = moq.Mock.ofType(); const rulesetId = faker.random.word(); const unitSystem = "usSurvey"; - await using(new PresentationManager({ addon: addonMock.object, defaultUnitSystem: unitSystem }), async (manager) => { - addonMock - .setup(async (x) => - x.handleRequest( - moq.It.isAny(), - moq.It.is((serializedRequest: string): boolean => { - const request = JSON.parse(serializedRequest); - return request.params.unitSystem === NativePresentationUnitSystem.UsSurvey; - }), - undefined, - ), - ) - .returns(async () => ({ result: "null" })) - .verifiable(moq.Times.once()); - await manager.getContentDescriptor({ imodel: imodelMock.object, rulesetOrId: rulesetId, displayType: "", keys: new KeySet() }); - addonMock.verifyAll(); - }); + using manager = new PresentationManager({ addon: addonMock.object, defaultUnitSystem: unitSystem }); + addonMock + .setup(async (x) => + x.handleRequest( + moq.It.isAny(), + moq.It.is((serializedRequest: string): boolean => { + const request = JSON.parse(serializedRequest); + return request.params.unitSystem === NativePresentationUnitSystem.UsSurvey; + }), + undefined, + ), + ) + .returns(async () => ({ result: "null" })) + .verifiable(moq.Times.once()); + await manager.getContentDescriptor({ imodel: imodelMock.object, rulesetOrId: rulesetId, displayType: "", keys: new KeySet() }); + addonMock.verifyAll(); }); it("ignores manager's defaultUnitSystem when unit system is specified in request options", async () => { const imodelMock = moq.Mock.ofType(); const rulesetId = faker.random.word(); const unitSystem = "usCustomary"; - await using(new PresentationManager({ addon: addonMock.object, defaultUnitSystem: "metric" }), async (manager) => { - expect(manager.activeUnitSystem).to.not.eq(unitSystem); - addonMock - .setup(async (x) => - x.handleRequest( - moq.It.isAny(), - moq.It.is((serializedRequest: string): boolean => { - const request = JSON.parse(serializedRequest); - return request.params.unitSystem === NativePresentationUnitSystem.UsCustomary; - }), - undefined, - ), - ) - .returns(async () => ({ result: "null" })) - .verifiable(moq.Times.once()); - await manager.getContentDescriptor({ imodel: imodelMock.object, rulesetOrId: rulesetId, unitSystem, displayType: "", keys: new KeySet() }); - addonMock.verifyAll(); - }); + using manager = new PresentationManager({ addon: addonMock.object, defaultUnitSystem: "metric" }); + expect(manager.activeUnitSystem).to.not.eq(unitSystem); + addonMock + .setup(async (x) => + x.handleRequest( + moq.It.isAny(), + moq.It.is((serializedRequest: string): boolean => { + const request = JSON.parse(serializedRequest); + return request.params.unitSystem === NativePresentationUnitSystem.UsCustomary; + }), + undefined, + ), + ) + .returns(async () => ({ result: "null" })) + .verifiable(moq.Times.once()); + await manager.getContentDescriptor({ imodel: imodelMock.object, rulesetOrId: rulesetId, unitSystem, displayType: "", keys: new KeySet() }); + addonMock.verifyAll(); }); }); @@ -487,16 +481,16 @@ describe("PresentationManager", () => { it("calls native platform dispose when manager is disposed", () => { const nativePlatformMock = moq.Mock.ofType(); const manager = new PresentationManager({ addon: nativePlatformMock.object }); - manager.dispose(); - manager.dispose(); + manager[Symbol.dispose](); + manager[Symbol.dispose](); // note: verify native platform's `dispose` called only once - nativePlatformMock.verify((x) => x.dispose(), moq.Times.once()); + nativePlatformMock.verify((x) => x[Symbol.dispose](), moq.Times.once()); }); it("throws when attempting to use native platform after disposal", () => { const nativePlatformMock = moq.Mock.ofType(); const manager = new PresentationManager({ addon: nativePlatformMock.object }); - manager.dispose(); + manager[Symbol.dispose](); expect(() => manager.getNativePlatform()).to.throw(PresentationError); }); }); @@ -510,7 +504,7 @@ describe("PresentationManager", () => { }); afterEach(() => { - manager.dispose(); + manager[Symbol.dispose](); }); it("returns correct id when input is a string", () => { @@ -774,7 +768,7 @@ describe("PresentationManager", () => { recreateManager(); }); afterEach(() => { - manager.dispose(); + manager[Symbol.dispose](); nativePlatformMock.verifyAll(); }); @@ -817,7 +811,7 @@ describe("PresentationManager", () => { }; function recreateManager(props?: Partial) { - manager && manager.dispose(); + manager && manager[Symbol.dispose](); manager = new PresentationManager({ addon: nativePlatformMock.object, ...props, @@ -3469,7 +3463,7 @@ describe("PresentationManager", () => { }); afterEach(() => { - manager.dispose(); + manager[Symbol.dispose](); }); it("requests scopes from `SelectionScopesHelper`", async () => { @@ -3493,7 +3487,7 @@ describe("PresentationManager", () => { }); afterEach(() => { - manager.dispose(); + manager[Symbol.dispose](); }); it("[deprecated] computes selection using `SelectionScopesHelper`", async () => { diff --git a/presentation/backend/src/test/PresentationRpcImpl.test.ts b/presentation/backend/src/test/PresentationRpcImpl.test.ts index b7c3f1a4d98f..eb9457ae47ec 100644 --- a/presentation/backend/src/test/PresentationRpcImpl.test.ts +++ b/presentation/backend/src/test/PresentationRpcImpl.test.ts @@ -7,7 +7,7 @@ import * as faker from "faker"; import * as sinon from "sinon"; import * as moq from "typemoq"; import { IModelDb, RpcTrace } from "@itwin/core-backend"; -import { BeEvent, Guid, using } from "@itwin/core-bentley"; +import { BeEvent, Guid } from "@itwin/core-bentley"; import { IModelNotFoundResponse, IModelRpcProps } from "@itwin/core-common"; import { ComputeSelectionRequestOptions, @@ -106,23 +106,20 @@ describe("PresentationRpcImpl", () => { Presentation.initialize({ addon: moq.Mock.ofType().object, }); - using(new PresentationRpcImpl(), (impl) => { - expect(impl.getManager()).is.instanceof(PresentationManager); - }); + using impl = new PresentationRpcImpl(); + expect(impl.getManager()).is.instanceof(PresentationManager); }); it("uses custom requestTimeout", () => { const randomRequestTimeout = faker.random.number({ min: 0, max: 90000 }); - using(new PresentationRpcImpl({ requestTimeout: randomRequestTimeout }), (impl) => { - expect(impl.requestTimeout).to.not.throw; - expect(impl.requestTimeout).to.equal(randomRequestTimeout); - }); + using impl = new PresentationRpcImpl({ requestTimeout: randomRequestTimeout }); + expect(impl.requestTimeout).to.not.throw; + expect(impl.requestTimeout).to.equal(randomRequestTimeout); }); it("doesn't cancel requests if request timeout is 0", () => { - using(new PresentationRpcImpl({ requestTimeout: 0 }), (impl) => { - expect(impl.pendingRequests.props.unusedValueLifetime).to.be.undefined; - }); + using impl = new PresentationRpcImpl({ requestTimeout: 0 }); + expect(impl.pendingRequests.props.unusedValueLifetime).to.be.undefined; }); it("returns all diagnostics when `PresentationManager` calls diagnostics handler multiple times", async () => { @@ -140,27 +137,26 @@ describe("PresentationRpcImpl", () => { configureForPromiseResult(imodelMock); sinon.stub(IModelDb, "findByKey").returns(imodelMock.object); - const impl = new PresentationRpcImpl({ requestTimeout: 10 }); - await using([{ dispose: () => Presentation.terminate() }, impl], async (_) => { - presentationManagerMock - .setup(async (x) => x.getNodesCount(moq.It.isAny())) - .callback((props: HierarchyRequestOptions & BackendDiagnosticsAttribute) => { - props.diagnostics!.handler({}); - props.diagnostics!.handler({ logs: [{ scope: "1" }] }); - props.diagnostics!.handler({ logs: [{ scope: "2" }] }); - }) - .returns(async () => 0); - const response = await impl.getNodesCount(imodelTokenMock.object, { rulesetOrId: "", diagnostics: { dev: true } }); - expect(response.diagnostics).to.deep.eq({ - logs: [ - { - scope: "1", - }, - { - scope: "2", - }, - ], - }); + using impl = new PresentationRpcImpl({ requestTimeout: 10 }); + using _ = { [Symbol.dispose]: () => Presentation.terminate() }; + presentationManagerMock + .setup(async (x) => x.getNodesCount(moq.It.isAny())) + .callback((props: HierarchyRequestOptions & BackendDiagnosticsAttribute) => { + props.diagnostics!.handler({}); + props.diagnostics!.handler({ logs: [{ scope: "1" }] }); + props.diagnostics!.handler({ logs: [{ scope: "2" }] }); + }) + .returns(async () => 0); + const response = await impl.getNodesCount(imodelTokenMock.object, { rulesetOrId: "", diagnostics: { dev: true } }); + expect(response.diagnostics).to.deep.eq({ + logs: [ + { + scope: "1", + }, + { + scope: "2", + }, + ], }); }); @@ -179,23 +175,22 @@ describe("PresentationRpcImpl", () => { configureForPromiseResult(imodelMock); sinon.stub(IModelDb, "findByKey").returns(imodelMock.object); - const impl = new PresentationRpcImpl({ requestTimeout: 10 }); - await using([{ dispose: () => Presentation.terminate() }, impl], async (_) => { - let callsCount = 0; - const result = new ResolvablePromise(); - presentationManagerMock - .setup(async (x) => x.getNodesCount(moq.It.isAny())) - .callback((props: HierarchyRequestOptions & BackendDiagnosticsAttribute) => { - props.diagnostics!.handler({ logs: [{ scope: `${callsCount++}` }] }); - }) - .returns(async () => result); - const response1 = await impl.getNodesCount(imodelTokenMock.object, { rulesetOrId: "", diagnostics: { dev: true } }); - expect(response1.statusCode).to.eq(PresentationStatus.BackendTimeout); - await result.resolve(123); - const response2 = await impl.getNodesCount(imodelTokenMock.object, { rulesetOrId: "", diagnostics: { dev: true } }); - expect(response2.statusCode).to.eq(PresentationStatus.Success); - expect(response2.diagnostics).to.deep.eq({ logs: [{ scope: "0" }] }); - }); + using impl = new PresentationRpcImpl({ requestTimeout: 10 }); + using _ = { [Symbol.dispose]: () => Presentation.terminate() }; + let callsCount = 0; + const result = new ResolvablePromise(); + presentationManagerMock + .setup(async (x) => x.getNodesCount(moq.It.isAny())) + .callback((props: HierarchyRequestOptions & BackendDiagnosticsAttribute) => { + props.diagnostics!.handler({ logs: [{ scope: `${callsCount++}` }] }); + }) + .returns(async () => result); + const response1 = await impl.getNodesCount(imodelTokenMock.object, { rulesetOrId: "", diagnostics: { dev: true } }); + expect(response1.statusCode).to.eq(PresentationStatus.BackendTimeout); + await result.resolve(123); + const response2 = await impl.getNodesCount(imodelTokenMock.object, { rulesetOrId: "", diagnostics: { dev: true } }); + expect(response2.statusCode).to.eq(PresentationStatus.Success); + expect(response2.diagnostics).to.deep.eq({ logs: [{ scope: "0" }] }); }); it("adds backend version to diagnostics response", async () => { @@ -213,13 +208,12 @@ describe("PresentationRpcImpl", () => { configureForPromiseResult(imodelMock); sinon.stub(IModelDb, "findByKey").returns(imodelMock.object); - const impl = new PresentationRpcImpl({ requestTimeout: 10 }); - await using([{ dispose: () => Presentation.terminate() }, impl], async (_) => { - presentationManagerMock.setup(async (x) => x.getNodesCount(moq.It.isAny())).returns(async () => 123); - const response = await impl.getNodesCount(imodelTokenMock.object, { rulesetOrId: "", diagnostics: { backendVersion: true } }); - expect(response.statusCode).to.eq(PresentationStatus.Success); - expect(response.diagnostics?.backendVersion).to.match(/\d+\.\d+\.\d+/i); - }); + using impl = new PresentationRpcImpl({ requestTimeout: 10 }); + using _ = { [Symbol.dispose]: () => Presentation.terminate() }; + presentationManagerMock.setup(async (x) => x.getNodesCount(moq.It.isAny())).returns(async () => 123); + const response = await impl.getNodesCount(imodelTokenMock.object, { rulesetOrId: "", diagnostics: { backendVersion: true } }); + expect(response.statusCode).to.eq(PresentationStatus.Success); + expect(response.diagnostics?.backendVersion).to.match(/\d+\.\d+\.\d+/i); }); describe("calls forwarding", () => { @@ -254,7 +248,7 @@ describe("PresentationRpcImpl", () => { }); afterEach(() => { - impl.dispose(); + impl[Symbol.dispose](); }); it("returns invalid argument status code when using invalid imodel token", async () => { @@ -297,7 +291,7 @@ describe("PresentationRpcImpl", () => { }); it("should return result if `requestTimeout` is set to 0", async () => { - impl.dispose(); + impl[Symbol.dispose](); impl = new PresentationRpcImpl({ requestTimeout: 0 }); const rpcOptions: HierarchyRpcRequestOptions = { ...defaultRpcParams, @@ -324,7 +318,7 @@ describe("PresentationRpcImpl", () => { }); it("should handle different iModel requests", async () => { - impl.dispose(); + impl[Symbol.dispose](); impl = new PresentationRpcImpl({ requestTimeout: 0 }); const rpcOptions: HierarchyRpcRequestOptions = { ...defaultRpcParams, @@ -482,7 +476,7 @@ describe("PresentationRpcImpl", () => { }); it("should return error result if manager throws and `requestTimeout` is set to 0", async () => { - impl.dispose(); + impl[Symbol.dispose](); impl = new PresentationRpcImpl({ requestTimeout: 0 }); const rpcOptions: HierarchyRpcRequestOptions = { ...defaultRpcParams, @@ -555,9 +549,7 @@ describe("PresentationRpcImpl", () => { describe("getPagedNodes", () => { it("calls manager for root nodes", async () => { - const getRootNodesResult: HierarchyLevelJSON = { - nodes: [createTestNode(), createTestNode(), createTestNode()].map(Node.toJSON), supportsFiltering: true, }; @@ -595,9 +587,7 @@ describe("PresentationRpcImpl", () => { }); it("calls manager for child nodes", async () => { - const getChildNodesResult: HierarchyLevelJSON = { - nodes: [createTestNode(), createTestNode(), createTestNode()].map(Node.toJSON), supportsFiltering: true, }; diff --git a/presentation/backend/src/test/RulesetManager.test.ts b/presentation/backend/src/test/RulesetManager.test.ts index e88efcd77e63..099c3c953b8c 100644 --- a/presentation/backend/src/test/RulesetManager.test.ts +++ b/presentation/backend/src/test/RulesetManager.test.ts @@ -137,7 +137,7 @@ describe("RulesetManager", () => { const result = manager.get(ruleset.id); expect(result).to.not.be.undefined; - result!.dispose(); + result![Symbol.dispose](); addonMock.verifyAll(); }); @@ -156,7 +156,7 @@ describe("RulesetManager", () => { const result = manager.add(ruleset); expect(result).to.not.be.undefined; - result.dispose(); + result[Symbol.dispose](); addonMock.verifyAll(); }); diff --git a/presentation/backend/src/test/TemporaryStorage.test.ts b/presentation/backend/src/test/TemporaryStorage.test.ts index 256a34c73c54..1287cb28a65f 100644 --- a/presentation/backend/src/test/TemporaryStorage.test.ts +++ b/presentation/backend/src/test/TemporaryStorage.test.ts @@ -5,7 +5,6 @@ import { expect } from "chai"; import * as fakeTimers from "@sinonjs/fake-timers"; import * as sinon from "sinon"; -import { using } from "@itwin/core-bentley"; import { PresentationError } from "@itwin/presentation-common"; import { FactoryBasedTemporaryStorage, FactoryBasedTemporaryStorageProps, TemporaryStorage } from "../presentation-backend/TemporaryStorage"; @@ -21,23 +20,20 @@ describe("TemporaryStorage", () => { describe("constructor", () => { it("doesn't set up timer callback when interval is not set", () => { const s = sinon.spy(clock, "setInterval"); - using(new TemporaryStorage({}), (_r) => { - expect(s).to.not.be.called; - }); + using _r = new TemporaryStorage({}); + expect(s).to.not.be.called; }); it("doesn't set up timer callback when interval is set to 0", () => { const s = sinon.spy(clock, "setInterval"); - using(new TemporaryStorage({ cleanupInterval: 0 }), (_r) => { - expect(s).to.not.be.called; - }); + using _r = new TemporaryStorage({ cleanupInterval: 0 }); + expect(s).to.not.be.called; }); it("sets up timer callback when interval is set to more than 0", () => { const s = sinon.spy(clock, "setInterval"); - using(new TemporaryStorage({ cleanupInterval: 1 }), (_r) => { - expect(s).to.be.calledOnce; - }); + using _r = new TemporaryStorage({ cleanupInterval: 1 }); + expect(s).to.be.calledOnce; }); }); @@ -45,7 +41,7 @@ describe("TemporaryStorage", () => { it("stops automatic cleanup when cleanup interval is set", () => { const s = sinon.spy(clock, "clearInterval"); const storage = new TemporaryStorage({ cleanupInterval: 1 }); - storage.dispose(); + storage[Symbol.dispose](); expect(s).to.be.calledOnce; }); @@ -58,7 +54,7 @@ describe("TemporaryStorage", () => { const values = ["a", "b", "c"]; values.forEach((v) => storage.addValue(v, v)); - storage.dispose(); + storage[Symbol.dispose](); expect(cleanupHandler.callCount).to.eq(values.length); expect(cleanupHandler.getCall(0)).to.be.calledWithExactly("a", "a", "dispose"); @@ -75,7 +71,7 @@ describe("TemporaryStorage", () => { const values = ["a", "b", "c"]; values.forEach((v) => storage.addValue(v, v)); - storage.dispose(); + storage[Symbol.dispose](); expect(spy).to.be.calledOnce; }); @@ -87,7 +83,7 @@ describe("TemporaryStorage", () => { storage = new TemporaryStorage({}); }); afterEach(() => { - storage.dispose(); + storage[Symbol.dispose](); }); it("adds a new value", () => { diff --git a/presentation/common/src/presentation-common/AsyncTasks.ts b/presentation/common/src/presentation-common/AsyncTasks.ts index 98784cf9db34..37b361f92fcf 100644 --- a/presentation/common/src/presentation-common/AsyncTasks.ts +++ b/presentation/common/src/presentation-common/AsyncTasks.ts @@ -6,14 +6,15 @@ * @module Core */ -import { Guid, GuidString, IDisposable } from "@itwin/core-bentley"; +import { Guid, GuidString } from "@itwin/core-bentley"; /** * A helper to track ongoing async tasks. Usage: * ``` - * await using(tracker.trackAsyncTask(), async (_r) => { + * { + * using _r = tracker.trackAsyncTask(); * await doSomethingAsync(); - * }); + * } * ``` * * Can be used with `waitForPendingAsyncs` in test helpers to wait for all @@ -26,11 +27,11 @@ export class AsyncTasksTracker { public get pendingAsyncs() { return this._asyncsInProgress; } - public trackAsyncTask(): IDisposable { + public trackAsyncTask(): Disposable { const id = Guid.createValue(); this._asyncsInProgress.add(id); return { - dispose: () => this._asyncsInProgress.delete(id), + [Symbol.dispose]: () => this._asyncsInProgress.delete(id), }; } } diff --git a/presentation/common/src/presentation-common/RegisteredRuleset.ts b/presentation/common/src/presentation-common/RegisteredRuleset.ts index 7fedd7552815..3025b5e867c3 100644 --- a/presentation/common/src/presentation-common/RegisteredRuleset.ts +++ b/presentation/common/src/presentation-common/RegisteredRuleset.ts @@ -6,7 +6,6 @@ * @module Core */ -import { IDisposable } from "@itwin/core-bentley"; import { Rule } from "./rules/Rule"; import { Ruleset, SupplementationInfo } from "./rules/Ruleset"; import { VariablesGroup } from "./rules/Variables"; @@ -15,7 +14,7 @@ import { VariablesGroup } from "./rules/Variables"; * A ruleset that is registered in a ruleset manager. * @public */ -export class RegisteredRuleset implements IDisposable, Ruleset { +export class RegisteredRuleset implements Disposable, Ruleset { private _ruleset: Ruleset; private _uniqueIdentifier: string; private _disposeFunc: (ruleset: RegisteredRuleset) => void; @@ -28,10 +27,16 @@ export class RegisteredRuleset implements IDisposable, Ruleset { } /** Dispose registered ruleset. */ - public dispose() { + public [Symbol.dispose]() { this._disposeFunc(this); } + /** @deprecated in 5.0 Use [Symbol.dispose] instead. */ + // istanbul ignore next + public dispose() { + this[Symbol.dispose](); + } + public get uniqueIdentifier() { return this._uniqueIdentifier; } diff --git a/presentation/common/src/presentation-common/content/ContentTraverser.ts b/presentation/common/src/presentation-common/content/ContentTraverser.ts index 4c626b7b8183..0973a7d93325 100644 --- a/presentation/common/src/presentation-common/content/ContentTraverser.ts +++ b/presentation/common/src/presentation-common/content/ContentTraverser.ts @@ -6,7 +6,7 @@ * @module Content */ -import { assert, IDisposable, using } from "@itwin/core-bentley"; +import { assert } from "@itwin/core-bentley"; import { CategoryDescription } from "./Category"; import { Content } from "./Content"; import { Descriptor } from "./Descriptor"; @@ -312,7 +312,7 @@ export function traverseContentItem(visitor: IContentVisitor, descriptor: Descri traverseContent(visitor, new Content(descriptor, [item])); } -class VisitedCategories implements IDisposable { +class VisitedCategories implements Disposable { private _visitedCategories: CategoryDescription[]; private _didVisitAllHierarchy: boolean; constructor( @@ -338,7 +338,7 @@ class VisitedCategories implements IDisposable { } } } - public dispose() { + public [Symbol.dispose]() { while (this._visitedCategories.pop()) { this._visitor.finishCategory(); } @@ -355,11 +355,10 @@ function traverseContentItemFields(visitor: IContentVisitor, fieldHierarchies: F try { fieldHierarchies.forEach((fieldHierarchy) => { - using(new VisitedCategories(visitor, fieldHierarchy.field.category), (res) => { - if (res.shouldContinue) { - traverseContentItemField(visitor, fieldHierarchy, item); - } - }); + using res = new VisitedCategories(visitor, fieldHierarchy.field.category) + if (res.shouldContinue) { + traverseContentItemField(visitor, fieldHierarchy, item); + } }); } finally { visitor.finishItem(); diff --git a/presentation/common/src/test/AsyncTasks.test.ts b/presentation/common/src/test/AsyncTasks.test.ts index 420394e451f8..f233de4e90f5 100644 --- a/presentation/common/src/test/AsyncTasks.test.ts +++ b/presentation/common/src/test/AsyncTasks.test.ts @@ -3,7 +3,6 @@ * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ import { expect } from "chai"; -import { using } from "@itwin/core-bentley"; import { AsyncTasksTracker } from "../presentation-common"; describe("AsyncTasksTracker", () => { @@ -12,19 +11,21 @@ describe("AsyncTasksTracker", () => { expect(tracker.pendingAsyncs.size).to.eq(0); const res = tracker.trackAsyncTask(); expect(tracker.pendingAsyncs.size).to.eq(1); - res.dispose(); + res[Symbol.dispose](); expect(tracker.pendingAsyncs.size).to.eq(0); }); it("supports nesting", () => { const tracker = new AsyncTasksTracker(); - using(tracker.trackAsyncTask(), (_r1) => { + { + using _r1 = tracker.trackAsyncTask(); expect(tracker.pendingAsyncs.size).to.eq(1); - using(tracker.trackAsyncTask(), (_r2) => { + { + using _r2 = tracker.trackAsyncTask(); expect(tracker.pendingAsyncs.size).to.eq(2); - }); + } expect(tracker.pendingAsyncs.size).to.eq(1); - }); + } expect(tracker.pendingAsyncs.size).to.eq(0); }); }); diff --git a/presentation/common/src/test/PresentationRpcInterface.test.ts b/presentation/common/src/test/PresentationRpcInterface.test.ts index 4a2ba34e2d55..ed611a5ec9f6 100644 --- a/presentation/common/src/test/PresentationRpcInterface.test.ts +++ b/presentation/common/src/test/PresentationRpcInterface.test.ts @@ -5,7 +5,7 @@ import { expect } from "chai"; import * as faker from "faker"; import * as sinon from "sinon"; -import { Id64String, using } from "@itwin/core-bentley"; +import { Id64String } from "@itwin/core-bentley"; import { IModelRpcProps, RpcOperation, RpcRegistry, RpcRequest, RpcSerializedValue } from "@itwin/core-common"; import { ContentDescriptorRpcRequestOptions, @@ -53,17 +53,17 @@ describe("PresentationRpcInterface", () => { RpcRegistry.instance.initializeRpcInterface(PresentationRpcInterface); const client = RpcRegistry.instance.getClientForInterface(PresentationRpcInterface); const operation = RpcOperation.lookup(PresentationRpcInterface, "getNodesCount"); - const disposableRequest = { - request: new TestRpcRequest(client, "getNodesCount", parameters), - dispose: () => { - // no way to properly destroy the created request... - (disposableRequest.request as any).dispose(); - }, - }; - using(disposableRequest, (dr) => { - const result = operation.policy.token(dr.request); + { + using disposableRequest = { + request: new TestRpcRequest(client, "getNodesCount", parameters), + [Symbol.dispose]: () => { + // no way to properly destroy the created request... + (disposableRequest.request as any)[Symbol.dispose](); + }, + }; + const result = operation.policy.token(disposableRequest.request); expect(result).to.eq(token); - }); + } RpcRegistry.instance.terminateRpcInterface(PresentationRpcInterface); }); diff --git a/presentation/common/src/test/RegisteredRuleset.test.ts b/presentation/common/src/test/RegisteredRuleset.test.ts index 9d0db4cdf40a..dbda72a5e22c 100644 --- a/presentation/common/src/test/RegisteredRuleset.test.ts +++ b/presentation/common/src/test/RegisteredRuleset.test.ts @@ -65,7 +65,7 @@ describe("RegisteredRuleset", () => { rules: [], }; const registered = new RegisteredRuleset(ruleset, uniqueIdentifier, (r: RegisteredRuleset) => managerMock.object(r)); - registered.dispose(); + registered[Symbol.dispose](); managerMock.verify((x) => x(registered), moq.Times.once()); }); }); diff --git a/presentation/frontend/src/presentation-frontend/ConnectivityInformationProvider.ts b/presentation/frontend/src/presentation-frontend/ConnectivityInformationProvider.ts index 9d99015dbb0c..b4a5a6b2c7e4 100644 --- a/presentation/frontend/src/presentation-frontend/ConnectivityInformationProvider.ts +++ b/presentation/frontend/src/presentation-frontend/ConnectivityInformationProvider.ts @@ -6,7 +6,7 @@ * @module Core */ -import { BeEvent, IDisposable } from "@itwin/core-bentley"; +import { BeEvent } from "@itwin/core-bentley"; import { InternetConnectivityStatus } from "@itwin/core-common"; import { NativeApp } from "@itwin/core-frontend"; @@ -22,7 +22,7 @@ export interface IConnectivityInformationProvider { * * @internal */ -export class ConnectivityInformationProvider implements IConnectivityInformationProvider, IDisposable { +export class ConnectivityInformationProvider implements IConnectivityInformationProvider, Disposable { private _currentStatus?: InternetConnectivityStatus; private _unsubscribeFromInternetConnectivityChangedEvent?: () => void; public readonly onInternetConnectivityChanged = new BeEvent<(args: { status: InternetConnectivityStatus }) => void>(); @@ -41,7 +41,7 @@ export class ConnectivityInformationProvider implements IConnectivityInformation } } - public dispose() { + public [Symbol.dispose]() { this._unsubscribeFromInternetConnectivityChangedEvent && this._unsubscribeFromInternetConnectivityChangedEvent(); } diff --git a/presentation/frontend/src/presentation-frontend/Presentation.ts b/presentation/frontend/src/presentation-frontend/Presentation.ts index a4525096f85f..c827bff11f47 100644 --- a/presentation/frontend/src/presentation-frontend/Presentation.ts +++ b/presentation/frontend/src/presentation-frontend/Presentation.ts @@ -118,17 +118,17 @@ export class Presentation { } if (presentationManager) { - presentationManager.dispose(); + presentationManager[Symbol.dispose](); } presentationManager = undefined; if (favoritePropertiesManager) { - favoritePropertiesManager.dispose(); + favoritePropertiesManager[Symbol.dispose](); } favoritePropertiesManager = undefined; if (selectionManager) { - selectionManager.dispose(); + selectionManager[Symbol.dispose](); } selectionManager = undefined; localization = undefined; @@ -153,7 +153,7 @@ export class Presentation { /** @internal */ public static setPresentationManager(value: PresentationManager) { if (presentationManager) { - presentationManager.dispose(); + presentationManager[Symbol.dispose](); } presentationManager = value; } @@ -185,7 +185,7 @@ export class Presentation { /** @internal */ public static setFavoritePropertiesManager(value: FavoritePropertiesManager) { if (favoritePropertiesManager) { - favoritePropertiesManager.dispose(); + favoritePropertiesManager[Symbol.dispose](); } favoritePropertiesManager = value; } diff --git a/presentation/frontend/src/presentation-frontend/PresentationManager.ts b/presentation/frontend/src/presentation-frontend/PresentationManager.ts index 9efff40e50fd..5d36aa5e7245 100644 --- a/presentation/frontend/src/presentation-frontend/PresentationManager.ts +++ b/presentation/frontend/src/presentation-frontend/PresentationManager.ts @@ -6,7 +6,7 @@ * @module Core */ -import { BeEvent, CompressedId64Set, IDisposable, OrderedId64Iterable } from "@itwin/core-bentley"; +import { BeEvent, CompressedId64Set, OrderedId64Iterable } from "@itwin/core-bentley"; import { IModelApp, IModelConnection, IpcApp } from "@itwin/core-frontend"; import { UnitSystemKey } from "@itwin/core-quantity"; import { SchemaContext } from "@itwin/ecschema-metadata"; @@ -195,7 +195,7 @@ export interface PresentationManagerProps { * * @public */ -export class PresentationManager implements IDisposable { +export class PresentationManager implements Disposable { private _requestsHandler: RpcRequestsHandler; private _rulesets: RulesetManager; private _localizationHelper: FrontendLocalizationHelper; @@ -259,13 +259,19 @@ export class PresentationManager implements IDisposable { this._localizationHelper.locale = locale; } - public dispose() { + public [Symbol.dispose]() { if (this._clearEventListener) { this._clearEventListener(); this._clearEventListener = undefined; } } + /** @deprecated in 5.0 Use [Symbol.dispose] instead. */ + // istanbul ignore next + public dispose() { + this[Symbol.dispose](); + } + private onUpdate = (_evt: Event, report: UpdateInfo) => { // eslint-disable-next-line @typescript-eslint/no-floating-promises this.handleUpdateAsync(report); diff --git a/presentation/frontend/src/presentation-frontend/favorite-properties/FavoritePropertiesManager.ts b/presentation/frontend/src/presentation-frontend/favorite-properties/FavoritePropertiesManager.ts index 329676c8bfa4..0819a9c34e58 100644 --- a/presentation/frontend/src/presentation-frontend/favorite-properties/FavoritePropertiesManager.ts +++ b/presentation/frontend/src/presentation-frontend/favorite-properties/FavoritePropertiesManager.ts @@ -6,7 +6,7 @@ * @module Core */ -import { BeEvent, IDisposable, isIDisposable } from "@itwin/core-bentley"; +import { BeEvent, isDisposable, isIDisposable } from "@itwin/core-bentley"; import { QueryRowFormat } from "@itwin/core-common"; import { IModelConnection } from "@itwin/core-frontend"; import { ClassId, Field, NestedContentField, PropertiesField } from "@itwin/presentation-common"; @@ -60,7 +60,7 @@ export interface FavoritePropertiesManagerProps { * * @public */ -export class FavoritePropertiesManager implements IDisposable { +export class FavoritePropertiesManager implements Disposable { /** * Used in tests to avoid collisions between multiple runs using the same storage * @internal @@ -89,13 +89,21 @@ export class FavoritePropertiesManager implements IDisposable { this._imodelInitializationPromises = new Map>(); } - public dispose() { + public [Symbol.dispose]() { // istanbul ignore else - if (isIDisposable(this._storage)) { + if (isDisposable(this._storage)) { + this._storage[Symbol.dispose](); + } else if (isIDisposable(this._storage)) { /* eslint-disable-line @typescript-eslint/no-deprecated */ this._storage.dispose(); } } + /** @deprecated in 5.0 Use [Symbol.dispose] instead. */ + // istanbul ignore next + public dispose() { + this[Symbol.dispose](); + } + /** * Initialize favorite properties for the provided IModelConnection. * @deprecated in 4.5. Initialization is performed automatically by all async methods and only needed for deprecated [[FavoritePropertiesManager.has]] and [[FavoritePropertiesManager.sortFields]]. diff --git a/presentation/frontend/src/presentation-frontend/favorite-properties/FavoritePropertiesStorage.ts b/presentation/frontend/src/presentation-frontend/favorite-properties/FavoritePropertiesStorage.ts index 906c5ca32f73..8bb579ed6f47 100644 --- a/presentation/frontend/src/presentation-frontend/favorite-properties/FavoritePropertiesStorage.ts +++ b/presentation/frontend/src/presentation-frontend/favorite-properties/FavoritePropertiesStorage.ts @@ -6,7 +6,7 @@ * @module Core */ -import { AccessToken, compareStrings, Dictionary, Guid, IDisposable, isIDisposable, OrderedComparator } from "@itwin/core-bentley"; +import { AccessToken, compareStrings, Dictionary, Guid, isDisposable, isIDisposable, OrderedComparator } from "@itwin/core-bentley"; import { InternetConnectivityStatus } from "@itwin/core-common"; import { IModelApp } from "@itwin/core-frontend"; import { PresentationError, PresentationStatus } from "@itwin/presentation-common"; @@ -187,7 +187,7 @@ export interface OfflineCachingFavoritePropertiesStorageProps { connectivityInfo?: IConnectivityInformationProvider; } /** @internal */ -export class OfflineCachingFavoritePropertiesStorage implements IFavoritePropertiesStorage, IDisposable { +export class OfflineCachingFavoritePropertiesStorage implements IFavoritePropertiesStorage, Disposable { private _connectivityInfo: IConnectivityInformationProvider; private _impl: IFavoritePropertiesStorage; private _propertiesOfflineCache = new DictionaryWithReservations>(iTwinAndIModelIdsKeyComparer); @@ -200,8 +200,11 @@ export class OfflineCachingFavoritePropertiesStorage implements IFavoritePropert this._connectivityInfo.onInternetConnectivityChanged.addListener(this.onConnectivityStatusChanged); } - public dispose() { - if (isIDisposable(this._connectivityInfo)) { + public [Symbol.dispose]() { + // istanbul ignore else + if (isDisposable(this._connectivityInfo)) { + this._connectivityInfo[Symbol.dispose](); + } else if (isIDisposable(this._connectivityInfo)) { /* eslint-disable-line @typescript-eslint/no-deprecated */ this._connectivityInfo.dispose(); } } diff --git a/presentation/frontend/src/presentation-frontend/selection/SelectionHandler.ts b/presentation/frontend/src/presentation-frontend/selection/SelectionHandler.ts index e7e29d62329d..899f7746fda3 100644 --- a/presentation/frontend/src/presentation-frontend/selection/SelectionHandler.ts +++ b/presentation/frontend/src/presentation-frontend/selection/SelectionHandler.ts @@ -6,7 +6,7 @@ * @module UnifiedSelection */ -import { DisposableList, IDisposable } from "@itwin/core-bentley"; +import { DisposableList } from "@itwin/core-bentley"; import { IModelConnection } from "@itwin/core-frontend"; import { Keys, KeySet } from "@itwin/presentation-common"; import { ISelectionProvider } from "./ISelectionProvider"; @@ -45,7 +45,7 @@ export interface SelectionHandlerProps { * * @public */ -export class SelectionHandler implements IDisposable { +export class SelectionHandler implements Disposable { private _inSelect: boolean; private _disposables: DisposableList; @@ -81,10 +81,16 @@ export class SelectionHandler implements IDisposable { * Destructor. Must be called before disposing this object to make sure it cleans * up correctly. */ - public dispose(): void { + public [Symbol.dispose](): void { this._disposables.dispose(); } + /** @deprecated in 5.0 Use [Symbol.dispose] instead. */ + // istanbul ignore next + public dispose() { + this[Symbol.dispose](); + } + /** * Called when the selection changes. Handles this callback by first checking whether * the event should be handled at all (using the `shouldHandle` method) and then calling `onSelect` diff --git a/presentation/frontend/src/presentation-frontend/selection/SelectionManager.ts b/presentation/frontend/src/presentation-frontend/selection/SelectionManager.ts index bfad8069567c..fed2982d0842 100644 --- a/presentation/frontend/src/presentation-frontend/selection/SelectionManager.ts +++ b/presentation/frontend/src/presentation-frontend/selection/SelectionManager.ts @@ -7,7 +7,7 @@ */ import { defer, EMPTY, mergeMap, Observable, of, Subject, Subscription, takeUntil, tap } from "rxjs"; -import { Id64, Id64Arg, Id64Array, IDisposable, using } from "@itwin/core-bentley"; +import { Id64, Id64Arg, Id64Array } from "@itwin/core-bentley"; import { IModelConnection, SelectableIds, SelectionSetEvent, SelectionSetEventType } from "@itwin/core-frontend"; import { AsyncTasksTracker, BaseNodeKey, InstanceKey, Key, Keys, KeySet, NodeKey, SelectionScope, SelectionScopeProps } from "@itwin/presentation-common"; import { @@ -44,7 +44,7 @@ export interface SelectionManagerProps { * The selection manager which stores the overall selection. * @public */ -export class SelectionManager implements ISelectionProvider { +export class SelectionManager implements ISelectionProvider, Disposable { private _selectionStorage: SelectionStorage; private _imodelToolSelectionSyncHandlers = new Map(); private _hiliteSetProviders = new Map(); @@ -84,11 +84,17 @@ export class SelectionManager implements ISelectionProvider { ); } - public dispose() { + public [Symbol.dispose]() { this._selectionEventsSubscription.unsubscribe(); this._listeners.forEach((dispose) => dispose()); } + /** @deprecated in 5.0. Use [Symbol.dispose] instead. */ + // istanbul ignore next + public dispose() { + this[Symbol.dispose](); + } + private onConnectionClose(imodel: IModelConnection): void { this._hiliteSetProviders.delete(imodel); this._knownIModels.delete(imodel.key); @@ -123,25 +129,27 @@ export class SelectionManager implements ISelectionProvider { this._imodelToolSelectionSyncHandlers.set(imodel, { ...registration, requestorsCount }); } else { this._imodelToolSelectionSyncHandlers.delete(imodel); - registration.handler.dispose(); + registration.handler[Symbol.dispose](); } } } } /** - * Temporarily suspends tool selection synchronization until the returned `IDisposable` + * Temporarily suspends tool selection synchronization until the returned `Disposable` * is disposed. */ - public suspendIModelToolSelectionSync(imodel: IModelConnection): IDisposable { + public suspendIModelToolSelectionSync(imodel: IModelConnection) { const registration = this._imodelToolSelectionSyncHandlers.get(imodel); if (!registration) { - return { dispose: () => {} }; + const noop = () => {}; + return { [Symbol.dispose]: noop, dispose: noop }; } const wasSuspended = registration.handler.isSuspended; registration.handler.isSuspended = true; - return { dispose: () => (registration.handler.isSuspended = wasSuspended) }; + const doDispose = () => (registration.handler.isSuspended = wasSuspended); + return { [Symbol.dispose]: doDispose, dispose: doDispose }; } /** Get the selection levels currently stored in this manager for the specified imodel */ @@ -400,7 +408,7 @@ export class SelectionManager implements ISelectionProvider { } /** @internal */ -export class ToolSelectionSyncHandler implements IDisposable { +export class ToolSelectionSyncHandler implements Disposable { private _selectionSourceName = "Tool"; private _logicalSelection: SelectionManager; private _imodel: IModelConnection; @@ -414,7 +422,7 @@ export class ToolSelectionSyncHandler implements IDisposable { this._imodelToolSelectionListenerDisposeFunc = imodel.selectionSet.onChanged.addListener(this.onToolSelectionChanged); } - public dispose() { + public [Symbol.dispose]() { this._imodelToolSelectionListenerDisposeFunc(); } @@ -463,22 +471,21 @@ export class ToolSelectionSyncHandler implements IDisposable { createSelectionScopeProps(this._logicalSelection.scopes.activeScope), ); - await using(this._asyncsTracker.trackAsyncTask(), async (_r) => { - switch (ev.type) { - case SelectionSetEventType.Add: - await changer.add(ids, selectionLevel); - break; - case SelectionSetEventType.Replace: - await changer.replace(ids, selectionLevel); - break; - case SelectionSetEventType.Remove: - await changer.remove(ids, selectionLevel); - break; - case SelectionSetEventType.Clear: - await changer.clear(selectionLevel); - break; - } - }); + using _r = this._asyncsTracker.trackAsyncTask(); + switch (ev.type) { + case SelectionSetEventType.Add: + await changer.add(ids, selectionLevel); + break; + case SelectionSetEventType.Replace: + await changer.replace(ids, selectionLevel); + break; + case SelectionSetEventType.Remove: + await changer.remove(ids, selectionLevel); + break; + case SelectionSetEventType.Clear: + await changer.clear(selectionLevel); + break; + } }; } diff --git a/presentation/frontend/src/test/ConnectivityInformationProvider.test.ts b/presentation/frontend/src/test/ConnectivityInformationProvider.test.ts index 4a6352b9ffe5..2d8301baac67 100644 --- a/presentation/frontend/src/test/ConnectivityInformationProvider.test.ts +++ b/presentation/frontend/src/test/ConnectivityInformationProvider.test.ts @@ -29,8 +29,6 @@ describe("ConnectivityInformationProvider", () => { NativeApp.onInternetConnectivityChanged.clear(); }); - afterEach(() => {}); - describe("constructor", () => { it("sets current status to the result of `NativeApp.checkInternetConnectivity` if not set already", async () => { const internetConnectivityResult = new ResolvablePromise(); @@ -60,7 +58,7 @@ describe("ConnectivityInformationProvider", () => { it("unsubscribes from `NativeApp.onInternetConnectivityChanged` event", () => { const provider = new ConnectivityInformationProvider(); expect(NativeApp.onInternetConnectivityChanged.numberOfListeners).to.eq(1); - provider.dispose(); + provider[Symbol.dispose](); expect(NativeApp.onInternetConnectivityChanged.numberOfListeners).to.eq(0); }); }); diff --git a/presentation/frontend/src/test/PresentationManager.test.ts b/presentation/frontend/src/test/PresentationManager.test.ts index 5201f9bf89e6..0893e3cb863f 100644 --- a/presentation/frontend/src/test/PresentationManager.test.ts +++ b/presentation/frontend/src/test/PresentationManager.test.ts @@ -6,7 +6,7 @@ import { expect } from "chai"; import * as faker from "faker"; import sinon from "sinon"; import * as moq from "typemoq"; -import { BeDuration, BeEvent, CompressedId64Set, using } from "@itwin/core-bentley"; +import { BeDuration, BeEvent, CompressedId64Set } from "@itwin/core-bentley"; import { IModelRpcProps, IpcListener, RemoveFunction } from "@itwin/core-common"; import { IModelApp, IModelConnection, IpcApp, QuantityFormatter } from "@itwin/core-frontend"; import { ITwinLocalization } from "@itwin/core-i18n"; @@ -113,12 +113,12 @@ describe("PresentationManager", () => { }); afterEach(() => { - manager.dispose(); + manager[Symbol.dispose](); Presentation.terminate(); }); function recreateManager(props?: Partial) { - manager && manager.dispose(); + manager && manager[Symbol.dispose](); manager = PresentationManager.create({ rpcRequestsHandler: rpcRequestsHandlerMock.object, ...props, @@ -214,7 +214,9 @@ describe("PresentationManager", () => { it("starts listening to update events", async () => { sinon.stub(IpcApp, "isValid").get(() => true); const addListenerSpy = sinon.stub(IpcApp, "addListener").returns(() => {}); - using(PresentationManager.create(), (_) => {}); + { + using _ = PresentationManager.create(); + } expect(addListenerSpy).to.be.calledOnceWith( PresentationIpcEvents.Update, sinon.match((arg) => typeof arg === "function"), @@ -415,7 +417,7 @@ describe("PresentationManager", () => { it("does not inject ruleset variables into request options in IpcApp", async () => { sinon.stub(IpcApp, "isValid").get(() => true); sinon.stub(IpcApp, "addListener"); - manager.dispose(); + manager[Symbol.dispose](); manager = PresentationManager.create({ rpcRequestsHandler: rpcRequestsHandlerMock.object, }); diff --git a/presentation/frontend/src/test/RulesetManager.test.ts b/presentation/frontend/src/test/RulesetManager.test.ts index ffaf79aa142d..248541523e49 100644 --- a/presentation/frontend/src/test/RulesetManager.test.ts +++ b/presentation/frontend/src/test/RulesetManager.test.ts @@ -118,7 +118,7 @@ describe("RulesetManager", () => { const result = await manager.add(ruleset); const eventSpy = sinon.spy(manager, "remove"); - result.dispose(); + result[Symbol.dispose](); expect(eventSpy).to.have.been.calledOnce; }); }); diff --git a/presentation/frontend/src/test/favorite-properties/FavoritePropertiesManager.test.ts b/presentation/frontend/src/test/favorite-properties/FavoritePropertiesManager.test.ts index afcbb4af923b..4cb98ae4a358 100644 --- a/presentation/frontend/src/test/favorite-properties/FavoritePropertiesManager.test.ts +++ b/presentation/frontend/src/test/favorite-properties/FavoritePropertiesManager.test.ts @@ -61,7 +61,7 @@ describe("FavoritePropertiesManager", () => { }); afterEach(() => { - manager.dispose(); + manager[Symbol.dispose](); storageMock.reset(); imodelMock.reset(); }); diff --git a/presentation/frontend/src/test/favorite-properties/FavoritePropertiesStorage.test.ts b/presentation/frontend/src/test/favorite-properties/FavoritePropertiesStorage.test.ts index e499a99dca3b..4255b0f95e6e 100644 --- a/presentation/frontend/src/test/favorite-properties/FavoritePropertiesStorage.test.ts +++ b/presentation/frontend/src/test/favorite-properties/FavoritePropertiesStorage.test.ts @@ -233,7 +233,7 @@ describe("OfflineCachingFavoritePropertiesStorage", () => { }); afterEach(() => { - storage.dispose(); + storage[Symbol.dispose](); sinon.restore(); }); @@ -579,11 +579,11 @@ describe("OfflineCachingFavoritePropertiesStorage", () => { const disposableConnectivityInfo = { onInternetConnectivityChanged: new BeEvent(), status: InternetConnectivityStatus.Offline, - dispose: sinon.spy(), + [Symbol.dispose]: sinon.spy(), }; storage = new OfflineCachingFavoritePropertiesStorage({ impl, connectivityInfo: disposableConnectivityInfo }); - storage.dispose(); - expect(disposableConnectivityInfo.dispose).to.be.calledOnce; + storage[Symbol.dispose](); + expect(disposableConnectivityInfo[Symbol.dispose]).to.be.calledOnce; }); const callInConnectivityContext = async (cb: () => Promise, connectivityStatus: InternetConnectivityStatus) => { diff --git a/presentation/frontend/src/test/selection/SelectionHandler.test.ts b/presentation/frontend/src/test/selection/SelectionHandler.test.ts index 3b0d32430561..3fc1da38793e 100644 --- a/presentation/frontend/src/test/selection/SelectionHandler.test.ts +++ b/presentation/frontend/src/test/selection/SelectionHandler.test.ts @@ -37,13 +37,13 @@ describe("SelectionHandler", () => { }); afterEach(() => { - selectionHandler.dispose(); + selectionHandler[Symbol.dispose](); }); describe("dispose", () => { it("stops listening for selection change events", () => { expect(selectionManagerMock.object.selectionChange.numberOfListeners).to.eq(1); - selectionHandler.dispose(); + selectionHandler[Symbol.dispose](); expect(selectionManagerMock.object.selectionChange.numberOfListeners).to.eq(0); }); }); diff --git a/presentation/frontend/src/test/selection/SelectionManager.test.ts b/presentation/frontend/src/test/selection/SelectionManager.test.ts index 8c455cf5cd3f..40b259e8d39a 100644 --- a/presentation/frontend/src/test/selection/SelectionManager.test.ts +++ b/presentation/frontend/src/test/selection/SelectionManager.test.ts @@ -5,7 +5,7 @@ import { expect } from "chai"; import * as sinon from "sinon"; -import { assert, BeDuration, Id64, Id64String, StopWatch, using } from "@itwin/core-bentley"; +import { assert, BeDuration, Id64, Id64String, StopWatch } from "@itwin/core-bentley"; import { BlankConnection, IModelApp, IModelConnection, SelectionSet, SelectionSetEventType } from "@itwin/core-frontend"; import { InstanceKey, KeySet, NodeKey, SelectionScope, StandardNodeTypes } from "@itwin/presentation-common"; import { @@ -503,7 +503,7 @@ describe("SelectionManager", () => { }); afterEach(() => { - syncer.dispose(); + syncer[Symbol.dispose](); }); describe("choosing scope", () => { @@ -787,9 +787,10 @@ describe("SelectionManager", () => { it("suspends selection synchronization", () => { const spy = sinon.spy(selectionManager, "clearSelection"); - using(selectionManager.suspendIModelToolSelectionSync(imodel), (_) => { + { + using _ = selectionManager.suspendIModelToolSelectionSync(imodel); ss.onChanged.raiseEvent({ type: SelectionSetEventType.Clear, set: ss, removed: [], removals: {} }); - }); + } expect(spy).to.not.be.called; ss.onChanged.raiseEvent({ type: SelectionSetEventType.Clear, set: ss, removed: [], removals: {} }); @@ -799,9 +800,10 @@ describe("SelectionManager", () => { it("does nothing if synchronization is not set up", () => { const spy = sinon.spy(selectionManager, "clearSelection"); selectionManager.setSyncWithIModelToolSelection(imodel, false); - using(selectionManager.suspendIModelToolSelectionSync(imodel), (_) => { + { + using _ = selectionManager.suspendIModelToolSelectionSync(imodel); ss.onChanged.raiseEvent({ type: SelectionSetEventType.Clear, set: ss, removed: [], removals: {} }); - }); + } expect(spy).to.not.be.called; }); @@ -812,9 +814,10 @@ describe("SelectionManager", () => { selectionManager.setSyncWithIModelToolSelection(imodel2); const spy = sinon.spy(selectionManager, "clearSelection"); - using(selectionManager.suspendIModelToolSelectionSync(imodel2), (_) => { + { + using _ = selectionManager.suspendIModelToolSelectionSync(imodel2); ss.onChanged.raiseEvent({ type: SelectionSetEventType.Clear, set: ss, removed: [], removals: {} }); - }); + } expect(spy).to.be.called; }); }); diff --git a/test-apps/display-performance-test-app/package.json b/test-apps/display-performance-test-app/package.json index ae0b985db260..76a31e51b4c6 100644 --- a/test-apps/display-performance-test-app/package.json +++ b/test-apps/display-performance-test-app/package.json @@ -65,7 +65,7 @@ "browserslist-to-esbuild": "^1.2.0", "@types/body-parser": "^1.17.0", "@types/express": "^4.17.20", - "@types/node": "~20.9.5", + "@types/node": "~20.17.0", "@typescript-eslint/parser": "~8.11.0", "child_process": "^1.0.2", "chrome-launcher": "^0.15.2", diff --git a/test-apps/display-performance-test-app/src/frontend/TestRunner.ts b/test-apps/display-performance-test-app/src/frontend/TestRunner.ts index b4812894a5cf..80cff437a84e 100644 --- a/test-apps/display-performance-test-app/src/frontend/TestRunner.ts +++ b/test-apps/display-performance-test-app/src/frontend/TestRunner.ts @@ -357,17 +357,15 @@ export class TestRunner { if (!test) return undefined; - const vp = test.viewport; + using vp = test.viewport; if (testConfig.testType === "image" || testConfig.testType === "both") { this.updateTestNames(test, undefined, true); const canvas = vp.readImageToCanvas(); await savePng(this.getImageName(test), canvas); - if (testConfig.testType === "image") { - vp.dispose(); + if (testConfig.testType === "image") return test; - } } // Throw away the first N frames until the timings become more consistent. @@ -379,7 +377,6 @@ export class TestRunner { this.updateTestNames(test); await (testConfig.testType === "readPixels" ? this.recordReadPixels(test) : this.recordRender(test)); - vp.dispose(); return test; } diff --git a/test-apps/display-test-app/package.json b/test-apps/display-test-app/package.json index e6d71cb7c6c6..e1e4a6b77391 100644 --- a/test-apps/display-test-app/package.json +++ b/test-apps/display-test-app/package.json @@ -82,7 +82,7 @@ "@types/express": "^4.17.20", "@types/express-ws": "^3.0.3", "@types/fs-extra": "^4.0.7", - "@types/node": "~20.9.5", + "@types/node": "~20.17.0", "@typescript-eslint/parser": "~8.11.0", "browserslist-to-esbuild": "^1.2.0", "child_process": "^1.0.2", @@ -122,4 +122,4 @@ "not dead", "not <0.2%" ] -} +} \ No newline at end of file diff --git a/test-apps/display-test-app/src/frontend/AnalysisStyleExample.ts b/test-apps/display-test-app/src/frontend/AnalysisStyleExample.ts index 277084bf84d1..40adc8d7ca81 100644 --- a/test-apps/display-test-app/src/frontend/AnalysisStyleExample.ts +++ b/test-apps/display-test-app/src/frontend/AnalysisStyleExample.ts @@ -196,7 +196,7 @@ class AnalysisDecorator { this.mesh = mesh; this._id = viewport.iModel.transientIds.getNext(); - const removeDisposalListener = viewport.onDisposed.addOnce(() => this.dispose()); + const removeDisposalListener = viewport.onDisposed.addOnce(() => this[Symbol.dispose]()); const removeAnalysisStyleListener = viewport.addOnAnalysisStyleChangedListener(() => { this._graphic?.disposeGraphic(); this._graphic = undefined; @@ -210,7 +210,7 @@ class AnalysisDecorator { IModelApp.viewManager.addDecorator(this); } - public dispose(): void { + public [Symbol.dispose](): void { if (!this._dispose) { assert(undefined === this._graphic); return; @@ -257,7 +257,7 @@ export async function openAnalysisStyleExample(viewer: Viewer): Promise { meshPicker.onchange = () => { const type = meshPicker.value as AnalysisMeshType; if (type !== decorator.mesh.type) { - decorator.dispose(); + decorator[Symbol.dispose](); decorator = new AnalysisDecorator(viewer.viewport, meshes[meshPicker.selectedIndex]); populateStylePicker(); } diff --git a/test-apps/display-test-app/src/frontend/Contours.ts b/test-apps/display-test-app/src/frontend/Contours.ts index 5b698eb977dc..78bfc943f6b3 100644 --- a/test-apps/display-test-app/src/frontend/Contours.ts +++ b/test-apps/display-test-app/src/frontend/Contours.ts @@ -3,7 +3,7 @@ * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ -import { assert, CompressedId64Set, dispose, IDisposable } from "@itwin/core-bentley"; +import { assert, CompressedId64Set, dispose } from "@itwin/core-bentley"; import { CheckBox, ColorInput, @@ -24,7 +24,7 @@ const indent1 = "5px"; const bottomSpace1 = "3px"; const bottomSpace2 = "5px"; -export class ContoursSettings implements IDisposable { +export class ContoursSettings implements Disposable { private readonly _vp: Viewport; private readonly _parent: HTMLElement; private readonly _element: HTMLElement; @@ -212,7 +212,7 @@ export class ContoursSettings implements IDisposable { this._checkbox.checkbox.checked = this._vp.view.displayStyle.settings.contours.displayContours; } - public dispose(): void { + public [Symbol.dispose](): void { this._parent.removeChild(this._element); } diff --git a/test-apps/display-test-app/src/frontend/DebugWindow.ts b/test-apps/display-test-app/src/frontend/DebugWindow.ts index a8511c245b3c..692ec383c079 100644 --- a/test-apps/display-test-app/src/frontend/DebugWindow.ts +++ b/test-apps/display-test-app/src/frontend/DebugWindow.ts @@ -36,8 +36,8 @@ export class DebugWindow extends Window { }); } - public dispose(): void { - this._panel.dispose(); + public [Symbol.dispose](): void { + this._panel[Symbol.dispose](); this.hide(); this._dispose(); } diff --git a/test-apps/display-test-app/src/frontend/DecorationGeometryExample.ts b/test-apps/display-test-app/src/frontend/DecorationGeometryExample.ts index 45fd1baec052..c2208fc3feb7 100644 --- a/test-apps/display-test-app/src/frontend/DecorationGeometryExample.ts +++ b/test-apps/display-test-app/src/frontend/DecorationGeometryExample.ts @@ -46,19 +46,19 @@ class GeometryDecorator { this._texture = texture; this._normalMap = normalMap; - this._dispose = viewport.iModel.onClose.addListener(() => this.dispose()); + this._dispose = viewport.iModel.onClose.addListener(() => this[Symbol.dispose]()); } - public dispose(): void { + public [Symbol.dispose](): void { if (this._dispose) { this._dispose(); this._dispose = undefined; } IModelApp.viewManager.dropDecorator(this); - this._texture?.dispose(); + this._texture?.[Symbol.dispose](); this._texture = undefined; - this._normalMap?.dispose(); + this._normalMap?.[Symbol.dispose](); this._normalMap = undefined; } diff --git a/test-apps/display-test-app/src/frontend/DynamicClassifierTool.ts b/test-apps/display-test-app/src/frontend/DynamicClassifierTool.ts index 8573cb19167f..85dab40944c2 100644 --- a/test-apps/display-test-app/src/frontend/DynamicClassifierTool.ts +++ b/test-apps/display-test-app/src/frontend/DynamicClassifierTool.ts @@ -145,7 +145,7 @@ export class DynamicClassifierTool extends PrimitiveTool { } this._spheres.add(ev.point); - this._graphic?.dispose(); + this._graphic?.[Symbol.dispose](); this._graphic = this._spheres.toGraphic(false); ev.viewport?.invalidateDecorations(); } @@ -282,7 +282,7 @@ export class DynamicClipMaskTool extends PrimitiveTool { } this._spheres.add(ev.point); - this._graphic?.dispose(); + this._graphic?.[Symbol.dispose](); this._graphic = this._spheres.toGraphic(false); ev.viewport?.invalidateDecorations(); diff --git a/test-apps/display-test-app/src/frontend/FeatureOverrides.ts b/test-apps/display-test-app/src/frontend/FeatureOverrides.ts index f3acec649198..b8931f3a86dc 100644 --- a/test-apps/display-test-app/src/frontend/FeatureOverrides.ts +++ b/test-apps/display-test-app/src/frontend/FeatureOverrides.ts @@ -3,7 +3,7 @@ * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ -import { dispose, Id64String, IDisposable } from "@itwin/core-bentley"; +import { dispose, Id64String } from "@itwin/core-bentley"; import { ComboBox, ComboBoxHandler, convertHexToRgb, createButton, createCheckBox, createColorInput, createComboBox, createNumericInput, } from "@itwin/frontend-devtools"; @@ -96,7 +96,7 @@ export class Provider implements FeatureOverrideProvider { } } -export class Settings implements IDisposable { +export class Settings implements Disposable { private _appearance = FeatureAppearance.defaults; private readonly _vp: Viewport; private readonly _parent: HTMLElement; @@ -167,7 +167,7 @@ export class Settings implements IDisposable { parent.appendChild(this._element); } - public dispose(): void { + public [Symbol.dispose](): void { this._parent.removeChild(this._element); } diff --git a/test-apps/display-test-app/src/frontend/ShadowMapDecoration.ts b/test-apps/display-test-app/src/frontend/ShadowMapDecoration.ts index 2c648fbfb2ff..e8a64dba1803 100644 --- a/test-apps/display-test-app/src/frontend/ShadowMapDecoration.ts +++ b/test-apps/display-test-app/src/frontend/ShadowMapDecoration.ts @@ -27,7 +27,7 @@ class ShadowMapDecoration { this._removeMe(); this._removeMe = undefined; for (const gf of this._graphics) { - gf.dispose(); + gf[Symbol.dispose](); if (gf instanceof RenderGraphicOwner) gf.disposeGraphic(); } diff --git a/test-apps/display-test-app/src/frontend/TerrainDrapeTool.ts b/test-apps/display-test-app/src/frontend/TerrainDrapeTool.ts index c780cf9eb65a..51f5ac81ce85 100644 --- a/test-apps/display-test-app/src/frontend/TerrainDrapeTool.ts +++ b/test-apps/display-test-app/src/frontend/TerrainDrapeTool.ts @@ -45,7 +45,7 @@ class TerrainDraper implements TileUser { IModelApp.tileAdmin.registerUser(this); } - public dispose(): void { + public [Symbol.dispose](): void { IModelApp.tileAdmin.forgetUser(this); } @@ -121,7 +121,7 @@ export class TerrainDrapeTool extends PrimitiveTool { } private disposeDraper(): void { - this._draper?.dispose(); + this._draper?.[Symbol.dispose](); this._draper = undefined; } diff --git a/test-apps/display-test-app/src/frontend/ToolBar.ts b/test-apps/display-test-app/src/frontend/ToolBar.ts index 8e5953edbc9f..04e0c4f3ebb5 100644 --- a/test-apps/display-test-app/src/frontend/ToolBar.ts +++ b/test-apps/display-test-app/src/frontend/ToolBar.ts @@ -54,7 +54,7 @@ export abstract class ToolBarDropDown { protected abstract _open(): void; protected abstract _close(): void; - public dispose(): void { } + public [Symbol.dispose](): void { } public abstract get isOpen(): boolean; @@ -107,9 +107,9 @@ class DropDown { this.element.appendChild(icon); } - public dispose(): void { + public [Symbol.dispose](): void { if (this.dropDown) { - this.dropDown.dispose(); + this.dropDown[Symbol.dispose](); this.dropDown = undefined; } } @@ -128,9 +128,9 @@ export class ToolBar { this.element = container; } - public dispose(): void { + public [Symbol.dispose](): void { for (const dd of this._dropDowns) - dd.dispose(); + dd[Symbol.dispose](); this._dropDowns.length = 0; this._currentlyOpen.clear(); diff --git a/test-apps/display-test-app/src/frontend/ViewAttributes.ts b/test-apps/display-test-app/src/frontend/ViewAttributes.ts index fd0a51262f12..a25a6b385e96 100644 --- a/test-apps/display-test-app/src/frontend/ViewAttributes.ts +++ b/test-apps/display-test-app/src/frontend/ViewAttributes.ts @@ -331,7 +331,7 @@ export class ViewAttributes { parent.appendChild(this._element); } - public dispose(): void { + public [Symbol.dispose](): void { this._removeMe(); this._parent.removeChild(this._element); } @@ -990,7 +990,7 @@ export class ViewAttributesPanel extends ToolBarDropDown { protected _close(): void { if (undefined !== this._attributes) { - this._attributes.dispose(); + this._attributes[Symbol.dispose](); this._attributes = undefined; } } diff --git a/test-apps/display-test-app/src/frontend/Viewer.ts b/test-apps/display-test-app/src/frontend/Viewer.ts index 6ec4203e7502..58b473388e72 100644 --- a/test-apps/display-test-app/src/frontend/Viewer.ts +++ b/test-apps/display-test-app/src/frontend/Viewer.ts @@ -565,9 +565,9 @@ export class Viewer extends Window { public get windowId(): string { return this.viewport.viewportId.toString(); } public override onClosing(): void { - this.toolBar.dispose(); + this.toolBar[Symbol.dispose](); if (this._debugWindow) { - this._debugWindow.dispose(); + this._debugWindow[Symbol.dispose](); this._debugWindow = undefined; } diff --git a/test-apps/export-gltf/package.json b/test-apps/export-gltf/package.json index e7f76b743653..485ba30894ef 100644 --- a/test-apps/export-gltf/package.json +++ b/test-apps/export-gltf/package.json @@ -23,10 +23,10 @@ "devDependencies": { "@itwin/build-tools": "workspace:*", "@itwin/eslint-plugin": "5.0.0-dev.1", - "@types/node": "~20.9.5", + "@types/node": "~20.17.0", "@types/yargs": "17.0.19", "eslint": "^9.13.0", "rimraf": "^3.0.2", "typescript": "~5.6.2" } -} +} \ No newline at end of file diff --git a/test-apps/imjs-importer/package.json b/test-apps/imjs-importer/package.json index 9b137ba26c7b..1eed2daecf04 100644 --- a/test-apps/imjs-importer/package.json +++ b/test-apps/imjs-importer/package.json @@ -36,7 +36,7 @@ "@itwin/eslint-plugin": "5.0.0-dev.1", "@types/chai": "4.3.1", "@types/mocha": "^10.0.6", - "@types/node": "~20.9.5", + "@types/node": "~20.17.0", "@types/yargs": "17.0.19", "chai": "^4.3.10", "eslint": "^9.13.0", @@ -44,4 +44,4 @@ "rimraf": "^3.0.2", "typescript": "~5.6.2" } -} +} \ No newline at end of file diff --git a/test-apps/imodel-from-geojson/package.json b/test-apps/imodel-from-geojson/package.json index b94ac3954cb6..eae224aeea8c 100644 --- a/test-apps/imodel-from-geojson/package.json +++ b/test-apps/imodel-from-geojson/package.json @@ -26,10 +26,10 @@ "@itwin/eslint-plugin": "5.0.0-dev.1", "@types/fs-extra": "^4.0.7", "@types/lodash": "^4.14.202", - "@types/node": "~20.9.5", + "@types/node": "~20.17.0", "@types/yargs": "17.0.19", "eslint": "^9.13.0", "rimraf": "^3.0.2", "typescript": "~5.6.2" } -} +} \ No newline at end of file diff --git a/test-apps/imodel-from-orbitgt/package.json b/test-apps/imodel-from-orbitgt/package.json index 247a1598e0ff..dab0d0dbd3ba 100644 --- a/test-apps/imodel-from-orbitgt/package.json +++ b/test-apps/imodel-from-orbitgt/package.json @@ -25,10 +25,10 @@ "@itwin/build-tools": "workspace:*", "@itwin/eslint-plugin": "5.0.0-dev.1", "@types/fs-extra": "^4.0.7", - "@types/node": "~20.9.5", + "@types/node": "~20.17.0", "@types/yargs": "17.0.19", "eslint": "^9.13.0", "rimraf": "^3.0.2", "typescript": "~5.6.2" } -} +} \ No newline at end of file diff --git a/test-apps/imodel-from-reality-model/package.json b/test-apps/imodel-from-reality-model/package.json index fae57d5dbc3e..726b8a96abc6 100644 --- a/test-apps/imodel-from-reality-model/package.json +++ b/test-apps/imodel-from-reality-model/package.json @@ -26,10 +26,10 @@ "@itwin/eslint-plugin": "5.0.0-dev.1", "@types/fs-extra": "^4.0.7", "@types/lodash": "^4.14.202", - "@types/node": "~20.9.5", + "@types/node": "~20.17.0", "@types/yargs": "17.0.19", "eslint": "^9.13.0", "rimraf": "^3.0.2", "typescript": "~5.6.2" } -} +} \ No newline at end of file diff --git a/tools/build/package.json b/tools/build/package.json index 4e1c8307a3bb..0447d065a642 100644 --- a/tools/build/package.json +++ b/tools/build/package.json @@ -47,7 +47,7 @@ }, "devDependencies": { "@itwin/eslint-plugin": "5.0.0-dev.1", - "@types/node": "~20.9.5", + "@types/node": "~20.17.0", "eslint": "^9.13.0" } -} +} \ No newline at end of file diff --git a/tools/build/tsconfig-base.json b/tools/build/tsconfig-base.json index f2a7721c5b6d..a37e96336c1a 100644 --- a/tools/build/tsconfig-base.json +++ b/tools/build/tsconfig-base.json @@ -23,6 +23,7 @@ "strict": true, "strictNullChecks": true, "stripInternal": false, - "target": "ES2021" + "target": "ES2021", + "lib": ["ES2021", "DOM", "DOM.Iterable", "ESNext.Disposable"] } } diff --git a/tools/certa/package.json b/tools/certa/package.json index aa960f5f6006..d6266ff6a040 100644 --- a/tools/certa/package.json +++ b/tools/certa/package.json @@ -50,7 +50,7 @@ "@types/express": "^4.17.20", "@types/lodash": "^4.14.202", "@types/mocha": "^10.0.6", - "@types/node": "~20.9.5", + "@types/node": "~20.17.0", "@types/yargs": "17.0.19", "electron": "^33.0.0", "eslint": "^9.13.0", @@ -66,4 +66,4 @@ "optional": true } } -} +} \ No newline at end of file diff --git a/tools/ecschema2ts/package.json b/tools/ecschema2ts/package.json index b5f2ae91e6e8..5b4283b06800 100644 --- a/tools/ecschema2ts/package.json +++ b/tools/ecschema2ts/package.json @@ -42,7 +42,7 @@ "@types/chai-string": "^1.4.1", "@types/fs-extra": "^4.0.7", "@types/mocha": "^10.0.6", - "@types/node": "~20.9.5", + "@types/node": "~20.17.0", "chai": "^4.3.10", "chai-string": "^1.5.0", "cpx2": "^3.0.0", @@ -69,4 +69,4 @@ "nyc": { "extends": "./node_modules/@itwin/build-tools/.nycrc" } -} +} \ No newline at end of file