|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196 |
- 'use strict';
-
- /*!
- * ignore
- */
-
- const Mixed = require('../../schema/mixed');
- const get = require('../get');
- const leanPopulateMap = require('./leanPopulateMap');
- const mpath = require('mpath');
-
- /*!
- * @param {Schema} schema
- * @param {Object} doc POJO
- * @param {string} path
- */
-
- module.exports = function getSchemaTypes(schema, doc, path) {
- const pathschema = schema.path(path);
- const topLevelDoc = doc;
-
- if (pathschema) {
- return pathschema;
- }
-
- 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 (doc != null && 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) {
- if (keys.indexOf(discriminator) !== -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 (let i = 0; i < schemas.length; ++i) {
- const _ret = search(
- parts.slice(p),
- schemas[i],
- 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.
- // Ignore discriminators.
- let type = foundschema;
- while (type.$isMongooseArray && !type.$isMongooseDocumentArray) {
- type = type.casterConstructor;
- }
- return search(
- parts.slice(p),
- type.schema,
- null,
- nestedPath.concat(parts.slice(0, p))
- );
- }
- }
-
- const fullPath = nestedPath.concat([trypath]).join('.');
- if (topLevelDoc.$__ && topLevelDoc.populated(fullPath) && p < parts.length) {
- const schema = get(doc.$__.populated[fullPath], 'options.model.schema');
- if (schema != null) {
- const ret = search(
- parts.slice(p),
- schema,
- subdoc ? mpath.get(trypath, subdoc) : null,
- nestedPath.concat(parts.slice(0, p))
- );
-
- if (ret) {
- ret.$isUnderneathDocArray = ret.$isUnderneathDocArray ||
- !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) {
- 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, []);
- };
|