UNPKG

@sap-ux/store

Version:

NPM module for storing persistent data

239 lines 8.58 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.basedir = void 0; exports.getFilesystemWatcherFor = getFilesystemWatcherFor; exports.getFilesystemStore = getFilesystemStore; const path_1 = __importDefault(require("path")); const fs_1 = __importStar(require("fs")); const pluralize_1 = require("pluralize"); const utils_1 = require("../utils"); const os_1 = __importDefault(require("os")); const basedir = ({ baseDirectory } = {}) => { if (!baseDirectory) { return (0, utils_1.getFioriToolsDirectory)(); } else if (path_1.default.isAbsolute(baseDirectory)) { return baseDirectory; } else { return path_1.default.join(os_1.default.homedir(), baseDirectory); } }; exports.basedir = basedir; class FilesystemStore { logger; storeDirectory; constructor(logger, options = {}) { this.logger = logger; this.storeDirectory = (0, exports.basedir)(options); } async read({ entityName, id }) { const name = toPersistenceName(entityName); if (!name) { this.logger.debug('read: Entity Type is falsy - ' + entityName); return Promise.resolve(undefined); } const { entities, error } = this._readAll(name); if (error) { if (error.code === 'ENOENT') { return Promise.resolve(undefined); } else { throw error; } } if (!entities) { this.logger.debug(`read: After parsing, entities is falsy. Entity: ${name}, parsed value: ${entities}`); return undefined; } return Promise.resolve(entities[id]); } async getAll({ entityName }) { const name = toPersistenceName(entityName); if (!name) { this.logger.debug('read: Entity Type is falsy - ' + entityName); return Promise.resolve([]); } const { entities, error } = this._readAll(name); if (error) { if (error.code === 'ENOENT') { return Promise.resolve([]); } else { throw error; } } if (!entities) { this.logger.debug(`read: After parsing, entities is falsy. Entity: ${name}, parsed value: ${entities}`); return Promise.resolve([]); } return Promise.resolve(Object.values(entities)); } async readAll({ entityName }) { const name = toPersistenceName(entityName); if (!name) { this.logger.debug('read: Entity Type is falsy - ' + entityName); return Promise.resolve({}); } const { entities, error } = this._readAll(name); if (error) { if (error.code === 'ENOENT') { return Promise.resolve({}); } else { throw error; } } if (!entities) { this.logger.debug(`read: After parsing, entities is falsy. Entity: ${name}, parsed value: ${entities}`); return Promise.resolve({}); } return Promise.resolve(entities); } async write({ entityName, id, entity }) { const name = toPersistenceName(entityName); if (!name) { this.logger.debug('write: Entity is falsy - ' + name); return Promise.resolve(undefined); } const { entities = {}, error } = this._readAll(name); if (error && error.code !== 'ENOENT') { throw error; } entities[id] = entity; this.writeToFile(name, entities); return Promise.resolve(entity); } async del({ entityName, id }) { const name = toPersistenceName(entityName); if (!name) { this.logger.debug('delete: Entity is falsy - ' + name); return Promise.resolve(false); } const { entities = {}, error } = this._readAll(name); if (error) { if (error.code !== 'ENOENT') { throw error; } } const exists = !!entities[id]; if (exists) { this.logger.debug(`delete: entity found for id - ${id}. Deleting`); delete entities[id]; this.writeToFile(name, entities); return Promise.resolve(true); } else { this.logger.debug('delete: entity not found'); return Promise.resolve(false); } } _readAll(entityName) { let rawContents; try { const configPath = path_1.default.join(this.storeDirectory, `${entityName}.json`); if ((0, fs_1.existsSync)(configPath)) { rawContents = (0, fs_1.readFileSync)(configPath).toString().trim(); } else { rawContents = ''; } } catch (e) { const err = (0, utils_1.errorInstance)(e); this.logger.debug(err.message); return { error: err }; } if (!rawContents) { return { entities: undefined }; } let entities; try { entities = JSON.parse(rawContents)?.[entityName]; } catch (e) { return { error: (0, utils_1.errorInstance)(e) }; } return { entities }; } writeToFile(entityName, entities) { const data = JSON.stringify({ [entityName]: entities }, null, 2); const filename = getEntityFileName(entityName); try { (0, fs_1.writeFileSync)(path_1.default.join(this.storeDirectory, filename), data); } catch (e) { const err = (0, utils_1.errorInstance)(e); if (err?.code === 'ENOENT') { this.logger.debug(`Base directory [${this.storeDirectory}] does not exist, trying to create it`); (0, fs_1.mkdirSync)(this.storeDirectory, { recursive: true }); (0, fs_1.writeFileSync)(path_1.default.join(this.storeDirectory, filename), data); } else { throw e; } } } } /** * Trims, lowercases and returns plural if a non-empty string * * @param s */ function toPersistenceName(s) { const t = s?.trim().toLowerCase(); return t && (0, pluralize_1.plural)(t); } function getEntityFileName(entityName) { return toPersistenceName(entityName) + '.json'; } /** Return an FSWatcher for a given entity name * The client is responsible for disposing of the FSWatcher */ function getFilesystemWatcherFor(entityName, callback, options = {}) { const watchPath = path_1.default.join((0, exports.basedir)(options), getEntityFileName(entityName)); if ((0, fs_1.existsSync)(watchPath)) { return fs_1.default.watch(watchPath, undefined, () => { callback(entityName); }); } else { console.warn(`File Not Found: ${watchPath}`); return undefined; } } /** * Filesystem store. The entity is stored in JSON format (don't depend on the format, this could change). * The entity is stored in a file named with the plural form of the entity name in the base directory. Again, this is an * implementation detail, please don't depend on it. */ function getFilesystemStore(logger, options) { return new FilesystemStore(logger, options); } //# sourceMappingURL=filesystem.js.map