Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 11 additions & 10 deletions data-attribute-resolver.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ var _ = require('lodash');
var {DataError} = require('@themost/common');
var Symbol = require('symbol');
var {hasOwnProperty} = require('./has-own-property');
var aliasProperty = Symbol('alias');
var DataAttributeResolverAliasProperty = Symbol('alias');
var {UnknownAttributeError} = require('./data-errors');
/**
* @class
Expand Down Expand Up @@ -185,7 +185,7 @@ DataAttributeResolver.prototype.resolveNestedAttributeJoin = function(memberExpr
var mapping = self.inferMapping(arrMember[0]);
if (_.isNil(mapping)) {
if (attrMember.type === 'Json') {
var collection = self[aliasProperty] || self.viewAdapter;
var collection = self[DataAttributeResolverAliasProperty] || self.viewAdapter;
var objectPath = arrMember.join('.');
var objectGet = new MethodCallExpression('jsonGet', [
new MemberExpression(collection + '.' + objectPath)
Expand Down Expand Up @@ -219,7 +219,7 @@ DataAttributeResolver.prototype.resolveNestedAttributeJoin = function(memberExpr
*/
res =QueryUtils.query(self.viewAdapter).select(['*']);
expr = QueryUtils.query().where(QueryField.select(childField.name)
.from(self[aliasProperty] || self.viewAdapter))
.from(self[DataAttributeResolverAliasProperty] || self.viewAdapter))
.equal(QueryField.select(mapping.parentField).from(childFieldName));
entity = new QueryEntity(parentModel.viewAdapter).as(childFieldName).left();
res.join(entity).with(expr);
Expand All @@ -230,7 +230,7 @@ DataAttributeResolver.prototype.resolveNestedAttributeJoin = function(memberExpr
value: parentModel.name
});
if (arrMember.length>2) {
parentModel[aliasProperty] = mapping.childField;
parentModel[DataAttributeResolverAliasProperty] = mapping.childField;
expr = new DataAttributeResolver().resolveNestedAttributeJoin.call(parentModel, arrMember.slice(1).join('/'));
return {
$select: expr.$select,
Expand All @@ -245,7 +245,7 @@ DataAttributeResolver.prototype.resolveNestedAttributeJoin = function(memberExpr
var nestedMapping = parentModel.inferMapping(nestedMember);
if (nestedMapping && nestedMapping.associationType === 'junction') {
// resolve nested member
parentModel[aliasProperty] = mapping.childField;
parentModel[DataAttributeResolverAliasProperty] = mapping.childField;
expr = new DataAttributeResolver().resolveJunctionAttributeJoin.call(parentModel, nestedMember);
return {
$select: expr.$select,
Expand All @@ -271,7 +271,7 @@ DataAttributeResolver.prototype.resolveNestedAttributeJoin = function(memberExpr
throw new Error(sprintf('Referenced field (%s) cannot be found.', mapping.parentField));
}
// get parent entity name for this expression
var parentEntity = self[aliasProperty] || self.viewAdapter;
var parentEntity = self[DataAttributeResolverAliasProperty] || self.viewAdapter;
// get child entity name for this expression
var childEntity = arrMember[0];
res =QueryUtils.query('Unknown').select(['*']);
Expand All @@ -286,7 +286,7 @@ DataAttributeResolver.prototype.resolveNestedAttributeJoin = function(memberExpr
});
if (arrMember.length>2) {
// set joined entity alias
childModel[aliasProperty] = childEntity;
childModel[DataAttributeResolverAliasProperty] = childEntity;
// resolve additional joins
expr = new DataAttributeResolver().resolveNestedAttributeJoin.call(childModel, arrMember.slice(1).join('/'));
// concat and return joins
Expand Down Expand Up @@ -316,7 +316,7 @@ DataAttributeResolver.prototype.resolveNestedAttributeJoin = function(memberExpr
if (mapping.associationType === 'junction' && mapping.parentModel === self.name) {
return new DataAttributeResolver().resolveJunctionAttributeJoin.call(self, memberExpr);
} else {
throw new Error(sprintf('The association type between %s and %s model is not supported for filtering, grouping or sorting data.', mapping.parentModel , mapping.childModel));
throw new Error(sprintf('The association of type "%s" between "%s" and "%s", defined by "%s", is not supported for filtering, grouping or sorting data.', mapping.associationType, mapping.parentModel , mapping.childModel, mapping.refersTo));
}
}
}
Expand Down Expand Up @@ -426,7 +426,7 @@ DataAttributeResolver.prototype.resolveJunctionAttributeJoin = function(attr) {
if (mapping && mapping.associationType === 'junction') {
//get field
var field = self.field(member[0]), entity, expr, q;
var thisAlias = self[aliasProperty] || self.viewAdapter;
var thisAlias = self[DataAttributeResolverAliasProperty] || self.viewAdapter;
//first approach (default association adapter)
//the underlying model is the parent model e.g. Group > Group Members
if (mapping.parentModel === self.name) {
Expand Down Expand Up @@ -570,5 +570,6 @@ DataAttributeResolver.prototype.resolveZeroOrOneNestedAttribute = function(attr)
}

module.exports = {
DataAttributeResolver
DataAttributeResolver,
DataAttributeResolverAliasProperty
}
15 changes: 7 additions & 8 deletions data-filter-resolver.d.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
// MOST Web Framework 2.0 Codename Blueshift BSD-3-Clause license Copyright (c) 2017-2022, THEMOST LP All rights reserved
export declare class DataFilterResolver {
resolveMember(member: string, callback: (err?: Error, res?: any) => void);
resolveMethod(name: string, args: Array<any>, callback: (err?: Error, res?: any) => void);
me(callback: (err?: Error, res?: any) => void);
user(callback: (err?: Error, res?: any) => void);
now(callback: (err?: Error, res?: Date) => void);
today(callback: (err?: Error, res?: Date) => void);
lang(callback: (err?: Error, res?: string) => void);

resolveMember(member: string, callback: (err?: Error, res?: any) => void): void;
resolveMethod(name: string, args: Array<any>, callback: (err?: Error, res?: any) => void): void;
me(callback: (err?: Error, res?: any) => void): void;
user(callback: (err?: Error, res?: any) => void): void;
now(callback: (err?: Error, res?: Date) => void): void;
today(callback: (err?: Error, res?: Date) => void): void;
lang(callback: (err?: Error, res?: string) => void): void;
}
35 changes: 35 additions & 0 deletions data-filter-resolver.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,41 @@ DataFilterResolver.prototype.resolveMember = function(member, callback) {
}
if (/\//.test(member)) {
var arr = member.split('/');
// validate that the expression resolves an existing attribute
var index = 0;
var model = this;
var context = this.context;
while (index < arr.length) {
var name = arr[index];
var attr = model.getAttribute(name);
if (attr == null) {
return callback(new UnknownAttributeError(model.name, name));
}
// if the attribute is a JSON type, then break the loop because
// the given expression e.g. metadata/identifier/name will be handled internally by the database engine
// and the attribute is not mapped to a model (the additionalType property is null)
if (attr.type === 'Json' && attr.additionalType == null) {
break;
}
// get mapping for the attribute
var mapping = model.inferMapping(name);
// throw exception because the attribute is not mapped and the expression is not fully resolved
if (mapping == null && index < arr.length-1) {
return callback(new UnknownAttributeError(model.name, name));
}
// if mapping is found, then get the model for the mapping
if (mapping != null) {
// throw exception because the mapping defines an association to a collection of primitive typed values
// and the expression is not fully resolved
// e.g. tags/tag/name where tags is an array of strings
if (mapping.childModel == null && index < arr.length-1) {
return callback(new UnknownAttributeError(model.name, name));
}
var type = attr.additionalType != null ? attr.additionalType : attr.type;
model = context.model(type);
}
index++;
}
return callback(null, arr.slice(arr.length-2).join('.'));
}
var attribute = this.getAttribute(member);
Expand Down
3 changes: 2 additions & 1 deletion data-model.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ var { DataStateValidatorListener } = require('./data-state-validator');
var resolver = require('./data-expand-resolver');
var isArrayLikeObject = require('lodash/isArrayLikeObject');
var {DataObjectFinder} = require('./data-object-finder');
var { DataAttributeResolver:DataAttributeResolverClass } = require('./data-attribute-resolver');
/**
* @this DataModel
* @param {DataField} field
Expand Down Expand Up @@ -755,7 +756,7 @@ function filterInternal(params, callback) {
mapping = self.inferMapping(member1[0]),
expr;
if (mapping && mapping.associationType === 'junction') {
var expr1 = DataAttributeResolver.prototype.resolveJunctionAttributeJoin.call(self, member);
var expr1 = DataAttributeResolverClass.prototype.resolveNestedAttributeJoin.call(self, member);
expr = expr1.$expand;
//replace member expression
member = expr1.$select.$name.replace(/\./g,'/');
Expand Down
12 changes: 9 additions & 3 deletions data-queryable.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,14 @@ var {QueryField, MethodCallExpression, MemberExpression, ObjectNameValidator} =
var {QueryEntity, Expression} = require('@themost/query');
var {QueryUtils} = require('@themost/query');
var Q = require('q');
var aliasProperty = Symbol('alias');
var {hasOwnProperty} = require('./has-own-property');
var {isObjectDeep} = require('./is-object');
var { UnknownAttributeError } = require('./data-errors');
var { DataExpandResolver } = require('./data-expand-resolver');
var {instanceOf} = require('./instance-of');

var { DataAttributeResolver:DataAttributeResolverClass, DataAttributeResolverAliasProperty } = require('./data-attribute-resolver');
// noinspection JSUnresolvedReference
var aliasProperty = DataAttributeResolverAliasProperty;
/**
* @param {DataQueryable} target
*/
Expand Down Expand Up @@ -549,7 +550,12 @@ DataAttributeResolver.prototype.resolveNestedAttributeJoin = function(memberExpr
return res.$expand;
}
else {
throw new Error(sprintf('The association type between %s and %s model is not supported for filtering, grouping or sorting data.', mapping.parentModel , mapping.childModel));
if (mapping.associationType === 'junction') {
const res = new DataAttributeResolverClass().resolveNestedAttributeJoin.call(self, memberExpr);
return res.$expand;
} else {
throw new Error(sprintf('The association of type "%s" between "%s" and "%s", defined by "%s", is not supported for filtering, grouping or sorting data.', mapping.associationType, mapping.parentModel , mapping.childModel, mapping.refersTo));
}
}
}
};
Expand Down