UNPKG

mongoosastic-ts

Version:

A mongoose plugin that indexes models into elastic search

285 lines 11.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Generator = void 0; // // Get type from the mongoose schema // // Returns the type, so in case none is set, it's the mongoose type. // // @param paths // @param field // @return the type or false // function getTypeFromPaths(paths, field) { var _a, _b, _c, _d; let type = false; if (((_b = (_a = paths === null || paths === void 0 ? void 0 : paths[field]) === null || _a === void 0 ? void 0 : _a.options) === null || _b === void 0 ? void 0 : _b.type) === Date) { return 'date'; } if (((_d = (_c = paths === null || paths === void 0 ? void 0 : paths[field]) === null || _c === void 0 ? void 0 : _c.options) === null || _d === void 0 ? void 0 : _d.type) === Boolean) { return 'boolean'; } if (paths[field]) { type = !!paths[field].instance ? paths[field].instance.toLowerCase() : 'object'; } if (type === 'array') { type = 'mixed'; } return type; } // // Generates the mapping // // Can be called recursively. // // @param cleanTree // @param inPrefix // @return the mapping // function getMapping(cleanTree, inPrefix) { const mapping = {}; const implicitFields = []; let hasEsIndex = false; const prefix = inPrefix !== '' ? `${inPrefix}.` : inPrefix; for (const field in cleanTree) { if (!cleanTree.hasOwnProperty(field)) { continue; } const value = cleanTree[field]; mapping[field] = {}; mapping[field].type = value.type; // Check if field was explicity indexed, if not keep track implicitly if (value.es_indexed) { hasEsIndex = true; } else if (value.type) { implicitFields.push(field); } // If there is no type, then it's an object with subfields. if (typeof value === 'object' && !value.type) { mapping[field].type = 'object'; mapping[field].properties = getMapping(value, prefix + field); } // If it is a objectid make it a string. if (value.type === 'objectid') { if (value.ref && value.es_schema) { mapping[field].type = 'object'; mapping[field].properties = getMapping(value, prefix + field); continue; } // do not continue here so we can handle other es_ options mapping[field].type = 'string'; } // If indexing a number, and no es_type specified, default to long if (value.type === 'number' && value.es_type === undefined) { mapping[field].type = 'long'; continue; } // Else, it has a type and we want to map that! for (const prop in value) { // Map to field if it's an Elasticsearch option if (value.hasOwnProperty(prop) && prop.indexOf('es_') === 0 && prop !== 'es_indexed') { mapping[field][prop.replace(/^es_/, '')] = value[prop]; } } // if type is never mapped, delete mapping if (mapping[field].type === undefined) { delete mapping[field]; } // Set default string type if (mapping[field] && mapping[field].type === 'string') { const textType = { type: 'text', fields: { keyword: { type: 'keyword', ignore_above: 256, }, }, }; mapping[field] = Object.assign(mapping[field], textType); } } // If one of the fields was explicitly indexed, delete all implicit fields if (hasEsIndex) { implicitFields.forEach((implicitField) => { delete mapping[implicitField]; }); } return mapping; } // // Generates a clean tree // // Can be called recursively. // // @param tree // @param paths // @param prefix // @return the tree // function getCleanTree(tree, paths, inPrefix, isRoot) { var _a, _b, _c, _d, _e, _f, _g, _h; const cleanTree = {}; let value = {}; let geoFound = false; const prefix = inPrefix !== '' ? `${inPrefix}.` : inPrefix; tree = Object.assign({}, tree); paths = Object.assign({}, paths); for (const field in tree) { if (prefix === '' && field === '_id' && isRoot) { continue; } const type = getTypeFromPaths(paths, prefix + field); value = tree[field]; if (value.es_indexed === false) { continue; } // Field has some kind of type if (type) { // If it is an nested schema if (value[0] || type === 'embedded') { // A nested array can contain complex objects nestedSchema(paths, field, cleanTree, value, prefix); // eslint-disable-line no-use-before-define } else if (value.type && Array.isArray(value.type)) { // An object with a nested array nestedSchema(paths, field, cleanTree, value, prefix); // eslint-disable-line no-use-before-define // Merge top level es settings for (const prop in value) { // Map to field if it's an Elasticsearch option if (value.hasOwnProperty(prop) && prop.indexOf('es_') === 0) { cleanTree[field][prop] = value[prop]; } } } else if (((_c = (_b = (_a = paths === null || paths === void 0 ? void 0 : paths[field]) === null || _a === void 0 ? void 0 : _a.options) === null || _b === void 0 ? void 0 : _b.es_schema) === null || _c === void 0 ? void 0 : _c.tree) && ((_f = (_e = (_d = paths === null || paths === void 0 ? void 0 : paths[field]) === null || _d === void 0 ? void 0 : _d.options) === null || _e === void 0 ? void 0 : _e.es_schema) === null || _f === void 0 ? void 0 : _f.paths)) { const subTree = paths[field].options.es_schema.tree; if ((_h = (_g = paths === null || paths === void 0 ? void 0 : paths[field]) === null || _g === void 0 ? void 0 : _g.options) === null || _h === void 0 ? void 0 : _h.es_select) { for (const treeNode in subTree) { if (!subTree.hasOwnProperty(treeNode)) { continue; } if (paths[field].options.es_select.split(' ').indexOf(treeNode) === -1) { delete subTree[treeNode]; } } } cleanTree[field] = getCleanTree(subTree, paths[field].options.es_schema.paths, ''); } else if (value === String || value === Object || value === Date || value === Number || value === Boolean || value === Array) { cleanTree[field] = {}; cleanTree[field].type = type; } else { cleanTree[field] = {}; for (const key in value) { if (value.hasOwnProperty(key)) { cleanTree[field][key] = value[key]; } } cleanTree[field].type = type; } // It has no type for some reason } else { // Because it is an geo_* object!! if (typeof value === 'object') { for (const key in value) { if (value.hasOwnProperty(key) && /^geo_/.test(key)) { cleanTree[field] = value[key]; geoFound = true; } } if (geoFound) { continue; } } // If it's a virtual type, don't map it if (typeof value === 'object' && value.getters && value.setters && value.options) { continue; } // Because it is some other object!! Or we assumed that it is one. if (typeof value === 'object') { cleanTree[field] = getCleanTree(value, paths, prefix + field); } } } return cleanTree; } // // Define a nested schema // // @param paths // @param field // @param cleanTree // @param value // @param prefix // @return cleanTree modified // function nestedSchema(paths, field, cleanTree, value, prefix) { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o; // A nested array can contain complex objects if (((_b = (_a = paths[prefix + field]) === null || _a === void 0 ? void 0 : _a.schema) === null || _b === void 0 ? void 0 : _b.tree) && ((_d = (_c = paths[prefix + field]) === null || _c === void 0 ? void 0 : _c.schema) === null || _d === void 0 ? void 0 : _d.paths)) { cleanTree[field] = getCleanTree(paths[prefix + field].schema.tree, paths[prefix + field].schema.paths, ''); } else if (((_h = (_g = (_f = (_e = paths[prefix + field]) === null || _e === void 0 ? void 0 : _e.options) === null || _f === void 0 ? void 0 : _f.type) === null || _g === void 0 ? void 0 : _g[0].es_schema) === null || _h === void 0 ? void 0 : _h.tree) && ((_o = (_m = (_l = (_k = (_j = paths[prefix + field]) === null || _j === void 0 ? void 0 : _j.options) === null || _k === void 0 ? void 0 : _k.type) === null || _l === void 0 ? void 0 : _l[0]) === null || _m === void 0 ? void 0 : _m.es_schema) === null || _o === void 0 ? void 0 : _o.paths)) { // A nested array of references filtered by the 'es_select' option const subTree = paths[field].options.type[0].es_schema.tree; if (paths[field].options.type[0].es_select) { for (const treeNode in subTree) { if (!subTree.hasOwnProperty(treeNode)) { continue; } if (paths[field].options.type[0].es_select.split(' ').indexOf(treeNode) === -1) { delete subTree[treeNode]; } } } cleanTree[field] = getCleanTree(subTree, paths[prefix + field].options.type[0].es_schema.paths, ''); } else if (paths[prefix + field] && paths[prefix + field].caster && paths[prefix + field].caster.instance) { // Even for simple types the value can be an object if there is other attributes than type if (typeof value[0] === 'object') { cleanTree[field] = value[0]; } else if (typeof value === 'object') { cleanTree[field] = value; } else { cleanTree[field] = {}; } cleanTree[field].type = paths[prefix + field].caster.instance.toLowerCase(); } else if (!paths[field] && prefix) { if (paths[prefix + field] && paths[prefix + field].caster && paths[prefix + field].caster.instance) { cleanTree[field] = { type: paths[prefix + field].caster.instance.toLowerCase(), }; } } else { cleanTree[field] = { type: 'object', }; } } exports.Generator = { // Schema<any, any, any> generateMapping: function generateMapping(schema) { const cleanTree = getCleanTree(schema.tree, schema.paths, '', true); delete cleanTree[schema.get('versionKey')]; const mapping = getMapping(cleanTree, ''); return { properties: mapping }; }, getCleanTree: function (schema) { return getCleanTree(schema.tree, schema.paths, '', true); }, }; //# sourceMappingURL=mapping-generator.js.map