@itwin/core-backend 4.1.0-dev.8 → 4.1.0-dev.80

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 (188) hide show
  1. package/CHANGELOG.md +99 -1
  2. package/lib/cjs/BackendHubAccess.js.map +1 -1
  3. package/lib/cjs/BackendLoggerCategory.js.map +1 -1
  4. package/lib/cjs/BisCoreSchema.js.map +1 -1
  5. package/lib/cjs/BlobContainerService.d.ts +38 -28
  6. package/lib/cjs/BlobContainerService.d.ts.map +1 -1
  7. package/lib/cjs/BlobContainerService.js.map +1 -1
  8. package/lib/cjs/BriefcaseManager.d.ts +8 -5
  9. package/lib/cjs/BriefcaseManager.d.ts.map +1 -1
  10. package/lib/cjs/BriefcaseManager.js +9 -16
  11. package/lib/cjs/BriefcaseManager.js.map +1 -1
  12. package/lib/cjs/Category.d.ts +4 -16
  13. package/lib/cjs/Category.d.ts.map +1 -1
  14. package/lib/cjs/Category.js +0 -12
  15. package/lib/cjs/Category.js.map +1 -1
  16. package/lib/cjs/ChangeSummaryManager.js +2 -2
  17. package/lib/cjs/ChangeSummaryManager.js.map +1 -1
  18. package/lib/cjs/ChangedElementsDb.js.map +1 -1
  19. package/lib/cjs/ChangedElementsManager.js.map +1 -1
  20. package/lib/cjs/ChannelControl.d.ts +5 -1
  21. package/lib/cjs/ChannelControl.d.ts.map +1 -1
  22. package/lib/cjs/ChannelControl.js +10 -5
  23. package/lib/cjs/ChannelControl.js.map +1 -1
  24. package/lib/cjs/CheckpointManager.d.ts.map +1 -1
  25. package/lib/cjs/CheckpointManager.js +20 -9
  26. package/lib/cjs/CheckpointManager.js.map +1 -1
  27. package/lib/cjs/ClassRegistry.d.ts +2 -1
  28. package/lib/cjs/ClassRegistry.d.ts.map +1 -1
  29. package/lib/cjs/ClassRegistry.js +7 -6
  30. package/lib/cjs/ClassRegistry.js.map +1 -1
  31. package/lib/cjs/CloudSqlite.d.ts +57 -40
  32. package/lib/cjs/CloudSqlite.d.ts.map +1 -1
  33. package/lib/cjs/CloudSqlite.js +54 -39
  34. package/lib/cjs/CloudSqlite.js.map +1 -1
  35. package/lib/cjs/CodeService.js.map +1 -1
  36. package/lib/cjs/CodeSpecs.js.map +1 -1
  37. package/lib/cjs/ConcurrentQuery.js.map +1 -1
  38. package/lib/cjs/CustomViewState3dCreator.js.map +1 -1
  39. package/lib/cjs/DevTools.js.map +1 -1
  40. package/lib/cjs/DisplayStyle.d.ts +2 -5
  41. package/lib/cjs/DisplayStyle.d.ts.map +1 -1
  42. package/lib/cjs/DisplayStyle.js +0 -3
  43. package/lib/cjs/DisplayStyle.js.map +1 -1
  44. package/lib/cjs/ECDb.d.ts +6 -0
  45. package/lib/cjs/ECDb.d.ts.map +1 -1
  46. package/lib/cjs/ECDb.js +6 -0
  47. package/lib/cjs/ECDb.js.map +1 -1
  48. package/lib/cjs/ECSchemaXmlContext.d.ts +28 -1
  49. package/lib/cjs/ECSchemaXmlContext.d.ts.map +1 -1
  50. package/lib/cjs/ECSchemaXmlContext.js +28 -1
  51. package/lib/cjs/ECSchemaXmlContext.js.map +1 -1
  52. package/lib/cjs/ECSqlStatement.js.map +1 -1
  53. package/lib/cjs/Element.d.ts +40 -97
  54. package/lib/cjs/Element.d.ts.map +1 -1
  55. package/lib/cjs/Element.js +0 -57
  56. package/lib/cjs/Element.js.map +1 -1
  57. package/lib/cjs/ElementAspect.d.ts +2 -4
  58. package/lib/cjs/ElementAspect.d.ts.map +1 -1
  59. package/lib/cjs/ElementAspect.js +2 -4
  60. package/lib/cjs/ElementAspect.js.map +1 -1
  61. package/lib/cjs/ElementGraphics.js.map +1 -1
  62. package/lib/cjs/ElementTreeWalker.js.map +1 -1
  63. package/lib/cjs/Entity.d.ts +5 -2
  64. package/lib/cjs/Entity.d.ts.map +1 -1
  65. package/lib/cjs/Entity.js +10 -2
  66. package/lib/cjs/Entity.js.map +1 -1
  67. package/lib/cjs/EntityReferences.js.map +1 -1
  68. package/lib/cjs/ExportGraphics.js.map +1 -1
  69. package/lib/cjs/ExternalSource.d.ts +4 -11
  70. package/lib/cjs/ExternalSource.d.ts.map +1 -1
  71. package/lib/cjs/ExternalSource.js +0 -7
  72. package/lib/cjs/ExternalSource.js.map +1 -1
  73. package/lib/cjs/GeoCoordConfig.js.map +1 -1
  74. package/lib/cjs/GeometrySummary.js +47 -47
  75. package/lib/cjs/GeometrySummary.js.map +1 -1
  76. package/lib/cjs/HubMock.js.map +1 -1
  77. package/lib/cjs/IModelCloneContext.js.map +1 -1
  78. package/lib/cjs/IModelDb.d.ts +61 -26
  79. package/lib/cjs/IModelDb.d.ts.map +1 -1
  80. package/lib/cjs/IModelDb.js +164 -83
  81. package/lib/cjs/IModelDb.js.map +1 -1
  82. package/lib/cjs/IModelElementCloneContext.js.map +1 -1
  83. package/lib/cjs/IModelHost.d.ts +1 -3
  84. package/lib/cjs/IModelHost.d.ts.map +1 -1
  85. package/lib/cjs/IModelHost.js +3 -5
  86. package/lib/cjs/IModelHost.js.map +1 -1
  87. package/lib/cjs/IModelJsFs.js.map +1 -1
  88. package/lib/cjs/IpcHost.js.map +1 -1
  89. package/lib/cjs/LineStyle.js.map +1 -1
  90. package/lib/cjs/LocalHub.js +1 -1
  91. package/lib/cjs/LocalHub.js.map +1 -1
  92. package/lib/cjs/LocalhostIpcHost.js.map +1 -1
  93. package/lib/cjs/Material.d.ts +0 -1
  94. package/lib/cjs/Material.d.ts.map +1 -1
  95. package/lib/cjs/Material.js +1 -2
  96. package/lib/cjs/Material.js.map +1 -1
  97. package/lib/cjs/Model.d.ts +4 -13
  98. package/lib/cjs/Model.d.ts.map +1 -1
  99. package/lib/cjs/Model.js +0 -9
  100. package/lib/cjs/Model.js.map +1 -1
  101. package/lib/cjs/NativeAppStorage.js.map +1 -1
  102. package/lib/cjs/NativeHost.js.map +1 -1
  103. package/lib/cjs/NavigationRelationship.js.map +1 -1
  104. package/lib/cjs/PromiseMemoizer.js.map +1 -1
  105. package/lib/cjs/PropertyStore.d.ts +3 -3
  106. package/lib/cjs/PropertyStore.d.ts.map +1 -1
  107. package/lib/cjs/PropertyStore.js +2 -5
  108. package/lib/cjs/PropertyStore.js.map +1 -1
  109. package/lib/cjs/Relationship.d.ts +2 -5
  110. package/lib/cjs/Relationship.d.ts.map +1 -1
  111. package/lib/cjs/Relationship.js +0 -3
  112. package/lib/cjs/Relationship.js.map +1 -1
  113. package/lib/cjs/RpcBackend.js.map +1 -1
  114. package/lib/cjs/SQLiteDb.d.ts +1 -1
  115. package/lib/cjs/SQLiteDb.d.ts.map +1 -1
  116. package/lib/cjs/SQLiteDb.js +1 -1
  117. package/lib/cjs/SQLiteDb.js.map +1 -1
  118. package/lib/cjs/Schema.d.ts +0 -1
  119. package/lib/cjs/Schema.d.ts.map +1 -1
  120. package/lib/cjs/Schema.js +0 -1
  121. package/lib/cjs/Schema.js.map +1 -1
  122. package/lib/cjs/SchemaUtils.d.ts +19 -0
  123. package/lib/cjs/SchemaUtils.d.ts.map +1 -0
  124. package/lib/cjs/SchemaUtils.js +42 -0
  125. package/lib/cjs/SchemaUtils.js.map +1 -0
  126. package/lib/cjs/ServerBasedLocks.js.map +1 -1
  127. package/lib/cjs/SqliteStatement.d.ts +13 -1
  128. package/lib/cjs/SqliteStatement.d.ts.map +1 -1
  129. package/lib/cjs/SqliteStatement.js +23 -1
  130. package/lib/cjs/SqliteStatement.js.map +1 -1
  131. package/lib/cjs/Texture.d.ts +3 -4
  132. package/lib/cjs/Texture.d.ts.map +1 -1
  133. package/lib/cjs/Texture.js +1 -2
  134. package/lib/cjs/Texture.js.map +1 -1
  135. package/lib/cjs/TileStorage.d.ts +3 -0
  136. package/lib/cjs/TileStorage.d.ts.map +1 -1
  137. package/lib/cjs/TileStorage.js +9 -1
  138. package/lib/cjs/TileStorage.js.map +1 -1
  139. package/lib/cjs/TxnManager.js.map +1 -1
  140. package/lib/cjs/ViewDefinition.d.ts +7 -28
  141. package/lib/cjs/ViewDefinition.d.ts.map +1 -1
  142. package/lib/cjs/ViewDefinition.js +0 -21
  143. package/lib/cjs/ViewDefinition.js.map +1 -1
  144. package/lib/cjs/ViewStateHydrator.js.map +1 -1
  145. package/lib/cjs/ViewStore.d.ts +488 -0
  146. package/lib/cjs/ViewStore.d.ts.map +1 -0
  147. package/lib/cjs/ViewStore.js +1246 -0
  148. package/lib/cjs/ViewStore.js.map +1 -0
  149. package/lib/cjs/assets/IModelChange.02.00.00.ecschema.xml +90 -90
  150. package/lib/cjs/assets/Settings/Schemas/Cloud.Schema.json +44 -44
  151. package/lib/cjs/assets/Settings/Schemas/Gcs.schema.json +31 -31
  152. package/lib/cjs/assets/Settings/Schemas/Workspace.Schema.json +52 -52
  153. package/lib/cjs/assets/Settings/backend.setting.json5 +132 -132
  154. package/lib/cjs/core-backend.d.ts +2 -0
  155. package/lib/cjs/core-backend.d.ts.map +1 -1
  156. package/lib/cjs/core-backend.js +2 -0
  157. package/lib/cjs/core-backend.js.map +1 -1
  158. package/lib/cjs/domains/FunctionalElements.d.ts +6 -12
  159. package/lib/cjs/domains/FunctionalElements.d.ts.map +1 -1
  160. package/lib/cjs/domains/FunctionalElements.js +0 -6
  161. package/lib/cjs/domains/FunctionalElements.js.map +1 -1
  162. package/lib/cjs/domains/FunctionalSchema.js.map +1 -1
  163. package/lib/cjs/domains/GenericElements.js.map +1 -1
  164. package/lib/cjs/domains/GenericSchema.js.map +1 -1
  165. package/lib/cjs/rpc/multipart.js.map +1 -1
  166. package/lib/cjs/rpc/tracing.js +2 -2
  167. package/lib/cjs/rpc/tracing.js.map +1 -1
  168. package/lib/cjs/rpc/web/logging.js.map +1 -1
  169. package/lib/cjs/rpc/web/request.js.map +1 -1
  170. package/lib/cjs/rpc/web/response.js.map +1 -1
  171. package/lib/cjs/rpc-impl/DevToolsRpcImpl.js.map +1 -1
  172. package/lib/cjs/rpc-impl/IModelReadRpcImpl.d.ts +5 -3
  173. package/lib/cjs/rpc-impl/IModelReadRpcImpl.d.ts.map +1 -1
  174. package/lib/cjs/rpc-impl/IModelReadRpcImpl.js +53 -36
  175. package/lib/cjs/rpc-impl/IModelReadRpcImpl.js.map +1 -1
  176. package/lib/cjs/rpc-impl/IModelTileRpcImpl.js.map +1 -1
  177. package/lib/cjs/rpc-impl/RpcBriefcaseUtility.d.ts.map +1 -1
  178. package/lib/cjs/rpc-impl/RpcBriefcaseUtility.js +0 -2
  179. package/lib/cjs/rpc-impl/RpcBriefcaseUtility.js.map +1 -1
  180. package/lib/cjs/rpc-impl/SnapshotIModelRpcImpl.js.map +1 -1
  181. package/lib/cjs/rpc-impl/WipRpcImpl.js.map +1 -1
  182. package/lib/cjs/workspace/Settings.js.map +1 -1
  183. package/lib/cjs/workspace/SettingsSchemas.js.map +1 -1
  184. package/lib/cjs/workspace/Workspace.d.ts +1 -1
  185. package/lib/cjs/workspace/Workspace.d.ts.map +1 -1
  186. package/lib/cjs/workspace/Workspace.js +4 -4
  187. package/lib/cjs/workspace/Workspace.js.map +1 -1
  188. package/package.json +21 -40
@@ -0,0 +1,1246 @@
1
+ "use strict";
2
+ /*---------------------------------------------------------------------------------------------
3
+ * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
4
+ * See LICENSE.md in the project root for license terms and full copyright notice.
5
+ *--------------------------------------------------------------------------------------------*/
6
+ /** @packageDocumentation
7
+ * @module ViewDefinitions
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.ViewStore = void 0;
11
+ const core_bentley_1 = require("@itwin/core-bentley");
12
+ const core_common_1 = require("@itwin/core-common");
13
+ const CloudSqlite_1 = require("./CloudSqlite");
14
+ const SQLiteDb_1 = require("./SQLiteDb");
15
+ const Category_1 = require("./Category");
16
+ const Model_1 = require("./Model");
17
+ /* eslint-disable @typescript-eslint/no-non-null-assertion */
18
+ // cspell:ignore nocase rowid
19
+ /**
20
+ * A ViewStore is a database that stores Views and related data. It is used to store and retrieve views for iTwin.js.
21
+ * It can either be a local SQLite file, or a CloudSqlite database stored in a cloud container. To use a CloudSqlite
22
+ * database, you must first create a container in Blob Storage and then call [[ViewStore.CloudAccess.initializeDb]].
23
+ *
24
+ * A ViewStore can hold:
25
+ * - Views
26
+ * - DisplayStyles
27
+ * - CategorySelectors
28
+ * - ModelSelectors
29
+ * - RenderTimelines
30
+ * - Searches
31
+ * - Tags
32
+ * - Thumbnails
33
+ * - ViewGroups
34
+ *
35
+ * Views are added to a ViewStore via ViewDefinitionProps that may hold references to a DisplayStyle, CategorySelector, ModelSelector, or RenderTimeline.
36
+ * Before storing a View, you must first add any referenced DisplayStyles, CategorySelectors, ModelSelectors, and RenderTimelines to the
37
+ * ViewStore. The "add" methods return a string that uniquely identifies the object in the ViewStore.
38
+ * You should set the ViewDefinitionProps's displayStyle, categorySelector, modelSelector, or renderTimeline member to the returned string.
39
+ * When you load a ViewDefinition from the ViewStore, the member may be used to load the DisplayStyle, CategorySelector,
40
+ * ModelSelector, RenderTimeline, etc.
41
+ *
42
+ * A IdString is a string that uniquely identifies a row in one of the ViewStore's internal tables. The string holds a base-36 integer
43
+ * that starts with "@" (vs. "0x" for ElementIds). For example, if you store a DisplayStyle and it is assigned the ViewStore Id "@y1", then you
44
+ * should set the ViewDefinitionProps's displayStyle member to "@y1". When you load the ViewDefinition from the ViewStore, the "@Y1" may be used to
45
+ * alo load the DisplayStyle from the ViewStore.
46
+ *
47
+ * Views are organized into hierarchical ViewGroups (like file and folder hierarchies on a file system). A View is always stored "in" a ViewGroup, and
48
+ * views must have a name that is unique within the ViewGroup. ViewGroups may each have a default ViewId.
49
+ * The root ViewGroup is named "Root" and has a RowId of 1. The root ViewGroup can not be deleted.
50
+ * View names and ViewGroup names may not contain either "/" or "@". ViewGroups are stored in the "viewGroups" table.
51
+ *
52
+ * Views may be "tagged" with one or more Tags. Tags are named with an arbitrary string that can be used to group Views. A Tag may
53
+ * be associated with multiple Views, and a View may have multiple Tags. Tags are stored in the "tags" table.
54
+ *
55
+ * Views may optionally have a thumbnail, paired via the View's Id. Thumbnails are stored in the "thumbnails" table.
56
+ *
57
+ * Note: All ElementIds and ModelIds in ModelSelectors, CategorySelectors, DisplayStyles, Timelines, etc. are converted to guid-based identifiers when stored in the ViewStore.
58
+ * They are then remapped back to their Ids when loaded from the ViewStore. This allows the ViewStore to be used with more than one iModel,
59
+ * provided that the same Guids are used in each iModel. This is done by storing the set of unique Guids in the "guids" table, and then
60
+ * creating a reference to the row in the "guids" table via the special Id prefix "^". For example, if a category selector contains the
61
+ * Id "0x123", then the guid from element 0x123 is stored in the "guids" table, and the category selector is stored with the rowId of the entry
62
+ * in the guid table (e.g. "^1w"). When the category selector is loaded from the ViewStore, the guid is looked up in the "guids" table and
63
+ * the iModel is queried for the element with that guid. That element's Id (which may or may not be 0x123) is then returned in the category selector.
64
+ *
65
+ * @beta
66
+ */
67
+ var ViewStore;
68
+ (function (ViewStore) {
69
+ ViewStore.tableName = {
70
+ categorySelectors: "categorySelectors",
71
+ displayStyles: "displayStyles",
72
+ viewGroups: "viewGroups",
73
+ guids: "guids",
74
+ modelSelectors: "modelSelectors",
75
+ taggedViews: "taggedViews",
76
+ tags: "tags",
77
+ thumbnails: "thumbnails",
78
+ timelines: "timelines",
79
+ searches: "searches",
80
+ views: "views",
81
+ };
82
+ /** convert a RowId to a RowString (base-36 integer with a leading "@") */
83
+ ViewStore.fromRowId = (rowId) => {
84
+ return `@${rowId.toString(36)}`;
85
+ };
86
+ /** convert a guid RowId to a GuidRowString (base-36 integer with a leading "^") */
87
+ const guidRowToString = (rowId) => {
88
+ return `^${rowId.toString(36)}`;
89
+ };
90
+ /** determine if a string is a guid row string (base-36 integer with a leading "^") */
91
+ const isGuidRowString = (id) => true === id?.startsWith("^");
92
+ /** @internal */
93
+ ViewStore.toRowId = (id) => {
94
+ if (typeof id === "number")
95
+ return id;
96
+ if (!core_common_1.ViewStoreRpc.isViewStoreId(id) && !isGuidRowString(id))
97
+ throw new Error(`invalid value: ${id}`);
98
+ return parseInt(id.slice(1), 36);
99
+ };
100
+ const maybeToRowId = (id) => undefined === id ? undefined : ViewStore.toRowId(id);
101
+ const cloneProps = (from) => JSON.parse(JSON.stringify(from));
102
+ const blankElementProps = (from, classFullName, idString, name) => {
103
+ from.id = ViewStore.fromRowId(ViewStore.toRowId(idString));
104
+ from.classFullName = classFullName;
105
+ from.model = core_common_1.IModel.dictionaryId;
106
+ from.code = { spec: "0x1", scope: "0x1", value: name };
107
+ return from;
108
+ };
109
+ const validateName = (name, msg) => {
110
+ if (name.trim().length === 0 || (/[@^#<>:"/\\"`'|?*\u0000-\u001F]/g.test(name)))
111
+ throw new Error(`illegal ${msg} name "${name}"`);
112
+ };
113
+ ViewStore.defaultViewGroupId = 1;
114
+ class ViewDb extends SQLiteDb_1.VersionedSqliteDb {
115
+ get guidMap() { return this._guidMap; }
116
+ set guidMap(guidMap) { this._guidMap = guidMap; }
117
+ get iModel() { return this._iModel; }
118
+ set iModel(iModel) { this._iModel = iModel; }
119
+ constructor(arg) {
120
+ super();
121
+ this.myVersion = "4.0.0";
122
+ this._iModel = arg?.iModel;
123
+ this._guidMap = arg?.guidMap ?? this._iModel?.elements; // this is only so tests can mock guids
124
+ }
125
+ /** create all the tables for a new ViewDb */
126
+ createDDL() {
127
+ const baseCols = "Id INTEGER PRIMARY KEY AUTOINCREMENT,json TEXT,owner TEXT";
128
+ this.createTable({
129
+ tableName: ViewStore.tableName.views,
130
+ columns: `${baseCols},name TEXT NOT NULL COLLATE NOCASE,className TEXT NOT NULL,private BOOLEAN NOT NULL,` +
131
+ `groupId INTEGER NOT NULL REFERENCES ${ViewStore.tableName.viewGroups}(Id) ON DELETE CASCADE, ` +
132
+ `modelSel INTEGER REFERENCES ${ViewStore.tableName.modelSelectors}(Id), ` +
133
+ `categorySel INTEGER NOT NULL REFERENCES ${ViewStore.tableName.categorySelectors}(Id), ` +
134
+ `displayStyle INTEGER NOT NULL REFERENCES ${ViewStore.tableName.displayStyles}(Id)`,
135
+ constraints: "UNIQUE(groupId,name)",
136
+ addTimestamp: true,
137
+ });
138
+ this.createTable({
139
+ tableName: ViewStore.tableName.viewGroups,
140
+ columns: `${baseCols},name TEXT NOT NULL COLLATE NOCASE,parent INTEGER NOT NULL REFERENCES ${ViewStore.tableName.viewGroups}(Id) ON DELETE CASCADE` +
141
+ `,defaultViewId INTEGER REFERENCES ${ViewStore.tableName.views}(Id)`,
142
+ constraints: "UNIQUE(parent,name)",
143
+ addTimestamp: true,
144
+ });
145
+ // for tables that have a "name" column, we want to enforce case-insensitive uniqueness. Names may be null.
146
+ const makeTable = (table, extra) => {
147
+ this.createTable({ tableName: table, columns: `${baseCols},name TEXT UNIQUE COLLATE NOCASE${extra ?? ""}`, addTimestamp: true });
148
+ };
149
+ makeTable(ViewStore.tableName.modelSelectors);
150
+ makeTable(ViewStore.tableName.categorySelectors);
151
+ makeTable(ViewStore.tableName.displayStyles);
152
+ makeTable(ViewStore.tableName.timelines);
153
+ makeTable(ViewStore.tableName.tags);
154
+ makeTable(ViewStore.tableName.searches);
155
+ this.createTable({ tableName: ViewStore.tableName.thumbnails, columns: `Id INTEGER PRIMARY KEY REFERENCES ${ViewStore.tableName.views} (Id) ON DELETE CASCADE,json,owner,data BLOB NOT NULL` });
156
+ this.createTable({
157
+ tableName: ViewStore.tableName.taggedViews, columns: `viewId INTEGER NOT NULL REFERENCES ${ViewStore.tableName.views} (Id) ON DELETE CASCADE,` +
158
+ `tagId INTEGER NOT NULL REFERENCES ${ViewStore.tableName.tags} (Id) ON DELETE CASCADE`,
159
+ constraints: `UNIQUE(tagId,viewId)`,
160
+ });
161
+ this.createTable({ tableName: ViewStore.tableName.guids, columns: `guid BLOB NOT NULL UNIQUE` });
162
+ this.addViewGroupRow({ name: "Root", json: JSON.stringify({}) });
163
+ }
164
+ /** get the row in the "guids" table for a given guid. If the guid is not present, return 0 */
165
+ getGuidRow(guid) {
166
+ return this.withPreparedSqliteStatement(`SELECT rowId FROM ${ViewStore.tableName.guids} WHERE guid=?`, (stmt) => {
167
+ stmt.bindGuid(1, guid);
168
+ return !stmt.nextRow() ? 0 : stmt.getValueInteger(0);
169
+ });
170
+ }
171
+ /** @internal */
172
+ getGuid(rowid) {
173
+ return this.withSqliteStatement(`SELECT guid FROM ${ViewStore.tableName.guids} WHERE rowId=?`, (stmt) => {
174
+ stmt.bindInteger(1, rowid);
175
+ return !stmt.nextRow() ? undefined : stmt.getValueGuid(0);
176
+ });
177
+ }
178
+ /** @internal */
179
+ iterateGuids(rowIds, fn) {
180
+ this.withSqliteStatement(`SELECT guid FROM ${ViewStore.tableName.guids} WHERE rowId=?`, (stmt) => {
181
+ for (const rowId of rowIds) {
182
+ stmt.reset();
183
+ stmt.bindInteger(1, rowId);
184
+ if (stmt.nextRow())
185
+ fn(stmt.getValueGuid(0), rowId);
186
+ }
187
+ });
188
+ }
189
+ /** @internal */
190
+ addGuid(guid) {
191
+ const existing = this.getGuidRow(guid);
192
+ return existing !== 0 ? existing : this.withPreparedSqliteStatement(`INSERT INTO ${ViewStore.tableName.guids} (guid) VALUES(?)`, (stmt) => {
193
+ stmt.bindGuid(1, guid);
194
+ stmt.stepForWrite();
195
+ return this.nativeDb.getLastInsertRowId();
196
+ });
197
+ }
198
+ /** @internal */
199
+ addViewRow(args) {
200
+ validateName(args.name, "view");
201
+ return this.withSqliteStatement(`INSERT INTO ${ViewStore.tableName.views} (className,name,json,owner,private,groupId,modelSel,categorySel,displayStyle) VALUES(?,?,?,?,?,?,?,?,?)`, (stmt) => {
202
+ stmt.bindString(1, args.className);
203
+ stmt.bindString(2, args.name);
204
+ stmt.bindString(3, args.json);
205
+ stmt.maybeBindString(4, args.owner);
206
+ stmt.bindBoolean(5, args.isPrivate ?? false);
207
+ stmt.bindInteger(6, args.groupId ?? 1);
208
+ stmt.maybeBindInteger(7, args.modelSel);
209
+ stmt.bindInteger(8, args.categorySel);
210
+ stmt.bindInteger(9, args.displayStyle);
211
+ stmt.stepForWrite();
212
+ return this.nativeDb.getLastInsertRowId();
213
+ });
214
+ }
215
+ /** @internal */
216
+ addViewGroupRow(args) {
217
+ validateName(args.name, "group");
218
+ return this.withSqliteStatement(`INSERT INTO ${ViewStore.tableName.viewGroups} (name,owner,parent,json) VALUES(?,?,?,?)`, (stmt) => {
219
+ stmt.bindString(1, args.name);
220
+ stmt.maybeBindString(2, args.owner);
221
+ stmt.bindInteger(3, args.parentId ?? 1);
222
+ stmt.bindString(4, args.json);
223
+ stmt.stepForWrite();
224
+ return this.nativeDb.getLastInsertRowId();
225
+ });
226
+ }
227
+ addTableRow(table, args) {
228
+ return this.withSqliteStatement(`INSERT INTO ${table} (name,json,owner) VALUES(?,?,?)`, (stmt) => {
229
+ stmt.maybeBindString(1, args.name);
230
+ stmt.bindString(2, args.json);
231
+ stmt.maybeBindString(3, args.owner);
232
+ stmt.stepForWrite();
233
+ return this.nativeDb.getLastInsertRowId();
234
+ });
235
+ }
236
+ /** add a row to the "modelSelectors" table, return the RowId
237
+ * @internal
238
+ */
239
+ addModelSelectorRow(args) {
240
+ return this.addTableRow(ViewStore.tableName.modelSelectors, args);
241
+ }
242
+ /** add a row to the "categorySelectors" table, return the RowId
243
+ * @internal
244
+ */
245
+ addCategorySelectorRow(args) {
246
+ return this.addTableRow(ViewStore.tableName.categorySelectors, args);
247
+ }
248
+ /** add a row to the "displayStyles" table, return the RowId
249
+ * @internal
250
+ */
251
+ addDisplayStyleRow(args) {
252
+ return this.addTableRow(ViewStore.tableName.displayStyles, args);
253
+ }
254
+ /** add a row to the "timelines" table, return the RowId
255
+ * @internal
256
+ */
257
+ addTimelineRow(args) {
258
+ return this.addTableRow(ViewStore.tableName.timelines, args);
259
+ }
260
+ /** add a row to the "tags" table, return the RowId
261
+ * @internal
262
+ */
263
+ addTag(args) {
264
+ return this.addTableRow(ViewStore.tableName.tags, args);
265
+ }
266
+ /** add a row to the "searches" table, return the RowId
267
+ * @internal
268
+ */
269
+ async addSearch(args) {
270
+ return this.addTableRow(ViewStore.tableName.searches, args);
271
+ }
272
+ /** add or update a row in the "thumbnails" table, return the RowId
273
+ * @internal
274
+ */
275
+ addOrReplaceThumbnailRow(args) {
276
+ return this.withSqliteStatement(`INSERT OR REPLACE INTO ${ViewStore.tableName.thumbnails} (Id,json,owner,data) VALUES(?,?,?,?)`, (stmt) => {
277
+ stmt.bindInteger(1, args.viewId);
278
+ stmt.bindString(2, JSON.stringify(args.format));
279
+ stmt.maybeBindString(3, args.owner);
280
+ stmt.bindBlob(4, args.data);
281
+ stmt.stepForWrite();
282
+ return this.nativeDb.getLastInsertRowId();
283
+ });
284
+ }
285
+ deleteFromTable(table, id) {
286
+ this.withSqliteStatement(`DELETE FROM ${table} WHERE Id=?`, (stmt) => {
287
+ stmt.bindInteger(1, ViewStore.toRowId(id));
288
+ stmt.stepForWrite();
289
+ });
290
+ }
291
+ /** @internal */
292
+ deleteViewRow(id) {
293
+ return this.deleteFromTable(ViewStore.tableName.views, id);
294
+ }
295
+ async deleteViewGroup(args) {
296
+ const rowId = this.findViewGroup(args.name);
297
+ if (rowId === 1)
298
+ throw new Error("Cannot delete root group");
299
+ return this.deleteFromTable(ViewStore.tableName.viewGroups, rowId);
300
+ }
301
+ deleteModelSelectorSync(id) {
302
+ return this.deleteFromTable(ViewStore.tableName.modelSelectors, id);
303
+ }
304
+ async deleteModelSelector(args) {
305
+ return this.deleteModelSelectorSync(args.id);
306
+ }
307
+ deleteCategorySelectorSync(id) {
308
+ return this.deleteFromTable(ViewStore.tableName.categorySelectors, id);
309
+ }
310
+ deleteDisplayStyleSync(id) {
311
+ return this.deleteFromTable(ViewStore.tableName.displayStyles, id);
312
+ }
313
+ deleteTimelineSync(id) {
314
+ return this.deleteFromTable(ViewStore.tableName.timelines, id);
315
+ }
316
+ deleteTagSync(arg) {
317
+ const id = this.findTagByName(arg.name);
318
+ return this.deleteFromTable(ViewStore.tableName.tags, id);
319
+ }
320
+ async deleteTag(arg) {
321
+ return this.deleteTagSync(arg);
322
+ }
323
+ async deleteCategorySelector(args) {
324
+ return this.deleteCategorySelectorSync(args.id);
325
+ }
326
+ async deleteDisplayStyle(args) {
327
+ return this.deleteDisplayStyleSync(args.id);
328
+ }
329
+ async deleteTimeline(args) {
330
+ return this.deleteTimelineSync(args.id);
331
+ }
332
+ deleteSearch(id) {
333
+ return this.deleteFromTable(ViewStore.tableName.searches, id);
334
+ }
335
+ deleteThumbnailSync(id) {
336
+ return this.deleteFromTable(ViewStore.tableName.thumbnails, ViewStore.toRowId(id));
337
+ }
338
+ async deleteThumbnail(arg) {
339
+ return this.deleteThumbnailSync(arg.viewId);
340
+ }
341
+ /** get the data for a view from the database
342
+ * @internal
343
+ */
344
+ getViewRow(viewId) {
345
+ return this.withSqliteStatement(`SELECT className,name,json,owner,private,groupId,modelSel,categorySel,displayStyle FROM ${ViewStore.tableName.views} WHERE Id=?`, (stmt) => {
346
+ stmt.bindInteger(1, viewId);
347
+ return !stmt.nextRow() ? undefined : {
348
+ className: stmt.getValueString(0),
349
+ name: stmt.getValueString(1),
350
+ json: stmt.getValueString(2),
351
+ owner: stmt.getValueStringMaybe(3),
352
+ isPrivate: stmt.getValueBoolean(4),
353
+ groupId: stmt.getValueInteger(5),
354
+ modelSel: stmt.getValueIntegerMaybe(6),
355
+ categorySel: stmt.getValueInteger(7),
356
+ displayStyle: stmt.getValueInteger(8),
357
+ };
358
+ });
359
+ }
360
+ /** @internal */
361
+ getThumbnailRow(viewId) {
362
+ return this.withSqliteStatement(`SELECT json,owner,data FROM ${ViewStore.tableName.thumbnails} WHERE Id=?`, (stmt) => {
363
+ stmt.bindInteger(1, viewId);
364
+ return !stmt.nextRow() ? undefined : {
365
+ viewId,
366
+ format: JSON.parse(stmt.getValueString(0)),
367
+ owner: stmt.getValueStringMaybe(1),
368
+ data: stmt.getValueBlob(2),
369
+ };
370
+ });
371
+ }
372
+ /** @internal */
373
+ getViewGroup(id) {
374
+ return this.withSqliteStatement(`SELECT name,owner,json,parent,defaultViewId FROM ${ViewStore.tableName.viewGroups} WHERE Id=?`, (stmt) => {
375
+ stmt.bindInteger(1, id);
376
+ return !stmt.nextRow() ? undefined : {
377
+ name: stmt.getValueString(0),
378
+ owner: stmt.getValueStringMaybe(1),
379
+ json: stmt.getValueString(2),
380
+ parentId: stmt.getValueInteger(3),
381
+ defaultViewId: stmt.getValueIntegerMaybe(4),
382
+ };
383
+ });
384
+ }
385
+ getTableRow(table, id) {
386
+ return this.withSqliteStatement(`SELECT name,json,owner FROM ${table} WHERE Id=?`, (stmt) => {
387
+ stmt.bindInteger(1, id);
388
+ return !stmt.nextRow() ? undefined : {
389
+ name: stmt.getValueStringMaybe(0),
390
+ json: stmt.getValueString(1),
391
+ owner: stmt.getValueStringMaybe(2),
392
+ };
393
+ });
394
+ }
395
+ /** read a ModelSelector given a rowId
396
+ * @internal
397
+ */
398
+ getModelSelectorRow(id) {
399
+ return this.getTableRow(ViewStore.tableName.modelSelectors, id);
400
+ }
401
+ /** read a CategorySelector given a rowId
402
+ * @internal
403
+ */
404
+ getCategorySelectorRow(id) {
405
+ return this.getTableRow(ViewStore.tableName.categorySelectors, id);
406
+ }
407
+ /** read a DisplayStyle given a rowId
408
+ * @internal
409
+ */
410
+ getDisplayStyleRow(id) {
411
+ return this.getTableRow(ViewStore.tableName.displayStyles, id);
412
+ }
413
+ /** @internal */
414
+ getTimelineRow(id) {
415
+ return this.getTableRow(ViewStore.tableName.timelines, id);
416
+ }
417
+ /** @internal */
418
+ getTag(id) {
419
+ return this.getTableRow(ViewStore.tableName.tags, id);
420
+ }
421
+ /** @internal */
422
+ getSearch(id) {
423
+ return this.getTableRow(ViewStore.tableName.searches, id);
424
+ }
425
+ updateJson(table, id, json) {
426
+ this.withSqliteStatement(`UPDATE ${table} SET json=? WHERE Id=?`, (stmt) => {
427
+ stmt.bindString(1, json);
428
+ stmt.bindInteger(2, ViewStore.toRowId(id));
429
+ stmt.stepForWrite();
430
+ });
431
+ }
432
+ async updateViewShared(arg) {
433
+ if (!arg.isShared && arg.owner === undefined)
434
+ throw new Error("owner must be defined for private views");
435
+ this.withSqliteStatement(`UPDATE ${ViewStore.tableName.views} SET private=?,owner=? WHERE Id=?`, (stmt) => {
436
+ stmt.bindBoolean(1, !arg.isShared);
437
+ stmt.maybeBindString(2, arg.owner);
438
+ stmt.bindInteger(3, ViewStore.toRowId(arg.viewId));
439
+ stmt.stepForWrite();
440
+ });
441
+ }
442
+ /** @internal */
443
+ updateViewGroupJson(groupId, json) {
444
+ return this.updateJson(ViewStore.tableName.viewGroups, groupId, json);
445
+ }
446
+ /** @internal */
447
+ updateModelSelectorJson(modelSelectorId, json) {
448
+ return this.updateJson(ViewStore.tableName.modelSelectors, modelSelectorId, json);
449
+ }
450
+ /** @internal */
451
+ updateCategorySelectorJson(categorySelectorId, json) {
452
+ return this.updateJson(ViewStore.tableName.categorySelectors, categorySelectorId, json);
453
+ }
454
+ /** @internal */
455
+ updateDisplayStyleJson(styleId, json) {
456
+ return this.updateJson(ViewStore.tableName.displayStyles, styleId, json);
457
+ }
458
+ /** @internal */
459
+ updateTimelineJson(timelineId, json) {
460
+ return this.updateJson(ViewStore.tableName.timelines, timelineId, json);
461
+ }
462
+ /** @internal */
463
+ updateSearchJson(searchId, json) {
464
+ return this.updateJson(ViewStore.tableName.searches, searchId, json);
465
+ }
466
+ updateName(table, id, name) {
467
+ this.withSqliteStatement(`UPDATE ${table} SET name=? WHERE Id=?`, (stmt) => {
468
+ stmt.maybeBindString(1, name);
469
+ stmt.bindInteger(2, ViewStore.toRowId(id));
470
+ stmt.stepForWrite();
471
+ });
472
+ }
473
+ async renameView(args) {
474
+ return this.updateName(ViewStore.tableName.views, args.viewId, args.name);
475
+ }
476
+ async renameViewGroup(args) {
477
+ return this.updateName(ViewStore.tableName.viewGroups, args.groupId, args.name);
478
+ }
479
+ async renameModelSelector(args) {
480
+ return this.updateName(ViewStore.tableName.modelSelectors, args.id, args.name);
481
+ }
482
+ async renameCategorySelector(args) {
483
+ return this.updateName(ViewStore.tableName.categorySelectors, args.id, args.name);
484
+ }
485
+ async renameDisplayStyle(args) {
486
+ return this.updateName(ViewStore.tableName.displayStyles, args.id, args.name);
487
+ }
488
+ async renameTimeline(args) {
489
+ return this.updateName(ViewStore.tableName.timelines, args.id, args.name);
490
+ }
491
+ async renameSearch(args) {
492
+ return this.updateName(ViewStore.tableName.searches, args.id, args.name);
493
+ }
494
+ async renameTag(args) {
495
+ this.withSqliteStatement(`UPDATE ${ViewStore.tableName.tags} SET name=? WHERE name=?`, (stmt) => {
496
+ stmt.bindString(1, args.newName);
497
+ stmt.bindString(2, args.oldName);
498
+ stmt.stepForWrite();
499
+ });
500
+ }
501
+ /** @internal */
502
+ addTagToView(args) {
503
+ this.withSqliteStatement(`INSERT OR IGNORE INTO ${ViewStore.tableName.taggedViews} (viewId,tagId) VALUES(?,?)`, (stmt) => {
504
+ stmt.bindInteger(1, args.viewId);
505
+ stmt.bindInteger(2, args.tagId);
506
+ stmt.stepForWrite();
507
+ });
508
+ }
509
+ deleteViewTag(args) {
510
+ this.withSqliteStatement(`DELETE FROM ${ViewStore.tableName.taggedViews} WHERE viewId=? AND tagId=?`, (stmt) => {
511
+ stmt.bindInteger(1, args.viewId);
512
+ stmt.bindInteger(2, args.tagId);
513
+ stmt.stepForWrite();
514
+ });
515
+ }
516
+ /** @internal */
517
+ findViewsForTag(tagId) {
518
+ return this.withSqliteStatement(`SELECT viewId FROM ${ViewStore.tableName.taggedViews} WHERE tagId=?`, (stmt) => {
519
+ stmt.bindInteger(1, tagId);
520
+ const list = [];
521
+ while (stmt.nextRow())
522
+ list.push(stmt.getValueInteger(0));
523
+ return list;
524
+ });
525
+ }
526
+ findByName(table, name) {
527
+ return this.withSqliteStatement(`SELECT Id FROM ${table} WHERE name=?`, (stmt) => {
528
+ stmt.bindString(1, name);
529
+ return !stmt.nextRow() ? 0 : stmt.getValueInteger(0);
530
+ });
531
+ }
532
+ /** @internal */
533
+ getViewGroupByName(name, parentId) {
534
+ return this.withSqliteStatement(`SELECT Id FROM ${ViewStore.tableName.viewGroups} WHERE name=? AND parent=?`, (stmt) => {
535
+ stmt.bindString(1, name);
536
+ stmt.bindInteger(2, parentId);
537
+ return !stmt.nextRow() ? 0 : stmt.getValueInteger(0);
538
+ });
539
+ }
540
+ /** @internal */
541
+ findModelSelectorByName(name) {
542
+ return this.findByName(ViewStore.tableName.modelSelectors, name);
543
+ }
544
+ /** @internal */
545
+ findCategorySelectorByName(name) {
546
+ return this.findByName(ViewStore.tableName.categorySelectors, name);
547
+ }
548
+ /** @internal */
549
+ findDisplayStyleByName(name) {
550
+ return this.findByName(ViewStore.tableName.displayStyles, name);
551
+ }
552
+ /** @internal */
553
+ findTagByName(name) {
554
+ return this.findByName(ViewStore.tableName.tags, name);
555
+ }
556
+ /** @internal */
557
+ findTimelineByName(name) {
558
+ return this.findByName(ViewStore.tableName.timelines, name);
559
+ }
560
+ /** @internal */
561
+ findSearchByName(name) {
562
+ return this.findByName(ViewStore.tableName.searches, name);
563
+ }
564
+ getViewInfoSync(id) {
565
+ const maybeId = (rowId) => rowId ? ViewStore.fromRowId(rowId) : undefined;
566
+ return this.withPreparedSqliteStatement(`SELECT owner,className,name,private,groupId,modelSel,categorySel,displayStyle FROM ${ViewStore.tableName.views} WHERE id=?`, (stmt) => {
567
+ const viewId = ViewStore.toRowId(id);
568
+ stmt.bindInteger(1, viewId);
569
+ return stmt.nextRow() ? {
570
+ id: ViewStore.fromRowId(viewId),
571
+ owner: stmt.getValueString(0),
572
+ className: stmt.getValueString(1),
573
+ name: stmt.getValueStringMaybe(2),
574
+ isPrivate: stmt.getValueBoolean(3),
575
+ groupId: ViewStore.fromRowId(stmt.getValueInteger(4)),
576
+ modelSelectorId: maybeId(stmt.getValueInteger(5)),
577
+ categorySelectorId: ViewStore.fromRowId(stmt.getValueInteger(6)),
578
+ displayStyleId: ViewStore.fromRowId(stmt.getValueInteger(7)),
579
+ tags: this.getTagsForView(viewId),
580
+ } : undefined;
581
+ });
582
+ }
583
+ async getViewInfo(args) {
584
+ return this.getViewInfoSync(args.viewId);
585
+ }
586
+ async findViewsByOwner(args) {
587
+ const list = [];
588
+ this.withSqliteStatement(`SELECT Id FROM ${ViewStore.tableName.views} WHERE owner=? ORDER BY Id ASC`, (stmt) => {
589
+ stmt.bindString(1, args.owner);
590
+ while (stmt.nextRow()) {
591
+ const info = this.getViewInfoSync(stmt.getValueInteger(0));
592
+ if (info)
593
+ list.push(info);
594
+ }
595
+ });
596
+ return list;
597
+ }
598
+ /** @internal */
599
+ findTagIdsForView(viewId) {
600
+ return this.withSqliteStatement(`SELECT tagId FROM ${ViewStore.tableName.taggedViews} WHERE viewId=?`, (stmt) => {
601
+ stmt.bindInteger(1, viewId);
602
+ const list = [];
603
+ while (stmt.nextRow())
604
+ list.push(stmt.getValueInteger(0));
605
+ return list;
606
+ });
607
+ }
608
+ toGuidRow(id) {
609
+ if (undefined === id)
610
+ return undefined;
611
+ const fedGuid = this.guidMap.getFederationGuidFromId(id);
612
+ return fedGuid ? this.addGuid(fedGuid) : undefined;
613
+ }
614
+ toCompressedGuidRows(ids) {
615
+ const result = new Set();
616
+ for (const id of (typeof ids === "string" ? core_bentley_1.CompressedId64Set.iterable(ids) : ids)) {
617
+ const guidRow = this.toGuidRow(id);
618
+ if (undefined !== guidRow)
619
+ result.add(core_bentley_1.Id64.fromLocalAndBriefcaseIds(guidRow, 0));
620
+ }
621
+ return core_bentley_1.CompressedId64Set.compressSet(result);
622
+ }
623
+ fromGuidRow(guidRow) {
624
+ return this.guidMap.getIdFromFederationGuid(this.getGuid(guidRow));
625
+ }
626
+ fromGuidRowString(id) {
627
+ return (typeof id !== "string" || !isGuidRowString(id)) ? id : this.fromGuidRow(ViewStore.toRowId(id));
628
+ }
629
+ iterateCompressedGuidRows(guidRows, callback) {
630
+ if (typeof guidRows !== "string")
631
+ return;
632
+ for (const rowId64String of core_bentley_1.CompressedId64Set.iterable(guidRows)) {
633
+ const elId = this.fromGuidRow(core_bentley_1.Id64.getLocalId(rowId64String));
634
+ if (undefined !== elId)
635
+ callback(elId);
636
+ }
637
+ }
638
+ fromCompressedGuidRows(guidRows) {
639
+ const result = new Set();
640
+ this.iterateCompressedGuidRows(guidRows, (id) => result.add(id));
641
+ return core_bentley_1.CompressedId64Set.compressSet(result);
642
+ }
643
+ toGuidRowMember(base, memberName) {
644
+ const id = base?.[memberName];
645
+ if (id === undefined)
646
+ return;
647
+ if (typeof id === "string") {
648
+ if (isGuidRowString(id)) {
649
+ // member is already a guid row. Make sure it exists.
650
+ if (undefined === this.getGuid(ViewStore.toRowId(id)))
651
+ throw new Error(`${memberName} id does not exist`);
652
+ return;
653
+ }
654
+ const guidRow = this.toGuidRow(id);
655
+ if (undefined !== guidRow) {
656
+ base[memberName] = guidRowToString(guidRow);
657
+ return;
658
+ }
659
+ }
660
+ throw new Error(`invalid ${memberName}: ${id} `);
661
+ }
662
+ fromGuidRowMember(base, memberName) {
663
+ const id = base?.[memberName];
664
+ if (id === undefined)
665
+ return;
666
+ if (typeof id === "string" && isGuidRowString(id)) {
667
+ const elId = this.fromGuidRow(ViewStore.toRowId(id));
668
+ if (undefined !== elId) {
669
+ base[memberName] = elId;
670
+ return;
671
+ }
672
+ }
673
+ throw new Error(`invalid ${memberName}: ${id} `);
674
+ }
675
+ verifyRowId(table, rowIdString) {
676
+ try {
677
+ const rowId = ViewStore.toRowId(rowIdString);
678
+ this.withSqliteStatement(`SELECT 1 FROM ${table} WHERE Id=?`, (stmt) => {
679
+ stmt.bindInteger(1, rowId);
680
+ if (!stmt.nextRow())
681
+ throw new Error(`missing: ${rowIdString} `);
682
+ });
683
+ return rowId;
684
+ }
685
+ catch (err) {
686
+ throw new Error(`invalid Id for ${table}: ${err.message} `);
687
+ }
688
+ }
689
+ scriptToGuids(script) {
690
+ const scriptProps = [];
691
+ for (const model of script) {
692
+ const modelGuidRow = this.toGuidRow(model.modelId);
693
+ if (modelGuidRow) {
694
+ model.modelId = guidRowToString(modelGuidRow);
695
+ scriptProps.push(model);
696
+ for (const batch of model.elementTimelines)
697
+ batch.elementIds = this.toCompressedGuidRows(batch.elementIds);
698
+ }
699
+ }
700
+ return scriptProps;
701
+ }
702
+ scriptFromGuids(script, omitElementIds) {
703
+ const scriptProps = [];
704
+ for (const model of script) {
705
+ const modelId = this.fromGuidRow(ViewStore.toRowId(model.modelId));
706
+ if (modelId) {
707
+ model.modelId = modelId;
708
+ scriptProps.push(model);
709
+ for (const batch of model.elementTimelines) {
710
+ if (undefined !== batch.elementIds)
711
+ batch.elementIds = omitElementIds ? "" : this.fromCompressedGuidRows(batch.elementIds);
712
+ }
713
+ }
714
+ }
715
+ return scriptProps;
716
+ }
717
+ async addViewGroup(args) {
718
+ const parentId = args.parentId ? this.findViewGroup(args.parentId) : ViewStore.defaultViewGroupId;
719
+ const json = JSON.stringify({});
720
+ return ViewStore.fromRowId(this.addViewGroupRow({ name: args.name, parentId, json, owner: args.owner }));
721
+ }
722
+ async getViewGroups(args) {
723
+ const parentIdRow = args.parent ? this.findViewGroup(args.parent) : ViewStore.defaultViewGroupId;
724
+ const groups = [];
725
+ this.withSqliteStatement(`SELECT Id,Name FROM ${ViewStore.tableName.viewGroups} WHERE ParentId=?`, (stmt) => {
726
+ stmt.bindInteger(1, parentIdRow);
727
+ while (stmt.nextRow()) {
728
+ const id = stmt.getValueInteger(0);
729
+ if (id !== ViewStore.defaultViewGroupId) // don't include root group
730
+ groups.push({ id: ViewStore.fromRowId(id), name: stmt.getValueString(1) });
731
+ }
732
+ });
733
+ return groups;
734
+ }
735
+ makeSelectorJson(props, entity) {
736
+ const selector = { ...props }; // shallow copy
737
+ if (selector.query) {
738
+ selector.query = { ...selector.query }; // shallow copy
739
+ selector.query.from = selector.query.from.toLowerCase().replace(".", ":").replace("bis:", "biscore:");
740
+ if (!this.iModel.getJsClass(selector.query.from).is(entity))
741
+ throw new Error(`query must select from ${entity.classFullName}`);
742
+ if (selector.query.adds)
743
+ selector.query.adds = this.toCompressedGuidRows(selector.query.adds);
744
+ if (selector.query.removes)
745
+ selector.query.removes = this.toCompressedGuidRows(selector.query.removes);
746
+ }
747
+ else {
748
+ if (!(selector.ids.length))
749
+ throw new Error(`Selector must specify at least one ${entity.className}`);
750
+ selector.ids = this.toCompressedGuidRows(selector.ids);
751
+ }
752
+ return JSON.stringify(selector);
753
+ }
754
+ querySelectorValues(json, bindings) {
755
+ if (typeof json !== "object")
756
+ throw new Error("invalid selector");
757
+ const props = json;
758
+ if (!props.query) {
759
+ // there's no query, so the ids are the list of elements
760
+ return (typeof props.ids === "string") ? core_bentley_1.CompressedId64Set.decompressArray(this.fromCompressedGuidRows(props.ids)) : [];
761
+ }
762
+ const query = props.query;
763
+ const sql = `SELECT ECInstanceId FROM ${query.only ? "ONLY " : ""}${query.from}${query.where ? ` WHERE ${query.where}` : ""}`;
764
+ const ids = new Set();
765
+ try {
766
+ this.iModel.withStatement(sql, (stmt) => {
767
+ if (bindings)
768
+ stmt.bindValues(bindings);
769
+ for (const el of stmt) {
770
+ if (typeof el.id === "string")
771
+ ids.add(el.id);
772
+ }
773
+ });
774
+ this.iterateCompressedGuidRows(props.query.adds, (id) => ids.add(id));
775
+ this.iterateCompressedGuidRows(props.query.removes, (id) => ids.delete(id)); // removes take precedence over adds
776
+ }
777
+ catch (err) {
778
+ core_bentley_1.Logger.logError("ViewStore", `querySelectorValues: ${err.message}`);
779
+ }
780
+ return [...ids];
781
+ }
782
+ async addCategorySelector(args) {
783
+ const json = this.makeSelectorJson(args.selector, Category_1.Category);
784
+ return ViewStore.fromRowId(this.addCategorySelectorRow({ name: args.name, owner: args.owner, json }));
785
+ }
786
+ async updateCategorySelector(args) {
787
+ const rowId = this.getRowId(ViewStore.tableName.categorySelectors, args);
788
+ const json = this.makeSelectorJson(args.selector, Category_1.Category);
789
+ return this.updateCategorySelectorJson(rowId, json);
790
+ }
791
+ getRowId(table, arg) {
792
+ return undefined !== arg.name ? this.findByName(table, arg.name) : ViewStore.toRowId(arg.id);
793
+ }
794
+ /** @internal */
795
+ getCategorySelectorSync(args) {
796
+ const rowId = this.getRowId(ViewStore.tableName.categorySelectors, args);
797
+ const row = this.getCategorySelectorRow(rowId);
798
+ if (undefined === row)
799
+ throw new Error("CategorySelector not found");
800
+ const props = blankElementProps({}, "BisCore:CategorySelector", rowId, row.name);
801
+ props.categories = this.querySelectorValues(JSON.parse(row.json), args.bindings);
802
+ return props;
803
+ }
804
+ async getCategorySelector(args) {
805
+ return this.getCategorySelectorSync(args);
806
+ }
807
+ async addModelSelector(args) {
808
+ const json = this.makeSelectorJson(args.selector, Model_1.Model);
809
+ return ViewStore.fromRowId(this.addModelSelectorRow({ name: args.name, owner: args.owner, json }));
810
+ }
811
+ async updateModelSelector(args) {
812
+ const rowId = this.getRowId(ViewStore.tableName.modelSelectors, args);
813
+ const json = this.makeSelectorJson(args.selector, Model_1.Model);
814
+ return this.updateModelSelectorJson(rowId, json);
815
+ }
816
+ getModelSelectorSync(args) {
817
+ const rowId = this.getRowId(ViewStore.tableName.modelSelectors, args);
818
+ const row = this.getModelSelectorRow(rowId);
819
+ if (undefined === row)
820
+ throw new Error("ModelSelector not found");
821
+ const props = blankElementProps({}, "BisCore:ModelSelector", rowId, row?.name);
822
+ props.models = this.querySelectorValues(JSON.parse(row.json), args.bindings);
823
+ return props;
824
+ }
825
+ async getModelSelector(args) {
826
+ return this.getModelSelectorSync(args);
827
+ }
828
+ makeTimelineJson(timeline) {
829
+ timeline = cloneProps(timeline);
830
+ if (!Array.isArray(timeline))
831
+ throw new Error("Timeline has no entries");
832
+ return JSON.stringify(this.scriptToGuids(timeline));
833
+ }
834
+ async addTimeline(args) {
835
+ const json = this.makeTimelineJson(args.timeline);
836
+ return ViewStore.fromRowId(this.addTimelineRow({ name: args.name, owner: args.owner, json }));
837
+ }
838
+ async updateTimeline(args) {
839
+ const rowId = this.getRowId(ViewStore.tableName.timelines, args);
840
+ const json = this.makeTimelineJson(args.timeline);
841
+ return this.updateTimelineJson(rowId, json);
842
+ }
843
+ getTimelineSync(args) {
844
+ const rowId = this.getRowId(ViewStore.tableName.timelines, args);
845
+ const row = this.getTimelineRow(rowId);
846
+ if (undefined === row)
847
+ throw new Error("Timeline not found");
848
+ const props = blankElementProps({}, "BisCore:RenderTimeline", rowId, row?.name);
849
+ props.script = JSON.stringify(this.scriptFromGuids(JSON.parse(row.json), false));
850
+ return props;
851
+ }
852
+ async getTimeline(args) {
853
+ return this.getTimelineSync(args);
854
+ }
855
+ /** make a JSON string for a DisplayStyle */
856
+ makeDisplayStyleJson(args) {
857
+ const settings = cloneProps(args.settings); // don't modify input
858
+ if (settings.subCategoryOvr) {
859
+ const outOvr = [];
860
+ for (const ovr of settings.subCategoryOvr) {
861
+ const subCategoryGuidRow = this.toGuidRow(ovr.subCategory);
862
+ if (subCategoryGuidRow) {
863
+ ovr.subCategory = guidRowToString(subCategoryGuidRow);
864
+ outOvr.push(ovr);
865
+ }
866
+ }
867
+ settings.subCategoryOvr = outOvr;
868
+ }
869
+ if (settings.excludedElements)
870
+ settings.excludedElements = this.toCompressedGuidRows(settings.excludedElements);
871
+ const settings3d = settings;
872
+ if (settings3d.planProjections) {
873
+ const planProjections = {};
874
+ for (const entry of Object.entries(settings3d.planProjections)) {
875
+ const modelGuidRow = this.toGuidRow(entry[0]);
876
+ if (modelGuidRow)
877
+ planProjections[guidRowToString(modelGuidRow)] = entry[1];
878
+ }
879
+ settings3d.planProjections = planProjections;
880
+ }
881
+ if (settings.renderTimeline) {
882
+ if (!core_common_1.ViewStoreRpc.isViewStoreId(settings.renderTimeline))
883
+ this.toGuidRowMember(settings, "renderTimeline");
884
+ delete settings.scheduleScript;
885
+ }
886
+ else if (settings.scheduleScript) {
887
+ const scriptProps = this.scriptToGuids(settings.scheduleScript);
888
+ if (scriptProps.length > 0)
889
+ settings.scheduleScript = scriptProps;
890
+ }
891
+ return JSON.stringify({ settings, className: args.className });
892
+ }
893
+ async addDisplayStyle(args) {
894
+ const json = this.makeDisplayStyleJson(args);
895
+ return ViewStore.fromRowId(this.addDisplayStyleRow({ name: args.name, owner: args.owner, json }));
896
+ }
897
+ async updateDisplayStyle(args) {
898
+ const rowId = this.getRowId(ViewStore.tableName.displayStyles, args);
899
+ const json = this.makeDisplayStyleJson(args);
900
+ return this.updateDisplayStyleJson(rowId, json);
901
+ }
902
+ getDisplayStyleSync(args) {
903
+ const rowId = this.getRowId(ViewStore.tableName.displayStyles, args);
904
+ const row = this.getDisplayStyleRow(rowId);
905
+ if (undefined === row)
906
+ throw new Error("DisplayStyle not found");
907
+ const val = JSON.parse(row.json);
908
+ const props = blankElementProps({}, val.className, rowId, row.name);
909
+ props.jsonProperties = { styles: val.settings };
910
+ const settings = val.settings;
911
+ if (settings.subCategoryOvr) {
912
+ const subCatOvr = [];
913
+ for (const ovr of settings.subCategoryOvr) {
914
+ const id = this.fromGuidRowString(ovr.subCategory);
915
+ if (undefined !== id) {
916
+ ovr.subCategory = id;
917
+ subCatOvr.push(ovr);
918
+ }
919
+ }
920
+ settings.subCategoryOvr = subCatOvr;
921
+ }
922
+ if (settings.excludedElements)
923
+ settings.excludedElements = this.fromCompressedGuidRows(settings.excludedElements);
924
+ const settings3d = settings;
925
+ if (settings3d.planProjections) {
926
+ const planProjections = {};
927
+ for (const entry of Object.entries(settings3d.planProjections)) {
928
+ const modelId = this.fromGuidRowString(entry[0]);
929
+ if (undefined !== modelId)
930
+ planProjections[modelId] = entry[1];
931
+ }
932
+ settings3d.planProjections = planProjections;
933
+ }
934
+ if (isGuidRowString(settings.renderTimeline))
935
+ settings.renderTimeline = this.fromGuidRowString(settings.renderTimeline);
936
+ if (undefined !== settings.renderTimeline) {
937
+ delete settings.scheduleScript;
938
+ }
939
+ else if (settings.scheduleScript) {
940
+ delete settings.renderTimeline;
941
+ settings.scheduleScript = this.scriptFromGuids(settings.scheduleScript, args.opts?.omitScheduleScriptElementIds === true);
942
+ }
943
+ return props;
944
+ }
945
+ async getDisplayStyle(args) {
946
+ return this.getDisplayStyleSync(args);
947
+ }
948
+ makeViewDefinitionProps(viewDefinition) {
949
+ const viewDef = cloneProps(viewDefinition); // don't modify input
950
+ this.verifyRowId(ViewStore.tableName.categorySelectors, viewDef.categorySelectorId);
951
+ this.verifyRowId(ViewStore.tableName.displayStyles, viewDef.displayStyleId);
952
+ if (viewDef.modelSelectorId)
953
+ this.verifyRowId(ViewStore.tableName.modelSelectors, viewDef.modelSelectorId);
954
+ this.toGuidRowMember(viewDef, "baseModelId");
955
+ this.toGuidRowMember(viewDef.jsonProperties?.viewDetails, "acs");
956
+ const props = viewDef;
957
+ delete props.id;
958
+ delete props.federationGuid;
959
+ delete props.parent;
960
+ delete props.code;
961
+ delete props.model;
962
+ return viewDef;
963
+ }
964
+ addViewDefinition(args) {
965
+ const name = args.viewDefinition.code.value;
966
+ if (name === undefined)
967
+ throw new Error("ViewDefinition must have a name");
968
+ const groupId = args.group ? this.findViewGroup(args.group) : ViewStore.defaultViewGroupId;
969
+ const maybeRow = (rowString) => rowString ? ViewStore.toRowId(rowString) : undefined;
970
+ const viewDef = this.makeViewDefinitionProps(args.viewDefinition);
971
+ try {
972
+ return this.addViewRow({
973
+ name,
974
+ className: viewDef.classFullName,
975
+ owner: args.owner,
976
+ groupId,
977
+ isPrivate: args.isPrivate,
978
+ json: JSON.stringify(viewDef),
979
+ modelSel: maybeRow(viewDef.modelSelectorId),
980
+ categorySel: ViewStore.toRowId(viewDef.categorySelectorId),
981
+ displayStyle: ViewStore.toRowId(viewDef.displayStyleId),
982
+ });
983
+ }
984
+ catch (e) {
985
+ const err = e;
986
+ if (err.errorId === "DuplicateValue")
987
+ err.message = `View "${name}" already exists`;
988
+ throw e;
989
+ }
990
+ }
991
+ async updateViewDefinition(args) {
992
+ const maybeRow = (rowString) => rowString ? ViewStore.toRowId(rowString) : undefined;
993
+ const viewDef = this.makeViewDefinitionProps(args.viewDefinition);
994
+ this.withSqliteStatement(`UPDATE ${ViewStore.tableName.views} SET json=?,modelSel=?,categorySel=?,displayStyle=? WHERE Id=?`, (stmt) => {
995
+ stmt.bindString(1, JSON.stringify(viewDef));
996
+ stmt.maybeBindInteger(2, maybeRow(viewDef.modelSelectorId));
997
+ stmt.bindInteger(3, ViewStore.toRowId(viewDef.categorySelectorId));
998
+ stmt.bindInteger(4, ViewStore.toRowId(viewDef.displayStyleId));
999
+ stmt.bindInteger(5, ViewStore.toRowId(args.viewId));
1000
+ stmt.stepForWrite();
1001
+ });
1002
+ }
1003
+ getViewDefinitionSync(args) {
1004
+ const viewId = ViewStore.toRowId(args.viewId);
1005
+ const row = this.getViewRow(viewId);
1006
+ if (undefined === row)
1007
+ throw new Error("View not found");
1008
+ const props = blankElementProps(JSON.parse(row.json), row.className, viewId, row.name);
1009
+ this.fromGuidRowMember(props, "baseModelId");
1010
+ this.fromGuidRowMember(props.jsonProperties?.viewDetails, "acs");
1011
+ return props;
1012
+ }
1013
+ async getViewDefinition(args) {
1014
+ return this.getViewDefinitionSync(args);
1015
+ }
1016
+ async addOrReplaceThumbnail(args) {
1017
+ const viewRow = this.getViewRow(ViewStore.toRowId(args.viewId));
1018
+ if (viewRow === undefined)
1019
+ throw new Error("View not found");
1020
+ const format = { format: args.thumbnail.format, height: args.thumbnail.height, width: args.thumbnail.width };
1021
+ this.addOrReplaceThumbnailRow({ data: args.thumbnail.image, viewId: ViewStore.toRowId(args.viewId), format, owner: args.owner });
1022
+ }
1023
+ getThumbnailSync(args) {
1024
+ const row = this.getThumbnailRow(ViewStore.toRowId(args.viewId));
1025
+ return row ? { image: row.data, format: row.format.format, height: row.format.height, width: row.format.width } : undefined;
1026
+ }
1027
+ async getThumbnail(args) {
1028
+ return this.getThumbnailSync(args);
1029
+ }
1030
+ /** find a group with the specified name using path syntax (e.g., "group1/design/issues"). If the group does not exist, return 0.
1031
+ * If groupName starts with "@", then it is considered to be a group id and this function verifies that it exists and throws if it does not.
1032
+ */
1033
+ findViewGroup(groupName) {
1034
+ // if it starts with "@", then it is a group id
1035
+ if (groupName.startsWith("@"))
1036
+ return this.verifyRowId(ViewStore.tableName.viewGroups, groupName);
1037
+ // split the name into parts using "/" as the separator
1038
+ const names = groupName.split("/");
1039
+ let groupId = 1; // start at root group
1040
+ for (const name of names) {
1041
+ if (name.length !== 0) {
1042
+ groupId = this.getViewGroupByName(name, groupId);
1043
+ if (groupId === 0)
1044
+ return 0;
1045
+ }
1046
+ }
1047
+ return groupId;
1048
+ }
1049
+ /**
1050
+ * find a view by name using path syntax (e.g., "group1/design/issues/issue113"). If the view does not exist, return 0.
1051
+ * If a groupId is specified, then the view is searched for in that group and the name should not contain a path.
1052
+ * @internal
1053
+ */
1054
+ findViewIdByName(arg) {
1055
+ let name = arg.name;
1056
+ let groupId = arg.groupId;
1057
+ if (groupId === undefined) {
1058
+ // find last "/" in name
1059
+ const slash = name.lastIndexOf("/");
1060
+ if (slash !== -1) {
1061
+ groupId = this.findViewGroup(name.slice(0, slash));
1062
+ name = name.slice(slash + 1);
1063
+ }
1064
+ }
1065
+ return this.withSqliteStatement(`SELECT Id FROM ${ViewStore.tableName.views} WHERE name=? AND groupId=?`, (stmt) => {
1066
+ stmt.bindString(1, name);
1067
+ stmt.bindInteger(2, maybeToRowId(groupId) ?? ViewStore.defaultViewGroupId);
1068
+ return !stmt.nextRow() ? 0 : stmt.getValueInteger(0);
1069
+ });
1070
+ }
1071
+ getViewByNameSync(arg) {
1072
+ const id = this.findViewIdByName(arg);
1073
+ return id ? this.getViewInfoSync(id) : undefined;
1074
+ }
1075
+ async getViewByName(arg) {
1076
+ return this.getViewByNameSync(arg);
1077
+ }
1078
+ async getViewGroupInfo(args) {
1079
+ const groupId = args.groupId ? this.findViewGroup(args.groupId) : ViewStore.defaultViewGroupId;
1080
+ const groupRow = groupId ? this.getViewGroup(groupId) : undefined;
1081
+ if (groupRow === undefined)
1082
+ return undefined;
1083
+ const info = {
1084
+ id: ViewStore.fromRowId(groupId),
1085
+ name: groupRow.name,
1086
+ defaultView: groupRow.defaultViewId ? ViewStore.fromRowId(groupRow.defaultViewId) : undefined,
1087
+ parent: ViewStore.fromRowId(groupRow.parentId),
1088
+ };
1089
+ return info;
1090
+ }
1091
+ async changeDefaultViewId(args) {
1092
+ const groupId = args.group ? this.findViewGroup(args.group) : ViewStore.defaultViewGroupId;
1093
+ const viewRow = this.getViewRow(ViewStore.toRowId(args.defaultView));
1094
+ if (viewRow === undefined)
1095
+ throw new Error("View not found");
1096
+ if (viewRow.groupId !== groupId)
1097
+ throw new Error("View is not in the specified group");
1098
+ const groupRow = this.getViewGroup(groupId);
1099
+ if (groupRow === undefined)
1100
+ throw new Error("View group not found");
1101
+ this.withSqliteStatement(`UPDATE ${ViewStore.tableName.viewGroups} SET defaultViewId=? WHERE Id=?`, (stmt) => {
1102
+ stmt.bindInteger(1, groupId);
1103
+ stmt.bindInteger(2, ViewStore.toRowId(args.defaultView));
1104
+ stmt.stepForWrite();
1105
+ });
1106
+ }
1107
+ /** get the array of tags for the specified view. Returns undefined if the view has no tags. */
1108
+ getTagsForView(viewId) {
1109
+ const tags = [];
1110
+ this.withPreparedSqliteStatement(`SELECT t.name FROM ${ViewStore.tableName.tags} t JOIN ${ViewStore.tableName.taggedViews} v ON t.Id = v.tagId WHERE v.viewId=?`, (stmt) => {
1111
+ stmt.bindInteger(1, ViewStore.toRowId(viewId));
1112
+ while (stmt.nextRow())
1113
+ tags.push(stmt.getValueString(0));
1114
+ });
1115
+ return tags.length === 0 ? undefined : tags;
1116
+ }
1117
+ iterateViewQuery(queryParams, callback) {
1118
+ const groupId = queryParams.group ? this.findViewGroup(queryParams.group) : ViewStore.defaultViewGroupId;
1119
+ let sql = `SELECT Id,className,name,owner,private FROM ${ViewStore.tableName.views} WHERE groupId=? ${queryParams.owner ? " AND (owner=@owner OR private!=1)" : " AND private!=1"}`;
1120
+ if (queryParams.classNames)
1121
+ sql += ` AND className IN(${queryParams.classNames.map((className) => `'${className}'`).join(",")})`;
1122
+ if (queryParams.nameSearch)
1123
+ sql += ` AND name ${queryParams.nameCompare ?? "="} @name`;
1124
+ if (queryParams.tags)
1125
+ sql += ` AND Id IN(SELECT viewId FROM ${ViewStore.tableName.taggedViews} WHERE tagId IN(SELECT Id FROM ${ViewStore.tableName.tags} WHERE name IN(${queryParams.tags.map((tag) => `'${tag}'`).join(",")})))`;
1126
+ sql += " ORDER BY name";
1127
+ if (queryParams.limit)
1128
+ sql += ` LIMIT ${queryParams.limit} `;
1129
+ if (queryParams.offset)
1130
+ sql += ` OFFSET ${queryParams.offset} `;
1131
+ this.withSqliteStatement(sql, (stmt) => {
1132
+ stmt.bindInteger(1, groupId);
1133
+ if (queryParams.nameSearch)
1134
+ stmt.bindString("@name", queryParams.nameSearch);
1135
+ if (queryParams.owner)
1136
+ stmt.bindString("@owner", queryParams.owner);
1137
+ while (stmt.nextRow())
1138
+ callback(stmt.getValueInteger(0));
1139
+ });
1140
+ }
1141
+ queryViewsSync(queryParams) {
1142
+ const entries = [];
1143
+ this.iterateViewQuery(queryParams, (rowId) => {
1144
+ const view = this.getViewInfoSync(rowId);
1145
+ if (view !== undefined)
1146
+ entries.push(view);
1147
+ });
1148
+ return entries;
1149
+ }
1150
+ async queryViews(queryParams) {
1151
+ return this.queryViewsSync(queryParams);
1152
+ }
1153
+ async addTagsToView(args) {
1154
+ const viewId = ViewStore.toRowId(args.viewId);
1155
+ for (const tag of args.tags) {
1156
+ let tagId = this.findTagByName(tag);
1157
+ if (tagId === 0)
1158
+ tagId = this.addTag({ name: tag, owner: args.owner, json: "{}" });
1159
+ this.addTagToView({ viewId, tagId });
1160
+ }
1161
+ }
1162
+ async removeTagFromView(args) {
1163
+ const viewId = ViewStore.toRowId(args.viewId);
1164
+ const tagId = this.findTagByName(args.tag);
1165
+ if (tagId !== 0)
1166
+ this.deleteViewTag({ viewId, tagId });
1167
+ }
1168
+ async addView(args) {
1169
+ const owner = args.owner;
1170
+ if (core_common_1.ViewStoreRpc.isViewStoreId(args.viewDefinition.categorySelectorId)) {
1171
+ this.verifyRowId(ViewStore.tableName.categorySelectors, args.viewDefinition.categorySelectorId);
1172
+ }
1173
+ else {
1174
+ if (args.categorySelectorProps === undefined)
1175
+ throw new Error("Must supply categorySelector");
1176
+ args.viewDefinition.categorySelectorId = await this.addCategorySelector({ selector: { ids: args.categorySelectorProps.categories }, owner });
1177
+ }
1178
+ const spatialDef = args.viewDefinition;
1179
+ if (core_common_1.ViewStoreRpc.isViewStoreId(spatialDef.modelSelectorId)) {
1180
+ this.verifyRowId(ViewStore.tableName.modelSelectors, spatialDef.modelSelectorId);
1181
+ }
1182
+ else if (args.modelSelectorProps) {
1183
+ spatialDef.modelSelectorId = await this.addModelSelector({ selector: { ids: args.modelSelectorProps.models }, owner });
1184
+ }
1185
+ else if (args.viewDefinition.classFullName === "BisCore:SpatialViewDefinition") {
1186
+ throw new Error("Must supply modelSelector for Spatial views");
1187
+ }
1188
+ if (core_common_1.ViewStoreRpc.isViewStoreId(spatialDef.displayStyleId)) {
1189
+ this.verifyRowId(ViewStore.tableName.displayStyles, spatialDef.displayStyleId);
1190
+ }
1191
+ else {
1192
+ if (args.displayStyleProps === undefined || args.displayStyleProps.jsonProperties?.styles === undefined)
1193
+ throw new Error("Must supply valid displayStyle");
1194
+ spatialDef.displayStyleId = await this.addDisplayStyle({ className: args.displayStyleProps.classFullName, settings: args.displayStyleProps.jsonProperties.styles, owner });
1195
+ }
1196
+ const viewId = this.addViewDefinition(args);
1197
+ if (args.tags)
1198
+ await this.addTagsToView({ viewId, tags: args.tags, owner });
1199
+ if (args.thumbnail)
1200
+ await this.addOrReplaceThumbnail({ viewId, thumbnail: args.thumbnail, owner });
1201
+ return ViewStore.fromRowId(viewId);
1202
+ }
1203
+ async deleteView(arg) {
1204
+ const rowId = ViewStore.toRowId(arg.viewId);
1205
+ const viewRow = this.getViewRow(rowId);
1206
+ if (viewRow === undefined)
1207
+ throw new Error("View not found");
1208
+ this.deleteViewRow(rowId);
1209
+ const hasName = (table, nameRow) => {
1210
+ const name = this.withSqliteStatement(`SELECT name FROM ${table} WHERE Id=?`, (stmt) => {
1211
+ stmt.bindInteger(1, nameRow);
1212
+ return stmt.nextRow() ? stmt.getValueString(0) : undefined;
1213
+ });
1214
+ return name !== undefined && name?.length > 0;
1215
+ };
1216
+ const tryDelete = (table, id) => {
1217
+ if (id !== undefined && !hasName(table, id)) { // only delete if the row has no name
1218
+ try {
1219
+ this.deleteFromTable(table, id);
1220
+ }
1221
+ catch (err) {
1222
+ // ignore constraint error if the row is still referenced by another view
1223
+ }
1224
+ }
1225
+ };
1226
+ // delete any selectors or display styles that are no longer referenced
1227
+ tryDelete(ViewStore.tableName.categorySelectors, viewRow.categorySel);
1228
+ tryDelete(ViewStore.tableName.modelSelectors, viewRow.modelSel);
1229
+ tryDelete(ViewStore.tableName.displayStyles, viewRow.displayStyle);
1230
+ }
1231
+ }
1232
+ ViewStore.ViewDb = ViewDb;
1233
+ const viewDbName = "ViewDb";
1234
+ /** Provides access to a cloud-based `ViewDb` */
1235
+ class CloudAccess extends CloudSqlite_1.CloudSqlite.DbAccess {
1236
+ constructor(props) {
1237
+ super({ dbType: ViewDb, props, dbName: viewDbName });
1238
+ }
1239
+ /** Initialize a cloud container for use as a ViewDb. */
1240
+ static async initializeDb(props) {
1241
+ return super._initializeDb({ props, dbType: ViewDb, dbName: viewDbName });
1242
+ }
1243
+ }
1244
+ ViewStore.CloudAccess = CloudAccess;
1245
+ })(ViewStore = exports.ViewStore || (exports.ViewStore = {}));
1246
+ //# sourceMappingURL=ViewStore.js.map