graphql-compose-mongoose
Version:
Plugin for `graphql-compose` which derive a graphql types from a mongoose model.
160 lines (131 loc) • 5.78 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.getIndexesFromModel = getIndexesFromModel;
exports.getUniqueIndexes = getUniqueIndexes;
exports.extendByReversedIndexes = extendByReversedIndexes;
exports.getIndexedFieldNamesForGraphQL = getIndexedFieldNamesForGraphQL;
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(source, true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(source).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function isSpecificIndex(idx) {
let hasSpecialIndex = false;
Object.keys(idx).forEach(k => {
if (typeof idx[k] !== 'number' && typeof idx[k] !== 'boolean') {
hasSpecialIndex = true;
}
});
return hasSpecialIndex;
}
/*
* Get mongoose model, and return array of fields with indexes.
* MongooseModel -> [ { _id: 1 }, { name: 1, surname: -1 } ]
*/
function getIndexesFromModel(mongooseModel, opts = {}) {
const extractCompound = opts.extractCompound === undefined ? true : Boolean(opts.extractCompound);
const skipSpecificIndexes = opts.skipSpecificIndexes === undefined ? true : Boolean(opts.skipSpecificIndexes);
const indexedFields = []; // add _id field if existed
if (mongooseModel.schema.paths._id) {
indexedFields.push({
_id: 1
});
} // scan all fields on index presence [MONGOOSE FIELDS LEVEL INDEX]
Object.keys(mongooseModel.schema.paths).forEach(name => {
if (mongooseModel.schema.paths[name]._index) {
indexedFields.push({
[name]: 1
}); // ASC by default
}
}); // scan compound and special indexes [MONGOOSE SCHEMA LEVEL INDEXES]
if (Array.isArray(mongooseModel.schema._indexes)) {
mongooseModel.schema._indexes.forEach(idxData => {
const partialIndexes = {};
const idxFields = idxData[0];
if (!skipSpecificIndexes || !isSpecificIndex(idxFields)) {
if (!extractCompound) {
indexedFields.push(idxFields);
} else {
// extract partial indexes from compound index
// { name: 1, age: 1, salary: 1} -> [{name:1}, {name:1, age:1}, {name:1, age:1, salary:1}]
Object.keys(idxFields).forEach(fieldName => {
partialIndexes[fieldName] = idxFields[fieldName];
indexedFields.push(_objectSpread({}, partialIndexes));
});
}
}
});
} // filter duplicates
const tmp = [];
const result = indexedFields.filter(val => {
const asString = JSON.stringify(val);
if (tmp.indexOf(asString) > -1) return false;
tmp.push(asString);
return true;
});
return result;
}
function getUniqueIndexes(mongooseModel) {
const indexedFields = []; // add _id field if existed
if (mongooseModel.schema.paths._id) {
indexedFields.push({
_id: 1
});
} // scan all fields on index presence [MONGOOSE FIELDS LEVEL INDEX]
Object.keys(mongooseModel.schema.paths).forEach(name => {
if (mongooseModel.schema.paths[name]._index && mongooseModel.schema.paths[name]._index.unique) {
indexedFields.push({
[name]: 1
}); // ASC by default
}
}); // scan compound and special indexes [MONGOOSE SCHEMA LEVEL INDEXES]
if (Array.isArray(mongooseModel.schema._indexes)) {
mongooseModel.schema._indexes.forEach(idxData => {
const idxFields = idxData[0];
const idxCfg = idxData[1];
if (idxCfg.unique && !isSpecificIndex(idxFields)) {
indexedFields.push(idxFields);
}
});
}
return indexedFields;
}
function extendByReversedIndexes(indexes, opts = {}) {
const reversedFirst = opts.reversedFirst === undefined ? false : Boolean(opts.reversedFirst);
const result = [];
indexes.forEach(indexObj => {
let hasSpecificIndex = false; // https://docs.mongodb.org/manual/tutorial/sort-results-with-indexes/#sort-on-multiple-fields
const reversedIndexObj = _objectSpread({}, indexObj);
Object.keys(reversedIndexObj).forEach(f => {
if (reversedIndexObj[f] === 1) reversedIndexObj[f] = -1;else if (reversedIndexObj[f] === -1) reversedIndexObj[f] = 1;else hasSpecificIndex = true;
});
if (reversedFirst) {
if (!hasSpecificIndex) {
result.push(reversedIndexObj);
}
result.push(indexObj);
} else {
result.push(indexObj);
if (!hasSpecificIndex) {
result.push(reversedIndexObj);
}
}
});
return result;
}
function getIndexedFieldNamesForGraphQL(model) {
const indexes = getIndexesFromModel(model);
const fieldNames = [];
indexes.forEach(indexData => {
const keys = Object.keys(indexData);
const clearedName = keys[0].replace(/[^_a-zA-Z0-9]/i, '__');
fieldNames.push(clearedName);
}); // filter duplicates
const uniqueNames = [];
const result = fieldNames.filter(val => {
if (uniqueNames.indexOf(val) > -1) return false;
uniqueNames.push(val);
return true;
});
return result;
}