@itwin/core-backend 4.5.0-dev.9 → 4.6.0-dev.0
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.
- package/CHANGELOG.md +48 -1
- package/LICENSE.md +1 -1
- package/lib/cjs/BackendHubAccess.js.map +1 -1
- package/lib/cjs/BackendLoggerCategory.js.map +1 -1
- package/lib/cjs/BisCoreSchema.js.map +1 -1
- package/lib/cjs/BlobContainerService.js.map +1 -1
- package/lib/cjs/BriefcaseManager.js.map +1 -1
- package/lib/cjs/Category.js.map +1 -1
- package/lib/cjs/ChangeSummaryManager.js +2 -2
- package/lib/cjs/ChangeSummaryManager.js.map +1 -1
- package/lib/cjs/ChangedElementsDb.js.map +1 -1
- package/lib/cjs/ChangedElementsManager.js.map +1 -1
- package/lib/cjs/ChangesetECAdaptor.js +237 -237
- package/lib/cjs/ChangesetECAdaptor.js.map +1 -1
- package/lib/cjs/ChannelControl.js.map +1 -1
- package/lib/cjs/CheckpointManager.js.map +1 -1
- package/lib/cjs/ClassRegistry.js +5 -5
- package/lib/cjs/ClassRegistry.js.map +1 -1
- package/lib/cjs/CloudSqlite.d.ts.map +1 -1
- package/lib/cjs/CloudSqlite.js +4 -1
- package/lib/cjs/CloudSqlite.js.map +1 -1
- package/lib/cjs/CodeService.js.map +1 -1
- package/lib/cjs/CodeSpecs.js.map +1 -1
- package/lib/cjs/ConcurrentQuery.js.map +1 -1
- package/lib/cjs/CustomViewState3dCreator.js.map +1 -1
- package/lib/cjs/DevTools.js.map +1 -1
- package/lib/cjs/DisplayStyle.js.map +1 -1
- package/lib/cjs/ECDb.js.map +1 -1
- package/lib/cjs/ECSchemaXmlContext.js.map +1 -1
- package/lib/cjs/ECSqlStatement.js.map +1 -1
- package/lib/cjs/Element.d.ts +6 -0
- package/lib/cjs/Element.d.ts.map +1 -1
- package/lib/cjs/Element.js +7 -1
- package/lib/cjs/Element.js.map +1 -1
- package/lib/cjs/ElementAspect.js.map +1 -1
- package/lib/cjs/ElementGraphics.js.map +1 -1
- package/lib/cjs/ElementTreeWalker.js.map +1 -1
- package/lib/cjs/Entity.js.map +1 -1
- package/lib/cjs/EntityReferences.js.map +1 -1
- package/lib/cjs/ExportGraphics.js.map +1 -1
- package/lib/cjs/ExternalSource.js.map +1 -1
- package/lib/cjs/GeoCoordConfig.js.map +1 -1
- package/lib/cjs/GeometrySummary.js +47 -47
- package/lib/cjs/GeometrySummary.js.map +1 -1
- package/lib/cjs/HubMock.js.map +1 -1
- package/lib/cjs/IModelCloneContext.js.map +1 -1
- package/lib/cjs/IModelDb.d.ts +19 -5
- package/lib/cjs/IModelDb.d.ts.map +1 -1
- package/lib/cjs/IModelDb.js +142 -11
- package/lib/cjs/IModelDb.js.map +1 -1
- package/lib/cjs/IModelElementCloneContext.js.map +1 -1
- package/lib/cjs/IModelHost.d.ts +0 -2
- package/lib/cjs/IModelHost.d.ts.map +1 -1
- package/lib/cjs/IModelHost.js +1 -5
- package/lib/cjs/IModelHost.js.map +1 -1
- package/lib/cjs/IModelJsFs.js.map +1 -1
- package/lib/cjs/IpcHost.js.map +1 -1
- package/lib/cjs/LineStyle.js.map +1 -1
- package/lib/cjs/LocalHub.js +1 -1
- package/lib/cjs/LocalHub.js.map +1 -1
- package/lib/cjs/LocalhostIpcHost.js.map +1 -1
- package/lib/cjs/Material.js.map +1 -1
- package/lib/cjs/Model.js.map +1 -1
- package/lib/cjs/NativeAppStorage.js.map +1 -1
- package/lib/cjs/NativeHost.js.map +1 -1
- package/lib/cjs/NavigationRelationship.js.map +1 -1
- package/lib/cjs/PromiseMemoizer.js.map +1 -1
- package/lib/cjs/PropertyStore.js.map +1 -1
- package/lib/cjs/Relationship.js.map +1 -1
- package/lib/cjs/RpcBackend.js.map +1 -1
- package/lib/cjs/SQLiteDb.js.map +1 -1
- package/lib/cjs/Schema.js.map +1 -1
- package/lib/cjs/SchemaSync.js.map +1 -1
- package/lib/cjs/SchemaUtils.js.map +1 -1
- package/lib/cjs/ServerBasedLocks.js.map +1 -1
- package/lib/cjs/SqliteChangesetReader.js.map +1 -1
- package/lib/cjs/SqliteStatement.js.map +1 -1
- package/lib/cjs/Texture.js.map +1 -1
- package/lib/cjs/TileStorage.d.ts.map +1 -1
- package/lib/cjs/TileStorage.js +9 -1
- package/lib/cjs/TileStorage.js.map +1 -1
- package/lib/cjs/TxnManager.js.map +1 -1
- package/lib/cjs/ViewDefinition.js.map +1 -1
- package/lib/cjs/ViewStateHydrator.js.map +1 -1
- package/lib/cjs/ViewStore.js.map +1 -1
- package/lib/cjs/assets/IModelChange.02.00.00.ecschema.xml +90 -90
- package/lib/cjs/assets/Settings/Schemas/Cloud.Schema.json +44 -44
- package/lib/cjs/assets/Settings/Schemas/Gcs.schema.json +31 -31
- package/lib/cjs/assets/Settings/Schemas/Workspace.Schema.json +52 -52
- package/lib/cjs/assets/Settings/backend.setting.json5 +132 -132
- package/lib/cjs/core-backend.js.map +1 -1
- package/lib/cjs/domains/FunctionalElements.js.map +1 -1
- package/lib/cjs/domains/FunctionalSchema.js.map +1 -1
- package/lib/cjs/domains/GenericElements.js.map +1 -1
- package/lib/cjs/domains/GenericSchema.js.map +1 -1
- package/lib/cjs/rpc/multipart.js.map +1 -1
- package/lib/cjs/rpc/tracing.js.map +1 -1
- package/lib/cjs/rpc/web/logging.d.ts.map +1 -1
- package/lib/cjs/rpc/web/logging.js +0 -2
- package/lib/cjs/rpc/web/logging.js.map +1 -1
- package/lib/cjs/rpc/web/request.js.map +1 -1
- package/lib/cjs/rpc/web/response.d.ts.map +1 -1
- package/lib/cjs/rpc/web/response.js +16 -0
- package/lib/cjs/rpc/web/response.js.map +1 -1
- package/lib/cjs/rpc-impl/DevToolsRpcImpl.js.map +1 -1
- package/lib/cjs/rpc-impl/IModelReadRpcImpl.js.map +1 -1
- package/lib/cjs/rpc-impl/IModelTileRpcImpl.js.map +1 -1
- package/lib/cjs/rpc-impl/RpcBriefcaseUtility.js.map +1 -1
- package/lib/cjs/rpc-impl/SnapshotIModelRpcImpl.js.map +1 -1
- package/lib/cjs/rpc-impl/WipRpcImpl.js.map +1 -1
- package/lib/cjs/workspace/Settings.js.map +1 -1
- package/lib/cjs/workspace/SettingsSchemas.js.map +1 -1
- package/lib/cjs/workspace/Workspace.d.ts +107 -123
- package/lib/cjs/workspace/Workspace.d.ts.map +1 -1
- package/lib/cjs/workspace/Workspace.js +132 -155
- package/lib/cjs/workspace/Workspace.js.map +1 -1
- package/package.json +13 -12
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* @module Workspace
|
|
8
8
|
*/
|
|
9
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
-
exports.EditableWorkspaceDb = exports.
|
|
10
|
+
exports.EditableWorkspaceDb = exports.Workspace = exports.WorkspaceDb = exports.WorkspaceContainer = exports.WorkspaceSetting = void 0;
|
|
11
11
|
const crypto_1 = require("crypto");
|
|
12
12
|
const fs = require("fs-extra");
|
|
13
13
|
const path_1 = require("path");
|
|
@@ -22,16 +22,116 @@ const Settings_1 = require("./Settings");
|
|
|
22
22
|
const SettingsSchemas_1 = require("./SettingsSchemas");
|
|
23
23
|
/* eslint-disable @typescript-eslint/naming-convention */
|
|
24
24
|
// cspell:ignore rowid primarykey julianday
|
|
25
|
+
function noLeadingOrTrailingSpaces(name, msg) {
|
|
26
|
+
if (name.trim() !== name)
|
|
27
|
+
throw new Error(`${msg} [${name}] may not have leading or tailing spaces`);
|
|
28
|
+
}
|
|
25
29
|
/** The Settings used by Workspace api
|
|
26
30
|
* @beta
|
|
27
31
|
*/
|
|
28
32
|
exports.WorkspaceSetting = {
|
|
29
|
-
Accounts: "cloud/accounts",
|
|
30
33
|
Containers: "cloud/containers",
|
|
31
34
|
Databases: "workspace/databases",
|
|
32
35
|
};
|
|
33
|
-
/** @
|
|
34
|
-
|
|
36
|
+
/** @beta */
|
|
37
|
+
var WorkspaceContainer;
|
|
38
|
+
(function (WorkspaceContainer) {
|
|
39
|
+
function validateDbName(dbName) {
|
|
40
|
+
if (dbName === "" || dbName.length > 255 || /[#\.<>:"/\\"`'|?*\u0000-\u001F]/g.test(dbName) || /^(con|prn|aux|nul|com\d|lpt\d)$/i.test(dbName))
|
|
41
|
+
throw new Error(`invalid dbName: [${dbName}]`);
|
|
42
|
+
noLeadingOrTrailingSpaces(dbName, "dbName");
|
|
43
|
+
}
|
|
44
|
+
WorkspaceContainer.validateDbName = validateDbName;
|
|
45
|
+
/**
|
|
46
|
+
* Validate that a WorkspaceContainer.Id is valid.
|
|
47
|
+
* The rules for ContainerIds (from Azure, see https://docs.microsoft.com/en-us/rest/api/storageservices/naming-and-referencing-containers--blobs--and-metadata):
|
|
48
|
+
* - may only contain lower case letters, numbers or dashes
|
|
49
|
+
* - may not start or end with with a dash nor have more than one dash in a row
|
|
50
|
+
* - may not be shorter than 3 or longer than 63 characters
|
|
51
|
+
*/
|
|
52
|
+
function validateContainerId(id) {
|
|
53
|
+
if (!/^(?=.{3,63}$)[a-z0-9]+(-[a-z0-9]+)*$/g.test(id))
|
|
54
|
+
throw new Error(`invalid containerId: [${id}]`);
|
|
55
|
+
}
|
|
56
|
+
WorkspaceContainer.validateContainerId = validateContainerId;
|
|
57
|
+
/** @internal */
|
|
58
|
+
function validateVersion(version) {
|
|
59
|
+
version = version ?? "1.0.0";
|
|
60
|
+
if (version) {
|
|
61
|
+
const opts = { loose: true, includePrerelease: true };
|
|
62
|
+
// clean allows prerelease, so try it first. If that fails attempt to coerce it (coerce strips prerelease even if you say not to.)
|
|
63
|
+
const semVersion = semver.clean(version, opts) ?? semver.coerce(version, opts)?.version;
|
|
64
|
+
if (!semVersion)
|
|
65
|
+
throw new Error("invalid version specification");
|
|
66
|
+
version = semVersion;
|
|
67
|
+
}
|
|
68
|
+
return version;
|
|
69
|
+
}
|
|
70
|
+
WorkspaceContainer.validateVersion = validateVersion;
|
|
71
|
+
/**
|
|
72
|
+
* Parse the name stored in a WorkspaceContainer into the dbName and version number. A single WorkspaceContainer may hold
|
|
73
|
+
* many versions of the same WorkspaceDb. The name of the Db in the WorkspaceContainer is in the format "name:version". This
|
|
74
|
+
* function splits them into separate strings.
|
|
75
|
+
*/
|
|
76
|
+
function parseDbFileName(dbFileName) {
|
|
77
|
+
const parts = dbFileName.split(":");
|
|
78
|
+
return { dbName: parts[0], version: parts[1] };
|
|
79
|
+
}
|
|
80
|
+
WorkspaceContainer.parseDbFileName = parseDbFileName;
|
|
81
|
+
/** Create a dbName for a WorkspaceDb from its base name and version. This will be in the format "name:version" */
|
|
82
|
+
function makeDbFileName(dbName, version) {
|
|
83
|
+
return `${dbName}:${WorkspaceContainer.validateVersion(version)}`;
|
|
84
|
+
}
|
|
85
|
+
WorkspaceContainer.makeDbFileName = makeDbFileName;
|
|
86
|
+
})(WorkspaceContainer = exports.WorkspaceContainer || (exports.WorkspaceContainer = {}));
|
|
87
|
+
/** @beta */
|
|
88
|
+
var WorkspaceDb;
|
|
89
|
+
(function (WorkspaceDb) {
|
|
90
|
+
/** file extension for local WorkspaceDbs
|
|
91
|
+
* @internal
|
|
92
|
+
*/
|
|
93
|
+
WorkspaceDb.fileExt = "itwin-workspace";
|
|
94
|
+
/** construct a new instance of a WorkspaceDb */
|
|
95
|
+
function construct(props, container) {
|
|
96
|
+
return new WorkspaceDbImpl(props, container);
|
|
97
|
+
}
|
|
98
|
+
WorkspaceDb.construct = construct;
|
|
99
|
+
})(WorkspaceDb = exports.WorkspaceDb || (exports.WorkspaceDb = {}));
|
|
100
|
+
/** @beta */
|
|
101
|
+
var Workspace;
|
|
102
|
+
(function (Workspace) {
|
|
103
|
+
/** @internal */
|
|
104
|
+
function construct(settings, opts) {
|
|
105
|
+
return new WorkspaceImpl(settings, opts);
|
|
106
|
+
}
|
|
107
|
+
Workspace.construct = construct;
|
|
108
|
+
})(Workspace = exports.Workspace || (exports.Workspace = {}));
|
|
109
|
+
/** @beta */
|
|
110
|
+
var EditableWorkspaceDb;
|
|
111
|
+
(function (EditableWorkspaceDb) {
|
|
112
|
+
/** construct a new instance of an EditableWorkspaceDb */
|
|
113
|
+
function construct(props, container) {
|
|
114
|
+
return new EditableWorkspaceDbImpl(props, container);
|
|
115
|
+
}
|
|
116
|
+
EditableWorkspaceDb.construct = construct;
|
|
117
|
+
/** Create a new, empty, EditableWorkspaceDb file on the local filesystem for importing Workspace resources. */
|
|
118
|
+
function createEmpty(fileName) {
|
|
119
|
+
const db = new SQLiteDb_1.SQLiteDb();
|
|
120
|
+
IModelJsFs_1.IModelJsFs.recursiveMkDirSync((0, path_1.dirname)(fileName));
|
|
121
|
+
db.createDb(fileName);
|
|
122
|
+
const timeStampCol = "lastMod TIMESTAMP NOT NULL DEFAULT(julianday('now'))";
|
|
123
|
+
db.executeSQL(`CREATE TABLE strings(id TEXT PRIMARY KEY NOT NULL,value TEXT,${timeStampCol})`);
|
|
124
|
+
db.executeSQL(`CREATE TABLE blobs(id TEXT PRIMARY KEY NOT NULL,value BLOB,${timeStampCol})`);
|
|
125
|
+
const createTrigger = (tableName) => {
|
|
126
|
+
db.executeSQL(`CREATE TRIGGER ${tableName}_timeStamp AFTER UPDATE ON ${tableName} WHEN old.lastMod=new.lastMod AND old.lastMod != julianday('now') BEGIN UPDATE ${tableName} SET lastMod=julianday('now') WHERE id=new.id; END`);
|
|
127
|
+
};
|
|
128
|
+
createTrigger("strings");
|
|
129
|
+
createTrigger("blobs");
|
|
130
|
+
db.closeDb(true);
|
|
131
|
+
}
|
|
132
|
+
EditableWorkspaceDb.createEmpty = createEmpty;
|
|
133
|
+
})(EditableWorkspaceDb = exports.EditableWorkspaceDb || (exports.EditableWorkspaceDb = {}));
|
|
134
|
+
class WorkspaceImpl {
|
|
35
135
|
getCloudCache() {
|
|
36
136
|
return this._cloudCache ??= CloudSqlite_1.CloudSqlite.CloudCaches.getCache({ cacheName: "Workspace", cacheSize: "20G" });
|
|
37
137
|
}
|
|
@@ -56,7 +156,7 @@ class ITwinWorkspace {
|
|
|
56
156
|
return this._containers.get(containerId);
|
|
57
157
|
}
|
|
58
158
|
getContainer(props) {
|
|
59
|
-
return this.findContainer(props.containerId) ?? new
|
|
159
|
+
return this.findContainer(props.containerId) ?? new WorkspaceContainerImpl(this, props);
|
|
60
160
|
}
|
|
61
161
|
getWorkspaceDbFromProps(dbProps, containerProps) {
|
|
62
162
|
return this.getContainer(containerProps).getWorkspaceDb(dbProps);
|
|
@@ -112,31 +212,11 @@ class ITwinWorkspace {
|
|
|
112
212
|
return resolved;
|
|
113
213
|
}
|
|
114
214
|
}
|
|
115
|
-
|
|
116
|
-
/** @internal */
|
|
117
|
-
class ITwinWorkspaceContainer {
|
|
215
|
+
class WorkspaceContainerImpl {
|
|
118
216
|
get dirName() { return (0, path_1.join)(this.workspace.containerDir, this.id); }
|
|
119
|
-
static noLeadingOrTrailingSpaces(name, msg) {
|
|
120
|
-
if (name.trim() !== name)
|
|
121
|
-
throw new Error(`${msg} [${name}] may not have leading or tailing spaces`);
|
|
122
|
-
}
|
|
123
|
-
/** rules for ContainerIds (from Azure, see https://docs.microsoft.com/en-us/rest/api/storageservices/naming-and-referencing-containers--blobs--and-metadata)
|
|
124
|
-
* - may only contain lower case letters, numbers or dashes
|
|
125
|
-
* - may not start or end with with a dash nor have more than one dash in a row
|
|
126
|
-
* - may not be shorter than 3 or longer than 63 characters
|
|
127
|
-
*/
|
|
128
|
-
static validateContainerId(id) {
|
|
129
|
-
if (!/^(?=.{3,63}$)[a-z0-9]+(-[a-z0-9]+)*$/g.test(id))
|
|
130
|
-
throw new Error(`invalid containerId: [${id}]`);
|
|
131
|
-
}
|
|
132
|
-
static validateDbName(dbName) {
|
|
133
|
-
if (dbName === "" || dbName.length > 255 || /[#\.<>:"/\\"`'|?*\u0000-\u001F]/g.test(dbName) || /^(con|prn|aux|nul|com\d|lpt\d)$/i.test(dbName))
|
|
134
|
-
throw new Error(`invalid dbName: [${dbName}]`);
|
|
135
|
-
this.noLeadingOrTrailingSpaces(dbName, "dbName");
|
|
136
|
-
}
|
|
137
217
|
constructor(workspace, props) {
|
|
138
218
|
this._wsDbs = new Map();
|
|
139
|
-
|
|
219
|
+
WorkspaceContainer.validateContainerId(props.containerId);
|
|
140
220
|
this.workspace = workspace;
|
|
141
221
|
this.id = props.containerId;
|
|
142
222
|
if (props.baseUri !== "")
|
|
@@ -156,31 +236,15 @@ class ITwinWorkspaceContainer {
|
|
|
156
236
|
}
|
|
157
237
|
}
|
|
158
238
|
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
if (
|
|
162
|
-
|
|
163
|
-
// clean allows prerelease, so try it first. If that fails attempt to coerce it (coerce strips prerelease even if you say not to.)
|
|
164
|
-
const semVersion = semver.clean(version, opts) ?? semver.coerce(version, opts)?.version;
|
|
165
|
-
if (!semVersion)
|
|
166
|
-
throw new Error("invalid version specification");
|
|
167
|
-
version = semVersion;
|
|
168
|
-
}
|
|
169
|
-
return version;
|
|
170
|
-
}
|
|
171
|
-
static parseDbFileName(dbFileName) {
|
|
172
|
-
const parts = dbFileName.split(":");
|
|
173
|
-
return { dbName: parts[0], version: parts[1] };
|
|
174
|
-
}
|
|
175
|
-
static makeDbFileName(dbName, version) {
|
|
176
|
-
return `${dbName}:${this.validateVersion(version)}`;
|
|
177
|
-
}
|
|
178
|
-
static resolveCloudFileName(cloudContainer, props) {
|
|
239
|
+
resolveDbFileName(props) {
|
|
240
|
+
const cloudContainer = this.cloudContainer;
|
|
241
|
+
if (undefined === cloudContainer)
|
|
242
|
+
return (0, path_1.join)(this.dirName, `${props.dbName}.${WorkspaceDb.fileExt}`); // local file, versions not allowed
|
|
179
243
|
const dbName = props.dbName;
|
|
180
244
|
const dbs = cloudContainer.queryDatabases(`${dbName}*`); // get all databases that start with dbName
|
|
181
245
|
const versions = [];
|
|
182
246
|
for (const db of dbs) {
|
|
183
|
-
const thisDb =
|
|
247
|
+
const thisDb = WorkspaceContainer.parseDbFileName(db);
|
|
184
248
|
if (thisDb.dbName === dbName && "string" === typeof thisDb.version && thisDb.version.length > 0)
|
|
185
249
|
versions.push(thisDb.version);
|
|
186
250
|
}
|
|
@@ -196,46 +260,31 @@ class ITwinWorkspaceContainer {
|
|
|
196
260
|
}
|
|
197
261
|
throw new Error(`No version of [${dbName}] available for "${range}"`);
|
|
198
262
|
}
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
* new content before the write lock is released, and thereafter should never be modified again.
|
|
206
|
-
*/
|
|
207
|
-
static async makeNewVersion(cloudContainer, fromProps, versionType) {
|
|
208
|
-
const oldName = this.resolveCloudFileName(cloudContainer, fromProps);
|
|
209
|
-
const oldDb = this.parseDbFileName(oldName);
|
|
263
|
+
async makeNewVersion(fromProps, versionType) {
|
|
264
|
+
const cloudContainer = this.cloudContainer;
|
|
265
|
+
if (undefined === cloudContainer)
|
|
266
|
+
throw new Error("versions require cloud containers");
|
|
267
|
+
const oldName = this.resolveDbFileName(fromProps);
|
|
268
|
+
const oldDb = WorkspaceContainer.parseDbFileName(oldName);
|
|
210
269
|
const newVersion = semver.inc(oldDb.version, versionType);
|
|
211
270
|
if (!newVersion)
|
|
212
271
|
throw new Error("invalid version");
|
|
213
|
-
const newName =
|
|
272
|
+
const newName = WorkspaceContainer.makeDbFileName(oldDb.dbName, newVersion);
|
|
214
273
|
await cloudContainer.copyDatabase(oldName, newName);
|
|
215
274
|
return { oldName, newName };
|
|
216
275
|
}
|
|
217
|
-
/**
|
|
218
|
-
* Convert a WorkspaceDb.Props specification into a DbFileName. For cloud-based containers, this resolves to the dbName, incorporating the appropriate
|
|
219
|
-
* version. For file-based containers, this returns a local filename of a WorkspaceDb file with the extension ".itwin-workspace"
|
|
220
|
-
*/
|
|
221
|
-
resolveDbFileName(props) {
|
|
222
|
-
const cloudContainer = this.cloudContainer;
|
|
223
|
-
if (undefined === cloudContainer)
|
|
224
|
-
return (0, path_1.join)(this.dirName, `${props.dbName}.${ITwinWorkspaceDb.fileExt}`); // local file, versions not allowed
|
|
225
|
-
return ITwinWorkspaceContainer.resolveCloudFileName(cloudContainer, props);
|
|
226
|
-
}
|
|
227
276
|
addWorkspaceDb(toAdd) {
|
|
228
277
|
if (undefined !== this._wsDbs.get(toAdd.dbName))
|
|
229
278
|
throw new Error(`workspaceDb ${toAdd.dbName} already exists in workspace`);
|
|
230
279
|
this._wsDbs.set(toAdd.dbName, toAdd);
|
|
231
280
|
}
|
|
232
281
|
getWorkspaceDb(props) {
|
|
233
|
-
const db = this._wsDbs.get(props.dbName) ?? new
|
|
282
|
+
const db = this._wsDbs.get(props.dbName) ?? new WorkspaceDbImpl(props, this);
|
|
234
283
|
if (!db.isOpen)
|
|
235
284
|
db.open();
|
|
236
285
|
return db;
|
|
237
286
|
}
|
|
238
|
-
|
|
287
|
+
closeWorkspaceDb(toDrop) {
|
|
239
288
|
const name = toDrop.dbName;
|
|
240
289
|
const wsDb = this._wsDbs.get(name);
|
|
241
290
|
if (wsDb === toDrop) {
|
|
@@ -249,17 +298,9 @@ class ITwinWorkspaceContainer {
|
|
|
249
298
|
this._wsDbs.clear();
|
|
250
299
|
this.cloudContainer?.disconnect();
|
|
251
300
|
}
|
|
252
|
-
/** Delete all local files extracted by [[WorkspaceDb.getFile]] for this container. */
|
|
253
|
-
purgeContainerFiles() {
|
|
254
|
-
IModelJsFs_1.IModelJsFs.purgeDirSync(this.filesDir);
|
|
255
|
-
}
|
|
256
301
|
}
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
* Implementation of WorkspaceDb
|
|
260
|
-
* @internal
|
|
261
|
-
*/
|
|
262
|
-
class ITwinWorkspaceDb {
|
|
302
|
+
/** Implementation of WorkspaceDb */
|
|
303
|
+
class WorkspaceDbImpl {
|
|
263
304
|
/** true if this WorkspaceDb is currently open */
|
|
264
305
|
get isOpen() { return this.sqliteDb.isOpen; }
|
|
265
306
|
queryFileResource(rscName) {
|
|
@@ -273,11 +314,9 @@ class ITwinWorkspaceDb {
|
|
|
273
314
|
return { localFileName, info };
|
|
274
315
|
}
|
|
275
316
|
constructor(props, container) {
|
|
276
|
-
/** the SQLiteDb for this WorkspaceDb*/
|
|
277
317
|
this.sqliteDb = new SQLiteDb_1.SQLiteDb();
|
|
278
|
-
/** called before db is closed */
|
|
279
318
|
this.onClose = new core_bentley_1.BeEvent();
|
|
280
|
-
|
|
319
|
+
WorkspaceContainer.validateDbName(props.dbName);
|
|
281
320
|
this.dbName = props.dbName;
|
|
282
321
|
this.container = container;
|
|
283
322
|
this.dbFileName = container.resolveDbFileName(props);
|
|
@@ -290,7 +329,7 @@ class ITwinWorkspaceDb {
|
|
|
290
329
|
if (this.isOpen) {
|
|
291
330
|
this.onClose.raiseEvent();
|
|
292
331
|
this.sqliteDb.closeDb();
|
|
293
|
-
this.container.
|
|
332
|
+
this.container.closeWorkspaceDb(this);
|
|
294
333
|
}
|
|
295
334
|
}
|
|
296
335
|
getString(rscName) {
|
|
@@ -299,9 +338,6 @@ class ITwinWorkspaceDb {
|
|
|
299
338
|
return core_bentley_1.DbResult.BE_SQLITE_ROW === stmt.step() ? stmt.getValueString(0) : undefined;
|
|
300
339
|
});
|
|
301
340
|
}
|
|
302
|
-
/** Get a BlobIO reader for a blob WorkspaceResource.
|
|
303
|
-
* @note when finished, caller *must* call `close` on the BlobIO.
|
|
304
|
-
*/
|
|
305
341
|
getBlobReader(rscName) {
|
|
306
342
|
return this.sqliteDb.withSqliteStatement("SELECT rowid from blobs WHERE id=?", (stmt) => {
|
|
307
343
|
stmt.bindString(1, rscName);
|
|
@@ -344,18 +380,9 @@ class ITwinWorkspaceDb {
|
|
|
344
380
|
return CloudSqlite_1.CloudSqlite.startCloudPrefetch(cloudContainer, this.dbFileName, opts);
|
|
345
381
|
}
|
|
346
382
|
}
|
|
347
|
-
|
|
348
|
-
ITwinWorkspaceDb.fileExt = "itwin-workspace";
|
|
349
|
-
exports.ITwinWorkspaceDb = ITwinWorkspaceDb;
|
|
350
|
-
/**
|
|
351
|
-
* An editable [[WorkspaceDb]]. This is used by administrators for creating and modifying `WorkspaceDb`s.
|
|
352
|
-
* For cloud-backed containers, the write token must be obtained before this class may be used. Only one user at at time
|
|
353
|
-
* may be editing.
|
|
354
|
-
* @internal
|
|
355
|
-
*/
|
|
356
|
-
class EditableWorkspaceDb extends ITwinWorkspaceDb {
|
|
383
|
+
class EditableWorkspaceDbImpl extends WorkspaceDbImpl {
|
|
357
384
|
static validateResourceName(name) {
|
|
358
|
-
|
|
385
|
+
noLeadingOrTrailingSpaces(name, "resource name");
|
|
359
386
|
if (name.length > 1024)
|
|
360
387
|
throw new Error("resource name too long");
|
|
361
388
|
}
|
|
@@ -389,72 +416,37 @@ class EditableWorkspaceDb extends ITwinWorkspaceDb {
|
|
|
389
416
|
}
|
|
390
417
|
else {
|
|
391
418
|
// currently the only way to create a workspaceDb in a cloud container is to create a temporary workspaceDb and upload it.
|
|
392
|
-
const tempDbFile = (0, path_1.join)(IModelHost_1.KnownLocations.tmpdir, `empty.${
|
|
419
|
+
const tempDbFile = (0, path_1.join)(IModelHost_1.KnownLocations.tmpdir, `empty.${WorkspaceDb.fileExt}`);
|
|
393
420
|
if (fs.existsSync(tempDbFile))
|
|
394
421
|
IModelJsFs_1.IModelJsFs.removeSync(tempDbFile);
|
|
395
422
|
EditableWorkspaceDb.createEmpty(tempDbFile);
|
|
396
|
-
this.dbFileName =
|
|
423
|
+
this.dbFileName = WorkspaceContainer.makeDbFileName(this.dbName, version);
|
|
397
424
|
await CloudSqlite_1.CloudSqlite.uploadDb(this.container.cloudContainer, { localFileName: tempDbFile, dbName: this.dbFileName });
|
|
398
425
|
IModelJsFs_1.IModelJsFs.removeSync(tempDbFile);
|
|
399
426
|
}
|
|
400
427
|
this.open();
|
|
401
428
|
}
|
|
402
|
-
/** Create a new, empty, EditableWorkspaceDb for importing Workspace resources. */
|
|
403
|
-
static createEmpty(fileName) {
|
|
404
|
-
const db = new SQLiteDb_1.SQLiteDb();
|
|
405
|
-
IModelJsFs_1.IModelJsFs.recursiveMkDirSync((0, path_1.dirname)(fileName));
|
|
406
|
-
db.createDb(fileName);
|
|
407
|
-
const timeStampCol = "lastMod TIMESTAMP NOT NULL DEFAULT(julianday('now'))";
|
|
408
|
-
db.executeSQL(`CREATE TABLE strings(id TEXT PRIMARY KEY NOT NULL,value TEXT,${timeStampCol})`);
|
|
409
|
-
db.executeSQL(`CREATE TABLE blobs(id TEXT PRIMARY KEY NOT NULL,value BLOB,${timeStampCol})`);
|
|
410
|
-
const createTrigger = (tableName) => {
|
|
411
|
-
db.executeSQL(`CREATE TRIGGER ${tableName}_timeStamp AFTER UPDATE ON ${tableName} WHEN old.lastMod=new.lastMod AND old.lastMod != julianday('now') BEGIN UPDATE ${tableName} SET lastMod=julianday('now') WHERE id=new.id; END`);
|
|
412
|
-
};
|
|
413
|
-
createTrigger("strings");
|
|
414
|
-
createTrigger("blobs");
|
|
415
|
-
db.closeDb(true);
|
|
416
|
-
}
|
|
417
|
-
/** Add a new string resource to this WorkspaceDb.
|
|
418
|
-
* @param rscName The name of the string resource.
|
|
419
|
-
* @param val The string to save.
|
|
420
|
-
*/
|
|
421
429
|
addString(rscName, val) {
|
|
422
|
-
|
|
430
|
+
EditableWorkspaceDbImpl.validateResourceName(rscName);
|
|
423
431
|
this.validateResourceSize(val);
|
|
424
432
|
this.performWriteSql(rscName, "INSERT INTO strings(id,value) VALUES(?,?)", (stmt) => stmt.bindString(2, val));
|
|
425
433
|
}
|
|
426
|
-
/** Update an existing string resource with a new value, or add it if it does not exist.
|
|
427
|
-
* @param rscName The name of the string resource.
|
|
428
|
-
* @param val The new value.
|
|
429
|
-
*/
|
|
430
434
|
updateString(rscName, val) {
|
|
431
435
|
this.validateResourceSize(val);
|
|
432
436
|
this.performWriteSql(rscName, "INSERT INTO strings(id,value) VALUES(?,?) ON CONFLICT(id) DO UPDATE SET value=excluded.value WHERE value!=excluded.value", (stmt) => stmt.bindString(2, val));
|
|
433
437
|
}
|
|
434
|
-
/** Remove a string resource. */
|
|
435
438
|
removeString(rscName) {
|
|
436
439
|
this.performWriteSql(rscName, "DELETE FROM strings WHERE id=?");
|
|
437
440
|
}
|
|
438
|
-
/** Add a new blob resource to this WorkspaceDb.
|
|
439
|
-
* @param rscName The name of the blob resource.
|
|
440
|
-
* @param val The blob to save.
|
|
441
|
-
*/
|
|
442
441
|
addBlob(rscName, val) {
|
|
443
|
-
|
|
442
|
+
EditableWorkspaceDbImpl.validateResourceName(rscName);
|
|
444
443
|
this.validateResourceSize(val);
|
|
445
444
|
this.performWriteSql(rscName, "INSERT INTO blobs(id,value) VALUES(?,?)", (stmt) => stmt.bindBlob(2, val));
|
|
446
445
|
}
|
|
447
|
-
/** Update an existing blob resource with a new value, or add it if it does not exist.
|
|
448
|
-
* @param rscName The name of the blob resource.
|
|
449
|
-
* @param val The new value.
|
|
450
|
-
*/
|
|
451
446
|
updateBlob(rscName, val) {
|
|
452
447
|
this.validateResourceSize(val);
|
|
453
448
|
this.performWriteSql(rscName, "INSERT INTO blobs(id,value) VALUES(?,?) ON CONFLICT(id) DO UPDATE SET value=excluded.value WHERE value!=excluded.value", (stmt) => stmt.bindBlob(2, val));
|
|
454
449
|
}
|
|
455
|
-
/** Get a BlobIO writer for a previously-added blob WorkspaceResource.
|
|
456
|
-
* @note after writing is complete, caller must call `close` on the BlobIO and must call `saveChanges` on the `db`.
|
|
457
|
-
*/
|
|
458
450
|
getBlobWriter(rscName) {
|
|
459
451
|
return this.sqliteDb.withSqliteStatement("SELECT rowid from blobs WHERE id=?", (stmt) => {
|
|
460
452
|
stmt.bindString(1, rscName);
|
|
@@ -463,34 +455,20 @@ class EditableWorkspaceDb extends ITwinWorkspaceDb {
|
|
|
463
455
|
return blobWriter;
|
|
464
456
|
});
|
|
465
457
|
}
|
|
466
|
-
/** Remove a blob resource. */
|
|
467
458
|
removeBlob(rscName) {
|
|
468
459
|
this.performWriteSql(rscName, "DELETE FROM blobs WHERE id=?");
|
|
469
460
|
}
|
|
470
|
-
/** Copy the contents of an existing local file into this WorkspaceDb as a file resource.
|
|
471
|
-
* @param rscName The name of the file resource.
|
|
472
|
-
* @param localFileName The name of a local file to be read.
|
|
473
|
-
* @param fileExt The extension (do not include the leading ".") to be appended to the generated fileName
|
|
474
|
-
* when this WorkspaceDb is extracted from the WorkspaceDb. By default the characters after the last "." in `localFileName`
|
|
475
|
-
* are used. Pass this argument to override that.
|
|
476
|
-
*/
|
|
477
461
|
addFile(rscName, localFileName, fileExt) {
|
|
478
|
-
|
|
462
|
+
EditableWorkspaceDbImpl.validateResourceName(rscName);
|
|
479
463
|
fileExt = fileExt ?? (0, path_1.extname)(localFileName);
|
|
480
464
|
if (fileExt?.[0] === ".")
|
|
481
465
|
fileExt = fileExt.slice(1);
|
|
482
466
|
this.sqliteDb.nativeDb.embedFile({ name: rscName, localFileName, date: this.getFileModifiedTime(localFileName), fileExt });
|
|
483
467
|
}
|
|
484
|
-
/** Replace an existing file resource with the contents of another local file.
|
|
485
|
-
* @param rscName The name of the file resource.
|
|
486
|
-
* @param localFileName The name of a local file to be read.
|
|
487
|
-
* @throws if rscName does not exist
|
|
488
|
-
*/
|
|
489
468
|
updateFile(rscName, localFileName) {
|
|
490
469
|
this.queryFileResource(rscName); // throws if not present
|
|
491
470
|
this.sqliteDb.nativeDb.replaceEmbeddedFile({ name: rscName, localFileName, date: this.getFileModifiedTime(localFileName) });
|
|
492
471
|
}
|
|
493
|
-
/** Remove a file resource. */
|
|
494
472
|
removeFile(rscName) {
|
|
495
473
|
const file = this.queryFileResource(rscName);
|
|
496
474
|
if (undefined === file)
|
|
@@ -500,5 +478,4 @@ class EditableWorkspaceDb extends ITwinWorkspaceDb {
|
|
|
500
478
|
this.sqliteDb.nativeDb.removeEmbeddedFile(rscName);
|
|
501
479
|
}
|
|
502
480
|
}
|
|
503
|
-
exports.EditableWorkspaceDb = EditableWorkspaceDb;
|
|
504
481
|
//# sourceMappingURL=Workspace.js.map
|