Skip to content

Commit

Permalink
fix: generic helper to map nested prop defs to data
Browse files Browse the repository at this point in the history
Co-authored-by: Miroslav Bajtoš <mbajtoss@gmail.com>
  • Loading branch information
biniam and bajtos committed Apr 2, 2019
1 parent 8c2a527 commit 691e52e
Show file tree
Hide file tree
Showing 2 changed files with 425 additions and 10 deletions.
94 changes: 84 additions & 10 deletions lib/mongodb.js
Original file line number Diff line number Diff line change
Expand Up @@ -1996,23 +1996,97 @@ function optimizedFindOrCreate(model, filter, data, options, callback) {
}

/**
* Convert the decimal properties from string to decimal.
* Convert decimal properties from string to decimal.
* Only supported after mongodb 3.4
*
* @param {Object} data The data that might contain a decimal property
* @param {Object} props The model property definitions
*/
function convertDecimalProps(data, props) {
if (debug.enabled) debug('convertDecimalProps props: ', util.inspect(props));
for (const p in props) {
const prop = props[p];
const isDecimal = data[p] && prop && prop.mongodb &&
prop.mongodb.dataType &&
prop.mongodb.dataType.toLowerCase() === 'decimal128';
if (isDecimal) {
data[p] = Decimal128.fromString(data[p]);
debug('convertDecimalProps decimal value: ', data[p]);
visitAllProperties(data, props, coerceDecimalProperties);

/**
*
* @param {*} data Plain Data Object for the matching property definition(s)
* @param {*} propDefMap Property definition(s) which include information about property type
* @param {*} visitor A callback function which takes a property value and
* definition to apply custom property coercion
*/
function visitAllProperties(data, propDefMap, visitor) {
if (data === null) return;
const props = new Set(Object.keys(data).concat(Object.keys(propDefMap)));
for (const p of props) {
const value = data[p];
const def = propDefMap[p];
if (checkNested(def)) {
if (Array.isArray(def.type)) {
if (value === null || value.length === 0) return;
for (const it of value) {
visitAllProperties(it, def.type[0].definition.properties, visitor);
}
} else {
visitAllProperties(value, def.type.definition.properties, visitor);
}
} else {
data[p] = visitor(value, def);
}
}
}

/**
*
* @param {*} value Property value to coerce into a Decimal128 value
* @param {*} def Property definition to check if property is MongoDB
* decima type
*/
function coerceDecimalProperties(value, def) {
if (checkDecimalProp(def)) {
if (Array.isArray(value)) {
return value.map(val => Decimal128.fromString(val));
} else {
return Decimal128.fromString(value);
}
} else {
return value;
}
}

/**
* A utility function which checks for nested property definitions
*
* @param {*} propDefinition Property definition which contains metadata for the
* property type
*/
function checkNested(propDefinition) {
if (!propDefinition || !propDefinition.type) {
return false;
}
if (Array.isArray(propDefinition.type)) {
if (!propDefinition.type[0].definition) {
return false;
} else {
if (propDefinition.type[0].definition.properties) return true;
}
} else {
if (!propDefinition.type.definition) {
return false;
} else {
if (propDefinition.type.definition.properties) return true;
}
}
}

/**
* A utility function which checks if a certain property definition is
* decimal128 type
* @param {*} propertyDef A property definition containing metadata about property type
*/
function checkDecimalProp(propertyDef) {
return propertyDef && propertyDef.mongodb &&
propertyDef.mongodb.dataType &&
propertyDef.mongodb.dataType.toLowerCase() === 'decimal128';
}

return data;
}

Loading

0 comments on commit 691e52e

Please sign in to comment.