UNPKG

@itwin/core-backend

Version:
180 lines • 8.53 kB
"use strict"; /*--------------------------------------------------------------------------------------------- * 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