UNPKG

odatafy-mongoose

Version:

Use mongoose to excel the capabilities of datafy-mongodb

306 lines (305 loc) 11.8 kB
"use strict"; var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var __values = (this && this.__values) || function(o) { var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; if (m) return m.call(o); if (o && typeof o.length === "number") return { next: function () { if (o && i >= o.length) o = void 0; return { value: o && o[i++], done: !o }; } }; throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); }; var __read = (this && this.__read) || function (o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); } catch (error) { e = { error: error }; } finally { try { if (r && !r.done && (m = i["return"])) m.call(i); } finally { if (e) throw e.error; } } return ar; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.mergeDeep = exports.extractMetaData = exports.getPathMetaData = exports.getModelMetadata = exports.getServiceMetaData = exports.getExpandMapping = void 0; var setup_1 = require("./setup"); var types_1 = require("./types"); /** * Get expandmap for use in odatafy-mongodb from a mongoose model * @param model - model to get expandmap for * @returns expandmap for the passed mongoose model */ function getExpandMapping(model, basePath, depth) { if (basePath === void 0) { basePath = ''; } if (depth === void 0) { depth = 0; } if (depth == 5) { return; } var mapping = {}; //improve typing var mongooseInstance = setup_1.MongooseInstanceWrapper.getInstance(); Object.keys(model.schema.paths).forEach(function (pathName) { var path = model.schema.path(pathName); if (path.instance == 'ObjectID' && path.options.ref) { var model_1 = mongooseInstance.model(path.options.ref); if (model_1) { mapping[basePath + path.path] = model_1.collection.collectionName; mapping = __assign(__assign({}, mapping), getExpandMapping(model_1, "".concat(basePath).concat(path.path, "."), depth + 1)); } } }); return mapping; } exports.getExpandMapping = getExpandMapping; /** * Get metadata for all models that are registered in the mongoose instance that is passed to init * @returns metadata for the odata service */ function getServiceMetaData() { var e_1, _a; var mongooseInstance = setup_1.MongooseInstanceWrapper.getInstance(); var serviceMetadata = { $schema: types_1.ODATASCHEMA, "odata-version": types_1.ODATAVERSION, definitions: {}, actions: {}, functions: {}, terms: {}, entityContainer: {}, schemas: {}, references: {} }; try { for (var _b = __values(Object.entries(mongooseInstance.models)), _c = _b.next(); !_c.done; _c = _b.next()) { var _d = __read(_c.value, 2), modelName = _d[0], modelEntry = _d[1]; serviceMetadata.definitions[modelName] = getModelMetadata(modelEntry); } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (_c && !_c.done && (_a = _b.return)) _a.call(_b); } finally { if (e_1) throw e_1.error; } } return serviceMetadata; } exports.getServiceMetaData = getServiceMetaData; /** * Extract metadata from a mongoose model * @param model - model to extract metadata from * @returns - metadata for the model */ function getModelMetadata(model) { var modelMetaData = { type: types_1.PrimitiveDataTypes.OBJECT, keys: ['_id'], properties: {} }; Object.keys(model.schema.paths).forEach(function (pathName) { var path = model.schema.path(pathName); //@ts-expect-error weird mongoose typings _presplitPath not appearing if (path._presplitPath.length > 1) { //@ts-expect-error weird mongoose typings _presplitPath not appearing modelMetaData.properties[path._presplitPath[0]] = getPathMetaData(model, pathName, modelMetaData); } else { modelMetaData.properties[pathName] = getPathMetaData(model, pathName, modelMetaData); } }); return modelMetaData; } exports.getModelMetadata = getModelMetadata; /** * Extract Metadata from mongoose model with pathanme * @param model - model to extract from * @param pathName - name of the path to extract * @param metaData - already extracted metadata * @returns extracted metadata for the specified pathName of the specified model */ function getPathMetaData(model, pathName, metaData) { var path = model.schema.path(pathName); return extractMetaData(model, path, metaData); } exports.getPathMetaData = getPathMetaData; /** * Extract Metadata from mongoose model path * @param model - model to extract from * @param path - path to extract * @param metaData - already extracted metadata * @returns extracted metadata for the specified path of the specified model */ function extractMetaData(model, path, metaData) { var e_2, _a; if (path.instance == 'ObjectID' && path.options.ref) { return { anyOf: [ { $ref: "#/definitions/".concat(path.options.ref) }, { type: types_1.PrimitiveDataTypes.NULL } ], relationships: { partner: model.modelName } }; //@ts-expect-error weird mongoose typings _presplitPath not appearing } else if (path._presplitPath.length > 1) { //@ts-expect-error weird mongoose typings _presplitPath not appearing var presplit = path._presplitPath; if (!(presplit[0] in metaData.properties)) { metaData.properties[presplit[0]] = { type: types_1.PrimitiveDataTypes.OBJECT, properties: {} }; } var copiedPath = JSON.parse(JSON.stringify(path)); copiedPath._presplitPath = []; var currField = extractMetaData(model, copiedPath, metaData); for (var i = presplit.length - 1; i > 0; i--) { var temp = JSON.parse(JSON.stringify(currField)); currField = { type: types_1.PrimitiveDataTypes.OBJECT, properties: {} }; currField.properties[presplit[i]] = temp; } ; //console.log(mergeDeep(metaData.properties[presplit[0]], currField)) return (0, exports.mergeDeep)(metaData.properties[presplit[0]], currField); } else if (path.instance == 'Array') { //@ts-expect-error property embeddedSchemaType does not exist on mongoose typings var embeddedType = path['$embeddedSchemaType']; var items = void 0; if (embeddedType.schema) { items = { type: types_1.PrimitiveDataTypes.OBJECT, properties: {} }; try { for (var _b = __values(Object.keys(embeddedType.schema.paths)), _c = _b.next(); !_c.done; _c = _b.next()) { var pathName = _c.value; var path_1 = embeddedType.schema.path(pathName); items.properties[pathName] = extractMetaData(model, path_1, metaData); } } catch (e_2_1) { e_2 = { error: e_2_1 }; } finally { try { if (_c && !_c.done && (_a = _b.return)) _a.call(_b); } finally { if (e_2) throw e_2.error; } } } else { items = extractMetaData(model, embeddedType, metaData); } return { type: types_1.PrimitiveDataTypes.ARRAY, items: items }; } else { switch (path.instance) { case 'Number': return { anyOf: [ { type: [types_1.PrimitiveDataTypes.STRING, types_1.PrimitiveDataTypes.NUMBER], format: types_1.DataFormats.DECIMAL }, { type: [types_1.PrimitiveDataTypes.NUMBER, types_1.PrimitiveDataTypes.STRING], format: types_1.DataFormats.DOUBLE }, { type: [types_1.PrimitiveDataTypes.INTEGER, types_1.PrimitiveDataTypes.INTEGER], format: types_1.DataFormats.INT64 } ] }; case 'String': return { type: types_1.PrimitiveDataTypes.STRING }; case 'ObjectID': return { type: types_1.PrimitiveDataTypes.STRING, maxlength: 24, pattern: '^[0-9a-fA-F]{24}$' }; case 'Boolean': return { type: types_1.PrimitiveDataTypes.BOOLEAN }; case 'Date': return { type: types_1.PrimitiveDataTypes.STRING, format: types_1.DataFormats.DATETIME }; } } return {}; } exports.extractMetaData = extractMetaData; //copied from https://gist.github.com/ahtcx/0cd94e62691f539160b32ecda18af3d6?permalink_comment_id=3571894#gistcomment-3571894 var mergeDeep = function (target, source, isMergingArrays) { if (isMergingArrays === void 0) { isMergingArrays = false; } target = (function (obj) { var cloneObj; try { cloneObj = JSON.parse(JSON.stringify(obj)); } catch (err) { // If the stringify fails due to circular reference, the merge defaults // to a less-safe assignment that may still mutate elements in the target. // You can change this part to throw an error for a truly safe deep merge. cloneObj = Object.assign({}, obj); } return cloneObj; })(target); var isObject = function (obj) { return obj && typeof obj === "object"; }; if (!isObject(target) || !isObject(source)) return source; Object.keys(source).forEach(function (key) { var targetValue = target[key]; var sourceValue = source[key]; if (Array.isArray(targetValue) && Array.isArray(sourceValue)) if (isMergingArrays) { target[key] = targetValue.map(function (x, i) { return sourceValue.length <= i ? x : (0, exports.mergeDeep)(x, sourceValue[i], isMergingArrays); }); if (sourceValue.length > targetValue.length) target[key] = target[key].concat(sourceValue.slice(targetValue.length)); } else { target[key] = targetValue.concat(sourceValue); } else if (isObject(targetValue) && isObject(sourceValue)) target[key] = (0, exports.mergeDeep)(Object.assign({}, targetValue), sourceValue, isMergingArrays); else target[key] = sourceValue; }); return target; }; exports.mergeDeep = mergeDeep;