Skip to content

Commit

Permalink
Merge pull request #8374 from surveyjs/bug/8371-expression-functions-…
Browse files Browse the repository at this point in the history
…originalparameters

The filtering condition without apostrophes doesn't work for the coun…
  • Loading branch information
andrewtelnov authored Jun 5, 2024
2 parents ec519e6 + ea2048f commit a19fb4f
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 20 deletions.
3 changes: 2 additions & 1 deletion src/expressions/expressions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,8 @@ export class FunctionOperand extends Operand {
return FunctionFactory.Instance.run(
this.originalValue,
this.parameters.evaluate(processValue),
processValue.properties
processValue.properties,
this.parameters.values
);
}

Expand Down
45 changes: 26 additions & 19 deletions src/functionsfactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ import { ConditionRunner } from "./conditions";

export class FunctionFactory {
public static Instance: FunctionFactory = new FunctionFactory();
private functionHash: HashTable<(params: any[]) => any> = {};
private functionHash: HashTable<(params: any[], originalParams?: any[]) => any> = {};
private isAsyncHash: HashTable<boolean> = {};

public register(
name: string,
func: (params: any[]) => any,
func: (params: any[], originalParams?: any[]) => any,
isAsync: boolean = false
): void {
this.functionHash[name] = func;
Expand Down Expand Up @@ -40,7 +40,8 @@ export class FunctionFactory {
public run(
name: string,
params: any[],
properties: HashTable<any> = null
properties: HashTable<any> = null,
originalParams: any[]
): any {
var func = this.functionHash[name];
if (!func) {
Expand All @@ -56,7 +57,7 @@ export class FunctionFactory {
(<any>classRunner)[key] = properties[key];
}
}
return classRunner.func(params);
return classRunner.func(params, originalParams);
}
}

Expand Down Expand Up @@ -129,17 +130,23 @@ function avg(params: any[]): any {
}
FunctionFactory.Instance.register("avg", avg);

function getInArrayParams(params: any[]): any {
function getInArrayParams(params: any[], originalParams: any[]): any {
if (params.length < 2 || params.length > 3) return null;
const arr = params[0];
if (!arr) return null;
if (!Array.isArray(arr) && !Array.isArray(Object.keys(arr))) return null;
const name = params[1];
if (typeof name !== "string" && !(name instanceof String)) return null;
let expression = params.length === 3 ? params[2] : undefined;
let expression = params.length > 2 ? params[2] : undefined;
if (typeof expression !== "string" && !(expression instanceof String)) {
expression = undefined;
}
if(!expression) {
const operand = Array.isArray(originalParams) && originalParams.length > 2 ? originalParams[2] : undefined;
if(operand && !!operand.toString()) {
expression = operand.toString();
}
}
return { data: arr, name: name, expression: expression };
}

Expand All @@ -155,10 +162,10 @@ function processItemInArray(item: any, name: string, res: number,
return func(res, val);
}
function calcInArray(
params: any[],
params: any[], originalParams: any[],
func: (res: number, val: number) => number, needToConvert: boolean = true
): any {
var v = getInArrayParams(params);
var v = getInArrayParams(params, originalParams);
if (!v) return undefined;
let condition = !!v.expression ? new ConditionRunner(v.expression) : undefined;
if(condition && condition.isAsync) {
Expand All @@ -177,8 +184,8 @@ function calcInArray(
return res;
}

function sumInArray(params: any[]): any {
var res = calcInArray(params, function(res: number, val: number): number {
function sumInArray(params: any[], originalParams: any[]): any {
var res = calcInArray(params, originalParams, function(res: number, val: number): number {
if (res == undefined) res = 0;
if(val == undefined || val == null) return res;
return Helpers.correctAfterPlusMinis(res, val, res + val);
Expand All @@ -187,26 +194,26 @@ function sumInArray(params: any[]): any {
}
FunctionFactory.Instance.register("sumInArray", sumInArray);

function minInArray(params: any[]): any {
return calcInArray(params, function(res: number, val: number): number {
function minInArray(params: any[], originalParams: any[]): any {
return calcInArray(params, originalParams, function(res: number, val: number): number {
if (res == undefined) return val;
if(val == undefined || val == null) return res;
return res < val ? res : val;
});
}
FunctionFactory.Instance.register("minInArray", minInArray);

function maxInArray(params: any[]): any {
return calcInArray(params, function(res: number, val: number): number {
function maxInArray(params: any[], originalParams: any[]): any {
return calcInArray(params, originalParams, function(res: number, val: number): number {
if (res == undefined) return val;
if(val == undefined || val == null) return res;
return res > val ? res : val;
});
}
FunctionFactory.Instance.register("maxInArray", maxInArray);

function countInArray(params: any[]): any {
var res = calcInArray(params, function(res: number, val: number): number {
function countInArray(params: any[], originalParams: any[]): any {
var res = calcInArray(params, originalParams, function(res: number, val: number): number {
if (res == undefined) res = 0;
if(val == undefined || val == null) return res;
return res + 1;
Expand All @@ -215,10 +222,10 @@ function countInArray(params: any[]): any {
}
FunctionFactory.Instance.register("countInArray", countInArray);

function avgInArray(params: any[]): any {
var count = countInArray(params);
function avgInArray(params: any[], originalParams: any[]): any {
var count = countInArray(params, originalParams);
if (count == 0) return 0;
return sumInArray(params) / count;
return sumInArray(params, originalParams) / count;
}
FunctionFactory.Instance.register("avgInArray", avgInArray);

Expand Down
10 changes: 10 additions & 0 deletions tests/expressions/expressionParserTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -721,6 +721,16 @@ QUnit.test("ExpressionRunner: sumInArray with conditional logic", function(asser
var values = { a: [{ val1: 1, val2: 4 }, { val1: 2, val2: 3 }, { val1: 3, val2: 5 }] };
assert.equal(runner.run(values), 4, "1 + 3");
});
QUnit.test("ExpressionRunner: sumInArray with conditional logic as operand", function(assert) {
var runner = new ExpressionRunner("sumInArray({a}, 'val1', {val2} > 3)");
var values = { a: [{ val1: 1, val2: 4 }, { val1: 2, val2: 3 }, { val1: 3, val2: 5 }] };
assert.equal(runner.run(values), 4, "1 + 3");
});
QUnit.test("ExpressionRunner: countInArray with conditional logic & strings", function(assert) {
var runner = new ExpressionRunner("sumInArray({a}, 'val1', {val2} <> 'item1')");
var values = { a: [{ val1: 1, val2: "item2" }, { val1: 2, val2: "item1" }, { val1: 3, val2: "item3" }] };
assert.equal(runner.run(values), 4, "1 + 3");
});

QUnit.test("ExpressionRunner: countInArray", function(assert) {
var runner = new ExpressionRunner("countInArray({a}, 'val1')");
Expand Down

0 comments on commit a19fb4f

Please sign in to comment.