@itwin/core-backend 5.5.0-dev.16 → 5.5.0-dev.17

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.
@@ -1,14 +1,7 @@
1
- import { GuidString, Id64String } from "@itwin/core-bentley";
1
+ import { GuidString, Id64String, ITwinError } from "@itwin/core-bentley";
2
2
  import { ChangesetIdWithIndex } from "@itwin/core-common";
3
3
  import { BriefcaseDb } from "./IModelDb";
4
4
  import { TxnProps } from "./TxnManager";
5
- /**
6
- * Custom error class for stash-related errors.
7
- * @internal
8
- */
9
- export declare class StashError extends Error {
10
- constructor(message: string);
11
- }
12
5
  /**
13
6
  * Properties of a stash
14
7
  * @internal
@@ -60,6 +53,18 @@ export interface StashArgs {
60
53
  readonly db: BriefcaseDb;
61
54
  readonly stash: Id64String | StashProps;
62
55
  }
56
+ /**
57
+ * An error originating from the StashManager API.
58
+ * @internal
59
+ */
60
+ export declare namespace StashError {
61
+ const scope = "itwin-StashManager";
62
+ type Key = "readonly" | "no-file" | "no-stashes" | "invalid-stash" | "nothing-to-stash" | "unsaved-changes" | "pending-schema-changes" | "stash-not-found";
63
+ /** Instantiate and throw a StashError */
64
+ function throwError(key: Key, message: string): never;
65
+ /** Determine whether an error object is a StashError */
66
+ function isError(error: unknown, key?: Key): error is ITwinError;
67
+ }
63
68
  /**
64
69
  * Stash manager allow stash, drop, apply and merge stashes
65
70
  * @internal
@@ -1 +1 @@
1
- {"version":3,"file":"StashManager.d.ts","sourceRoot":"","sources":["../../src/StashManager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"StashManager.d.ts","sourceRoot":"","sources":["../../src/StashManager.ts"],"names":[],"mappings":"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"}
@@ -11,18 +11,6 @@ const SQLiteDb_1 = require("./SQLiteDb");
11
11
  const IModelHost_1 = require("./IModelHost");
12
12
  const BackendLoggerCategory_1 = require("./BackendLoggerCategory");
13
13
  const loggerCategory = BackendLoggerCategory_1.BackendLoggerCategory.StashManager;
14
- /**
15
- * Custom error class for stash-related errors.
16
- * @internal
17
- */
18
- class StashError extends Error {
19
- constructor(message) {
20
- super(message);
21
- this.name = "StashError";
22
- core_bentley_1.Logger.logError(loggerCategory, message);
23
- }
24
- }
25
- exports.StashError = StashError;
26
14
  var LockOrigin;
27
15
  (function (LockOrigin) {
28
16
  LockOrigin[LockOrigin["Acquired"] = 0] = "Acquired";
@@ -30,6 +18,24 @@ var LockOrigin;
30
18
  LockOrigin[LockOrigin["Discovered"] = 2] = "Discovered";
31
19
  })(LockOrigin || (LockOrigin = {}));
32
20
  ;
21
+ /**
22
+ * An error originating from the StashManager API.
23
+ * @internal
24
+ */
25
+ var StashError;
26
+ (function (StashError) {
27
+ StashError.scope = "itwin-StashManager";
28
+ /** Instantiate and throw a StashError */
29
+ function throwError(key, message) {
30
+ core_bentley_1.ITwinError.throwError({ iTwinErrorId: { scope: StashError.scope, key }, message });
31
+ }
32
+ StashError.throwError = throwError;
33
+ /** Determine whether an error object is a StashError */
34
+ function isError(error, key) {
35
+ return core_bentley_1.ITwinError.isError(error, StashError.scope, key);
36
+ }
37
+ StashError.isError = isError;
38
+ })(StashError || (exports.StashError = StashError = {}));
33
39
  /**
34
40
  * Stash manager allow stash, drop, apply and merge stashes
35
41
  * @internal
@@ -45,9 +51,9 @@ class StashManager {
45
51
  */
46
52
  static getStashRootFolder(db, ensureExists) {
47
53
  if (!db.isOpen || db.isReadonly)
48
- throw new StashError("Database is not open or is readonly");
54
+ StashError.throwError("readonly", "Database is not open or is readonly");
49
55
  if (!(0, node_fs_1.existsSync)(db[Symbols_1._nativeDb].getFilePath())) {
50
- throw new StashError("Could not determine briefcase path");
56
+ StashError.throwError("no-file", "Database file does not exist");
51
57
  }
52
58
  const stashDir = path.join(path.dirname(db[Symbols_1._nativeDb].getFilePath()), this.STASHES_ROOT_DIR_NAME, `${db.briefcaseId}`);
53
59
  if (ensureExists && !(0, node_fs_1.existsSync)(stashDir)) {
@@ -76,11 +82,11 @@ class StashManager {
76
82
  static getStashFilePath(args) {
77
83
  const stashRoot = this.getStashRootFolder(args.db, false);
78
84
  if (!(0, node_fs_1.existsSync)(stashRoot)) {
79
- throw new StashError("Invalid stash");
85
+ StashError.throwError("no-stashes", "No stashes exist for this briefcase");
80
86
  }
81
87
  const stashFilePath = path.join(stashRoot, `${this.getStashId(args)}.stash`);
82
88
  if (!(0, node_fs_1.existsSync)(stashFilePath)) {
83
- throw new StashError("Invalid stash");
89
+ StashError.throwError("invalid-stash", "Invalid stash");
84
90
  }
85
91
  return stashFilePath;
86
92
  }
@@ -130,13 +136,13 @@ class StashManager {
130
136
  */
131
137
  static async stash(args) {
132
138
  if (!args.db.txns.hasPendingTxns) {
133
- throw new StashError("nothing to stash");
139
+ StashError.throwError("nothing-to-stash", "Nothing to stash");
134
140
  }
135
141
  if (args.db.txns.hasUnsavedChanges) {
136
- throw new StashError("Unsaved changes exist");
142
+ StashError.throwError("unsaved-changes", "Unsaved changes exist");
137
143
  }
138
144
  if (args.db.txns.hasPendingSchemaChanges) {
139
- throw new StashError("Pending schema changeset. Stashing is not currently supported for schema changes");
145
+ StashError.throwError("pending-schema-changes", "Pending schema changeset. Stashing is not currently supported for schema changes");
140
146
  }
141
147
  const stashRootDir = this.getStashRootFolder(args.db, true);
142
148
  const iModelId = args.db.iModelId;
@@ -172,7 +178,7 @@ class StashManager {
172
178
  return this.withStash(args, (stashDb) => {
173
179
  const stashProps = stashDb.withPreparedSqliteStatement("SELECT [val] FROM [be_Local] WHERE [name]='$stash_info'", (stmt) => {
174
180
  if (stmt.step() !== core_bentley_1.DbResult.BE_SQLITE_ROW)
175
- throw new StashError("Invalid stash");
181
+ StashError.throwError("invalid-stash", "Invalid stash");
176
182
  return JSON.parse(stmt.getValueString(0));
177
183
  });
178
184
  return stashProps;
@@ -189,7 +195,7 @@ class StashManager {
189
195
  static withStash(args, callback) {
190
196
  const stashFile = this.getStashFilePath(args);
191
197
  if (!(0, node_fs_1.existsSync)(stashFile)) {
192
- throw new StashError("Invalid stash");
198
+ StashError.throwError("invalid-stash", "Invalid stash");
193
199
  }
194
200
  const stashDb = new SQLiteDb_1.SQLiteDb();
195
201
  stashDb.openDb(stashFile, core_bentley_1.OpenMode.Readonly);
@@ -275,16 +281,16 @@ class StashManager {
275
281
  core_bentley_1.Logger.logInfo(loggerCategory, `Restoring stash: ${this.getStashId(args)}`);
276
282
  const stash = this.tryGetStash(args);
277
283
  if (!stash) {
278
- throw new StashError(`Stash not found ${this.getStashId(args)}`);
284
+ StashError.throwError("stash-not-found", `Stash not found ${this.getStashId(args)}`);
279
285
  }
280
286
  if (db.txns.hasUnsavedChanges) {
281
- throw new StashError(`Unsaved changes present`);
287
+ StashError.throwError("unsaved-changes", `Unsaved changes are present.`);
282
288
  }
283
289
  if (db.iModelId !== stash.iModelId) {
284
- throw new StashError(`Stash does not belong to this iModel`);
290
+ StashError.throwError("invalid-stash", `Stash does not belong to this iModel`);
285
291
  }
286
292
  if (db.briefcaseId !== stash.briefcaseId) {
287
- throw new StashError(`Stash does not belong to this briefcase`);
293
+ StashError.throwError("invalid-stash", `Stash does not belong to this briefcase`);
288
294
  }
289
295
  const stashFile = this.getStashFilePath({ db, stash });
290
296
  // we need to retain lock that overlapped with stash locks instead of all locks
@@ -1 +1 @@
1
- {"version":3,"file":"StashManager.js","sourceRoot":"","sources":["../../src/StashManager.ts"],"names":[],"mappings":"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","sourcesContent":["import { DbResult, GuidString, Id64Array, Id64String, Logger, OpenMode } from \"@itwin/core-bentley\";\r\nimport { ChangesetIdWithIndex, LocalDirName, LockState } from \"@itwin/core-common\";\r\nimport { existsSync, mkdirSync, readdirSync, statSync, unlinkSync } from \"node:fs\";\r\nimport * as path from \"node:path\";\r\nimport { BriefcaseManager } from \"./BriefcaseManager\";\r\nimport { BriefcaseDb } from \"./IModelDb\";\r\nimport { _elementWasCreated, _getHubAccess, _hubAccess, _nativeDb, _resetIModelDb } from \"./internal/Symbols\";\r\nimport { SQLiteDb } from \"./SQLiteDb\";\r\nimport { TxnProps } from \"./TxnManager\";\r\nimport { IModelHost } from \"./IModelHost\";\r\nimport { BackendLoggerCategory } from \"./BackendLoggerCategory\";\r\n\r\nconst loggerCategory = BackendLoggerCategory.StashManager;\r\n\r\n/**\r\n * Custom error class for stash-related errors.\r\n * @internal\r\n */\r\nexport class StashError extends Error {\r\n constructor(message: string) {\r\n super(message);\r\n this.name = \"StashError\";\r\n Logger.logError(loggerCategory, message);\r\n }\r\n}\r\n\r\n/**\r\n * Properties of a stash\r\n * @internal\r\n */\r\nexport interface StashProps {\r\n /** Unique identifier for the stash */\r\n readonly id: GuidString;\r\n\r\n /** ID of the iModel being stashed */\r\n readonly iModelId: GuidString;\r\n\r\n /** ID of the briefcase being stashed */\r\n readonly briefcaseId: number;\r\n\r\n /** ISO local Timestamp of the stash */\r\n readonly timestamp: string;\r\n\r\n /** Description of the stash */\r\n readonly description: string;\r\n\r\n /** Hash of the stash */\r\n readonly hash: string;\r\n\r\n /** Parent changeset of the stash */\r\n readonly parentChangeset: ChangesetIdWithIndex;\r\n\r\n /** ID sequences for the stash */\r\n readonly idSequences: {\r\n element: Id64String;\r\n instance: Id64String;\r\n };\r\n\r\n /** Transaction properties for the stash */\r\n readonly txns: TxnProps[];\r\n\r\n /** Number of locks acquired by the stash */\r\n readonly acquiredLocks: number;\r\n}\r\n\r\n/**\r\n * Properties for creating a stash\r\n * @internal\r\n */\r\nexport interface CreateStashProps {\r\n /** Briefcase database instance */\r\n readonly db: BriefcaseDb;\r\n /** description of the stash */\r\n readonly description: string;\r\n /** discard all local changes and unless retainLocks flag is set, all locks will be released */\r\n readonly discardLocalChanges?: true;\r\n /** retains all locks after discarding local changes */\r\n readonly retainLocks?: true;\r\n}\r\n\r\n/**\r\n * Arguments for stash operations\r\n * @internal\r\n */\r\nexport interface StashArgs {\r\n readonly db: BriefcaseDb;\r\n readonly stash: Id64String | StashProps;\r\n}\r\n\r\nenum LockOrigin {\r\n Acquired = 0,\r\n NewElement = 1,\r\n Discovered = 2,\r\n};\r\n\r\n/**\r\n * Stash manager allow stash, drop, apply and merge stashes\r\n * @internal\r\n */\r\nexport class StashManager {\r\n\r\n private static readonly STASHES_ROOT_DIR_NAME: string = \".stashes\";\r\n /**\r\n * Retrieves the root folder path for stash files associated with the specified BriefcaseDb.\r\n *\r\n * @param db - The BriefcaseDb instance for which to determine the stash root folder.\r\n * @param ensureExists - If true, the stash root directory will be created if it does not already exist.\r\n * @returns The absolute path to the stash root directory.\r\n */\r\n private static getStashRootFolder(db: BriefcaseDb, ensureExists: boolean): LocalDirName {\r\n if (!db.isOpen || db.isReadonly)\r\n throw new StashError(\"Database is not open or is readonly\");\r\n\r\n if (!existsSync(db[_nativeDb].getFilePath())) {\r\n throw new StashError(\"Could not determine briefcase path\");\r\n }\r\n\r\n const stashDir = path.join(path.dirname(db[_nativeDb].getFilePath()), this.STASHES_ROOT_DIR_NAME, `${db.briefcaseId}`);\r\n if (ensureExists && !existsSync(stashDir)) {\r\n mkdirSync(stashDir, { recursive: true });\r\n }\r\n return stashDir;\r\n }\r\n\r\n /**\r\n * Retrieves the stash ID from the provided arguments.\r\n *\r\n * If the `stash` property of `args` is a string, it returns the string in lowercase.\r\n * If the `stash` property is an object, it returns the `id` property of the object in lowercase.\r\n *\r\n * @param args - The arguments containing the stash information, which can be either a string or an object with an `id` property.\r\n * @returns The stash ID as a lowercase string.\r\n */\r\n private static getStashId(args: StashArgs) {\r\n return (typeof args.stash === \"string\" ? args.stash : args.stash.id).toLowerCase();\r\n }\r\n\r\n /**\r\n * Retrieves the file path to the stash file associated with the provided arguments.\r\n *\r\n * @param args - The arguments required to identify the stash, including the database reference.\r\n * @returns The absolute path to the stash file.\r\n */\r\n private static getStashFilePath(args: StashArgs) {\r\n const stashRoot = this.getStashRootFolder(args.db, false);\r\n if (!existsSync(stashRoot)) {\r\n throw new StashError(\"Invalid stash\");\r\n }\r\n\r\n const stashFilePath = path.join(stashRoot, `${this.getStashId(args)}.stash`);\r\n if (!existsSync(stashFilePath)) {\r\n throw new StashError(\"Invalid stash\");\r\n }\r\n return stashFilePath;\r\n }\r\n\r\n /**\r\n * Queries the stash database for lock IDs matching the specified state and origin.\r\n *\r\n * @param args - The arguments required to access the stash database.\r\n * @param state - The lock state to filter by.\r\n * @param origin - The lock origin to filter by.\r\n * @returns An array of lock IDs (`Id64Array`) that match the given state and origin.\r\n */\r\n private static queryLocks(args: StashArgs, state: LockState, origin: LockOrigin): Id64Array {\r\n return this.withStash(args, (stashDb) => {\r\n const query = `SELECT JSON_GROUP_ARRAY(FORMAT('0x%x', Id)) FROM [locks] WHERE State = ${state} AND origin = ${origin}`;\r\n return stashDb.withPreparedSqliteStatement(query, (stmt) => {\r\n if (stmt.step() === DbResult.BE_SQLITE_ROW) {\r\n return JSON.parse(stmt.getValueString(0)) as Id64Array;\r\n }\r\n return [];\r\n });\r\n });\r\n }\r\n\r\n /**\r\n * Acquire locks for the specified stash. If this fail then stash should not be applied.\r\n * @param args The stash arguments.\r\n */\r\n private static async acquireLocks(args: StashArgs) {\r\n const shared = this.queryLocks(args, LockState.Shared, LockOrigin.Acquired);\r\n await args.db.locks.acquireLocks({ shared });\r\n\r\n const exclusive = this.queryLocks(args, LockState.Exclusive, LockOrigin.Acquired);\r\n await args.db.locks.acquireLocks({ exclusive });\r\n\r\n const newElements = this.queryLocks(args, LockState.Shared, LockOrigin.NewElement);\r\n for (const id of newElements) {\r\n if (!args.db.locks.holdsExclusiveLock(id)) {\r\n args.db.locks[_elementWasCreated](id);\r\n }\r\n }\r\n }\r\n /**\r\n * Creates a stash of changes for the specified briefcase.\r\n *\r\n * This method generates a stash in the stash root directory for the given briefcase, using the provided description and iModelId.\r\n * Optionally, it can reset the briefcase by releasing all locks after stashing.\r\n *\r\n * @param args - The properties required to create a stash, including the briefcase, description, iModelId, and an optional resetBriefcase flag.\r\n * @returns A promise that resolves to the properties of the created stash.\r\n */\r\n public static async stash(args: CreateStashProps): Promise<StashProps> {\r\n if (!args.db.txns.hasPendingTxns) {\r\n throw new StashError(\"nothing to stash\");\r\n }\r\n\r\n if (args.db.txns.hasUnsavedChanges) {\r\n throw new StashError(\"Unsaved changes exist\");\r\n }\r\n\r\n if (args.db.txns.hasPendingSchemaChanges) {\r\n throw new StashError(\"Pending schema changeset. Stashing is not currently supported for schema changes\");\r\n }\r\n\r\n const stashRootDir = this.getStashRootFolder(args.db, true);\r\n const iModelId = args.db.iModelId;\r\n const stash = args.db[_nativeDb].stashChanges({ stashRootDir, description: args.description, iModelId }) as StashProps;\r\n if (args.discardLocalChanges) {\r\n await args.db.discardChanges({ retainLocks: args.retainLocks });\r\n }\r\n\r\n Logger.logInfo(loggerCategory, `Stashed changes`, () => stash);\r\n return stash;\r\n }\r\n\r\n /**\r\n * Retrieves the stash properties from the database for the given arguments.\r\n *\r\n * @param args - The arguments required to locate and access the stash.\r\n * @returns The stash file properties if found; otherwise, `undefined`.\r\n */\r\n public static tryGetStash(args: StashArgs): StashProps | undefined {\r\n try {\r\n return this.getStash(args);\r\n } catch (error: any) {\r\n Logger.logError(loggerCategory, `Error getting stash with ${this.getStashId(args)}: ${error.message}`);\r\n }\r\n return undefined;\r\n }\r\n\r\n /**\r\n * Retrieves the stash properties from the database using the provided arguments.\r\n *\r\n * @param args - The arguments required to access the stash.\r\n * @returns The stash properties parsed from the database.\r\n */\r\n public static getStash(args: StashArgs): StashProps {\r\n return this.withStash(args, (stashDb) => {\r\n const stashProps = stashDb.withPreparedSqliteStatement(\"SELECT [val] FROM [be_Local] WHERE [name]='$stash_info'\", (stmt) => {\r\n if (stmt.step() !== DbResult.BE_SQLITE_ROW)\r\n throw new StashError(\"Invalid stash\");\r\n return JSON.parse(stmt.getValueString(0)) as StashProps;\r\n });\r\n return stashProps;\r\n });\r\n }\r\n\r\n /**\r\n * Executes a callback function with a read-only SQLite database connection to a stash file.\r\n *\r\n * @typeParam T - The return type of the callback function.\r\n * @param args - Arguments required to determine the stash file path.\r\n * @param callback - A function that receives an open {@link SQLiteDb} instance connected to the stash file.\r\n * @returns The value returned by the callback function.\r\n */\r\n private static withStash<T>(args: StashArgs, callback: (stashDb: SQLiteDb) => T): T {\r\n const stashFile = this.getStashFilePath(args);\r\n if (!existsSync(stashFile)) {\r\n throw new StashError(\"Invalid stash\");\r\n }\r\n\r\n const stashDb = new SQLiteDb();\r\n stashDb.openDb(stashFile, OpenMode.Readonly);\r\n try {\r\n return callback(stashDb);\r\n } finally {\r\n stashDb.closeDb();\r\n }\r\n }\r\n\r\n /**\r\n * Retrieves all stash files associated with the specified {@link BriefcaseDb}.\r\n * @param db - The {@link BriefcaseDb} instance for which to retrieve stash files.\r\n * @returns An array of `StashProps` representing the found stash files, sorted by timestamp.\r\n */\r\n public static getStashes(db: BriefcaseDb): StashProps[] {\r\n const stashes: StashProps[] = [];\r\n const stashDir = this.getStashRootFolder(db, false);\r\n if (!existsSync(stashDir)) {\r\n return stashes;\r\n }\r\n readdirSync(stashDir).filter((file) => {\r\n const filePath = path.join(stashDir, file);\r\n if (existsSync(filePath) && statSync(filePath).isFile() && file.endsWith(\".stash\")) {\r\n const id = file.slice(0, -path.extname(file).length)\r\n const stash = this.tryGetStash({ db, stash: id });\r\n if (stash) {\r\n stashes.push(stash);\r\n }\r\n }\r\n });\r\n stashes.sort((a, b) => Date.parse(b.timestamp) - Date.parse(a.timestamp));\r\n return stashes;\r\n }\r\n\r\n /**\r\n * Deletes the stash file associated with the specified stash ID or properties from the given {@link BriefcaseDb}.\r\n *\r\n * @param db - The {@link BriefcaseDb} instance from which the stash should be dropped.\r\n * @param stashId - The unique identifier (GuidString) or properties (StashProps) of the stash to be deleted.\r\n * @returns Returns `true` if the stash file was successfully deleted, otherwise returns `false`.\r\n */\r\n public static dropStash(args: StashArgs): boolean {\r\n try {\r\n const stashFile = this.getStashFilePath(args);\r\n unlinkSync(stashFile);\r\n return true;\r\n } catch (error: any) {\r\n Logger.logError(loggerCategory, `Error dropping stash: ${error}`);\r\n }\r\n return false;\r\n }\r\n\r\n /**\r\n * Removes all stashes associated with the specified {@link BriefcaseDb}.\r\n *\r\n * @param db - The {@link BriefcaseDb} instance from which all stashes will be removed.\r\n */\r\n public static dropAllStashes(db: BriefcaseDb): void {\r\n this.getStashes(db).forEach((stash) => {\r\n this.dropStash({ db, stash });\r\n });\r\n }\r\n\r\n /**\r\n * Queries the hub for the changeset information associated with the given stash.\r\n *\r\n * @param args - The arguments including the stash properties.\r\n * @returns A promise resolving to the changeset ID and index.\r\n */\r\n private static async queryChangeset(args: StashArgs & { stash: StashProps }): Promise<ChangesetIdWithIndex> {\r\n return IModelHost[_hubAccess].queryChangeset({\r\n iModelId: args.stash.iModelId,\r\n changeset: args.stash.parentChangeset,\r\n accessToken: await IModelHost.getAccessToken()\r\n });\r\n }\r\n /**\r\n * Restores the specified stash to the given {@link BriefcaseDb}. This operation will discard any local changes made to db and reverse the tip to the state of the stash and then apply stash. This will restore the undo stack.\r\n *\r\n * @param args - The arguments including the target database and stash properties.\r\n */\r\n public static async restore(args: StashArgs): Promise<void> {\r\n const { db } = args;\r\n Logger.logInfo(loggerCategory, `Restoring stash: ${this.getStashId(args)}`);\r\n\r\n const stash = this.tryGetStash(args);\r\n if (!stash) {\r\n throw new StashError(`Stash not found ${this.getStashId(args)}`);\r\n }\r\n\r\n if (db.txns.hasUnsavedChanges) {\r\n throw new StashError(`Unsaved changes present`);\r\n }\r\n\r\n if (db.iModelId !== stash.iModelId) {\r\n throw new StashError(`Stash does not belong to this iModel`);\r\n }\r\n\r\n if (db.briefcaseId !== stash.briefcaseId) {\r\n throw new StashError(`Stash does not belong to this briefcase`);\r\n }\r\n\r\n const stashFile = this.getStashFilePath({ db, stash });\r\n // we need to retain lock that overlapped with stash locks instead of all locks\r\n await db.discardChanges({ retainLocks: true });\r\n await this.acquireLocks(args);\r\n if (db.changeset.id !== stash.parentChangeset.id) {\r\n // Changeset ID mismatch\r\n Logger.logWarning(loggerCategory, \"Changeset ID mismatch\");\r\n const stashChangeset = await this.queryChangeset({ db, stash });\r\n await BriefcaseManager.pullAndApplyChangesets(db, { toIndex: stashChangeset.index });\r\n }\r\n\r\n db[_nativeDb].stashRestore(stashFile);\r\n db[_resetIModelDb]();\r\n db.saveChanges();\r\n Logger.logInfo(loggerCategory, `Restored stash: ${this.getStashId(args)}`);\r\n }\r\n}\r\n"]}
1
+ {"version":3,"file":"StashManager.js","sourceRoot":"","sources":["../../src/StashManager.ts"],"names":[],"mappings":"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","sourcesContent":["import { DbResult, GuidString, Id64Array, Id64String, ITwinError, Logger, OpenMode } from \"@itwin/core-bentley\";\r\nimport { ChangesetIdWithIndex, LocalDirName, LockState } from \"@itwin/core-common\";\r\nimport { existsSync, mkdirSync, readdirSync, statSync, unlinkSync } from \"node:fs\";\r\nimport * as path from \"node:path\";\r\nimport { BriefcaseManager } from \"./BriefcaseManager\";\r\nimport { BriefcaseDb } from \"./IModelDb\";\r\nimport { _elementWasCreated, _getHubAccess, _hubAccess, _nativeDb, _resetIModelDb } from \"./internal/Symbols\";\r\nimport { SQLiteDb } from \"./SQLiteDb\";\r\nimport { TxnProps } from \"./TxnManager\";\r\nimport { IModelHost } from \"./IModelHost\";\r\nimport { BackendLoggerCategory } from \"./BackendLoggerCategory\";\r\n\r\nconst loggerCategory = BackendLoggerCategory.StashManager;\r\n\r\n/**\r\n * Properties of a stash\r\n * @internal\r\n */\r\nexport interface StashProps {\r\n /** Unique identifier for the stash */\r\n readonly id: GuidString;\r\n\r\n /** ID of the iModel being stashed */\r\n readonly iModelId: GuidString;\r\n\r\n /** ID of the briefcase being stashed */\r\n readonly briefcaseId: number;\r\n\r\n /** ISO local Timestamp of the stash */\r\n readonly timestamp: string;\r\n\r\n /** Description of the stash */\r\n readonly description: string;\r\n\r\n /** Hash of the stash */\r\n readonly hash: string;\r\n\r\n /** Parent changeset of the stash */\r\n readonly parentChangeset: ChangesetIdWithIndex;\r\n\r\n /** ID sequences for the stash */\r\n readonly idSequences: {\r\n element: Id64String;\r\n instance: Id64String;\r\n };\r\n\r\n /** Transaction properties for the stash */\r\n readonly txns: TxnProps[];\r\n\r\n /** Number of locks acquired by the stash */\r\n readonly acquiredLocks: number;\r\n}\r\n\r\n/**\r\n * Properties for creating a stash\r\n * @internal\r\n */\r\nexport interface CreateStashProps {\r\n /** Briefcase database instance */\r\n readonly db: BriefcaseDb;\r\n /** description of the stash */\r\n readonly description: string;\r\n /** discard all local changes and unless retainLocks flag is set, all locks will be released */\r\n readonly discardLocalChanges?: true;\r\n /** retains all locks after discarding local changes */\r\n readonly retainLocks?: true;\r\n}\r\n\r\n/**\r\n * Arguments for stash operations\r\n * @internal\r\n */\r\nexport interface StashArgs {\r\n readonly db: BriefcaseDb;\r\n readonly stash: Id64String | StashProps;\r\n}\r\n\r\nenum LockOrigin {\r\n Acquired = 0,\r\n NewElement = 1,\r\n Discovered = 2,\r\n};\r\n\r\n/**\r\n * An error originating from the StashManager API.\r\n * @internal\r\n */\r\nexport namespace StashError {\r\n export const scope = \"itwin-StashManager\";\r\n export type Key =\r\n \"readonly\" |\r\n \"no-file\" |\r\n \"no-stashes\" |\r\n \"invalid-stash\" |\r\n \"nothing-to-stash\" |\r\n \"unsaved-changes\" |\r\n \"pending-schema-changes\" |\r\n \"stash-not-found\";\r\n\r\n /** Instantiate and throw a StashError */\r\n export function throwError(key: Key, message: string): never {\r\n ITwinError.throwError<ITwinError>({ iTwinErrorId: { scope, key }, message });\r\n }\r\n /** Determine whether an error object is a StashError */\r\n export function isError(error: unknown, key?: Key): error is ITwinError {\r\n return ITwinError.isError<ITwinError>(error, scope, key);\r\n }\r\n}\r\n\r\n/**\r\n * Stash manager allow stash, drop, apply and merge stashes\r\n * @internal\r\n */\r\nexport class StashManager {\r\n\r\n private static readonly STASHES_ROOT_DIR_NAME: string = \".stashes\";\r\n /**\r\n * Retrieves the root folder path for stash files associated with the specified BriefcaseDb.\r\n *\r\n * @param db - The BriefcaseDb instance for which to determine the stash root folder.\r\n * @param ensureExists - If true, the stash root directory will be created if it does not already exist.\r\n * @returns The absolute path to the stash root directory.\r\n */\r\n private static getStashRootFolder(db: BriefcaseDb, ensureExists: boolean): LocalDirName {\r\n if (!db.isOpen || db.isReadonly)\r\n StashError.throwError(\"readonly\", \"Database is not open or is readonly\");\r\n\r\n if (!existsSync(db[_nativeDb].getFilePath())) {\r\n StashError.throwError(\"no-file\", \"Database file does not exist\");\r\n }\r\n\r\n const stashDir = path.join(path.dirname(db[_nativeDb].getFilePath()), this.STASHES_ROOT_DIR_NAME, `${db.briefcaseId}`);\r\n if (ensureExists && !existsSync(stashDir)) {\r\n mkdirSync(stashDir, { recursive: true });\r\n }\r\n return stashDir;\r\n }\r\n\r\n /**\r\n * Retrieves the stash ID from the provided arguments.\r\n *\r\n * If the `stash` property of `args` is a string, it returns the string in lowercase.\r\n * If the `stash` property is an object, it returns the `id` property of the object in lowercase.\r\n *\r\n * @param args - The arguments containing the stash information, which can be either a string or an object with an `id` property.\r\n * @returns The stash ID as a lowercase string.\r\n */\r\n private static getStashId(args: StashArgs) {\r\n return (typeof args.stash === \"string\" ? args.stash : args.stash.id).toLowerCase();\r\n }\r\n\r\n /**\r\n * Retrieves the file path to the stash file associated with the provided arguments.\r\n *\r\n * @param args - The arguments required to identify the stash, including the database reference.\r\n * @returns The absolute path to the stash file.\r\n */\r\n private static getStashFilePath(args: StashArgs) {\r\n const stashRoot = this.getStashRootFolder(args.db, false);\r\n if (!existsSync(stashRoot)) {\r\n StashError.throwError(\"no-stashes\", \"No stashes exist for this briefcase\");\r\n }\r\n\r\n const stashFilePath = path.join(stashRoot, `${this.getStashId(args)}.stash`);\r\n if (!existsSync(stashFilePath)) {\r\n StashError.throwError(\"invalid-stash\", \"Invalid stash\");\r\n }\r\n return stashFilePath;\r\n }\r\n\r\n /**\r\n * Queries the stash database for lock IDs matching the specified state and origin.\r\n *\r\n * @param args - The arguments required to access the stash database.\r\n * @param state - The lock state to filter by.\r\n * @param origin - The lock origin to filter by.\r\n * @returns An array of lock IDs (`Id64Array`) that match the given state and origin.\r\n */\r\n private static queryLocks(args: StashArgs, state: LockState, origin: LockOrigin): Id64Array {\r\n return this.withStash(args, (stashDb) => {\r\n const query = `SELECT JSON_GROUP_ARRAY(FORMAT('0x%x', Id)) FROM [locks] WHERE State = ${state} AND origin = ${origin}`;\r\n return stashDb.withPreparedSqliteStatement(query, (stmt) => {\r\n if (stmt.step() === DbResult.BE_SQLITE_ROW) {\r\n return JSON.parse(stmt.getValueString(0)) as Id64Array;\r\n }\r\n return [];\r\n });\r\n });\r\n }\r\n\r\n /**\r\n * Acquire locks for the specified stash. If this fail then stash should not be applied.\r\n * @param args The stash arguments.\r\n */\r\n private static async acquireLocks(args: StashArgs) {\r\n const shared = this.queryLocks(args, LockState.Shared, LockOrigin.Acquired);\r\n await args.db.locks.acquireLocks({ shared });\r\n\r\n const exclusive = this.queryLocks(args, LockState.Exclusive, LockOrigin.Acquired);\r\n await args.db.locks.acquireLocks({ exclusive });\r\n\r\n const newElements = this.queryLocks(args, LockState.Shared, LockOrigin.NewElement);\r\n for (const id of newElements) {\r\n if (!args.db.locks.holdsExclusiveLock(id)) {\r\n args.db.locks[_elementWasCreated](id);\r\n }\r\n }\r\n }\r\n /**\r\n * Creates a stash of changes for the specified briefcase.\r\n *\r\n * This method generates a stash in the stash root directory for the given briefcase, using the provided description and iModelId.\r\n * Optionally, it can reset the briefcase by releasing all locks after stashing.\r\n *\r\n * @param args - The properties required to create a stash, including the briefcase, description, iModelId, and an optional resetBriefcase flag.\r\n * @returns A promise that resolves to the properties of the created stash.\r\n */\r\n public static async stash(args: CreateStashProps): Promise<StashProps> {\r\n if (!args.db.txns.hasPendingTxns) {\r\n StashError.throwError(\"nothing-to-stash\", \"Nothing to stash\");\r\n }\r\n\r\n if (args.db.txns.hasUnsavedChanges) {\r\n StashError.throwError(\"unsaved-changes\", \"Unsaved changes exist\");\r\n }\r\n\r\n if (args.db.txns.hasPendingSchemaChanges) {\r\n StashError.throwError(\"pending-schema-changes\", \"Pending schema changeset. Stashing is not currently supported for schema changes\");\r\n }\r\n\r\n const stashRootDir = this.getStashRootFolder(args.db, true);\r\n const iModelId = args.db.iModelId;\r\n const stash = args.db[_nativeDb].stashChanges({ stashRootDir, description: args.description, iModelId }) as StashProps;\r\n if (args.discardLocalChanges) {\r\n await args.db.discardChanges({ retainLocks: args.retainLocks });\r\n }\r\n\r\n Logger.logInfo(loggerCategory, `Stashed changes`, () => stash);\r\n return stash;\r\n }\r\n\r\n /**\r\n * Retrieves the stash properties from the database for the given arguments.\r\n *\r\n * @param args - The arguments required to locate and access the stash.\r\n * @returns The stash file properties if found; otherwise, `undefined`.\r\n */\r\n public static tryGetStash(args: StashArgs): StashProps | undefined {\r\n try {\r\n return this.getStash(args);\r\n } catch (error: any) {\r\n Logger.logError(loggerCategory, `Error getting stash with ${this.getStashId(args)}: ${error.message}`);\r\n }\r\n return undefined;\r\n }\r\n\r\n /**\r\n * Retrieves the stash properties from the database using the provided arguments.\r\n *\r\n * @param args - The arguments required to access the stash.\r\n * @returns The stash properties parsed from the database.\r\n */\r\n public static getStash(args: StashArgs): StashProps {\r\n return this.withStash(args, (stashDb) => {\r\n const stashProps = stashDb.withPreparedSqliteStatement(\"SELECT [val] FROM [be_Local] WHERE [name]='$stash_info'\", (stmt) => {\r\n if (stmt.step() !== DbResult.BE_SQLITE_ROW)\r\n StashError.throwError(\"invalid-stash\", \"Invalid stash\");\r\n return JSON.parse(stmt.getValueString(0)) as StashProps;\r\n });\r\n return stashProps;\r\n });\r\n }\r\n\r\n /**\r\n * Executes a callback function with a read-only SQLite database connection to a stash file.\r\n *\r\n * @typeParam T - The return type of the callback function.\r\n * @param args - Arguments required to determine the stash file path.\r\n * @param callback - A function that receives an open {@link SQLiteDb} instance connected to the stash file.\r\n * @returns The value returned by the callback function.\r\n */\r\n private static withStash<T>(args: StashArgs, callback: (stashDb: SQLiteDb) => T): T {\r\n const stashFile = this.getStashFilePath(args);\r\n if (!existsSync(stashFile)) {\r\n StashError.throwError(\"invalid-stash\", \"Invalid stash\");\r\n }\r\n\r\n const stashDb = new SQLiteDb();\r\n stashDb.openDb(stashFile, OpenMode.Readonly);\r\n try {\r\n return callback(stashDb);\r\n } finally {\r\n stashDb.closeDb();\r\n }\r\n }\r\n\r\n /**\r\n * Retrieves all stash files associated with the specified {@link BriefcaseDb}.\r\n * @param db - The {@link BriefcaseDb} instance for which to retrieve stash files.\r\n * @returns An array of `StashProps` representing the found stash files, sorted by timestamp.\r\n */\r\n public static getStashes(db: BriefcaseDb): StashProps[] {\r\n const stashes: StashProps[] = [];\r\n const stashDir = this.getStashRootFolder(db, false);\r\n if (!existsSync(stashDir)) {\r\n return stashes;\r\n }\r\n readdirSync(stashDir).filter((file) => {\r\n const filePath = path.join(stashDir, file);\r\n if (existsSync(filePath) && statSync(filePath).isFile() && file.endsWith(\".stash\")) {\r\n const id = file.slice(0, -path.extname(file).length)\r\n const stash = this.tryGetStash({ db, stash: id });\r\n if (stash) {\r\n stashes.push(stash);\r\n }\r\n }\r\n });\r\n stashes.sort((a, b) => Date.parse(b.timestamp) - Date.parse(a.timestamp));\r\n return stashes;\r\n }\r\n\r\n /**\r\n * Deletes the stash file associated with the specified stash ID or properties from the given {@link BriefcaseDb}.\r\n *\r\n * @param db - The {@link BriefcaseDb} instance from which the stash should be dropped.\r\n * @param stashId - The unique identifier (GuidString) or properties (StashProps) of the stash to be deleted.\r\n * @returns Returns `true` if the stash file was successfully deleted, otherwise returns `false`.\r\n */\r\n public static dropStash(args: StashArgs): boolean {\r\n try {\r\n const stashFile = this.getStashFilePath(args);\r\n unlinkSync(stashFile);\r\n return true;\r\n } catch (error: any) {\r\n Logger.logError(loggerCategory, `Error dropping stash: ${error}`);\r\n }\r\n return false;\r\n }\r\n\r\n /**\r\n * Removes all stashes associated with the specified {@link BriefcaseDb}.\r\n *\r\n * @param db - The {@link BriefcaseDb} instance from which all stashes will be removed.\r\n */\r\n public static dropAllStashes(db: BriefcaseDb): void {\r\n this.getStashes(db).forEach((stash) => {\r\n this.dropStash({ db, stash });\r\n });\r\n }\r\n\r\n /**\r\n * Queries the hub for the changeset information associated with the given stash.\r\n *\r\n * @param args - The arguments including the stash properties.\r\n * @returns A promise resolving to the changeset ID and index.\r\n */\r\n private static async queryChangeset(args: StashArgs & { stash: StashProps }): Promise<ChangesetIdWithIndex> {\r\n return IModelHost[_hubAccess].queryChangeset({\r\n iModelId: args.stash.iModelId,\r\n changeset: args.stash.parentChangeset,\r\n accessToken: await IModelHost.getAccessToken()\r\n });\r\n }\r\n /**\r\n * Restores the specified stash to the given {@link BriefcaseDb}. This operation will discard any local changes made to db and reverse the tip to the state of the stash and then apply stash. This will restore the undo stack.\r\n *\r\n * @param args - The arguments including the target database and stash properties.\r\n */\r\n public static async restore(args: StashArgs): Promise<void> {\r\n const { db } = args;\r\n Logger.logInfo(loggerCategory, `Restoring stash: ${this.getStashId(args)}`);\r\n\r\n const stash = this.tryGetStash(args);\r\n if (!stash) {\r\n StashError.throwError(\"stash-not-found\", `Stash not found ${this.getStashId(args)}`);\r\n }\r\n\r\n if (db.txns.hasUnsavedChanges) {\r\n StashError.throwError(\"unsaved-changes\", `Unsaved changes are present.`);\r\n }\r\n\r\n if (db.iModelId !== stash.iModelId) {\r\n StashError.throwError(\"invalid-stash\", `Stash does not belong to this iModel`);\r\n }\r\n\r\n if (db.briefcaseId !== stash.briefcaseId) {\r\n StashError.throwError(\"invalid-stash\", `Stash does not belong to this briefcase`);\r\n }\r\n\r\n const stashFile = this.getStashFilePath({ db, stash });\r\n // we need to retain lock that overlapped with stash locks instead of all locks\r\n await db.discardChanges({ retainLocks: true });\r\n await this.acquireLocks(args);\r\n if (db.changeset.id !== stash.parentChangeset.id) {\r\n // Changeset ID mismatch\r\n Logger.logWarning(loggerCategory, \"Changeset ID mismatch\");\r\n const stashChangeset = await this.queryChangeset({ db, stash });\r\n await BriefcaseManager.pullAndApplyChangesets(db, { toIndex: stashChangeset.index });\r\n }\r\n\r\n db[_nativeDb].stashRestore(stashFile);\r\n db[_resetIModelDb]();\r\n db.saveChanges();\r\n Logger.logInfo(loggerCategory, `Restored stash: ${this.getStashId(args)}`);\r\n }\r\n}\r\n"]}
@@ -1,14 +1,7 @@
1
- import { GuidString, Id64String } from "@itwin/core-bentley";
1
+ import { GuidString, Id64String, ITwinError } from "@itwin/core-bentley";
2
2
  import { ChangesetIdWithIndex } from "@itwin/core-common";
3
3
  import { BriefcaseDb } from "./IModelDb";
4
4
  import { TxnProps } from "./TxnManager";
5
- /**
6
- * Custom error class for stash-related errors.
7
- * @internal
8
- */
9
- export declare class StashError extends Error {
10
- constructor(message: string);
11
- }
12
5
  /**
13
6
  * Properties of a stash
14
7
  * @internal
@@ -60,6 +53,18 @@ export interface StashArgs {
60
53
  readonly db: BriefcaseDb;
61
54
  readonly stash: Id64String | StashProps;
62
55
  }
56
+ /**
57
+ * An error originating from the StashManager API.
58
+ * @internal
59
+ */
60
+ export declare namespace StashError {
61
+ const scope = "itwin-StashManager";
62
+ type Key = "readonly" | "no-file" | "no-stashes" | "invalid-stash" | "nothing-to-stash" | "unsaved-changes" | "pending-schema-changes" | "stash-not-found";
63
+ /** Instantiate and throw a StashError */
64
+ function throwError(key: Key, message: string): never;
65
+ /** Determine whether an error object is a StashError */
66
+ function isError(error: unknown, key?: Key): error is ITwinError;
67
+ }
63
68
  /**
64
69
  * Stash manager allow stash, drop, apply and merge stashes
65
70
  * @internal
@@ -1 +1 @@
1
- {"version":3,"file":"StashManager.d.ts","sourceRoot":"","sources":["../../src/StashManager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"StashManager.d.ts","sourceRoot":"","sources":["../../src/StashManager.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { DbResult, Logger, OpenMode } from "@itwin/core-bentley";
1
+ import { DbResult, ITwinError, Logger, OpenMode } from "@itwin/core-bentley";
2
2
  import { LockState } from "@itwin/core-common";
3
3
  import { existsSync, mkdirSync, readdirSync, statSync, unlinkSync } from "node:fs";
4
4
  import * as path from "node:path";
@@ -8,17 +8,6 @@ import { SQLiteDb } from "./SQLiteDb";
8
8
  import { IModelHost } from "./IModelHost";
9
9
  import { BackendLoggerCategory } from "./BackendLoggerCategory";
10
10
  const loggerCategory = BackendLoggerCategory.StashManager;
11
- /**
12
- * Custom error class for stash-related errors.
13
- * @internal
14
- */
15
- export class StashError extends Error {
16
- constructor(message) {
17
- super(message);
18
- this.name = "StashError";
19
- Logger.logError(loggerCategory, message);
20
- }
21
- }
22
11
  var LockOrigin;
23
12
  (function (LockOrigin) {
24
13
  LockOrigin[LockOrigin["Acquired"] = 0] = "Acquired";
@@ -26,6 +15,24 @@ var LockOrigin;
26
15
  LockOrigin[LockOrigin["Discovered"] = 2] = "Discovered";
27
16
  })(LockOrigin || (LockOrigin = {}));
28
17
  ;
18
+ /**
19
+ * An error originating from the StashManager API.
20
+ * @internal
21
+ */
22
+ export var StashError;
23
+ (function (StashError) {
24
+ StashError.scope = "itwin-StashManager";
25
+ /** Instantiate and throw a StashError */
26
+ function throwError(key, message) {
27
+ ITwinError.throwError({ iTwinErrorId: { scope: StashError.scope, key }, message });
28
+ }
29
+ StashError.throwError = throwError;
30
+ /** Determine whether an error object is a StashError */
31
+ function isError(error, key) {
32
+ return ITwinError.isError(error, StashError.scope, key);
33
+ }
34
+ StashError.isError = isError;
35
+ })(StashError || (StashError = {}));
29
36
  /**
30
37
  * Stash manager allow stash, drop, apply and merge stashes
31
38
  * @internal
@@ -41,9 +48,9 @@ export class StashManager {
41
48
  */
42
49
  static getStashRootFolder(db, ensureExists) {
43
50
  if (!db.isOpen || db.isReadonly)
44
- throw new StashError("Database is not open or is readonly");
51
+ StashError.throwError("readonly", "Database is not open or is readonly");
45
52
  if (!existsSync(db[_nativeDb].getFilePath())) {
46
- throw new StashError("Could not determine briefcase path");
53
+ StashError.throwError("no-file", "Database file does not exist");
47
54
  }
48
55
  const stashDir = path.join(path.dirname(db[_nativeDb].getFilePath()), this.STASHES_ROOT_DIR_NAME, `${db.briefcaseId}`);
49
56
  if (ensureExists && !existsSync(stashDir)) {
@@ -72,11 +79,11 @@ export class StashManager {
72
79
  static getStashFilePath(args) {
73
80
  const stashRoot = this.getStashRootFolder(args.db, false);
74
81
  if (!existsSync(stashRoot)) {
75
- throw new StashError("Invalid stash");
82
+ StashError.throwError("no-stashes", "No stashes exist for this briefcase");
76
83
  }
77
84
  const stashFilePath = path.join(stashRoot, `${this.getStashId(args)}.stash`);
78
85
  if (!existsSync(stashFilePath)) {
79
- throw new StashError("Invalid stash");
86
+ StashError.throwError("invalid-stash", "Invalid stash");
80
87
  }
81
88
  return stashFilePath;
82
89
  }
@@ -126,13 +133,13 @@ export class StashManager {
126
133
  */
127
134
  static async stash(args) {
128
135
  if (!args.db.txns.hasPendingTxns) {
129
- throw new StashError("nothing to stash");
136
+ StashError.throwError("nothing-to-stash", "Nothing to stash");
130
137
  }
131
138
  if (args.db.txns.hasUnsavedChanges) {
132
- throw new StashError("Unsaved changes exist");
139
+ StashError.throwError("unsaved-changes", "Unsaved changes exist");
133
140
  }
134
141
  if (args.db.txns.hasPendingSchemaChanges) {
135
- throw new StashError("Pending schema changeset. Stashing is not currently supported for schema changes");
142
+ StashError.throwError("pending-schema-changes", "Pending schema changeset. Stashing is not currently supported for schema changes");
136
143
  }
137
144
  const stashRootDir = this.getStashRootFolder(args.db, true);
138
145
  const iModelId = args.db.iModelId;
@@ -168,7 +175,7 @@ export class StashManager {
168
175
  return this.withStash(args, (stashDb) => {
169
176
  const stashProps = stashDb.withPreparedSqliteStatement("SELECT [val] FROM [be_Local] WHERE [name]='$stash_info'", (stmt) => {
170
177
  if (stmt.step() !== DbResult.BE_SQLITE_ROW)
171
- throw new StashError("Invalid stash");
178
+ StashError.throwError("invalid-stash", "Invalid stash");
172
179
  return JSON.parse(stmt.getValueString(0));
173
180
  });
174
181
  return stashProps;
@@ -185,7 +192,7 @@ export class StashManager {
185
192
  static withStash(args, callback) {
186
193
  const stashFile = this.getStashFilePath(args);
187
194
  if (!existsSync(stashFile)) {
188
- throw new StashError("Invalid stash");
195
+ StashError.throwError("invalid-stash", "Invalid stash");
189
196
  }
190
197
  const stashDb = new SQLiteDb();
191
198
  stashDb.openDb(stashFile, OpenMode.Readonly);
@@ -271,16 +278,16 @@ export class StashManager {
271
278
  Logger.logInfo(loggerCategory, `Restoring stash: ${this.getStashId(args)}`);
272
279
  const stash = this.tryGetStash(args);
273
280
  if (!stash) {
274
- throw new StashError(`Stash not found ${this.getStashId(args)}`);
281
+ StashError.throwError("stash-not-found", `Stash not found ${this.getStashId(args)}`);
275
282
  }
276
283
  if (db.txns.hasUnsavedChanges) {
277
- throw new StashError(`Unsaved changes present`);
284
+ StashError.throwError("unsaved-changes", `Unsaved changes are present.`);
278
285
  }
279
286
  if (db.iModelId !== stash.iModelId) {
280
- throw new StashError(`Stash does not belong to this iModel`);
287
+ StashError.throwError("invalid-stash", `Stash does not belong to this iModel`);
281
288
  }
282
289
  if (db.briefcaseId !== stash.briefcaseId) {
283
- throw new StashError(`Stash does not belong to this briefcase`);
290
+ StashError.throwError("invalid-stash", `Stash does not belong to this briefcase`);
284
291
  }
285
292
  const stashFile = this.getStashFilePath({ db, stash });
286
293
  // we need to retain lock that overlapped with stash locks instead of all locks
@@ -1 +1 @@
1
- {"version":3,"file":"StashManager.js","sourceRoot":"","sources":["../../src/StashManager.ts"],"names":[],"mappings":"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","sourcesContent":["import { DbResult, GuidString, Id64Array, Id64String, Logger, OpenMode } from \"@itwin/core-bentley\";\r\nimport { ChangesetIdWithIndex, LocalDirName, LockState } from \"@itwin/core-common\";\r\nimport { existsSync, mkdirSync, readdirSync, statSync, unlinkSync } from \"node:fs\";\r\nimport * as path from \"node:path\";\r\nimport { BriefcaseManager } from \"./BriefcaseManager\";\r\nimport { BriefcaseDb } from \"./IModelDb\";\r\nimport { _elementWasCreated, _getHubAccess, _hubAccess, _nativeDb, _resetIModelDb } from \"./internal/Symbols\";\r\nimport { SQLiteDb } from \"./SQLiteDb\";\r\nimport { TxnProps } from \"./TxnManager\";\r\nimport { IModelHost } from \"./IModelHost\";\r\nimport { BackendLoggerCategory } from \"./BackendLoggerCategory\";\r\n\r\nconst loggerCategory = BackendLoggerCategory.StashManager;\r\n\r\n/**\r\n * Custom error class for stash-related errors.\r\n * @internal\r\n */\r\nexport class StashError extends Error {\r\n constructor(message: string) {\r\n super(message);\r\n this.name = \"StashError\";\r\n Logger.logError(loggerCategory, message);\r\n }\r\n}\r\n\r\n/**\r\n * Properties of a stash\r\n * @internal\r\n */\r\nexport interface StashProps {\r\n /** Unique identifier for the stash */\r\n readonly id: GuidString;\r\n\r\n /** ID of the iModel being stashed */\r\n readonly iModelId: GuidString;\r\n\r\n /** ID of the briefcase being stashed */\r\n readonly briefcaseId: number;\r\n\r\n /** ISO local Timestamp of the stash */\r\n readonly timestamp: string;\r\n\r\n /** Description of the stash */\r\n readonly description: string;\r\n\r\n /** Hash of the stash */\r\n readonly hash: string;\r\n\r\n /** Parent changeset of the stash */\r\n readonly parentChangeset: ChangesetIdWithIndex;\r\n\r\n /** ID sequences for the stash */\r\n readonly idSequences: {\r\n element: Id64String;\r\n instance: Id64String;\r\n };\r\n\r\n /** Transaction properties for the stash */\r\n readonly txns: TxnProps[];\r\n\r\n /** Number of locks acquired by the stash */\r\n readonly acquiredLocks: number;\r\n}\r\n\r\n/**\r\n * Properties for creating a stash\r\n * @internal\r\n */\r\nexport interface CreateStashProps {\r\n /** Briefcase database instance */\r\n readonly db: BriefcaseDb;\r\n /** description of the stash */\r\n readonly description: string;\r\n /** discard all local changes and unless retainLocks flag is set, all locks will be released */\r\n readonly discardLocalChanges?: true;\r\n /** retains all locks after discarding local changes */\r\n readonly retainLocks?: true;\r\n}\r\n\r\n/**\r\n * Arguments for stash operations\r\n * @internal\r\n */\r\nexport interface StashArgs {\r\n readonly db: BriefcaseDb;\r\n readonly stash: Id64String | StashProps;\r\n}\r\n\r\nenum LockOrigin {\r\n Acquired = 0,\r\n NewElement = 1,\r\n Discovered = 2,\r\n};\r\n\r\n/**\r\n * Stash manager allow stash, drop, apply and merge stashes\r\n * @internal\r\n */\r\nexport class StashManager {\r\n\r\n private static readonly STASHES_ROOT_DIR_NAME: string = \".stashes\";\r\n /**\r\n * Retrieves the root folder path for stash files associated with the specified BriefcaseDb.\r\n *\r\n * @param db - The BriefcaseDb instance for which to determine the stash root folder.\r\n * @param ensureExists - If true, the stash root directory will be created if it does not already exist.\r\n * @returns The absolute path to the stash root directory.\r\n */\r\n private static getStashRootFolder(db: BriefcaseDb, ensureExists: boolean): LocalDirName {\r\n if (!db.isOpen || db.isReadonly)\r\n throw new StashError(\"Database is not open or is readonly\");\r\n\r\n if (!existsSync(db[_nativeDb].getFilePath())) {\r\n throw new StashError(\"Could not determine briefcase path\");\r\n }\r\n\r\n const stashDir = path.join(path.dirname(db[_nativeDb].getFilePath()), this.STASHES_ROOT_DIR_NAME, `${db.briefcaseId}`);\r\n if (ensureExists && !existsSync(stashDir)) {\r\n mkdirSync(stashDir, { recursive: true });\r\n }\r\n return stashDir;\r\n }\r\n\r\n /**\r\n * Retrieves the stash ID from the provided arguments.\r\n *\r\n * If the `stash` property of `args` is a string, it returns the string in lowercase.\r\n * If the `stash` property is an object, it returns the `id` property of the object in lowercase.\r\n *\r\n * @param args - The arguments containing the stash information, which can be either a string or an object with an `id` property.\r\n * @returns The stash ID as a lowercase string.\r\n */\r\n private static getStashId(args: StashArgs) {\r\n return (typeof args.stash === \"string\" ? args.stash : args.stash.id).toLowerCase();\r\n }\r\n\r\n /**\r\n * Retrieves the file path to the stash file associated with the provided arguments.\r\n *\r\n * @param args - The arguments required to identify the stash, including the database reference.\r\n * @returns The absolute path to the stash file.\r\n */\r\n private static getStashFilePath(args: StashArgs) {\r\n const stashRoot = this.getStashRootFolder(args.db, false);\r\n if (!existsSync(stashRoot)) {\r\n throw new StashError(\"Invalid stash\");\r\n }\r\n\r\n const stashFilePath = path.join(stashRoot, `${this.getStashId(args)}.stash`);\r\n if (!existsSync(stashFilePath)) {\r\n throw new StashError(\"Invalid stash\");\r\n }\r\n return stashFilePath;\r\n }\r\n\r\n /**\r\n * Queries the stash database for lock IDs matching the specified state and origin.\r\n *\r\n * @param args - The arguments required to access the stash database.\r\n * @param state - The lock state to filter by.\r\n * @param origin - The lock origin to filter by.\r\n * @returns An array of lock IDs (`Id64Array`) that match the given state and origin.\r\n */\r\n private static queryLocks(args: StashArgs, state: LockState, origin: LockOrigin): Id64Array {\r\n return this.withStash(args, (stashDb) => {\r\n const query = `SELECT JSON_GROUP_ARRAY(FORMAT('0x%x', Id)) FROM [locks] WHERE State = ${state} AND origin = ${origin}`;\r\n return stashDb.withPreparedSqliteStatement(query, (stmt) => {\r\n if (stmt.step() === DbResult.BE_SQLITE_ROW) {\r\n return JSON.parse(stmt.getValueString(0)) as Id64Array;\r\n }\r\n return [];\r\n });\r\n });\r\n }\r\n\r\n /**\r\n * Acquire locks for the specified stash. If this fail then stash should not be applied.\r\n * @param args The stash arguments.\r\n */\r\n private static async acquireLocks(args: StashArgs) {\r\n const shared = this.queryLocks(args, LockState.Shared, LockOrigin.Acquired);\r\n await args.db.locks.acquireLocks({ shared });\r\n\r\n const exclusive = this.queryLocks(args, LockState.Exclusive, LockOrigin.Acquired);\r\n await args.db.locks.acquireLocks({ exclusive });\r\n\r\n const newElements = this.queryLocks(args, LockState.Shared, LockOrigin.NewElement);\r\n for (const id of newElements) {\r\n if (!args.db.locks.holdsExclusiveLock(id)) {\r\n args.db.locks[_elementWasCreated](id);\r\n }\r\n }\r\n }\r\n /**\r\n * Creates a stash of changes for the specified briefcase.\r\n *\r\n * This method generates a stash in the stash root directory for the given briefcase, using the provided description and iModelId.\r\n * Optionally, it can reset the briefcase by releasing all locks after stashing.\r\n *\r\n * @param args - The properties required to create a stash, including the briefcase, description, iModelId, and an optional resetBriefcase flag.\r\n * @returns A promise that resolves to the properties of the created stash.\r\n */\r\n public static async stash(args: CreateStashProps): Promise<StashProps> {\r\n if (!args.db.txns.hasPendingTxns) {\r\n throw new StashError(\"nothing to stash\");\r\n }\r\n\r\n if (args.db.txns.hasUnsavedChanges) {\r\n throw new StashError(\"Unsaved changes exist\");\r\n }\r\n\r\n if (args.db.txns.hasPendingSchemaChanges) {\r\n throw new StashError(\"Pending schema changeset. Stashing is not currently supported for schema changes\");\r\n }\r\n\r\n const stashRootDir = this.getStashRootFolder(args.db, true);\r\n const iModelId = args.db.iModelId;\r\n const stash = args.db[_nativeDb].stashChanges({ stashRootDir, description: args.description, iModelId }) as StashProps;\r\n if (args.discardLocalChanges) {\r\n await args.db.discardChanges({ retainLocks: args.retainLocks });\r\n }\r\n\r\n Logger.logInfo(loggerCategory, `Stashed changes`, () => stash);\r\n return stash;\r\n }\r\n\r\n /**\r\n * Retrieves the stash properties from the database for the given arguments.\r\n *\r\n * @param args - The arguments required to locate and access the stash.\r\n * @returns The stash file properties if found; otherwise, `undefined`.\r\n */\r\n public static tryGetStash(args: StashArgs): StashProps | undefined {\r\n try {\r\n return this.getStash(args);\r\n } catch (error: any) {\r\n Logger.logError(loggerCategory, `Error getting stash with ${this.getStashId(args)}: ${error.message}`);\r\n }\r\n return undefined;\r\n }\r\n\r\n /**\r\n * Retrieves the stash properties from the database using the provided arguments.\r\n *\r\n * @param args - The arguments required to access the stash.\r\n * @returns The stash properties parsed from the database.\r\n */\r\n public static getStash(args: StashArgs): StashProps {\r\n return this.withStash(args, (stashDb) => {\r\n const stashProps = stashDb.withPreparedSqliteStatement(\"SELECT [val] FROM [be_Local] WHERE [name]='$stash_info'\", (stmt) => {\r\n if (stmt.step() !== DbResult.BE_SQLITE_ROW)\r\n throw new StashError(\"Invalid stash\");\r\n return JSON.parse(stmt.getValueString(0)) as StashProps;\r\n });\r\n return stashProps;\r\n });\r\n }\r\n\r\n /**\r\n * Executes a callback function with a read-only SQLite database connection to a stash file.\r\n *\r\n * @typeParam T - The return type of the callback function.\r\n * @param args - Arguments required to determine the stash file path.\r\n * @param callback - A function that receives an open {@link SQLiteDb} instance connected to the stash file.\r\n * @returns The value returned by the callback function.\r\n */\r\n private static withStash<T>(args: StashArgs, callback: (stashDb: SQLiteDb) => T): T {\r\n const stashFile = this.getStashFilePath(args);\r\n if (!existsSync(stashFile)) {\r\n throw new StashError(\"Invalid stash\");\r\n }\r\n\r\n const stashDb = new SQLiteDb();\r\n stashDb.openDb(stashFile, OpenMode.Readonly);\r\n try {\r\n return callback(stashDb);\r\n } finally {\r\n stashDb.closeDb();\r\n }\r\n }\r\n\r\n /**\r\n * Retrieves all stash files associated with the specified {@link BriefcaseDb}.\r\n * @param db - The {@link BriefcaseDb} instance for which to retrieve stash files.\r\n * @returns An array of `StashProps` representing the found stash files, sorted by timestamp.\r\n */\r\n public static getStashes(db: BriefcaseDb): StashProps[] {\r\n const stashes: StashProps[] = [];\r\n const stashDir = this.getStashRootFolder(db, false);\r\n if (!existsSync(stashDir)) {\r\n return stashes;\r\n }\r\n readdirSync(stashDir).filter((file) => {\r\n const filePath = path.join(stashDir, file);\r\n if (existsSync(filePath) && statSync(filePath).isFile() && file.endsWith(\".stash\")) {\r\n const id = file.slice(0, -path.extname(file).length)\r\n const stash = this.tryGetStash({ db, stash: id });\r\n if (stash) {\r\n stashes.push(stash);\r\n }\r\n }\r\n });\r\n stashes.sort((a, b) => Date.parse(b.timestamp) - Date.parse(a.timestamp));\r\n return stashes;\r\n }\r\n\r\n /**\r\n * Deletes the stash file associated with the specified stash ID or properties from the given {@link BriefcaseDb}.\r\n *\r\n * @param db - The {@link BriefcaseDb} instance from which the stash should be dropped.\r\n * @param stashId - The unique identifier (GuidString) or properties (StashProps) of the stash to be deleted.\r\n * @returns Returns `true` if the stash file was successfully deleted, otherwise returns `false`.\r\n */\r\n public static dropStash(args: StashArgs): boolean {\r\n try {\r\n const stashFile = this.getStashFilePath(args);\r\n unlinkSync(stashFile);\r\n return true;\r\n } catch (error: any) {\r\n Logger.logError(loggerCategory, `Error dropping stash: ${error}`);\r\n }\r\n return false;\r\n }\r\n\r\n /**\r\n * Removes all stashes associated with the specified {@link BriefcaseDb}.\r\n *\r\n * @param db - The {@link BriefcaseDb} instance from which all stashes will be removed.\r\n */\r\n public static dropAllStashes(db: BriefcaseDb): void {\r\n this.getStashes(db).forEach((stash) => {\r\n this.dropStash({ db, stash });\r\n });\r\n }\r\n\r\n /**\r\n * Queries the hub for the changeset information associated with the given stash.\r\n *\r\n * @param args - The arguments including the stash properties.\r\n * @returns A promise resolving to the changeset ID and index.\r\n */\r\n private static async queryChangeset(args: StashArgs & { stash: StashProps }): Promise<ChangesetIdWithIndex> {\r\n return IModelHost[_hubAccess].queryChangeset({\r\n iModelId: args.stash.iModelId,\r\n changeset: args.stash.parentChangeset,\r\n accessToken: await IModelHost.getAccessToken()\r\n });\r\n }\r\n /**\r\n * Restores the specified stash to the given {@link BriefcaseDb}. This operation will discard any local changes made to db and reverse the tip to the state of the stash and then apply stash. This will restore the undo stack.\r\n *\r\n * @param args - The arguments including the target database and stash properties.\r\n */\r\n public static async restore(args: StashArgs): Promise<void> {\r\n const { db } = args;\r\n Logger.logInfo(loggerCategory, `Restoring stash: ${this.getStashId(args)}`);\r\n\r\n const stash = this.tryGetStash(args);\r\n if (!stash) {\r\n throw new StashError(`Stash not found ${this.getStashId(args)}`);\r\n }\r\n\r\n if (db.txns.hasUnsavedChanges) {\r\n throw new StashError(`Unsaved changes present`);\r\n }\r\n\r\n if (db.iModelId !== stash.iModelId) {\r\n throw new StashError(`Stash does not belong to this iModel`);\r\n }\r\n\r\n if (db.briefcaseId !== stash.briefcaseId) {\r\n throw new StashError(`Stash does not belong to this briefcase`);\r\n }\r\n\r\n const stashFile = this.getStashFilePath({ db, stash });\r\n // we need to retain lock that overlapped with stash locks instead of all locks\r\n await db.discardChanges({ retainLocks: true });\r\n await this.acquireLocks(args);\r\n if (db.changeset.id !== stash.parentChangeset.id) {\r\n // Changeset ID mismatch\r\n Logger.logWarning(loggerCategory, \"Changeset ID mismatch\");\r\n const stashChangeset = await this.queryChangeset({ db, stash });\r\n await BriefcaseManager.pullAndApplyChangesets(db, { toIndex: stashChangeset.index });\r\n }\r\n\r\n db[_nativeDb].stashRestore(stashFile);\r\n db[_resetIModelDb]();\r\n db.saveChanges();\r\n Logger.logInfo(loggerCategory, `Restored stash: ${this.getStashId(args)}`);\r\n }\r\n}\r\n"]}
1
+ {"version":3,"file":"StashManager.js","sourceRoot":"","sources":["../../src/StashManager.ts"],"names":[],"mappings":"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","sourcesContent":["import { DbResult, GuidString, Id64Array, Id64String, ITwinError, Logger, OpenMode } from \"@itwin/core-bentley\";\r\nimport { ChangesetIdWithIndex, LocalDirName, LockState } from \"@itwin/core-common\";\r\nimport { existsSync, mkdirSync, readdirSync, statSync, unlinkSync } from \"node:fs\";\r\nimport * as path from \"node:path\";\r\nimport { BriefcaseManager } from \"./BriefcaseManager\";\r\nimport { BriefcaseDb } from \"./IModelDb\";\r\nimport { _elementWasCreated, _getHubAccess, _hubAccess, _nativeDb, _resetIModelDb } from \"./internal/Symbols\";\r\nimport { SQLiteDb } from \"./SQLiteDb\";\r\nimport { TxnProps } from \"./TxnManager\";\r\nimport { IModelHost } from \"./IModelHost\";\r\nimport { BackendLoggerCategory } from \"./BackendLoggerCategory\";\r\n\r\nconst loggerCategory = BackendLoggerCategory.StashManager;\r\n\r\n/**\r\n * Properties of a stash\r\n * @internal\r\n */\r\nexport interface StashProps {\r\n /** Unique identifier for the stash */\r\n readonly id: GuidString;\r\n\r\n /** ID of the iModel being stashed */\r\n readonly iModelId: GuidString;\r\n\r\n /** ID of the briefcase being stashed */\r\n readonly briefcaseId: number;\r\n\r\n /** ISO local Timestamp of the stash */\r\n readonly timestamp: string;\r\n\r\n /** Description of the stash */\r\n readonly description: string;\r\n\r\n /** Hash of the stash */\r\n readonly hash: string;\r\n\r\n /** Parent changeset of the stash */\r\n readonly parentChangeset: ChangesetIdWithIndex;\r\n\r\n /** ID sequences for the stash */\r\n readonly idSequences: {\r\n element: Id64String;\r\n instance: Id64String;\r\n };\r\n\r\n /** Transaction properties for the stash */\r\n readonly txns: TxnProps[];\r\n\r\n /** Number of locks acquired by the stash */\r\n readonly acquiredLocks: number;\r\n}\r\n\r\n/**\r\n * Properties for creating a stash\r\n * @internal\r\n */\r\nexport interface CreateStashProps {\r\n /** Briefcase database instance */\r\n readonly db: BriefcaseDb;\r\n /** description of the stash */\r\n readonly description: string;\r\n /** discard all local changes and unless retainLocks flag is set, all locks will be released */\r\n readonly discardLocalChanges?: true;\r\n /** retains all locks after discarding local changes */\r\n readonly retainLocks?: true;\r\n}\r\n\r\n/**\r\n * Arguments for stash operations\r\n * @internal\r\n */\r\nexport interface StashArgs {\r\n readonly db: BriefcaseDb;\r\n readonly stash: Id64String | StashProps;\r\n}\r\n\r\nenum LockOrigin {\r\n Acquired = 0,\r\n NewElement = 1,\r\n Discovered = 2,\r\n};\r\n\r\n/**\r\n * An error originating from the StashManager API.\r\n * @internal\r\n */\r\nexport namespace StashError {\r\n export const scope = \"itwin-StashManager\";\r\n export type Key =\r\n \"readonly\" |\r\n \"no-file\" |\r\n \"no-stashes\" |\r\n \"invalid-stash\" |\r\n \"nothing-to-stash\" |\r\n \"unsaved-changes\" |\r\n \"pending-schema-changes\" |\r\n \"stash-not-found\";\r\n\r\n /** Instantiate and throw a StashError */\r\n export function throwError(key: Key, message: string): never {\r\n ITwinError.throwError<ITwinError>({ iTwinErrorId: { scope, key }, message });\r\n }\r\n /** Determine whether an error object is a StashError */\r\n export function isError(error: unknown, key?: Key): error is ITwinError {\r\n return ITwinError.isError<ITwinError>(error, scope, key);\r\n }\r\n}\r\n\r\n/**\r\n * Stash manager allow stash, drop, apply and merge stashes\r\n * @internal\r\n */\r\nexport class StashManager {\r\n\r\n private static readonly STASHES_ROOT_DIR_NAME: string = \".stashes\";\r\n /**\r\n * Retrieves the root folder path for stash files associated with the specified BriefcaseDb.\r\n *\r\n * @param db - The BriefcaseDb instance for which to determine the stash root folder.\r\n * @param ensureExists - If true, the stash root directory will be created if it does not already exist.\r\n * @returns The absolute path to the stash root directory.\r\n */\r\n private static getStashRootFolder(db: BriefcaseDb, ensureExists: boolean): LocalDirName {\r\n if (!db.isOpen || db.isReadonly)\r\n StashError.throwError(\"readonly\", \"Database is not open or is readonly\");\r\n\r\n if (!existsSync(db[_nativeDb].getFilePath())) {\r\n StashError.throwError(\"no-file\", \"Database file does not exist\");\r\n }\r\n\r\n const stashDir = path.join(path.dirname(db[_nativeDb].getFilePath()), this.STASHES_ROOT_DIR_NAME, `${db.briefcaseId}`);\r\n if (ensureExists && !existsSync(stashDir)) {\r\n mkdirSync(stashDir, { recursive: true });\r\n }\r\n return stashDir;\r\n }\r\n\r\n /**\r\n * Retrieves the stash ID from the provided arguments.\r\n *\r\n * If the `stash` property of `args` is a string, it returns the string in lowercase.\r\n * If the `stash` property is an object, it returns the `id` property of the object in lowercase.\r\n *\r\n * @param args - The arguments containing the stash information, which can be either a string or an object with an `id` property.\r\n * @returns The stash ID as a lowercase string.\r\n */\r\n private static getStashId(args: StashArgs) {\r\n return (typeof args.stash === \"string\" ? args.stash : args.stash.id).toLowerCase();\r\n }\r\n\r\n /**\r\n * Retrieves the file path to the stash file associated with the provided arguments.\r\n *\r\n * @param args - The arguments required to identify the stash, including the database reference.\r\n * @returns The absolute path to the stash file.\r\n */\r\n private static getStashFilePath(args: StashArgs) {\r\n const stashRoot = this.getStashRootFolder(args.db, false);\r\n if (!existsSync(stashRoot)) {\r\n StashError.throwError(\"no-stashes\", \"No stashes exist for this briefcase\");\r\n }\r\n\r\n const stashFilePath = path.join(stashRoot, `${this.getStashId(args)}.stash`);\r\n if (!existsSync(stashFilePath)) {\r\n StashError.throwError(\"invalid-stash\", \"Invalid stash\");\r\n }\r\n return stashFilePath;\r\n }\r\n\r\n /**\r\n * Queries the stash database for lock IDs matching the specified state and origin.\r\n *\r\n * @param args - The arguments required to access the stash database.\r\n * @param state - The lock state to filter by.\r\n * @param origin - The lock origin to filter by.\r\n * @returns An array of lock IDs (`Id64Array`) that match the given state and origin.\r\n */\r\n private static queryLocks(args: StashArgs, state: LockState, origin: LockOrigin): Id64Array {\r\n return this.withStash(args, (stashDb) => {\r\n const query = `SELECT JSON_GROUP_ARRAY(FORMAT('0x%x', Id)) FROM [locks] WHERE State = ${state} AND origin = ${origin}`;\r\n return stashDb.withPreparedSqliteStatement(query, (stmt) => {\r\n if (stmt.step() === DbResult.BE_SQLITE_ROW) {\r\n return JSON.parse(stmt.getValueString(0)) as Id64Array;\r\n }\r\n return [];\r\n });\r\n });\r\n }\r\n\r\n /**\r\n * Acquire locks for the specified stash. If this fail then stash should not be applied.\r\n * @param args The stash arguments.\r\n */\r\n private static async acquireLocks(args: StashArgs) {\r\n const shared = this.queryLocks(args, LockState.Shared, LockOrigin.Acquired);\r\n await args.db.locks.acquireLocks({ shared });\r\n\r\n const exclusive = this.queryLocks(args, LockState.Exclusive, LockOrigin.Acquired);\r\n await args.db.locks.acquireLocks({ exclusive });\r\n\r\n const newElements = this.queryLocks(args, LockState.Shared, LockOrigin.NewElement);\r\n for (const id of newElements) {\r\n if (!args.db.locks.holdsExclusiveLock(id)) {\r\n args.db.locks[_elementWasCreated](id);\r\n }\r\n }\r\n }\r\n /**\r\n * Creates a stash of changes for the specified briefcase.\r\n *\r\n * This method generates a stash in the stash root directory for the given briefcase, using the provided description and iModelId.\r\n * Optionally, it can reset the briefcase by releasing all locks after stashing.\r\n *\r\n * @param args - The properties required to create a stash, including the briefcase, description, iModelId, and an optional resetBriefcase flag.\r\n * @returns A promise that resolves to the properties of the created stash.\r\n */\r\n public static async stash(args: CreateStashProps): Promise<StashProps> {\r\n if (!args.db.txns.hasPendingTxns) {\r\n StashError.throwError(\"nothing-to-stash\", \"Nothing to stash\");\r\n }\r\n\r\n if (args.db.txns.hasUnsavedChanges) {\r\n StashError.throwError(\"unsaved-changes\", \"Unsaved changes exist\");\r\n }\r\n\r\n if (args.db.txns.hasPendingSchemaChanges) {\r\n StashError.throwError(\"pending-schema-changes\", \"Pending schema changeset. Stashing is not currently supported for schema changes\");\r\n }\r\n\r\n const stashRootDir = this.getStashRootFolder(args.db, true);\r\n const iModelId = args.db.iModelId;\r\n const stash = args.db[_nativeDb].stashChanges({ stashRootDir, description: args.description, iModelId }) as StashProps;\r\n if (args.discardLocalChanges) {\r\n await args.db.discardChanges({ retainLocks: args.retainLocks });\r\n }\r\n\r\n Logger.logInfo(loggerCategory, `Stashed changes`, () => stash);\r\n return stash;\r\n }\r\n\r\n /**\r\n * Retrieves the stash properties from the database for the given arguments.\r\n *\r\n * @param args - The arguments required to locate and access the stash.\r\n * @returns The stash file properties if found; otherwise, `undefined`.\r\n */\r\n public static tryGetStash(args: StashArgs): StashProps | undefined {\r\n try {\r\n return this.getStash(args);\r\n } catch (error: any) {\r\n Logger.logError(loggerCategory, `Error getting stash with ${this.getStashId(args)}: ${error.message}`);\r\n }\r\n return undefined;\r\n }\r\n\r\n /**\r\n * Retrieves the stash properties from the database using the provided arguments.\r\n *\r\n * @param args - The arguments required to access the stash.\r\n * @returns The stash properties parsed from the database.\r\n */\r\n public static getStash(args: StashArgs): StashProps {\r\n return this.withStash(args, (stashDb) => {\r\n const stashProps = stashDb.withPreparedSqliteStatement(\"SELECT [val] FROM [be_Local] WHERE [name]='$stash_info'\", (stmt) => {\r\n if (stmt.step() !== DbResult.BE_SQLITE_ROW)\r\n StashError.throwError(\"invalid-stash\", \"Invalid stash\");\r\n return JSON.parse(stmt.getValueString(0)) as StashProps;\r\n });\r\n return stashProps;\r\n });\r\n }\r\n\r\n /**\r\n * Executes a callback function with a read-only SQLite database connection to a stash file.\r\n *\r\n * @typeParam T - The return type of the callback function.\r\n * @param args - Arguments required to determine the stash file path.\r\n * @param callback - A function that receives an open {@link SQLiteDb} instance connected to the stash file.\r\n * @returns The value returned by the callback function.\r\n */\r\n private static withStash<T>(args: StashArgs, callback: (stashDb: SQLiteDb) => T): T {\r\n const stashFile = this.getStashFilePath(args);\r\n if (!existsSync(stashFile)) {\r\n StashError.throwError(\"invalid-stash\", \"Invalid stash\");\r\n }\r\n\r\n const stashDb = new SQLiteDb();\r\n stashDb.openDb(stashFile, OpenMode.Readonly);\r\n try {\r\n return callback(stashDb);\r\n } finally {\r\n stashDb.closeDb();\r\n }\r\n }\r\n\r\n /**\r\n * Retrieves all stash files associated with the specified {@link BriefcaseDb}.\r\n * @param db - The {@link BriefcaseDb} instance for which to retrieve stash files.\r\n * @returns An array of `StashProps` representing the found stash files, sorted by timestamp.\r\n */\r\n public static getStashes(db: BriefcaseDb): StashProps[] {\r\n const stashes: StashProps[] = [];\r\n const stashDir = this.getStashRootFolder(db, false);\r\n if (!existsSync(stashDir)) {\r\n return stashes;\r\n }\r\n readdirSync(stashDir).filter((file) => {\r\n const filePath = path.join(stashDir, file);\r\n if (existsSync(filePath) && statSync(filePath).isFile() && file.endsWith(\".stash\")) {\r\n const id = file.slice(0, -path.extname(file).length)\r\n const stash = this.tryGetStash({ db, stash: id });\r\n if (stash) {\r\n stashes.push(stash);\r\n }\r\n }\r\n });\r\n stashes.sort((a, b) => Date.parse(b.timestamp) - Date.parse(a.timestamp));\r\n return stashes;\r\n }\r\n\r\n /**\r\n * Deletes the stash file associated with the specified stash ID or properties from the given {@link BriefcaseDb}.\r\n *\r\n * @param db - The {@link BriefcaseDb} instance from which the stash should be dropped.\r\n * @param stashId - The unique identifier (GuidString) or properties (StashProps) of the stash to be deleted.\r\n * @returns Returns `true` if the stash file was successfully deleted, otherwise returns `false`.\r\n */\r\n public static dropStash(args: StashArgs): boolean {\r\n try {\r\n const stashFile = this.getStashFilePath(args);\r\n unlinkSync(stashFile);\r\n return true;\r\n } catch (error: any) {\r\n Logger.logError(loggerCategory, `Error dropping stash: ${error}`);\r\n }\r\n return false;\r\n }\r\n\r\n /**\r\n * Removes all stashes associated with the specified {@link BriefcaseDb}.\r\n *\r\n * @param db - The {@link BriefcaseDb} instance from which all stashes will be removed.\r\n */\r\n public static dropAllStashes(db: BriefcaseDb): void {\r\n this.getStashes(db).forEach((stash) => {\r\n this.dropStash({ db, stash });\r\n });\r\n }\r\n\r\n /**\r\n * Queries the hub for the changeset information associated with the given stash.\r\n *\r\n * @param args - The arguments including the stash properties.\r\n * @returns A promise resolving to the changeset ID and index.\r\n */\r\n private static async queryChangeset(args: StashArgs & { stash: StashProps }): Promise<ChangesetIdWithIndex> {\r\n return IModelHost[_hubAccess].queryChangeset({\r\n iModelId: args.stash.iModelId,\r\n changeset: args.stash.parentChangeset,\r\n accessToken: await IModelHost.getAccessToken()\r\n });\r\n }\r\n /**\r\n * Restores the specified stash to the given {@link BriefcaseDb}. This operation will discard any local changes made to db and reverse the tip to the state of the stash and then apply stash. This will restore the undo stack.\r\n *\r\n * @param args - The arguments including the target database and stash properties.\r\n */\r\n public static async restore(args: StashArgs): Promise<void> {\r\n const { db } = args;\r\n Logger.logInfo(loggerCategory, `Restoring stash: ${this.getStashId(args)}`);\r\n\r\n const stash = this.tryGetStash(args);\r\n if (!stash) {\r\n StashError.throwError(\"stash-not-found\", `Stash not found ${this.getStashId(args)}`);\r\n }\r\n\r\n if (db.txns.hasUnsavedChanges) {\r\n StashError.throwError(\"unsaved-changes\", `Unsaved changes are present.`);\r\n }\r\n\r\n if (db.iModelId !== stash.iModelId) {\r\n StashError.throwError(\"invalid-stash\", `Stash does not belong to this iModel`);\r\n }\r\n\r\n if (db.briefcaseId !== stash.briefcaseId) {\r\n StashError.throwError(\"invalid-stash\", `Stash does not belong to this briefcase`);\r\n }\r\n\r\n const stashFile = this.getStashFilePath({ db, stash });\r\n // we need to retain lock that overlapped with stash locks instead of all locks\r\n await db.discardChanges({ retainLocks: true });\r\n await this.acquireLocks(args);\r\n if (db.changeset.id !== stash.parentChangeset.id) {\r\n // Changeset ID mismatch\r\n Logger.logWarning(loggerCategory, \"Changeset ID mismatch\");\r\n const stashChangeset = await this.queryChangeset({ db, stash });\r\n await BriefcaseManager.pullAndApplyChangesets(db, { toIndex: stashChangeset.index });\r\n }\r\n\r\n db[_nativeDb].stashRestore(stashFile);\r\n db[_resetIModelDb]();\r\n db.saveChanges();\r\n Logger.logInfo(loggerCategory, `Restored stash: ${this.getStashId(args)}`);\r\n }\r\n}\r\n"]}