UNPKG

dobo

Version:

DBMS for Bajo Framework

101 lines (95 loc) 4.88 kB
import { getFilterAndOptions, execHook, execModelHook, execDynHook, execValidation, getRefs, handleReq, clearCache } from './_util.js' const action = 'upsertRecord' async function native (body = {}, opts = {}) { const { isSet } = this.app.lib.aneka const { getDefaultValues } = this.app.dobo const { cloneDeep, get } = this.app.lib._ opts.dataOnly = opts.dataOnly ?? true const { dataOnly } = opts const { options } = await getFilterAndOptions.call(this, null, opts, action) const { truncateString, noResult, noBodySanitizer, noResultSanitizer, noValidation } = options const extFields = get(options, 'validation.extFields', []) let input = noBodySanitizer ? cloneDeep(body) : await this.sanitizeBody({ body, extFields, strict: true, truncateString, action }) if (!noValidation) input = await execValidation.call(this, input, options) await execHook.call(this, 'beforeUpsertRecord', input, options) await execModelHook.call(this, 'beforeUpsertRecord', input, options) await execDynHook.call(this, 'beforeUpsertRecord', input, options) const result = options.record ?? (await this.driver._upsertRecord(this, input, options)) ?? {} if (noResult) return await handleReq.call(this, result.data.id, 'upserted', options) await clearCache.call(this, body.id) const { warnings } = getDefaultValues(options) if (!warnings) delete result.warnings if (isSet(options.refs)) await getRefs.call(this, [result.data], options) if (!noResultSanitizer) result.data = await this.sanitizeRecord(result.data, options) await execDynHook.call(this, 'afterUpsertRecord', input, result, options) await execModelHook.call(this, 'afterUpsertRecord', input, result, options) await execHook.call(this, 'afterUpsertRecord', input, result, options) return dataOnly ? result.data : result } async function manual (body = {}, options = {}) { const { isSet } = this.app.lib.aneka const { get, omit } = this.app.lib._ if (isSet(body.id)) body.id = this.sanitizeId(body.id) let old = false if (isSet(body.id)) { try { old = await this.driver._getRecord(this, body.id, { noHook: true, noModelHook: true }) } catch (err) { } } const id = get(old, 'data.id') if (id) return await this.updateRecord(old.data.id, omit(body, ['id']), options) return await this.createRecord(body, options) } /** * @typedef {Object} TRecordUpdateOptions * @see Model#updateRecord * @property {boolean} [dataOnly=true] - If ```true``` (default) returns record's object. Otherwise {@link TRecordUpdateResult} * @property {boolean} [noHook=false] - If ```true```, no model's hook will be executed * @property {boolean} [noModelHook=false] - If ```true```, no model's hook will be executed * @property {boolean} [noValidation=false] - If ```true```, no validation of data payload performed * @property {boolean} [noCheckUnique=false] - If ```true```, no unique validation for ID performed * @property {boolean} [noBodySanitizer=false] - If ```true```, accept data payload as is without sanitization * @property {boolean} [noRecordSanitizer=false] - If ```true```, accept result payload as is without sanitization * @property {boolean} [noResult=false] - If ```true```, returns nothing * @property {boolean} [truncateString=true] - If ```true``` (default), string is truncated to its model's ```maxLength``` * @property {boolean} [partial=true] - If ```true``` (default), only updated values are saved. Otherwise replace all existing values with given payload * @property {boolean} [fields=[]] - If not empty, return only these fields EXCLUDING hidden fields * @property {boolean} [hidden=[]] - Additional fields to hide, in addition the one set in model's model * @property {boolean} [forceNoHidden=false] - If ```true```, hidden fields will be ignored and ALL fields will be returned */ /** * Update a record by it's ID and body payload * * Example: * ```javascript * const { recordUpdate } = this.app.dobo * const { body } = { * name: 'Republic of Indonesia', * phoneCode: '+62' * } * const result = await recordUpdate('CdbCountry', 'ID', body) * ``` * * @method * @memberof Dobo * @async * @instance * @name recordUpdate * @param {string} name - Model's name * @param {(string|number)} id - Record's ID * @param {Object} body - Body payload * @param {TRecordUpdateOptions} [options={}] * @returns {(TRecordUpdateResult|Object)} Returns updated record if ```options.dataOnly``` is set. {@link TRecordUpdateResult} otherwise */ async function upsertRecord (...args) { if (args.length === 0) return this.action(action, ...args) const [body = {}, opts = {}] = args if (this.driver.upsertRecord) { const { options } = await getFilterAndOptions.call(this, null, opts, action) return await native.call(this, body, options) } return await manual.call(this, body, opts) } export default upsertRecord