You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
156 lines
4.8 KiB
156 lines
4.8 KiB
'use strict';
|
|
|
|
const get = require('../get');
|
|
const helperIsObject = require('../isObject');
|
|
|
|
/*!
|
|
* Gather all indexes defined in the schema, including single nested,
|
|
* document arrays, and embedded discriminators.
|
|
*/
|
|
|
|
module.exports = function getIndexes(schema) {
|
|
let indexes = [];
|
|
const schemaStack = new WeakMap();
|
|
const indexTypes = schema.constructor.indexTypes;
|
|
const indexByName = new Map();
|
|
|
|
collectIndexes(schema);
|
|
return indexes;
|
|
|
|
function collectIndexes(schema, prefix, baseSchema) {
|
|
// Ignore infinitely nested schemas, if we've already seen this schema
|
|
// along this path there must be a cycle
|
|
if (schemaStack.has(schema)) {
|
|
return;
|
|
}
|
|
schemaStack.set(schema, true);
|
|
|
|
prefix = prefix || '';
|
|
const keys = Object.keys(schema.paths);
|
|
|
|
for (const key of keys) {
|
|
const path = schema.paths[key];
|
|
if (baseSchema != null && baseSchema.paths[key]) {
|
|
// If looking at an embedded discriminator schema, don't look at paths
|
|
// that the
|
|
continue;
|
|
}
|
|
|
|
if (path.$isMongooseDocumentArray || path.$isSingleNested) {
|
|
if (get(path, 'options.excludeIndexes') !== true &&
|
|
get(path, 'schemaOptions.excludeIndexes') !== true &&
|
|
get(path, 'schema.options.excludeIndexes') !== true) {
|
|
collectIndexes(path.schema, prefix + key + '.');
|
|
}
|
|
|
|
if (path.schema.discriminators != null) {
|
|
const discriminators = path.schema.discriminators;
|
|
const discriminatorKeys = Object.keys(discriminators);
|
|
for (const discriminatorKey of discriminatorKeys) {
|
|
collectIndexes(discriminators[discriminatorKey],
|
|
prefix + key + '.', path.schema);
|
|
}
|
|
}
|
|
|
|
// Retained to minimize risk of backwards breaking changes due to
|
|
// gh-6113
|
|
if (path.$isMongooseDocumentArray) {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
const index = path._index || (path.caster && path.caster._index);
|
|
|
|
if (index !== false && index !== null && index !== undefined) {
|
|
const field = {};
|
|
const isObject = helperIsObject(index);
|
|
const options = isObject ? index : {};
|
|
const type = typeof index === 'string' ? index :
|
|
isObject ? index.type :
|
|
false;
|
|
|
|
if (type && indexTypes.indexOf(type) !== -1) {
|
|
field[prefix + key] = type;
|
|
} else if (options.text) {
|
|
field[prefix + key] = 'text';
|
|
delete options.text;
|
|
} else {
|
|
const isDescendingIndex = Number(index) === -1;
|
|
field[prefix + key] = isDescendingIndex ? -1 : 1;
|
|
}
|
|
|
|
delete options.type;
|
|
if (!('background' in options)) {
|
|
options.background = true;
|
|
}
|
|
if (schema.options.autoIndex != null) {
|
|
options._autoIndex = schema.options.autoIndex;
|
|
}
|
|
|
|
const indexName = options && options.name;
|
|
if (typeof indexName === 'string') {
|
|
if (indexByName.has(indexName)) {
|
|
Object.assign(indexByName.get(indexName), field);
|
|
} else {
|
|
indexes.push([field, options]);
|
|
indexByName.set(indexName, field);
|
|
}
|
|
} else {
|
|
indexes.push([field, options]);
|
|
indexByName.set(indexName, field);
|
|
}
|
|
}
|
|
}
|
|
|
|
schemaStack.delete(schema);
|
|
|
|
if (prefix) {
|
|
fixSubIndexPaths(schema, prefix);
|
|
} else {
|
|
schema._indexes.forEach(function(index) {
|
|
if (!('background' in index[1])) {
|
|
index[1].background = true;
|
|
}
|
|
});
|
|
indexes = indexes.concat(schema._indexes);
|
|
}
|
|
}
|
|
|
|
/*!
|
|
* Checks for indexes added to subdocs using Schema.index().
|
|
* These indexes need their paths prefixed properly.
|
|
*
|
|
* schema._indexes = [ [indexObj, options], [indexObj, options] ..]
|
|
*/
|
|
|
|
function fixSubIndexPaths(schema, prefix) {
|
|
const subindexes = schema._indexes;
|
|
const len = subindexes.length;
|
|
for (let i = 0; i < len; ++i) {
|
|
const indexObj = subindexes[i][0];
|
|
const indexOptions = subindexes[i][1];
|
|
const keys = Object.keys(indexObj);
|
|
const klen = keys.length;
|
|
const newindex = {};
|
|
|
|
// use forward iteration, order matters
|
|
for (let j = 0; j < klen; ++j) {
|
|
const key = keys[j];
|
|
newindex[prefix + key] = indexObj[key];
|
|
}
|
|
|
|
const newIndexOptions = Object.assign({}, indexOptions);
|
|
if (indexOptions != null && indexOptions.partialFilterExpression != null) {
|
|
newIndexOptions.partialFilterExpression = {};
|
|
const partialFilterExpression = indexOptions.partialFilterExpression;
|
|
for (const key of Object.keys(partialFilterExpression)) {
|
|
newIndexOptions.partialFilterExpression[prefix + key] =
|
|
partialFilterExpression[key];
|
|
}
|
|
}
|
|
|
|
indexes.push([newindex, newIndexOptions]);
|
|
}
|
|
}
|
|
};
|