| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147 |
- 'use strict';
- const mpath = require('mpath');
- const utils = require('../../utils');
- module.exports = applyVirtuals;
- /**
- * Apply a given schema's virtuals to a given POJO
- *
- * @param {Schema} schema
- * @param {Object} obj
- * @param {Array<string>} [virtuals] optional whitelist of virtuals to apply
- * @returns
- */
- function applyVirtuals(schema, obj, virtuals) {
- if (obj == null) {
- return obj;
- }
- let virtualsForChildren = virtuals;
- let toApply = null;
- if (Array.isArray(virtuals)) {
- virtualsForChildren = [];
- toApply = [];
- for (const virtual of virtuals) {
- if (virtual.length === 1) {
- toApply.push(virtual[0]);
- } else {
- virtualsForChildren.push(virtual);
- }
- }
- }
- applyVirtualsToChildren(schema, obj, virtualsForChildren);
- return applyVirtualsToDoc(schema, obj, toApply);
- }
- /**
- * Apply virtuals to any subdocuments
- *
- * @param {Schema} schema subdocument schema
- * @param {Object} res subdocument
- * @param {Array<String>} [virtuals] optional whitelist of virtuals to apply
- */
- function applyVirtualsToChildren(schema, res, virtuals) {
- let attachedVirtuals = false;
- for (const childSchema of schema.childSchemas) {
- const _path = childSchema.model.path;
- const _schema = childSchema.schema;
- if (!_path) {
- continue;
- }
- const _obj = mpath.get(_path, res);
- if (_obj == null || (Array.isArray(_obj) && _obj.flat(Infinity).length === 0)) {
- continue;
- }
- let virtualsForChild = null;
- if (Array.isArray(virtuals)) {
- virtualsForChild = [];
- for (const virtual of virtuals) {
- if (virtual[0] == _path) {
- virtualsForChild.push(virtual.slice(1));
- }
- }
- if (virtualsForChild.length === 0) {
- continue;
- }
- }
- applyVirtuals(_schema, _obj, virtualsForChild);
- attachedVirtuals = true;
- }
- if (virtuals?.length && !attachedVirtuals) {
- applyVirtualsToDoc(schema, res, virtuals);
- }
- }
- /**
- * Apply virtuals to a given document. Does not apply virtuals to subdocuments: use `applyVirtualsToChildren` instead
- *
- * @param {Schema} schema
- * @param {Object} doc
- * @param {Array<String>} [virtuals] optional whitelist of virtuals to apply
- * @returns
- */
- function applyVirtualsToDoc(schema, obj, virtuals) {
- if (obj == null || typeof obj !== 'object') {
- return;
- }
- if (Array.isArray(obj)) {
- for (const el of obj) {
- applyVirtualsToDoc(schema, el, virtuals);
- }
- return;
- }
- if (schema.discriminators && utils.hasOwnKeys(schema.discriminators)) {
- for (const discriminatorKey of Object.keys(schema.discriminators)) {
- const discriminator = schema.discriminators[discriminatorKey];
- const key = discriminator.discriminatorMapping.key;
- const value = discriminator.discriminatorMapping.value;
- if (obj[key] == value) {
- schema = discriminator;
- break;
- }
- }
- }
- if (virtuals == null) {
- virtuals = Object.keys(schema.virtuals);
- }
- for (const virtual of virtuals) {
- if (schema.virtuals[virtual] == null) {
- continue;
- }
- const virtualType = schema.virtuals[virtual];
- const sp = Array.isArray(virtual)
- ? virtual
- : virtual.indexOf('.') === -1
- ? [virtual]
- : virtual.split('.');
- let cur = obj;
- for (let i = 0; i < sp.length - 1; ++i) {
- cur[sp[i]] = sp[i] in cur ? cur[sp[i]] : {};
- cur = cur[sp[i]];
- }
- let val = virtualType.applyGetters(cur[sp[sp.length - 1]], obj);
- const isPopulateVirtual =
- virtualType.options?.ref || virtualType.options?.refPath;
- if (isPopulateVirtual && val === undefined) {
- if (virtualType.options.justOne) {
- val = null;
- } else {
- val = [];
- }
- }
- cur[sp[sp.length - 1]] = val;
- }
- }
|