@sap-ux/store
Version:
NPM module for storing persistent data
113 lines • 5.24 kB
JavaScript
import { getFilesystemStore as dataAccessFilesystem } from './filesystem.js';
import { hasAnyValue, pick } from '../utils/index.js';
import { getSecureStore } from '../secure-store/index.js';
import { getSensitiveDataProperties, getSerializableProperties } from '../decorators/index.js';
import { inspect } from 'node:util';
function getFullyQualifiedServiceName(name) {
return 'fiori/v2/' + name;
}
class HybridStore {
logger;
filesystem;
secureStore;
constructor(logger, options = {}) {
this.logger = logger;
this.filesystem = dataAccessFilesystem(this.logger, options);
this.secureStore = getSecureStore(this.logger);
}
async read({ entityName, id }) {
const serialized = await this.filesystem.read({ entityName, id });
if (!serialized) {
this.logger.debug(`hybrid/read - id: [${id}], nothing on the filesystem`);
}
else {
this.logger.debug(`hybrid/read - id: [${id}], filesystem: ${inspect(serialized)}`);
}
const sensitiveData = await this.secureStore.retrieve(getFullyQualifiedServiceName(entityName), id);
if (!sensitiveData) {
this.logger.debug(`hybrid/read - id: [${id}], nothing in the secure store`);
}
else {
this.logger.debug(`hybrid/read - id: [${id}]. Found sensitive data in secure store`);
}
if (serialized || sensitiveData) {
// Make sure sensitive props override serialized ones
return { ...serialized, ...sensitiveData };
}
else {
return undefined;
}
}
async getAll({ entityName, includeSensitiveData = true }) {
return Object.values(await this.readAll({ entityName, includeSensitiveData }));
}
async readAll({ entityName, includeSensitiveData = true }) {
const result = {};
const entitiesFs = (await this.filesystem.readAll({ entityName })) || {};
const isEntitiesFsEmpty = Object.keys(entitiesFs).length === 0;
if (!includeSensitiveData && !isEntitiesFsEmpty) {
return entitiesFs;
}
const entitiesInSecureStore = (await this.secureStore.getAll(getFullyQualifiedServiceName(entityName))) || {};
for (const key of new Set([...Object.keys(entitiesFs), ...Object.keys(entitiesInSecureStore)])) {
// Make sure sensitive props override serialized ones
const entity = { ...entitiesFs[key], ...entitiesInSecureStore[key] };
result[key] = entity;
}
return result;
}
async write({ entityName, id, entity }) {
const serializableProps = getSerializableProperties(entity);
const sensitiveProps = getSensitiveDataProperties(entity);
if (serializableProps.length > 0 && sensitiveProps.length > 0) {
for (let i = 0; i < serializableProps.length; i = i + 1) {
if (sensitiveProps.indexOf(serializableProps[i]) !== -1) {
this.logger.debug(`hybrid/write - [${String(serializableProps[i])}] is also marked as sensitive. Not writing to filesystem`);
serializableProps.splice(i, 1);
}
}
}
const serializable = pick(entity, ...serializableProps);
if (hasAnyValue(entity, serializableProps)) {
this.logger.debug(`hybrid/write - writing serializable properties: ${inspect(serializable)}`);
await this.filesystem.write({ entityName, id, entity: serializable });
}
else {
this.logger.debug(`hybrid/write - no serializable properties found in ${inspect(serializable)}`);
}
const sensitiveData = pick(entity, ...sensitiveProps);
if (hasAnyValue(sensitiveData, sensitiveProps)) {
this.logger.debug(`hybrid/write - writing sensitive properties to secure store. ID: [${id}]`);
await this.secureStore.save(getFullyQualifiedServiceName(entityName), id, sensitiveData);
}
else {
this.logger.debug(`hybrid/write - no sensitive properties found in ${inspect(entity)}`);
}
return entity;
}
async del({ entityName, id }) {
const deletedinFs = await this.filesystem.del({ entityName, id });
this.logger.debug(`hybrid/del - delete result for id [${id}] on the filesystem: ${deletedinFs}`);
const deletedInSecureStore = await this.secureStore.delete(getFullyQualifiedServiceName(entityName), id);
this.logger.debug(`hybrid/del - delete result for id [${id}] in the secure store: ${deletedInSecureStore}`);
return deletedinFs || deletedInSecureStore;
}
async partialUpdate({ entityName, id, entity }) {
return this.filesystem.partialUpdate({
entityName,
id,
entity
});
}
}
/** A hybrid store
* Stores serializable properties on the filesystem
* The properties need to be decorated with `@serilizable` annotations
*
* Sensitive properties (decorated with `@sensitiveData`) will be stored
* in the system's secure store
*/
export function getHybridStore(logger, options) {
return new HybridStore(logger, options);
}
//# sourceMappingURL=hybrid.js.map