@itwin/core-backend
Version:
iTwin.js backend components
180 lines • 8.53 kB
JavaScript
;
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.PropertyStore = void 0;
const CloudSqlite_1 = require("./CloudSqlite");
const SQLiteDb_1 = require("./SQLiteDb");
/** @beta */
var PropertyStore;
(function (PropertyStore) {
/**
* A SQLite database for storing PropertyName/PropertyValue pairs.
*/
class PropertyDb extends SQLiteDb_1.VersionedSqliteDb {
myVersion = "3.0.0";
createDDL() {
this.createTable({ tableName: "properties", columns: "name TEXT NOT NULL PRIMARY KEY,type,value", addTimestamp: true });
}
/** get the value of a Property by name.
* @returns the property's value if it exists, `undefined` otherwise.
*/
getProperty(name) {
return this.withPreparedSqliteStatement("SELECT type,value from properties WHERE name=?", (stmt) => {
stmt.bindString(1, name);
if (!stmt.nextRow())
return undefined;
switch (stmt.getValueString(0)) {
case "string":
return stmt.getValueString(1);
case "boolean":
return stmt.getValueInteger(1) !== 0;
case "blob":
return stmt.getValueBlob(1);
case "number":
return stmt.getValueDouble(1);
case "object":
return JSON.parse(stmt.getValueString(1));
}
return undefined;
});
}
getString(name, defaultValue) {
const out = this.getProperty(name);
return typeof out === "string" ? out : defaultValue;
}
getBoolean(name, defaultValue) {
const out = this.getProperty(name);
return typeof out === "boolean" ? out : defaultValue;
}
getNumber(name, defaultValue) {
const out = this.getProperty(name);
return typeof out === "number" ? out : defaultValue;
}
getBlob(name, defaultValue) {
const out = this.getProperty(name);
return out instanceof Uint8Array ? out : defaultValue;
}
getObject(name, defaultValue) {
const out = this.getProperty(name);
return typeof out === "object" ? out : defaultValue;
}
/** call an iteration function for each property, optionally applying a filter */
forAllProperties(iter, filter) {
let sql = "SELECT name FROM properties WHERE name IS NOT NULL";
if (filter?.sqlExpression)
sql += ` AND ${filter.sqlExpression} `;
if (filter?.value)
sql += ` AND name ${filter.valueCompare ?? "="} @val`;
if (filter?.orderBy)
sql += ` ORDER BY name ${filter.orderBy} `;
this.withSqliteStatement(sql, (stmt) => {
if (filter?.value)
stmt.bindString("@val", filter.value);
while (stmt.nextRow()) {
if (iter(stmt.getValueString(0)) === "stop")
return;
}
});
}
/** Delete a single property from this PropertyDb. If the value does not exist, this method does nothing.
* @note the database must be opened for write
*/
async deleteProperty(propName) {
this.withSqliteStatement("DELETE from properties WHERE name=?", (stmt) => {
stmt.bindString(1, propName);
stmt.stepForWrite();
});
}
/** Delete an array of properties from this PropertyDb. Any value that does not exist is ignored.
* @note the database must be opened for write
*/
async deleteProperties(propNames) {
propNames.forEach(async (name) => this.deleteProperty(name));
}
validateName(name) {
if (typeof name !== "string" || name.trim() !== name || name.length > 2 * 1024 || name.length < 2)
throw new Error(`illegal property name[${name}]`);
}
/** Save a single property in this PropertyDb. If the property already exists, its value is overwritten.
* @note the database must be opened for write
*/
async saveProperty(name, value) {
this.validateName(name);
this.withSqliteStatement("INSERT OR REPLACE INTO properties(name,type,value) VALUES (?,?,?)", (stmt) => {
stmt.bindString(1, name);
switch (typeof value) {
case "string":
stmt.bindString(2, "string");
stmt.bindString(3, value);
break;
case "boolean":
stmt.bindString(2, "boolean");
stmt.bindInteger(3, value ? 1 : 0);
break;
case "number":
stmt.bindString(2, "number");
stmt.bindDouble(3, value);
break;
case "object":
if (value instanceof Uint8Array) {
stmt.bindString(2, "blob");
stmt.bindBlob(3, value);
}
else {
stmt.bindString(2, "object");
stmt.bindString(3, JSON.stringify(value));
}
break;
default:
throw new Error("illegal property value type");
}
stmt.stepForWrite();
});
}
/** Save an array of properties in this PropertyDb. If a property already exists, its value is overwritten.
* @note the database must be opened for write
*/
async saveProperties(props) {
for (const prop of props)
await this.saveProperty(prop.name, prop.value);
}
}
PropertyStore.PropertyDb = PropertyDb;
const defaultDbName = "PropertyDb";
/**
* Provides access to a cloud-based `PropertyDb` to hold a set of values of type `PropertyType`, each with a unique `PropertyName`.
* `PropertyStore.PropertyDb`s that are stored in cloud containers require an access token that grants permission to read and/or write them.
* All write operations will fail without an access token that grants write permission.
*
* The database is cached on a local drive so reads are fast and inexpensive, and may even be done offline after a prefetch.
* However, that means that callers are responsible for synchronizing the local cache to ensure it includes changes
* made by others, as appropriate (see [[synchronizeWithCloud]]).
*/
class CloudAccess extends CloudSqlite_1.CloudSqlite.DbAccess {
constructor(props) {
super({ dbType: PropertyDb, props, dbName: defaultDbName });
}
/**
* Initialize a cloud container for use as a PropertyStore. This method is called by [[createNewContainer]].
* It is only necessary to convert an existing container to a PropertyStore container.
* @note this deletes any existing content in the container.
* @internal
*/
static async initializeDb(args) {
return super._initializeDb({ ...args, dbType: PropertyDb, dbName: defaultDbName });
}
/** Create and initialize a new BlobContainer to hold a PropertyStore
* @note the current user must have administrator rights to create containers.
*/
static async createNewContainer(args) {
const props = await this.createBlobContainer({ scope: args.scope, metadata: { ...args.metadata, containerType: "property-store" } });
await this.initializeDb({ props });
return props;
}
}
PropertyStore.CloudAccess = CloudAccess;
})(PropertyStore || (exports.PropertyStore = PropertyStore = {}));
//# sourceMappingURL=PropertyStore.js.map