
com.xresch.cfw.features.query.functions.CFWQueryFunctionStdev Maven / Gradle / Ivy
package com.xresch.cfw.features.query.functions;
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Map.Entry;
import java.util.TreeSet;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.xresch.cfw._main.CFW;
import com.xresch.cfw.features.query.CFWQueryContext;
import com.xresch.cfw.features.query.CFWQueryFunction;
import com.xresch.cfw.features.query.EnhancedJsonObject;
import com.xresch.cfw.features.query.FeatureQuery;
import com.xresch.cfw.features.query.parse.QueryPartValue;
import com.xresch.cfw.utils.CFWMath;
/************************************************************************************************************
*
* @author Reto Scheiwiller, (c) Copyright 2023
* @license MIT-License
************************************************************************************************************/
public class CFWQueryFunctionStdev extends CFWQueryFunction {
public static final String FUNCTION_NAME = "stdev";
private ArrayList values = new ArrayList();
private BigDecimal sum = new BigDecimal(0).setScale(6);
private boolean isAggregated = false;
private int precision = 3;
public CFWQueryFunctionStdev(CFWQueryContext context) {
super(context);
}
/***********************************************************************************************
*
***********************************************************************************************/
@Override
public String uniqueName() {
return FUNCTION_NAME;
}
/***********************************************************************************************
*
***********************************************************************************************/
@Override
public TreeSet getTags(){
TreeSet tags = new TreeSet<>();
tags.add(CFWQueryFunction.TAG_AGGREGATION);
return tags;
}
/***********************************************************************************************
*
***********************************************************************************************/
@Override
public String descriptionSyntax() {
return FUNCTION_NAME+"(valueOrFieldname, includeNulls, precision, usePopulation)";
}
/***********************************************************************************************
*
***********************************************************************************************/
@Override
public String descriptionShort() {
return "Aggregation function to calculate standard deviation.";
}
/***********************************************************************************************
*
***********************************************************************************************/
@Override
public String descriptionSyntaxDetailsHTML() {
return "valueOrFieldname: The value or fieldname used for the average.
"
+ "includeNulls: (Optional)Toggle if null values should be included as zero in the average(Default:false).
"
+ "precision: (Optional)Decimal precision of the result.(Default:3)
"
+ "usePopulation: (Optional)If true use population formula, if false use sample formula.(Default: true)
"
;
}
/***********************************************************************************************
*
***********************************************************************************************/
@Override
public String descriptionHTML() {
return CFW.Files.readPackageResource(FeatureQuery.PACKAGE_MANUAL+".functions", "function_"+FUNCTION_NAME+".html");
}
/***********************************************************************************************
*
***********************************************************************************************/
@Override
public boolean supportsAggregation() {
return true;
}
/***********************************************************************************************
*
***********************************************************************************************/
private void addValueToAggregation(QueryPartValue value, boolean countNulls) {
if(value.isNumberOrNumberString()) {
values.add(value.getAsBigDecimal());
sum = sum.add(value.getAsBigDecimal());
}else if(countNulls && value.isNull()) {
values.add(BigDecimal.ZERO);
}
}
/***********************************************************************************************
*
***********************************************************************************************/
private BigDecimal calculateStandardDeviation(boolean usePopulation) {
BigDecimal standardDeviation = CFW.Math.bigStdev(values, usePopulation);
//reset values when calculation is done
values.clear();
sum = BigDecimal.ZERO.setScale(6);
return standardDeviation;
}
/***********************************************************************************************
*
***********************************************************************************************/
@Override
public void aggregate(EnhancedJsonObject object,ArrayList parameters) {
isAggregated = true;
QueryPartValue value = parameters.get(0);
boolean countNulls = false;
if(parameters.size() > 1) {
countNulls = parameters.get(1).getAsBoolean();
}
addValueToAggregation(value, countNulls);
}
/***********************************************************************************************
* Returns the current count and increases it by 1;
***********************************************************************************************/
@Override
public QueryPartValue execute(EnhancedJsonObject object, ArrayList parameters) {
//----------------------------
// Handle usePopulation
boolean usePopulation = true;
if(parameters.size() > 3
&& parameters.get(3).isBoolOrBoolString()) {
usePopulation = parameters.get(3).getAsBoolean();
}
BigDecimal result = BigDecimal.ZERO;
if(isAggregated) {
result = calculateStandardDeviation(usePopulation);
}else if(parameters.size() == 0) {
result = null;
}else {
QueryPartValue param = parameters.get(0);
boolean countNulls = false;
if(parameters.size() > 1) {
countNulls = parameters.get(1).getAsBoolean();
}
if(param.isJsonArray()) {
JsonArray array = param.getAsJsonArray();
for(int i = 0; i < array.size(); i++) {
//Be lazy, use QueryPart for conversion
QueryPartValue value = QueryPartValue.newFromJsonElement(array.get(i));
addValueToAggregation(value, countNulls);
}
result = calculateStandardDeviation(usePopulation);
}else if(param.isJsonObject()) {
for(Entry entry : param.getAsJsonObject().entrySet()){
QueryPartValue value = QueryPartValue.newFromJsonElement(entry.getValue());
addValueToAggregation(value, countNulls);
}
result = calculateStandardDeviation(usePopulation);
}else if(param.isNumberOrNumberString()) {
addValueToAggregation(param, countNulls);
result = calculateStandardDeviation(usePopulation);
}
}
//----------------------------
// Handle Precision
if(parameters.size() > 2
&& parameters.get(2).isNumberOrNumberString()) {
precision = parameters.get(2).getAsInteger();
}
//----------------------------
// Return Value
if(result == null) {
return QueryPartValue.newNull();
}else {
return QueryPartValue.newNumber(result.setScale(precision, RoundingMode.HALF_UP));
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy