odatafy-mongoose
Version:
Use mongoose to excel the capabilities of datafy-mongodb
306 lines (305 loc) • 11.8 kB
JavaScript
;
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;