@itwin/core-backend 5.15.0-dev.2 → 5.15.0-dev.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/CHANGELOG.md +30 -1
  2. package/lib/cjs/BriefcaseManager.d.ts +2 -2
  3. package/lib/cjs/BriefcaseManager.js.map +1 -1
  4. package/lib/cjs/ChangesetReaderTypes.d.ts +1 -1
  5. package/lib/cjs/ChangesetReaderTypes.js.map +1 -1
  6. package/lib/cjs/ECSqlRowExecutor.d.ts +3 -3
  7. package/lib/cjs/ECSqlRowExecutor.d.ts.map +1 -1
  8. package/lib/cjs/ECSqlRowExecutor.js +2 -2
  9. package/lib/cjs/ECSqlRowExecutor.js.map +1 -1
  10. package/lib/cjs/ECSqlStatement.d.ts +5 -0
  11. package/lib/cjs/ECSqlStatement.d.ts.map +1 -1
  12. package/lib/cjs/ECSqlStatement.js +15 -2
  13. package/lib/cjs/ECSqlStatement.js.map +1 -1
  14. package/lib/cjs/ECSqlSyncReader.d.ts.map +1 -1
  15. package/lib/cjs/ECSqlSyncReader.js +2 -2
  16. package/lib/cjs/ECSqlSyncReader.js.map +1 -1
  17. package/lib/esm/BriefcaseManager.d.ts +2 -2
  18. package/lib/esm/BriefcaseManager.js.map +1 -1
  19. package/lib/esm/ChangesetReaderTypes.d.ts +1 -1
  20. package/lib/esm/ChangesetReaderTypes.js.map +1 -1
  21. package/lib/esm/ECSqlRowExecutor.d.ts +3 -3
  22. package/lib/esm/ECSqlRowExecutor.d.ts.map +1 -1
  23. package/lib/esm/ECSqlRowExecutor.js +2 -2
  24. package/lib/esm/ECSqlRowExecutor.js.map +1 -1
  25. package/lib/esm/ECSqlStatement.d.ts +5 -0
  26. package/lib/esm/ECSqlStatement.d.ts.map +1 -1
  27. package/lib/esm/ECSqlStatement.js +15 -2
  28. package/lib/esm/ECSqlStatement.js.map +1 -1
  29. package/lib/esm/ECSqlSyncReader.d.ts.map +1 -1
  30. package/lib/esm/ECSqlSyncReader.js +3 -3
  31. package/lib/esm/ECSqlSyncReader.js.map +1 -1
  32. package/lib/esm/test/ecdb/ECSqlSyncReader.test.js +140 -0
  33. package/lib/esm/test/ecdb/ECSqlSyncReader.test.js.map +1 -1
  34. package/lib/esm/test/imodel/IModelGeolocation.test.js +3 -3
  35. package/lib/esm/test/imodel/IModelGeolocation.test.js.map +1 -1
  36. package/lib/esm/test/standalone/SessionApplyIndirect.test.d.ts +2 -0
  37. package/lib/esm/test/standalone/SessionApplyIndirect.test.d.ts.map +1 -0
  38. package/lib/esm/test/standalone/SessionApplyIndirect.test.js +211 -0
  39. package/lib/esm/test/standalone/SessionApplyIndirect.test.js.map +1 -0
  40. package/package.json +16 -16
@@ -5,7 +5,7 @@
5
5
  /** @packageDocumentation
6
6
  * @module ECSQL
7
7
  */
8
- import { DbValueFormat, ECSqlReaderBase, IModelError, PropertyMetaDataMap, QueryBinder, QueryOptionsBuilder, QueryRowFormat, } from "@itwin/core-common";
8
+ import { DbValueFormat, ECSqlReaderBase, IModelError, QueryBinder, QueryOptionsBuilder, QueryRowFormat, } from "@itwin/core-common";
9
9
  import { DbResult } from "@itwin/core-bentley";
10
10
  /**
11
11
  * Execute ECSQL statements synchronously and read the results one row at a time.
@@ -86,7 +86,7 @@ export class ECSqlSyncReader extends ECSqlReaderBase {
86
86
  }
87
87
  // Fetch metadata once on the first call.
88
88
  if (this._props.length === 0) {
89
- this._props = new PropertyMetaDataMap(this._executor.fetchMetadata(this._cachedRowOptions));
89
+ this._props = this._executor.fetchMetadata(this._cachedRowOptions);
90
90
  }
91
91
  return this.stepWithRetry();
92
92
  }
@@ -115,7 +115,7 @@ export class ECSqlSyncReader extends ECSqlReaderBase {
115
115
  */
116
116
  getMetaData() {
117
117
  if (this._props.length === 0) {
118
- this._props = new PropertyMetaDataMap(this._executor.fetchMetadata(this._cachedRowOptions));
118
+ this._props = this._executor.fetchMetadata(this._cachedRowOptions);
119
119
  }
120
120
  return this._props.properties;
121
121
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ECSqlSyncReader.js","sourceRoot":"","sources":["../../src/ECSqlSyncReader.ts"],"names":[],"mappings":"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","sourcesContent":["/*---------------------------------------------------------------------------------------------\r\n* Copyright (c) Bentley Systems, Incorporated. All rights reserved.\r\n* See LICENSE.md in the project root for license terms and full copyright notice.\r\n*--------------------------------------------------------------------------------------------*/\r\n/** @packageDocumentation\r\n * @module ECSQL\r\n */\r\nimport {\r\n DbValueFormat,\r\n ECSqlReaderBase,\r\n IModelError,\r\n PropertyMetaDataMap, QueryBinder, QueryOptions, QueryOptionsBuilder, QueryPropertyMetaData, QueryRowFormat, QueryRowProxy,\r\n} from \"@itwin/core-common\";\r\nimport { ECSqlRowExecutor } from \"./ECSqlRowExecutor\";\r\nimport { DbResult } from \"@itwin/core-bentley\";\r\n\r\n/** @beta */\r\nexport type SynchronousQueryOptions = Omit<QueryOptions, \"suppressLogErrors\" | \"includeMetaData\" | \"limit\" | \"priority\" | \"restartToken\" | \"delay\" | \"usePrimaryConn\" | \"quota\">;\r\n\r\n/**\r\n * Execute ECSQL statements synchronously and read the results one row at a time.\r\n *\r\n * This is the synchronous counterpart of [[ECSqlReader]] from `@itwin/core-common`.\r\n * It uses [[ECSqlRowExecutor]] directly — each call to [[step]] fetches exactly one row\r\n * with no internal caching, paging, or offset tracking.\r\n *\r\n * The query results are returned one row at a time. The format of the row is dictated by the\r\n * `rowFormat` specified in the `options` parameter of the constructed ECSqlSyncReader object.\r\n * Defaults to [[QueryRowFormat.UseECSqlPropertyIndexes]] when no `rowFormat` is defined.\r\n *\r\n * There are three primary ways to interact with and read the results:\r\n * - Iterate using ECSqlSyncReader as a synchronous iterator.\r\n * - Step manually using [[ECSqlSyncReader.step]].\r\n * - Capture all results at once using [[ECSqlSyncReader.toArray]].\r\n *\r\n * @note When iterating over the results, the current row is a [[QueryRowProxy]] object.\r\n * To get the row as a basic JavaScript object, call [[QueryRowProxy.toRow]] on it.\r\n * @beta\r\n */\r\nexport class ECSqlSyncReader extends ECSqlReaderBase implements IterableIterator<QueryRowProxy> {\r\n private _currentRow: any;\r\n private _options: SynchronousQueryOptions;\r\n /** Cached native row-adaptor options — built once and reused for every row. */\r\n private _cachedRowOptions: any;\r\n\r\n /**\r\n * @internal\r\n */\r\n public constructor(private _executor: ECSqlRowExecutor, public readonly query: string, param?: QueryBinder, options?: SynchronousQueryOptions) {\r\n const resolvedOptions = options ?? new QueryOptionsBuilder().getOptions();\r\n if (typeof resolvedOptions.rowFormat === \"undefined\")\r\n resolvedOptions.rowFormat = QueryRowFormat.UseECSqlPropertyIndexes;\r\n\r\n super(resolvedOptions.rowFormat);\r\n\r\n if (query.trim().length === 0) {\r\n throw new IModelError(DbResult.BE_SQLITE_ERROR, \"expecting non-empty ecsql statement\");\r\n }\r\n\r\n this._options = resolvedOptions;\r\n const serializedParam = param ? param.serialize() : new QueryBinder().serialize();\r\n\r\n // Prepare the statement and bind parameters once — avoids per-row ensureStatementReady overhead.\r\n const args = Object.keys(serializedParam).length > 0 ? serializedParam : undefined;\r\n this._executor.prepareAndBind(this.query, args);\r\n\r\n // Build and cache the native row-adaptor options — reused for every step call.\r\n // eslint-disable-next-line @typescript-eslint/no-deprecated\r\n const valueFormat = this._options.rowFormat === QueryRowFormat.UseJsPropertyNames ? DbValueFormat.JsNames : DbValueFormat.ECSqlNames;\r\n this._cachedRowOptions = {\r\n abbreviateBlobs: this._options.abbreviateBlobs ?? false,\r\n // eslint-disable-next-line @typescript-eslint/no-deprecated\r\n classIdsToClassNames: this._options.convertClassIdsToClassNames ?? false,\r\n useJsName: valueFormat === DbValueFormat.JsNames,\r\n doNotConvertClassIdsToClassNamesWhenAliased: true,\r\n };\r\n this._currentRow = undefined;\r\n }\r\n\r\n /**\r\n * @internal\r\n */\r\n protected override getRowInternal(): any[] {\r\n if (!this._currentRow)\r\n throw new IModelError(DbResult.BE_SQLITE_ERROR, \"no current row\");\r\n return this._currentRow as any[];\r\n }\r\n\r\n /**\r\n * Reads a single row from the executor. Returns the row data or `undefined` when the\r\n * result set is exhausted.\r\n *\r\n * Uses the fast-path `stepNextRow` method on the executor, which calls `stmt.step()`\r\n * and `stmt.toRow()` directly — no intermediate request/response objects are allocated per row.\r\n * @internal\r\n */\r\n private readRow(): any {\r\n if (this._done) {\r\n return undefined;\r\n }\r\n\r\n // Fetch metadata once on the first call.\r\n if (this._props.length === 0) {\r\n this._props = new PropertyMetaDataMap(this._executor.fetchMetadata(this._cachedRowOptions));\r\n }\r\n\r\n return this.stepWithRetry();\r\n }\r\n\r\n /**\r\n * Steps the cursor with retry logic for transient busy/interrupt conditions.\r\n * Returns the row data array, or `undefined` when the result set is exhausted.\r\n * @internal\r\n */\r\n private stepWithRetry(): any {\r\n const result = this._executor.stepNextRow(this._cachedRowOptions);\r\n if (result) {\r\n ECSqlSyncReader.replaceBase64WithUint8Array(result);\r\n return result;\r\n }\r\n return undefined; // undefined (done) → undefined\r\n }\r\n\r\n /**\r\n * Get the metadata for each column in the query result.\r\n *\r\n * If metadata has not been retrieved yet, fetches it directly from the prepared\r\n * statement. If a step has not yet occurred, executes a single step to ensure\r\n * the statement cursor is positioned, preserving the row for the next [[step]] call.\r\n *\r\n * @returns An array of [[QueryPropertyMetaData]].\r\n * @beta\r\n */\r\n public getMetaData(): QueryPropertyMetaData[] {\r\n if (this._props.length === 0) {\r\n this._props = new PropertyMetaDataMap(this._executor.fetchMetadata(this._cachedRowOptions));\r\n }\r\n return this._props.properties;\r\n }\r\n\r\n /**\r\n * Step to the next row of the query result.\r\n *\r\n * Each call executes exactly one step on the underlying statement — there is no\r\n * internal row caching or offset tracking.\r\n *\r\n * @returns `true` if a row can be read from `current`.<br/>\r\n * `false` if there are no more rows; i.e., all rows have been stepped through already.\r\n * @beta\r\n */\r\n public step(): boolean {\r\n if (this._done) {\r\n return false;\r\n }\r\n this._currentRow = this.readRow();\r\n if (!this._currentRow) {\r\n this._done = true;\r\n return false;\r\n }\r\n return true;\r\n }\r\n\r\n /**\r\n * Get all remaining rows from the query result.\r\n *\r\n * @returns An array of all remaining rows from the query result.\r\n * @beta\r\n */\r\n public toArray(): any[] {\r\n const rows = [];\r\n while (this.step()) {\r\n rows.push(this.formatCurrentRow());\r\n }\r\n return rows;\r\n }\r\n\r\n /**\r\n * Accessor for using ECSqlSyncReader as a synchronous iterator.\r\n *\r\n * @returns A synchronous iterator over the rows returned by the executed ECSQL query.\r\n * @beta\r\n */\r\n public [Symbol.iterator](): IterableIterator<QueryRowProxy> {\r\n return this;\r\n }\r\n\r\n /**\r\n * Calls step when called as an iterator.\r\n *\r\n * Returns the row alongside a `done` boolean to indicate if there are any more rows for an iterator to step to.\r\n *\r\n * @returns An object with the keys: `value` which contains the row and `done` which contains a boolean.\r\n * @beta\r\n */\r\n public next(): IteratorResult<QueryRowProxy, any> {\r\n if (this.step()) {\r\n return {\r\n done: false,\r\n value: this.current,\r\n };\r\n } else {\r\n return {\r\n done: true,\r\n value: this.current,\r\n };\r\n }\r\n }\r\n}\r\n"]}
1
+ {"version":3,"file":"ECSqlSyncReader.js","sourceRoot":"","sources":["../../src/ECSqlSyncReader.ts"],"names":[],"mappings":"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","sourcesContent":["/*---------------------------------------------------------------------------------------------\r\n* Copyright (c) Bentley Systems, Incorporated. All rights reserved.\r\n* See LICENSE.md in the project root for license terms and full copyright notice.\r\n*--------------------------------------------------------------------------------------------*/\r\n/** @packageDocumentation\r\n * @module ECSQL\r\n */\r\nimport {\r\n DbValueFormat,\r\n ECSqlReaderBase,\r\n IModelError,\r\n QueryBinder, QueryOptions, QueryOptionsBuilder, QueryPropertyMetaData, QueryRowFormat, QueryRowProxy,\r\n} from \"@itwin/core-common\";\r\nimport { ECSqlRowExecutor } from \"./ECSqlRowExecutor\";\r\nimport { DbResult } from \"@itwin/core-bentley\";\r\n\r\n/** @beta */\r\nexport type SynchronousQueryOptions = Omit<QueryOptions, \"suppressLogErrors\" | \"includeMetaData\" | \"limit\" | \"priority\" | \"restartToken\" | \"delay\" | \"usePrimaryConn\" | \"quota\">;\r\n\r\n/**\r\n * Execute ECSQL statements synchronously and read the results one row at a time.\r\n *\r\n * This is the synchronous counterpart of [[ECSqlReader]] from `@itwin/core-common`.\r\n * It uses [[ECSqlRowExecutor]] directly — each call to [[step]] fetches exactly one row\r\n * with no internal caching, paging, or offset tracking.\r\n *\r\n * The query results are returned one row at a time. The format of the row is dictated by the\r\n * `rowFormat` specified in the `options` parameter of the constructed ECSqlSyncReader object.\r\n * Defaults to [[QueryRowFormat.UseECSqlPropertyIndexes]] when no `rowFormat` is defined.\r\n *\r\n * There are three primary ways to interact with and read the results:\r\n * - Iterate using ECSqlSyncReader as a synchronous iterator.\r\n * - Step manually using [[ECSqlSyncReader.step]].\r\n * - Capture all results at once using [[ECSqlSyncReader.toArray]].\r\n *\r\n * @note When iterating over the results, the current row is a [[QueryRowProxy]] object.\r\n * To get the row as a basic JavaScript object, call [[QueryRowProxy.toRow]] on it.\r\n * @beta\r\n */\r\nexport class ECSqlSyncReader extends ECSqlReaderBase implements IterableIterator<QueryRowProxy> {\r\n private _currentRow: any;\r\n private _options: SynchronousQueryOptions;\r\n /** Cached native row-adaptor options — built once and reused for every row. */\r\n private _cachedRowOptions: any;\r\n\r\n /**\r\n * @internal\r\n */\r\n public constructor(private _executor: ECSqlRowExecutor, public readonly query: string, param?: QueryBinder, options?: SynchronousQueryOptions) {\r\n const resolvedOptions = options ?? new QueryOptionsBuilder().getOptions();\r\n if (typeof resolvedOptions.rowFormat === \"undefined\")\r\n resolvedOptions.rowFormat = QueryRowFormat.UseECSqlPropertyIndexes;\r\n\r\n super(resolvedOptions.rowFormat);\r\n\r\n if (query.trim().length === 0) {\r\n throw new IModelError(DbResult.BE_SQLITE_ERROR, \"expecting non-empty ecsql statement\");\r\n }\r\n\r\n this._options = resolvedOptions;\r\n const serializedParam = param ? param.serialize() : new QueryBinder().serialize();\r\n\r\n // Prepare the statement and bind parameters once — avoids per-row ensureStatementReady overhead.\r\n const args = Object.keys(serializedParam).length > 0 ? serializedParam : undefined;\r\n this._executor.prepareAndBind(this.query, args);\r\n\r\n // Build and cache the native row-adaptor options — reused for every step call.\r\n // eslint-disable-next-line @typescript-eslint/no-deprecated\r\n const valueFormat = this._options.rowFormat === QueryRowFormat.UseJsPropertyNames ? DbValueFormat.JsNames : DbValueFormat.ECSqlNames;\r\n this._cachedRowOptions = {\r\n abbreviateBlobs: this._options.abbreviateBlobs ?? false,\r\n // eslint-disable-next-line @typescript-eslint/no-deprecated\r\n classIdsToClassNames: this._options.convertClassIdsToClassNames ?? false,\r\n useJsName: valueFormat === DbValueFormat.JsNames,\r\n doNotConvertClassIdsToClassNamesWhenAliased: true,\r\n };\r\n this._currentRow = undefined;\r\n }\r\n\r\n /**\r\n * @internal\r\n */\r\n protected override getRowInternal(): any[] {\r\n if (!this._currentRow)\r\n throw new IModelError(DbResult.BE_SQLITE_ERROR, \"no current row\");\r\n return this._currentRow as any[];\r\n }\r\n\r\n /**\r\n * Reads a single row from the executor. Returns the row data or `undefined` when the\r\n * result set is exhausted.\r\n *\r\n * Uses the fast-path `stepNextRow` method on the executor, which calls `stmt.step()`\r\n * and `stmt.toRow()` directly — no intermediate request/response objects are allocated per row.\r\n * @internal\r\n */\r\n private readRow(): any {\r\n if (this._done) {\r\n return undefined;\r\n }\r\n\r\n // Fetch metadata once on the first call.\r\n if (this._props.length === 0) {\r\n this._props = this._executor.fetchMetadata(this._cachedRowOptions);\r\n }\r\n\r\n return this.stepWithRetry();\r\n }\r\n\r\n /**\r\n * Steps the cursor with retry logic for transient busy/interrupt conditions.\r\n * Returns the row data array, or `undefined` when the result set is exhausted.\r\n * @internal\r\n */\r\n private stepWithRetry(): any {\r\n const result = this._executor.stepNextRow(this._cachedRowOptions);\r\n if (result) {\r\n ECSqlSyncReader.replaceBase64WithUint8Array(result);\r\n return result;\r\n }\r\n return undefined; // undefined (done) → undefined\r\n }\r\n\r\n /**\r\n * Get the metadata for each column in the query result.\r\n *\r\n * If metadata has not been retrieved yet, fetches it directly from the prepared\r\n * statement. If a step has not yet occurred, executes a single step to ensure\r\n * the statement cursor is positioned, preserving the row for the next [[step]] call.\r\n *\r\n * @returns An array of [[QueryPropertyMetaData]].\r\n * @beta\r\n */\r\n public getMetaData(): QueryPropertyMetaData[] {\r\n if (this._props.length === 0) {\r\n this._props = this._executor.fetchMetadata(this._cachedRowOptions);\r\n }\r\n return this._props.properties;\r\n }\r\n\r\n /**\r\n * Step to the next row of the query result.\r\n *\r\n * Each call executes exactly one step on the underlying statement — there is no\r\n * internal row caching or offset tracking.\r\n *\r\n * @returns `true` if a row can be read from `current`.<br/>\r\n * `false` if there are no more rows; i.e., all rows have been stepped through already.\r\n * @beta\r\n */\r\n public step(): boolean {\r\n if (this._done) {\r\n return false;\r\n }\r\n this._currentRow = this.readRow();\r\n if (!this._currentRow) {\r\n this._done = true;\r\n return false;\r\n }\r\n return true;\r\n }\r\n\r\n /**\r\n * Get all remaining rows from the query result.\r\n *\r\n * @returns An array of all remaining rows from the query result.\r\n * @beta\r\n */\r\n public toArray(): any[] {\r\n const rows = [];\r\n while (this.step()) {\r\n rows.push(this.formatCurrentRow());\r\n }\r\n return rows;\r\n }\r\n\r\n /**\r\n * Accessor for using ECSqlSyncReader as a synchronous iterator.\r\n *\r\n * @returns A synchronous iterator over the rows returned by the executed ECSQL query.\r\n * @beta\r\n */\r\n public [Symbol.iterator](): IterableIterator<QueryRowProxy> {\r\n return this;\r\n }\r\n\r\n /**\r\n * Calls step when called as an iterator.\r\n *\r\n * Returns the row alongside a `done` boolean to indicate if there are any more rows for an iterator to step to.\r\n *\r\n * @returns An object with the keys: `value` which contains the row and `done` which contains a boolean.\r\n * @beta\r\n */\r\n public next(): IteratorResult<QueryRowProxy, any> {\r\n if (this.step()) {\r\n return {\r\n done: false,\r\n value: this.current,\r\n };\r\n } else {\r\n return {\r\n done: true,\r\n value: this.current,\r\n };\r\n }\r\n }\r\n}\r\n"]}
@@ -56,6 +56,7 @@ var __disposeResources = (this && this.__disposeResources) || (function (Suppres
56
56
  });
57
57
  import { assert, expect } from "chai";
58
58
  import * as sinon from "sinon";
59
+ import * as path from "node:path";
59
60
  import { QueryBinder, QueryOptionsBuilder, QueryRowFormat } from "@itwin/core-common";
60
61
  import { SnapshotDb } from "../../IModelDb";
61
62
  import { IModelTestUtils } from "../IModelTestUtils";
@@ -63,6 +64,8 @@ import { Id64 } from "@itwin/core-bentley";
63
64
  import { ECSqlStatement } from "../../ECSqlStatement";
64
65
  import { ECDbTestHelper } from "./ECDbTestHelper";
65
66
  import { KnownTestLocations } from "../KnownTestLocations";
67
+ import { IModelNative } from "../../internal/NativePlatform";
68
+ import { IModelJsFs } from "../../IModelJsFs";
66
69
  describe("WithQueryReaderTests", () => {
67
70
  let iModel;
68
71
  before(async () => {
@@ -257,5 +260,142 @@ describe("WithQueryReaderTests", () => {
257
260
  }
258
261
  });
259
262
  });
263
+ describe("metadata caching", () => {
264
+ // Column metadata depends only on the prepared statement and the row-adaptor options, so it is cached
265
+ // on the cached ECSqlStatement instead of being fetched from native code on every withQueryReader call.
266
+ const sql = "SELECT ECInstanceId, ECClassId, CodeValue, GeometryStream FROM bis.GeometricElement3d WHERE ECInstanceId=?";
267
+ let elementId;
268
+ before(() => {
269
+ elementId = iModel.withQueryReader("SELECT ECInstanceId FROM bis.GeometricElement3d WHERE GeometryStream IS NOT NULL LIMIT 1", (reader) => {
270
+ assert.isTrue(reader.step());
271
+ return reader.current[0];
272
+ });
273
+ });
274
+ afterEach(() => sinon.restore());
275
+ function readMetadata(options) {
276
+ return iModel.withQueryReader(sql, (reader) => {
277
+ assert.isTrue(reader.step());
278
+ return { meta: reader.getMetaData(), row: reader.current.toRow() };
279
+ }, new QueryBinder().bindId(1, elementId), options);
280
+ }
281
+ it("returns metadata matching the row options when the same statement is reused with different options", () => {
282
+ const optionSets = [
283
+ // eslint-disable-next-line @typescript-eslint/no-deprecated
284
+ { rowFormat: QueryRowFormat.UseJsPropertyNames },
285
+ { rowFormat: QueryRowFormat.UseECSqlPropertyNames },
286
+ // eslint-disable-next-line @typescript-eslint/no-deprecated
287
+ { rowFormat: QueryRowFormat.UseJsPropertyNames, abbreviateBlobs: true },
288
+ { rowFormat: QueryRowFormat.UseECSqlPropertyNames, abbreviateBlobs: true },
289
+ { rowFormat: QueryRowFormat.UseECSqlPropertyNames, convertClassIdsToClassNames: true },
290
+ ];
291
+ // Expected metadata comes from a freshly prepared statement for each option set.
292
+ const expected = optionSets.map((options) => {
293
+ iModel.clearCaches();
294
+ return readMetadata({ ...options }).meta;
295
+ });
296
+ expect(expected[0].map((p) => p.jsonName)).to.deep.equal(["id", "className", "codeValue", "geometryStream"]);
297
+ expect(expected[1].map((p) => p.name)).to.deep.equal(["ECInstanceId", "ECClassId", "CodeValue", "GeometryStream"]);
298
+ iModel.clearCaches();
299
+ for (let pass = 0; pass < 2; pass++) {
300
+ optionSets.forEach((options, i) => {
301
+ const { meta, row } = readMetadata({ ...options });
302
+ expect(meta).to.deep.equal(expected[i]);
303
+ const geometryStream = row[options.rowFormat === QueryRowFormat.UseECSqlPropertyNames ? "GeometryStream" : "geometryStream"];
304
+ if (options.abbreviateBlobs)
305
+ expect(geometryStream).to.be.a("string").and.match(/^\{"bytes":\d+\}$/);
306
+ else
307
+ expect(geometryStream).to.be.instanceOf(Uint8Array);
308
+ });
309
+ }
310
+ });
311
+ it("fetches native metadata once per statement and row options", () => {
312
+ // Native prototype methods cannot be spied on directly, so count calls through a subclass.
313
+ const getMetadataSpy = sinon.spy();
314
+ const nativeStatement = IModelNative.platform.ECSqlStatement;
315
+ sinon.replace(IModelNative.platform, "ECSqlStatement", class extends nativeStatement {
316
+ getMetadata(...args) {
317
+ getMetadataSpy();
318
+ return super.getMetadata(...args);
319
+ }
320
+ });
321
+ iModel.clearCaches();
322
+ const options = { rowFormat: QueryRowFormat.UseECSqlPropertyNames };
323
+ for (let i = 0; i < 10; i++)
324
+ readMetadata({ ...options });
325
+ expect(getMetadataSpy.callCount).to.equal(1);
326
+ readMetadata({ ...options, abbreviateBlobs: true });
327
+ readMetadata({ ...options, abbreviateBlobs: true });
328
+ expect(getMetadataSpy.callCount).to.equal(2, "different row options need their own metadata");
329
+ iModel.clearCaches();
330
+ readMetadata({ ...options });
331
+ expect(getMetadataSpy.callCount).to.equal(3, "a re-prepared statement must not reuse cached metadata");
332
+ });
333
+ it("does not share metadata objects between calls", () => {
334
+ iModel.clearCaches();
335
+ const options = { rowFormat: QueryRowFormat.UseECSqlPropertyNames };
336
+ const expected = structuredClone(readMetadata({ ...options }).meta);
337
+ iModel.withQueryReader(sql, (reader) => {
338
+ assert.isTrue(reader.step());
339
+ const readerMeta = reader.getMetaData();
340
+ readerMeta[0].name = "Changed";
341
+ readerMeta[0].index = 3;
342
+ readerMeta.reverse();
343
+ const proxyMeta = reader.current.getMetaData();
344
+ proxyMeta.push({ ...proxyMeta[0], name: "Extra" });
345
+ }, new QueryBinder().bindId(1, elementId), options);
346
+ const { meta, row } = readMetadata({ ...options });
347
+ expect(meta).to.deep.equal(expected);
348
+ expect(row.ECInstanceId).to.equal(elementId);
349
+ });
350
+ it("returns metadata for queries that produce no rows", () => {
351
+ iModel.clearCaches();
352
+ const options = { rowFormat: QueryRowFormat.UseECSqlPropertyNames };
353
+ const expected = readMetadata({ ...options }).meta;
354
+ for (let i = 0; i < 3; i++) {
355
+ iModel.withQueryReader(sql, (reader) => {
356
+ expect(reader.step()).to.be.false;
357
+ expect(reader.getMetaData()).to.deep.equal(expected);
358
+ }, new QueryBinder().bindId(1, "0xffffff"), options);
359
+ iModel.withQueryReader(sql, (reader) => {
360
+ expect(reader.getMetaData()).to.deep.equal(expected);
361
+ expect(reader.toArray()).to.deep.equal([]);
362
+ }, new QueryBinder().bindId(1, "0xffffff"), options);
363
+ }
364
+ });
365
+ it("reflects a schema import between calls", () => {
366
+ const env_2 = { stack: [], error: void 0, hasError: false };
367
+ try {
368
+ const schemaXml = (version, extraProperty) => `<ECSchema schemaName="Test" alias="ts" version="${version}" xmlns="http://www.bentley.com/schemas/Bentley.ECXML.3.2">
369
+ <ECEntityClass typeName="Foo" modifier="Sealed">
370
+ <ECProperty propertyName="n" typeName="int"/>
371
+ ${extraProperty}
372
+ </ECEntityClass>
373
+ </ECSchema>`;
374
+ const ecdb = __addDisposableResource(env_2, ECDbTestHelper.createECDb(KnownTestLocations.outputDir, "syncReaderMetadataCache.ecdb", schemaXml("01.00.00", "")), false);
375
+ ecdb.withCachedWriteStatement("INSERT INTO ts.Foo(n) VALUES(1)", (stmt) => stmt.stepForInsert());
376
+ ecdb.saveChanges();
377
+ const fooSql = "SELECT * FROM ts.Foo";
378
+ const options = { rowFormat: QueryRowFormat.UseECSqlPropertyNames };
379
+ const readNames = () => ecdb.withQueryReader(fooSql, (reader) => {
380
+ assert.isTrue(reader.step());
381
+ return reader.getMetaData().map((p) => p.name);
382
+ }, undefined, options);
383
+ expect(readNames()).to.deep.equal(["ECInstanceId", "ECClassId", "n"]);
384
+ expect(readNames()).to.deep.equal(["ECInstanceId", "ECClassId", "n"]);
385
+ const schemaPath = path.join(KnownTestLocations.outputDir, "syncReaderMetadataCache.ecschema.xml");
386
+ IModelJsFs.writeFileSync(schemaPath, schemaXml("01.00.01", `<ECProperty propertyName="m" typeName="string"/>`));
387
+ ecdb.importSchema(schemaPath);
388
+ ecdb.saveChanges();
389
+ expect(readNames()).to.deep.equal(["ECInstanceId", "ECClassId", "n", "m"]);
390
+ }
391
+ catch (e_2) {
392
+ env_2.error = e_2;
393
+ env_2.hasError = true;
394
+ }
395
+ finally {
396
+ __disposeResources(env_2);
397
+ }
398
+ });
399
+ });
260
400
  });
261
401
  //# sourceMappingURL=ECSqlSyncReader.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ECSqlSyncReader.test.js","sourceRoot":"","sources":["../../../../src/test/ecdb/ECSqlSyncReader.test.ts"],"names":[],"mappings":"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","sourcesContent":["/*---------------------------------------------------------------------------------------------\r\n* Copyright (c) Bentley Systems, Incorporated. All rights reserved.\r\n* See LICENSE.md in the project root for license terms and full copyright notice.\r\n*--------------------------------------------------------------------------------------------*/\r\n\r\nimport { assert, expect } from \"chai\";\r\nimport * as sinon from \"sinon\";\r\nimport { QueryBinder, QueryOptionsBuilder, QueryRowFormat } from \"@itwin/core-common\";\r\nimport { SnapshotDb } from \"../../IModelDb\";\r\nimport { IModelTestUtils } from \"../IModelTestUtils\";\r\nimport { Id64 } from \"@itwin/core-bentley\";\r\nimport { ECSqlStatement } from \"../../ECSqlStatement\";\r\nimport { ECDbTestHelper } from \"./ECDbTestHelper\";\r\nimport { KnownTestLocations } from \"../KnownTestLocations\";\r\n\r\ndescribe(\"WithQueryReaderTests\", () => {\r\n let iModel: SnapshotDb;\r\n\r\n before(async () => {\r\n iModel = SnapshotDb.openFile(IModelTestUtils.resolveAssetFile(\"test.bim\"));\r\n });\r\n\r\n after(async () => {\r\n iModel.close();\r\n });\r\n it(\"check behvaiour if we call clearCaches in between\", () => {\r\n let actualRowCount = 0;\r\n const expectedInstanceIds = [\"0x1\", \"0xe\", \"0x10\", \"0x11\", \"0x12\",\r\n \"0x13\", \"0x14\", \"0x15\", \"0x16\", \"0x17\"];\r\n\r\n expect(() => iModel.withQueryReader(\"SELECT * FROM bis.Element\", (reader) => {\r\n let loopCount = 0;\r\n // First loop - read first 10 rows\r\n while (loopCount < 10) {\r\n reader.step()\r\n actualRowCount++;\r\n loopCount++;\r\n assert.isDefined(reader.current[0]);\r\n assert.equal(reader.current[0], expectedInstanceIds[actualRowCount - 1]);\r\n }\r\n assert.equal(loopCount, 10);\r\n iModel.clearCaches();\r\n\r\n reader.step(); // step should fail after clearCaches\r\n })).to.throw(\"Step failed\");\r\n });\r\n it(\"should throw error if we try to step on a closed iModelDb object\", () => {\r\n const imodelPath = iModel.pathName;\r\n expect(() => iModel.withQueryReader(\"SELECT * FROM bis.Element\", (reader) => {\r\n let loopCount = 0;\r\n while (loopCount < 10) {\r\n reader.step();\r\n assert.isDefined(reader.current[0]);\r\n loopCount++;\r\n }\r\n assert.equal(loopCount, 10);\r\n iModel.close();\r\n\r\n iModel = SnapshotDb.openFile(imodelPath);\r\n assert.isDefined(reader.current[0]);\r\n reader.step(); // step should fail after iModelDb is closed\r\n })).to.throw(\"Statement is not prepared\");\r\n });\r\n it(\"returning reader from withQueryReader callback should throw error if we try to step on it\", () => {\r\n const readerObj = iModel.withQueryReader(\"SELECT * FROM bis.Element\", (reader) => {\r\n reader.step();\r\n return reader;\r\n });\r\n expect(readerObj.current[0]).to.equal(\"0x1\"); // will not throw error as we are just accessing current row\r\n expect(() => readerObj.step()).to.throw(\"Statement is not prepared\");\r\n });\r\n it(\"checking rowFormat unspecified case - values accessed by index\", () => {\r\n // Default rowFormat is UseECSqlPropertyIndexes: columns are accessed by their SELECT-order index.\r\n iModel.withQueryReader(\"SELECT ECInstanceId, ECClassId FROM bis.Element\", (reader) => {\r\n assert.isTrue(reader.step());\r\n const id: string = reader.current[0];\r\n const classId: string = reader.current[1];\r\n assert.isTrue(Id64.isValid(classId));\r\n assert.isTrue(Id64.isValid(id));\r\n assert.equal(id, \"0x19\");\r\n });\r\n });\r\n\r\n it(\"checking rowFormat UseECSqlPropertyIndexes - values accessed by index\", () => {\r\n const config = new QueryOptionsBuilder().setRowFormat(QueryRowFormat.UseECSqlPropertyIndexes).getOptions();\r\n iModel.withQueryReader(\"SELECT ECInstanceId, ECClassId FROM bis.Element\", (reader) => {\r\n assert.isTrue(reader.step());\r\n // Index 0 → ECInstanceId, index 1 → ECClassId\r\n const id: string = reader.current[0];\r\n const classId: string = reader.current[1];\r\n assert.equal(id, \"0x19\");\r\n assert.isTrue(Id64.isValid(classId));\r\n // Swapping column order changes index, not value\r\n }, undefined, config);\r\n });\r\n\r\n it(\"checking rowFormat UseECSqlPropertyNames - values accessed by ECSQL property name\", () => {\r\n const config = new QueryOptionsBuilder().setRowFormat(QueryRowFormat.UseECSqlPropertyNames).getOptions();\r\n iModel.withQueryReader(\"SELECT ECInstanceId, ECClassId FROM bis.Element\", (reader) => {\r\n assert.isTrue(reader.step());\r\n const id: string = reader.current.ECInstanceId;\r\n const classId: string = reader.current.ECClassId;\r\n assert.equal(id, \"0x19\");\r\n assert.isTrue(Id64.isValid(classId));\r\n }, undefined, config);\r\n });\r\n\r\n it(\"checking rowFormat UseJsPropertyNames - values accessed by JavaScript property name\", () => {\r\n // eslint-disable-next-line @typescript-eslint/no-deprecated\r\n const config = new QueryOptionsBuilder().setRowFormat(QueryRowFormat.UseJsPropertyNames).getOptions();\r\n iModel.withQueryReader(\"SELECT ECInstanceId, ECClassId FROM bis.Element\", (reader) => {\r\n assert.isTrue(reader.step());\r\n // ECInstanceId → id, ECClassId → className (resolved to a fully-qualified class name string)\r\n const id: string = reader.current.id;\r\n const className: string = reader.current.className;\r\n assert.equal(id, \"0x19\");\r\n // className should be in the form \"SchemaName.ClassName\"\r\n assert.equal(className, \"BisCore.DrawingCategory\");\r\n }, undefined, config);\r\n });\r\n\r\n it(\"checking rowFormat UseECSqlPropertyNames with convertClassIdsToClassNames - ECClassId returned as class name string\", () => {\r\n const config = new QueryOptionsBuilder()\r\n .setRowFormat(QueryRowFormat.UseECSqlPropertyNames)\r\n // eslint-disable-next-line @typescript-eslint/no-deprecated\r\n .setConvertClassIdsToNames(true)\r\n .getOptions();\r\n iModel.withQueryReader(\"SELECT ECInstanceId, ECClassId FROM bis.Element\", (reader) => {\r\n assert.isTrue(reader.step());\r\n const id: string = reader.current.ECInstanceId;\r\n const classId: string = reader.current.ECClassId;\r\n assert.equal(id, \"0x19\");\r\n // With convertClassIdsToClassNames, ECClassId is resolved to \"SchemaName.ClassName\" instead of an Id\r\n assert.equal(classId, \"BisCore.DrawingCategory\");\r\n }, undefined, config);\r\n });\r\n\r\n describe(\"statement caching (regression)\", () => {\r\n // `withQueryReader` used to build a fresh `ECSqlStatement` and re-compile the ECSQL on every\r\n // call (via `ECSqlRowExecutor`), with no caching. Callers such as `IModelTransformer` invoke\r\n // per-element helpers (e.g. `hasSubModel`) once per element, so on large models this turned one\r\n // cached ECSQL prepare into N full native compiles - a significant performance regression. The\r\n // reader now reuses a prepared statement from the owning db's `_statementCache`.\r\n const sql = \"SELECT ECInstanceId FROM bis.Element WHERE ECInstanceId=?\";\r\n\r\n afterEach(() => sinon.restore());\r\n\r\n it(\"reuses a single prepared statement across repeated calls instead of re-preparing\", () => {\r\n iModel.clearCaches();\r\n const prepareSpy = sinon.spy(ECSqlStatement.prototype, \"prepare\"); // eslint-disable-line @typescript-eslint/no-deprecated\r\n for (let i = 0; i < 20; i++) {\r\n iModel.withQueryReader(sql, (reader) => {\r\n reader.step();\r\n }, new QueryBinder().bindId(1, \"0x1\"));\r\n }\r\n expect(prepareSpy.callCount).to.equal(1, \"queries with identical ECSQL text should re-use one cached prepared statement\");\r\n });\r\n\r\n it(\"keeps nested withQueryReader calls on the same SQL independent\", () => {\r\n iModel.clearCaches();\r\n // A nested reader on the same SQL must get its own statement (findAndRemove hands the outer\r\n // reader's statement out of the cache), so results do not corrupt each other.\r\n const outerId = iModel.withQueryReader(sql, (outer) => {\r\n assert.isTrue(outer.step());\r\n const innerId = iModel.withQueryReader(sql, (inner) => {\r\n assert.isTrue(inner.step());\r\n return inner.current[0] as string;\r\n }, new QueryBinder().bindId(1, \"0xe\"));\r\n expect(innerId).to.equal(\"0xe\");\r\n // Outer reader's cursor must be unaffected by the nested reader.\r\n return outer.current[0] as string;\r\n }, new QueryBinder().bindId(1, \"0x1\"));\r\n expect(outerId).to.equal(\"0x1\");\r\n });\r\n\r\n it(\"recovers from a prepare failure without poisoning the cache\", () => {\r\n iModel.clearCaches();\r\n const invalidSql = \"SELECT * FROM bis.ThisClassDoesNotExist\";\r\n const prepareSpy = sinon.spy(ECSqlStatement.prototype, \"prepare\"); // eslint-disable-line @typescript-eslint/no-deprecated\r\n expect(() => iModel.withQueryReader(invalidSql, (reader) => reader.step())).to.throw();\r\n expect(() => iModel.withQueryReader(invalidSql, (reader) => reader.step())).to.throw();\r\n expect(prepareSpy.callCount).to.equal(2, \"a statement that failed to prepare must not be cached\");\r\n\r\n iModel.withQueryReader(sql, (reader) => {\r\n assert.isTrue(reader.step());\r\n expect(reader.current[0]).to.equal(\"0x1\");\r\n }, new QueryBinder().bindId(1, \"0x1\"));\r\n });\r\n\r\n it(\"releases the executor and cached statement when binding fails during reader construction\", () => {\r\n iModel.clearCaches();\r\n const prepareSpy = sinon.spy(ECSqlStatement.prototype, \"prepare\"); // eslint-disable-line @typescript-eslint/no-deprecated\r\n iModel.withQueryReader(sql, (reader) => reader.step(), new QueryBinder().bindId(1, \"0x1\"));\r\n const listenerCount = iModel.onBeforeClose.numberOfListeners;\r\n\r\n const bindStub = sinon.stub(ECSqlStatement.prototype, \"bindParams\").throws(new Error(\"Expected bind failure\")); // eslint-disable-line @typescript-eslint/no-deprecated\r\n expect(() => iModel.withQueryReader(sql, () => undefined, new QueryBinder().bindId(1, \"0x1\"))).to.throw(\"Expected bind failure\");\r\n bindStub.restore();\r\n expect(iModel.onBeforeClose.numberOfListeners).to.equal(listenerCount);\r\n\r\n iModel.withQueryReader(sql, (reader) => reader.step(), new QueryBinder().bindId(1, \"0x1\"));\r\n expect(prepareSpy.callCount).to.equal(1, \"the statement checked out before the bind failure should be returned to the cache\");\r\n });\r\n\r\n it(\"also caches for ECDb.withQueryReader (shared ECSqlRowExecutor path)\", () => {\r\n using ecdb = ECDbTestHelper.createECDb(KnownTestLocations.outputDir, \"syncReaderStmtCache.ecdb\",\r\n `<ECSchema schemaName=\"Test\" alias=\"ts\" version=\"01.00.00\" xmlns=\"http://www.bentley.com/schemas/Bentley.ECXML.3.2\">\r\n <ECEntityClass typeName=\"Foo\" modifier=\"Sealed\">\r\n <ECProperty propertyName=\"n\" typeName=\"int\"/>\r\n </ECEntityClass>\r\n </ECSchema>`);\r\n ecdb.saveChanges();\r\n const ecdbSql = \"SELECT ECInstanceId FROM meta.ECClassDef WHERE ECInstanceId=?\";\r\n const prepareSpy = sinon.spy(ECSqlStatement.prototype, \"prepare\"); // eslint-disable-line @typescript-eslint/no-deprecated\r\n for (let i = 0; i < 10; i++)\r\n ecdb.withQueryReader(ecdbSql, (reader) => reader.step(), new QueryBinder().bindId(1, \"0x1\"));\r\n expect(prepareSpy.callCount).to.equal(1, \"ECDb.withQueryReader should also reuse a cached prepared statement\");\r\n });\r\n });\r\n});\r\n"]}
1
+ {"version":3,"file":"ECSqlSyncReader.test.js","sourceRoot":"","sources":["../../../../src/test/ecdb/ECSqlSyncReader.test.ts"],"names":[],"mappings":"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","sourcesContent":["/*---------------------------------------------------------------------------------------------\r\n* Copyright (c) Bentley Systems, Incorporated. All rights reserved.\r\n* See LICENSE.md in the project root for license terms and full copyright notice.\r\n*--------------------------------------------------------------------------------------------*/\r\n\r\nimport { assert, expect } from \"chai\";\r\nimport * as sinon from \"sinon\";\r\nimport * as path from \"node:path\";\r\nimport { QueryBinder, QueryOptionsBuilder, QueryPropertyMetaData, QueryRowFormat } from \"@itwin/core-common\";\r\nimport { SnapshotDb } from \"../../IModelDb\";\r\nimport { IModelTestUtils } from \"../IModelTestUtils\";\r\nimport { Id64 } from \"@itwin/core-bentley\";\r\nimport { ECSqlStatement } from \"../../ECSqlStatement\";\r\nimport { ECDbTestHelper } from \"./ECDbTestHelper\";\r\nimport { KnownTestLocations } from \"../KnownTestLocations\";\r\nimport { IModelNative } from \"../../internal/NativePlatform\";\r\nimport { IModelJsFs } from \"../../IModelJsFs\";\r\nimport { SynchronousQueryOptions } from \"../../ECSqlSyncReader\";\r\n\r\ndescribe(\"WithQueryReaderTests\", () => {\r\n let iModel: SnapshotDb;\r\n\r\n before(async () => {\r\n iModel = SnapshotDb.openFile(IModelTestUtils.resolveAssetFile(\"test.bim\"));\r\n });\r\n\r\n after(async () => {\r\n iModel.close();\r\n });\r\n it(\"check behvaiour if we call clearCaches in between\", () => {\r\n let actualRowCount = 0;\r\n const expectedInstanceIds = [\"0x1\", \"0xe\", \"0x10\", \"0x11\", \"0x12\",\r\n \"0x13\", \"0x14\", \"0x15\", \"0x16\", \"0x17\"];\r\n\r\n expect(() => iModel.withQueryReader(\"SELECT * FROM bis.Element\", (reader) => {\r\n let loopCount = 0;\r\n // First loop - read first 10 rows\r\n while (loopCount < 10) {\r\n reader.step()\r\n actualRowCount++;\r\n loopCount++;\r\n assert.isDefined(reader.current[0]);\r\n assert.equal(reader.current[0], expectedInstanceIds[actualRowCount - 1]);\r\n }\r\n assert.equal(loopCount, 10);\r\n iModel.clearCaches();\r\n\r\n reader.step(); // step should fail after clearCaches\r\n })).to.throw(\"Step failed\");\r\n });\r\n it(\"should throw error if we try to step on a closed iModelDb object\", () => {\r\n const imodelPath = iModel.pathName;\r\n expect(() => iModel.withQueryReader(\"SELECT * FROM bis.Element\", (reader) => {\r\n let loopCount = 0;\r\n while (loopCount < 10) {\r\n reader.step();\r\n assert.isDefined(reader.current[0]);\r\n loopCount++;\r\n }\r\n assert.equal(loopCount, 10);\r\n iModel.close();\r\n\r\n iModel = SnapshotDb.openFile(imodelPath);\r\n assert.isDefined(reader.current[0]);\r\n reader.step(); // step should fail after iModelDb is closed\r\n })).to.throw(\"Statement is not prepared\");\r\n });\r\n it(\"returning reader from withQueryReader callback should throw error if we try to step on it\", () => {\r\n const readerObj = iModel.withQueryReader(\"SELECT * FROM bis.Element\", (reader) => {\r\n reader.step();\r\n return reader;\r\n });\r\n expect(readerObj.current[0]).to.equal(\"0x1\"); // will not throw error as we are just accessing current row\r\n expect(() => readerObj.step()).to.throw(\"Statement is not prepared\");\r\n });\r\n it(\"checking rowFormat unspecified case - values accessed by index\", () => {\r\n // Default rowFormat is UseECSqlPropertyIndexes: columns are accessed by their SELECT-order index.\r\n iModel.withQueryReader(\"SELECT ECInstanceId, ECClassId FROM bis.Element\", (reader) => {\r\n assert.isTrue(reader.step());\r\n const id: string = reader.current[0];\r\n const classId: string = reader.current[1];\r\n assert.isTrue(Id64.isValid(classId));\r\n assert.isTrue(Id64.isValid(id));\r\n assert.equal(id, \"0x19\");\r\n });\r\n });\r\n\r\n it(\"checking rowFormat UseECSqlPropertyIndexes - values accessed by index\", () => {\r\n const config = new QueryOptionsBuilder().setRowFormat(QueryRowFormat.UseECSqlPropertyIndexes).getOptions();\r\n iModel.withQueryReader(\"SELECT ECInstanceId, ECClassId FROM bis.Element\", (reader) => {\r\n assert.isTrue(reader.step());\r\n // Index 0 → ECInstanceId, index 1 → ECClassId\r\n const id: string = reader.current[0];\r\n const classId: string = reader.current[1];\r\n assert.equal(id, \"0x19\");\r\n assert.isTrue(Id64.isValid(classId));\r\n // Swapping column order changes index, not value\r\n }, undefined, config);\r\n });\r\n\r\n it(\"checking rowFormat UseECSqlPropertyNames - values accessed by ECSQL property name\", () => {\r\n const config = new QueryOptionsBuilder().setRowFormat(QueryRowFormat.UseECSqlPropertyNames).getOptions();\r\n iModel.withQueryReader(\"SELECT ECInstanceId, ECClassId FROM bis.Element\", (reader) => {\r\n assert.isTrue(reader.step());\r\n const id: string = reader.current.ECInstanceId;\r\n const classId: string = reader.current.ECClassId;\r\n assert.equal(id, \"0x19\");\r\n assert.isTrue(Id64.isValid(classId));\r\n }, undefined, config);\r\n });\r\n\r\n it(\"checking rowFormat UseJsPropertyNames - values accessed by JavaScript property name\", () => {\r\n // eslint-disable-next-line @typescript-eslint/no-deprecated\r\n const config = new QueryOptionsBuilder().setRowFormat(QueryRowFormat.UseJsPropertyNames).getOptions();\r\n iModel.withQueryReader(\"SELECT ECInstanceId, ECClassId FROM bis.Element\", (reader) => {\r\n assert.isTrue(reader.step());\r\n // ECInstanceId → id, ECClassId → className (resolved to a fully-qualified class name string)\r\n const id: string = reader.current.id;\r\n const className: string = reader.current.className;\r\n assert.equal(id, \"0x19\");\r\n // className should be in the form \"SchemaName.ClassName\"\r\n assert.equal(className, \"BisCore.DrawingCategory\");\r\n }, undefined, config);\r\n });\r\n\r\n it(\"checking rowFormat UseECSqlPropertyNames with convertClassIdsToClassNames - ECClassId returned as class name string\", () => {\r\n const config = new QueryOptionsBuilder()\r\n .setRowFormat(QueryRowFormat.UseECSqlPropertyNames)\r\n // eslint-disable-next-line @typescript-eslint/no-deprecated\r\n .setConvertClassIdsToNames(true)\r\n .getOptions();\r\n iModel.withQueryReader(\"SELECT ECInstanceId, ECClassId FROM bis.Element\", (reader) => {\r\n assert.isTrue(reader.step());\r\n const id: string = reader.current.ECInstanceId;\r\n const classId: string = reader.current.ECClassId;\r\n assert.equal(id, \"0x19\");\r\n // With convertClassIdsToClassNames, ECClassId is resolved to \"SchemaName.ClassName\" instead of an Id\r\n assert.equal(classId, \"BisCore.DrawingCategory\");\r\n }, undefined, config);\r\n });\r\n\r\n describe(\"statement caching (regression)\", () => {\r\n // `withQueryReader` used to build a fresh `ECSqlStatement` and re-compile the ECSQL on every\r\n // call (via `ECSqlRowExecutor`), with no caching. Callers such as `IModelTransformer` invoke\r\n // per-element helpers (e.g. `hasSubModel`) once per element, so on large models this turned one\r\n // cached ECSQL prepare into N full native compiles - a significant performance regression. The\r\n // reader now reuses a prepared statement from the owning db's `_statementCache`.\r\n const sql = \"SELECT ECInstanceId FROM bis.Element WHERE ECInstanceId=?\";\r\n\r\n afterEach(() => sinon.restore());\r\n\r\n it(\"reuses a single prepared statement across repeated calls instead of re-preparing\", () => {\r\n iModel.clearCaches();\r\n const prepareSpy = sinon.spy(ECSqlStatement.prototype, \"prepare\"); // eslint-disable-line @typescript-eslint/no-deprecated\r\n for (let i = 0; i < 20; i++) {\r\n iModel.withQueryReader(sql, (reader) => {\r\n reader.step();\r\n }, new QueryBinder().bindId(1, \"0x1\"));\r\n }\r\n expect(prepareSpy.callCount).to.equal(1, \"queries with identical ECSQL text should re-use one cached prepared statement\");\r\n });\r\n\r\n it(\"keeps nested withQueryReader calls on the same SQL independent\", () => {\r\n iModel.clearCaches();\r\n // A nested reader on the same SQL must get its own statement (findAndRemove hands the outer\r\n // reader's statement out of the cache), so results do not corrupt each other.\r\n const outerId = iModel.withQueryReader(sql, (outer) => {\r\n assert.isTrue(outer.step());\r\n const innerId = iModel.withQueryReader(sql, (inner) => {\r\n assert.isTrue(inner.step());\r\n return inner.current[0] as string;\r\n }, new QueryBinder().bindId(1, \"0xe\"));\r\n expect(innerId).to.equal(\"0xe\");\r\n // Outer reader's cursor must be unaffected by the nested reader.\r\n return outer.current[0] as string;\r\n }, new QueryBinder().bindId(1, \"0x1\"));\r\n expect(outerId).to.equal(\"0x1\");\r\n });\r\n\r\n it(\"recovers from a prepare failure without poisoning the cache\", () => {\r\n iModel.clearCaches();\r\n const invalidSql = \"SELECT * FROM bis.ThisClassDoesNotExist\";\r\n const prepareSpy = sinon.spy(ECSqlStatement.prototype, \"prepare\"); // eslint-disable-line @typescript-eslint/no-deprecated\r\n expect(() => iModel.withQueryReader(invalidSql, (reader) => reader.step())).to.throw();\r\n expect(() => iModel.withQueryReader(invalidSql, (reader) => reader.step())).to.throw();\r\n expect(prepareSpy.callCount).to.equal(2, \"a statement that failed to prepare must not be cached\");\r\n\r\n iModel.withQueryReader(sql, (reader) => {\r\n assert.isTrue(reader.step());\r\n expect(reader.current[0]).to.equal(\"0x1\");\r\n }, new QueryBinder().bindId(1, \"0x1\"));\r\n });\r\n\r\n it(\"releases the executor and cached statement when binding fails during reader construction\", () => {\r\n iModel.clearCaches();\r\n const prepareSpy = sinon.spy(ECSqlStatement.prototype, \"prepare\"); // eslint-disable-line @typescript-eslint/no-deprecated\r\n iModel.withQueryReader(sql, (reader) => reader.step(), new QueryBinder().bindId(1, \"0x1\"));\r\n const listenerCount = iModel.onBeforeClose.numberOfListeners;\r\n\r\n const bindStub = sinon.stub(ECSqlStatement.prototype, \"bindParams\").throws(new Error(\"Expected bind failure\")); // eslint-disable-line @typescript-eslint/no-deprecated\r\n expect(() => iModel.withQueryReader(sql, () => undefined, new QueryBinder().bindId(1, \"0x1\"))).to.throw(\"Expected bind failure\");\r\n bindStub.restore();\r\n expect(iModel.onBeforeClose.numberOfListeners).to.equal(listenerCount);\r\n\r\n iModel.withQueryReader(sql, (reader) => reader.step(), new QueryBinder().bindId(1, \"0x1\"));\r\n expect(prepareSpy.callCount).to.equal(1, \"the statement checked out before the bind failure should be returned to the cache\");\r\n });\r\n\r\n it(\"also caches for ECDb.withQueryReader (shared ECSqlRowExecutor path)\", () => {\r\n using ecdb = ECDbTestHelper.createECDb(KnownTestLocations.outputDir, \"syncReaderStmtCache.ecdb\",\r\n `<ECSchema schemaName=\"Test\" alias=\"ts\" version=\"01.00.00\" xmlns=\"http://www.bentley.com/schemas/Bentley.ECXML.3.2\">\r\n <ECEntityClass typeName=\"Foo\" modifier=\"Sealed\">\r\n <ECProperty propertyName=\"n\" typeName=\"int\"/>\r\n </ECEntityClass>\r\n </ECSchema>`);\r\n ecdb.saveChanges();\r\n const ecdbSql = \"SELECT ECInstanceId FROM meta.ECClassDef WHERE ECInstanceId=?\";\r\n const prepareSpy = sinon.spy(ECSqlStatement.prototype, \"prepare\"); // eslint-disable-line @typescript-eslint/no-deprecated\r\n for (let i = 0; i < 10; i++)\r\n ecdb.withQueryReader(ecdbSql, (reader) => reader.step(), new QueryBinder().bindId(1, \"0x1\"));\r\n expect(prepareSpy.callCount).to.equal(1, \"ECDb.withQueryReader should also reuse a cached prepared statement\");\r\n });\r\n });\r\n\r\n describe(\"metadata caching\", () => {\r\n // Column metadata depends only on the prepared statement and the row-adaptor options, so it is cached\r\n // on the cached ECSqlStatement instead of being fetched from native code on every withQueryReader call.\r\n const sql = \"SELECT ECInstanceId, ECClassId, CodeValue, GeometryStream FROM bis.GeometricElement3d WHERE ECInstanceId=?\";\r\n let elementId: string;\r\n\r\n before(() => {\r\n elementId = iModel.withQueryReader(\"SELECT ECInstanceId FROM bis.GeometricElement3d WHERE GeometryStream IS NOT NULL LIMIT 1\", (reader) => {\r\n assert.isTrue(reader.step());\r\n return reader.current[0] as string;\r\n });\r\n });\r\n\r\n afterEach(() => sinon.restore());\r\n\r\n function readMetadata(options: SynchronousQueryOptions): { meta: QueryPropertyMetaData[], row: any } {\r\n return iModel.withQueryReader(sql, (reader) => {\r\n assert.isTrue(reader.step());\r\n return { meta: reader.getMetaData(), row: reader.current.toRow() };\r\n }, new QueryBinder().bindId(1, elementId), options);\r\n }\r\n\r\n it(\"returns metadata matching the row options when the same statement is reused with different options\", () => {\r\n const optionSets: SynchronousQueryOptions[] = [\r\n // eslint-disable-next-line @typescript-eslint/no-deprecated\r\n { rowFormat: QueryRowFormat.UseJsPropertyNames },\r\n { rowFormat: QueryRowFormat.UseECSqlPropertyNames },\r\n // eslint-disable-next-line @typescript-eslint/no-deprecated\r\n { rowFormat: QueryRowFormat.UseJsPropertyNames, abbreviateBlobs: true },\r\n { rowFormat: QueryRowFormat.UseECSqlPropertyNames, abbreviateBlobs: true },\r\n { rowFormat: QueryRowFormat.UseECSqlPropertyNames, convertClassIdsToClassNames: true },\r\n ];\r\n\r\n // Expected metadata comes from a freshly prepared statement for each option set.\r\n const expected = optionSets.map((options) => {\r\n iModel.clearCaches();\r\n return readMetadata({ ...options }).meta;\r\n });\r\n expect(expected[0].map((p) => p.jsonName)).to.deep.equal([\"id\", \"className\", \"codeValue\", \"geometryStream\"]);\r\n expect(expected[1].map((p) => p.name)).to.deep.equal([\"ECInstanceId\", \"ECClassId\", \"CodeValue\", \"GeometryStream\"]);\r\n\r\n iModel.clearCaches();\r\n for (let pass = 0; pass < 2; pass++) {\r\n optionSets.forEach((options, i) => {\r\n const { meta, row } = readMetadata({ ...options });\r\n expect(meta).to.deep.equal(expected[i]);\r\n const geometryStream = row[options.rowFormat === QueryRowFormat.UseECSqlPropertyNames ? \"GeometryStream\" : \"geometryStream\"];\r\n if (options.abbreviateBlobs)\r\n expect(geometryStream).to.be.a(\"string\").and.match(/^\\{\"bytes\":\\d+\\}$/);\r\n else\r\n expect(geometryStream).to.be.instanceOf(Uint8Array);\r\n });\r\n }\r\n });\r\n\r\n it(\"fetches native metadata once per statement and row options\", () => {\r\n // Native prototype methods cannot be spied on directly, so count calls through a subclass.\r\n const getMetadataSpy = sinon.spy();\r\n const nativeStatement = IModelNative.platform.ECSqlStatement;\r\n sinon.replace(IModelNative.platform, \"ECSqlStatement\", class extends nativeStatement {\r\n public override getMetadata(...args: Parameters<typeof nativeStatement.prototype.getMetadata>) {\r\n getMetadataSpy();\r\n return super.getMetadata(...args);\r\n }\r\n });\r\n iModel.clearCaches();\r\n const options = { rowFormat: QueryRowFormat.UseECSqlPropertyNames };\r\n for (let i = 0; i < 10; i++)\r\n readMetadata({ ...options });\r\n expect(getMetadataSpy.callCount).to.equal(1);\r\n\r\n readMetadata({ ...options, abbreviateBlobs: true });\r\n readMetadata({ ...options, abbreviateBlobs: true });\r\n expect(getMetadataSpy.callCount).to.equal(2, \"different row options need their own metadata\");\r\n\r\n iModel.clearCaches();\r\n readMetadata({ ...options });\r\n expect(getMetadataSpy.callCount).to.equal(3, \"a re-prepared statement must not reuse cached metadata\");\r\n });\r\n\r\n it(\"does not share metadata objects between calls\", () => {\r\n iModel.clearCaches();\r\n const options = { rowFormat: QueryRowFormat.UseECSqlPropertyNames };\r\n const expected = structuredClone(readMetadata({ ...options }).meta);\r\n\r\n iModel.withQueryReader(sql, (reader) => {\r\n assert.isTrue(reader.step());\r\n const readerMeta = reader.getMetaData();\r\n readerMeta[0].name = \"Changed\";\r\n readerMeta[0].index = 3;\r\n readerMeta.reverse();\r\n const proxyMeta = reader.current.getMetaData();\r\n proxyMeta.push({ ...proxyMeta[0], name: \"Extra\" });\r\n }, new QueryBinder().bindId(1, elementId), options);\r\n\r\n const { meta, row } = readMetadata({ ...options });\r\n expect(meta).to.deep.equal(expected);\r\n expect(row.ECInstanceId).to.equal(elementId);\r\n });\r\n\r\n it(\"returns metadata for queries that produce no rows\", () => {\r\n iModel.clearCaches();\r\n const options = { rowFormat: QueryRowFormat.UseECSqlPropertyNames };\r\n const expected = readMetadata({ ...options }).meta;\r\n for (let i = 0; i < 3; i++) {\r\n iModel.withQueryReader(sql, (reader) => {\r\n expect(reader.step()).to.be.false;\r\n expect(reader.getMetaData()).to.deep.equal(expected);\r\n }, new QueryBinder().bindId(1, \"0xffffff\"), options);\r\n iModel.withQueryReader(sql, (reader) => {\r\n expect(reader.getMetaData()).to.deep.equal(expected);\r\n expect(reader.toArray()).to.deep.equal([]);\r\n }, new QueryBinder().bindId(1, \"0xffffff\"), options);\r\n }\r\n });\r\n\r\n it(\"reflects a schema import between calls\", () => {\r\n const schemaXml = (version: string, extraProperty: string) => `<ECSchema schemaName=\"Test\" alias=\"ts\" version=\"${version}\" xmlns=\"http://www.bentley.com/schemas/Bentley.ECXML.3.2\">\r\n <ECEntityClass typeName=\"Foo\" modifier=\"Sealed\">\r\n <ECProperty propertyName=\"n\" typeName=\"int\"/>\r\n ${extraProperty}\r\n </ECEntityClass>\r\n </ECSchema>`;\r\n using ecdb = ECDbTestHelper.createECDb(KnownTestLocations.outputDir, \"syncReaderMetadataCache.ecdb\", schemaXml(\"01.00.00\", \"\"));\r\n ecdb.withCachedWriteStatement(\"INSERT INTO ts.Foo(n) VALUES(1)\", (stmt) => stmt.stepForInsert());\r\n ecdb.saveChanges();\r\n\r\n const fooSql = \"SELECT * FROM ts.Foo\";\r\n const options = { rowFormat: QueryRowFormat.UseECSqlPropertyNames };\r\n const readNames = () => ecdb.withQueryReader(fooSql, (reader) => {\r\n assert.isTrue(reader.step());\r\n return reader.getMetaData().map((p) => p.name);\r\n }, undefined, options);\r\n expect(readNames()).to.deep.equal([\"ECInstanceId\", \"ECClassId\", \"n\"]);\r\n expect(readNames()).to.deep.equal([\"ECInstanceId\", \"ECClassId\", \"n\"]);\r\n\r\n const schemaPath = path.join(KnownTestLocations.outputDir, \"syncReaderMetadataCache.ecschema.xml\");\r\n IModelJsFs.writeFileSync(schemaPath, schemaXml(\"01.00.01\", `<ECProperty propertyName=\"m\" typeName=\"string\"/>`));\r\n ecdb.importSchema(schemaPath);\r\n ecdb.saveChanges();\r\n\r\n expect(readNames()).to.deep.equal([\"ECInstanceId\", \"ECClassId\", \"n\", \"m\"]);\r\n });\r\n });\r\n});\r\n"]}
@@ -188,7 +188,7 @@ describe("iModel geolocation", () => {
188
188
  const expectedPt1 = Point3d.fromJSON(outputCoord.p);
189
189
  const outPt1 = Point3d.fromJSON(response1.geoCoords[0].p);
190
190
  expect(Geometry.isSamePoint3dXY(expectedPt1, outPt1, 0.001)).to.be.true;
191
- expect(Math.abs(expectedPt1.z - outPt1.z) < 0.0001).to.be.true;
191
+ expect(Math.abs(expectedPt1.z - outPt1.z), fileName).to.be.lessThan(0.0001);
192
192
  // No point testing reversal when Out of useful range since reversibility is doubtful
193
193
  if (outputCoord.s !== GeoCoordStatus.OutOfUsefulRange) {
194
194
  const testPoint2 = [];
@@ -285,7 +285,7 @@ describe("iModel geolocation", () => {
285
285
  },
286
286
  };
287
287
  await convertTest("ExtonCampus1.bim", { horizontalCRS: { id: "EPSG:2272" }, verticalCRS: { id: "NAVD88" } }, "WGS84", { x: 775970.3155166894, y: 83323.24543981979, z: 130.74977547686285 }, { p: { x: -75.68712011112366, y: 40.06524845273591, z: 95.9769083 }, s: GeoCoordStatus.Success });
288
- await convertTest("UTM83-10-NGVD29-10.bim", { horizontalCRS: { id: "UTM83-10" }, verticalCRS: { id: "NAVD88" } }, { horizontalCRS: { id: "UTM27-10" }, verticalCRS: { id: "NGVD29" } }, { x: 548296.472, y: 4179414.470, z: 0.8457 }, { p: { x: 548392.9689991799, y: 4179217.683834238, z: -0.0006774162750405877 }, s: GeoCoordStatus.Success });
288
+ await convertTest("UTM83-10-NGVD29-10.bim", { horizontalCRS: { id: "UTM83-10" }, verticalCRS: { id: "NAVD88" } }, { horizontalCRS: { id: "UTM27-10" }, verticalCRS: { id: "NGVD29" } }, { x: 548296.472, y: 4179414.470, z: 0.8457 }, { p: { x: 548392.9689991799, y: 4179217.683834238, z: -0.000392204716569311 }, s: GeoCoordStatus.Success });
289
289
  await convertTest("BritishNatGrid-EllipsoidHelmert1.bim", EWRGCS, "WGS84", { x: 199247.08883859176, y: 150141.68625139236, z: 0.0 }, { p: { x: -0.80184489371471, y: 51.978341907041205, z: 0.0 }, s: GeoCoordStatus.Success });
290
290
  await convertTest("BritishNatGrid-Ellipsoid1.bim", { horizontalCRS: { id: "BritishNatGrid" }, verticalCRS: { id: "ELLIPSOID" } }, "", { x: 170370.718, y: 11572.405, z: 0.0 }, { p: { x: -5.2020119082059511, y: 49.959453295440234, z: 0.0 }, s: GeoCoordStatus.Success });
291
291
  await convertTest("BritishNatGrid-Ellipsoid2.bim", { horizontalCRS: { id: "BritishNatGrid" }, verticalCRS: { id: "ELLIPSOID" } }, "ETRF89", { x: 170370.718, y: 11572.405, z: 0.0 }, { p: { x: -5.2030365061523707, y: 49.960007477936202, z: 0.0 }, s: GeoCoordStatus.Success });
@@ -304,7 +304,7 @@ describe("iModel geolocation", () => {
304
304
  await convertTest("UTM83-10-NGVD29-7.bim", { horizontalCRS: { id: "UTM83-10" }, verticalCRS: { id: "NGVD29" } }, { horizontalCRS: { id: "CA83-II" }, verticalCRS: { id: "GEOID" } }, { x: 569024.940, y: 4386341.752, z: 0.0 }, { p: { x: 1983192.529823256, y: 717304.0311293667, z: 0.745910484422781 }, s: GeoCoordStatus.Success });
305
305
  await convertTest("UTM83-10-NGVD29-8.bim", { horizontalCRS: { id: "UTM83-10" }, verticalCRS: { id: "NGVD29" } }, { horizontalCRS: { id: "CA83-II" }, verticalCRS: { id: "NGVD29" } }, { x: 569024.940, y: 4386341.752, z: 0.0 }, { p: { x: 1983192.529823256, y: 717304.0311293667, z: 0.0 }, s: GeoCoordStatus.Success });
306
306
  await convertTest("UTM83-10-NGVD29-9.bim", { horizontalCRS: { id: "UTM83-10" }, verticalCRS: { id: "NGVD29" } }, { horizontalCRS: { epsg: 26942 }, verticalCRS: { id: "NAVD88" } }, { x: 569024.940, y: 4386341.752, z: 0.0 }, { p: { x: 1983192.529823256, y: 717304.0311293667, z: 0.745910484422781 }, s: GeoCoordStatus.Success });
307
- await convertTest("UTM83-10-NGVD29-10.bim", { horizontalCRS: { id: "UTM83-10" }, verticalCRS: { id: "NAVD88" } }, { horizontalCRS: { id: "UTM27-10" }, verticalCRS: { id: "NGVD29" } }, { x: 548296.472, y: 4179414.470, z: 0.8457 }, { p: { x: 548392.9689991799, y: 4179217.683834238, z: -0.0006774162750405877 }, s: GeoCoordStatus.Success });
307
+ await convertTest("UTM83-10-NGVD29-10.bim", { horizontalCRS: { id: "UTM83-10" }, verticalCRS: { id: "NAVD88" } }, { horizontalCRS: { id: "UTM27-10" }, verticalCRS: { id: "NGVD29" } }, { x: 548296.472, y: 4179414.470, z: 0.8457 }, { p: { x: 548392.9689991799, y: 4179217.683834238, z: -0.000392204716569311 }, s: GeoCoordStatus.Success });
308
308
  await convertTest("BritishNatGrid-Ellipsoid4.bim", { horizontalCRS: { id: "BritishNatGrid" }, verticalCRS: { id: "ELLIPSOID" } }, { horizontalCRS: { id: "HS2_Snake_2015" }, verticalCRS: { id: "GEOID" } }, { x: 473327.251, y: 257049.636, z: 0.0 }, { p: { x: 237732.58101946692, y: 364048.01547843055, z: -47.874172425966336 }, s: GeoCoordStatus.Success });
309
309
  await convertTest("BritishNatGrid-Ellipsoid5.bim", { horizontalCRS: { id: "BritishNatGrid" }, verticalCRS: { id: "ELLIPSOID" } }, {
310
310
  horizontalCRS: {