@themost/data
Version:
MOST Web Framework Codename Blueshift - Data module
157 lines (151 loc) • 7.43 kB
JavaScript
const {DataAttributeResolver} = require('./data-attribute-resolver');
const {isObjectDeep} = require('./is-object');
const {sprintf} = require('sprintf-js');
var {Expression} = require('@themost/query');
/**
* @class DataValueResolver
* @param {import('./index').DataQueryable} target
* @constructor
*/
function DataValueResolver(target) {
Object.defineProperty(this, 'target', { get: function() {
return target;
}, configurable:false, enumerable:false});
}
DataValueResolver.prototype.resolve = function(value) {
/**
* @type {DataQueryable}
*/
var target = this.target;
if (typeof value === 'string' && /^\$it\//.test(value)) {
var attr = value.replace(/^\$it\//,'');
if (DataAttributeResolver.prototype.testNestedAttribute(attr)) {
return DataAttributeResolver.prototype.resolveNestedAttribute.call(target, attr);
}
else {
attr = DataAttributeResolver.prototype.testAttribute(attr);
if (attr) {
return target.fieldOf(attr.name);
}
}
}
// if value is an instance of Expression e.g. an instance if MemberExpression
if (value instanceof Expression) {
// return the expression
return value;
}
if (isObjectDeep(value)) {
// try to get in-process left operand
// noinspection JSUnresolvedReference
var left = target.query.privates && target.query.privates.property;
if (typeof left === 'string' && /\./.test(left)) {
var members = left.split('.');
if (Array.isArray(members)) {
// try to find member mapping
/**
* @type {import('./data-model').DataModel}
*/
var model = target.model;
var mapping;
var attribute;
var index = 0;
var context = target.model.context;
// if the first segment contains the view adapter name
if (members[0] === target.model.viewAdapter) {
// move next
index++;
} else if (target.query.$expand != null) {
// try to find if the first segment is contained in the collection of joined entities
var joins = Array.isArray(target.query.$expand) ? target.query.$expand : [ target.query.$expand ];
if (joins.length) {
var found = joins.find(function(x) {
return x.$entity && x.$entity.$as === members[0];
});
if (found) {
var mapping1 = model.inferMapping(found.$entity.$as);
if (mapping1 && mapping1.associationType === 'junction') {
// get next segment of members
var nextMember = members[index + 1];
if (nextMember === mapping1.associationObjectField) {
// the next segment is the association object field
// e.g. groups/group
model = context.model(mapping1.parentModel);
members[index + 1] = mapping1.parentField;
} else if (nextMember === mapping1.associationValueField) {
// the next segment is the association value field
// e.g. groups/user
model = context.model(mapping1.childModel);
members[index + 1] = mapping1.childField;
} else if (model.name === mapping1.parentModel) {
model = context.model(mapping1.childModel);
} else {
model = context.model(mapping1.parentModel);
}
} else if (found.$entity.model != null) {
model = context.model(found.$entity.model);
} else {
throw new Error(sprintf('Expected a valid mapping for property "%s"', found.$entity.$as));
}
index++;
}
}
}
var mapValue = function(x) {
if (Object.hasOwnProperty.call(x, name)) {
return x[name];
}
throw new Error(sprintf('Invalid value for property "%s"', members[members.length - 1]));
}
while (index < members.length) {
mapping = model.inferMapping(members[index]);
if (mapping) {
if (mapping.associationType === 'association' && mapping.childModel === model.name) {
model = context.model(mapping.parentModel);
if (model) {
attribute = model.getAttribute(mapping.parentField);
}
} else if (mapping.associationType === 'association' && mapping.parentModel === model.name) {
model = context.model(mapping.childModel);
if (model) {
attribute = model.getAttribute(mapping.childField);
}
} else if (mapping.associationType === 'junction' && mapping.childModel === model.name) {
model = context.model(mapping.parentModel);
if (model) {
attribute = model.getAttribute(mapping.parentField);
}
} else if (mapping.associationType === 'junction' && mapping.parentModel === model.name) {
model = context.model(mapping.childModel);
if (model) {
attribute = model.getAttribute(mapping.childField);
}
}
} else {
// if mapping is not found, and we are in the last segment
// try to find if this last segment is a field of the current model
if (index === members.length - 1) {
attribute = model.getAttribute(members[index]);
break;
}
attribute = null;
model = null;
break;
}
index++;
}
if (attribute) {
var name = attribute.property || attribute.name;
if (Array.isArray(value)) {
return value.map(function(x) {
return mapValue(x);
});
} else {
return mapValue(value);
}
}
}
}
}
return value;
}
module.exports = { DataValueResolver };