UNPKG

waibu-db

Version:
247 lines (232 loc) 8.45 kB
import countRecord from './lib/method/count-record.js' import createAggregate from './lib/method/create-aggregate.js' import createHistogram from './lib/method/create-histogram.js' import createRecord from './lib/method/create-record.js' import findOneRecord from './lib/method/find-one-record.js' import findRecord from './lib/method/find-record.js' import getSchemaExt from './lib/method/get-schema-ext.js' import getRecord from './lib/method/get-record.js' import removeRecord from './lib/method/remove-record.js' import updateRecord from './lib/method/update-record.js' import findAllRecord from './lib/method/find-all-record.js' import config from './lib/config.js' /** * Plugin factory. * * **Never** call this function directly!!! It's only-meant to be called by the {@link https://ardhi.github.io/bajo|Bajo framework} during plugin initialization. * * @param {string} pkgName - NPM package name * @returns {WaibuDb} WaibuDb class */ async function factory (pkgName) { const me = this /** * WaibuDb class definition. * * @class */ class WaibuDb extends this.app.baseClass.Base { /** * Constructor. */ constructor () { super(pkgName, me.app) /** * Configuration object. * @type {TConfig} */ this.config = config /** * Method map for CRUD operations. * @type {object} * @property {string} [create='POST'] - HTTP method for create operation * @property {string} [find='GET'] - HTTP method for find operation * @property {string} [get='GET'] - HTTP method for get operation * @property {string} [update='PUT'] - HTTP method for update operation * @property {string} [remove='DELETE'] - HTTP method for remove operation */ this.methodMap = { create: 'POST', find: 'GET', get: 'GET', update: 'PUT', remove: 'DELETE' } this.selfBind([ 'countRecord', 'createAggregate', 'createHistogram', 'createRecord', 'findOneRecord', 'findRecord', 'getSchemaExt', 'getRecord', 'removeRecord', 'updateRecord', 'findAllRecord' ]) } /** * Export data and save it as a file you can download later. * This method is intended to be called by a worker process. * * If sumba is loaded, file download is handled by sumba download management which provides * you a slick UI to monitor the download progress and status. * * If not, file is saved in standard bajo download directory. * @async * @method * @param {object} params * @returns {string} Path to the exported file */ exportData = async (params) => { const { get } = this.app.lib._ const { fs } = this.app.lib const { exportTo } = this.app.doboExtra const model = get(params, 'payload.data.name') const fields = get(params, 'payload.data.opts.fields') const { id, file } = get(params, 'payload.data.download', {}) let dest = `${this.app.bajo.getDownloadDir()}/${file}` const options = { filter: get(params, 'payload.data.filter', {}), ensureDir: true, fields } options.filter.sort = 'id:1' // TODO: make this configurable if (!this.app.sumba || !id) { await exportTo(model, dest, options) return dest } const { downloadDir } = this.app.sumba dest = `${downloadDir}/${file}` const dmodel = this.app.dobo.getModel('SumbaDownload') try { await dmodel.updateRecord(id, { status: 'PROCESSING' }) await exportTo(model, dest, options) const { size } = fs.statSync(dest) await dmodel.updateRecord(id, { size, status: 'COMPLETE' }) } catch (err) { await dmodel.updateRecord(id, { status: 'FAIL' }) } return dest } /** * Get all models that will be automatically included in the WaibuAdmin menu. * @method * @returns {Array} List of models */ getAutoModels = () => { const { filter, get, map, isArray } = this.app.lib._ const { pascalCase } = this.app.lib.aneka const allModels = this.app.dobo.models const models = filter(allModels, s => { const byModelFind = !s.disabled.includes('find') const disabled = get(this, `app.${s.plugin.ns}.config.waibuAdmin.modelDisabled`, []) let modelDisabled = [] if (['*', 'all'].includes(disabled)) modelDisabled = map(filter(allModels, m => m.plugin.ns === s.plugin.ns), 'name') else if (isArray(disabled)) modelDisabled = map(disabled, m => pascalCase(`${this.app[s.plugin.ns].alias} ${m}`)) const byDbDisabled = !modelDisabled.includes(s.name) return byModelFind && byDbDisabled }) return models } /** * Build menu for WaibuAdmin * @param {object} locals - Locals object * @param {object} req - Request object * @returns {Array<object>} Menu structure */ adminMenu = async (locals, req) => { const { getPluginPrefix } = this.app.waibu const { getPluginTitle } = this.app.waibuMpa const { camelCase, map, groupBy, keys, kebabCase } = this.app.lib._ const prefix = getPluginPrefix(this.ns) const models = this.getAutoModels() const omenu = groupBy(map(models, s => { const item = { name: s.name, ns: s.plugin.ns } item.nsTitle = getPluginTitle(s.plugin.ns, req) return item }), 'nsTitle') const menu = [] for (const k of keys(omenu).sort()) { const items = omenu[k] const plugin = this.app[items[0].ns] menu.push({ title: req.t(k), children: map(items, item => { const params = { model: kebabCase(item.name), action: 'list' } return { title: camelCase(item.name.slice(plugin.alias.length)), href: `waibuAdmin:/${prefix}/:model/:action`, params } }) }) } return menu } /** * Collect all available parameters from the request object. * @method * @param {object} req - Request object * @param {...string} items - List of parameter names * @returns {object} Collected parameters */ getParams = (req, ...items) => { const { map, trim, get } = this.app.lib._ let fields req.query = req.query ?? {} req.params = req.params ?? {} if (req.query.fields) fields = map((req.query.fields ?? '').split(','), i => trim(i)) const params = { fields, count: get(this, 'config.dbModel.count', false), body: req.body } items.forEach(i => { params[i] = req.params[i] }) return params } /** * Get lookup data for a specific model and field based on provided options. * @method * @async * @param {object} opts - Options for the lookup * @param {string} opts.model - Model name * @param {object} opts.req - Request object * @param {Array<object>} opts.data - Data array * @param {string} [opts.id='id'] - ID field name * @param {string} opts.field - Field name to lookup * @param {object} [opts.query] - Optional query object * @returns {Promise<Array<object>>} Lookup results */ getLookupData = async (opts = {}) => { const { model, req, data, id = 'id', field, query } = opts const { set, map } = this.app.lib._ const $in = map(data, id) const q = query ?? set({}, field, { $in }) const options = { dataOnly: true, query: q } return await this.findAllRecord({ model, req, options }) } countRecord = countRecord createAggregate = createAggregate createHistogram = createHistogram createRecord = createRecord findOneRecord = findOneRecord findRecord = findRecord findAllRecord = findAllRecord getSchemaExt = getSchemaExt getRecord = getRecord removeRecord = removeRecord updateRecord = updateRecord } return WaibuDb } export default factory