@@ -6,7 +6,7 @@ import { Context } from '../runtime/context';
66import { Exception } from '../datatypes/exception' ;
77import { greaterThan , lessThan } from '../util/comparison' ;
88import { build } from './builder' ;
9- import { overflowsOrUnderflows } from '../util/math' ;
9+ import { overflowsOrUnderflows , finalizeNumericResult } from '../util/math' ;
1010import { ELM_DECIMAL_TYPE } from '../util/elmTypes' ;
1111
1212class AggregateExpression extends Expression {
@@ -18,28 +18,6 @@ class AggregateExpression extends Expression {
1818 }
1919}
2020
21- function hasDecimals ( values : any [ ] ) {
22- return values . some ( value => value && value . isDecimal ) ;
23- }
24-
25- function isDecimal ( value : any ) : value is Decimal {
26- return value != null && value . isDecimal ;
27- }
28-
29- function sumDecimals ( values : Decimal [ ] ) {
30- return values . reduce ( ( sum , value ) => sum . add ( value ) ) ;
31- }
32-
33- function productDecimals ( values : Decimal [ ] ) {
34- return values . reduce ( ( product , value ) => product . multiplyBy ( value ) ) ;
35- }
36-
37- function decimalResult ( value : number , values : any [ ] , resultTypeName ?: string ) {
38- return hasDecimals ( values ) || resultTypeName === ELM_DECIMAL_TYPE
39- ? Decimal . from ( value ) . normalized ( )
40- : value ;
41- }
42-
4321export class Count extends AggregateExpression {
4422 constructor ( json : any ) {
4523 super ( json ) ;
@@ -76,12 +54,16 @@ export class Sum extends AggregateExpression {
7654 }
7755
7856 if ( hasOnlyQuantities ( items ) ) {
79- const sum = sumDecimals ( getValuesFromQuantities ( items ) ) ;
57+ const sum = sumOfDecimals ( getValuesFromQuantities ( items ) ) ;
8058 return overflowsOrUnderflows ( sum , ELM_DECIMAL_TYPE ) ? null : new Quantity ( sum , items [ 0 ] . unit ) ;
8159 } else {
82- const sum = hasDecimals ( items )
83- ? sumDecimals ( items . map ( Decimal . from ) )
84- : items . reduce ( ( x : any , y : any ) => x + y ) ;
60+ let sum ;
61+ if ( hasDecimals ( items ) ) {
62+ sum = sumOfDecimals ( items . map ( Decimal . from ) ) ;
63+ } else {
64+ sum = items . reduce ( ( x : any , y : any ) => x + y ) ;
65+ }
66+ sum = finalizeNumericResult ( sum ) ;
8567 return overflowsOrUnderflows ( sum , this . resultTypeName ) ? null : sum ;
8668 }
8769 }
@@ -177,11 +159,11 @@ export class Avg extends AggregateExpression {
177159 }
178160
179161 if ( hasOnlyQuantities ( items ) ) {
180- const sum = sumDecimals ( getValuesFromQuantities ( items ) ) ;
162+ const sum = sumOfDecimals ( getValuesFromQuantities ( items ) ) ;
181163 return new Quantity ( sum . divideBy ( items . length ) , items [ 0 ] . unit ) ;
182164 } else {
183165 // return type is always Decimal, so just map everything to Decimals
184- return sumDecimals ( items . map ( Decimal . from ) ) . divideBy ( items . length ) . normalized ( ) ;
166+ return sumOfDecimals ( items . map ( Decimal . from ) ) . divideBy ( items . length ) . normalized ( ) ;
185167 }
186168 }
187169}
@@ -206,14 +188,17 @@ export class Median extends AggregateExpression {
206188 return null ;
207189 }
208190
209- if ( ! hasOnlyQuantities ( items ) ) {
210- return hasDecimals ( items )
211- ? medianOfDecimals ( items . map ( Decimal . from ) )
212- : decimalResult ( medianOfNumbers ( items ) , items , this . resultTypeName ) ;
191+ if ( hasOnlyQuantities ( items ) ) {
192+ const median = medianOfDecimals ( getValuesFromQuantities ( items ) ) ;
193+ return new Quantity ( median , items [ 0 ] . unit ) ;
194+ }
195+
196+ if ( hasDecimals ( items ) ) {
197+ const decimals = items . map ( Decimal . from ) ;
198+ return finalizeNumericResult ( medianOfDecimals ( decimals ) ) ;
213199 }
214200
215- const median = medianOfDecimals ( getValuesFromQuantities ( items ) ) ;
216- return new Quantity ( median , items [ 0 ] . unit ) ;
201+ return medianOfNumbers ( items ) ;
217202 }
218203}
219204
@@ -240,7 +225,7 @@ export class Mode extends AggregateExpression {
240225
241226 if ( hasOnlyQuantities ( filtered ) ) {
242227 const values = getValuesFromQuantities ( filtered ) ;
243- let mode = this . mode ( values ) ;
228+ const mode = this . mode ( values ) ;
244229 if ( mode . length === 1 ) {
245230 return new Quantity ( mode [ 0 ] , items [ 0 ] . unit ) ;
246231 } else {
@@ -362,16 +347,19 @@ export class Product extends AggregateExpression {
362347 }
363348
364349 if ( hasOnlyQuantities ( items ) ) {
365- const product = productDecimals ( getValuesFromQuantities ( items ) ) ;
350+ const product = productOfDecimals ( getValuesFromQuantities ( items ) ) ;
366351 // Units are not multiplied for the geometric product
367352 return overflowsOrUnderflows ( product , ELM_DECIMAL_TYPE )
368353 ? null
369354 : new Quantity ( product , items [ 0 ] . unit ) ;
370355 } else {
371- const product = hasDecimals ( items )
372- ? productDecimals ( items . map ( Decimal . from ) )
373- : items . reduce ( ( x : number , y : number ) => x * y ) ;
374- const result = isDecimal ( product ) ? product : decimalResult ( product , items , this . resultTypeName ) ;
356+ let result ;
357+ if ( hasDecimals ( items ) ) {
358+ result = productOfDecimals ( items . map ( Decimal . from ) ) ;
359+ } else {
360+ result = items . reduce ( ( x : number , y : number ) => x * y ) ;
361+ }
362+ result = finalizeNumericResult ( result ) ;
375363 return overflowsOrUnderflows ( result , this . resultTypeName ) ? null : result ;
376364 }
377365 }
@@ -399,12 +387,13 @@ export class GeometricMean extends AggregateExpression {
399387 }
400388
401389 if ( hasOnlyQuantities ( items ) ) {
402- const product = productDecimals ( getValuesFromQuantities ( items ) ) ;
390+ const product = productOfDecimals ( getValuesFromQuantities ( items ) ) ;
403391 const geoMean = product . power ( 1.0 / items . length ) ;
404392 return new Quantity ( geoMean , items [ 0 ] . unit ) ;
405393 } else {
406- return productDecimals ( items . map ( Decimal . from ) )
407- . power ( 1.0 / items . length ) . normalized ( ) ;
394+ return productOfDecimals ( items . map ( Decimal . from ) )
395+ . power ( 1.0 / items . length )
396+ . normalized ( ) ;
408397 }
409398 }
410399}
@@ -458,6 +447,10 @@ export class AnyTrue extends AggregateExpression {
458447 }
459448}
460449
450+ function hasDecimals ( values : any [ ] ) {
451+ return values . some ( value => value && value . isDecimal ) ;
452+ }
453+
461454function processQuantities ( values : any [ ] ) {
462455 const items = removeNulls ( values ) ;
463456 if ( hasOnlyQuantities ( items ) ) {
@@ -502,7 +495,13 @@ function medianOfNumbers(numbers: number[]) {
502495function medianOfDecimals ( decimals : Decimal [ ] ) {
503496 const items = [ ...decimals ] . sort ( ( a , b ) => a . compareTo ( b ) ) ;
504497 const middle = Math . floor ( items . length / 2 ) ;
505- return items . length % 2 === 1
506- ? items [ middle ]
507- : items [ middle - 1 ] . add ( items [ middle ] ) . divideBy ( 2 ) ;
498+ return items . length % 2 === 1 ? items [ middle ] : items [ middle - 1 ] . add ( items [ middle ] ) . divideBy ( 2 ) ;
499+ }
500+
501+ function sumOfDecimals ( values : Decimal [ ] ) {
502+ return values . reduce ( ( sum , value ) => sum . add ( value ) ) ;
503+ }
504+
505+ function productOfDecimals ( values : Decimal [ ] ) {
506+ return values . reduce ( ( product , value ) => product . multiplyBy ( value ) ) ;
508507}
0 commit comments