deno.land / x / mongoose@6.7.5 / lib / helpers / populate / getSchemaTypes.js
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234'use strict';
/*! * ignore */
const Mixed = require('../../schema/mixed');const get = require('../get');const getDiscriminatorByValue = require('../discriminator/getDiscriminatorByValue');const leanPopulateMap = require('./leanPopulateMap');const mpath = require('mpath');
const populateModelSymbol = require('../symbols').populateModelSymbol;
/** * Given a model and its schema, find all possible schema types for `path`, * including searching through discriminators. If `doc` is specified, will * use the doc's values for discriminator keys when searching, otherwise * will search all discriminators. * * @param {Model} model * @param {Schema} schema * @param {Object} doc POJO * @param {string} path * @api private */
module.exports = function getSchemaTypes(model, schema, doc, path) { const pathschema = schema.path(path); const topLevelDoc = doc; if (pathschema) { return pathschema; }
const discriminatorKey = schema.discriminatorMapping && schema.discriminatorMapping.key; if (discriminatorKey && model != null) { if (doc != null && doc[discriminatorKey] != null) { const discriminator = getDiscriminatorByValue(model.discriminators, doc[discriminatorKey]); schema = discriminator ? discriminator.schema : schema; } else if (model.discriminators != null) { return Object.keys(model.discriminators).reduce((arr, name) => { const disc = model.discriminators[name]; return arr.concat(getSchemaTypes(disc, disc.schema, null, path)); }, []); } }
function search(parts, schema, subdoc, nestedPath) { let p = parts.length + 1; let foundschema; let trypath;
while (p--) { trypath = parts.slice(0, p).join('.'); foundschema = schema.path(trypath); if (foundschema == null) { continue; }
if (foundschema.caster) { // array of Mixed? if (foundschema.caster instanceof Mixed) { return foundschema.caster; }
let schemas = null; if (foundschema.schema != null && foundschema.schema.discriminators != null) { const discriminators = foundschema.schema.discriminators; const discriminatorKeyPath = trypath + '.' + foundschema.schema.options.discriminatorKey; const keys = subdoc ? mpath.get(discriminatorKeyPath, subdoc) || [] : []; schemas = Object.keys(discriminators). reduce(function(cur, discriminator) { const tiedValue = discriminators[discriminator].discriminatorMapping.value; if (doc == null || keys.indexOf(discriminator) !== -1 || keys.indexOf(tiedValue) !== -1) { cur.push(discriminators[discriminator]); } return cur; }, []); }
// Now that we found the array, we need to check if there // are remaining document paths to look up for casting. // Also we need to handle array.$.path since schema.path // doesn't work for that. // If there is no foundschema.schema we are dealing with // a path like array.$ if (p !== parts.length && foundschema.schema) { let ret; if (parts[p] === '$') { if (p + 1 === parts.length) { // comments.$ return foundschema; } // comments.$.comments.$.title ret = search( parts.slice(p + 1), schema, subdoc ? mpath.get(trypath, subdoc) : null, nestedPath.concat(parts.slice(0, p)) ); if (ret) { ret.$isUnderneathDocArray = ret.$isUnderneathDocArray || !foundschema.schema.$isSingleNested; } return ret; }
if (schemas != null && schemas.length > 0) { ret = []; for (const schema of schemas) { const _ret = search( parts.slice(p), schema, subdoc ? mpath.get(trypath, subdoc) : null, nestedPath.concat(parts.slice(0, p)) ); if (_ret != null) { _ret.$isUnderneathDocArray = _ret.$isUnderneathDocArray || !foundschema.schema.$isSingleNested; if (_ret.$isUnderneathDocArray) { ret.$isUnderneathDocArray = true; } ret.push(_ret); } } return ret; } else { ret = search( parts.slice(p), foundschema.schema, subdoc ? mpath.get(trypath, subdoc) : null, nestedPath.concat(parts.slice(0, p)) );
if (ret) { ret.$isUnderneathDocArray = ret.$isUnderneathDocArray || !foundschema.schema.$isSingleNested; } return ret; } } else if (p !== parts.length && foundschema.$isMongooseArray && foundschema.casterConstructor.$isMongooseArray) { // Nested arrays. Drill down to the bottom of the nested array. let type = foundschema; while (type.$isMongooseArray && !type.$isMongooseDocumentArray) { type = type.casterConstructor; }
const ret = search( parts.slice(p), type.schema, null, nestedPath.concat(parts.slice(0, p)) ); if (ret != null) { return ret; }
if (type.schema.discriminators) { const discriminatorPaths = []; for (const discriminatorName of Object.keys(type.schema.discriminators)) { const _schema = type.schema.discriminators[discriminatorName] || type.schema; const ret = search(parts.slice(p), _schema, null, nestedPath.concat(parts.slice(0, p))); if (ret != null) { discriminatorPaths.push(ret); } } if (discriminatorPaths.length > 0) { return discriminatorPaths; } } } } else if (foundschema.$isSchemaMap && foundschema.$__schemaType instanceof Mixed) { return foundschema.$__schemaType; }
const fullPath = nestedPath.concat([trypath]).join('.'); if (topLevelDoc != null && topLevelDoc.$__ && topLevelDoc.$populated(fullPath) && p < parts.length) { const model = doc.$__.populated[fullPath].options[populateModelSymbol]; if (model != null) { const ret = search( parts.slice(p), model.schema, subdoc ? mpath.get(trypath, subdoc) : null, nestedPath.concat(parts.slice(0, p)) );
if (ret) { ret.$isUnderneathDocArray = ret.$isUnderneathDocArray || !model.schema.$isSingleNested; } return ret; } }
const _val = get(topLevelDoc, trypath); if (_val != null) { const model = Array.isArray(_val) && _val.length > 0 ? leanPopulateMap.get(_val[0]) : leanPopulateMap.get(_val); // Populated using lean, `leanPopulateMap` value is the foreign model const schema = model != null ? model.schema : null; if (schema != null) { const ret = search( parts.slice(p), schema, subdoc ? mpath.get(trypath, subdoc) : null, nestedPath.concat(parts.slice(0, p)) );
if (ret != null) { ret.$isUnderneathDocArray = ret.$isUnderneathDocArray || !schema.$isSingleNested; return ret; } } } return foundschema; } } // look for arrays const parts = path.split('.'); for (let i = 0; i < parts.length; ++i) { if (parts[i] === '$') { // Re: gh-5628, because `schema.path()` doesn't take $ into account. parts[i] = '0'; } } return search(parts, schema, doc, []);};
Version Info